Merge from Etherboot 5.4
[people/andreif/gpxe.git] / src / arch / i386 / core / start32.S
index 6dc3f20..37ef5eb 100644 (file)
@@ -1,18 +1,5 @@
-/* #defines because ljmp wants a number, probably gas bug */
-/*     .equ    KERN_CODE_SEG,_pmcs-_gdt        */
-#define        KERN_CODE_SEG   0x08
-       .equ    KERN_DATA_SEG,_pmds-_gdt
-/*     .equ    REAL_CODE_SEG,_rmcs-_gdt        */
-#define        REAL_CODE_SEG   0x18
-       .equ    REAL_DATA_SEG,_rmds-_gdt
-       .equ    FLAT_CODE_SEG,_pmcs2-_gdt
-       .equ    FLAT_DATA_SEG,_pmds2-_gdt
-       .equ    CR0_PE,1
-#ifdef CONFIG_X86_64
-       .equ    LM_CODE_SEG,  _lmcs-_gdt
-       .equ    LM_DATA_SEG,  _lmds-_gdt
-#endif
-
+#include "virtaddr.h"
+       
        .equ    MSR_K6_EFER,   0xC0000080
        .equ    EFER_LME,      0x00000100
        .equ    X86_CR4_PAE,   0x00000020
 #define        LJMPI(x)        ljmp    x
 #endif
 
-#define BOCHSBP xchgw %bx, %bx
-
-#include "callbacks.h"
-#define NUM_PUSHA_REGS (8)
-#define NUM_SEG_REGS (6)
-       
 /*
  * NOTE: if you write a subroutine that is called from C code (gcc/egcs),
  * then you only have to take care of %ebx, %esi, %edi and %ebp.  These
  * deal correctly with 16 bit return addresses.  I tried it, but failed.
  */
 
-/**************************************************************************
- * START
- *
- * This file is no longer enterered from the top.  init.S will jump to
- * either _in_call or _rm_in_call, depending on the processor mode
- * when init.S was entered.
- **************************************************************************/
        .text
        .arch i386
        .code32
-       
-/**************************************************************************
-_IN_CALL - make a call in to Etherboot.
-**************************************************************************/
 
