mirror of
https://github.com/ipxe/ipxe
synced 2026-01-13 17:43:49 +03:00
[librm] Prepare for long-mode memory map
The bulk of the iPXE binary (the .textdata section) is physically relocated at runtime to the top of the 32-bit address space in order to allow space for an OS to be loaded. The relocation is achieved with the assistance of segmentation: we adjust the code and data segment bases so that the link-time addresses remain valid. Segmentation is not available (for normal code and data segments) in long mode. We choose to compile the C code with -mcmodel=kernel and use a link-time address of 0xffffffffeb000000. This choice allows us to identity-map the entirety of the 32-bit address space, and to alias our chosen link-time address to the physical location of our .textdata section. (This requires the .textdata section to always be aligned to a page boundary.) We simultaneously choose to set the 32-bit virtual address segment bases such that the link-time addresses may simply be truncated to 32 bits in order to generate a valid 32-bit virtual address. This allows symbols in .textdata to be trivially accessed by both 32-bit and 64-bit code. There is no (sensible) way in 32-bit assembly code to generate the required R_X86_64_32S relocation records for these truncated symbols. However, subtracting the fixed constant 0xffffffff00000000 has the same effect as truncation, and can be represented in a standard R_X86_64_32 relocation record. We define the VIRTUAL() macro to abstract away this truncation operation, and apply it to all references by 32-bit (or 16-bit) assembly code to any symbols within the .textdata section. We define "virt_offset" for a 64-bit build as "the value to be added to an address within .textdata in order to obtain its physical address". With this definition, the low 32 bits of "virt_offset" can be treated by 32-bit code as functionally equivalent to "virt_offset" in a 32-bit build. We define "text16" and "data16" for a 64-bit build as the physical addresses of the .text16 and .data16 sections. Since a physical address within the 32-bit address space may be used directly as a 64-bit virtual address (thanks to the identity map), this definition provides the most natural access to variables in .text16 and .data16. Note that this requires a minor adjustment in prot_to_real(), which accesses .text16 using 32-bit virtual addresses. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -7,7 +7,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
* Don't change these unless you really know what you're doing.
|
||||
*/
|
||||
|
||||
#define VIRTUAL_CS 0x08
|
||||
#define VIRTUAL_DS 0x10
|
||||
#define PHYSICAL_CS 0x18
|
||||
@@ -16,6 +15,40 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define REAL_DS 0x30
|
||||
#define P2R_DS 0x38
|
||||
|
||||
/* Calculate symbol address within VIRTUAL_CS or VIRTUAL_DS
|
||||
*
|
||||
* In a 64-bit build, we set the bases of VIRTUAL_CS and VIRTUAL_DS
|
||||
* such that truncating a .textdata symbol value to 32 bits gives a
|
||||
* valid 32-bit virtual address.
|
||||
*
|
||||
* The C code is compiled with -mcmodel=kernel and so we must place
|
||||
* all .textdata symbols within the negative 2GB of the 64-bit address
|
||||
* space. Consequently, all .textdata symbols will have the MSB set
|
||||
* after truncation to 32 bits. This means that a straightforward
|
||||
* R_X86_64_32 relocation record for the symbol will fail, since the
|
||||
* truncated symbol value will not correctly zero-extend to the
|
||||
* original 64-bit value.
|
||||
*
|
||||
* Using an R_X86_64_32S relocation record would work, but there is no
|
||||
* (sensible) way to generate these relocation records within 32-bit
|
||||
* or 16-bit code.
|
||||
*
|
||||
* The simplest solution is to generate an R_X86_64_32 relocation
|
||||
* record with an addend of (-0xffffffff00000000). Since all
|
||||
* .textdata symbols are within the negative 2GB of the 64-bit address
|
||||
* space, this addend acts to effectively truncate the symbol to 32
|
||||
* bits, thereby matching the semantics of the R_X86_64_32 relocation
|
||||
* records generated for 32-bit and 16-bit code.
|
||||
*
|
||||
* In a 32-bit build, this problem does not exist, and we can just use
|
||||
* the .textdata symbol values directly.
|
||||
*/
|
||||
#ifdef __x86_64__
|
||||
#define VIRTUAL(address) ( (address) - 0xffffffff00000000 )
|
||||
#else
|
||||
#define VIRTUAL(address) (address)
|
||||
#endif
|
||||
|
||||
#ifdef ASSEMBLY
|
||||
|
||||
/**
|
||||
@@ -24,7 +57,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* @v function C function
|
||||
*/
|
||||
.macro virtcall function
|
||||
pushl $\function
|
||||
pushl $VIRTUAL(\function)
|
||||
call prot_call
|
||||
.endm
|
||||
|
||||
@@ -42,7 +75,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* @v function C function
|
||||
*/
|
||||
#define VIRT_CALL( function ) \
|
||||
"pushl $( " #function " )\n\t" \
|
||||
"pushl $( " _S2 ( VIRTUAL ( function ) ) " )\n\t" \
|
||||
"call prot_call\n\t"
|
||||
|
||||
/* Variables in librm.S */
|
||||
|
||||
Reference in New Issue
Block a user