; FAT32 driver ; BOOT_DRIVE, part_table_entry and bp must be set up by the code using this driver. ; first_data_sec is to be set up by calling get_1st_data_sec. ; eax - start cluster number ; es:di - where to load the cluster chain ; NOTE: Cluster chain might be the root directory or a file. read_cluster_chain: pusha .loop: ; get the first sector of the cluster to read push eax sub eax, 2 xor ebx, ebx mov bl, BPB_SecPerClus mul ebx add eax, [first_data_sec] mov ebx, eax pop eax ; read the cluster movzx cx, BPB_SecPerClus call read_sectors ; increment the load offset (and segment if needed) push eax xor eax, eax movzx ax, BPB_SecPerClus mul word BPB_BytsPerSec add di, ax jno .get_next_cluster mov ax, es add ax, 0x1000 mov es, ax .get_next_cluster: pop eax ; get FAT sector number and offset containing the next cluster number xor edx, edx mov ebx, 4 mul dword ebx movzx ebx, word BPB_BytsPerSec div dword ebx movzx ebx, word BPB_RsvdSecCnt add eax, ebx push bp mov bp, [part_table_entry] add eax, [bp+part_entry.lba_start] pop bp mov ebx, edx ; reminder for myself: EAX is FAT sector number, (E)BX is offset into FAT sector ; load the FAT sector we're looking for push ebx ; offset push es ; we want to read at 0:1000, not STAGE3_SEGMENT:1000 push eax ; desired LBA xor ax, ax mov es, ax pop ebx ; pop LBA into EBX mov di, 0x1000 mov cx, 1 call read_sectors ; find the cluster we're looking for pop es ; restore STAGE3_SEGMENT pop ebx ; pop FAT offset back into EBX for cmp cmp dword [di+bx], 0xffffff7 jge .done ; if cluster number is greater than or equal to the defective cluster value, we're done ; TODO: should this perhaps be changed so that equal makes it error out? ; otherwise, load the next sector number in eax and read again mov eax, [di+bx] jmp .loop .done: ; cleanup and return popa ret ; es:di - where to load the sector(s) ; ebx - start LBA address ; cx - how many sectors to read read_sectors: pusha mov ah, 0x42 push dword 0 push dword ebx push es push di push cx push word 0x10 mov si, sp mov dl, [BOOT_DRIVE] int 0x13 jc .error add sp, 16 popa ret .error: mov si, read_error call print hlt jmp $-1 ; no arguments get_1st_data_sec: push eax push ebx xor eax, eax movzx ax, BPB_NumFats mul dword BPB_FatSz32 ; space occupied by all FATs movzx ebx, word BPB_RsvdSecCnt add eax, ebx ; space occupied by the reserved area mov bx, [part_table_entry] add eax, [bx+part_entry.lba_start] ; space before the partition mov [first_data_sec], eax pop ebx pop eax ret read_error: db "Read error", 0 BOOT_DRIVE: db 0 part_table_entry: dw 0 first_data_sec: dd 0