xref: /OK3568_Linux_fs/kernel/arch/x86/platform/pvh/head.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun/*
4*4882a593Smuzhiyun * Copyright C 2016, Oracle and/or its affiliates. All rights reserved.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun	.code32
8*4882a593Smuzhiyun	.text
9*4882a593Smuzhiyun#define _pa(x)          ((x) - __START_KERNEL_map)
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun#include <linux/elfnote.h>
12*4882a593Smuzhiyun#include <linux/init.h>
13*4882a593Smuzhiyun#include <linux/linkage.h>
14*4882a593Smuzhiyun#include <asm/segment.h>
15*4882a593Smuzhiyun#include <asm/asm.h>
16*4882a593Smuzhiyun#include <asm/boot.h>
17*4882a593Smuzhiyun#include <asm/processor-flags.h>
18*4882a593Smuzhiyun#include <asm/msr.h>
19*4882a593Smuzhiyun#include <xen/interface/elfnote.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun	__HEAD
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun/*
24*4882a593Smuzhiyun * Entry point for PVH guests.
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * Xen ABI specifies the following register state when we come here:
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * - `ebx`: contains the physical memory address where the loader has placed
29*4882a593Smuzhiyun *          the boot start info structure.
30*4882a593Smuzhiyun * - `cr0`: bit 0 (PE) must be set. All the other writeable bits are cleared.
31*4882a593Smuzhiyun * - `cr4`: all bits are cleared.
32*4882a593Smuzhiyun * - `cs `: must be a 32-bit read/execute code segment with a base of ‘0’
33*4882a593Smuzhiyun *          and a limit of ‘0xFFFFFFFF’. The selector value is unspecified.
34*4882a593Smuzhiyun * - `ds`, `es`: must be a 32-bit read/write data segment with a base of
35*4882a593Smuzhiyun *               ‘0’ and a limit of ‘0xFFFFFFFF’. The selector values are all
36*4882a593Smuzhiyun *               unspecified.
37*4882a593Smuzhiyun * - `tr`: must be a 32-bit TSS (active) with a base of '0' and a limit
38*4882a593Smuzhiyun *         of '0x67'.
39*4882a593Smuzhiyun * - `eflags`: bit 17 (VM) must be cleared. Bit 9 (IF) must be cleared.
40*4882a593Smuzhiyun *             Bit 8 (TF) must be cleared. Other bits are all unspecified.
41*4882a593Smuzhiyun *
42*4882a593Smuzhiyun * All other processor registers and flag bits are unspecified. The OS is in
43*4882a593Smuzhiyun * charge of setting up it's own stack, GDT and IDT.
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun#define PVH_GDT_ENTRY_CS	1
47*4882a593Smuzhiyun#define PVH_GDT_ENTRY_DS	2
48*4882a593Smuzhiyun#define PVH_GDT_ENTRY_CANARY	3
49*4882a593Smuzhiyun#define PVH_CS_SEL		(PVH_GDT_ENTRY_CS * 8)
50*4882a593Smuzhiyun#define PVH_DS_SEL		(PVH_GDT_ENTRY_DS * 8)
51*4882a593Smuzhiyun#define PVH_CANARY_SEL		(PVH_GDT_ENTRY_CANARY * 8)
52*4882a593Smuzhiyun
53*4882a593SmuzhiyunSYM_CODE_START_LOCAL(pvh_start_xen)
54*4882a593Smuzhiyun	cld
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun	lgdt (_pa(gdt))
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun	mov $PVH_DS_SEL,%eax
59*4882a593Smuzhiyun	mov %eax,%ds
60*4882a593Smuzhiyun	mov %eax,%es
61*4882a593Smuzhiyun	mov %eax,%ss
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun	/* Stash hvm_start_info. */
64*4882a593Smuzhiyun	mov $_pa(pvh_start_info), %edi
65*4882a593Smuzhiyun	mov %ebx, %esi
66*4882a593Smuzhiyun	mov _pa(pvh_start_info_sz), %ecx
67*4882a593Smuzhiyun	shr $2,%ecx
68*4882a593Smuzhiyun	rep
69*4882a593Smuzhiyun	movsl
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun	mov $_pa(early_stack_end), %esp
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun	/* Enable PAE mode. */
74*4882a593Smuzhiyun	mov %cr4, %eax
75*4882a593Smuzhiyun	orl $X86_CR4_PAE, %eax
76*4882a593Smuzhiyun	mov %eax, %cr4
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun#ifdef CONFIG_X86_64
79*4882a593Smuzhiyun	/* Enable Long mode. */
80*4882a593Smuzhiyun	mov $MSR_EFER, %ecx
81*4882a593Smuzhiyun	rdmsr
82*4882a593Smuzhiyun	btsl $_EFER_LME, %eax
83*4882a593Smuzhiyun	wrmsr
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun	/* Enable pre-constructed page tables. */
86*4882a593Smuzhiyun	mov $_pa(init_top_pgt), %eax
87*4882a593Smuzhiyun	mov %eax, %cr3
88*4882a593Smuzhiyun	mov $(X86_CR0_PG | X86_CR0_PE), %eax
89*4882a593Smuzhiyun	mov %eax, %cr0
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun	/* Jump to 64-bit mode. */
92*4882a593Smuzhiyun	ljmp $PVH_CS_SEL, $_pa(1f)
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun	/* 64-bit entry point. */
95*4882a593Smuzhiyun	.code64
96*4882a593Smuzhiyun1:
97*4882a593Smuzhiyun	/* Set base address in stack canary descriptor. */
98*4882a593Smuzhiyun	mov $MSR_GS_BASE,%ecx
99*4882a593Smuzhiyun	mov $_pa(canary), %eax
100*4882a593Smuzhiyun	xor %edx, %edx
101*4882a593Smuzhiyun	wrmsr
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun	call xen_prepare_pvh
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun	/* startup_64 expects boot_params in %rsi. */
106*4882a593Smuzhiyun	mov $_pa(pvh_bootparams), %rsi
107*4882a593Smuzhiyun	mov $_pa(startup_64), %rax
108*4882a593Smuzhiyun	jmp *%rax
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun#else /* CONFIG_X86_64 */
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun	/* Set base address in stack canary descriptor. */
113*4882a593Smuzhiyun	movl $_pa(gdt_start),%eax
114*4882a593Smuzhiyun	movl $_pa(canary),%ecx
115*4882a593Smuzhiyun	movw %cx, (PVH_GDT_ENTRY_CANARY * 8) + 2(%eax)
116*4882a593Smuzhiyun	shrl $16, %ecx
117*4882a593Smuzhiyun	movb %cl, (PVH_GDT_ENTRY_CANARY * 8) + 4(%eax)
118*4882a593Smuzhiyun	movb %ch, (PVH_GDT_ENTRY_CANARY * 8) + 7(%eax)
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun	mov $PVH_CANARY_SEL,%eax
121*4882a593Smuzhiyun	mov %eax,%gs
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun	call mk_early_pgtbl_32
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun	mov $_pa(initial_page_table), %eax
126*4882a593Smuzhiyun	mov %eax, %cr3
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun	mov %cr0, %eax
129*4882a593Smuzhiyun	or $(X86_CR0_PG | X86_CR0_PE), %eax
130*4882a593Smuzhiyun	mov %eax, %cr0
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun	ljmp $PVH_CS_SEL, $1f
133*4882a593Smuzhiyun1:
134*4882a593Smuzhiyun	call xen_prepare_pvh
135*4882a593Smuzhiyun	mov $_pa(pvh_bootparams), %esi
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun	/* startup_32 doesn't expect paging and PAE to be on. */
138*4882a593Smuzhiyun	ljmp $PVH_CS_SEL, $_pa(2f)
139*4882a593Smuzhiyun2:
140*4882a593Smuzhiyun	mov %cr0, %eax
141*4882a593Smuzhiyun	and $~X86_CR0_PG, %eax
142*4882a593Smuzhiyun	mov %eax, %cr0
143*4882a593Smuzhiyun	mov %cr4, %eax
144*4882a593Smuzhiyun	and $~X86_CR4_PAE, %eax
145*4882a593Smuzhiyun	mov %eax, %cr4
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun	ljmp $PVH_CS_SEL, $_pa(startup_32)
148*4882a593Smuzhiyun#endif
149*4882a593SmuzhiyunSYM_CODE_END(pvh_start_xen)
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun	.section ".init.data","aw"
152*4882a593Smuzhiyun	.balign 8
153*4882a593SmuzhiyunSYM_DATA_START_LOCAL(gdt)
154*4882a593Smuzhiyun	.word gdt_end - gdt_start
155*4882a593Smuzhiyun	.long _pa(gdt_start)
156*4882a593Smuzhiyun	.word 0
157*4882a593SmuzhiyunSYM_DATA_END(gdt)
158*4882a593SmuzhiyunSYM_DATA_START_LOCAL(gdt_start)
159*4882a593Smuzhiyun	.quad 0x0000000000000000            /* NULL descriptor */
160*4882a593Smuzhiyun#ifdef CONFIG_X86_64
161*4882a593Smuzhiyun	.quad GDT_ENTRY(0xa09a, 0, 0xfffff) /* PVH_CS_SEL */
162*4882a593Smuzhiyun#else
163*4882a593Smuzhiyun	.quad GDT_ENTRY(0xc09a, 0, 0xfffff) /* PVH_CS_SEL */
164*4882a593Smuzhiyun#endif
165*4882a593Smuzhiyun	.quad GDT_ENTRY(0xc092, 0, 0xfffff) /* PVH_DS_SEL */
166*4882a593Smuzhiyun	.quad GDT_ENTRY(0x4090, 0, 0x18)    /* PVH_CANARY_SEL */
167*4882a593SmuzhiyunSYM_DATA_END_LABEL(gdt_start, SYM_L_LOCAL, gdt_end)
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun	.balign 16
170*4882a593SmuzhiyunSYM_DATA_LOCAL(canary, .fill 48, 1, 0)
171*4882a593Smuzhiyun
172*4882a593SmuzhiyunSYM_DATA_START_LOCAL(early_stack)
173*4882a593Smuzhiyun	.fill BOOT_STACK_SIZE, 1, 0
174*4882a593SmuzhiyunSYM_DATA_END_LABEL(early_stack, SYM_L_LOCAL, early_stack_end)
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun	ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY,
177*4882a593Smuzhiyun	             _ASM_PTR (pvh_start_xen - __START_KERNEL_map))
178