blob: 8f1e42eed1e1455b96e2a22155e0a605da96109f [file] [log] [blame]
.globl entry, __switch_context, __exit_context, halt, init_exceptions
.text
.align 4
/*
* Entry point
* We start execution from here.
* It is assumed that CPU is in 32-bit protected mode and
* all segments are 4GB and base zero (flat model).
*/
entry:
/* Save boot context and switch to our main context.
* Main context is statically defined in C.
*/
pushl %cs
call __switch_context
/* We get here when the main context switches back to
* the boot context.
* Return to previous bootloader.
*/
ret
/*
* Switch execution context
* This saves registers, segments, and GDT in the stack, then
* switches the stack, and restores everything from the new stack.
* This function takes no argument. New stack pointer is
* taken from global variable __context, and old stack pointer
* is also saved to __context. This way we can just jump to
* this routine to get back to the original context.
*
* Call this routine with lcall or pushl %cs; call.
*/
__switch_context:
/* Save everything in current stack */
pushfl /* 56 */
pushl %ds /* 52 */
pushl %es /* 48 */
pushl %fs /* 44 */
pushl %gs /* 40 */
pushal /* 8 */
subl $8, %esp
movw %ss, (%esp) /* 0 */
sgdt 2(%esp) /* 2 */
#if 0
/* Swap %cs and %eip on the stack, so lret will work */
movl 60(%esp), %eax
xchgl %eax, 64(%esp)
movl %eax, 60(%esp)
#endif
/* At this point we don't know if we are on flat segment
* or relocated. So compute the address offset from %eip.
* Assuming CS.base==DS.base==SS.base.
*/
call 1f
1: popl %ebx
subl $1b, %ebx
/* Interrupts are not allowed... */
cli
/* Current context pointer is our stack pointer */
movl %esp, %esi
/* Normalize the ctx pointer */
subl %ebx, %esi
/* Swap it with new value */
xchgl %esi, __context(%ebx)
/* Adjust new ctx pointer for current address offset */
addl %ebx, %esi
/* Load new %ss and %esp to temporary */
movzwl (%esi), %edx
movl 20(%esi), %eax
/* Load new GDT */
lgdt 2(%esi)
/* Load new stack segment with new GDT */
movl %edx, %ss
/* Set new stack pointer, but we have to adjust it because
* pushal saves %esp value before pushal, and we want the value
* after pushal.
*/
leal -32(%eax), %esp
/* Load the rest from new stack */
popal
popl %gs
popl %fs
popl %es
popl %ds
popfl
/* Finally, load new %cs and %eip */
lret
__exit_context:
/* Get back to the original context */
pushl %cs
call __switch_context
/* We get here if the other context attempt to switch to this
* dead context. This should not happen. */
halt:
cli
hlt
jmp halt
/*
* initialize exception handler. All exceptions end up in the same
* C function.
*/
init_exceptions:
pushl %ebx
pushl %edi
/* Initialize the Interrupt Descriptor table */
leal _idt, %edi
leal vec0, %ebx
movl $(0x08 << 16), %eax /* cs selector */
1: movw %bx, %ax
movl %ebx, %edx
movw $0x8E00, %dx /* Interrupt gate - dpl=0, present */
movl %eax, 0(%edi)
movl %edx, 4(%edi)
addl $6, %ebx
addl $8, %edi
cmpl $_idt_end, %edi
jne 1b
/* Load the Interrupt descriptor table */
lidt idtarg
movl $0, %eax
popl %edi
popl %ebx
ret
vec0:
pushl $0 /* error code */
pushl $0 /* vector */
jmp int_hand
vec1:
pushl $0 /* error code */
pushl $1 /* vector */
jmp int_hand
vec2:
pushl $0 /* error code */
pushl $2 /* vector */
jmp int_hand
vec3:
pushl $0 /* error code */
pushl $3 /* vector */
jmp int_hand
vec4:
pushl $0 /* error code */
pushl $4 /* vector */
jmp int_hand
vec5:
pushl $0 /* error code */
pushl $5 /* vector */
jmp int_hand
vec6:
pushl $0 /* error code */
pushl $6 /* vector */
jmp int_hand
vec7:
pushl $0 /* error code */
pushl $7 /* vector */
jmp int_hand
vec8:
/* error code */
pushl $8 /* vector */
jmp int_hand
.word 0x9090
vec9:
pushl $0 /* error code */
pushl $9 /* vector */
jmp int_hand
vec10:
/* error code */
pushl $10 /* vector */
jmp int_hand
.word 0x9090
vec11:
/* error code */
pushl $11 /* vector */
jmp int_hand
.word 0x9090
vec12:
/* error code */
pushl $12 /* vector */
jmp int_hand
.word 0x9090
vec13:
/* error code */
pushl $13 /* vector */
jmp int_hand
.word 0x9090
vec14:
/* error code */
pushl $14 /* vector */
jmp int_hand
.word 0x9090
vec15:
pushl $0 /* error code */
pushl $15 /* vector */
jmp int_hand
vec16:
pushl $0 /* error code */
pushl $16 /* vector */
jmp int_hand
vec17:
/* error code */
pushl $17 /* vector */
jmp int_hand
.word 0x9090
vec18:
pushl $0 /* error code */
pushl $18 /* vector */
jmp int_hand
vec19:
pushl $0 /* error code */
pushl $19 /* vector */
jmp int_hand
__divide_error:
pushl $0 /* error code */
pushl $20 /* vector */
jmp int_hand
.global __divide_error
int_hand:
/* At this point on the stack there is:
* 0(%esp) vector
* 4(%esp) error code
* 8(%esp) eip
* 12(%esp) cs
* 16(%esp) eflags
*/
pushl %edi
pushl %esi
pushl %ebp
/* Original stack pointer */
leal 32(%esp), %ebp
pushl %ebp
pushl %ebx
pushl %edx
pushl %ecx
pushl %eax
pushl %esp /* Pointer to structure on the stack */
call x86_exception
pop %eax /* Drop the pointer */
popl %eax
popl %ecx
popl %edx
popl %ebx
popl %ebp /* Ignore saved %esp value */
popl %ebp
popl %esi
popl %edi
addl $8, %esp /* pop of the vector and error code */
iret
idtarg:
.word _idt_end - _idt - 1 /* limit */
.long _idt
.word 0
_idt:
.fill 20, 8, 0 # idt is unitiailzed
_idt_end:
.globl arch_nvram_size, arch_nvram_get, arch_nvram_put
arch_nvram_size:
xor %eax, %eax
ret
arch_nvram_get:
ret
arch_nvram_put:
ret