2024-09-17 08:01:16 -05:00
stn := @use("../../../libraries/stn/src/lib.hb");
.{string, memory, buffer, log} := stn
2024-12-20 04:37:06 -06:00
VALID_JUMP_BYTES := u8.[0xEB, 0x3C, 0x90]
2024-09-17 08:01:16 -05:00
OemIdent := struct {
2024-12-20 04:37:06 -06:00
dos_version: [8]u8,
dos_version_name: [8]u8,
2024-09-17 08:01:16 -05:00
2024-12-01 11:52:26 -06:00
new := fn(major: int, minor: int): OemIdent {
2024-12-20 04:37:06 -06:00
return .(.[0, 0, 0, 0, 0, 0, 0, 0], .[0, 0, 0, 0, 0, 0, 0, 0])
2024-12-01 11:52:26 -06:00
}
2024-09-17 08:01:16 -05:00
}
BiosParameterBlock := struct {
2024-12-20 04:37:06 -06:00
jump_bytes: [3]u8,
2024-09-17 08:01:16 -05:00
oem_ident: OemIdent,
bytes_per_sector: u16,
sectors_per_cluster: u8,
reserved_sectors: u16,
// The amount of FileAllocationTables on the disk. Often 2.
fat_count: u8,
root_directory_count: u16,
// if 0 then refer to large_sector_count
total_sectors: u16,
media_type: u8,
// if 0 refer to sectors_per_fat in the ExtendedBootRecord
sectors_per_fat: u16,
sectors_per_track: u16,
head_count: u16,
hidden_sectors: u32,
large_sector_count: u32,
2024-12-01 11:52:26 -06:00
sanity_check := fn(bpb: BiosParameterBlock): int {
return 0
}
2024-09-17 08:01:16 -05:00
2024-12-01 11:52:26 -06:00
new := fn(): BiosParameterBlock {
return .(VALID_JUMP_BYTES, OemIdent.new(0, 0), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
}
2024-09-17 08:01:16 -05:00
2024-12-01 11:52:26 -06:00
sector_count := fn(bpb: BiosParameterBlock): u32 {
if bpb.total_sectors == 0 {
return bpb.large_sector_count
} else {
return bpb.total_sectors
}
2024-09-17 08:01:16 -05:00
}
}
FatVersionNumber := struct {
major_version: u8,
minor_version: u8,
}
2024-12-20 04:37:06 -06:00
FormatReservation := [12]u8
2024-09-17 08:01:16 -05:00
// Padded with spaces.
2024-12-20 04:37:06 -06:00
VolumeName := [11]u8
2024-09-17 08:01:16 -05:00
2024-12-20 04:37:06 -06:00
SystemIdentifierString := [8]u8
VALID_SYSTEM_IDENTIFIER_STRING := u8.[46, 41, 54, 33, 32, 20, 20, 20]
2024-10-25 10:37:38 -05:00
BOOTABLE_PARTITION_SIGNATURE := @as(u32, 0xAA55)
2024-09-17 08:01:16 -05:00
2024-12-20 04:37:06 -06:00
BootCode := [420]u8
2024-09-17 08:01:16 -05:00
ExtendedBootRecord := struct {
sectors_per_fat: u32,
flags: u16,
fat_version_number: FatVersionNumber,
// Typically set to 2.
root_directory_cluster_number: u32,
fsinfo_structure: u16,
backup_boot_sector: u16,
// When a volume is formated these bytes should be zero. As a sanity check I guess?
format_reserved: FormatReservation,
// 0x00 floppy or 0x80 hard disk
drive_number: u8,
nt_reserved: u8,
// must be 0x28 or 0x29
signature: u8,
volume_id_serial: u32,
volume_id_name: VolumeName,
// The spec says this is always FAT32. Untrustworthy and another sanity check I guess.
system_identifier_string: SystemIdentifierString,
boot_code: BootCode,
partition_signature: u16,
2024-12-01 11:52:26 -06:00
sanity_check := fn(ebr: ExtendedBootRecord): int {
ret := 0
if ebr.drive_number != 0x0 | ebr.drive_number != 0x80 {
log.warn("EBR-Drive-Number sanity check failed\0")
}
if ebr.signature != 0x28 | ebr.signature != 0x29 {
log.warn("EBR-Signature sanity check failed\0")
}
// ! comparison between [u8] is not supported in hblang
// if ebr.system_identifier_string != VALID_SYSTEM_IDENTIFIER_STRING {
// log.warn("EBR-Signature-Identifier-String sanity check failed\0")
// }
return 0
2024-09-17 08:01:16 -05:00
}
2024-12-01 11:52:26 -06:00
new := fn(): ExtendedBootRecord {
2024-12-20 04:37:06 -06:00
version := u8.[0, 0]
fmt_res := u8.[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
vol_name := @as([11]u8, idk)
boot_code := @as([420]u8, idk)
2024-12-01 11:52:26 -06:00
return ExtendedBootRecord.(
0,
0,
version,
0,
0,
0,
fmt_res,
0,
0,
0,
0,
vol_name,
VALID_SYSTEM_IDENTIFIER_STRING,
boot_code,
0,
)
2024-09-17 08:01:16 -05:00
}
}
2024-10-25 10:37:38 -05:00
VALID_LEAD_FS_INFO := @as(u32, 0x41615252)
VALID_TRAIL_FS_INFO := @as(u32, 0xAA550000)
2024-09-17 08:01:16 -05:00
FSInfo := struct {
// Must be 0x41615252 to indicate a valid FSInfo structure
lead_signature: u32,
2024-12-20 04:37:06 -06:00
lead_reserved: [480]u8,
2024-10-25 10:37:38 -05:00
// 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)
2024-09-17 08:01:16 -05:00
last_known_free_cluster_count: u32,
last_known_avalible_cluster: u32,
2024-12-20 04:37:06 -06:00
trail_reserved: [12]u8,
2024-09-17 08:01:16 -05:00
trail_signature: u32,
2024-12-01 11:52:26 -06:00
sanity_check := fn(fs_info: FSInfo): uint {
ret := 0
if fs_info.lead_signature != VALID_LEAD_FS_INFO {
ret &= 1
log.warn("Invalid leading signature in FSInfo.\0")
}
if fs_info.last_known_free_cluster_count == 0xFFFFFFFF {
ret &= 2
log.warn("Last known free cluster count unknown.\0")
}
if fs_info.last_known_avalible_cluster == 0xFFFFFFFF {
ret &= 4
log.warn("Last known avalible cluster count unknown.\0")
}
if fs_info.trail_signature != VALID_TRAIL_FS_INFO {
ret &= 8
log.warn("Invalid trailing signature in FSInfo.\0")
}
return ret
2024-09-17 08:01:16 -05:00
}
2024-12-01 11:52:26 -06:00
new := fn(): FSInfo {
2024-12-20 04:37:06 -06:00
lead_reserved := @as([480]u8, idk)
trail_reserved := @as([12]u8, idk)
2024-12-01 11:52:26 -06:00
return FSInfo.(
VALID_LEAD_FS_INFO,
lead_reserved,
0,
0,
trail_reserved,
VALID_TRAIL_FS_INFO,
)
}
2024-12-20 04:37:06 -06:00
}