## ============================= 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 register into ACC jne $_load_mbr_data_block_wait_loop, 0x00 ## If 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