You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
2.6 KiB
ArmAsm
170 lines
2.6 KiB
ArmAsm
%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
|
|
|
|
|