%include "defines.s" extern gdt_flat_slice extern gdt_flat extern GDT_FLAT_IDX_CODE_32 extern GDT_FLAT_IDX_CODE_16 extern GDT_FLAT_IDX_DATA section .text [bits 32] ; FIXME: use a separate stack for real mode bios_call: .PARAMS_START equ 36 .PARAM_BIOS_INTR_NUM equ .PARAMS_START .PARAM_BIOS_INTR_ARGS_PTR equ .PARAMS_START + 4 pushad mov ebp, esp push ds push es push fs push gs push ss ; Push cr0, the GDT and the IDT to the stack so we can restore them once we're finished with real mode. mov eax, cr0 push eax sub esp, 8 sidt [esp] sub esp, 8 sgdt [esp] ; Load the address of the `int` instruction we want to run, and store it on the stack for later. mov eax, [ebp + .PARAM_BIOS_INTR_NUM] lea eax, [int_fns + (3 * eax)] push eax ; Copy the BIOS call arguments provided by the caller onto the stack, for us to pop later. sub esp, 28 mov ecx, 28 mov esi, [ebp + .PARAM_BIOS_INTR_ARGS_PTR] mov edi, esp rep movsb ; Switch to a 16-bit code segment, but remain in protected mode. jmp GDT_FLAT_IDX_CODE_16:.protected_mode_16 [bits 16] .protected_mode_16: ; Disable paging and protected mode. mov eax, cr0 and eax, 0x7ffffffe mov cr0, eax jmp 0:.real_mode .real_mode: xor ax, ax mov ds, ax mov es, ax mov fs, ax mov gs, ax mov ss, ax ; Load the caller-provided register values off the stack. pop eax pop ebx pop ecx pop edx pop esi pop edi pop ds pop es ; Call the function which runs the correct `int` instruction. push bp mov bp, sp call [bp + 2] pop bp ; TODO: return resulting registers to the caller ; Reset the segment registers that were changed to the caller-provided values. xor ax, ax mov ds, ax mov es, ax ; Reload the GDT in case the BIOS call changed it. mov bx, sp lgdt [bx] add sp, 8 mov bx, sp lidt [bx] add sp, 8 ; Restore cr0, re-enabling protected mode. pop eax mov cr0, eax jmp GDT_FLAT_IDX_CODE_32:.protected_mode_32 [bits 32] .protected_mode_32: pop ss pop gs pop fs pop es pop ds popad ret global bios_call %macro int_fn 1 int %1 ret %endmacro int_fns: int_fn 0x00 int_fn 0x01 int_fn 0x02 int_fn 0x03 int_fn 0x04 int_fn 0x05 int_fn 0x06 int_fn 0x07 int_fn 0x08 int_fn 0x09 int_fn 0x0a int_fn 0x0b int_fn 0x0c int_fn 0x0d int_fn 0x0e int_fn 0x0f int_fn 0x10 int_fn 0x11 int_fn 0x12 int_fn 0x13 int_fn 0x14 int_fn 0x15 int_fn 0x16 int_fn 0x17 int_fn 0x18 int_fn 0x19 int_fn 0x1a int_fn 0x1b int_fn 0x1c int_fn 0x1d int_fn 0x1e int_fn 0x1f section .rodata idt_real: dw 0x3ff dd 0