Message ID | 20240924102811.86884-3-frediano.ziglio@cloud.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | x86/boot: Reduce assembly code | expand |
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
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 */
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(-)