27 Commits

Author SHA1 Message Date
4a944bc493 minor changes in fat32 2025-09-20 08:29:43 -04:00
137735431a move stack after bss padding 2025-09-18 19:16:27 -04:00
6caaf6aa6d some structures for okteta
put in $(qtpaths --paths GenericDataLocation)
2025-09-18 17:20:17 -04:00
1e9de446f0 a few fixes to complete the move 2025-09-18 14:25:27 -04:00
5f2ca55af7 move mbr/vbr code to FAT32 system 2025-09-18 14:19:39 -04:00
11656c2827 more error codes and checks in vbr 2025-09-18 14:07:45 -04:00
f87f88a0dc fix qemu launch 2025-09-18 14:06:52 -04:00
7baa53178a update gitignore 2025-09-18 14:06:32 -04:00
8002d1cb54 more fat fs type checks 2025-09-18 11:50:27 -04:00
d8a89cfd2b remove shortjmp and ident from bpb 2025-09-18 11:20:05 -04:00
6c402b5c4f update structures 2025-09-17 21:48:37 -04:00
a3c9897291 prototyping 2025-09-17 20:59:48 -04:00
831d45c33c rename ext_disk_read to BIOS_int13h_ext_read 2025-09-17 18:54:59 -04:00
918e94689f 2KiB stack 2025-09-17 18:44:55 -04:00
8d2cde0a31 added no planned fat32 error codes and added mbr/vbr reading error codes 2025-09-17 17:02:08 -04:00
8d3788a76e remove unused structure 2025-09-17 16:50:59 -04:00
4a27e09872 use partition entry size constant 2025-09-17 16:24:45 -04:00
59bc1afb7c stick mmap info in SteviaInfo 2025-09-17 16:24:27 -04:00
8b0b73d8a4 start partition table at entry 1 2025-09-17 16:22:47 -04:00
803be58c10 Merge branch 'trunk' into fat_v2 2025-09-16 08:36:46 -04:00
528e3d69fe update github workflow since github includes firefox & snaps in the default runner image, which causes the build to fail.
All checks were successful
Daily Build and trunk tester / debian_update (push) Successful in 1m11s
going to need a custom runner I guess...might as well only do actions on gitea.
2025-09-16 08:34:22 -04:00
51bd250925 minor corrections 2025-09-13 15:30:11 -04:00
460165a8d1 re-naming 2025-09-13 15:07:36 -04:00
935cbd1089 naming changes to ReadMbr/Vbr 2025-09-13 14:56:26 -04:00
7f1b4fa632 more naming changes 2025-09-13 14:51:30 -04:00
14f6788a22 renaming things to a hungarian style and adding "types" 2025-09-13 14:41:09 -04:00
526c3e7ea5 remove define_info macro, improved cstr macro and renamed all the OK/Msg debug strings 2025-09-13 13:45:37 -04:00
17 changed files with 441 additions and 363 deletions

View File

@@ -3,7 +3,7 @@ on:
push:
branches: [ $default-branch ]
schedule:
- cron: "0 7 * * *" # daily 07:00
- cron: "0 7 * * 1" # mondays at 07:00
workflow_dispatch: {}
jobs:

3
.gitignore vendored
View File

@@ -10,4 +10,5 @@ stevia-log
*.map
compose-dev.yaml
eth_null-tx.log
eth_null-txdump.txt
eth_null-txdump.txt
*.log

View File

@@ -38,9 +38,6 @@ QEMU_ARGS := \
-device e1000,netdev=n0,mac=52:54:00:12:34:56 \
-netdev user,id=n0 \
-device piix3-usb-uhci \
-device usb-ohci,id=ohci0 \
-device usb-ehci,id=ehci0 \
-device pcspk \
-parallel null \
-serial null -serial none -serial none -serial none \
-chardev file,id=dbg,path=bochs-e9.log,append=on \

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<data>
<struct name="MBR">
<!-- 446 bytes: bootstrap code -->
<array name="bootCode" length="446">
<primitive type="UInt8"/>
</array>
<!-- 4 x 16-byte partition entries -->
<array name="partitions" length="4">
<struct name="PartitionEntry">
<primitive name="status" type="UInt8"/> <!-- 0x80=bootable -->
<array name="chsFirst" length="3"><primitive type="UInt8"/></array>
<primitive name="type" type="UInt8"/>
<array name="chsLast" length="3"><primitive type="UInt8"/></array>
<primitive name="lbaStart" type="UInt32"/>
<primitive name="lbaSectors" type="UInt32"/>
</struct>
</array>
<!-- Signature 0x55AA (little-endian UInt16 == 0xAA55 on disk) -->
<primitive name="signature" type="UInt16"/>
</struct>
</data>

View File

