DragonVM/extra/dss/bios.dss

135 lines
4.8 KiB
Text

## ============================= Memory Mapped Devices and Registers =============================
@group MemoryAddresses
MBR 0x1380
INT_VEC 0x1080
DISK_INTERFACE 0x1580
RAM 0x1740
CMOS 0x1000
@end
@group CMOS_Settings
BOOT_DISK {MemoryAddresses.CMOS + 0x0010}
@end
## ===============================================================================================
.load 0x0000 ## BIOS is mapped to address 0x0000 in memory
.data
$bios_version_number 0x00, 0x01 ## BIOS Version stored in memory
## ============================= BIOS Program =============================
.code
## mov FL, 0
## jmp 0x1740
mov FL, 0b0000000000000001 ## Zero the FL Register and enable interrupts
movb [{MemoryAddresses.INT_VEC + (0x20 * 3)}], 0xFF ## Setting up int 0x20 handler
mov [{MemoryAddresses.INT_VEC + (0x20 * 3) + 1}], $_int_20_handler ## --
mov R10, 0x00 ## Setting up int 0x30 handler by using int 0x20 functionality
mov R9, $_int_30_handler ## -Passing the handler's address
mov R8, 0x30 ## -Passing the interrupt's code to setup
int 0x20 ## -Calling int 0x20 with 0x00 as parameter, to set new handler up
## MBR Loading
and FL, 0b1111111111111110 ## Disable interrupts
push 0
call $_load_mbr_data_block
or FL, 0b0000000000000001 ## Enable interrupts
## ----
jmp MemoryAddresses.MBR ## Jump to start of MBR in memory
hlt ## Just in case somehow execution reaches this point
## ========================================================================
## ============================= BIOS Interrupt handler =============================
_int_20_handler:
mov ACC, R10
jeq $_int_20_disk_interface, 0x0010
jeq $_int_20_set_new_interrupt_handler, 0x0000
jeq $_int_20_clear_interrupt, 0x0001
jmp $_int_20_end
_int_20_disk_interface:
movb [{MemoryAddresses.DISK_INTERFACE + 0x1}], *R9 ## Mode
inc R9
movb [{MemoryAddresses.DISK_INTERFACE + 0x2}], *R9 ## Disk
inc R9
mov [{MemoryAddresses.DISK_INTERFACE + 0x3}], *R9 ## Sector
inc R9
inc R9
mov [{MemoryAddresses.DISK_INTERFACE + 0x5}], *R9 ## Address
inc R9
inc R9
mov [{MemoryAddresses.DISK_INTERFACE + 0x7}], *R9 ## Size
inc R9
inc R9
mov [{MemoryAddresses.DISK_INTERFACE + 0x9}], *R9 ## Memory Address
movb [MemoryAddresses.DISK_INTERFACE], 0x00 ## Signal set to "Start Operation"
jmp $_int_20_end
_int_20_set_new_interrupt_handler:
push R8 ## Interrupt Code
push R9 ## Handler Address
push 2
call $_set_interrupt_vector_entry
jmp $_int_20_end
_int_20_clear_interrupt:
push R9
push 0x0000
push 2
call $_set_interrupt_vector_entry
_int_20_end:
rti
## ==================================================================================
## ========================== BIOS Video Interrupt handler =========================
_int_30_handler:
mov ACC, R10
jeq $_int_30_clear_screen, 0x0000
jmp $_int_30_end
_int_30_clear_screen:
nop
_int_30_end:
rti
## ==================================================================================
_load_mbr_data_block:
movb [{MemoryAddresses.DISK_INTERFACE + 0x1}], 0x00 ## Mode = Read
movb R1, [CMOS_Settings.BOOT_DISK]
movb [{MemoryAddresses.DISK_INTERFACE + 0x2}], R1 ## Disk = Default
mov [{MemoryAddresses.DISK_INTERFACE + 0x3}],0x0000 ## Sector = 0x0000
mov [{MemoryAddresses.DISK_INTERFACE + 0x5}],0x0000 ## Address = 0x0000 (Start of Disk)
mov [{MemoryAddresses.DISK_INTERFACE + 0x7}], 512 ## Size = 512 (Size of MBR is 512 bytes)
mov [{MemoryAddresses.DISK_INTERFACE + 0x9}], MemoryAddresses.MBR ## MemoryAddress = MBR Address in memory
movb [MemoryAddresses.DISK_INTERFACE], 0x00 ## Signal = Start
_load_mbr_data_block_wait_loop:
mov ACC, [{MemoryAddresses.DISK_INTERFACE + 0xB}] ## Moving <Status> register into ACC
jne $_load_mbr_data_block_wait_loop, 0x00 ## If <Status> register not Free, loop around and wait
ret
_calc_interrupt_vector_address:
arg R1
mul R1, 0x03 ## Multiply the interrupt code by 3 for memory alignment
mov R1, ACC
add R1, MemoryAddresses.INT_VEC ## Add Interrupt Vector base address to Interrupt code
mov RV, ACC
ret
_set_interrupt_vector_entry:
arg R1
push R1
push 1
call $_calc_interrupt_vector_address
mov R1, RV
arg ACC
jeq $_set_interrupt_vector_entry_disable, 0x0000
movb *R1, 0xFF
jmp $_set_interrupt_vector_entry_end
_set_interrupt_vector_entry_disable:
movb *R1, 0x00
_set_interrupt_vector_entry_end:
inc R1
mov *R1, ACC
ret
.fixed 4096, 0x00 ## BIOS Needs to be 4096 Bytes exactly