The 2 code paths were sharing quite some common code, reuse it instead
of having duplications.
Use %dl register to store boot type before running common code.
Using a 8 bit register reduces code size.
Signed-off-by: Frediano Ziglio <frediano.ziglio@cloud.com>
---
Changes since v1:
- use %dl instead of %ebp to reduce code size;
- fold cli instruction;
- update some comments.
---
xen/arch/x86/boot/head.S | 117 +++++++++++++++------------------------
1 file changed, 45 insertions(+), 72 deletions(-)
diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S
index fa21024042..80bba6ff21 100644
--- a/xen/arch/x86/boot/head.S
+++ b/xen/arch/x86/boot/head.S
@@ -25,6 +25,9 @@
#define MB2_HT(name) (MULTIBOOT2_HEADER_TAG_##name)
#define MB2_TT(name) (MULTIBOOT2_TAG_TYPE_##name)
+#define BOOT_TYPE_BIOS 1
+#define BOOT_TYPE_PVH 2
+
.macro mb2ht_args arg:req, args:vararg
.long \arg
.ifnb \args
@@ -409,17 +412,31 @@ cs32_switch:
ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, .long sym_offs(__pvh_start))
__pvh_start:
- cld
+ mov $BOOT_TYPE_PVH, %dl
+ jmp .Lcommon_bios_pvh
+#endif /* CONFIG_PVH_GUEST */
+
+__start:
+ mov $BOOT_TYPE_BIOS, %dl
+
+.Lcommon_bios_pvh:
cli
+ cld
/*
- * We need one call (i.e. push) to determine the load address. See
- * __start for a discussion on how to do this safely using the PVH
- * info structure.
+ * Multiboot (both 1 and 2) and PVH specify the stack pointer as
+ * undefined. This is unhelpful for relocatable images, where one
+ * call (i.e. push) is required to calculate the image's load address.
+ *
+ * Durig BIOS boot, there is one area of memory we know about with
+ * reasonable confidence that it isn't overlapped by Xen, and that's
+ * the Multiboot info structure in %ebx. Use it as a temporary stack.
+ *
+ * During PVH boot use info structure in %ebx.
*/
/* Preserve the field we're about to clobber. */
- mov (%ebx), %edx
+ mov (%ebx), %ecx
lea 4(%ebx), %esp
/* Calculate the load base address. */
@@ -428,19 +445,12 @@ __pvh_start:
sub $sym_offs(1b), %esi
/* Restore the clobbered field. */
- mov %edx, (%ebx)
+ mov %ecx, (%ebx)
/* Set up stack. */
lea STACK_SIZE - CPUINFO_sizeof + sym_esi(cpu0_stack), %esp
- call .Linitialise_bss
-
- mov %ebx, sym_esi(pvh_start_info_pa)
-
- /* Force xen console. Will revert to user choice in init code. */
- movb $-1, sym_esi(opt_console_xen)
-
- /* Prepare gdt and segments */
+ /* Initialize GDTR and basic data segments. */
add %esi, sym_esi(gdt_boot_base)
lgdt sym_esi(gdt_boot_descr)
@@ -449,62 +459,40 @@ __pvh_start:
mov %ecx, %es
mov %ecx, %ss
- /* Skip bootloader setup and bios setup, go straight to trampoline */
- movb $1, sym_esi(pvh_boot)
- movb $1, sym_esi(skip_realmode)
-
- /* Set trampoline_phys to use mfn 1 to avoid having a mapping at VA 0 */
- movw $0x1000, sym_esi(trampoline_phys)
- mov (%ebx), %eax /* mov $XEN_HVM_START_MAGIC_VALUE, %eax */
- jmp trampoline_setup
-
-#endif /* CONFIG_PVH_GUEST */
+ /* Load null selector to unused segment registers. */
+ xor %ecx, %ecx
+ mov %ecx, %fs
+ mov %ecx, %gs
-.Linitialise_bss:
/* Initialise the BSS. */
- mov %eax, %edx
-
+ mov %eax, %ebp
lea sym_esi(__bss_start), %edi
lea sym_esi(__bss_end), %ecx
sub %edi, %ecx
xor %eax, %eax
shr $2, %ecx
rep stosl
+ mov %ebp, %eax
- mov %edx, %eax
- ret
-
-__start:
- cld
- cli
-
- /*
- * Multiboot (both 1 and 2) specify the stack pointer as undefined
- * when entering in BIOS circumstances. This is unhelpful for
- * relocatable images, where one call (i.e. push) is required to
- * calculate the image's load address.
- *
- * This early in boot, there is one area of memory we know about with
- * reasonable confidence that it isn't overlapped by Xen, and that's
- * the Multiboot info structure in %ebx. Use it as a temporary stack.
- */
-
- /* Preserve the field we're about to clobber. */
- mov (%ebx), %edx
- lea 4(%ebx), %esp
+#ifdef CONFIG_PVH_GUEST
+ cmp $BOOT_TYPE_PVH, %dl
+ jne 1f
- /* Calculate the load base address. */
- call 1f
-1: pop %esi
- sub $sym_offs(1b), %esi
+ mov %ebx, sym_esi(pvh_start_info_pa)
- /* Restore the clobbered field. */
- mov %edx, (%ebx)
+ /* Force xen console. Will revert to user choice in init code. */
+ movb $-1, sym_esi(opt_console_xen)
- /* Set up stack. */
- lea STACK_SIZE - CPUINFO_sizeof + sym_esi(cpu0_stack), %esp
+ /* Skip bootloader setup and bios setup, go straight to trampoline */
+ movb $1, sym_esi(pvh_boot)
+ movb $1, sym_esi(skip_realmode)
- call .Linitialise_bss
+ /* Set trampoline_phys to use mfn 1 to avoid having a mapping at VA 0 */
+ movl $PAGE_SIZE, sym_esi(trampoline_phys)
+ mov (%ebx), %eax /* mov $XEN_HVM_START_MAGIC_VALUE, %eax */
+ jmp trampoline_setup
+1:
+#endif /* CONFIG_PVH_GUEST */
/* Bootloaders may set multiboot{1,2}.mem_lower to a nonzero value. */
xor %edx,%edx
@@ -563,22 +551,7 @@ __start:
trampoline_bios_setup:
/*
* Called on legacy BIOS platforms only.
- *
- * Initialize GDTR and basic data segments.
*/
- add %esi,sym_esi(gdt_boot_base)
- lgdt sym_esi(gdt_boot_descr)
-
- mov $BOOT_DS,%ecx
- mov %ecx,%ds
- mov %ecx,%es
- mov %ecx,%ss
- /* %esp is initialized later. */
-
- /* Load null descriptor to unused segment registers. */
- xor %ecx,%ecx
- mov %ecx,%fs
- mov %ecx,%gs
/* Set up trampoline segment 64k below EBDA */
movzwl 0x40e,%ecx /* EBDA segment */
--
2.34.1
On 24/09/2024 11:28 am, Frediano Ziglio wrote: > diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S > index fa21024042..80bba6ff21 100644 > --- a/xen/arch/x86/boot/head.S > +++ b/xen/arch/x86/boot/head.S > ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, .long sym_offs(__pvh_start)) > > __pvh_start: > - cld > + mov $BOOT_TYPE_PVH, %dl > + jmp .Lcommon_bios_pvh > +#endif /* CONFIG_PVH_GUEST */ > + > +__start: > + mov $BOOT_TYPE_BIOS, %dl Even if we're generally using %dl, these must be full %edx writes. %edx commonly contains FMS on entry, and we don't want part of FMS left in the upper half of the register. > + > +.Lcommon_bios_pvh: > cli > + cld > > /* > - * We need one call (i.e. push) to determine the load address. See > - * __start for a discussion on how to do this safely using the PVH > - * info structure. > + * Multiboot (both 1 and 2) and PVH specify the stack pointer as > + * undefined. This is unhelpful for relocatable images, where one > + * call (i.e. push) is required to calculate the image's load address. > + * > + * Durig BIOS boot, there is one area of memory we know about with > + * reasonable confidence that it isn't overlapped by Xen, and that's > + * the Multiboot info structure in %ebx. Use it as a temporary stack. > + * > + * During PVH boot use info structure in %ebx. > */ > > /* Preserve the field we're about to clobber. */ > - mov (%ebx), %edx > + mov (%ebx), %ecx Both here, and ... > lea 4(%ebx), %esp > > /* Calculate the load base address. */ > @@ -449,62 +459,40 @@ __pvh_start: > mov %ecx, %es > mov %ecx, %ss > > - /* Skip bootloader setup and bios setup, go straight to trampoline */ > - movb $1, sym_esi(pvh_boot) > - movb $1, sym_esi(skip_realmode) > - > - /* Set trampoline_phys to use mfn 1 to avoid having a mapping at VA 0 */ > - movw $0x1000, sym_esi(trampoline_phys) > - mov (%ebx), %eax /* mov $XEN_HVM_START_MAGIC_VALUE, %eax */ > - jmp trampoline_setup > - > -#endif /* CONFIG_PVH_GUEST */ > + /* Load null selector to unused segment registers. */ > + xor %ecx, %ecx > + mov %ecx, %fs > + mov %ecx, %gs > > -.Linitialise_bss: > /* Initialise the BSS. */ > - mov %eax, %edx > - > + mov %eax, %ebp ... here, we've got changes caused by now using %edx for a long-lived purpose (and a change in linebreaks.) For this, %ebp should be used straight away in patch 1. I've not committed it yet, so can fix that up. I have to admit that I think this patch would be easier if the "use %ebx for BOOT_TYPE_*" change was split out of "better merge the BIOS/PVH paths". That would at least get the incidental %edx changes out of the way. Also, inserting #ifdef CONFIG_PVH_GUEST cmp $BOOT_TYPE_PVH, %dl jne 1f 1: #endif /* CONFIG_PVH_GUEST */ in the same patch will probably make the subsequent diff far more legible. Thoughts? I might give this a quick go, and see how it ends up looking... ~Andrew
On 24/09/2024 2:25 pm, Andrew Cooper wrote: > On 24/09/2024 11:28 am, Frediano Ziglio wrote: >> diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S >> index fa21024042..80bba6ff21 100644 >> --- a/xen/arch/x86/boot/head.S >> +++ b/xen/arch/x86/boot/head.S >> ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, .long sym_offs(__pvh_start)) >> >> __pvh_start: >> - cld >> + mov $BOOT_TYPE_PVH, %dl >> + jmp .Lcommon_bios_pvh >> +#endif /* CONFIG_PVH_GUEST */ >> + >> +__start: >> + mov $BOOT_TYPE_BIOS, %dl > Even if we're generally using %dl, these must be full %edx writes. > > %edx commonly contains FMS on entry, and we don't want part of FMS left > in the upper half of the register. > >> + >> +.Lcommon_bios_pvh: >> cli >> + cld >> >> /* >> - * We need one call (i.e. push) to determine the load address. See >> - * __start for a discussion on how to do this safely using the PVH >> - * info structure. >> + * Multiboot (both 1 and 2) and PVH specify the stack pointer as >> + * undefined. This is unhelpful for relocatable images, where one >> + * call (i.e. push) is required to calculate the image's load address. >> + * >> + * Durig BIOS boot, there is one area of memory we know about with >> + * reasonable confidence that it isn't overlapped by Xen, and that's >> + * the Multiboot info structure in %ebx. Use it as a temporary stack. >> + * >> + * During PVH boot use info structure in %ebx. >> */ >> >> /* Preserve the field we're about to clobber. */ >> - mov (%ebx), %edx >> + mov (%ebx), %ecx > Both here, and ... > >> lea 4(%ebx), %esp >> >> /* Calculate the load base address. */ >> @@ -449,62 +459,40 @@ __pvh_start: >> mov %ecx, %es >> mov %ecx, %ss >> >> - /* Skip bootloader setup and bios setup, go straight to trampoline */ >> - movb $1, sym_esi(pvh_boot) >> - movb $1, sym_esi(skip_realmode) >> - >> - /* Set trampoline_phys to use mfn 1 to avoid having a mapping at VA 0 */ >> - movw $0x1000, sym_esi(trampoline_phys) >> - mov (%ebx), %eax /* mov $XEN_HVM_START_MAGIC_VALUE, %eax */ >> - jmp trampoline_setup >> - >> -#endif /* CONFIG_PVH_GUEST */ >> + /* Load null selector to unused segment registers. */ >> + xor %ecx, %ecx >> + mov %ecx, %fs >> + mov %ecx, %gs >> >> -.Linitialise_bss: >> /* Initialise the BSS. */ >> - mov %eax, %edx >> - >> + mov %eax, %ebp > ... here, we've got changes caused by now using %edx for a long-lived > purpose (and a change in linebreaks.) > > For this, %ebp should be used straight away in patch 1. I've not > committed it yet, so can fix that up. > > > I have to admit that I think this patch would be easier if the "use %ebx > for BOOT_TYPE_*" change was split out of "better merge the BIOS/PVH > paths". That would at least get the incidental %edx changes out of the way. > > Also, inserting > > #ifdef CONFIG_PVH_GUEST > cmp $BOOT_TYPE_PVH, %dl > jne 1f > 1: > #endif /* CONFIG_PVH_GUEST */ > > in the same patch will probably make the subsequent diff far more legible. > > Thoughts? > > I might give this a quick go, and see how it ends up looking... Actually, why do we need BOOT_TYPE_* at all? We've already got BOOTLOADER_MAGIC in %eax which can be used to identify PVH. ~Andrew
On 24/09/2024 2:30 pm, Andrew Cooper wrote: > On 24/09/2024 2:25 pm, Andrew Cooper wrote: >> On 24/09/2024 11:28 am, Frediano Ziglio wrote: >>> diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S >>> index fa21024042..80bba6ff21 100644 >>> --- a/xen/arch/x86/boot/head.S >>> +++ b/xen/arch/x86/boot/head.S >>> ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, .long sym_offs(__pvh_start)) >>> >>> __pvh_start: >>> - cld >>> + mov $BOOT_TYPE_PVH, %dl >>> + jmp .Lcommon_bios_pvh >>> +#endif /* CONFIG_PVH_GUEST */ >>> + >>> +__start: >>> + mov $BOOT_TYPE_BIOS, %dl >> Even if we're generally using %dl, these must be full %edx writes. >> >> %edx commonly contains FMS on entry, and we don't want part of FMS left >> in the upper half of the register. >> >>> + >>> +.Lcommon_bios_pvh: >>> cli >>> + cld >>> >>> /* >>> - * We need one call (i.e. push) to determine the load address. See >>> - * __start for a discussion on how to do this safely using the PVH >>> - * info structure. >>> + * Multiboot (both 1 and 2) and PVH specify the stack pointer as >>> + * undefined. This is unhelpful for relocatable images, where one >>> + * call (i.e. push) is required to calculate the image's load address. >>> + * >>> + * Durig BIOS boot, there is one area of memory we know about with >>> + * reasonable confidence that it isn't overlapped by Xen, and that's >>> + * the Multiboot info structure in %ebx. Use it as a temporary stack. >>> + * >>> + * During PVH boot use info structure in %ebx. >>> */ >>> >>> /* Preserve the field we're about to clobber. */ >>> - mov (%ebx), %edx >>> + mov (%ebx), %ecx >> Both here, and ... >> >>> lea 4(%ebx), %esp >>> >>> /* Calculate the load base address. */ >>> @@ -449,62 +459,40 @@ __pvh_start: >>> mov %ecx, %es >>> mov %ecx, %ss >>> >>> - /* Skip bootloader setup and bios setup, go straight to trampoline */ >>> - movb $1, sym_esi(pvh_boot) >>> - movb $1, sym_esi(skip_realmode) >>> - >>> - /* Set trampoline_phys to use mfn 1 to avoid having a mapping at VA 0 */ >>> - movw $0x1000, sym_esi(trampoline_phys) >>> - mov (%ebx), %eax /* mov $XEN_HVM_START_MAGIC_VALUE, %eax */ >>> - jmp trampoline_setup >>> - >>> -#endif /* CONFIG_PVH_GUEST */ >>> + /* Load null selector to unused segment registers. */ >>> + xor %ecx, %ecx >>> + mov %ecx, %fs >>> + mov %ecx, %gs >>> >>> -.Linitialise_bss: >>> /* Initialise the BSS. */ >>> - mov %eax, %edx >>> - >>> + mov %eax, %ebp >> ... here, we've got changes caused by now using %edx for a long-lived >> purpose (and a change in linebreaks.) >> >> For this, %ebp should be used straight away in patch 1. I've not >> committed it yet, so can fix that up. >> >> >> I have to admit that I think this patch would be easier if the "use %ebx >> for BOOT_TYPE_*" change was split out of "better merge the BIOS/PVH >> paths". That would at least get the incidental %edx changes out of the way. >> >> Also, inserting >> >> #ifdef CONFIG_PVH_GUEST >> cmp $BOOT_TYPE_PVH, %dl >> jne 1f >> 1: >> #endif /* CONFIG_PVH_GUEST */ >> >> in the same patch will probably make the subsequent diff far more legible. >> >> Thoughts? >> >> I might give this a quick go, and see how it ends up looking... > Actually, why do we need BOOT_TYPE_* at all? We've already got > BOOTLOADER_MAGIC in %eax which can be used to identify PVH. Summary of the "quick look". The suggested empty ifdefary doesn't really help. However, moving the mov (%ebx), %eax /* mov $XEN_HVM_START_MAGIC_VALUE, %eax */ into __pvh_entry avoids the need for any BOOT_TYPE_* being held in %edx. The one place where it's needed can be `cmp $XEN_ ...; jne` and this avoids needing to shuffle the register scheduling. ~Andrew
© 2016 - 2025 Red Hat, Inc.