Move fat32 and BIOS functions to their own files
This commit is contained in:
272
include/BIOS/BIOS_func.inc
Normal file
272
include/BIOS/BIOS_func.inc
Normal file
@@ -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
|
||||||
274
include/fat32/fat32_func_old.inc
Normal file
274
include/fat32/fat32_func_old.inc
Normal file
@@ -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
|
||||||
@@ -138,260 +138,7 @@ hcf:
|
|||||||
;
|
;
|
||||||
; ###############
|
; ###############
|
||||||
|
|
||||||
InitFATDriver:
|
%include 'fat32/fat32_func_old.inc'
|
||||||
__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
|
|
||||||
|
|
||||||
; ###############
|
; ###############
|
||||||
;
|
;
|
||||||
@@ -399,59 +146,13 @@ ReadFATCluster:
|
|||||||
;
|
;
|
||||||
; ###############
|
; ###############
|
||||||
|
|
||||||
|
%include 'BIOS/BIOS_func.inc'
|
||||||
|
|
||||||
; Wrapper for AH=0x42 INT13h (Extended Read)
|
; ##############################
|
||||||
;
|
;
|
||||||
; BIOS call details
|
; SYSTEM CONFIGURATION FUNCTIONS
|
||||||
; 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
|
|
||||||
|
|
||||||
; Prints a C-Style string (null terminated) using BIOS vga teletype call
|
; Prints a C-Style string (null terminated) using BIOS vga teletype call
|
||||||
; void PrintString(char* buf)
|
; void PrintString(char* buf)
|
||||||
@@ -550,217 +251,12 @@ PrintDWORD:
|
|||||||
__CDECL16_EXIT
|
__CDECL16_EXIT
|
||||||
ret
|
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
|
; 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:
|
EnterUnrealMode:
|
||||||
__CDECL16_ENTRY
|
__CDECL16_ENTRY
|
||||||
.func:
|
.func:
|
||||||
|
|||||||
Reference in New Issue
Block a user