]> git.dujemihanovic.xyz Git - nameless-os.git/blob - boot/x86/fat32/fat32.s
Separate loading clusters and cluster chains
[nameless-os.git] / boot / x86 / fat32 / fat32.s
1 ; FAT32 driver
2 ; BOOT_DRIVE, si and bp must be set up by the code using this driver.
3 ; (Specifically, si must be a pointer to the partition's partition
4 ; table entry and bp must be a pointer to the BPB.)
5 ; Before reading any cluster chains, callers must call get_1st_data_sec
6 ; and must be careful not to trash ecx after calling it.
7
8 ; eax - start cluster number
9 ; es:di - where to load the cluster chain
10 ; RETURN: CF set = error
11 ; NOTE: Cluster chain might be the root directory or a file.
12 read_cluster_chain:
13 push eax
14 push es
15 push di
16 .loop:
17 call read_cluster
18 jc .done
19 cmp eax, 0xffffff7
20 jl .loop
21 .done:
22 pop di
23 pop es
24 pop eax
25 ret
26
27 ; eax - cluster number
28 ; es:di - where to load the cluster (incremented automatically)
29 ; RETURN: eax - next cluster number
30 ; CF set = error
31 read_cluster:
32 push ebx
33 push ecx
34 push edx
35 .loop:
36 ; get the first sector of the cluster to read
37 push eax
38 sub eax, 2
39 xor ebx, ebx
40 mov bl, BPB_SecPerClus
41 mul ebx
42 add eax, ecx
43 mov ebx, eax
44 pop eax
45
46 ; read the cluster
47 push cx
48 movzx cx, BPB_SecPerClus
49 call read_sectors
50 pop cx
51 cmp dl, 0
52 je .error
53
54 ; increment the load offset (and segment if needed)
55 push eax
56 xor eax, eax
57 movzx ax, BPB_SecPerClus
58 mul word BPB_BytsPerSec
59 add di, ax
60 jno .get_next_cluster
61 mov ax, es
62 add ax, 0x1000
63 mov es, ax
64
65 .get_next_cluster:
66 pop eax
67 ; get FAT sector number and offset containing the next cluster number
68 xor ebx, ebx
69 mov bl, 4 ; put 4 in EBX, doing this instead of "mov ebx, 4" saves us an entire byte
70 mul ebx
71 movzx ebx, word BPB_BytsPerSec
72 div ebx
73 movzx ebx, word BPB_RsvdSecCnt
74 add eax, ebx
75 add eax, [si]
76 mov ebx, edx
77 ; reminder for myself: EAX is FAT sector number, (E)BX is offset into FAT sector
78
79 ; load the FAT sector we're looking for
80 push di
81 push ebx ; offset
82 push es ; we want to read at 0:1000, not STAGE3_SEGMENT:1000
83 push eax ; desired LBA
84 xor ax, ax
85 mov es, ax
86 pop ebx ; pop LBA into EBX
87 mov di, 0x6000
88 mov cx, 1
89 call read_sectors
90 cmp dl, 0
91 ; find the cluster we're looking for
92 pop es ; restore STAGE3_SEGMENT
93 pop ebx ; pop FAT offset back into EBX for cmp
94 mov eax, [di+bx]
95 pop di
96 jne .end
97 ; cleanup and return
98 .error:
99 stc
100 .end:
101 pop edx
102 pop ecx
103 pop ebx
104 ret
105
106 ; es:di - where to load the sector(s)
107 ; ebx - start LBA address
108 ; cx - how many sectors to read
109 ; RETURN: DL=0 means error
110 read_sectors:
111 clc
112 push ax
113 push si
114 mov ah, 0x42
115 push dword 0
116 push dword ebx
117 push es
118 push di
119 push cx
120 push word 0x10
121 mov si, sp
122 mov dl, [BOOT_DRIVE]
123 int 0x13
124 mov dl, 1
125 jnc .done
126 mov dl, 0
127 .done:
128 add sp, 16
129 pop si
130 pop ax
131 ret
132
133 ; ds:si - pointer to partition table entry
134 ; RETURN: ecx - first data sector
135 get_1st_data_sec:
136 push eax
137 push ebx
138 movzx ax, BPB_NumFats
139 mul dword BPB_FatSz32 ; space occupied by all FATs
140 movzx ebx, word BPB_RsvdSecCnt
141 add eax, ebx ; space occupied by the reserved area
142 add eax, [si] ; space before the partition
143 mov ecx, eax
144 pop ebx
145 pop eax
146 ret
147
148 read_error: db "Read error", 0
149
150 BOOT_DRIVE: db 0