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