move old fat32 system to fat32/old

This commit is contained in:
2025-09-09 17:01:14 -04:00
parent 1d696371d2
commit 14ef0151ca
2 changed files with 228 additions and 0 deletions

View File

@@ -0,0 +1,320 @@
; Copyright (C) 2025 Elaina Claus
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <https://www.gnu.org/licenses/>.
%ifndef __INC_FAT32_SYS
%include "partition_table.inc"
%include "fat32/bpb_offset_bx.inc"
%include "fat32/fat32_structures.inc"
; Clobbers: eax, edx
; returns: none
ALIGN 4, db 0x90
InitFATDriver:
__CDECL16_PROC_ENTRY
.func:
__CDECL16_CALL_ARGS fat32_state, 0x0000, FAT32_State_t_size
__CDECL16_CALL kmemset, 3
.calc_active_part:
mov ax, word [partition_offset]
mov di, fat32_state
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 [di + FAT32_State_t.curr_drive_lba_32], eax
mov si, fat32_bpb
mov bx, fat32_ebpb
.calc_first_fat:
movzx eax, word [si + FAT32_bpb_t.reserved_sectors_word] ; first fat from start of partition
add eax, dword [di + FAT32_State_t.curr_drive_lba_32] ; calculate offset from start of drive
jc InitFATDriver.error
mov dword [di + FAT32_State_t.first_fat_sector_32], eax
.calc_total_fat:
mov edx, dword [bx + FAT32_ebpb_t.FATSz_dword]
movzx eax, byte [si + FAT32_bpb_t.fat_count_byte]
mul edx ; 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 [di + FAT32_State_t.fat_size_32], eax
.calc_first_data:
mov edx, dword [di + FAT32_State_t.first_fat_sector_32]
add eax, edx
jc InitFATDriver.error
mov dword [di + FAT32_State_t.first_data_sector_32], eax
.set_first_dir:
mov eax, dword [bx + FAT32_ebpb_t.root_clus_dword]
mov dword [di + FAT32_State_t.curr_dir_cluster_32], eax
.endp:
__CDECL16_PROC_EXIT
ret
.error:
ERROR STAGE2_FAT32_INIT_CF
ALIGN 4, db 0x90
FSInfoPrinter:
__CDECL16_PROC_ENTRY
.func:
;info we want to print to validate we are loading stuff from the disk correctly
; boot_drive # (i.e 0x80)
; active/bootable partition info (lba_start, lba_length, part_type)
; BPB Info: BS_OEMName = ident_8, BPB_BytsPerSec = bytes_per_sector_16, BPB_SecPerClus = sectors_per_cluster_8
; eBPB info: FATSz_dword, volid, vol label
;
; print entire FAT32 state
;
.endp:
__CDECL16_PROC_EXIT
ret
.error:
ERROR STAGE2_ERROR_INFOPRINTER
; 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);
ALIGN 4, db 0x90
SearchFATDIR:
__CDECL16_PROC_ENTRY
.file_lookup:
__CDECL16_CALL_ARGS SearchFATDIR_info
__CDECL16_CALL PrintString, 1
mov bx, fat32_state
.load_first_dir:
; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster)
push dword [bx + FAT32_State_t.curr_dir_cluster_32] ; cluster
push dir_buffer ; offset
push 0x0000 ; segment
call ReadFATCluster
add sp, 0x8
mov 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
; uint32_t NextCluster(uint32_t active_cluster);
push dword [bx + FAT32_State_t.curr_dir_cluster_32]
call NextCluster
add sp, 0x4
cmp eax, 0x0fff_fff7
;je SearchFATDIR.bad_cluster ; TODO: Implement Bad cluster checks
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
; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster)
push dword [bx + FAT32_State_t.curr_dir_cluster_32] ; cluster
push dir_buffer ; offset
push 0x0000 ; segment
call ReadFATCluster
add sp, 0x8
.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
mov ax, dir_buffer
add ax, 0x1FF ; 512 - 1 bytes
cmp si, ax
jae SearchFATDIR.load_next_dir
jmp SearchFATDIR.empty_dir_entry
; TODO: move this to a seperate string search function
.parse_dir:
__CDECL16_CALL_ARGS MaybeFound_Boot_info
__CDECL16_CALL PrintString, 1
.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
mov di, BootTarget ; 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_PROC_EXIT
ret
; BUG: this function needs review
; 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_PROC_ENTRY
.func:
__CDECL16_CALL_ARGS NextFATCluster_info
__CDECL16_CALL PrintString, 1
__CDECL16_CALL_ARGS fat32_nc_data, 0x0000, FAT32_NextClusterData_t_size
__CDECL16_CALL kmemset, 3
mov edx, dword [bp + 4] ; active_cluster
mov si, fat32_nc_data ; instead of push/pop and moving the data back
mov di, fat32_bpb ; load si & di then use xchg
mov bx, fat32_state
.calc_offset:
; fat_offset = active_cluster * 4
mov eax, 4
mul edx
jc NextCluster.error_cfdivz
mov dword [si + FAT32_NextClusterData_t.fat_offset], eax ; move lower 32 bits to fat offset
.calc_fat_sector:
; fat_sector = first_fat_sector + (fat_offset / sector_size)
; entry_offset = fat_offset % sector_size
xor edx, edx
movzx ecx, word [di + FAT32_bpb_t.bytes_per_sector_word]
cmp eax, 0
je NextCluster.error_cfdivz
div ecx ; eDX:eAX / eCX = fat_sector - first_fat_sector in eAX
; eDX = remainder (fat_offset mod sector_size)
mov dword [si + FAT32_NextClusterData_t.entry_offset], edx
mov ecx, dword [bx + FAT32_State_t.first_fat_sector_32]
add eax, ecx ; fat_sector + first_fat_sector
mov dword [si + FAT32_NextClusterData_t.fat_sector], eax
.load_fat_table:
xor ax, ax
mov al, byte [boot_drive]
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
push ax
xor ax, ax
push ax
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]
mov si, fat_buffer
mov eax, dword [bx+si+0]
; BUG: ???
.endp:
__CDECL16_PROC_EXIT
ret
.error_cfdivz:
ERROR STAGE2_FAT32_NCLUS_CFDIVZ
; uint8_t ReadFATCluster(uint16_t seg, uint16_t offset, uint32_t cluster)
ALIGN 4, db 0x90
ReadFATCluster:
__CDECL16_PROC_ENTRY
.func:
__CDECL16_CALL_ARGS ReadFATCluster_info
__CDECL16_CALL PrintString, 1
mov bx, fat32_bpb
mov si, fat32_ebpb
xor ax, ax
mov al, byte [boot_drive]
push ax
mov ax, 0x1 ; count = 1
push ax
mov eax, dword [bp + 8] ; cluster
sub eax, 2
movzx edx, byte [bx + FAT32_bpb_t.sectors_per_cluster_byte]
mul edx ; result in eax, error on carry
jc ReadFATCluster.error
add eax, dword [si + FAT32_State_t.first_data_sector_32]
jc ReadFATCluster.error
; eax contains the LBA now
push dword eax ; lba = ClusterToLBA(..)
mov ax, word [bp + 6] ; offset
push ax
mov ax, word [bp + 4]
push ax
; uint8_t read_disk_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
.endp:
__CDECL16_PROC_EXIT
ret
.error:
ERROR STAGE2_FAT32_CLS2LBA_CF
%endif
%define __INC_FAT32_SYS