@@ -0,0 +1,12 @@
[Desktop Entry]
Icon=application-x-executable
Type=Service
ServiceTypes=KPluginInfo
Name=Stevia MBR Structure
X-KDE-PluginInfo-Author=Elaina Claus
X-KDE-PluginInfo-Name=mbr
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=https://chtm.me
X-KDE-PluginInfo-Category=structure
X-KDE-PluginInfo-License=MIT
X-KDE-PluginInfo-EnabledByDefault=false

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<data>
<struct name="VBR">
<!-- 3 bytes: jmp over bpb code -->
<array name="jmpcode" length="3">
<primitive name="opcode" type="UInt8"/>
</array>
<array name="bs_ident" length="8">
<primitive type="Char"/>
</array>
<struct name="FAT32_bpb">
<primitive name="BytesPerSector" type="UInt16"/>
<primitive name="SectorsPerCluster" type="UInt8"/>
<primitive name="ReservedSectors" type="UInt16"/>
<primitive name="FatCount" type="UInt8"/>
<primitive name="RootEntryCount16" type="UInt16"/>
<primitive name="TotalSectors16" type="UInt16"/>
<primitive name="MediaDesc" type="UInt8"/>
<primitive name="FATSize16" type="UInt16"/>
<primitive name="SectorsPerTrack" type="UInt16"/>
<primitive name="HeadCount" type="UInt16"/>
<primitive name="HiddenSectors" type="UInt32"/>
<primitive name="TotalSectors32" type="UInt32"/>
</struct>
<struct name="FAT32_ebpb">
<primitive name="FATSize32" type="UInt32"/>
<primitive name="ExtFlags" type="UInt16"/>
<primitive name="FSVersion" type="UInt16"/>
<primitive name="RootDirCluster" type="UInt32"/>
<primitive name="FSInfoSector" type="UInt16"/>
<primitive name="BkBootSector" type="UInt16"/>
<array name="reserved0" length="12">
<primitive type="uint8"/>
</array>
<primitive name="DriveNumber" type="UInt8"/>
<primitive name="NtFlags" type="UInt8"/>
<primitive name="Signature" type="UInt8"/>
<primitive name="VolumeId" type="UInt32"/>
<array name="VolumeLabel" length="11">
<primitive type="Char"/>
</array>
<array name="FilesystemIdent" length="8">
<primitive type="Char"/>
</array>
</struct>
<array name="BootCode" length="420">
<primitive type="UInt8"/>
</array>
<!-- Signature 0xAA55 -->
<primitive name="signature" type="UInt16"/>
</struct>
</data>

View File

@@ -0,0 +1,12 @@
[Desktop Entry]
Icon=application-x-executable
Type=Service
ServiceTypes=KPluginInfo
Name=Stevia FAT32 VBR Structure
X-KDE-PluginInfo-Author=Elaina Claus
X-KDE-PluginInfo-Name=vbr32
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=https://chtm.me
X-KDE-PluginInfo-Category=structure
X-KDE-PluginInfo-License=MIT
X-KDE-PluginInfo-EnabledByDefault=false

View File

@@ -33,35 +33,27 @@ struc AddressRangeDescStruct_t
.ExtType resd 1
endstruc
; !!! this procedure changes ES !!!
ALIGN 4, db 0x90
GetMemoryMap:
__CDECL16_PROC_ENTRY
push es ; save segment register
.func:
mov dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries], 0
mov word [SteviaInfo + SteviaInfoStruct_t.u16_E820MMapEntryCount], 0
xor ebx, ebx ; Continuation value, 0 for the first call
mov dx, BIOSMemoryMap
shr dx, 4
mov es, dx
xor di, di ; (BIOSMemoryMap >> 4):0 makes di an index into BIOSMemoryMap
mov di, BIOSMemoryMap ; destination is es:di, es should == ds
mov ecx, AddressRangeDescStruct_t_size ; hard request ACPI 3.0 table versions (24 bytes)
.loop_L1:
mov eax, 0x0000E820 ; select 0xE820 function
mov edx, 0x534D4150 ; 'SMAP' magic
clc ; clear carry
int 0x15
int 0x15 ; data will be stored at es:di by e820 call
jc GetMemoryMap.error
cmp eax, 0x534D4150
jne GetMemoryMap.no_smap_returned
.no_error:
mov eax, dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries]
add eax, 1
mov dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries], eax
inc word [SteviaInfo + SteviaInfoStruct_t.u16_E820MMapEntryCount]
cmp ecx, 20 ; TODO: maybe this could be handled better than just panicing
jb GetMemoryMap.nonstandard_e820 ; non-standard entry found
@@ -89,7 +81,7 @@ GetMemoryMap:
PrintMemoryMap:
__CDECL16_PROC_ENTRY
.func:
mov eax, dword [SteviaInfo + SteviaInfoStruct_t.MemoryMapEntries]
mov eax, dword [SteviaInfo + SteviaInfoStruct_t.u16_E820MMapEntryCount]
cmp eax, 0
je PrintMemoryMap.endp ; if entries == 0, exit

View File

@@ -51,7 +51,7 @@ endstruc
; uint32_t lba,
; uint16_t count, uint8_t drive_num)
ALIGN 4, db 0x90
read_disk_raw:
BIOS_int13h_ext_read:
__CDECL16_PROC_ENTRY
.func:
push LBAPkt_t_size ; len
@@ -94,7 +94,7 @@ read_disk_raw:
%elifdef __STEVIA_VBR
ERROR VBR_ERROR_DISK_READ_ERR
%else
ERROR STAGE2_MBR_DISK_READ_ERROR
ERROR STAGE2_INT13_DISK_READ_ERR
%endif
.endf:
__CDECL16_PROC_EXIT

View File

