[prefix] Cope with image source addresses outside base memory
authorMichael Brown <mcb30@etherboot.org>
Tue, 11 Mar 2008 13:26:46 +0000 (13:26 +0000)
committerMichael Brown <mcb30@etherboot.org>
Tue, 11 Mar 2008 13:26:46 +0000 (13:26 +0000)
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.

src/arch/i386/prefix/libprefix.S

index bf26358..deea5ab 100644 (file)
@@ -175,13 +175,14 @@ print_hex_nibble:
 #ifndef KEEP_IT_REAL
 
        /* GDT for protected-mode calls */
-       .section ".data16"
+       .section ".prefix.lib"
        .align 16
+pm_call_vars:
 gdt:
 gdt_limit:             .word gdt_length - 1
 gdt_base:              .long 0
                        .word 0 /* padding */
-pm_cs:         /* 16-bit protected-mode code segment */
+pm_cs:         /* 16-bit protected-mode code segment */        
        .equ    PM_CS, pm_cs - gdt
        .word   0xffff, 0
        .byte   0, 0x9b, 0x00, 0
@@ -197,18 +198,24 @@ gdt_end:
        .equ    gdt_length, . - gdt
        .size   gdt, . - gdt
 
-       .section ".data16"
+       .section ".prefix.lib"
        .align 16
 pm_saved_gdt:  
        .long   0, 0
        .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"
        .code16
 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
-       sgdt    pm_saved_gdt
        pushw   %gs
        pushw   %fs
        pushw   %es
@@ -217,27 +224,43 @@ pm_call:
        pushw   %cs
        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 */
        pushl   %eax
-       pushw   %bx
+       pushl   %edi
        xorl    %eax, %eax
-       movw    %ds, %ax
+       movw    %ss, %ax
        shll    $4, %eax
-       addl    $gdt, %eax
-       movl    %eax, gdt_base
+       movzwl  %bp, %edi
+       leal    PM_CALL_VAR(gdt)(%eax, %edi), %eax
+       movl    %eax, PM_CALL_VAR(gdt_base)(%bp)
        movw    %cs, %ax
-       movw    $pm_cs, %bx
+       movw    $PM_CALL_VAR(pm_cs), %di
        call    set_seg_base
        movw    %ss, %ax
-       movw    $pm_ss, %bx
+       movw    $PM_CALL_VAR(pm_ss), %di
        call    set_seg_base
-       popw    %bx
+       popl    %edi
        popl    %eax
 
        /* Switch CPU to protected mode and load up segment registers */
        pushl   %eax
        cli
-       lgdt    gdt
+       lgdt    PM_CALL_VAR(gdt)(%bp)
        movl    %cr0, %eax
        orb     $CR0_PE, %al
        movl    %eax, %cr0
@@ -273,18 +296,19 @@ pm_call:
        popw    %es
        popw    %fs
        popw    %gs
-       lgdt    pm_saved_gdt
+       lgdt    PM_CALL_VAR(pm_saved_gdt)(%bp)
        popfl
-
+       movw    %bp, %sp
+       popw    %bp
        ret
        .size pm_call, . - pm_call
 
 set_seg_base:
        rolw    $4, %ax
-       movw    %ax, 2(%bx)
-       andw    $0xfff0, 2(%bx)
-       movb    %al, 4(%bx)
-       andb    $0x0f, 4(%bx)
+       movw    %ax, 2(%bp,%di)
+       andw    $0xfff0, 2(%bp,%di)
+       movb    %al, 4(%bp,%di)
+       andb    $0x0f, 4(%bp,%di)
        ret
        .size set_seg_base, . - set_seg_base
 
@@ -301,7 +325,7 @@ set_seg_base:
  *   %ecx : length
  * Returns:
  *   %ds:esi : next source address
- *   %ds:esi : next destination address
+ *   %es:edi : next destination address
  * Corrupts:
  *   None
  ****************************************************************************
@@ -316,27 +340,57 @@ 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
  *
  * Parameters:
- *   %ds:esi : source address (must be a multiple of 16)
- *   %es:edi : destination address
+ *   %esi : source physical address (must be a multiple of 16)
+ *   %edi : destination physical address (must be a multiple of 16)
  *   %ecx : length of (decompressed) data
  *   %edx : total length of block (including any uninitialised data portion)
  * Returns:
- *   %ds:esi : next source address (will be a multiple of 16)
+ *   %esi : next source physical address (will be a multiple of 16)
  * Corrupts:
- *   %ecx, %edx
+ *   none
  ****************************************************************************
  */
        .section ".prefix.lib"
        .code16
 install_block:
+       
+#ifdef KEEP_IT_REAL
+
+       /* Preserve registers */
+       pushw   %ds
+       pushw   %es
+       pushl   %ecx
+       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
        /* Decompress source to destination */
        call    decompress16
@@ -357,8 +411,28 @@ install_block:
        addl    $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    %ecx
+       popw    %es
+       popw    %ds
+
+#else /* KEEP_IT_REAL */
+
+       /* Restore registers */
+       popl    %edi
+       popl    %ecx
+
+#endif
+
        ret
        .size install_block, . - install_block
        
@@ -406,87 +480,6 @@ alloc_basemem:
        ret
        .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)
  *
@@ -555,17 +548,19 @@ install_prealloc:
        shll    $4, %esi
 1:     addl    $_payload_offset, %esi
 
-       /* Install .text16 */
-       movw    %ax, %es
-       movw    $_text16_size, %cx
-       movw    %cx, %dx
-       call    install_basemem
-
-       /* Install .data16 */
-       movw    %bx, %es
-       movw    $_data16_progbits_size, %cx
-       movw    $_data16_size, %dx
-       call    install_basemem
+       /* Install .text16 and .data16 */
+       pushl   %edi
+       movzwl  %ax, %edi
+       shll    $4, %edi
+       movl    $_text16_size, %ecx
+       movl    %ecx, %edx
+       call    install_block           /* .text16 */
+       movzwl  %bx, %edi
+       shll    $4, %edi
+       movl    $_data16_progbits_size, %ecx
+       movl    $_data16_size, %edx
+       call    install_block           /* .data16 */
+       popl    %edi
 
        /* Set up %ds for access to .data16 */
        movw    %bx, %ds
@@ -581,9 +576,7 @@ install_prealloc:
         */
        movl    $_textdata_progbits_size, %ecx
        movl    $_textdata_size, %edx
-       pushl   %edi
-       call    install_highmem
-       popl    %edi
+       call    install_block
 
        /* Initialise librm at current location */
        movw    %ax, (init_librm_vector+2)