[prefix] Cope with image source addresses outside base memory

When PMM is used, the gPXE image source will no longer be in base memory.
Decompression of .text16 and .data16 can therefore no longer be done in
real mode.
This commit is contained in:
Michael Brown
2008-03-11 13:26:46 +00:00
parent 9c86a39551
commit 3bf7105cab

View File

@@ -175,8 +175,9 @@ print_hex_nibble:
#ifndef KEEP_IT_REAL #ifndef KEEP_IT_REAL
/* GDT for protected-mode calls */ /* GDT for protected-mode calls */
.section ".data16" .section ".prefix.lib"
.align 16 .align 16
pm_call_vars:
gdt: gdt:
gdt_limit: .word gdt_length - 1 gdt_limit: .word gdt_length - 1
gdt_base: .long 0 gdt_base: .long 0
@@ -197,18 +198,24 @@ gdt_end:
.equ gdt_length, . - gdt .equ gdt_length, . - gdt
.size gdt, . - gdt .size gdt, . - gdt
.section ".data16" .section ".prefix.lib"
.align 16 .align 16
pm_saved_gdt: pm_saved_gdt:
.long 0, 0 .long 0, 0
.size pm_saved_gdt, . - pm_saved_gdt .size pm_saved_gdt, . - pm_saved_gdt
.equ pm_call_vars_size, . - pm_call_vars
#define PM_CALL_VAR(x) ( -pm_call_vars_size + ( (x) - pm_call_vars ) )
.section ".prefix.lib" .section ".prefix.lib"
.code16 .code16
pm_call: pm_call:
/* Preserve registers, flags, GDT, and RM return point */ /* Preserve registers, flags, and RM return point */
pushw %bp
movw %sp, %bp
subw $pm_call_vars_size, %sp
andw $0xfff0, %sp
pushfl pushfl
sgdt pm_saved_gdt
pushw %gs pushw %gs
pushw %fs pushw %fs
pushw %es pushw %es
@@ -217,27 +224,43 @@ pm_call:
pushw %cs pushw %cs
pushw $99f pushw $99f
/* Set up local variable block, and preserve GDT */
pushw %cx
pushw %si
pushw %di
pushw %ss
popw %es
movw $pm_call_vars, %si
leaw PM_CALL_VAR(pm_call_vars)(%bp), %di
movw $pm_call_vars_size, %cx
cs rep movsb
popw %di
popw %si
popw %cx
sgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
/* Set up GDT bases */ /* Set up GDT bases */
pushl %eax pushl %eax
pushw %bx pushl %edi
xorl %eax, %eax xorl %eax, %eax
movw %ds, %ax movw %ss, %ax
shll $4, %eax shll $4, %eax
addl $gdt, %eax movzwl %bp, %edi
movl %eax, gdt_base leal PM_CALL_VAR(gdt)(%eax, %edi), %eax
movl %eax, PM_CALL_VAR(gdt_base)(%bp)
movw %cs, %ax movw %cs, %ax
movw $pm_cs, %bx movw $PM_CALL_VAR(pm_cs), %di
call set_seg_base call set_seg_base
movw %ss, %ax movw %ss, %ax
movw $pm_ss, %bx movw $PM_CALL_VAR(pm_ss), %di
call set_seg_base call set_seg_base
popw %bx popl %edi
popl %eax popl %eax
/* Switch CPU to protected mode and load up segment registers */ /* Switch CPU to protected mode and load up segment registers */
pushl %eax pushl %eax
cli cli
lgdt gdt lgdt PM_CALL_VAR(gdt)(%bp)
movl %cr0, %eax movl %cr0, %eax
orb $CR0_PE, %al orb $CR0_PE, %al
movl %eax, %cr0 movl %eax, %cr0
@@ -273,18 +296,19 @@ pm_call:
popw %es popw %es
popw %fs popw %fs
popw %gs popw %gs
lgdt pm_saved_gdt lgdt PM_CALL_VAR(pm_saved_gdt)(%bp)
popfl popfl
movw %bp, %sp
popw %bp
ret ret
.size pm_call, . - pm_call .size pm_call, . - pm_call
set_seg_base: set_seg_base:
rolw $4, %ax rolw $4, %ax
movw %ax, 2(%bx) movw %ax, 2(%bp,%di)
andw $0xfff0, 2(%bx) andw $0xfff0, 2(%bp,%di)
movb %al, 4(%bx) movb %al, 4(%bp,%di)
andb $0x0f, 4(%bx) andb $0x0f, 4(%bp,%di)
ret ret
.size set_seg_base, . - set_seg_base .size set_seg_base, . - set_seg_base
@@ -301,7 +325,7 @@ set_seg_base:
* %ecx : length * %ecx : length
* Returns: * Returns:
* %ds:esi : next source address * %ds:esi : next source address
* %ds:esi : next destination address * %es:edi : next destination address
* Corrupts: * Corrupts:
* None * None
**************************************************************************** ****************************************************************************
@@ -316,27 +340,57 @@ copy_bytes:
.size copy_bytes, . - copy_bytes .size copy_bytes, . - copy_bytes
/**************************************************************************** /****************************************************************************
* install_block (real-mode or 16-bit protected-mode near call) * install_block (real-mode near call)
* *
* Install block to specified address * Install block to specified address
* *
* Parameters: * Parameters:
* %ds:esi : source address (must be a multiple of 16) * %esi : source physical address (must be a multiple of 16)
* %es:edi : destination address * %edi : destination physical address (must be a multiple of 16)
* %ecx : length of (decompressed) data * %ecx : length of (decompressed) data
* %edx : total length of block (including any uninitialised data portion) * %edx : total length of block (including any uninitialised data portion)
* Returns: * Returns:
* %ds:esi : next source address (will be a multiple of 16) * %esi : next source physical address (will be a multiple of 16)
* Corrupts: * Corrupts:
* %ecx, %edx * none
**************************************************************************** ****************************************************************************
*/ */
.section ".prefix.lib" .section ".prefix.lib"
.code16 .code16
install_block: install_block:
#ifdef KEEP_IT_REAL
/* Preserve registers */ /* Preserve registers */
pushw %ds
pushw %es
pushl %ecx
pushl %edi pushl %edi
/* Convert %esi and %edi to segment registers */
shrl $4, %esi
movw %si, %ds
xorw %si, %si
shrl $4, %edi
movw %di, %es
xorw %di, %di
#else /* KEEP_IT_REAL */
/* Call self in protected mode */
pushw %ax
movw $1f, %ax
call pm_call
popw %ax
ret
1:
/* Preserve registers */
pushl %ecx
pushl %edi
#endif /* KEEP_IT_REAL */
#if COMPRESS #if COMPRESS
/* Decompress source to destination */ /* Decompress source to destination */
call decompress16 call decompress16
@@ -357,8 +411,28 @@ install_block:
addl $0xf, %esi addl $0xf, %esi
andl $~0xf, %esi andl $~0xf, %esi
/* Restore registers and return */
#ifdef KEEP_IT_REAL
/* Convert %ds:esi back to a physical address */
movzwl %ds, %cx
shll $4, %ecx
addl %ecx, %esi
/* Restore registers */
popl %edi popl %edi
popl %ecx
popw %es
popw %ds
#else /* KEEP_IT_REAL */
/* Restore registers */
popl %edi
popl %ecx
#endif
ret ret
.size install_block, . - install_block .size install_block, . - install_block
@@ -406,87 +480,6 @@ alloc_basemem:
ret ret
.size alloc_basemem, . - alloc_basemem .size alloc_basemem, . - alloc_basemem
/****************************************************************************
* install_basemem (real-mode near call)
*
* Install source block into base memory
*
* Parameters:
* %esi : source physical address (must be a multiple of 16)
* %es : destination segment address
* %cx : length of (decompressed) data
* %dx : total length of block (including any uninitialised data portion)
* Returns:
* %esi : next source physical address (will be a multiple of 16)
* Corrupts:
* %ecx, %edx
****************************************************************************
*/
.section ".prefix.lib"
.code16
install_basemem:
/* Preserve registers */
pushl %edi
pushw %ds
/* Preserve original %esi */
pushl %esi
/* Install to specified address */
shrl $4, %esi
movw %si, %ds
xorw %si, %si
xorl %edi, %edi
movzwl %cx, %ecx
movzwl %dx, %edx
call install_block
/* Fix up %esi for return */
popl %ecx
addl %ecx, %esi
/* Restore registers */
popw %ds
popl %edi
ret
.size install_basemem, . - install_basemem
/****************************************************************************
* install_highmem (real-mode near call)
*
* Install source block into high memory
*
* Parameters:
* %esi : source physical address (must be a multiple of 16)
* %edi : destination physical address
* %ecx : length of (decompressed) data
* %edx : total length of block (including any uninitialised data portion)
* Returns:
* %esi : next source physical address (will be a multiple of 16)
* Corrupts:
* %ecx, %edx
****************************************************************************
*/
#ifndef KEEP_IT_REAL
.section ".prefix.lib"
.code16
install_highmem:
/* Preserve registers */
pushw %ax
/* Install to specified address */
movw $install_block, %ax
call pm_call
/* Restore registers */
popw %ax
ret
.size install_highmem, . - install_highmem
#endif /* KEEP_IT_REAL */
/**************************************************************************** /****************************************************************************
* install (real-mode near call) * install (real-mode near call)
* *
@@ -555,17 +548,19 @@ install_prealloc:
shll $4, %esi shll $4, %esi
1: addl $_payload_offset, %esi 1: addl $_payload_offset, %esi
/* Install .text16 */ /* Install .text16 and .data16 */
movw %ax, %es pushl %edi
movw $_text16_size, %cx movzwl %ax, %edi
movw %cx, %dx shll $4, %edi
call install_basemem movl $_text16_size, %ecx
movl %ecx, %edx
/* Install .data16 */ call install_block /* .text16 */
movw %bx, %es movzwl %bx, %edi
movw $_data16_progbits_size, %cx shll $4, %edi
movw $_data16_size, %dx movl $_data16_progbits_size, %ecx
call install_basemem movl $_data16_size, %edx
call install_block /* .data16 */
popl %edi
/* Set up %ds for access to .data16 */ /* Set up %ds for access to .data16 */
movw %bx, %ds movw %bx, %ds
@@ -581,9 +576,7 @@ install_prealloc:
*/ */
movl $_textdata_progbits_size, %ecx movl $_textdata_progbits_size, %ecx
movl $_textdata_size, %edx movl $_textdata_size, %edx
pushl %edi call install_block
call install_highmem
popl %edi
/* Initialise librm at current location */ /* Initialise librm at current location */
movw %ax, (init_librm_vector+2) movw %ax, (init_librm_vector+2)