[BITS 32]

global bios_disk_op

THUNK_BASE equ 0x8000
DAP_ADDR   equ 0x0600
BUF_ADDR   equ 0x6000 ; keep this away from FONT8X8 at 0x7000

PM16_LOW   equ THUNK_BASE + (pm16_entry - thunk_start)
REAL_LOW   equ THUNK_BASE + (real_entry - thunk_start)
PM32_LOW   equ THUNK_BASE + (pm32_entry - thunk_start)

DRIVE_LOW  equ THUNK_BASE + (bios_drive - thunk_start)
WRITE_LOW  equ THUNK_BASE + (bios_write - thunk_start)
RESULT_LOW equ THUNK_BASE + (bios_result - thunk_start)
ESP_LOW    equ THUNK_BASE + (saved_esp - thunk_start)
IDT_LOW    equ THUNK_BASE + (saved_idt - thunk_start)
RMIDT_LOW  equ THUNK_BASE + (real_idt - thunk_start)

bios_disk_op:
	cli

	mov [saved_esp], esp
	sidt [saved_idt]

	mov esi, thunk_start
	mov edi, THUNK_BASE
	mov ecx, thunk_end - thunk_start
	cld
	rep movsb

	mov byte  [DAP_ADDR + 0], 16
	mov byte  [DAP_ADDR + 1], 0
	mov word  [DAP_ADDR + 2], 1
	mov word  [DAP_ADDR + 4], BUF_ADDR
	mov word  [DAP_ADDR + 6], 0

	mov eax, [esp + 8]
	mov dword [DAP_ADDR + 8], eax
	mov dword [DAP_ADDR + 12], 0

	mov al, [esp + 4]
	mov [DRIVE_LOW], al

	mov eax, [esp + 12]
	mov [WRITE_LOW], eax

	mov dword [RESULT_LOW], 0

	mov eax, [saved_esp]
	mov [ESP_LOW], eax

	lgdt [gdt_ptr]

	jmp 0x18:PM16_LOW

thunk_start:

[BITS 16]

pm16_entry:
	mov ax, 0x20
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	mov sp, 0x5000

	mov eax, cr0
	and eax, 0xFFFFFFFE
	mov cr0, eax

	jmp 0x0000:REAL_LOW

real_entry:
	xor ax, ax
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	mov sp, 0x5000

	lidt [RMIDT_LOW]

	mov dl, [DRIVE_LOW]
	mov si, DAP_ADDR

	cmp dword [WRITE_LOW], 0
	je .read

.write:
	mov ah, 0x43
	jmp .go

.read:
	mov ah, 0x42

.go:
	int 0x13
	jc .fail

	mov dword [RESULT_LOW], 1
	jmp .back

.fail:
	mov dword [RESULT_LOW], 0

.back:
	cli

	mov eax, cr0
	or eax, 1
	mov cr0, eax

	jmp 0x08:PM32_LOW

[BITS 32]

pm32_entry:
	mov ax, 0x10
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax

	lidt [IDT_LOW]

	mov esp, [ESP_LOW]
	mov eax, [RESULT_LOW]

	ret

bios_drive db 0
bios_write dd 0
bios_result dd 0
saved_esp dd 0

saved_idt:
	dw 0
	dd 0

real_idt:
	dw 0x03FF
	dd 0x00000000

thunk_end:

align 8

gdt:
	dq 0

	; 0x08 32-bit code
	dw 0xFFFF
	dw 0x0000
	db 0x00
	db 10011010b
	db 11001111b
	db 0x00

	; 0x10 32-bit data
	dw 0xFFFF
	dw 0x0000
	db 0x00
	db 10010010b
	db 11001111b
	db 0x00

	; 0x18 16-bit code
	dw 0xFFFF
	dw 0x0000
	db 0x00
	db 10011010b
	db 00001111b
	db 0x00

	; 0x20 16-bit data
	dw 0xFFFF
	dw 0x0000
	db 0x00
	db 10010010b
	db 00001111b
	db 0x00

gdt_end:

gdt_ptr:
	dw gdt_end - gdt - 1
	dd gdt
