Skip to content

Commit 1db29f9

Browse files
Jason Andryukjgross1
authored andcommitted
x86/pvh: Make PVH entrypoint PIC for x86-64
The PVH entrypoint is 32bit non-PIC code running the uncompressed vmlinux at its load address CONFIG_PHYSICAL_START - default 0x1000000 (16MB). The kernel is loaded at that physical address inside the VM by the VMM software (Xen/QEMU). When running a Xen PVH Dom0, the host reserved addresses are mapped 1-1 into the PVH container. There exist system firmwares (Coreboot/EDK2) with reserved memory at 16MB. This creates a conflict where the PVH kernel cannot be loaded at that address. Modify the PVH entrypoint to be position-indepedent to allow flexibility in load address. Only the 64bit entry path is converted. A 32bit kernel is not PIC, so calling into other parts of the kernel, like xen_prepare_pvh() and mk_pgtable_32(), don't work properly when relocated. This makes the code PIC, but the page tables need to be updated as well to handle running from the kernel high map. The UNWIND_HINT_END_OF_STACK is to silence: vmlinux.o: warning: objtool: pvh_start_xen+0x7f: unreachable instruction after the lret into 64bit code. 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 08377ed commit 1db29f9

File tree

1 file changed

+34
-12
lines changed

1 file changed

+34
-12
lines changed

arch/x86/platform/pvh/head.S

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
.code32
88
.text
99
#define _pa(x) ((x) - __START_KERNEL_map)
10+
#define rva(x) ((x) - pvh_start_xen)
1011

1112
#include <linux/elfnote.h>
1213
#include <linux/init.h>
@@ -54,22 +55,40 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
5455
UNWIND_HINT_END_OF_STACK
5556
cld
5657

57-
lgdt (_pa(gdt))
58+
/*
59+
* See the comment for startup_32 for more details. We need to
60+
* execute a call to get the execution address to be position
61+
* independent, but we don't have a stack. Save and restore the
62+
* magic field of start_info in ebx, and use that as the stack.
63+
*/
64+
mov (%ebx), %eax
65+
leal 4(%ebx), %esp
66+
ANNOTATE_INTRA_FUNCTION_CALL
67+
call 1f
68+
1: popl %ebp
69+
mov %eax, (%ebx)
70+
subl $rva(1b), %ebp
71+
movl $0, %esp
72+
73+
leal rva(gdt)(%ebp), %eax
74+
leal rva(gdt_start)(%ebp), %ecx
75+
movl %ecx, 2(%eax)
76+
lgdt (%eax)
5877

5978
mov $PVH_DS_SEL,%eax
6079
mov %eax,%ds
6180
mov %eax,%es
6281
mov %eax,%ss
6382

6483
/* Stash hvm_start_info. */
65-
mov $_pa(pvh_start_info), %edi
84+
leal rva(pvh_start_info)(%ebp), %edi
6685
mov %ebx, %esi
67-
mov _pa(pvh_start_info_sz), %ecx
86+
movl rva(pvh_start_info_sz)(%ebp), %ecx
6887
shr $2,%ecx
6988
rep
7089
movsl
7190

72-
mov $_pa(early_stack_end), %esp
91+
leal rva(early_stack_end)(%ebp), %esp
7392

7493
/* Enable PAE mode. */
7594
mov %cr4, %eax
@@ -84,30 +103,33 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
84103
wrmsr
85104

86105
/* Enable pre-constructed page tables. */
87-
mov $_pa(init_top_pgt), %eax
106+
leal rva(init_top_pgt)(%ebp), %eax
88107
mov %eax, %cr3
89108
mov $(X86_CR0_PG | X86_CR0_PE), %eax
90109
mov %eax, %cr0
91110

92111
/* Jump to 64-bit mode. */
93-
ljmp $PVH_CS_SEL, $_pa(1f)
112+
pushl $PVH_CS_SEL
113+
leal rva(1f)(%ebp), %eax
114+
pushl %eax
115+
lretl
94116

95117
/* 64-bit entry point. */
96118
.code64
97119
1:
120+
UNWIND_HINT_END_OF_STACK
121+
98122
/* Set base address in stack canary descriptor. */
99123
mov $MSR_GS_BASE,%ecx
100-
mov $_pa(canary), %eax
124+
leal canary(%rip), %eax
101125
xor %edx, %edx
102126
wrmsr
103127

104128
call xen_prepare_pvh
105129

106130
/* 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
131+
lea pvh_bootparams(%rip), %rsi
132+
jmp startup_64
111133

112134
#else /* CONFIG_X86_64 */
113135

@@ -143,7 +165,7 @@ SYM_CODE_END(pvh_start_xen)
143165
.balign 8
144166
SYM_DATA_START_LOCAL(gdt)
145167
.word gdt_end - gdt_start
146-
.long _pa(gdt_start)
168+
.long _pa(gdt_start) /* x86-64 will overwrite if relocated. */
147169
.word 0
148170
SYM_DATA_END(gdt)
149171
SYM_DATA_START_LOCAL(gdt_start)

0 commit comments

Comments
 (0)