x86/boot: Preserve the value clobbered by the load-base calculation

Right now, Xen clobbers the value at 0xffc when performing it's load-base
calculation.  We've got plenty of free registers at this point, so the value
can be preserved easily.

This fixes a real bug booting under Coreboot+SeaBIOS, where 0xffc happens to
be the cbmem pointer (e.g. Coreboot's dmesg ring, among other things).

However, there's also a better choice of memory location to use than 0xffc, as
all our supported boot protocols have a pointer to an info structure in %ebx.

Update the documentation to match.

Fixes: 1695e53851 ("x86/boot: Fix the boot time relocation calculations")
Fixes: d96bb172e8 ("x86/entry: Early PVH boot code")
Signed-off-by: Frediano Ziglio <frediano.ziglio@cloud.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jason Andryuk <jason.andryuk@amd.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Frediano Ziglio authored and Andrew Cooper committed 2024-08-27 18:08:19 +01:00
1 parent b8cdfac2be
commit e58a2858d5
2 files changed
+31 -14

No files matched your search

+9 -3
View File
@@ -96,6 +96,12 @@ Xen, once loaded into memory, identifies its position in order to relocate
system structures. For 32bit entrypoints, this necessarily requires a call
instruction, and therefore a stack, but none of the ABIs provide one.
Overall, given that on a BIOS-based system, the IVT and BDA occupy the first
5/16ths of the first page of RAM, with the rest free to use, Xen assumes the
top of the page is safe to use.
In each supported 32bit entry protocol, ``%ebx`` is a pointer to an info
structure, and it is highly likely that this structure does not overlap with
Xen. Therefore we use this as a temporary stack, preserving the prior value,
in order to calculate Xen's position in memory.
If this heuristic happens to be wrong (most likely because we were booted by
some other protocol), the calculation stills works as long as ``%ebx`` points
at RAM and does not alias the currently-executing instructions. This is
reasonably likely, and the best we can manage given no other information.
+22 -11
View File
@@ -414,17 +414,23 @@ __pvh_start:
cli
/*
* We need one push/pop to determine load address. Use the same
* absolute stack address as the native path, for lack of a better
* alternative.
* 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.
*/
mov $0x1000, %esp
/* Preserve the field we're about to clobber. */
mov (%ebx), %edx
lea 4(%ebx), %esp
/* Calculate the load base address. */
call 1f
1: pop %esi
sub $sym_offs(1b), %esi
/* Restore the clobbered field. */
mov %edx, (%ebx)
/* Set up stack. */
lea STACK_SIZE - CPUINFO_sizeof + sym_esi(cpu0_stack), %esp
@@ -460,21 +466,26 @@ __start:
/*
* Multiboot (both 1 and 2) specify the stack pointer as undefined
* when entering in BIOS circumstances. This is unhelpful for
* relocatable images, where one push/pop is required to calculate
* images load address.
* relocatable images, where one call (i.e. push) is required to
* calculate the image's load address.
*
* On a BIOS-based system, the IVT and BDA occupy the first 5/16ths of
* the first page of RAM, with the rest free for use. Use the top of
* this page for a temporary stack, being one of the safest locations
* to clobber.
* 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.
*/
mov $0x1000, %esp
/* Preserve the field we're about to clobber. */
mov (%ebx), %edx
lea 4(%ebx), %esp
/* Calculate the load base address. */
call 1f
1: pop %esi
sub $sym_offs(1b), %esi
/* Restore the clobbered field. */
mov %edx, (%ebx)
/* Set up stack. */
lea STACK_SIZE - CPUINFO_sizeof + sym_esi(cpu0_stack), %esp
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.