@@ -15,8 +15,7 @@
%ifndef __INC_ERROR_CODES
; Errors
; 12 Errors, 5 in use
; MBR Error codes
%define MBR_ERROR_DISK_T_ERR 'a'
%define MBR_ERROR_NO_INT32E 'b'
%define MBR_ERROR_NO_NO_BOOT_PART 'c'
@@ -30,7 +29,7 @@
%define MBR_ERROR_RESERVED_k 'k'
%define MBR_ERROR_INT13h_EREAD_ERR 'l'
; 12 Error
; VBR Error codes
%define VBR_ERROR_WRONG_FAT_SIZE 'm'
%define VBR_ERROR_NO_SIGNATURE 'n'
%define VBR_ERROR_DISK_READ_ERR 'o'
@@ -44,35 +43,35 @@
%define VBR_ERROR_RESERVED_w 'w'
%define VBR_ERROR_RESERVED_x 'x'
; 22 errors, 8 in use
; Stage2 Error codes
%define STAGE2_A20_FAILED 'A'
%define STAGE2_SIGNATURE_MISSING 'B'
%define STAGE2_MM_E820_NO_SUPPORT 'C'
%define STAGE2_MM_E820_MISC_ERR 'D'
%define STAGE2_MM_E820_NONSTANDARD 'E'
%define STAGE2_MM_E820_NO_SMAP 'F'
%define STAGE2_MBR_DISK_READ_ERROR 'G'
%define STAGE2_FAT32_INIT_ERROR 'H'
%define STAGE2_FAT32_NO_FILE 'I'
%define STAGE2_FAT32_END_OF_CHAIN 'J'
%define STAGE2_FAT32_NCLUS_CFDIVZ 'K'
%define STAGE2_FAT32_CLS2LBA_CF 'L'
%define STAGE2_FAT32_INIT_CF 'M'
%define STAGE2_ERROR_INFOPRINTER 'N'
%define STAGE2_ERROR_RESERVED_O 'O'
%define STAGE2_ERROR_RESERVED_P 'P'
%define STAGE2_ERROR_RESERVED_Q 'Q'
%define STAGE2_ERROR_RESERVED_R 'R'
%define STAGE2_ERROR_RESERVED_S 'S'
%define STAGE2_ERROR_RESERVED_T 'T'
%define STAGE2_ERROR_RESERVED_U 'U'
%define STAGE2_ERROR_RESERVED_V 'V'
%define STAGE2_INT13_DISK_READ_ERR 'G'
%define STAGE2_FAT32_E_FMT 'H'
%define STAGE2_FAT32_E_RANGE 'I'
%define STAGE2_FAT32_E_NOSUCH 'J'
%define STAGE2_FAT32_E_ISDIR 'K'
%define STAGE2_FAT32_E_TOOLONG 'L'
%define STAGE2_FAT32_E_UNSUPPORTED 'M'
%define STAGE2_FAT32_E_UNIMPLEMENTED 'N'
%define STAGE2_ERROR_BAD_MBR 'O'
%define STAGE2_VBR_E_ACTIVE 'P'
%define STAGE2_VBR_E_SIGN 'Q'
%define STAGE2_VBR_E_TOT 'R'
%define STAGE2_VBR_E_FATSZ 'S'
%define STAGE2_VBR_E_DIRENT 'T'
%define STAGE2_VBR_E_PARTTYPE 'U'
%define STAGE2_RESERVED_E_V 'V'
; for development only, specific errors should be above.
%define STEVIA_DEBUG_OK 'W'
%define STEVIA_DEBUG_ERR 'X'
%define STEVIA_DEBUG_UNIMPLEMENTED 'Y'
%define STEVIA_DEBUG_HALT 'Z'
; Debug error codes
%define STEVIA_DEBUG_OK 'W'
%define STEVIA_DEBUG_ERR 'X'
%define STEVIA_DEBUG_UNIMPLEMENTED 'Y'
%define STEVIA_DEBUG_HALT 'Z'
%endif
%define __INC_ERROR_CODES

View File

