From a4fa48949c11cc117d6b6d786d22fb5bf3e9eb37 Mon Sep 17 00:00:00 2001 From: Elaina Claus Date: Sat, 5 Oct 2024 12:04:40 -0400 Subject: [PATCH 1/5] Move fat32 and BIOS functions to their own files --- include/BIOS/BIOS_func.inc | 272 ++++++++++++++++ include/fat32/fat32_func_old.inc | 274 ++++++++++++++++ src/stage2/stage2.nasm | 514 +------------------------------ 3 files changed, 551 insertions(+), 509 deletions(-) create mode 100644 include/BIOS/BIOS_func.inc create mode 100644 include/fat32/fat32_func_old.inc diff --git a/include/BIOS/BIOS_func.inc b/include/BIOS/BIOS_func.inc new file mode 100644 index 0000000..64050de --- /dev/null +++ b/include/BIOS/BIOS_func.inc @@ -0,0 +1,272 @@ +; Copyright (c) 2024 Elaina Claus +; +; Permission is hereby granted, free of charge, to any person obtaining a copy +; of this software and associated documentation files (the "Software"), to deal +; in the Software without restriction, including without limitation the rights +; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the Software is +; furnished to do so, subject to the following conditions: +; +; The above copyright notice and this permission notice shall be included in all +; copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. + +; +;INT 0x15 Function 2400 - Disable A20 +;Returns: +; +; CF = clear if success +; AH = 0 +; CF = set on error +; AH = status (01=keyboard controller is in secure mode, 0x86=function not supported) +; +;INT 0x15 Function 2401 - Enable A20 +;Returns: +; +; CF = clear if success +; AH = 0 +; CF = set on error +; AH = status (01=keyboard controller is in secure mode, 0x86=function not supported) +; +;INT 0x15 Function 2402 - A20 Status +; Returns: +; +; CF = clear if success +; AH = status (01: keyboard controller is in secure mode; 0x86: function not supported) +; AL = current state (00: disabled, 01: enabled) +; CX = set to 0xffff is keyboard controller is no ready in 0xc000 read attempts +; CF = set on error +; +;INT 0x15 Function 2403 - Query A20 support +;Returns: +; +;CF = clear if success +;AH = status (01: keyboard controller is in secure mode; 0x86: function not supported) +;BX = status. +; +;BX contains a bit pattern: +; +; Bit 0 - supported on keyboard controller +; Bit 1 - if supported on bit 1 of I/O port 0x92 +; Bits 2:14 - Reserved +; Bit 15 - 1 if additional data is available. +; +; I/O Port 0x92 infomation: +; +; Bit 0 - Setting to 1 causes a fast reset +; Bit 1 - 0: disable A20; 1: enable A20 +; Bit 2 - Manufacturer defined +; Bit 3 - power on password bytes (CMOS bytes 0x38-0x3f or 0x36-0x3f). 0: accessible, 1: inaccessible +; Bits 4-5 - Manufacturer defined +; Bits 6-7 - 00: HDD activity LED off; any other value is "on" +EnableA20: + __CDECL16_ENTRY + push ds + push es +.a20_check: + cli + + xor ax, ax + mov es, ax + + not ax ; ax = 0xFFFF + mov ds, ax + + mov di, 0x0500 ; scratch location 1 + mov si, 0x0510 ; scratch location 2 + + mov al, byte [es:di] + push ax ; save whatever is at 0x0000:0500, physical location 0x0500 + + mov al, byte [ds:si] + push ax ; save whatever is at 0xFFFF:0510 [clarification: 0x100500 physical location (0x100500 - 1MB = 0x0500)] + + mov byte [es:di], 0x00 ; zero non-wraped location and write 0xFF to it after (ab)using wrapping + mov byte [ds:si], 0xFF ; if the non-wrapped location is 0xFF, then we wraped and A20 is disabled + + cmp byte [es:di], 0xFF + + pop ax + mov byte [ds:si], al ; restore original contents of scratch location 2 + + pop ax + mov byte [es:di], al ; restore original contents of scratch location 1 + + mov ax, 0 ; return 0 if es:di == ds:si (memory wraps) + je EnableA20.end_check + mov ax, 1 ; return 1 if es:di != ds:si (A20 is enabled) +.end_check: + sti + cmp ax, 1 + je EnableA20.endp ; A20 is already enabled + + mov ax, 0x2403 + int 0x15 + jc EnableA20.do_fallback_a20 ; carry = error...not supported? + cmp ah, 0 + ja EnableA20.do_fallback_a20 ; non-zero return = error as well + + mov al, bl + and al, 0000_0010b + cmp al, 0000_0010b + je EnableA20.do_fast_a20 ; if fast a20 is supported use it + + jmp EnableA20.do_bios_a20 ; else fall back to enabling via BIOS + +.do_fallback_a20: + ERROR STAGE2_A20_FAILED +.do_bios_a20: + mov ax, 0x2401 + int 0x15 + jmp EnableA20.a20_check +.do_fast_a20: + in al, 0x92 ; read from FAST A20 port + or al, 2 ; bit 0 is a fast reset, bit 1 is fast A20 + and al, 0xFE ; make sure bit 0 is 0 + out 0x92, al ; enable A20 + jmp EnableA20.a20_check +.endp: + pop es + pop ds + __CDECL16_EXIT + ret + +; See memory.inc for a brief description of E820 mmap function +GetMemoryMap: + __CDECL16_ENTRY + push es ; save segment register +.func: + mov dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries], 0 + + mov eax, 0xE820 ; select 0xE820 function + xor ebx, ebx ; Continuation value, 0 for the first call + + mov dx, (BIOSMemoryMap >> 4) + mov es, dx + xor di, di ; (BIOSMemoryMap >> 4):0 makes di an index into BIOSMemoryMap + + mov ecx, AddressRangeDescStruct_t_size + mov edx, 0x534D4150 ; 'SMAP' magic +.loop_L1: + int 0x15 + jc GetMemoryMap.error + cmp eax, 0x534D4150 + jne GetMemoryMap.no_smap_returned +.no_error: + inc dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries] + + cmp ecx, 20 ; TODO: maybe this could be handled better than just panicing + jb GetMemoryMap.nonstandard_e820 ; non-standard entry found + + cmp ebx, 0 + je GetMemoryMap.endp ; 0 in ebx means we have reached the end of memory ranges + + add di, AddressRangeDescStruct_t_size ; increment di to next descriptor + mov edx, eax ; 'SMAP' to edx + mov eax, 0xE820 ; select E820 function + jmp GetMemoryMap.loop_L1 +.error: + ERROR STAGE2_MM_E820_MISC_ERR +.nonstandard_e820: + ERROR STAGE2_MM_E820_NONSTANDARD +.no_smap_returned: + ERROR STAGE2_MM_E820_NO_SMAP +.endp: + pop es + __CDECL16_EXIT + ret + +; Wrapper for AH=0x42 INT13h (Extended Read) +; +; BIOS call details +; AH = 42h +; DL = drive number +; DS:SI -> disk address packet +; +; Return: +; CF clear if successful +; AH = 00h +; CF set on error +; AH = error code +; disk address packet's block count field set to number of blocks +; successfully transferred +; +; +; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint32_t lba) +; TODO: this needs validation +read_disk_raw: + __CDECL16_ENTRY +.func: + mov ax, 0x10 + push ax ; len = 16 bytes + xor ax, ax + push ax ; val = 0 + mov ax, lba_packet + push ax ; dest = lba_packet address + + call kmemset ; uint8_t* kmemset(void* dest, uint8_t val, size_t len); + add sp, 0x6 + + mov byte [lba_packet + LBAPkt_t.size], 0x10 + mov word [lba_packet + LBAPkt_t.xfer_size], 0x0001 + + mov dword eax, [bp + 8] + mov dword [lba_packet + LBAPkt_t.lower_lba], eax + + mov ax, [bp + 6] + mov word [lba_packet + LBAPkt_t.offset], ax + + mov ax, [bp + 4] + mov word [lba_packet + LBAPkt_t.segment], ax + + mov si, lba_packet + mov ah, 0x42 + mov dl, byte [fat32_ebpb + FAT32_ebpb_t.drive_number_8] + int 0x13 + jnc read_disk_raw.endp + ERROR STAGE2_MBR_DISK_READ_ERROR +.endp: + __CDECL16_EXIT + ret + +; Sets output to 80x25 16 color text mode via BIOS call +; also clears screen +; void SetTextMode(void) +SetTextMode: +.prolog: + __CDECL16_ENTRY + pushf +.func: + xor ah, ah ; Set Video mode BIOS function + mov al, 0x02 ; 16 color 80x25 Text mode + int 0x10 ; Call video interrupt + + mov ah, 0x05 ; Select active display page BIOS function + xor al, al ; page 0 + int 0x10 ; call video interrupt +.endp: + popf + __CDECL16_EXIT + ret + +; disables blinking text mode cursor +disable_cursor: + __CDECL16_ENTRY +.func: + mov dx, 0x3D4 + mov al, 0xA ; low cursor shape register + out dx, al + + inc dx + mov al, 0x20 ; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape + out dx, al +.endp: + __CDECL16_EXIT + ret \ No newline at end of file diff --git a/include/fat32/fat32_func_old.inc b/include/fat32/fat32_func_old.inc new file mode 100644 index 0000000..581d3c0 --- /dev/null +++ b/include/fat32/fat32_func_old.inc @@ -0,0 +1,274 @@ +; Copyright (c) 2024 Elaina Claus +; +; Permission is hereby granted, free of charge, to any person obtaining a copy +; of this software and associated documentation files (the "Software"), to deal +; in the Software without restriction, including without limitation the rights +; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the Software is +; furnished to do so, subject to the following conditions: +; +; The above copyright notice and this permission notice shall be included in all +; copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. + +InitFATDriver: + __CDECL16_ENTRY +.func: + xor eax, eax + mov dword [fat32_state + FAT32_State_t.active_cluster_32], eax + mov dword [fat32_state + FAT32_State_t.active_FAT_cluster_32], eax + mov dword [fat32_state + FAT32_State_t.first_root_dir_sector_32], eax + mov dword [fat32_state + FAT32_State_t.active_dir_cluster_32], eax + +.calc_active_part: + mov ax, word [partition_offset] + mov bx, partition_table + add bx, ax ; bx points to the partition that was booted from + + mov eax, dword [bx + PartEntry_t.lba_start] + mov dword [fat32_state + FAT32_State_t.active_drive_lba_32], eax + +.calc_first_fat: + movzx eax, word [fat32_bpb + FAT32_bpb_t.reserved_sectors_16] ; first fat from start of partition + add eax, dword [fat32_state + FAT32_State_t.active_drive_lba_32] ; calculate offset from start of drive + + mov dword [fat32_state + FAT32_State_t.first_fat_sector_32], eax +.calc_total_fat: + mov ebx, dword [fat32_ebpb + FAT32_ebpb_t.sectors_per_fat_32] + movzx eax, byte [fat32_bpb + FAT32_bpb_t.fat_count_8] + mul ebx ; result in EDX:EAX, CF set on > 32bit return value + jc InitFATDriver.error ; as a catch for unhandled overflow, just error if value is greater than 32bits + + mov dword [fat32_state + FAT32_State_t.fat_size_32], eax +.calc_first_data: + mov edx, dword [fat32_state + FAT32_State_t.first_fat_sector_32] + add eax, edx + + mov dword [fat32_state + FAT32_State_t.first_data_sector_32], eax +.get_first_root_dir: + ; TODO + + jmp InitFATDriver.endp +.error: + ERROR STAGE2_FAT32_INIT_ERROR +.endp: + __CDECL16_EXIT + ret + +; TODO: needs validation +; load a file to the high memory buffer for the elf parser +; this involves using the low memory buffer for the bios call and moving the file sector by sector to high memory +; +; SFN is a 8.3 file name, all uppercase, and padded with spaces +; do not add a null byte to the end of the string +; eg. kernel.bin == "KERNEL BIN" +; +; returns first cluster of file if found +; halts/errors if file is not found +; uint32_t SearchFATDIR(uint8_t* SFN); +SearchFATDIR: + __CDECL16_ENTRY +.file_lookup: + .load_first_dir: + mov eax, [fat32_ebpb + FAT32_ebpb_t.root_dir_cluster_32] + mov dword [fat32_state + FAT32_State_t.active_dir_cluster_32], eax + + push dword eax ; cluster + lea ax, [dir_buffer] + push ax ; offset + xor ax, ax + push ax ; segment + call ReadFATCluster ; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster) + add sp, 0x8 + + lea si, [dir_buffer] + jmp SearchFATDIR.empty_dir_entry + + .load_next_dir: + ; if eax >= 0x0FFFFFF8 then there are no more clusters (end of chain) + ; if eax == 0x0FFFFFF7 then this is a cluster that is marked as bad + mov eax, dword [fat32_state + FAT32_State_t.active_dir_cluster_32] + push dword eax + call NextCluster ; uint32_t NextCluster(uint32_t active_cluster); + add sp, 0x4 + + cmp eax, 0x0fff_fff7 + jb SearchFATDIR.load_next_dir_next_OK + ERROR STAGE2_FAT32_END_OF_CHAIN + + .load_next_dir_next_OK: + ; load 512 bytes of directory entries from data sector + mov eax, [fat32_state + FAT32_State_t.active_dir_cluster_32] + + push dword eax + lea ax, [dir_buffer] ; cluster + push ax ; offset + xor ax, ax + push ax ; segment + call ReadFATCluster ; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster) + sub sp, 0x8 + + lea si, [dir_buffer] + .empty_dir_entry: + ; check for 0x0 in first byte, if true then there are no more files + ; if true we did not find the file, we should error here + cmp byte [si], 0 + jne SearchFATDIR.unused_dir_entry + ERROR STAGE2_FAT32_NO_FILE + + .unused_dir_entry: + ; check for 0xe5 and 0x05 in first byte, if true then this entry is unused, but it is not the last entry. + cmp byte [si], 0xe5 + je SearchFATDIR.next_entry + + cmp byte [si], 0x05 + je SearchFATDIR.next_entry + jmp SearchFATDIR.parse_dir + + .next_entry: + ; increment offset by 32 bytes to read the next entry in this set of dir entries + ; if we are at the end of the buffer, then load the next buffer + add si, 0x20 ; 32 bytes + + lea ax, [dir_buffer] + add ax, 0x1FF ; 512 - 1 bytes + cmp si, ax + jae SearchFATDIR.load_next_dir + jmp SearchFATDIR.empty_dir_entry + + .parse_dir: + .lfn_check: + ; check for ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID (0x0F) in offset 11 + ; TODO: going to skip LFN for now, since all valid volumes will have SFN's + cmp byte [si+11], 0x0F + je SearchFATDIR.next_entry + .sfn_file_name_check: + push si + push di + + mov cx, 0xA ; max of 11 filename length of 11 characters + ; si points to the start of the current directory entry + lea di, [BootTarget_str] ; current memory location (8.3 name is at offset 0) + repe cmpsb ; compare the strings + + pop di + pop si + jne SearchFATDIR.next_entry + + .sfn_entry_found: + mov ax, [si + FAT32_SFN_t.cluster_16_high] + shl eax, 16 + mov ax, [si + FAT32_SFN_t.cluster_16_low] + ; eax == first cluster of file +.endp: + __CDECL16_EXIT + ret + +; uint32_t NextCluster(uint32_t active_cluster); +; if eax >= 0x0FFFFFF8 then there are no more clusters (end of chain) +; if eax == 0x0FFFFFF7 then this is a cluster that is marked as bad +NextCluster: + __CDECL16_ENTRY +.func: + mov dword edx, [bp + 4] + mov si, fat32_nc_data +.calc_offset: +; fat_offset = active_cluster * 4 + mov eax, 4 + mul edx + mov dword [si + FAT32_NextClusterData_t.fat_offset], eax + +.calc_fat_sector: +; fat_sector = first_fat_sector + (fat_offset / sector_size) +; entry_offset = fat_offset % sector_size + mov edx, 0xffff_0000 + and edx, eax + shr edx, 16 + + push si + mov si, fat32_bpb + mov cx, word [si + FAT32_bpb_t.bytes_per_sector_16] + pop si + + div cx ; DX:AX / cx = fat_sector - first_fat_sector in AX + ; DX = remainder (fat_offset mod sector_size) + + mov ecx, 0x0000_ffff + and edx, ecx + mov dword [si + FAT32_NextClusterData_t.entry_offset], edx + + push si + mov si, fat32_state + mov ecx, dword [si + FAT32_State_t.first_fat_sector_32] + pop si + + mov edx, 0x0000ffff + and eax, edx + add eax, ecx ; fat_sector + first_fat_sector + mov dword [si + FAT32_NextClusterData_t.fat_sector], eax +.load_fat_table: + ; load correct fat + push dword eax + + mov ax, fat_buffer + push ax + + xor ax, ax + push ax + ; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint16_t lower_lower_lba, uint16_t upper_lower_lba) + call read_disk_raw ; read_disk_raw(0, fat_buffer, fat_sector) + add sp, 0x8 + +.read_cluster: +; next_cluster = fat_buffer[entry_offset] + mov ebx, dword [si + FAT32_NextClusterData_t.entry_offset] + mov si, fat_buffer + mov eax, dword [bx+si+0] +.endp: + __CDECL16_EXIT + ret + +; uint32_t ClusterToLBA(uint32_t cluster) +ClusterToLBA: + __CDECL16_ENTRY +.func: + mov dword eax, [bp + 4] + sub eax, 2 + movzx edx, byte [fat32_bpb + FAT32_bpb_t.sectors_per_cluster_8] + mul edx + add eax, dword [fat32_state + FAT32_State_t.first_data_sector_32] + ; eax contains the LBA now +.endp: + __CDECL16_EXIT + ret + +; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster) +ReadFATCluster: + __CDECL16_ENTRY +.func: + mov dword eax, [bp + 8] + push dword eax + call ClusterToLBA ; uint32_t ClusterToLBA(uint32_t cluster) + add sp, 0x4 ; eax == LBA + + + push dword eax ;uint32_t lba + + mov dx, [bp + 4] ; seg + push dx ; uint16_t buf_offset + + mov dx, [bp + 6] ; offset + push dx ; unit16_t segment + + call read_disk_raw ; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint32_t lba) + add sp, 0x8 +.endp: + __CDECL16_EXIT + ret diff --git a/src/stage2/stage2.nasm b/src/stage2/stage2.nasm index 87609ca..e061f9c 100755 --- a/src/stage2/stage2.nasm +++ b/src/stage2/stage2.nasm @@ -138,260 +138,7 @@ hcf: ; ; ############### -InitFATDriver: - __CDECL16_ENTRY -.func: - xor eax, eax - mov dword [fat32_state + FAT32_State_t.active_cluster_32], eax - mov dword [fat32_state + FAT32_State_t.active_FAT_cluster_32], eax - mov dword [fat32_state + FAT32_State_t.first_root_dir_sector_32], eax - mov dword [fat32_state + FAT32_State_t.active_dir_cluster_32], eax - -.calc_active_part: - mov ax, word [partition_offset] - mov bx, partition_table - add bx, ax ; bx points to the partition that was booted from - - mov eax, dword [bx + PartEntry_t.lba_start] - mov dword [fat32_state + FAT32_State_t.active_drive_lba_32], eax - -.calc_first_fat: - movzx eax, word [fat32_bpb + FAT32_bpb_t.reserved_sectors_16] ; first fat from start of partition - add eax, dword [fat32_state + FAT32_State_t.active_drive_lba_32] ; calculate offset from start of drive - - mov dword [fat32_state + FAT32_State_t.first_fat_sector_32], eax -.calc_total_fat: - mov ebx, dword [fat32_ebpb + FAT32_ebpb_t.sectors_per_fat_32] - movzx eax, byte [fat32_bpb + FAT32_bpb_t.fat_count_8] - mul ebx ; result in EDX:EAX, CF set on > 32bit return value - jc InitFATDriver.error ; as a catch for unhandled overflow, just error if value is greater than 32bits - - mov dword [fat32_state + FAT32_State_t.fat_size_32], eax -.calc_first_data: - mov edx, dword [fat32_state + FAT32_State_t.first_fat_sector_32] - add eax, edx - - mov dword [fat32_state + FAT32_State_t.first_data_sector_32], eax -.get_first_root_dir: - ; TODO - - jmp InitFATDriver.endp -.error: - ERROR STAGE2_FAT32_INIT_ERROR -.endp: - __CDECL16_EXIT - ret - -; TODO: needs validation -; load a file to the high memory buffer for the elf parser -; this involves using the low memory buffer for the bios call and moving the file sector by sector to high memory -; -; SFN is a 8.3 file name, all uppercase, and padded with spaces -; do not add a null byte to the end of the string -; eg. kernel.bin == "KERNEL BIN" -; -; returns first cluster of file if found -; halts/errors if file is not found -; uint32_t SearchFATDIR(uint8_t* SFN); -SearchFATDIR: - __CDECL16_ENTRY -.file_lookup: - .load_first_dir: - mov eax, [fat32_ebpb + FAT32_ebpb_t.root_dir_cluster_32] - mov dword [fat32_state + FAT32_State_t.active_dir_cluster_32], eax - - push dword eax ; cluster - lea ax, [dir_buffer] - push ax ; offset - xor ax, ax - push ax ; segment - call ReadFATCluster ; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster) - add sp, 0x8 - - lea si, [dir_buffer] - jmp SearchFATDIR.empty_dir_entry - - .load_next_dir: - ; if eax >= 0x0FFFFFF8 then there are no more clusters (end of chain) - ; if eax == 0x0FFFFFF7 then this is a cluster that is marked as bad - mov eax, dword [fat32_state + FAT32_State_t.active_dir_cluster_32] - push dword eax - call NextCluster ; uint32_t NextCluster(uint32_t active_cluster); - add sp, 0x4 - - cmp eax, 0x0fff_fff7 - jb SearchFATDIR.load_next_dir_next_OK - ERROR STAGE2_FAT32_END_OF_CHAIN - - .load_next_dir_next_OK: - ; load 512 bytes of directory entries from data sector - mov eax, [fat32_state + FAT32_State_t.active_dir_cluster_32] - - push dword eax - lea ax, [dir_buffer] ; cluster - push ax ; offset - xor ax, ax - push ax ; segment - call ReadFATCluster ; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster) - sub sp, 0x8 - - lea si, [dir_buffer] - .empty_dir_entry: - ; check for 0x0 in first byte, if true then there are no more files - ; if true we did not find the file, we should error here - cmp byte [si], 0 - jne SearchFATDIR.unused_dir_entry - ERROR STAGE2_FAT32_NO_FILE - - .unused_dir_entry: - ; check for 0xe5 and 0x05 in first byte, if true then this entry is unused, but it is not the last entry. - cmp byte [si], 0xe5 - je SearchFATDIR.next_entry - - cmp byte [si], 0x05 - je SearchFATDIR.next_entry - jmp SearchFATDIR.parse_dir - - .next_entry: - ; increment offset by 32 bytes to read the next entry in this set of dir entries - ; if we are at the end of the buffer, then load the next buffer - add si, 0x20 ; 32 bytes - - lea ax, [dir_buffer] - add ax, 0x1FF ; 512 - 1 bytes - cmp si, ax - jae SearchFATDIR.load_next_dir - jmp SearchFATDIR.empty_dir_entry - - .parse_dir: - .lfn_check: - ; check for ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID (0x0F) in offset 11 - ; TODO: going to skip LFN for now, since all valid volumes will have SFN's - cmp byte [si+11], 0x0F - je SearchFATDIR.next_entry - .sfn_file_name_check: - push si - push di - - mov cx, 0xA ; max of 11 filename length of 11 characters - ; si points to the start of the current directory entry - lea di, [BootTarget_str] ; current memory location (8.3 name is at offset 0) - repe cmpsb ; compare the strings - - pop di - pop si - jne SearchFATDIR.next_entry - - .sfn_entry_found: - mov ax, [si + FAT32_SFN_t.cluster_16_high] - shl eax, 16 - mov ax, [si + FAT32_SFN_t.cluster_16_low] - ; eax == first cluster of file -.endp: - __CDECL16_EXIT - ret - -; uint32_t NextCluster(uint32_t active_cluster); -; if eax >= 0x0FFFFFF8 then there are no more clusters (end of chain) -; if eax == 0x0FFFFFF7 then this is a cluster that is marked as bad -NextCluster: - __CDECL16_ENTRY -.func: - mov dword edx, [bp + 4] - mov si, fat32_nc_data -.calc_offset: -; fat_offset = active_cluster * 4 - mov eax, 4 - mul edx - mov dword [si + FAT32_NextClusterData_t.fat_offset], eax - -.calc_fat_sector: -; fat_sector = first_fat_sector + (fat_offset / sector_size) -; entry_offset = fat_offset % sector_size - mov edx, 0xffff_0000 - and edx, eax - shr edx, 16 - - push si - mov si, fat32_bpb - mov cx, word [si + FAT32_bpb_t.bytes_per_sector_16] - pop si - - div cx ; DX:AX / cx = fat_sector - first_fat_sector in AX - ; DX = remainder (fat_offset mod sector_size) - - mov ecx, 0x0000_ffff - and edx, ecx - mov dword [si + FAT32_NextClusterData_t.entry_offset], edx - - push si - mov si, fat32_state - mov ecx, dword [si + FAT32_State_t.first_fat_sector_32] - pop si - - mov edx, 0x0000ffff - and eax, edx - add eax, ecx ; fat_sector + first_fat_sector - mov dword [si + FAT32_NextClusterData_t.fat_sector], eax -.load_fat_table: - ; load correct fat - push dword eax - - mov ax, fat_buffer - push ax - - xor ax, ax - push ax - ; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint16_t lower_lower_lba, uint16_t upper_lower_lba) - call read_disk_raw ; read_disk_raw(0, fat_buffer, fat_sector) - add sp, 0x8 - -.read_cluster: -; next_cluster = fat_buffer[entry_offset] - mov ebx, dword [si + FAT32_NextClusterData_t.entry_offset] - mov si, fat_buffer - mov eax, dword [bx+si+0] -.endp: - __CDECL16_EXIT - ret - -; uint32_t ClusterToLBA(uint32_t cluster) -ClusterToLBA: - __CDECL16_ENTRY -.func: - mov dword eax, [bp + 4] - sub eax, 2 - movzx edx, byte [fat32_bpb + FAT32_bpb_t.sectors_per_cluster_8] - mul edx - add eax, dword [fat32_state + FAT32_State_t.first_data_sector_32] - ; eax contains the LBA now -.endp: - __CDECL16_EXIT - ret - -; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster) -ReadFATCluster: - __CDECL16_ENTRY -.func: - mov dword eax, [bp + 8] - push dword eax - call ClusterToLBA ; uint32_t ClusterToLBA(uint32_t cluster) - add sp, 0x4 ; eax == LBA - - - push dword eax ;uint32_t lba - - mov dx, [bp + 4] ; seg - push dx ; uint16_t buf_offset - - mov dx, [bp + 6] ; offset - push dx ; unit16_t segment - - call read_disk_raw ; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint32_t lba) - add sp, 0x8 -.endp: - __CDECL16_EXIT - ret +%include 'fat32/fat32_func_old.inc' ; ############### ; @@ -399,59 +146,13 @@ ReadFATCluster: ; ; ############### +%include 'BIOS/BIOS_func.inc' -; Wrapper for AH=0x42 INT13h (Extended Read) +; ############################## ; -; BIOS call details -; AH = 42h -; DL = drive number -; DS:SI -> disk address packet +; SYSTEM CONFIGURATION FUNCTIONS ; -; Return: -; CF clear if successful -; AH = 00h -; CF set on error -; AH = error code -; disk address packet's block count field set to number of blocks -; successfully transferred -; -; -; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint32_t lba) -; TODO: this needs validation -read_disk_raw: - __CDECL16_ENTRY -.func: - mov ax, 0x10 - push ax ; len = 16 bytes - xor ax, ax - push ax ; val = 0 - mov ax, lba_packet - push ax ; dest = lba_packet address - - call kmemset ; uint8_t* kmemset(void* dest, uint8_t val, size_t len); - add sp, 0x6 - - mov byte [lba_packet + LBAPkt_t.size], 0x10 - mov word [lba_packet + LBAPkt_t.xfer_size], 0x0001 - - mov dword eax, [bp + 8] - mov dword [lba_packet + LBAPkt_t.lower_lba], eax - - mov ax, [bp + 6] - mov word [lba_packet + LBAPkt_t.offset], ax - - mov ax, [bp + 4] - mov word [lba_packet + LBAPkt_t.segment], ax - - mov si, lba_packet - mov ah, 0x42 - mov dl, byte [fat32_ebpb + FAT32_ebpb_t.drive_number_8] - int 0x13 - jnc read_disk_raw.endp - ERROR STAGE2_MBR_DISK_READ_ERROR -.endp: - __CDECL16_EXIT - ret +; ############################## ; Prints a C-Style string (null terminated) using BIOS vga teletype call ; void PrintString(char* buf) @@ -550,217 +251,12 @@ PrintDWORD: __CDECL16_EXIT ret -; Sets output to 80x25 16 color text mode via BIOS call -; also clears screen -; void SetTextMode(void) -SetTextMode: -.prolog: - __CDECL16_ENTRY - pushf -.func: - xor ah, ah ; Set Video mode BIOS function - mov al, 0x02 ; 16 color 80x25 Text mode - int 0x10 ; Call video interrupt - - mov ah, 0x05 ; Select active display page BIOS function - xor al, al ; page 0 - int 0x10 ; call video interrupt -.endp: - popf - __CDECL16_EXIT - ret - -; See memory.inc for a brief description of E820 mmap function -GetMemoryMap: - __CDECL16_ENTRY - push es ; save segment register -.func: - mov dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries], 0 - - mov eax, 0xE820 ; select 0xE820 function - xor ebx, ebx ; Continuation value, 0 for the first call - - mov dx, (BIOSMemoryMap >> 4) - mov es, dx - xor di, di ; (BIOSMemoryMap >> 4):0 makes di an index into BIOSMemoryMap - - mov ecx, AddressRangeDescStruct_t_size - mov edx, 0x534D4150 ; 'SMAP' magic -.loop_L1: - int 0x15 - jc GetMemoryMap.error - cmp eax, 0x534D4150 - jne GetMemoryMap.no_smap_returned -.no_error: - inc dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries] - - cmp ecx, 20 ; TODO: maybe this could be handled better than just panicing - jb GetMemoryMap.nonstandard_e820 ; non-standard entry found - - cmp ebx, 0 - je GetMemoryMap.endp ; 0 in ebx means we have reached the end of memory ranges - - add di, AddressRangeDescStruct_t_size ; increment di to next descriptor - mov edx, eax ; 'SMAP' to edx - mov eax, 0xE820 ; select E820 function - jmp GetMemoryMap.loop_L1 -.error: - ERROR STAGE2_MM_E820_MISC_ERR -.nonstandard_e820: - ERROR STAGE2_MM_E820_NONSTANDARD -.no_smap_returned: - ERROR STAGE2_MM_E820_NO_SMAP -.endp: - pop es - __CDECL16_EXIT - ret - ; ############################## ; ; SYSTEM CONFIGURATION FUNCTIONS ; ; ############################## -; disables blinking text mode cursor -disable_cursor: -.prolog: - __CDECL16_ENTRY - pushf -.func: - mov dx, 0x3D4 - mov al, 0xA ; low cursor shape register - out dx, al - - inc dx - mov al, 0x20 ; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape - out dx, al -.endp: - popf - __CDECL16_EXIT - ret - -; -;NT 0x15 Function 2400 - Disable A20 -;Returns: -; -; CF = clear if success -; AH = 0 -; CF = set on error -; AH = status (01=keyboard controller is in secure mode, 0x86=function not supported) -; -;INT 0x15 Function 2401 - Enable A20 -;Returns: -; -; CF = clear if success -; AH = 0 -; CF = set on error -; AH = status (01=keyboard controller is in secure mode, 0x86=function not supported) -; -;INT 0x15 Function 2402 - A20 Status -; Returns: -; -; CF = clear if success -; AH = status (01: keyboard controller is in secure mode; 0x86: function not supported) -; AL = current state (00: disabled, 01: enabled) -; CX = set to 0xffff is keyboard controller is no ready in 0xc000 read attempts -; CF = set on error -; -;INT 0x15 Function 2403 - Query A20 support -;Returns: -; -;CF = clear if success -;AH = status (01: keyboard controller is in secure mode; 0x86: function not supported) -;BX = status. -; -;BX contains a bit pattern: -; -; Bit 0 - supported on keyboard controller -; Bit 1 - if supported on bit 1 of I/O port 0x92 -; Bits 2:14 - Reserved -; Bit 15 - 1 if additional data is available. -; -; I/O Port 0x92 infomation: -; -; Bit 0 - Setting to 1 causes a fast reset -; Bit 1 - 0: disable A20; 1: enable A20 -; Bit 2 - Manufacturer defined -; Bit 3 - power on password bytes (CMOS bytes 0x38-0x3f or 0x36-0x3f). 0: accessible, 1: inaccessible -; Bits 4-5 - Manufacturer defined -; Bits 6-7 - 00: HDD activity LED off; any other value is "on" -EnableA20: - __CDECL16_ENTRY - push ds - push es - pushf ; save data and extra segment since we touch them and save flags -.a20_check: - cli - - xor ax, ax - mov es, ax - - not ax ; ax = 0xFFFF - mov ds, ax - - mov di, 0x0500 ; scratch location 1 - mov si, 0x0510 ; scratch location 2 - - mov al, byte [es:di] - push ax ; save whatever is at 0x0000:0500, physical location 0x0500 - - mov al, byte [ds:si] - push ax ; save whatever is at 0xFFFF:0510 [clarification: 0x100500 physical location (0x100500 - 1MB = 0x0500)] - - mov byte [es:di], 0x00 ; zero non-wraped location and write 0xFF to it after (ab)using wrapping - mov byte [ds:si], 0xFF ; if the non-wrapped location is 0xFF, then we wraped and A20 is disabled - - cmp byte [es:di], 0xFF - - pop ax - mov byte [ds:si], al ; restore original contents of scratch location 2 - - pop ax - mov byte [es:di], al ; restore original contents of scratch location 1 - - mov ax, 0 ; return 0 if es:di == ds:si (memory wraps) - je EnableA20.end_check - mov ax, 1 ; return 1 if es:di != ds:si (A20 is enabled) -.end_check: - sti - cmp ax, 1 - je EnableA20.endp ; A20 is already enabled - - mov ax, 0x2403 - int 0x15 - jc EnableA20.do_fallback_a20 ; carry = error...not supported? - cmp ah, 0 - ja EnableA20.do_fallback_a20 ; non-zero return = error as well - - mov al, bl - and al, 0000_0010b - cmp al, 0000_0010b - je EnableA20.do_fast_a20 ; if fast a20 is supported use it - - jmp EnableA20.do_bios_a20 ; else fall back to enabling via BIOS - -.do_fallback_a20: - ERROR STAGE2_A20_FAILED -.do_bios_a20: - mov ax, 0x2401 - int 0x15 - jmp EnableA20.a20_check -.do_fast_a20: - in al, 0x92 ; read from FAST A20 port - or al, 2 ; bit 0 is a fast reset, bit 1 is fast A20 - and al, 0xFE ; make sure bit 0 is 0 - out 0x92, al ; enable A20 - jmp EnableA20.a20_check -.endp: - popf - pop es - pop ds - __CDECL16_EXIT - ret - EnterUnrealMode: __CDECL16_ENTRY .func: From d6af15a7a673513857b6d12d9173b64288d22b5d Mon Sep 17 00:00:00 2001 From: Elaina Claus Date: Sat, 5 Oct 2024 12:16:31 -0400 Subject: [PATCH 2/5] typo fix --- include/fat32/fat32_func_old.inc | 1 - 1 file changed, 1 deletion(-) diff --git a/include/fat32/fat32_func_old.inc b/include/fat32/fat32_func_old.inc index 581d3c0..33175ed 100644 --- a/include/fat32/fat32_func_old.inc +++ b/include/fat32/fat32_func_old.inc @@ -63,7 +63,6 @@ InitFATDriver: ret ; TODO: needs validation -; load a file to the high memory buffer for the elf parser ; this involves using the low memory buffer for the bios call and moving the file sector by sector to high memory ; ; SFN is a 8.3 file name, all uppercase, and padded with spaces From 5440a1ae61cdba182494c53988efa21129b76b6f Mon Sep 17 00:00:00 2001 From: Elaina Claus Date: Sat, 5 Oct 2024 13:35:39 -0400 Subject: [PATCH 3/5] more modularization and updating date in MIT licence header --- include/BIOS/BIOS_sys.inc | 24 +++ include/BIOS/func/E820_memory_map.inc | 161 ++++++++++++++++++ .../{BIOS_func.inc => func/a20enable.inc} | 133 --------------- include/BIOS/func/ext_read.inc | 90 ++++++++++ include/BIOS/func/video.inc | 54 ++++++ include/config.inc | 2 +- include/entry.inc | 10 +- include/{errors.inc => error_codes.inc} | 36 +--- include/fat32/bpb.inc | 2 +- include/memory.inc | 99 +---------- include/partition_table.inc | 21 +-- include/util/error_func.inc | 50 ++++++ src/mbr/mbr.nasm | 2 +- src/stage2/stage2.nasm | 6 +- src/vbr/vbr.nasm | 2 +- 15 files changed, 395 insertions(+), 297 deletions(-) create mode 100644 include/BIOS/BIOS_sys.inc create mode 100644 include/BIOS/func/E820_memory_map.inc rename include/BIOS/{BIOS_func.inc => func/a20enable.inc} (55%) create mode 100644 include/BIOS/func/ext_read.inc create mode 100644 include/BIOS/func/video.inc rename include/{errors.inc => error_codes.inc} (80%) create mode 100644 include/util/error_func.inc diff --git a/include/BIOS/BIOS_sys.inc b/include/BIOS/BIOS_sys.inc new file mode 100644 index 0000000..c453986 --- /dev/null +++ b/include/BIOS/BIOS_sys.inc @@ -0,0 +1,24 @@ +; Copyright (c) 2024 Elaina Claus +; +; Permission is hereby granted, free of charge, to any person obtaining a copy +; of this software and associated documentation files (the "Software"), to deal +; in the Software without restriction, including without limitation the rights +; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the Software is +; furnished to do so, subject to the following conditions: +; +; The above copyright notice and this permission notice shall be included in all +; copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. + +%include 'BIOS/func/a20enable.inc' +%include 'BIOS/func/E820_memory_map.inc' +%include 'BIOS/func/ext_read.inc' +%include 'BIOS/func/video.inc' \ No newline at end of file diff --git a/include/BIOS/func/E820_memory_map.inc b/include/BIOS/func/E820_memory_map.inc new file mode 100644 index 0000000..9cd9231 --- /dev/null +++ b/include/BIOS/func/E820_memory_map.inc @@ -0,0 +1,161 @@ +; Copyright (c) 2024 Elaina Claus +; +; Permission is hereby granted, free of charge, to any person obtaining a copy +; of this software and associated documentation files (the "Software"), to deal +; in the Software without restriction, including without limitation the rights +; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the Software is +; furnished to do so, subject to the following conditions: +; +; The above copyright notice and this permission notice shall be included in all +; copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. + + +; Address Range Descriptor Structure +; +; Offset in Bytes Name Description +; 0 BaseAddrLow Low 32 Bits of Base Address +; 4 BaseAddrHigh High 32 Bits of Base Address +; 8 LengthLow Low 32 Bits of Length in Bytes +; 12 LengthHigh High 32 Bits of Length in Bytes +; 16 Type Address type of this range. +; Address Range Descriptor Structure +; +; Offset in Bytes Name Description +; 0 BaseAddrLow Low 32 Bits of Base Address +; 4 BaseAddrHigh High 32 Bits of Base Address +; 8 LengthLow Low 32 Bits of Length in Bytes +; 12 LengthHigh High 32 Bits of Length in Bytes +; 16 Type Address type of this range. +; Input: +; +; EAX Function Code E820h +; EBX Continuation Contains the "continuation value" to get the +; next run of physical memory. This is the +; value returned by a previous call to this +; routine. If this is the first call, EBX +; must contain zero. +; ES:DI Buffer Pointer Pointer to an Address Range Descriptor +; structure which the BIOS is to fill in. +; ECX Buffer Size The length in bytes of the structure passed +; to the BIOS. The BIOS will fill in at most +; ECX bytes of the structure or however much +; of the structure the BIOS implements. The +; minimum size which must be supported by both +; the BIOS and the caller is 20 bytes. Future +; implementations may extend this structure. +; EDX Signature 'SMAP' - Used by the BIOS to verify the +; caller is requesting the system map +; information to be returned in ES:DI. +; +; Output: +; +; CF Carry Flag Non-Carry - indicates no error +; EAX Signature 'SMAP' - Signature to verify correct BIOS +; revision. +; ES:DI Buffer Pointer Returned Address Range Descriptor pointer. +; Same value as on input. +; ECX Buffer Size Number of bytes returned by the BIOS in the +; address range descriptor. The minimum size +; structure returned by the BIOS is 20 bytes. +; EBX Continuation Contains the continuation value to get the +; next address descriptor. The actual +; significance of the continuation value is up +; to the discretion of the BIOS. The caller +; must pass the continuation value unchanged +; as input to the next iteration of the E820 +; call in order to get the next Address Range +; Descriptor. A return value of zero means that +; this is the last descriptor +; +; Address Range Descriptor Structure +; +; Offset in Bytes Name Description +; 0 BaseAddrLow Low 32 Bits of Base Address +; 4 BaseAddrHigh High 32 Bits of Base Address +; 8 LengthLow Low 32 Bits of Length in Bytes +; 12 LengthHigh High 32 Bits of Length in Bytes +; 16 Type Address type of this range. +; +; The BaseAddrLow and BaseAddrHigh together are the 64 bit BaseAddress of this range. +; The BaseAddress is the physical address of the start of the range being specified. +; +; The LengthLow and LengthHigh together are the 64 bit Length of this range. +; The Length is the physical contiguous length in bytes of a range being specified. +; +; The Type field describes the usage of the described address range as defined in the table below. + +; Value Pneumonic Description +; 1 AddressRangeMemory This run is available RAM usable by the operating system. +; 2 AddressRangeReserved This run of addresses is in use or reserved by the system, and must not be used by the operating system. +; Other Undefined Undefined - Reserved for future use. + +; Address Range Descriptor Structure +; +; Offset in Bytes Name Description +; 0 BaseAddrLow u32 - Low 32 Bits of Base Address +; 4 BaseAddrHigh u32 - High 32 Bits of Base Address +; 8 LengthLow u32 - Low 32 Bits of Length in Bytes +; 12 LengthHigh u32 - High 32 Bits of Length in Bytes +; 16 Type u32 - Address type of this range. +; 20 ExtType u32 - ACPI 3.0 extended type +struc AddressRangeDescStruct_t + .BaseAddrLow resd 1 + .BaseAddrHigh resd 1 + .LengthLow resd 1 + .LengthHigh resd 1 + .Type resd 1 + .ExtType resd 1 +endstruc + +GetMemoryMap: + __CDECL16_ENTRY + push es ; save segment register +.func: + mov dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries], 0 + + mov eax, 0xE820 ; select 0xE820 function + xor ebx, ebx ; Continuation value, 0 for the first call + + mov dx, (BIOSMemoryMap >> 4) + mov es, dx + xor di, di ; (BIOSMemoryMap >> 4):0 makes di an index into BIOSMemoryMap + + mov ecx, AddressRangeDescStruct_t_size + mov edx, 0x534D4150 ; 'SMAP' magic +.loop_L1: + int 0x15 + jc GetMemoryMap.error + cmp eax, 0x534D4150 + jne GetMemoryMap.no_smap_returned +.no_error: + inc dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries] + + cmp ecx, 20 ; TODO: maybe this could be handled better than just panicing + jb GetMemoryMap.nonstandard_e820 ; non-standard entry found + + cmp ebx, 0 + je GetMemoryMap.endp ; 0 in ebx means we have reached the end of memory ranges + + add di, AddressRangeDescStruct_t_size ; increment di to next descriptor + mov edx, eax ; 'SMAP' to edx + mov eax, 0xE820 ; select E820 function + jmp GetMemoryMap.loop_L1 +.error: + ERROR STAGE2_MM_E820_MISC_ERR +.nonstandard_e820: + ERROR STAGE2_MM_E820_NONSTANDARD +.no_smap_returned: + ERROR STAGE2_MM_E820_NO_SMAP +.endp: + pop es + __CDECL16_EXIT + ret \ No newline at end of file diff --git a/include/BIOS/BIOS_func.inc b/include/BIOS/func/a20enable.inc similarity index 55% rename from include/BIOS/BIOS_func.inc rename to include/BIOS/func/a20enable.inc index 64050de..0b18bf5 100644 --- a/include/BIOS/BIOS_func.inc +++ b/include/BIOS/func/a20enable.inc @@ -135,138 +135,5 @@ EnableA20: .endp: pop es pop ds - __CDECL16_EXIT - ret - -; See memory.inc for a brief description of E820 mmap function -GetMemoryMap: - __CDECL16_ENTRY - push es ; save segment register -.func: - mov dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries], 0 - - mov eax, 0xE820 ; select 0xE820 function - xor ebx, ebx ; Continuation value, 0 for the first call - - mov dx, (BIOSMemoryMap >> 4) - mov es, dx - xor di, di ; (BIOSMemoryMap >> 4):0 makes di an index into BIOSMemoryMap - - mov ecx, AddressRangeDescStruct_t_size - mov edx, 0x534D4150 ; 'SMAP' magic -.loop_L1: - int 0x15 - jc GetMemoryMap.error - cmp eax, 0x534D4150 - jne GetMemoryMap.no_smap_returned -.no_error: - inc dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries] - - cmp ecx, 20 ; TODO: maybe this could be handled better than just panicing - jb GetMemoryMap.nonstandard_e820 ; non-standard entry found - - cmp ebx, 0 - je GetMemoryMap.endp ; 0 in ebx means we have reached the end of memory ranges - - add di, AddressRangeDescStruct_t_size ; increment di to next descriptor - mov edx, eax ; 'SMAP' to edx - mov eax, 0xE820 ; select E820 function - jmp GetMemoryMap.loop_L1 -.error: - ERROR STAGE2_MM_E820_MISC_ERR -.nonstandard_e820: - ERROR STAGE2_MM_E820_NONSTANDARD -.no_smap_returned: - ERROR STAGE2_MM_E820_NO_SMAP -.endp: - pop es - __CDECL16_EXIT - ret - -; Wrapper for AH=0x42 INT13h (Extended Read) -; -; BIOS call details -; AH = 42h -; DL = drive number -; DS:SI -> disk address packet -; -; Return: -; CF clear if successful -; AH = 00h -; CF set on error -; AH = error code -; disk address packet's block count field set to number of blocks -; successfully transferred -; -; -; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint32_t lba) -; TODO: this needs validation -read_disk_raw: - __CDECL16_ENTRY -.func: - mov ax, 0x10 - push ax ; len = 16 bytes - xor ax, ax - push ax ; val = 0 - mov ax, lba_packet - push ax ; dest = lba_packet address - - call kmemset ; uint8_t* kmemset(void* dest, uint8_t val, size_t len); - add sp, 0x6 - - mov byte [lba_packet + LBAPkt_t.size], 0x10 - mov word [lba_packet + LBAPkt_t.xfer_size], 0x0001 - - mov dword eax, [bp + 8] - mov dword [lba_packet + LBAPkt_t.lower_lba], eax - - mov ax, [bp + 6] - mov word [lba_packet + LBAPkt_t.offset], ax - - mov ax, [bp + 4] - mov word [lba_packet + LBAPkt_t.segment], ax - - mov si, lba_packet - mov ah, 0x42 - mov dl, byte [fat32_ebpb + FAT32_ebpb_t.drive_number_8] - int 0x13 - jnc read_disk_raw.endp - ERROR STAGE2_MBR_DISK_READ_ERROR -.endp: - __CDECL16_EXIT - ret - -; Sets output to 80x25 16 color text mode via BIOS call -; also clears screen -; void SetTextMode(void) -SetTextMode: -.prolog: - __CDECL16_ENTRY - pushf -.func: - xor ah, ah ; Set Video mode BIOS function - mov al, 0x02 ; 16 color 80x25 Text mode - int 0x10 ; Call video interrupt - - mov ah, 0x05 ; Select active display page BIOS function - xor al, al ; page 0 - int 0x10 ; call video interrupt -.endp: - popf - __CDECL16_EXIT - ret - -; disables blinking text mode cursor -disable_cursor: - __CDECL16_ENTRY -.func: - mov dx, 0x3D4 - mov al, 0xA ; low cursor shape register - out dx, al - - inc dx - mov al, 0x20 ; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape - out dx, al -.endp: __CDECL16_EXIT ret \ No newline at end of file diff --git a/include/BIOS/func/ext_read.inc b/include/BIOS/func/ext_read.inc new file mode 100644 index 0000000..6e137ce --- /dev/null +++ b/include/BIOS/func/ext_read.inc @@ -0,0 +1,90 @@ +; Copyright (c) 2024 Elaina Claus +; +; Permission is hereby granted, free of charge, to any person obtaining a copy +; of this software and associated documentation files (the "Software"), to deal +; in the Software without restriction, including without limitation the rights +; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the Software is +; furnished to do so, subject to the following conditions: +; +; The above copyright notice and this permission notice shall be included in all +; copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. + +;Offset Size Description +; 0 1 size of packet (16 bytes) +; 1 1 always 0 +; 2 2 number of sectors to transfer (max 127 on some BIOSes) +; 4 4 transfer buffer (0xFFFF:0xFFFF) +; 8 4 lower 32-bits of starting 48-bit LBA +; 12 4 upper 32-bits of starting 48-bit LBA +; needs to be aligned to a uint32_t +struc LBAPkt_t + .size resb 1 + .res0 resb 1 + .xfer_size resw 1 + .offset resw 1 + .segment resw 1 + .lower_lba resd 1 + .upper_lba resd 1 +endstruc + +; Wrapper for AH=0x42 INT13h (Extended Read) +; +; BIOS call details +; AH = 42h +; DL = drive number +; DS:SI -> disk address packet +; +; Return: +; CF clear if successful +; AH = 00h +; CF set on error +; AH = error code +; disk address packet's block count field set to number of blocks +; successfully transferred +; +; +; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint32_t lba) +; TODO: this needs validation +read_disk_raw: + __CDECL16_ENTRY +.func: + mov ax, 0x10 + push ax ; len = 16 bytes + xor ax, ax + push ax ; val = 0 + mov ax, lba_packet + push ax ; dest = lba_packet address + + call kmemset ; uint8_t* kmemset(void* dest, uint8_t val, size_t len); + add sp, 0x6 + + mov byte [lba_packet + LBAPkt_t.size], 0x10 + mov word [lba_packet + LBAPkt_t.xfer_size], 0x0001 + + mov dword eax, [bp + 8] + mov dword [lba_packet + LBAPkt_t.lower_lba], eax + + mov ax, [bp + 6] + mov word [lba_packet + LBAPkt_t.offset], ax + + mov ax, [bp + 4] + mov word [lba_packet + LBAPkt_t.segment], ax + + mov si, lba_packet + mov ah, 0x42 + mov dl, byte [fat32_ebpb + FAT32_ebpb_t.drive_number_8] + int 0x13 + jnc read_disk_raw.endp + ERROR STAGE2_MBR_DISK_READ_ERROR +.endp: + __CDECL16_EXIT + ret \ No newline at end of file diff --git a/include/BIOS/func/video.inc b/include/BIOS/func/video.inc new file mode 100644 index 0000000..5a5e78e --- /dev/null +++ b/include/BIOS/func/video.inc @@ -0,0 +1,54 @@ +; Copyright (c) 2024 Elaina Claus +; +; Permission is hereby granted, free of charge, to any person obtaining a copy +; of this software and associated documentation files (the "Software"), to deal +; in the Software without restriction, including without limitation the rights +; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the Software is +; furnished to do so, subject to the following conditions: +; +; The above copyright notice and this permission notice shall be included in all +; copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. + +; Sets output to 80x25 16 color text mode via BIOS call +; also clears screen +; void SetTextMode(void) +SetTextMode: +.prolog: + __CDECL16_ENTRY + pushf +.func: + xor ah, ah ; Set Video mode BIOS function + mov al, 0x02 ; 16 color 80x25 Text mode + int 0x10 ; Call video interrupt + + mov ah, 0x05 ; Select active display page BIOS function + xor al, al ; page 0 + int 0x10 ; call video interrupt +.endp: + popf + __CDECL16_EXIT + ret + +; disables blinking text mode cursor +disable_cursor: + __CDECL16_ENTRY +.func: + mov dx, 0x3D4 + mov al, 0xA ; low cursor shape register + out dx, al + + inc dx + mov al, 0x20 ; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape + out dx, al +.endp: + __CDECL16_EXIT + ret \ No newline at end of file diff --git a/include/config.inc b/include/config.inc index 20e2430..3a780f6 100755 --- a/include/config.inc +++ b/include/config.inc @@ -1,4 +1,4 @@ -; Copyright (c) 2023 Elaina Claus +; Copyright (c) 2024 Elaina Claus ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal diff --git a/include/entry.inc b/include/entry.inc index f9f566e..f295305 100755 --- a/include/entry.inc +++ b/include/entry.inc @@ -1,4 +1,4 @@ -; Copyright (c) 2023 Elaina Claus +; Copyright (c) 2024 Elaina Claus ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ ; 8KiB from 0x2500 -> 0x500 -%define STACK_START 0x2500 -%define MBR_ENTRY 0x7A00 -%define VBR_ENTRY 0x7C00 -%define STAGE2_ENTRY 0x7E00 \ No newline at end of file +%define EARLY_STACK_START 0x2500 +%define MBR_ENTRY 0x7A00 +%define VBR_ENTRY 0x7C00 +%define STAGE2_ENTRY 0x7E00 \ No newline at end of file diff --git a/include/errors.inc b/include/error_codes.inc similarity index 80% rename from include/errors.inc rename to include/error_codes.inc index 82da97d..bc1999c 100755 --- a/include/errors.inc +++ b/include/error_codes.inc @@ -1,4 +1,4 @@ -; Copyright (c) 2023 Elaina Claus +; Copyright (c) 2024 Elaina Claus ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal @@ -76,36 +76,4 @@ %define STEVIA_DEBUG_OK 'W' %define STEVIA_DEBUG_ERR 'X' %define STEVIA_DEBUG_UNIMPLEMENTED 'Y' -%define STEVIA_DEBUG_HALT 'Z' - - -%macro ERROR 1 - xor ax, ax - mov al, %1 - jmp error -%endmacro - -; pass error as ascii character in al, errors a-zA-Z or 0-9 -error: - ; fs = 0xb800 => fs:0x0000 = 0xb8000 - mov dx, 0xB800 - mov fs, dx - - mov dx, STEVIA_DEBUG_OK - cmp ax, dx - jge error.debug_err - mov dh, 0x4F ; color 0x4F is white text/red background - jmp error.print -.debug_err: - mov dh, 0x5F ; debug case is white text/purple background - - ; the characters are two bytes in the order of 0xb8000: byte c, byte attribute - ; since x86 is le, we store the attribute in the MSB of dx -.print: - mov dl, al - mov word [fs:0x0000], dx - jmp error.stop - -.stop: - hlt - jmp short error.stop \ No newline at end of file +%define STEVIA_DEBUG_HALT 'Z' \ No newline at end of file diff --git a/include/fat32/bpb.inc b/include/fat32/bpb.inc index e6ce621..8200b34 100755 --- a/include/fat32/bpb.inc +++ b/include/fat32/bpb.inc @@ -1,4 +1,4 @@ -; Copyright (c) 2023 Elaina Claus +; Copyright (c) 2024 Elaina Claus ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal diff --git a/include/memory.inc b/include/memory.inc index 7f0e15b..68e1305 100755 --- a/include/memory.inc +++ b/include/memory.inc @@ -1,4 +1,4 @@ -; Copyright (c) 2023 Elaina Claus +; Copyright (c) 2024 Elaina Claus ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal @@ -110,103 +110,6 @@ struc SteviaInfoStruct_t .EBPBDataPtr resd 1 endstruc -; Address Range Descriptor Structure -; -; Offset in Bytes Name Description -; 0 BaseAddrLow Low 32 Bits of Base Address -; 4 BaseAddrHigh High 32 Bits of Base Address -; 8 LengthLow Low 32 Bits of Length in Bytes -; 12 LengthHigh High 32 Bits of Length in Bytes -; 16 Type Address type of this range. -; Address Range Descriptor Structure -; -; Offset in Bytes Name Description -; 0 BaseAddrLow Low 32 Bits of Base Address -; 4 BaseAddrHigh High 32 Bits of Base Address -; 8 LengthLow Low 32 Bits of Length in Bytes -; 12 LengthHigh High 32 Bits of Length in Bytes -; 16 Type Address type of this range. -; Input: -; -; EAX Function Code E820h -; EBX Continuation Contains the "continuation value" to get the -; next run of physical memory. This is the -; value returned by a previous call to this -; routine. If this is the first call, EBX -; must contain zero. -; ES:DI Buffer Pointer Pointer to an Address Range Descriptor -; structure which the BIOS is to fill in. -; ECX Buffer Size The length in bytes of the structure passed -; to the BIOS. The BIOS will fill in at most -; ECX bytes of the structure or however much -; of the structure the BIOS implements. The -; minimum size which must be supported by both -; the BIOS and the caller is 20 bytes. Future -; implementations may extend this structure. -; EDX Signature 'SMAP' - Used by the BIOS to verify the -; caller is requesting the system map -; information to be returned in ES:DI. -; -; Output: -; -; CF Carry Flag Non-Carry - indicates no error -; EAX Signature 'SMAP' - Signature to verify correct BIOS -; revision. -; ES:DI Buffer Pointer Returned Address Range Descriptor pointer. -; Same value as on input. -; ECX Buffer Size Number of bytes returned by the BIOS in the -; address range descriptor. The minimum size -; structure returned by the BIOS is 20 bytes. -; EBX Continuation Contains the continuation value to get the -; next address descriptor. The actual -; significance of the continuation value is up -; to the discretion of the BIOS. The caller -; must pass the continuation value unchanged -; as input to the next iteration of the E820 -; call in order to get the next Address Range -; Descriptor. A return value of zero means that -; this is the last descriptor -; -; Address Range Descriptor Structure -; -; Offset in Bytes Name Description -; 0 BaseAddrLow Low 32 Bits of Base Address -; 4 BaseAddrHigh High 32 Bits of Base Address -; 8 LengthLow Low 32 Bits of Length in Bytes -; 12 LengthHigh High 32 Bits of Length in Bytes -; 16 Type Address type of this range. -; -; The BaseAddrLow and BaseAddrHigh together are the 64 bit BaseAddress of this range. -; The BaseAddress is the physical address of the start of the range being specified. -; -; The LengthLow and LengthHigh together are the 64 bit Length of this range. -; The Length is the physical contiguous length in bytes of a range being specified. -; -; The Type field describes the usage of the described address range as defined in the table below. - -; Value Pneumonic Description -; 1 AddressRangeMemory This run is available RAM usable by the operating system. -; 2 AddressRangeReserved This run of addresses is in use or reserved by the system, and must not be used by the operating system. -; Other Undefined Undefined - Reserved for future use. - -; Address Range Descriptor Structure -; -; Offset in Bytes Name Description -; 0 BaseAddrLow u32 - Low 32 Bits of Base Address -; 4 BaseAddrHigh u32 - High 32 Bits of Base Address -; 8 LengthLow u32 - Low 32 Bits of Length in Bytes -; 12 LengthHigh u32 - High 32 Bits of Length in Bytes -; 16 Type u32 - Address type of this range. -; 20 ExtType u32 - ACPI 3.0 extended type -struc AddressRangeDescStruct_t - .BaseAddrLow resd 1 - .BaseAddrHigh resd 1 - .LengthLow resd 1 - .LengthHigh resd 1 - .Type resd 1 - .ExtType resd 1 -endstruc - %macro DEBUG_HCF 0 DEBUG_LOOP: hlt diff --git a/include/partition_table.inc b/include/partition_table.inc index 5fc7a20..7f149fa 100755 --- a/include/partition_table.inc +++ b/include/partition_table.inc @@ -1,4 +1,4 @@ -; Copyright (c) 2023 Elaina Claus +; Copyright (c) 2024 Elaina Claus ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal @@ -41,23 +41,4 @@ struc PartTable_t .partition2 resb 16 .partition3 resb 16 .partition4 resb 16 -endstruc - - -;Offset Size Description -; 0 1 size of packet (16 bytes) -; 1 1 always 0 -; 2 2 number of sectors to transfer (max 127 on some BIOSes) -; 4 4 transfer buffer (0xFFFF:0xFFFF) -; 8 4 lower 32-bits of starting 48-bit LBA -; 12 4 upper 32-bits of starting 48-bit LBA -; needs to be aligned to a uint32_t -struc LBAPkt_t - .size resb 1 - .res0 resb 1 - .xfer_size resw 1 - .offset resw 1 - .segment resw 1 - .lower_lba resd 1 - .upper_lba resd 1 endstruc \ No newline at end of file diff --git a/include/util/error_func.inc b/include/util/error_func.inc new file mode 100644 index 0000000..cbd238a --- /dev/null +++ b/include/util/error_func.inc @@ -0,0 +1,50 @@ +; Copyright (c) 2024 Elaina Claus +; +; Permission is hereby granted, free of charge, to any person obtaining a copy +; of this software and associated documentation files (the "Software"), to deal +; in the Software without restriction, including without limitation the rights +; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +; copies of the Software, and to permit persons to whom the Software is +; furnished to do so, subject to the following conditions: +; +; The above copyright notice and this permission notice shall be included in all +; copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +; SOFTWARE. + +%macro ERROR 1 + xor ax, ax + mov al, %1 + jmp error +%endmacro + +; pass error as ascii character in al, errors a-zA-Z or 0-9 +error: + ; fs = 0xb800 => fs:0x0000 = 0xb8000 + mov dx, 0xB800 + mov fs, dx + + mov dx, STEVIA_DEBUG_OK + cmp ax, dx + jge error.debug_err + mov dh, 0x4F ; color 0x4F is white text/red background + jmp error.print +.debug_err: + mov dh, 0x5F ; debug case is white text/purple background + + ; the characters are two bytes in the order of 0xb8000: byte c, byte attribute + ; since x86 is le, we store the attribute in the MSB of dx +.print: + mov dl, al + mov word [fs:0x0000], dx + jmp error.stop + +.stop: + hlt + jmp short error.stop \ No newline at end of file diff --git a/src/mbr/mbr.nasm b/src/mbr/mbr.nasm index 1d14927..f65a202 100755 --- a/src/mbr/mbr.nasm +++ b/src/mbr/mbr.nasm @@ -33,7 +33,7 @@ init: mov es, ax ; * mov ss, ax ; Set Stack Segment to 0 - mov sp, STACK_START + mov sp, EARLY_STACK_START mov ch, 0x01 ; 256 WORDs in MBR (512 bytes), 0x0100 in cx mov si, 0x7C00 ; Current MBR Address (loaded here by BIOS) diff --git a/src/stage2/stage2.nasm b/src/stage2/stage2.nasm index e061f9c..5fad4a8 100755 --- a/src/stage2/stage2.nasm +++ b/src/stage2/stage2.nasm @@ -38,7 +38,7 @@ init: mov gs, ax ; * mov ss, ax ; Set Stack Segment to 0 - mov sp, STACK_START ; Set Stack Pointer + mov sp, EARLY_STACK_START ; Set Stack Pointer add sp, 0x4 mov ax, 0xDEAD @@ -52,7 +52,7 @@ init: jmp 0:main %include "config.inc" -%include "errors.inc" +%include "error_codes.inc" %include "memory.inc" %include "kmem_func.inc" %include "partition_table.inc" @@ -146,7 +146,7 @@ hcf: ; ; ############### -%include 'BIOS/BIOS_func.inc' +%include 'BIOS/BIOS_sys.inc' ; ############################## ; diff --git a/src/vbr/vbr.nasm b/src/vbr/vbr.nasm index ebb8b71..37759ca 100755 --- a/src/vbr/vbr.nasm +++ b/src/vbr/vbr.nasm @@ -40,7 +40,7 @@ init: mov es, ax ; * mov ss, ax ; Set Stack Segment to 0 - mov sp, STACK_START ; Setup stack + mov sp, EARLY_STACK_START ; Setup stack mov bp, sp ; base ptr = stack ptr mov bx, VBR_ENTRY ; move Bx to the new start of the initial boot sector From 8f95c8f26709585f24ca19373a07bb0d12f1eb28 Mon Sep 17 00:00:00 2001 From: Elaina Claus Date: Sat, 5 Oct 2024 18:55:00 -0400 Subject: [PATCH 4/5] tons more work on modularizing the code --- bochsrc.bxrc | 2 +- include/BIOS/func/E820_memory_map.inc | 7 +- include/BIOS/func/a20enable.inc | 7 +- include/BIOS/func/ext_read.inc | 44 +++-- include/BIOS/func/video.inc | 8 +- include/cdecl16.inc | 3 +- include/config.inc | 6 +- include/entry.inc | 6 +- include/error_codes.inc | 6 +- include/fat32/{bpb.inc => bpb_offset_bx.inc} | 6 +- include/fat32/fat32_structures.inc | 4 +- .../{fat32_func_old.inc => fat32_sys.inc} | 76 ++++++-- include/kmem_func.inc | 13 +- include/{memory.inc => mem.inc} | 21 +- include/partition_table.inc | 7 +- include/util/error_func.inc | 15 +- src/mbr/mbr.nasm | 179 +++++++----------- src/stage2/stage2.nasm | 73 ++++--- src/vbr/vbr.nasm | 173 +++++++---------- 19 files changed, 360 insertions(+), 296 deletions(-) rename include/fat32/{bpb.inc => bpb_offset_bx.inc} (98%) rename include/fat32/{fat32_func_old.inc => fat32_sys.inc} (82%) rename include/{memory.inc => mem.inc} (93%) diff --git a/bochsrc.bxrc b/bochsrc.bxrc index 6de97b7..34c323d 100644 --- a/bochsrc.bxrc +++ b/bochsrc.bxrc @@ -10,7 +10,7 @@ floppy_bootsig_check: disabled=0 floppya: type=1_44 # no floppyb ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 -ata0-master: type=disk, path=".\disk.img", mode=flat, cylinders=0, heads=0, spt=0, sect_size=512, model="Stevia Disk", biosdetect=auto, translation=auto +ata0-master: type=disk, path=".\disk.img", mode=flat, cylinders=0, heads=0, spt=0, sect_size=512, model="Stevia Disk", biosdetect=auto, translation=lba ata0-slave: type=none ata1: type=none ata1-master: type=none diff --git a/include/BIOS/func/E820_memory_map.inc b/include/BIOS/func/E820_memory_map.inc index 9cd9231..3447a47 100644 --- a/include/BIOS/func/E820_memory_map.inc +++ b/include/BIOS/func/E820_memory_map.inc @@ -18,6 +18,7 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_E820MEMORY_MAP ; Address Range Descriptor Structure ; @@ -116,6 +117,7 @@ struc AddressRangeDescStruct_t .ExtType resd 1 endstruc +ALIGN 4, db 0x90 GetMemoryMap: __CDECL16_ENTRY push es ; save segment register @@ -158,4 +160,7 @@ GetMemoryMap: .endp: pop es __CDECL16_EXIT - ret \ No newline at end of file + ret + +%endif +%define __INC_E820MEMORY_MAP \ No newline at end of file diff --git a/include/BIOS/func/a20enable.inc b/include/BIOS/func/a20enable.inc index 0b18bf5..cde9a18 100644 --- a/include/BIOS/func/a20enable.inc +++ b/include/BIOS/func/a20enable.inc @@ -18,6 +18,7 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_A20ENABLE ; ;INT 0x15 Function 2400 - Disable A20 ;Returns: @@ -66,6 +67,7 @@ ; Bit 3 - power on password bytes (CMOS bytes 0x38-0x3f or 0x36-0x3f). 0: accessible, 1: inaccessible ; Bits 4-5 - Manufacturer defined ; Bits 6-7 - 00: HDD activity LED off; any other value is "on" +ALIGN 4, db 0x90 EnableA20: __CDECL16_ENTRY push ds @@ -136,4 +138,7 @@ EnableA20: pop es pop ds __CDECL16_EXIT - ret \ No newline at end of file + ret + +%endif +%define __INC_A20ENABLE \ No newline at end of file diff --git a/include/BIOS/func/ext_read.inc b/include/BIOS/func/ext_read.inc index 6e137ce..a107c94 100644 --- a/include/BIOS/func/ext_read.inc +++ b/include/BIOS/func/ext_read.inc @@ -18,6 +18,7 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_EXT_READ ;Offset Size Description ; 0 1 size of packet (16 bytes) ; 1 1 always 0 @@ -52,25 +53,28 @@ endstruc ; successfully transferred ; ; -; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint32_t lba) -; TODO: this needs validation +; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset, +; uint32_t lba, +; uint16_t count, uint16_t drive_num) +ALIGN 4, db 0x90 read_disk_raw: __CDECL16_ENTRY -.func: +.func: mov ax, 0x10 push ax ; len = 16 bytes xor ax, ax push ax ; val = 0 mov ax, lba_packet push ax ; dest = lba_packet address - - call kmemset ; uint8_t* kmemset(void* dest, uint8_t val, size_t len); - add sp, 0x6 + call kmemset + add sp, 0x06 mov byte [lba_packet + LBAPkt_t.size], 0x10 - mov word [lba_packet + LBAPkt_t.xfer_size], 0x0001 - mov dword eax, [bp + 8] + mov ax, [bp + 12] + mov word [lba_packet + LBAPkt_t.xfer_size], ax + + mov eax, [bp + 8] mov dword [lba_packet + LBAPkt_t.lower_lba], eax mov ax, [bp + 6] @@ -81,10 +85,26 @@ read_disk_raw: mov si, lba_packet mov ah, 0x42 - mov dl, byte [fat32_ebpb + FAT32_ebpb_t.drive_number_8] + + ;BUG: still working on getting this passed down correctly, going to hard set it for now. + movzx dx, byte [bp + 14] + and dx, 0x00ff + ;xor dl, dl + ;mov dl, 0x80 + int 0x13 - jnc read_disk_raw.endp + jnc .endf + + %ifdef __STEVIA_MBR + ERROR MBR_ERROR_DISK_READ_ERR + %elifsef __STEVIA_VBR + ERROR VBR_ERROR_DISK_READ_ERR + %else ERROR STAGE2_MBR_DISK_READ_ERROR -.endp: + %endif +.endf: __CDECL16_EXIT - ret \ No newline at end of file + ret + +%endif +%define __INC_EXT_READ \ No newline at end of file diff --git a/include/BIOS/func/video.inc b/include/BIOS/func/video.inc index 5a5e78e..33b0a6e 100644 --- a/include/BIOS/func/video.inc +++ b/include/BIOS/func/video.inc @@ -18,9 +18,11 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_VIDEO ; Sets output to 80x25 16 color text mode via BIOS call ; also clears screen ; void SetTextMode(void) +ALIGN 4, db 0x90 SetTextMode: .prolog: __CDECL16_ENTRY @@ -39,6 +41,7 @@ SetTextMode: ret ; disables blinking text mode cursor +ALIGN 4, db 0x90 disable_cursor: __CDECL16_ENTRY .func: @@ -51,4 +54,7 @@ disable_cursor: out dx, al .endp: __CDECL16_EXIT - ret \ No newline at end of file + ret + +%endif +%define __INC_VIDEO \ No newline at end of file diff --git a/include/cdecl16.inc b/include/cdecl16.inc index b039985..13bdc50 100644 --- a/include/cdecl16.inc +++ b/include/cdecl16.inc @@ -21,6 +21,7 @@ %macro __CDECL16_ENTRY 0 push bp mov bp, sp + sub sp, 0x20 push si push di @@ -37,4 +38,4 @@ mov sp, bp pop bp %endmacro -%endif +%endif \ No newline at end of file diff --git a/include/config.inc b/include/config.inc index 3a780f6..db74252 100755 --- a/include/config.inc +++ b/include/config.inc @@ -18,8 +18,12 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_STEVIA_CONFIG %define SECTOR_SIZE 512 %define STAGE2_SECTOR_COUNT 0x40 ; 32 KiB -%define MAX_STAGE2_BYTES (SECTOR_SIZE * STAGE2_SECTOR_COUNT) \ No newline at end of file +%define MAX_STAGE2_BYTES (SECTOR_SIZE * STAGE2_SECTOR_COUNT) + +%endif +%define __INC_STEVIA_CONFIG \ No newline at end of file diff --git a/include/entry.inc b/include/entry.inc index f295305..fa5e710 100755 --- a/include/entry.inc +++ b/include/entry.inc @@ -18,9 +18,13 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_ENTRY ; 8KiB from 0x2500 -> 0x500 %define EARLY_STACK_START 0x2500 %define MBR_ENTRY 0x7A00 %define VBR_ENTRY 0x7C00 -%define STAGE2_ENTRY 0x7E00 \ No newline at end of file +%define STAGE2_ENTRY 0x7E00 + +%endif +%define __INC_ENTRY \ No newline at end of file diff --git a/include/error_codes.inc b/include/error_codes.inc index bc1999c..d1eb182 100755 --- a/include/error_codes.inc +++ b/include/error_codes.inc @@ -18,6 +18,7 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_ERROR_CODES ; Errors ; 12 Errors, 5 in use @@ -76,4 +77,7 @@ %define STEVIA_DEBUG_OK 'W' %define STEVIA_DEBUG_ERR 'X' %define STEVIA_DEBUG_UNIMPLEMENTED 'Y' -%define STEVIA_DEBUG_HALT 'Z' \ No newline at end of file +%define STEVIA_DEBUG_HALT 'Z' + +%endif +%define __INC_ERROR_CODES \ No newline at end of file diff --git a/include/fat32/bpb.inc b/include/fat32/bpb_offset_bx.inc similarity index 98% rename from include/fat32/bpb.inc rename to include/fat32/bpb_offset_bx.inc index 8200b34..e807556 100755 --- a/include/fat32/bpb.inc +++ b/include/fat32/bpb_offset_bx.inc @@ -18,6 +18,7 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_BPD_OFFSET_BX ; BPB Information ; Off. Hex Off. Size Description @@ -88,4 +89,7 @@ %define bsVolumeSerial bx+0x43 %define bsVolumeLabel bx+0x47 %define bsSystemIdent bx+0x52 -;-- End EBPB \ No newline at end of file +;-- End EBPB + +%endif +%define __INC_BPD_OFFSET_BX \ No newline at end of file diff --git a/include/fat32/fat32_structures.inc b/include/fat32/fat32_structures.inc index 959b0e5..0bba2a5 100755 --- a/include/fat32/fat32_structures.inc +++ b/include/fat32/fat32_structures.inc @@ -18,6 +18,7 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_FAT32_STRUCT ; ## FAT32 Info ## ; total_sectors = bsSectorsHuge @@ -230,4 +231,5 @@ endstruc ; LFN == RO | HIDDEN | SYSTEM | VOLID == 0x0F %define FAT32_ATTR_LFN 0x0F - +%endif +%define __INC_FAT32_STRUCT \ No newline at end of file diff --git a/include/fat32/fat32_func_old.inc b/include/fat32/fat32_sys.inc similarity index 82% rename from include/fat32/fat32_func_old.inc rename to include/fat32/fat32_sys.inc index 33175ed..3de49ab 100644 --- a/include/fat32/fat32_func_old.inc +++ b/include/fat32/fat32_sys.inc @@ -18,6 +18,13 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_FAT32_SYS + +%include "partition_table.inc" +%include "fat32/bpb_offset_bx.inc" +%include "fat32/fat32_structures.inc" + +ALIGN 4, db 0x90 InitFATDriver: __CDECL16_ENTRY .func: @@ -28,9 +35,14 @@ InitFATDriver: mov dword [fat32_state + FAT32_State_t.active_dir_cluster_32], eax .calc_active_part: - mov ax, word [partition_offset] - mov bx, partition_table - add bx, ax ; bx points to the partition that was booted from + mov bx, [partition_offset_ptr] + mov ax, [bx + 0] + mov bx, ax + mov ax, [bx + 0] + + mov dx, partition_table + add dx, ax ; dx points to the partition that was booted from + mov bx, dx ; set bx, should point at our partition mov eax, dword [bx + PartEntry_t.lba_start] mov dword [fat32_state + FAT32_State_t.active_drive_lba_32], eax @@ -72,6 +84,7 @@ InitFATDriver: ; returns first cluster of file if found ; halts/errors if file is not found ; uint32_t SearchFATDIR(uint8_t* SFN); +ALIGN 4, db 0x90 SearchFATDIR: __CDECL16_ENTRY .file_lookup: @@ -173,9 +186,16 @@ SearchFATDIR: ; uint32_t NextCluster(uint32_t active_cluster); ; if eax >= 0x0FFFFFF8 then there are no more clusters (end of chain) ; if eax == 0x0FFFFFF7 then this is a cluster that is marked as bad +ALIGN 4, db 0x90 NextCluster: __CDECL16_ENTRY .func: + mov bx, [boot_drive_ptr] + mov ax, [bx + 0] + mov bx, ax + movzx ax, byte [bx + 0] ; 67h override would probably work but this is the 16bit way to do it + mov byte [bp - 2], al ; save boot drive as a local for easy access + mov dword edx, [bp + 4] mov si, fat32_nc_data .calc_offset: @@ -213,7 +233,14 @@ NextCluster: add eax, ecx ; fat_sector + first_fat_sector mov dword [si + FAT32_NextClusterData_t.fat_sector], eax .load_fat_table: - ; load correct fat + movzx ax, [bp - 2] + push ax + + mov ax, 0x1 + push ax + + ; load correct fat + mov eax, dword [si + FAT32_NextClusterData_t.fat_sector] push dword eax mov ax, fat_buffer @@ -221,10 +248,11 @@ NextCluster: xor ax, ax push ax - ; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint16_t lower_lower_lba, uint16_t upper_lower_lba) - call read_disk_raw ; read_disk_raw(0, fat_buffer, fat_sector) - add sp, 0x8 - + call read_disk_raw + add sp, 0xC + ; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset, +; uint32_t lba, +; uint16_t count, uint16_t drive_num) .read_cluster: ; next_cluster = fat_buffer[entry_offset] mov ebx, dword [si + FAT32_NextClusterData_t.entry_offset] @@ -235,6 +263,7 @@ NextCluster: ret ; uint32_t ClusterToLBA(uint32_t cluster) +ALIGN 4, db 0x90 ClusterToLBA: __CDECL16_ENTRY .func: @@ -249,25 +278,42 @@ ClusterToLBA: ret ; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster) +ALIGN 4, db 0x90 ReadFATCluster: __CDECL16_ENTRY .func: + mov bx, [boot_drive_ptr] + mov ax, [bx + 0] + mov bx, ax + movzx ax, byte [bx + 0] ; 67h override would probably work but this is the 16bit way to do it + mov byte [bp - 2], al ; save boot drive as a local for easy access + mov dword eax, [bp + 8] push dword eax call ClusterToLBA ; uint32_t ClusterToLBA(uint32_t cluster) add sp, 0x4 ; eax == LBA - push dword eax ;uint32_t lba + movzx ax, [bp - 2] + push ax - mov dx, [bp + 4] ; seg - push dx ; uint16_t buf_offset + mov ax, 0x1 + push ax - mov dx, [bp + 6] ; offset - push dx ; unit16_t segment + ; load correct fat + mov eax, dword [si + FAT32_NextClusterData_t.fat_sector] + push dword eax - call read_disk_raw ; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint32_t lba) - add sp, 0x8 + mov ax, fat_buffer + push ax + + xor ax, ax + push ax + call read_disk_raw + add sp, 0xC .endp: __CDECL16_EXIT ret + +%endif +%define __INC_FAT32_SYS \ No newline at end of file diff --git a/include/kmem_func.inc b/include/kmem_func.inc index e69ca31..93f544d 100644 --- a/include/kmem_func.inc +++ b/include/kmem_func.inc @@ -17,15 +17,18 @@ ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. + +%ifndef __INC_KMEM_FUNC %include 'cdecl16.inc' -; uint8_t* kmemset(void* dest, uint8_t val, uint8_t len); +; uint8_t* kmemset_byte(void* dst, uint8_t val, uint16_t len); +ALIGN 4, db 0x90 kmemset: __CDECL16_ENTRY .func: mov cx, [bp + 8] ; size_t len mov al, [bp + 6] ; uint8_t val - mov di, [bp + 4] ; void * ptr + mov di, [bp + 4] ; void * dst cld rep stosb @@ -36,6 +39,7 @@ kmemset: ; uint8_t* kmemset(uint8_t* dest, uint8_t* src, uint8_t len); ; not overlap safe +ALIGN 4, db 0x90 kmemcpy: __CDECL16_ENTRY .func: @@ -48,4 +52,7 @@ kmemcpy: mov ax, di ; return pointer to dest .endf: __CDECL16_EXIT - ret \ No newline at end of file + ret + +%endif +%define __INC_KMEM_FUNC \ No newline at end of file diff --git a/include/memory.inc b/include/mem.inc similarity index 93% rename from include/memory.inc rename to include/mem.inc index 68e1305..ca8ac77 100755 --- a/include/memory.inc +++ b/include/mem.inc @@ -18,6 +18,8 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_MEM + ; ## Generic Low mem map (from osdev wiki) ## ; start end size type description @@ -54,12 +56,12 @@ ; copy of FAT32 BPB, 33 bytes (+1 to the next value to align to uint16_t) ;0x3048 -%define fat32_bpb 0x3050 -%define fat32_bpb_SIZE 33 +%define fat32_bpb 0x304A +%define fat32_bpb_SIZE 36 ; copy of FAT32 EBPB, 54 bytes ;0x306A -%define fat32_ebpb 0x30A0 +%define fat32_ebpb 0x306E %define fat32_ebpb_SIZE 54 ; FAT32 FSInfo, 512 bytes @@ -69,18 +71,18 @@ ; some stored state for the fat32 driver ;0x32A2 -%define fat32_state 0x32B0 +%define fat32_state 0x34B0 %define fat32_state_SIZE 32 ; next free space is 0x32D0 -%define fat32_nc_data 0x32D0 +%define fat32_nc_data 0x35D0 %define fat32_nc_data_size 16 ; lba_packet for raw_disk_read %define lba_packet 0x4000 %define BIOSMemoryMap 0x4200 -%define SteviaInfo 0x4400 +%define SteviaInfo 0x5200 ; High memory addresses for loading kernel (for use with unreal mode and 32bit override) @@ -110,8 +112,5 @@ struc SteviaInfoStruct_t .EBPBDataPtr resd 1 endstruc -%macro DEBUG_HCF 0 - DEBUG_LOOP: - hlt - jmp short DEBUG_LOOP -%endmacro \ No newline at end of file +%endif +%define __INC_MEM \ No newline at end of file diff --git a/include/partition_table.inc b/include/partition_table.inc index 7f149fa..ddd9ab6 100755 --- a/include/partition_table.inc +++ b/include/partition_table.inc @@ -18,6 +18,8 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_PART_TABLE + ; Partition table entry format ; Off. Size. Description ;0x00 1 Drive attributes (bit 7 set = active or bootable) @@ -41,4 +43,7 @@ struc PartTable_t .partition2 resb 16 .partition3 resb 16 .partition4 resb 16 -endstruc \ No newline at end of file +endstruc + +%endif +%define __INC_PART_TABLE \ No newline at end of file diff --git a/include/util/error_func.inc b/include/util/error_func.inc index cbd238a..d2a4901 100644 --- a/include/util/error_func.inc +++ b/include/util/error_func.inc @@ -18,13 +18,23 @@ ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ; SOFTWARE. +%ifndef __INC_ERROR_FUNC + %macro ERROR 1 xor ax, ax mov al, %1 jmp error %endmacro +%macro DEBUG_HCF 0 + DEBUG_LOOP: + cli + hlt + jmp short DEBUG_LOOP +%endmacro + ; pass error as ascii character in al, errors a-zA-Z or 0-9 +ALIGN 4, db 0x90 error: ; fs = 0xb800 => fs:0x0000 = 0xb8000 mov dx, 0xB800 @@ -47,4 +57,7 @@ error: .stop: hlt - jmp short error.stop \ No newline at end of file + jmp short error.stop + +%endif +%define __INC_ERROR_FUNC \ No newline at end of file diff --git a/src/mbr/mbr.nasm b/src/mbr/mbr.nasm index f65a202..e4450a8 100755 --- a/src/mbr/mbr.nasm +++ b/src/mbr/mbr.nasm @@ -23,17 +23,37 @@ [CPU KATMAI] jmp short init nop -%include "cdecl16.inc" ; include calling convention macros for cdecl16 -%include "entry.inc" ; defines with entry points for various stages & stack -init: - cli ; We do not want to be interrupted - xor ax, ax ; 0 AX - mov ds, ax ; Set segment registers to 0 - mov es, ax ; * - - mov ss, ax ; Set Stack Segment to 0 - mov sp, EARLY_STACK_START +; ############### +; +; Headers/Includes/Definitions +; +; ############### + +%define __STEVIA_MBR + +%include "cdecl16.inc" +%include "entry.inc" +%include "config.inc" +%include "mem.inc" +%include "error_codes.inc" +%include "partition_table.inc" + +; ############### +; End Section +; ############### + +ALIGN 4, db 0x90 +init: + cli ; We do not want to be interrupted + + xor ax, ax ; 0 AX + mov ds, ax ; Set segment registers to 0 + + mov ss, ax ; Set Stack Segment to 0 + mov sp, EARLY_STACK_START ; Setup stack + mov bp, sp ; base ptr = stack ptr + sub sp, 0x20 ; local varible space mov ch, 0x01 ; 256 WORDs in MBR (512 bytes), 0x0100 in cx mov si, 0x7C00 ; Current MBR Address (loaded here by BIOS) @@ -43,16 +63,28 @@ init: sti jmp 0:main - nop -%include "config.inc" -%include "memory.inc" +; ############### +; +; Extra/Shared Functions +; +; ############### + %include "kmem_func.inc" -%include "partition_table.inc" -%include "errors.inc" +%include "util/error_func.inc" +; ############### +; End Section +; ############### + +; +; bp - 2 : uint8_t boot_drive +; bp - 4 : uint16_t part_offset +; + +ALIGN 4, db 0x90 main: - mov [boot_drive], dl ; BIOS passes drive number in DL + mov byte [bp - 2], dl ; BIOS passes drive number in DL .check_disk: cmp dl, 0x80 @@ -62,7 +94,7 @@ main: .check_extentions: xor ax, ax mov bx, 0x55AA - mov dl, byte [boot_drive] + mov dl, byte [bp - 2] int 0x13 jnc main.find_active ERROR MBR_ERROR_NO_INT32E ; no extended function support @@ -83,25 +115,30 @@ main: mov ax, bx sub ax, DiskSig ; leaves us with the offset relative from start of table ; this gives us an offset from the begining of the partition table - mov word [part_offset], ax ; update part_offset + mov word [bp - 4], ax ; update part_offset .read_data: - ;uint8_t read_disk_raw(size_t count, uint16_t buf_segment, uint16_t buf_offset, - ; uint16_t lower_lower_lba, uint16_t upper_lower_lba) - mov eax, dword [bx + PartEntry_t.lba_start] - ror eax, 16 - push ax + movzx ax, byte [bp - 2] + push ax ; drive_num - ror eax, 16 - push ax + mov ax, 0x1 + push ax ; count - mov ax, VBR_ENTRY - push ax + mov dword eax, dword [bx + PartEntry_t.lba_start] + push dword eax ; lba xor ax, ax - push ax ; segment = 0 + push ax ; offset = 0 + + mov ax, VBR_ENTRY + shr ax, 4 + push ax ; segment = 7C0 + + ; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset, + ; uint32_t lba, + ; uint16_t count, uint16_t drive_num) + call read_disk_raw + add sp, 0xC - call read_vbr_raw - add sp, 0x8 jnc main.goto_vbr ERROR MBR_ERROR_DISK_READ_ERR ; error in LBA read @@ -120,86 +157,16 @@ main: call kmemcpy ; copy partition table to memory add sp, 0x6 - xor ah, ah ; Set Video mode BIOS function - mov al, 0x02 ; 16 color 80x25 Text mode - int 0x10 ; Call video interrupt - - mov ah, 0x05 ; Select active display page BIOS function - xor al, al ; page 0 - int 0x10 ; call video interrupt - - mov si, word [part_offset] - mov dl, byte [boot_drive] + mov si, word [bp - 4] + mov dl, byte [bp - 2] jmp 0:0x7C00 -; Wrapper for AH=0x42 INT13h (Extended Read) +; ############### ; -; BIOS call details -; AH = 42h -; DL = drive number -; DS:SI -> disk address packet +; BIOS Functions ; -; Return: -; CF clear if successful -; AH = 00h -; CF set on error -; AH = error code -; disk address packet's block count field set to number of blocks -; successfully transferred -; -; -; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, uint16_t lower_lower_lba, uint16_t upper_lower_lba) -read_vbr_raw: - __CDECL16_ENTRY -.func: - mov ax, 0x10 - push ax ; len = 16 bytes - xor ax, ax - push ax ; val = 0 - mov ax, lba_packet - push ax ; dest = lba_packet address - call kmemset - add sp, 0x06 - - mov byte [lba_packet + LBAPkt_t.size], 0x10 - mov word [lba_packet + LBAPkt_t.xfer_size], 0x0001 - - mov ax, [bp + 10] - shl eax, 16 - mov ax, [bp + 8] - mov dword [lba_packet + LBAPkt_t.lower_lba], eax - - mov ax, [bp + 6] - mov word [lba_packet + LBAPkt_t.offset], ax - - mov ax, [bp + 4] - mov word [lba_packet + LBAPkt_t.segment], ax - - mov si, lba_packet - mov ah, 0x42 - mov dl, byte [boot_drive] - int 0x13 - jnc .endf - - ERROR MBR_ERROR_INT13h_EREAD_ERR -.endf: - __CDECL16_EXIT - ret - -; ############# -; -; Locals -; -; ############# - -boot_drive: - db 0x00 -mbr_reserved1: - db 0x00 - -; OFFSET from BEGINING of partition table, ie. DiskSig (-6 from PartEntry1) -part_offset: - dw 0x0000 +; ############### +%include 'BIOS/func/ext_read.inc' %assign bytes_remaining (440 - ($ - $$)) %warning MBR has bytes_remaining bytes remaining for code (MAX: 440 bytes) diff --git a/src/stage2/stage2.nasm b/src/stage2/stage2.nasm index 5fad4a8..f014125 100755 --- a/src/stage2/stage2.nasm +++ b/src/stage2/stage2.nasm @@ -23,11 +23,27 @@ [CPU KATMAI] jmp short init nop - ; boot drive in dl ; active partition offset in si + +; ############### +; +; Headers/Includes/Definitions +; +; ############### +%define __STEVIA_STAGE2 + + %include "cdecl16.inc" %include "entry.inc" +%include "config.inc" +%include "mem.inc" +%include "error_codes.inc" + +; ############### +; End Section +; ############### +ALIGN 4, db 0x90 init: cli ; We do not want to be interrupted @@ -37,32 +53,36 @@ init: mov fs, ax ; * mov gs, ax ; * - mov ss, ax ; Set Stack Segment to 0 + mov ss, ax ; Set Stack Segment to 0 mov sp, EARLY_STACK_START ; Set Stack Pointer - - add sp, 0x4 - mov ax, 0xDEAD - push word ax - mov ax, 0xBEEF - push word ax ; mark top of stack for debuging - mov bp, sp + sub sp, 0x20 ; 32 bytes for local varibles + sti jmp 0:main -%include "config.inc" -%include "error_codes.inc" -%include "memory.inc" -%include "kmem_func.inc" -%include "partition_table.inc" -%include "fat32/bpb.inc" -%include "fat32/fat32_structures.inc" +; ############### +; +; Extra/Shared Functions +; +; ############### + +%include "kmem_func.inc" +%include "util/error_func.inc" + +; ############### +; End Section +; ############### main: - mov byte [fat32_ebpb + FAT32_ebpb_t.drive_number_8], dl - mov word [partition_offset], si + lea ax, [bp - 2] + mov [boot_drive_ptr], ax + lea ax, [bp - 4] + mov [partition_offset_ptr], ax + mov byte [bp - 2], dl ; boot_drive (probably 0x80) + mov word [bp - 4], si ; partition_offset mov eax, dword [STAGE2_SIG] cmp eax, 0xDEADBEEF @@ -138,7 +158,7 @@ hcf: ; ; ############### -%include 'fat32/fat32_func_old.inc' +%include 'fat32/fat32_sys.inc' ; ############### ; @@ -306,18 +326,13 @@ NewLine_cstr: db StrCRLF_NUL BootTarget_str: db "BOOTI686BIN" - -; ############# -; -; Locals -; -; ############# - -partition_offset: +boot_drive_ptr: + db 0x00 +stage2_resb_1: + db 0x00 +partition_offset_ptr: dw 0x0000 - - ; GDT documentation below: ; ; Pr: Present bit. This must be 1 for all valid selectors. diff --git a/src/vbr/vbr.nasm b/src/vbr/vbr.nasm index 37759ca..2ffdd30 100755 --- a/src/vbr/vbr.nasm +++ b/src/vbr/vbr.nasm @@ -30,36 +30,59 @@ phy_ebpb_start: ; fill eBPB area with 0x00 since we skip writing this part to disk times 54 db 0x00 +; ############### +; +; Headers/Includes/Definitions +; +; ############### +%define __STEVIA_VBR + + %include "cdecl16.inc" %include "entry.inc" +%include "config.inc" +%include "mem.inc" +%include "error_codes.inc" +%include "fat32/bpb_offset_bx.inc" + +; ############### +; End Section +; ############### + +ALIGN 4, db 0x90 init: cli ; We do not want to be interrupted xor ax, ax ; 0 AX mov ds, ax ; Set segment registers to 0 - mov es, ax ; * mov ss, ax ; Set Stack Segment to 0 - mov sp, EARLY_STACK_START ; Setup stack + mov sp, EARLY_STACK_START ; Setup stack mov bp, sp ; base ptr = stack ptr + sub sp, 0x20 ; local varible space mov bx, VBR_ENTRY ; move Bx to the new start of the initial boot sector sti ; all done with inital setup and relocation, reenable interupts jmp 0:main ; fix up cs:ip just in case and jump to relocated code - nop -%include "config.inc" -%include "memory.inc" +; ############### +; +; Extra/Shared Functions +; +; ############### + %include "kmem_func.inc" -%include "partition_table.inc" -%include "errors.inc" +%include "util/error_func.inc" -%include "fat32/bpb.inc" +; ############### +; End Section +; ############### +ALIGN 4, db 0x90 main: - mov [bsDriveNumber], dl ; BIOS passes drive number in DL - mov [partition_offset], si ; save passed partition entry offset + mov byte [bp - 2], dl ; boot_drive + mov [bp - 4], si ; part_offset .check_FAT_size: ; we only support a very specific setup of FAT32 cmp dword [bsSectorHuge], 0 ; SectorsHuge will not be set if FAT12/16 @@ -69,24 +92,39 @@ main: ; read sectors 1-63 to stage2 entry point .load_stage2: - xor ax, ax - push ax ; upper_lower_lba = 0 + mov ax, (fat32_bpb_SIZE + fat32_ebpb_SIZE) ; size in byte + push ax + mov ax, (phy_bpb_start - 0x3) ; start of bpb - 0x3 for the jump short main at the start + push ax + mov ax, fat32_bpb ; defined in memory.inc, destination + push ax + call kmemcpy ; copy bpb to memory + add sp, 0x6 - mov ax , 1 - push ax ; lower_lower_lba = 1 + mov bx, fat32_bpb ; bx now points to aligned memory structure + + movzx ax, byte [bp - 2] + push ax ; drive_num + + mov ax, STAGE2_SECTOR_COUNT + push ax ; count + + mov dword eax, 0x1 + push dword eax ; lba xor ax, ax - push ax ; offset = 0 + push ax ; offset = 0 - ; 07E0:0 + ; 07E0:0 = 0x00007e00 mov ax, STAGE2_ENTRY shr ax, 4 - push ax ; segment = 7E0 + push ax ; segment = 7E0 - ;uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset, - ; uint16_t lower_lower_lba, uint16_t upper_lower_lba) - call read_stage2_raw - add sp, 0x8 + ; uint8_t read_stage2_raw(uint16_t buf_segment, uint16_t buf_offset, + ; uint32_t lba, + ; uint16_t count, uint16_t drive_num) + call read_disk_raw + add sp, 0xC .check_sig: mov ax, 0x7E0 @@ -97,97 +135,16 @@ main: ERROR VBR_ERROR_NO_SIGNATURE ; no signature present in stage2 .sig_ok: - mov ax, fat32_bpb_SIZE ; size in byte - push ax - mov ax, phy_bpb_start ; start of bpb - push ax - mov ax, fat32_bpb ; defined in memory.inc, destination - push ax - call kmemcpy ; copy bpb to memory - add sp, 0x6 - - mov ax, fat32_ebpb_SIZE ; 72 bytes of data - push ax - mov ax, phy_ebpb_start ; start of ebpb - push ax - mov ax, fat32_ebpb ; defined in memory.inc, destination - push ax - call kmemcpy ; copy ebpb to memory - add sp, 0x6 - - mov si, [partition_offset] - mov dl, [bsDriveNumber] + mov si, [bp - 4] + mov dx, [bp - 2] jmp 0:0x7E00 -stop: - hlt - jmp short stop - -; Wrapper for AH=0x42 INT13h (Extended Read) +; ############### ; -; BIOS call details -; AH = 42h -; DL = drive number -; DS:SI -> disk address packet +; Required BIOS functions ; -; Return: -; CF clear if successful -; AH = 00h -; CF set on error -; AH = error code -; disk address packet's block count field set to number of blocks -; successfully transferred -; -; -; uint8_t read_disk_raw(uint16_t buf_segment, uint16_t buf_offset, -; uint16_t lower_lower_lba, uint16_t upper_lower_lba) -read_stage2_raw: - __CDECL16_ENTRY -.func: - mov ax, 0x10 - push ax ; len = 16 bytes - xor ax, ax - push ax ; val = 0 - mov ax, lba_packet - push ax ; dest = lba_packet address - call kmemset - add sp, 0x06 - - mov byte [lba_packet + LBAPkt_t.size], 0x10 - mov word [lba_packet + LBAPkt_t.xfer_size], STAGE2_SECTOR_COUNT - - mov ax, [bp + 10] - shl eax, 16 - mov ax, [bp + 8] - mov dword [lba_packet + LBAPkt_t.lower_lba], eax - - mov ax, [bp + 6] - mov word [lba_packet + LBAPkt_t.offset], ax - - mov ax, [bp + 4] - mov word [lba_packet + LBAPkt_t.segment], ax - - mov si, lba_packet - mov ah, 0x42 - mov dl, byte [bsDriveNumber] - int 0x13 - jnc .endf - - ERROR VBR_ERROR_DISK_READ_ERR -.endf: - __CDECL16_EXIT - ret -; Data - -; ############# -; -; Locals -; -; ############# - -; offset from the begining of sector 0 to the active partition. -partition_offset: - dw 0x0000 +; ############### +%include 'BIOS/func/ext_read.inc' %assign bytes_remaining (420 - ($ - $$)) %warning VBR has bytes_remaining bytes remaining for code (MAX: 420 bytes) From 145e9fbaa9cafae895f958f55936334ac0dcff12 Mon Sep 17 00:00:00 2001 From: Elaina Claus Date: Sat, 5 Oct 2024 20:14:00 -0400 Subject: [PATCH 5/5] =?UTF-8?q?fixed=20read=5Fdisk=5Fraw=20in=20ReadFATClu?= =?UTF-8?q?ster=20boot=5Fdrive=20and=20partition=5Foffset=20are=20global?= =?UTF-8?q?=20pointers=20now=20removed=20an=20extra=20error=20from=20mbr?= =?UTF-8?q?=20disk=20read=20and=20some=20general=20formating=20and=20clean?= =?UTF-8?q?up=20=F0=9F=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/BIOS/func/ext_read.inc | 2 +- include/fat32/fat32_sys.inc | 13 +++---------- src/mbr/mbr.nasm | 10 +++++----- src/stage2/stage2.nasm | 11 ++++++----- src/vbr/vbr.nasm | 13 ++++--------- 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/include/BIOS/func/ext_read.inc b/include/BIOS/func/ext_read.inc index a107c94..42d1cdc 100644 --- a/include/BIOS/func/ext_read.inc +++ b/include/BIOS/func/ext_read.inc @@ -97,7 +97,7 @@ read_disk_raw: %ifdef __STEVIA_MBR ERROR MBR_ERROR_DISK_READ_ERR - %elifsef __STEVIA_VBR + %elifdef __STEVIA_VBR ERROR VBR_ERROR_DISK_READ_ERR %else ERROR STAGE2_MBR_DISK_READ_ERROR diff --git a/include/fat32/fat32_sys.inc b/include/fat32/fat32_sys.inc index 3de49ab..60f155a 100644 --- a/include/fat32/fat32_sys.inc +++ b/include/fat32/fat32_sys.inc @@ -36,9 +36,7 @@ InitFATDriver: .calc_active_part: mov bx, [partition_offset_ptr] - mov ax, [bx + 0] - mov bx, ax - mov ax, [bx + 0] + mov ax, [bx + 0] mov dx, partition_table add dx, ax ; dx points to the partition that was booted from @@ -66,7 +64,6 @@ InitFATDriver: mov dword [fat32_state + FAT32_State_t.first_data_sector_32], eax .get_first_root_dir: ; TODO - jmp InitFATDriver.endp .error: ERROR STAGE2_FAT32_INIT_ERROR @@ -74,7 +71,6 @@ InitFATDriver: __CDECL16_EXIT ret -; TODO: needs validation ; this involves using the low memory buffer for the bios call and moving the file sector by sector to high memory ; ; SFN is a 8.3 file name, all uppercase, and padded with spaces @@ -284,15 +280,13 @@ ReadFATCluster: .func: mov bx, [boot_drive_ptr] mov ax, [bx + 0] - mov bx, ax - movzx ax, byte [bx + 0] ; 67h override would probably work but this is the 16bit way to do it mov byte [bp - 2], al ; save boot drive as a local for easy access mov dword eax, [bp + 8] push dword eax call ClusterToLBA ; uint32_t ClusterToLBA(uint32_t cluster) add sp, 0x4 ; eax == LBA - + mov dword [bp - 6], eax movzx ax, [bp - 2] push ax @@ -300,8 +294,7 @@ ReadFATCluster: mov ax, 0x1 push ax - ; load correct fat - mov eax, dword [si + FAT32_NextClusterData_t.fat_sector] + mov eax, dword [bp + 6] push dword eax mov ax, fat_buffer diff --git a/src/mbr/mbr.nasm b/src/mbr/mbr.nasm index e4450a8..b1ad23d 100755 --- a/src/mbr/mbr.nasm +++ b/src/mbr/mbr.nasm @@ -138,15 +138,10 @@ main: ; uint16_t count, uint16_t drive_num) call read_disk_raw add sp, 0xC - - - jnc main.goto_vbr - ERROR MBR_ERROR_DISK_READ_ERR ; error in LBA read .goto_vbr: cmp word [VBR_ENTRY + 0x1FE], 0xAA55 je main.sig_ok ERROR MBR_ERROR_NO_VBR_SIG ; no signature present - .sig_ok: mov ax, partition_table_SIZE ; 72 bytes of data push ax @@ -166,8 +161,13 @@ main: ; BIOS Functions ; ; ############### + %include 'BIOS/func/ext_read.inc' +; ############### +; End Section +; ############### + %assign bytes_remaining (440 - ($ - $$)) %warning MBR has bytes_remaining bytes remaining for code (MAX: 440 bytes) times ((512 - 72) - ($ - $$)) nop ; Fill the rest of sector with nop diff --git a/src/stage2/stage2.nasm b/src/stage2/stage2.nasm index f014125..d6d11bd 100755 --- a/src/stage2/stage2.nasm +++ b/src/stage2/stage2.nasm @@ -23,16 +23,14 @@ [CPU KATMAI] jmp short init nop -; boot drive in dl -; active partition offset in si ; ############### ; ; Headers/Includes/Definitions ; ; ############### -%define __STEVIA_STAGE2 +%define __STEVIA_STAGE2 %include "cdecl16.inc" %include "entry.inc" @@ -43,6 +41,7 @@ nop ; ############### ; End Section ; ############### + ALIGN 4, db 0x90 init: cli ; We do not want to be interrupted @@ -62,7 +61,6 @@ init: jmp 0:main - ; ############### ; ; Extra/Shared Functions @@ -76,6 +74,10 @@ init: ; End Section ; ############### +; +; bp - 2 : uint8_t boot_drive +; bp - 4 : uint16_t part_offset +; main: lea ax, [bp - 2] mov [boot_drive_ptr], ax @@ -147,7 +149,6 @@ main: add sp, 0x2 ERROR STEVIA_DEBUG_HALT - hcf: hlt jmp short hcf diff --git a/src/vbr/vbr.nasm b/src/vbr/vbr.nasm index 2ffdd30..4c46864 100755 --- a/src/vbr/vbr.nasm +++ b/src/vbr/vbr.nasm @@ -37,7 +37,6 @@ times 54 db 0x00 ; ############### %define __STEVIA_VBR - %include "cdecl16.inc" %include "entry.inc" %include "config.inc" @@ -81,17 +80,14 @@ init: ALIGN 4, db 0x90 main: - mov byte [bp - 2], dl ; boot_drive + mov byte [bp - 2], dl ; boot_drive mov [bp - 4], si ; part_offset .check_FAT_size: ; we only support a very specific setup of FAT32 cmp dword [bsSectorHuge], 0 ; SectorsHuge will not be set if FAT12/16 ja main.load_stage2 - ERROR VBR_ERROR_WRONG_FAT_SIZE - -; read sectors 1-63 to stage2 entry point -.load_stage2: +.load_stage2: ; read sectors 1-63 to stage2 entry point mov ax, (fat32_bpb_SIZE + fat32_ebpb_SIZE) ; size in byte push ax mov ax, (phy_bpb_start - 0x3) ; start of bpb - 0x3 for the jump short main at the start @@ -140,10 +136,9 @@ main: jmp 0:0x7E00 ; ############### -; -; Required BIOS functions -; +; Required BIOS function(s) ; ############### + %include 'BIOS/func/ext_read.inc' %assign bytes_remaining (420 - ($ - $$))