-/* There are two 32-bit entry points: _in_call and _in_call_far, for
- * near calls and far calls respectively.  Both should be called with
- * flat physical addresses.  They will result in a call to the C
- * routine in_call(); see there for API details.
- *
- * Note that this routine makes fairly heavy use of the stack and no
- * use of fixed data areas.  This is because it must be re-entrant;
- * there may be more than one concurrent call in to Etherboot.
- */
-
-#define IC_OFFSET_VA_LIST_PTR ( 0 )
-#define IC_OFFSET_VA_LIST_PTR_E ( IC_OFFSET_VA_LIST_PTR + 4 )
-#define IC_OFFSET_REGISTERS ( IC_OFFSET_VA_LIST_PTR_E )
-#define IC_OFFSET_REGISTERS_E ( IC_OFFSET_REGISTERS + ( NUM_PUSHA_REGS * 4 ) )
-#define IC_OFFSET_SEG_REGS ( IC_OFFSET_REGISTERS_E )
-#define IC_OFFSET_SEG_REGS_E ( IC_OFFSET_SEG_REGS + ( NUM_SEG_REGS * 2 ) )
-#define IC_OFFSET_GDT ( IC_OFFSET_SEG_REGS_E )
-#define IC_OFFSET_GDT_E ( IC_OFFSET_GDT + 8 )
-#define IC_OFFSET_FLAGS ( IC_OFFSET_GDT_E )
-#define IC_OFFSET_FLAGS_E ( IC_OFFSET_FLAGS + 4 )
-#define IC_OFFSET_RETADDR ( IC_OFFSET_FLAGS_E )
-#define IC_OFFSET_RETADDR_E ( IC_OFFSET_RETADDR + 8 )
-#define IC_OFFSET_ORIG_STACK ( IC_OFFSET_RETADDR )
-#define IC_OFFSET_OPCODE ( IC_OFFSET_ORIG_STACK + 8 )
-#define IC_OFFSET_OPCODE_E ( IC_OFFSET_OPCODE + 4 )
-#define IC_OFFSET_VA_LIST ( IC_OFFSET_OPCODE_E )
-       
-       .code32
-       .globl _in_call
-       .globl _in_call_far
-_in_call:
-       /* Expand to far return address */
-       pushl   %eax                    /* Store %eax */
-       xorl    %eax, %eax
-       movw    %cs, %ax
-       xchgl   %eax, 4(%esp)           /* 4(%esp) = %cs, %eax = ret addr */
-       xchgl   %eax, 0(%esp)           /* 0(%esp) = ret addr, restore %eax */
-_in_call_far:
-       /* Store flags */
-       pushfl
-       /* Store the GDT */
-       subl    $8, %esp
-       sgdt    0(%esp)
-       /* Store segment register values */
-       pushw   %gs
-       pushw   %fs
-       pushw   %es
-       pushw   %ds
-       pushw   %ss
-       pushw   %cs
-       /* Store general-purpose register values */
-       pushal
-       /* Replace %esp in store with physical %esp value on entry */
-       leal    (IC_OFFSET_ORIG_STACK - IC_OFFSET_REGISTERS)(%esp), %eax
-       movl    %eax, (IC_OFFSET_REGISTERS - IC_OFFSET_REGISTERS + 12)(%esp)
-       /* Store va_list pointer (physical address) */
-       leal    (IC_OFFSET_VA_LIST - IC_OFFSET_VA_LIST_PTR_E)(%esp), %eax
-       pushl   %eax
-       /* IC_OFFSET_*(%esp) are now valid */
-
-       /* Switch to virtual addresses */
-       call    _phys_to_virt
-
-       /* Fixup the va_list pointer */
-       movl    virt_offset, %ebp
-       subl    %ebp, IC_OFFSET_VA_LIST_PTR(%esp)
-
-       /* Check opcode for EB_USE_INTERNAL_STACK flag */
-       movl    IC_OFFSET_OPCODE(%esp), %eax
-       testl   $EB_USE_INTERNAL_STACK, %eax
-       je      2f
-       /* Use internal stack flag set */
-       /* Check %esp is not already in internal stack range */
-       leal    _stack, %esi            /* %esi = bottom of internal stack */
-       leal    _estack, %edi           /* %edi = top of internal stack */
-       cmpl    %esi, %esp
-       jb      1f
-       cmpl    %edi, %esp
-       jbe     2f
-1:     /* %esp not currently in internal stack range */
-       movl    %esp, %esi              /* %esi = original stack */
-       movl    $IC_OFFSET_OPCODE_E, %ecx /* %ecx = length to transfer */
-       subl    %ecx, %edi              /* %edi = internal stack pos */
-       movl    %edi, %esp              /*  = new %esp */
-       rep movsb                       /* Copy data to internal stack */
-2:
-
-       /* Call to C code */
-       call    i386_in_call
-
-       /* Set %eax (return code from C) in registers structure on
-        * stack, so that we return it to the caller.
-        */
-       movl    %eax, (IC_OFFSET_REGISTERS + 28)(%esp)
-
-       /* Calculate physical continuation address */
-       movl    virt_offset, %ebp
-       movzwl  (IC_OFFSET_SEG_REGS + 0)(%esp), %eax    /* %cs */
-       movzwl  (IC_OFFSET_SEG_REGS + 2)(%esp), %ebx    /* %ss */
-       pushl   %eax                    /* Continuation segment */
-       leal    1f(%ebp), %eax
-       pushl   %eax                    /* Continuation offset */
-       
-       /* Restore caller's GDT */
-       cli                             /* Temporarily disable interrupts */
-       lgdt    (8+IC_OFFSET_GDT)(%esp)
-       /* Reset %ss and adjust %esp */
-       movw    %bx, %ss
-       addl    %ebp, %esp
-       lret                            /* Reload %cs:eip, flush prefetch */
-1:
-
-       /* Skip va_list ptr */
-       popl    %eax
-       /* Reload general-purpose registers to be returned */
-       popal
-       /* Reload segment registers as passed in from caller */
-       popw    %gs
-       popw    %fs
-       popw    %es
-       popw    %ds
-       addl    $(4+8), %esp    /* Skip %cs, %ss and GDT (already reloaded) */
-       /* Restore flags (including revert of interrupt status) */
-       popfl
-
-       /* Restore physical %esp from entry.  It will only be
-        * different if EB_USE_INTERNAL_STACK was specified.
-        */
-       movl    ( 12 + IC_OFFSET_REGISTERS - IC_OFFSET_RETADDR )(%esp), %esp
+       /* This is a struct os_entry_regs */
+       .globl os_regs
+os_regs:       .space 56
                
