| .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 |