@@ -16,9 +16,169 @@
%ifndef __INC_FAT32_SYS
%include "partition_table.inc"
%include "fat32/bpb_offset_bx.inc"
%include "fat32/fat32_structures.inc"
; int read_mbr(int boot_drive, void* dst)
; destination buffer needs 512 bytes of space
FAT32_load_mbr:
__CDECL16_PROC_ENTRY
.proc:
; read mbr on boot drive to memory (for the partition table)
movzx ax, byte [bp + 4]
push ax ; drive_num (2)
push 0x01 ; count (2)
push dword 0x0 ; lba (4)
push word [bp + 6] ; offset = dst
push __STAGE2_SEGMENT ; this segment
call BIOS_int13h_ext_read
add sp, 0xC
.check_sig:
mov bx, [bp + 6]
cmp word [bx + 0x1FE], 0xAA55 ; check for bytes at end
jne .error_nosign
; TODO: this needs more error checking, zero checking, check the sig a bunch of stuff...
.endp:
__CDECL16_PROC_EXIT
ret
.error_nosign:
ERROR STAGE2_ERROR_BAD_MBR
; int read_vbr(int boot_drive, void* buf)
; read vbr on boot partition to memory (for fat bpb/ebpb)
; TODO: seperate validation and loading the sector, just check the 0xAA55 at the end here...
FAT32_load_vbr:
__CDECL16_PROC_ENTRY
.proc:
mov bx, SteviaInfo
mov ax, word [bx + SteviaInfoStruct_t.p16_MbrPtr]
add ax, DISK_PARTITION_TABLE_OFFSET
mov bx, ax ; offset to part table
mov cx, 4 ; only checking 4 entries
.find_active_L0:
mov al, [bx + PartEntry_t.attributes]
cmp al, 0x80 ; 0x80 == 1000_0000b
je .check_fstype
add bx, PartEntry_t_size ; next part entry's attributes
loop .find_active_L0
jmp .error_noactive
.check_fstype:
; check for part_type = 0x0C (DOS 7.1+/W95 FAT32 w/ LBA) or 0x1C (Hidden 0x0C)
__BOCHS_MAGIC_DEBUG
mov al, [bx + PartEntry_t.part_type]
cmp al, 0x0C
je .active_ok
; *or*
cmp al, 0x1C
je .active_ok
jmp .error_badparttype ; error if part_type != 0x1C or 0x0C
.active_ok:
movzx ax, byte [bp + 4]
push ax ; drive_num (2)
push 0x01 ; count (2)
mov eax, dword [bx + PartEntry_t.lba_start]
push dword eax ; lba (4)
push word [bp + 6] ; offset = dst
push __STAGE2_SEGMENT ; this segment
call BIOS_int13h_ext_read
add sp, 0xC
; vbr (with fat bpb/ebpb) is at the buffer now
.check_sig:
mov bx, [bp + 6]
cmp word [bx + 0x1FE], 0xAA55 ; check for bytes at end
jne .error_nosign
.check_FAT_sanity:
; we only quickly validate that this is *probably* a FAT32 volume
add bx, 11 ; point bx at start of bpb (skip jmp code and ident)
cmp word [bx + FAT32_bpb_t.u16_TotalSectors16], 0 ; TotalSectors16 should be 0 (use TotalSectors32 in bpb)
jne .error_totsectors
cmp word [bx + FAT32_bpb_t.u16_FATSize16], 0 ; FatSize16 will be 0 if FAT32 (use FATSize32 in ebpb)
jne .error_fatsz
cmp word [bx + FAT32_bpb_t.u16_RootEntryCount16], 0 ; root dir info is in data clusters on fat32
jne .error_rootdir
.endp:
__CDECL16_PROC_EXIT
ret
.error_noactive:
ERROR STAGE2_VBR_E_ACTIVE
.error_nosign:
ERROR STAGE2_VBR_E_SIGN
.error_totsectors:
ERROR STAGE2_VBR_E_TOT
.error_fatsz:
ERROR STAGE2_VBR_E_FATSZ
.error_rootdir:
ERROR STAGE2_VBR_E_DIRENT
.error_badparttype:
ERROR STAGE2_VBR_E_PARTTYPE
; what a 'mount' should probably do at this point...
; - read VBR at partition_lba
; - validate FAT32 signatures
; - fill fat32_bpb_t and compute derived fields
; - read FSInfo (free count/next free)
; - ???
; int fat32_mount(FAT32_State_t* state, uint32_t partition_lba);
FAT32_mountfs:
__CDECL16_PROC_ENTRY
.proc:
; mount: parse BPB, derive fat0_lba, data_lba, cluster0_lba.
.endp:
__CDECL16_PROC_EXIT
ret
.error:
ERROR STEVIA_DEBUG_ERR
; int fat32_read_fat(FAT32_State_t* state, uint32_t clus, uint32_t* out);
FAT32_read_fat:
__CDECL16_PROC_ENTRY
.proc:
; Read 32-bit FAT entry for cluster n
.endp:
__CDECL16_PROC_EXIT
ret
.error:
ERROR STEVIA_DEBUG_ERR
; FAT32 entry is 32-bits; only low 28 bits are meaningful.
; EOC if (val & 0x0FFFFFFF) >= 0x0FFFFFF8.
; bad if == 0x0FFFFFF7.
; free if == 0x00000000.
; int fat32_next_clus(FAT32_State_t* state, uint32_t clus, uint32_t* out_next);
FAT32_next_cluster:
__CDECL16_PROC_ENTRY
.proc:
; Walk to next cluster in chain (validates EOC/bad)
.endp:
__CDECL16_PROC_EXIT
ret
.error:
ERROR STEVIA_DEBUG_ERR
; e.g:
; uint64_t clus_to_lba(FAT32_State_t* state, uint32_t clus) {
; return v->data_lba + (uint64_t)(clus - 2) * v->secs_per_clus;
; }
FAT32_clus_to_lba:
__CDECL16_PROC_ENTRY
.proc:
; Convert cluster -> LBA of first sector of that cluster
.endp:
__CDECL16_PROC_EXIT
ret
.error:
ERROR STEVIA_DEBUG_ERR
; Prototyping for now...
; TODO:
@@ -59,35 +219,6 @@
; int cache_read_sector(uint64_t lba, void* dst);
; int cache_invalidate_all(void);
; what a 'mount' should probably do at this point...
; - read VBR at partition_lba
; - validate FAT32 signatures
; - fill fat32_bpb_t and compute derived fields
; - read FSInfo (free count/next free)
; - ???
; int fat32_mount(uint32_t partition_lba, fat32_bpb_t* out);
;
; Accessors
;
; // Convert cluster -> LBA of first sector of that cluster
; uint64_t clus_to_lba(const fat32_bpb_t* v, uint32_t clus) {
; return v->data_lba + (uint64_t)(clus - 2) * v->secs_per_clus;
; }
; FAT32 entry is 32-bits; only low 28 bits are meaningful.
; EOC if (val & 0x0FFFFFFF) >= 0x0FFFFFF8.
; bad if == 0x0FFFFFF7.
; free if == 0x00000000.
; // Read 32-bit FAT entry for cluster n
; int fat32_read_fat(const fat32_bpb_t* v, uint32_t clus, uint32_t* out);
; // Walk to next cluster in chain (validates EOC/bad)
; int fat32_next_clus(const fat32_bpb_t* v, uint32_t clus, uint32_t* out_next);
;
; SFN directories
;
@@ -109,7 +240,6 @@
;int fat32_dir_iter_open(fat32_bpb_t* v, uint32_t first_clus, fat32_dir_iter_t* it);
;int fat32_dir_iter_next(fat32_dir_iter_t* it, fat32_dirent_sfn_t* out); // FS_OK or FS_E_END
; typedef struct {
; uint32_t first_clus;
; uint32_t size;

View File

@@ -58,20 +58,18 @@
; 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
.u16_BytesPerSector resw 1
.u8_SectorsPerCluster resb 1
.u16_ReservedSectors resw 1
.u8_FatCount resb 1
.u16_RootEntryCount16 resw 1 ; Root dir entry count field, 0 on fat32
.u16_TotalSectors16 resw 1 ; total number of sectors size, 0 on fat32
.u8_MediaDesc resb 1
.u16_FATSize16 resw 1 ; FAT size 16, 0 on fat32
.u16_SectorsPerTrack resw 1
.u16_HeadCount resw 1
.u32_HiddenSectors resd 1
.u32_TotalSectors32 resd 1
endstruc
; EBPB Information (FAT32)
@@ -91,19 +89,19 @@ endstruc
; 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
.u32_FATSize32 resd 1 ; size of *each* fat in sectors, total = FATSz * (# of FATs)
.u16_ExtFlags resw 1
.u16_FSVersion resw 1
.u32_RootDirCluster resd 1
.u16_FSInfoSector resw 1
.u16_BkBootSector resw 1
.reserved0 resb 12
.u8_DriveNumber resb 1
.u8_NtFlags resb 1
.u8_Signature resb 1
.u32_VolumeId resd 1
.volume_label resb 11
.system_ident resb 8 ; Should always be 'FAT32 '
endstruc
; ## Standard 8.3 structure ###
@@ -197,20 +195,11 @@ 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
.u32_TotalClusters resd 1
.u32_DataAreaStartSector resd 1
.u32_FATAreaStartSector resd 1
.p16_FATBuffer resw 1
.p16_ClustBuffer resw 1
endstruc
; FAT32 Attributes

View File

@@ -15,6 +15,9 @@
%ifndef __INC_PART_TABLE
%define DISK_SIGNATURE_OFFSET 0x1B8
%define DISK_PARTITION_TABLE_OFFSET 0x1BE
; Partition table entry format
; Off. Size. Description
;0x00 1 Drive attributes (bit 7 set = active or bootable)
@@ -34,8 +37,6 @@ struc PartEntry_t
endstruc
struc PartTable_t
.signature resb 4
.reserved resb 2
.partition1 resb PartEntry_t_size
.partition2 resb PartEntry_t_size
.partition3 resb PartEntry_t_size

View File

@@ -11,9 +11,9 @@ endstruc
; void arena_init(ArenaState *a)
;
arena_init:
ArenaInit:
__CDECL16_PROC_ENTRY
.func:
.proc:
mov ax, word [bp + 4] ; ptr to state structure
mov di, ax
@@ -25,15 +25,11 @@ arena_init:
; zero out heap area on init
; void* kmemset_byte(void* dst, uint8_t val, uint16_t len);
; TODO: use word or qword spacing at least to speed this up
mov ax, __ARENA_HEAP_SIZE
push ax ; len
xor ax, ax
push ax ; val = 0
mov ax, __ARENA_HEAP_START
push ax ; dst
push __ARENA_HEAP_SIZE ; len
push 0x0 ; val = 0
push __ARENA_HEAP_START ; dst
call kmemset
add sp, 0x6
.endp:
__CDECL16_PROC_EXIT
ret
@@ -43,7 +39,7 @@ arena_init:
; align x up to the nearest specified alignment (a), a should be a power of 2
; (x + (a-1)) & ~(a-1)
; return value in ax
arena_align_up:
ArenaAlignUp:
__CDECL16_PROC_ENTRY
.func:
; if a == 0 return x
@@ -51,7 +47,7 @@ arena_align_up:
mov bx, [bp + 6] ; a
test bx, bx
jz .endp
jz .endf
; enforce power-of-two for alignment, return x
; for example...
@@ -69,7 +65,7 @@ arena_align_up:
mov cx, bx
dec cx
test bx, cx
jnz .endp
jnz .endf
dec bx ; a - 1
@@ -80,7 +76,7 @@ arena_align_up:
and cx, bx ; and with the inverse
mov ax, cx ; move to ax and return
.endp:
.endf:
__CDECL16_PROC_EXIT
ret
@@ -88,9 +84,9 @@ arena_align_up:
; bp-2 - current used arena (i.e 'highmark')
; bp-4 - aligned_ptr
; bp-6 - new_end
arena_alloc:
ArenaAlloc:
__CDECL16_PROC_ENTRY 0x10
.func:
.proc:
; remove bytes from pool and increment mark to the new cursor location
; return a pointer to the begining of allocated segment
mov bx, early_heap_state
@@ -102,11 +98,10 @@ arena_alloc:
push bx ; save heap_state pointer
mov ax, word [bp + 6] ; requested next allocation alignment
push ax
mov ax, word [bp - 2] ; current arena 'highmark'
push ax
call arena_align_up
push word [bp + 6] ; requested next allocation alignment
push word [bp - 2] ; current arena 'highmark'
call ArenaAlignUp
add sp, 0x4
mov word [bp - 4], ax ; save return value
@@ -118,7 +113,7 @@ arena_alloc:
mov dx, word [bx + ArenaStateStruc_t.end]
cmp ax, dx
ja arena_alloc.error ; if our heap end is < the requested throw an error, heap is full
ja .error ; if our heap end is < the requested throw an error, heap is full
; else update the mark to the new value & return the aligned pointer
; mark_delta = new_end - curr_used
@@ -140,7 +135,7 @@ arena_alloc:
arena_mark:
__CDECL16_PROC_ENTRY
.func:
.proc:
; return the current location of the 'cursor' in the allocator
ERROR STEVIA_DEBUG_UNIMPLEMENTED
.endp:
@@ -149,7 +144,7 @@ arena_mark:
arena_reset_to:
__CDECL16_PROC_ENTRY
.func:
.proc:
; rewind the arena to a previously marked point
ERROR STEVIA_DEBUG_UNIMPLEMENTED
.endp:
@@ -158,7 +153,7 @@ arena_reset_to:
arena_reset:
__CDECL16_PROC_ENTRY
.func:
.proc:
; reset the entire heap to a fresh state
ERROR STEVIA_DEBUG_UNIMPLEMENTED
.endp:

View File

@@ -109,7 +109,7 @@ main:
mov al, byte [bx + PartEntry_t.attributes]
test al, 0x80 ; 0x80 == 1000_0000b
jnz main.active_found
add bx, 0x10 ; add 16 bytes to offset
add bx, PartEntry_t_size ; add 16 bytes to offset
loop main.find_active_L0
ERROR MBR_ERROR_NO_NO_BOOT_PART
@@ -133,7 +133,7 @@ main:
; 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
call BIOS_int13h_ext_read
add sp, 0xC
.goto_vbr:
cmp word [VBR_ENTRY + 0x1FE], 0xAA55

View File

@@ -39,7 +39,7 @@ begin_text:
ALIGN 16, db 0x90
init:
cli ; We do not want to be interrupted
mov [boot_drive], dl ; copy boot_drive to globals
mov [u8_BootDrive], dl ; copy boot_drive to globals
mov ax, __STAGE2_SEGMENT ; set all our segments to the configured segment, except es
mov ds, ax ; *
@@ -91,7 +91,7 @@ init:
%include "partition_table.inc"
%include "fat32/fat32_structures.inc"
;%include 'fat32/FAT32_SYS.inc'
%include 'fat32/FAT32_SYS.nasm'
; ###############
; BIOS functions
@@ -102,14 +102,10 @@ init:
; structures
struc SteviaInfoStruct_t
.MemoryMapPtr resd 1
.MemoryMapEntries resd 1
endstruc
struc EarlyBootStruct_t
.partition_table resb PartTable_t_size
.fat32_bpb resb FAT32_bpb_t_size
.fat32_ebpb resb FAT32_ebpb_t_size
.p16_E820MemoryMapPtr resw 1
.u16_E820MMapEntryCount resw 1
.p16_MbrPtr resw 1
.p16_VbrPtr resw 1
endstruc
ALIGN 4, db 0x90
@@ -126,38 +122,39 @@ main:
; setup the early heap
__CDECL16_CALL_ARGS early_heap_state
__CDECL16_CALL arena_init, 1
__CDECL16_CALL ArenaInit, 1
__CDECL16_CALL_ARGS HelloPrompt_info
__CDECL16_CALL_ARGS pszHelloPrompt
__CDECL16_CALL PrintString, 1
; setup and store our vbr/mbr (e)bpb
; setup heap space for mbr data
__CDECL16_CALL_ARGS 0x200, 0x10
__CDECL16_CALL arena_alloc, 2
mov word [mbr_ptr], ax
__CDECL16_CALL ArenaAlloc, 2
mov word [SteviaInfo + SteviaInfoStruct_t.p16_MbrPtr], ax
push ax ; dst
movzx ax, byte [boot_drive]
movzx ax, byte [u8_BootDrive]
push ax ; boot_drive
__CDECL16_CALL read_mbr, 2 ; fill mbr buffer
__CDECL16_CALL FAT32_load_mbr, 2 ; fill/validate mbr buffer
; setup heap space for vbr data
__CDECL16_CALL_ARGS 0x200, 0x10
__CDECL16_CALL arena_alloc, 2
mov word [vbr_ptr], ax
__CDECL16_CALL ArenaAlloc, 2
mov word [SteviaInfo + SteviaInfoStruct_t.p16_VbrPtr], ax
push ax ; dst
movzx ax, byte [boot_drive]
movzx ax, byte [u8_BootDrive]
push ax ; boot_drive
__CDECL16_CALL read_vbr, 2 ; fill vbr buffer
__CDECL16_CALL FAT32_load_vbr, 2 ; fill/validate vbr buffer
; enable A20 gate
call EnableA20
__CDECL16_CALL_ARGS A20_Enabled_OK_info
__CDECL16_CALL_ARGS pszA20EnabledOk
__CDECL16_CALL PrintString, 1
; get system memory map
call GetMemoryMap
__CDECL16_CALL_ARGS MemoryMap_OK_info
__CDECL16_CALL_ARGS pszMemoryMapOk
__CDECL16_CALL PrintString, 1
; enter unreal mode (enter PM w/ 16 bit code, 32 bit flat memory model & return to real)
@@ -165,12 +162,12 @@ main:
; use __REFLAT macros to re-flat ds/es for easy transfers to >1MiB
; NOTE: if you modify a segment register you will need to re-unreal it
call EnterUnrealMode
__CDECL16_CALL_ARGS UnrealMode_OK_info
__CDECL16_CALL_ARGS pszUnrealModeOk
__CDECL16_CALL PrintString, 1
; FAT Driver setup
;call InitFATDriver
;__CDECL16_CALL_ARGS InitFATSYS_OK_info
;__CDECL16_CALL_ARGS pszInitFAT32Ok
;__CDECL16_CALL PrintString, 1
;
@@ -178,7 +175,7 @@ main:
;call SearchFATDIR
;push dword eax ; save first cluster of bootable file
;__CDECL16_CALL_ARGS FileFound_OK_info
;__CDECL16_CALL_ARGS pszFileFoundMsg
;__CDECL16_CALL PrintString, 1
;pop dword eax
@@ -197,87 +194,6 @@ hcf:
;
; ##############################
; int read_mbr(int boot_drive, void* dst)
; destination buffer needs 512 bytes of space
read_mbr:
__CDECL16_PROC_ENTRY
.proc:
; read mbr on boot drive to memory (for the partition table)
movzx ax, byte [bp + 4]
push ax ; drive_num (2)
push 0x01 ; count (2)
push dword 0x0 ; lba (4)
push word [bp + 6] ; offset = dst
push __STAGE2_SEGMENT ; this segment
call read_disk_raw
add sp, 0xC
.check_sig:
mov bx, [bp + 6]
cmp word [bx + 0x1FE], 0xAA55 ; check for bytes at end
jne read_mbr.error
; TODO: this needs error checking, zero checking, check the sig a bunch of stuff...
.update_globals:
mov ax, [bp + 6]
add ax, 0x1B8 ; offset to start of PartTable
mov [part_table_ptr], ax
.endp:
__CDECL16_PROC_EXIT
ret
.error:
ERROR STEVIA_DEBUG_ERR
; int read_vbr(int boot_drive, void* buf)
read_vbr:
__CDECL16_PROC_ENTRY
.proc:
__BOCHS_MAGIC_DEBUG
; read vbr on boot partition to memory (for fat bpb/ebpb)
.calc_part_offset:
mov bx, word [part_table_ptr] ; base pointer @ partition table
mov cx, 4 ; only checking 4 entries
mov si, PartEntry_t.attributes
.find_active_L0:
mov al, byte [bx + si]
test al, 0x80 ; 0x80 == 1000_0000b
je read_vbr.active_found
add si, 0x10 ; add 16 bytes to offset (next part entry's attributes)
loop read_vbr.find_active_L0
jmp read_vbr.error
.active_found:
add bx, si ; update base to active part
movzx ax, byte [bp + 4]
push ax ; drive_num (2)
push 0x01 ; count (2)
mov eax, dword [bx + PartEntry_t.lba_start]
push dword eax ; lba (4)
push word [bp + 6] ; offset = dst
push __STAGE2_SEGMENT ; this segment
call read_disk_raw
add sp, 0xC
; vbr (with fat bpb/ebpb) is at the buffer now
.check_sig:
mov bx, [bp + 6]
cmp word [bx + 0x1FE], 0xAA55 ; check for bytes at end
jne read_mbr.error
.check_FAT_size:
test word [bx + FAT32_bpb_t.unused2_ZERO_word], 0 ; TotSectors16 will not be set if FAT32
jnz read_vbr.error
.update_globals:
mov word [fat32_bpb_ptr], bx
add bx, FAT32_bpb_t_size ; offset to ebpb
mov word [fat32_ebpb_ptr], bx
.endp:
__CDECL16_PROC_EXIT
ret
.error:
ERROR STEVIA_DEBUG_ERR
; set ds and es segments back to the base of the loader
%ifnmacro __TINY_DS_ES
%macro __TINY_DS_ES 0
@@ -291,7 +207,7 @@ read_vbr:
%ifnmacro __REFLAT_DS_ES
%macro __REFLAT_DS_ES 0
cli ; no interrupts
lgdt [((__STAGE2_SEGMENT << 4) + unreal_gdt_info)] ; load unreal gdt
lgdt [((__STAGE2_SEGMENT << 4) + UnrealGdtInfo)] ; load unreal gdt
mov eax, cr0
or eax, 1 ; set pmode bit
@@ -315,7 +231,7 @@ read_vbr:
%ifnmacro __REFLAT_ES
%macro __REFLAT_ES 0
cli ; no interrupts
lgdt [((__STAGE2_SEGMENT << 4) + unreal_gdt_info)] ; load unreal gdt
lgdt [((__STAGE2_SEGMENT << 4) + UnrealGdtInfo)] ; load unreal gdt
mov eax, cr0
or eax, 1 ; set pmode bit
@@ -338,8 +254,8 @@ ALIGN 4, db 0x90
EnterUnrealMode:
__CDECL16_PROC_ENTRY
cli ; no interrupts
.func:
lgdt [((__STAGE2_SEGMENT << 4) + unreal_gdt_info)] ; load unreal gdt
.proc:
lgdt [((__STAGE2_SEGMENT << 4) + UnrealGdtInfo)] ; load unreal gdt
mov eax, cr0
or eax, 1 ; set pmode bit
@@ -385,51 +301,46 @@ begin_data:
; #############
%define CRLF 0Dh, 0Ah
%macro define_cstr 2
%macro define_cstr 2-*
%if %0 > 2
align 16
%1_cstr:
%1:
db %{2:-1}, 00h
%else
align 16
%1:
db %2, 00h
%endif
%endmacro
%macro define_info 2
align 16
%1_info:
db %2, CRLF, 00h
%endmacro
define_cstr pszHelloPrompt, "Hello from Stevia Stage2!", CRLF
define_cstr pszA20EnabledOk, "A20 Enabled OK", CRLF
define_cstr pszMemoryMapOk, "Memory map OK", CRLF
define_cstr pszUnrealModeOk, "Unreal mode OK", CRLF
define_cstr pszInitFAT32Ok, "FAT32 Driver Init OK", CRLF
define_info HelloPrompt, "Hello from Stevia Stage2!"
define_info A20_Enabled_OK, "A20 Enabled OK"
define_info MemoryMap_OK, "Memory map OK"
define_info UnrealMode_OK, "Unreal mode OK"
define_info FileFound_OK, "Found SFN entry for bootable binary, first cluster -> "
define_info InitFATSYS_OK, "FAT32 Driver Init..."
define_info SearchFATDIR, "Searching FAT DIR for bootable file..."
define_info NextFATCluster, "Attempting to find next FAT cluster..."
define_info ReadFATCluster, "Attempting to load next FAT"
define_info MaybeFound_Boot, "Maybe found a file...checking..."
define_cstr pszFileFoundMsg, "Found SFN entry for bootable binary, first cluster -> ", CRLF
define_cstr pszSearchFAT32DirMsg, "Searching FAT fs for bootable file...", CRLF
define_cstr pszReadFAT32ClusterMsg, "Attempting to load next FAT", CRLF
define_cstr pszMaybeFoundBootMsg, "Maybe found a file...checking...", CRLF
define_cstr BootTarget, "BOOT BIN"
; set to boot_drive passed from BIOS almost first thing in init
align 4, db 0
boot_drive:
u8_BootDrive:
db 0x00
align 16, db 0
BootTarget:
db 'BOOT BIN'
align 16, db 0
IntToHex_table:
db '0123456789ABCDEF'
; see docs/gdt.txt for a quick refresher on GDT
align 16, db 0
unreal_gdt_info:
unreal_gdt_size: dw (unreal_gdt_end - unreal_gdt_start) - 1
unreal_gdt_ptr: dd ((__STAGE2_SEGMENT << 4) + unreal_gdt_start)
unreal_gdt_start:
UnrealGdtInfo:
u16_UnrealGdt_size: dw (UnrealGdtEnd - UnrealGdtStart) - 1
pF_UnrealGdtPtr: dd ((__STAGE2_SEGMENT << 4) + UnrealGdtStart)
UnrealGdtStart:
; entry 0 (null descriptor)
dq 0 ; first entry is null
@@ -446,14 +357,14 @@ unreal_gdt_start:
db 1001_0010b ; Access Byte: Present, ring0, S = 1, data (0), non-confirming, writable, present
db 1000_1111b ; Flags: GR = 4KiB, attr = <16-bit/?/?>, Granularity = 4KiB & 16:19 of limit
db 0x00 ; Base Address(31:24)
unreal_gdt_end:
UnrealGdtEnd:
align 16, db 0
gdt32_info:
gdt32_size: dw (gdt32_end - gdt32_start) - 1
gdt32_ptr: dd ((__STAGE2_SEGMENT << 4) + gdt32_start)
gdt32_start:
dq 0
Gdt32Info:
gdt32_size: dw (Gdt32End - Gdt32Start) - 1
gdt32_ptr: dd ((__STAGE2_SEGMENT << 4) + Gdt32Start)
Gdt32Start:
dq 0 ; null segment
.gdt32_code:
dw 0xFFFF ; code segment (RX)
dw 0x0000
@@ -482,22 +393,22 @@ gdt32_start:
db 1001_0000b ; Access: readable, not writable
db 1100_1111b ; 4KB granularity, 32-bit
db 0x00
gdt32_end:
Gdt32End:
align 16,db 0
BUILD_NASM_VER:
BuildNasmVer:
db "Stevia Stage2 built with NASM - ", __NASM_VER__, 00h
align 16,db 0
BUILD_DATETIME:
BuildDateTime:
db 'Assembled - ', __DATE__, ' ', __TIME__, 00h
align 16,db 0
BUILD_GIT_VER:
BuildGitVer:
db __GIT_VER__, 00h
align 16,db 0
BUILD_GIT_HASH:
BuildGitHash:
db __GIT_HASH__, 00h
end_data:
@@ -518,72 +429,22 @@ align 16, resb 1
section .bss follows=.sign
begin_bss:
align 4, resb 1
mbr_ptr:
resw 1
align 4, resb 1
vbr_ptr:
resw 1
align 4, resb 1
part_table_ptr:
resw 1
align 4, resb 1
fat32_bpb_ptr:
resw 1
align 4, resb 1
fat32_ebpb_ptr:
resw 1
; structures
align 16, resb 1
partition_table:
resb PartTable_t_size
SteviaInfo:
resd SteviaInfoStruct_t_size
align 16, resb 1
fat32_bpb:
resb FAT32_bpb_t_size
fat32_ebpb:
resb FAT32_ebpb_t_size
align 16, resb 1
fat32_nc_data:
resb 16
early_heap_state:
resb ArenaStateStruc_t_size
align 16, resb 1
lba_packet:
resb LBAPkt_t_size
align 16, resb 1
fat32_state:
resb FAT32_State_t_size
align 16, resb 1
SteviaInfo:
resd 4
align 16, resb 1
early_heap_state:
resb ArenaStateStruc_t_size
;
; post-bss init globals
;
;
; large continuous allocations
;
align 16, resb 1
disk_buffer:
resb 512
fat_buffer:
resb 512
dir_buffer:
resb 512
fat_fsinfo:
resb 512
; TODO: this will hold 42 entries from the map function
; the e820 function needs to check that it doesn't overflow
@@ -592,17 +453,19 @@ align 16, resb 1
%define BIOSMemoryMap_SIZE 1024
BIOSMemoryMap:
resb BIOSMemoryMap_SIZE
align 16, resb 1
stack_bottom:
resb 1024
stack_top:
end_bss:
; !!! End bss data !!!
%define STACK_SIZE 0x1000 ; 4 KiB
; Pad to the cap (emits nothing in the file; only increases .bss virtual size).
; If BSS_SIZE > BSS_MAX_BYTES, this becomes negative and NASM errors out.
%define BSS_MAX_BYTES 0x3000
%define BSS_MAX_BYTES (0x2000 - STACK_SIZE)
resb (BSS_MAX_BYTES - (end_bss - begin_bss))
align 16, resb 1
stack_bottom:
resb STACK_SIZE
stack_top:
; Optional: keep a label for later math:
bss_cap_end:

View File

@@ -21,15 +21,21 @@
%define __STEVIA_VBR
section .text
__ENTRY:
phy_bpb_start:
; try to force encode a short jmp nop: i.e 0xEB 0x5A 0x90
; will jump right 0x5A (90 bytes) after the end of the ebpb
; this could also be encoded as 0xE9 0x?? 0x?? for a near jump
; if init ends up being >= 128 bytes from entry.
jmp short (init - $$)
nop
; fill BPB area with 0x00 since we skip writing this part to disk
; but we need it for the 'jmp short entry; nop' above
times 33 db 0x00
; 8 ascii bytes, "MSWIN 4.1", ""
phy_bs_ident:
times 8 db 0x00
phy_bpb_start:
times 25 db 0x00
phy_ebpb_start:
; fill eBPB area with 0x00 since we skip writing this part to disk
times 54 db 0x00
; ###############
@@ -95,7 +101,7 @@ main:
mov byte [bp - 2], dl ; boot_drive
.check_FAT_size: ; we only support a very specific setup of FAT32
mov bx, phy_bpb_start
test word [bx + FAT32_bpb_t.unused2_ZERO_word], 0 ; TotSectors16 will not be set if FAT32
test word [bx + FAT32_bpb_t.u16_TotalSectors16], 0 ; TotSectors16 will not be set if FAT32
jz main.load_stage2
ERROR VBR_ERROR_WRONG_FAT_SIZE
.load_stage2:
@@ -114,7 +120,7 @@ main:
; 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
call BIOS_int13h_ext_read
add sp, 0xC
.enter_stage2:
mov dl, byte [bp - 2] ; byte boot_drive