View File

@@ -0,0 +1,228 @@
; Copyright (C) 2025 Elaina Claus
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <https://www.gnu.org/licenses/>.
%ifndef __INC_FAT32_STRUCT
; ## FAT32 Info ##
; total_sectors = bsSectorsHuge
; fat_size = bsSectorsPerFat
;
; first_data_sector = bsResSectors + (bsFATs * bsSectPerFAT);
; total_data_sectors = bsSectorsHuge - (bsResSectors + (bsFATs * bsSectPerFAT));
; total_clusters = total_data_sectors / bsSectsPerClust
; first_fat_sector = bsResSectors
;
; ## FAT32 Table information ##
;
; fat_offset = active_cluster * 4
; fat_sector = first_fat_sector + (fat_offset / sector_size)
; entry_offset = fat_offset % sector_size
;
; table_value = fat_table[entry_offset] & 0x0FFF_FFFF
;
; ## FAT32 Directory Entries ##
; root_dir_cluster = bsRootDirCluster
; root_dir_sectors = ? (this is varible on FAT32 since the root dir is a cluster chain)
; first_sector_of_cluster = ((cluster - 2) * bsSectPerClust) + first_data_sector;
; BPB Information
; Size Description
; 8 OEM identifier.
; 2 The number of Bytes per sector (remember, all numbers are in the little-endian format).
; 1 Number of sectors per cluster.
; 2 Number of reserved sectors. The boot record sectors are included in this value.
; 1 Number of File Allocation Tables (FAT's) on the storage media. Often this value is 2.
; 2 Number of directory entries (must be set so that the root directory occupies entire sectors).
; 2 The total sectors in the logical volume.
; If this value is 0, it means there are more than 65535 sectors in the volume,
; and the actual count is stored in the Large Sector Count entry at 0x20.
;
; 1 This Byte indicates the media descriptor type.
; 2 Number of sectors per FAT. FAT12/FAT16 only.
; 2 Number of sectors per track.
; 2 Number of heads or sides on the storage media.
; 4 Number of hidden sectors. (i.e. the LBA of the beginning of the partition.)
; 4 Large sector count. This field is set if there are more than 65535 sectors in the volume,
; resulting in a value which does not fit in the Number of Sectors entry at 0x13.
struc FAT32_bpb_t
.reserved_jmpboot resb 3
.ident resb 8
.bytes_per_sector_word resb 2
.sectors_per_cluster_byte resb 1
.reserved_sectors_word resb 2
.fat_count_byte resb 1
.unused1_ZERO_word resb 2 ; Root entry count field, 0 on fat32
.unused2_ZERO_word resb 2 ; total sectors size 16, 0 on fat32
.media_desc_byte resb 1
.unused3_ZERO_word resb 2 ; FAT size 16, 0 on fat32
.sectors_per_track_word resb 2
.head_count_word resb 2
.hidden_sectors_dword resb 4
.total_sectors_dword resb 4
endstruc
; EBPB Information (FAT32)
; Size Description
; 4 Sectors per FAT. The size of the FAT in sectors.
; 2 Flags.
; 2 FAT version number. The high byte is the major version and the low byte is the minor version. FAT drivers should respect this field.
; 4 The cluster number of the root directory. Often this field is set to 2.
; 2 The sector number of the FSInfo structure.
; 2 The sector number of the backup boot sector.
; 12 Reserved. When the volume is formated these bytes should be zero.
; 1 Drive number. The values here are identical to the values returned by the BIOS interrupt 0x13. 0x00 for a floppy disk and 0x80 for hard disks.
; 1 Flags in Windows NT. Reserved otherwise.
; 1 Signature (must be 0x28 or 0x29).
; 4 Volume ID 'Serial' number. Used for tracking volumes between computers. You can ignore this if you want.
; 11 Volume label string. This field is padded with spaces.
; 8 System identifier string. Always "FAT32 ". The spec says never to trust the contents of this string for any use.
struc FAT32_ebpb_t
.FATSz_dword resb 4
.extflags_word resb 2
.FSVersion_word resb 2
.root_clus_dword resb 4
.FSInfo_word resb 2
.BkBootSec_word resb 2
.reserved1 resb 12
.drive_number_byte resb 1
.nt_flags_byte resb 1
.signature_byte resb 1
.volume_id_dword resb 4
.volume_label_bytea resb 11
.system_ident_bytea resb 8
endstruc
; ## Standard 8.3 structure ###
; Offset Length (Bytes) Description
; 0 11 8.3 file name. The first 8 characters are the name and the last 3 are the extension.
; 11 1 File Atrributes
; READ_ONLY=0x01
; HIDDEN=0x02
; SYSTEM=0x04
; VOLUME_ID=0x08
; DIRECTORY=0x10
; ARCHIVE=0x20
; LFN=READ_ONLY|HIDDEN|SYSTEM|VOLUME_ID == 0x0F
;
; 12 1 NT Reserved
; 13 1 Creation time in tenths of a second.
; 14 2 File creation time, Hour 5 bits, Minutes 6 bits, Seconds 5 Bits, multiply seconds by 2
; 16 2 File creation date, Year 7 bits, month 4 bits, day 5 bits
; 18 2 Last Accessed date. same format at creation date
; 20 2 High 16 bits of entry's first cluster
; 22 2 Last modification time. same format at creation time
; 24 2 Last modification date. same format as creation date
; 26 2 Low 16 bits of entry's first cluster
; 28 4 File size in bytes
; FSInfo
; 0 0x0 4 Lead signature (must be 0x41615252 to indicate a valid FSInfo structure)
; 4 0x4 480 Reserved, these bytes should never be used
; 484 0x1E4 4 Another signature (must be 0x61417272)
; 488 0x1E8 4 Contains the last known free cluster count on the volume. If the value is 0xFFFFFFFF, then the free count is unknown and must be computed.
; However, this value might be incorrect and should at least be range checked (<= volume cluster count)
;
; 492 0x1EC 4 Indicates the cluster number at which the filesystem driver should start looking for available clusters.
; If the value is 0xFFFFFFFF, then there is no hint and the driver should start searching at 2.
; Typically this value is set to the last allocated cluster number. As the previous field, this value should be range checked.
;
; 496 0x1F0 12 Reserved
; 508 0x1FC 4 Trail signature (0xAA550000)
struc FAT32_FSInfo_t
.head_sig_dword resd 1 ; 0x41615252
.reserved1 resb 480 ; fill zero
.body_sig_dword resd 1 ; 0x61417272
.free_count_dword resd 1
.next_free_dword resd 1
.reserved2 resb 12 ; fill zero
.tail_sig_dword resd 1 ; 0xAA550000
endstruc
struc FAT32_SFN_t
.label_83 resb 11
.attributes_byte resb 1
.nt_res_byte resb 1
.csec_byte resb 1
.ctime_word resb 2
.cdate_word resb 2
.adate_word resb 2
.cluster_16_high resb 2
.mtime_word resb 2
.mdate_word resb 2
.cluster_16_low resb 2
.size_dword resb 4
endstruc
; ## Long file name (LFN) structure format ##
;
; 0 1 The order of this entry in the sequence of long file name entries. This value helps you to know where in the file's name the characters from this entry should be placed.
; 1 10 The first 5, 2-byte characters of this entry.
; 11 1 Attribute. Always equals 0x0F. (the long file name attribute)
; 12 1 Long entry type. Zero for name entries.
; 13 1 Checksum generated of the short file name when the file was created. The short filename can change without changing the long filename in cases where the partition is mounted on a system which does not support long filenames.
; 14 12 The next 6, 2-byte characters of this entry.
; 26 2 Always zero.
; 28 4 The final 2, 2-byte characters of this entry.
;
; LFN entries are always placed immediately before their respective 8.3 entry
;
; LAST_LFN_ENTRY == 0x40
; Max of 20 in sequence == 0x14
struc FAT32_LFN_t
.order resb 1
.lfn_first5 resb 10
.attributes_8 resb 1
.zero1 resb 1
.checksum resb 1
.lfn_next6 resb 12
.zero2 resb 2
.lfn_last2 resb 4
endstruc
; 32 bytes
struc FAT32_State_t
.first_data_sector_32 resd 1
.first_fat_sector_32 resd 1
.fat_size_32 resd 1
.curr_FAT_cluster_32 resd 1
.curr_dir_cluster_32 resd 1
.curr_drive_lba_32 resd 1
endstruc
; 16 bytes
struc FAT32_NextClusterData_t
.fat_offset resd 1
.fat_sector resd 1
.entry_offset resd 1
.reserved_1 resd 1
endstruc
; FAT32 Attributes
%define FAT32_ATTR_RO 0x01
%define FAT32_ATTR_HIDDEN 0x02
%define FAT32_ATTR_SYSTEM 0x04
%define FAT32_ATTR_VOLID 0x08
%define FAT32_ATTR_DIR 0x10
%define FAT32_ATTR_ARC 0x20
; LFN == RO | HIDDEN | SYSTEM | VOLID == 0x0F
%define FAT32_ATTR_LFN 0x0F
%endif
%define __INC_FAT32_STRUCT