mirror of
https://github.com/xcat2/xNBA.git
synced 2024-12-16 00:01:34 +00:00
768 lines
18 KiB
ArmAsm
768 lines
18 KiB
ArmAsm
|
/* #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
|
||
|
|
||
|
.equ MSR_K6_EFER, 0xC0000080
|
||
|
.equ EFER_LME, 0x00000100
|
||
|
.equ X86_CR4_PAE, 0x00000020
|
||
|
.equ CR0_PG, 0x80000000
|
||
|
|
||
|
#ifdef GAS291
|
||
|
#define DATA32 data32;
|
||
|
#define ADDR32 addr32;
|
||
|
#define LJMPI(x) ljmp x
|
||
|
#else
|
||
|
#define DATA32 data32
|
||
|
#define ADDR32 addr32
|
||
|
/* newer GAS295 require #define LJMPI(x) ljmp *x */
|
||
|
#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
|
||
|
* registers must not be altered under any circumstance. All other registers
|
||
|
* may be clobbered without any negative side effects. If you don't follow
|
||
|
* this rule then you'll run into strange effects that only occur on some
|
||
|
* gcc versions (because the register allocator may use different registers).
|
||
|
*
|
||
|
* All the data32 prefixes for the ljmp instructions are necessary, because
|
||
|
* the assembler emits code with a relocation address of 0. This means that
|
||
|
* all destinations are initially negative, which the assembler doesn't grok,
|
||
|
* because for some reason negative numbers don't fit into 16 bits. The addr32
|
||
|
* prefixes are there for the same reasons, because otherwise the memory
|
||
|
* references are only 16 bit wide. Theoretically they are all superfluous.
|
||
|
* One last note about prefixes: the data32 prefixes on all call _real_to_prot
|
||
|
* instructions could be removed if the _real_to_prot function is changed to
|
||
|
* 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
|
||
|
**************************************************************************/
|
||
|
.globl xstart32
|
||
|
xstart32:
|
||
|
/* Save the callee save registers */
|
||
|
movl %ebp, os_regs + 32
|
||
|
movl %esi, os_regs + 36
|
||
|
movl %edi, os_regs + 40
|
||
|
movl %ebx, os_regs + 44
|
||
|
|
||
|
/* save the return address */
|
||
|
popl %eax
|
||
|
movl %eax, os_regs + 48
|
||
|
|
||
|
/* save the stack pointer */
|
||
|
movl %esp, os_regs + 52
|
||
|
|
||
|
/* Get the new destination address */
|
||
|
popl %ecx
|
||
|
|
||
|
/* Store the physical address of xend on the stack */
|
||
|
movl $xend32, %ebx
|
||
|
addl virt_offset, %ebx
|
||
|
pushl %ebx
|
||
|
|
||
|
/* Store the destination address on the stack */
|
||
|
pushl $FLAT_CODE_SEG
|
||
|
pushl %ecx
|
||
|
|
||
|
/* Cache virt_offset */
|
||
|
movl virt_offset, %ebp
|
||
|
|
||
|
/* Switch to using physical addresses */
|
||
|
call _virt_to_phys
|
||
|
|
||
|
/* Save the target stack pointer */
|
||
|
movl %esp, os_regs + 12(%ebp)
|
||
|
leal os_regs(%ebp), %esp
|
||
|
|
||
|
/* Store the pointer to os_regs */
|
||
|
movl %esp, os_regs_ptr(%ebp)
|
||
|
|
||
|
/* Load my new registers */
|
||
|
popal
|
||
|
movl (-32 + 12)(%esp), %esp
|
||
|
|
||
|
/* Jump to the new kernel
|
||
|
* The lret switches to a flat code segment
|
||
|
*/
|
||
|
lret
|
||
|
|
||
|
.balign 4
|
||
|
.globl xend32
|
||
|
xend32:
|
||
|
/* Fixup %eflags */
|
||
|
nop
|
||
|
cli
|
||
|
cld
|
||
|
|
||
|
/* Load %esp with &os_regs + virt_offset */
|
||
|
.byte 0xbc /* movl $0, %esp */
|
||
|
os_regs_ptr:
|
||
|
.long 0
|
||
|
|
||
|
/* Save the result registers */
|
||
|
addl $32, %esp
|
||
|
pushal
|
||
|
|
||
|
/* Compute virt_offset */
|
||
|
movl %esp, %ebp
|
||
|
subl $os_regs, %ebp
|
||
|
|
||
|
/* Load the stack pointer */
|
||
|
movl 52(%esp), %esp
|
||
|
|
||
|
/* Enable the virtual addresses */
|
||
|
leal _phys_to_virt(%ebp), %eax
|
||
|
call *%eax
|
||
|
|
||
|
/* Restore the callee save registers */
|
||
|
movl os_regs + 32, %ebp
|
||
|
movl os_regs + 36, %esi
|
||
|
movl os_regs + 40, %edi
|
||
|
movl os_regs + 44, %ebx
|
||
|
movl os_regs + 48, %edx
|
||
|
movl os_regs + 52, %esp
|
||
|
|
||
|
/* Get the C return value */
|
||
|
movl os_regs + 28, %eax
|
||
|
|
||
|
jmpl *%edx
|
||
|
|
||
|
#ifdef CONFIG_X86_64
|
||
|
.arch sledgehammer
|
||
|
/**************************************************************************
|
||
|
XSTART_lm - Transfer control to the kernel just loaded in long mode
|
||
|
**************************************************************************/
|
||
|
.globl xstart_lm
|
||
|
xstart_lm:
|
||
|
/* Save the callee save registers */
|
||
|
pushl %ebp
|
||
|
pushl %esi
|
||
|
pushl %edi
|
||
|
pushl %ebx
|
||
|
|
||
|
/* Cache virt_offset && (virt_offset & 0xfffff000) */
|
||
|
movl virt_offset, %ebp
|
||
|
movl %ebp, %ebx
|
||
|
andl $0xfffff000, %ebx
|
||
|
|
||
|
/* Switch to using physical addresses */
|
||
|
call _virt_to_phys
|
||
|
|
||
|
/* Initialize the page tables */
|
||
|
/* Level 4 */
|
||
|
leal 0x23 + pgt_level3(%ebx), %eax
|
||
|
leal pgt_level4(%ebx), %edi
|
||
|
movl %eax, (%edi)
|
||
|
|
||
|
/* Level 3 */
|
||
|
leal 0x23 + pgt_level2(%ebx), %eax
|
||
|
leal pgt_level3(%ebx), %edi
|
||
|
movl %eax, 0x00(%edi)
|
||
|
addl $4096, %eax
|
||
|
movl %eax, 0x08(%edi)
|
||
|
addl $4096, %eax
|
||
|
movl %eax, 0x10(%edi)
|
||
|
addl $4096, %eax
|
||
|
movl %eax, 0x18(%edi)
|
||
|
|
||
|
/* Level 2 */
|
||
|
movl $0xe3, %eax
|
||
|
leal pgt_level2(%ebx), %edi
|
||
|
leal 16384(%edi), %esi
|
||
|
pgt_level2_loop:
|
||
|
movl %eax, (%edi)
|
||
|
addl $8, %edi
|
||
|
addl $0x200000, %eax
|
||
|
cmp %esi, %edi
|
||
|
jne pgt_level2_loop
|
||
|
|
||
|
/* Point at the x86_64 page tables */
|
||
|
leal pgt_level4(%ebx), %edi
|
||
|
movl %edi, %cr3
|
||
|
|
||
|
|
||
|
/* Setup for the return from 64bit mode */
|
||
|
/* 64bit align the stack */
|
||
|
movl %esp, %ebx /* original stack pointer + 16 */
|
||
|
andl $0xfffffff8, %esp
|
||
|
|
||
|
/* Save original stack pointer + 16 */
|
||
|
pushl %ebx
|
||
|
|
||
|
/* Save virt_offset */
|
||
|
pushl %ebp
|
||
|
|
||
|
/* Setup for the jmp to 64bit long mode */
|
||
|
leal start_lm(%ebp), %eax
|
||
|
movl %eax, 0x00 + start_lm_addr(%ebp)
|
||
|
movl $LM_CODE_SEG, %eax
|
||
|
movl %eax, 0x04 + start_lm_addr(%ebp)
|
||
|
|
||
|
/* Setup for the jump out of 64bit long mode */
|
||
|
leal end_lm(%ebp), %eax
|
||
|
movl %eax, 0x00 + end_lm_addr(%ebp)
|
||
|
movl $FLAT_CODE_SEG, %eax
|
||
|
movl %eax, 0x04 + end_lm_addr(%ebp)
|
||
|
|
||
|
/* Enable PAE mode */
|
||
|
movl %cr4, %eax
|
||
|
orl $X86_CR4_PAE, %eax
|
||
|
movl %eax, %cr4
|
||
|
|
||
|
/* Enable long mode */
|
||
|
movl $MSR_K6_EFER, %ecx
|
||
|
rdmsr
|
||
|
orl $EFER_LME, %eax
|
||
|
wrmsr
|
||
|
|
||
|
/* Start paging, entering 32bit compatiblity mode */
|
||
|
movl %cr0, %eax
|
||
|
orl $CR0_PG, %eax
|
||
|
movl %eax, %cr0
|
||
|
|
||
|
/* Enter 64bit long mode */
|
||
|
ljmp *start_lm_addr(%ebp)
|
||
|
.code64
|
||
|
start_lm:
|
||
|
/* Load 64bit data segments */
|
||
|
movl $LM_DATA_SEG, %eax
|
||
|
movl %eax, %ds
|
||
|
movl %eax, %es
|
||
|
movl %eax, %ss
|
||
|
|
||
|
andq $0xffffffff, %rbx
|
||
|
/* Get the address to jump to */
|
||
|
movl 20(%rbx), %edx
|
||
|
andq $0xffffffff, %rdx
|
||
|
|
||
|
/* Get the argument pointer */
|
||
|
movl 24(%rbx), %ebx
|
||
|
andq $0xffffffff, %rbx
|
||
|
|
||
|
/* Jump to the 64bit code */
|
||
|
call *%rdx
|
||
|
|
||
|
/* Preserve the result */
|
||
|
movl %eax, %edx
|
||
|
|
||
|
/* Fixup %eflags */
|
||
|
cli
|
||
|
cld
|
||
|
|
||
|
/* Switch to 32bit compatibility mode */
|
||
|
ljmp *end_lm_addr(%rip)
|
||
|
|
||
|
.code32
|
||
|
end_lm:
|
||
|
/* Disable paging */
|
||
|
movl %cr0, %eax
|
||
|
andl $~CR0_PG, %eax
|
||
|
movl %eax, %cr0
|
||
|
|
||
|
/* Disable long mode */
|
||
|
movl $MSR_K6_EFER, %ecx
|
||
|
rdmsr
|
||
|
andl $~EFER_LME, %eax
|
||
|
wrmsr
|
||
|
|
||
|
/* Disable PAE */
|
||
|
movl %cr4, %eax
|
||
|
andl $~X86_CR4_PAE, %eax
|
||
|
movl %eax, %cr4
|
||
|
|
||
|
/* Compute virt_offset */
|
||
|
popl %ebp
|
||
|
|
||
|
/* Compute the original stack pointer + 16 */
|
||
|
popl %ebx
|
||
|
movl %ebx, %esp
|
||
|
|
||
|
/* Enable the virtual addresses */
|
||
|
leal _phys_to_virt(%ebp), %eax
|
||
|
call *%eax
|
||
|
|
||
|
/* Restore the callee save registers */
|
||
|
popl %ebx
|
||
|
popl %esi
|
||
|
popl %edi
|
||
|
popl %ebp
|
||
|
|
||
|
/* Get the C return value */
|
||
|
movl %edx, %eax
|
||
|
|
||
|
/* Return */
|
||
|
ret
|
||
|
|
||
|
.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
|
||
|
/* Include a dummy space in case we are loaded badly aligned */
|
||
|
.space 4096
|
||
|
/* Reserve enough space for a page table convering 4GB with 2MB pages */
|
||
|
pgt_level4:
|
||
|
.space 4096
|
||
|
pgt_level3:
|
||
|
.space 4096
|
||
|
pgt_level2:
|
||
|
.space 16384
|
||
|
start_lm_addr:
|
||
|
.space 8
|
||
|
end_lm_addr:
|
||
|
.space 8
|
||
|
#endif
|