diff options
Diffstat (limited to 'roms/openbios/arch/x86/entry.S')
-rw-r--r-- | roms/openbios/arch/x86/entry.S | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/roms/openbios/arch/x86/entry.S b/roms/openbios/arch/x86/entry.S new file mode 100644 index 000000000..8f1e42eed --- /dev/null +++ b/roms/openbios/arch/x86/entry.S @@ -0,0 +1,315 @@ + .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 |