-       /* Check for EB_SKIP_OPCODE */
-       pushfl
-       testl   $EB_SKIP_OPCODE, 12(%esp)
-       jnz     1f
-       /* Normal return */
-       popfl
-       lret
-1:     /* Return and skip opcode */
-       popfl
-       lret    $4
-       
-/**************************************************************************
-RELOCATE_TO - relocate etherboot to the specified address
-**************************************************************************/
-       .globl relocate_to
-relocate_to:
-       /* Save the callee save registers */
-       pushl   %ebp
-       pushl   %esi
-       pushl   %edi
-
-       /* Compute the virtual destination address */
-       movl    16(%esp), %edi  # dest
-       subl    virt_offset, %edi
-       
-
-       /* Compute the new value of virt_offset */
-       movl    16(%esp), %ebp  # virt_offset
-       subl    $_text, %ebp
-
-       /* Fixup the gdt */
-       pushl   $_pmcs
-       pushl   %ebp            # virt_offset
-       call    set_seg_base
-       addl    $8, %esp
-
-       /* Fixup gdtarg */
-       leal    _gdt(%ebp), %eax
-       movl    %eax, gdtarg +2
-
-       /* Fixup virt_offset */
-       movl    %ebp, virt_offset
-
-       /* Load the move parameters */
-       movl    $_text, %esi
-       movl    $_end, %ecx
-       subl    %esi, %ecx
-
-       /* Move etherboot uses %esi, %edi, %ecx */
-       rep 
-       movsb
-
-       /* Reload the gdt */
-       cs
-       lgdt    gdtarg
-
-       /* Reload %cs */
-       ljmp    $KERN_CODE_SEG, $1f
-1:
-       /* reload other segment registers */
-       movl    $KERN_DATA_SEG, %eax
-       movl    %eax,%ds
-       movl    %eax,%es
-       movl    %eax,%ss
-       movl    %eax,%fs
-       movl    %eax,%gs
-
-       /* Restore the callee save registers */
-       popl    %edi
-       popl    %esi
-       popl    %ebp
-
-       /* return */
-       ret
-
 /**************************************************************************
 XSTART32 - Transfer control to the kernel just loaded
 **************************************************************************/
@@ -301,7 +70,7 @@ xstart32:
        pushl   %ebx
 
        /* Store the destination address on the stack */
-       pushl   $FLAT_CODE_SEG
+       pushl   $PHYSICAL_CS
        pushl   %ecx
 
        /* Cache virt_offset */
@@ -347,8 +116,9 @@ os_regs_ptr:
        movl    %esp, %ebp
        subl    $os_regs, %ebp
        
-       /* Load the stack pointer */
+       /* Load the stack pointer and convert it to physical address */
        movl    52(%esp), %esp
+       addl    %ebp, %esp
 
        /* Enable the virtual addresses */
        leal    _phys_to_virt(%ebp), %eax
@@ -536,218 +306,6 @@ end_lm:
        .arch i386
 #endif /* CONFIG_X86_64 */
 
