Merged mcb30-realmode-redesign back to HEAD

This commit is contained in:
Michael Brown
2005-04-08 15:01:17 +00:00
parent de5d935135
commit 0ff80b477d
100 changed files with 4877 additions and 4263 deletions

View 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
@@ -29,12 +16,6 @@
#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
@@ -54,226 +35,10 @@
* 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
/* 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 +66,7 @@ xstart32:
pushl %ebx
/* Store the destination address on the stack */
pushl $FLAT_CODE_SEG
pushl $PHYSICAL_CS
pushl %ecx
/* Cache virt_offset */
@@ -536,218 +301,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