Skip to content

Commit 47ffe05

Browse files
Jason Andryukjgross1
authored andcommitted
x86/pvh: Add 64bit relocation page tables
The PVH entry point is 32bit. For a 64bit kernel, the entry point must switch to 64bit mode, which requires a set of page tables. In the past, PVH used init_top_pgt. This works fine when the kernel is loaded at LOAD_PHYSICAL_ADDR, as the page tables are prebuilt for this address. If the kernel is loaded at a different address, they need to be adjusted. __startup_64() adjusts the prebuilt page tables for the physical load address, but it is 64bit code. The 32bit PVH entry code can't call it to adjust the page tables, so it can't readily be re-used. 64bit PVH entry needs page tables set up for identity map, the kernel high map and the direct map. pvh_start_xen() enters identity mapped. Inside xen_prepare_pvh(), it jumps through a pv_ops function pointer into the highmap. The direct map is used for __va() on the initramfs and other guest physical addresses. Add a dedicated set of prebuild page tables for PVH entry. They are adjusted in assembly before loading. Add XEN_ELFNOTE_PHYS32_RELOC to indicate support for relocation along with the kernel's loading constraints. The maximum load address, KERNEL_IMAGE_SIZE - 1, is determined by a single pvh_level2_ident_pgt page. It could be larger with more pages. Signed-off-by: Jason Andryuk <[email protected]> Reviewed-by: Juergen Gross <[email protected]> Message-ID: <[email protected]> Signed-off-by: Juergen Gross <[email protected]>
1 parent e3e8cd9 commit 47ffe05

File tree

1 file changed

+103
-1
lines changed

1 file changed

+103
-1
lines changed

arch/x86/platform/pvh/head.S

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <asm/segment.h>
1717
#include <asm/asm.h>
1818
#include <asm/boot.h>
19+
#include <asm/pgtable.h>
1920
#include <asm/processor-flags.h>
2021
#include <asm/msr.h>
2122
#include <asm/nospec-branch.h>
@@ -102,8 +103,47 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
102103
btsl $_EFER_LME, %eax
103104
wrmsr
104105

106+
mov %ebp, %ebx
107+
subl $_pa(pvh_start_xen), %ebx /* offset */
108+
jz .Lpagetable_done
109+
110+
/* Fixup page-tables for relocation. */
111+
leal rva(pvh_init_top_pgt)(%ebp), %edi
112+
movl $PTRS_PER_PGD, %ecx
113+
2:
114+
testl $_PAGE_PRESENT, 0x00(%edi)
115+
jz 1f
116+
addl %ebx, 0x00(%edi)
117+
1:
118+
addl $8, %edi
119+
decl %ecx
120+
jnz 2b
121+
122+
/* L3 ident has a single entry. */
123+
leal rva(pvh_level3_ident_pgt)(%ebp), %edi
124+
addl %ebx, 0x00(%edi)
125+
126+
leal rva(pvh_level3_kernel_pgt)(%ebp), %edi
127+
addl %ebx, (PAGE_SIZE - 16)(%edi)
128+
addl %ebx, (PAGE_SIZE - 8)(%edi)
129+
130+
/* pvh_level2_ident_pgt is fine - large pages */
131+
132+
/* pvh_level2_kernel_pgt needs adjustment - large pages */
133+
leal rva(pvh_level2_kernel_pgt)(%ebp), %edi
134+
movl $PTRS_PER_PMD, %ecx
135+
2:
136+
testl $_PAGE_PRESENT, 0x00(%edi)
137+
jz 1f
138+
addl %ebx, 0x00(%edi)
139+
1:
140+
addl $8, %edi
141+
decl %ecx
142+
jnz 2b
143+
144+
.Lpagetable_done:
105145
/* Enable pre-constructed page tables. */
106-
leal rva(init_top_pgt)(%ebp), %eax
146+
leal rva(pvh_init_top_pgt)(%ebp), %eax
107147
mov %eax, %cr3
108148
mov $(X86_CR0_PG | X86_CR0_PE), %eax
109149
mov %eax, %cr0
@@ -198,5 +238,67 @@ SYM_DATA_START_LOCAL(early_stack)
198238
.fill BOOT_STACK_SIZE, 1, 0
199239
SYM_DATA_END_LABEL(early_stack, SYM_L_LOCAL, early_stack_end)
200240

241+
#ifdef CONFIG_X86_64
242+
/*
243+
* Xen PVH needs a set of identity mapped and kernel high mapping
244+
* page tables. pvh_start_xen starts running on the identity mapped
245+
* page tables, but xen_prepare_pvh calls into the high mapping.
246+
* These page tables need to be relocatable and are only used until
247+
* startup_64 transitions to init_top_pgt.
248+
*/
249+
SYM_DATA_START_PAGE_ALIGNED(pvh_init_top_pgt)
250+
.quad pvh_level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
251+
.org pvh_init_top_pgt + L4_PAGE_OFFSET * 8, 0
252+
.quad pvh_level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
253+
.org pvh_init_top_pgt + L4_START_KERNEL * 8, 0
254+
/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
255+
.quad pvh_level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC
256+
SYM_DATA_END(pvh_init_top_pgt)
257+
258+
SYM_DATA_START_PAGE_ALIGNED(pvh_level3_ident_pgt)
259+
.quad pvh_level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
260+
.fill 511, 8, 0
261+
SYM_DATA_END(pvh_level3_ident_pgt)
262+
SYM_DATA_START_PAGE_ALIGNED(pvh_level2_ident_pgt)
263+
/*
264+
* Since I easily can, map the first 1G.
265+
* Don't set NX because code runs from these pages.
266+
*
267+
* Note: This sets _PAGE_GLOBAL despite whether
268+
* the CPU supports it or it is enabled. But,
269+
* the CPU should ignore the bit.
270+
*/
271+
PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
272+
SYM_DATA_END(pvh_level2_ident_pgt)
273+
SYM_DATA_START_PAGE_ALIGNED(pvh_level3_kernel_pgt)
274+
.fill L3_START_KERNEL, 8, 0
275+
/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
276+
.quad pvh_level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
277+
.quad 0 /* no fixmap */
278+
SYM_DATA_END(pvh_level3_kernel_pgt)
279+
280+
SYM_DATA_START_PAGE_ALIGNED(pvh_level2_kernel_pgt)
281+
/*
282+
* Kernel high mapping.
283+
*
284+
* The kernel code+data+bss must be located below KERNEL_IMAGE_SIZE in
285+
* virtual address space, which is 1 GiB if RANDOMIZE_BASE is enabled,
286+
* 512 MiB otherwise.
287+
*
288+
* (NOTE: after that starts the module area, see MODULES_VADDR.)
289+
*
290+
* This table is eventually used by the kernel during normal runtime.
291+
* Care must be taken to clear out undesired bits later, like _PAGE_RW
292+
* or _PAGE_GLOBAL in some cases.
293+
*/
294+
PMDS(0, __PAGE_KERNEL_LARGE_EXEC, KERNEL_IMAGE_SIZE / PMD_SIZE)
295+
SYM_DATA_END(pvh_level2_kernel_pgt)
296+
297+
ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_RELOC,
298+
.long CONFIG_PHYSICAL_ALIGN;
299+
.long LOAD_PHYSICAL_ADDR;
300+
.long KERNEL_IMAGE_SIZE - 1)
301+
#endif
302+
201303
ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY,
202304
_ASM_PTR (pvh_start_xen - __START_KERNEL_map))

0 commit comments

Comments
 (0)