-/**************************************************************************
-SETJMP - Save stack context for non-local goto
-**************************************************************************/
-       .globl  setjmp
-setjmp:
-       movl    4(%esp),%ecx            /* jmpbuf */
-       movl    0(%esp),%edx            /* return address */
-       movl    %edx,0(%ecx)
-       movl    %ebx,4(%ecx)
-       movl    %esp,8(%ecx)
-       movl    %ebp,12(%ecx)
-       movl    %esi,16(%ecx)
-       movl    %edi,20(%ecx)
-       movl    $0,%eax
-       ret
-
-/**************************************************************************
-LONGJMP - Non-local jump to a saved stack context
-**************************************************************************/
-       .globl  longjmp
-longjmp:
-       movl    4(%esp),%edx            /* jumpbuf */
-       movl    8(%esp),%eax            /* result */
-       movl    0(%edx),%ecx
-       movl    4(%edx),%ebx
-       movl    8(%edx),%esp
-       movl    12(%edx),%ebp
-       movl    16(%edx),%esi
-       movl    20(%edx),%edi
-       cmpl    $0,%eax
-       jne     1f
-       movl    $1,%eax
-1:     movl    %ecx,0(%esp)
-       ret
-
-/**************************************************************************
-_VIRT_TO_PHYS - Transition from virtual to physical addresses
-               Preserves all preservable registers and flags
-**************************************************************************/
-       .globl _virt_to_phys
-_virt_to_phys:
-       pushfl
-       pushl   %ebp
-       pushl   %eax
-       movl    virt_offset, %ebp       /* Load virt_offset */
-       addl    %ebp, 12(%esp)          /* Adjust the return address */
-
-       /* reload the code segment */
-       pushl   $FLAT_CODE_SEG
-       leal    1f(%ebp), %eax
-       pushl   %eax
-       lret
-
-1:
-       /* reload other segment registers */
-       movl    $FLAT_DATA_SEG, %eax
-       movl    %eax, %ds
-       movl    %eax, %es       
-       movl    %eax, %ss       
-       addl    %ebp, %esp              /* Adjust the stack pointer */
-       movl    %eax, %fs       
-       movl    %eax, %gs
-
-       popl    %eax
-       popl    %ebp
-       popfl
-       ret
-
-
-/**************************************************************************
-_PHYS_TO_VIRT - Transition from using physical to virtual addresses
-               Preserves all preservable registers and flags
-**************************************************************************/
-       .globl _phys_to_virt
-_phys_to_virt:
-       pushfl
-       pushl   %ebp
-       pushl   %eax
-
-       call    1f
-1:     popl    %ebp
-       subl    $1b, %ebp
-       movl    %ebp, virt_offset(%ebp)
-
-       /* Fixup the gdt */
-       leal    _pmcs(%ebp), %eax
-       pushl   %eax
-       pushl   %ebp
-       call    set_seg_base
-       addl    $8, %esp
-
-       /* Fixup gdtarg */
-       leal    _gdt(%ebp), %eax
-       movl    %eax, (gdtarg+2)(%ebp)
-
-       /* Load the global descriptor table */
-       cli
-       lgdt    %cs:gdtarg(%ebp)
-       ljmp    $KERN_CODE_SEG, $1f
-1:
-       /* reload other segment regsters */
-       movl    $KERN_DATA_SEG, %eax
-       movl    %eax, %ds
-       movl    %eax, %es       
-       movl    %eax, %ss       
-       subl    %ebp, %esp      /* Adjust the stack pointer */
-       movl    %eax, %fs       
-       movl    %eax, %gs
-
-       subl    %ebp, 12(%esp)  /* Adjust the return address */
-       popl    %eax
-       popl    %ebp
-       popfl
-       ret
-       
-
-/**************************************************************************
-SET_SEG_BASE - Set the base address of a segment register
-**************************************************************************/
-       .globl set_seg_base
-set_seg_base:
-       pushl   %eax
-       pushl   %ebx
-       movl    12(%esp), %eax          /* %eax = base address */
-       movl    16(%esp), %ebx          /* %ebx = &code_descriptor */
-       movw    %ax, (0+2)(%ebx)        /* CS base bits 0-15 */
-       movw    %ax, (8+2)(%ebx)        /* DS base bits 0-15 */
-       shrl    $16, %eax
-       movb    %al, (0+4)(%ebx)        /* CS base bits 16-23 */
-       movb    %al, (8+4)(%ebx)        /* DS base bits 16-23 */
-       movb    %ah, (0+7)(%ebx)        /* CS base bits 24-31 */
-       movb    %ah, (8+7)(%ebx)        /* DS base bits 24-31 */
-       popl    %ebx
-       popl    %eax
-       ret
-       
-/**************************************************************************
-GLOBAL DESCRIPTOR TABLE
-**************************************************************************/
-       .data
-       .align  4
-
-       .globl  _gdt
-       .globl  gdtarg
-_gdt:
-gdtarg:
-       .word   _gdt_end - _gdt - 1     /* limit */
-       .long   _gdt                    /* addr */
-       .word   0
-
-       .globl  _pmcs
-_pmcs:
-       /* 32 bit protected mode code segment */
-       .word   0xffff,0
-       .byte   0,0x9f,0xcf,0
-
-_pmds:
-       /* 32 bit protected mode data segment */
-       .word   0xffff,0
-       .byte   0,0x93,0xcf,0
-
-_rmcs:
-       /* 16 bit real mode code segment */
-       .word   0xffff,(0&0xffff)
-       .byte   (0>>16),0x9b,0x00,(0>>24)
-
-_rmds:
-       /* 16 bit real mode data segment */
-       .word   0xffff,(0&0xffff)
-       .byte   (0>>16),0x93,0x00,(0>>24)
-
-_pmcs2:
-       /* 32 bit protected mode code segment, base 0 */
-       .word   0xffff,0
-       .byte   0,0x9f,0xcf,0
-
-_pmds2:
-       /* 32 bit protected mode data segment, base 0 */
-       .word   0xffff,0
-       .byte   0,0x93,0xcf,0
-
-#ifdef CONFIG_X86_64
-_lmcs:
-       /* 64bit long mode code segment, base 0 */
-       .word   0xffff, 0
-       .byte   0x00, 0x9f, 0xaf , 0x00
-_lmds:
-       /* 64bit long mode data segment, base 0 */
-       .word   0xffff, 0
-       .byte   0x00, 0x93, 0xcf, 0x00
-#endif
-_gdt_end:
-
-       /* The initial register contents */
-       .balign 4
-       .globl initial_regs
-initial_regs:
-       .fill 8, 4, 0
-
-       /* The virtual address offset  */       
-       .globl virt_offset
-virt_offset:
-       .long   0
-
-       .section ".stack"
-       .p2align 3
-       /* allocate a 4K stack in the stack segment */
-       .globl  _stack
-_stack:
-       .space 4096
-       .globl  _estack
-_estack:
 #ifdef CONFIG_X86_64
        .section ".bss"
        .p2align 12