1- // fathelp.S
2- // FAT12/ 16 Boot Sector Helper Code
3- // Copyright (c) 1998 , 2001 , 2002 , 2003 Brian Palmer
1+ / *
2+ * PROJECT: FreeLoader
3+ * LICENSE: GPL - 2 . 0 - or - later (https://spdx.org/licenses/GPL - 2 . 0 - or - later)
4+ * PURPOSE: FAT12/ 16 Boot Sector Helper Code
5+ * COPYRIGHT: Copyright 1998 - 2003 Brian Palmer ([email protected] ) 6+ * Copyright 2019 Dmitry Borisov ( di [email protected] )7+ * Copyright 2022 Hermès Bélusca - Maïto
8+ * /
49
510//#include <asm. inc >
611
@@ -67,12 +72,10 @@ FatHelperEntryPoint:
6772 mov si , offset msgLoading
6873 call word ptr [ bp - PutCharsOffset ]
6974
70- call ReadFatIntoMemory
71-
7275 / * Restore AX (start cluster) * /
7376 pop ax
77+ xor dx , dx
7478
75- // AX has start cluster of freeldr.sys
7679 mov bx , FREELDR_BASE / 16
7780 mov es , bx
7881
@@ -94,8 +97,7 @@ LoadFile3:
9497 call word ptr [ bp - ReadClusterOffset ]
9598 pop es
9699
97- xor bx , bx
98- mov bl , [ bp + SectsPerCluster ]
100+ movzx bx , byte ptr [ bp + SectsPerCluster ]
99101 shl bx , 5 // BX = BX * 512 / 16
100102 mov ax , es // Increment the load address by
101103 add ax , bx // The size of a cluster
@@ -122,33 +124,37 @@ LoadFile_Done:
122124 jmp start
123125
124126
125- // Reads the entire F AT into memory at 7000 : 0000
126- ReadFatIntoMemory:
127- mov ax , [ bp + HiddenSectors ]
128- mov dx , [ bp + HiddenSectors + 2 ]
129- add ax , [ bp + ReservedSectors ]
130- adc dx , 0
131- mov cx , [ bp + SectorsPerF at ]
132- mov bx , HEX( 7000 )
133- mov es , bx
134- xor bx , bx
135- call word ptr [ bp - ReadSectorsOffset ]
136- ret
137-
138-
139127// Returns the F AT entry for a given cluster number for 16 - bit F AT
140- // On entry AX has cluster number
128+ // On entry DX : AX has cluster number
141129// On return AX has F AT entry for th at cluster
142130GetFatEntry16:
143- mov cx , 2 // AX = AX * 2 (since FAT16 entries are 2 bytes)
144- mul cx
145- shl dx , 12
131+ // NOTE: Do the DX : AX arithmetics via EAX instead.
132+ xchg ax , dx
133+ shl eax , 16 // HIWORD( EAX ) = old DX
134+ mov ax , dx // LOWORD( EAX ) = DX == old AX .
135+ shl ax , 1 // AX = AX * 2 (since FAT16 entries are 2 bytes)
136+ mov cx , ax // Save this for later in CX
137+
138+ xor edx , edx // Dividend
139+ movzx ebx , word ptr [ bp + BytesPerSector ] // F AT Sector Number = original AX / BytesPerSector
140+ div ebx
141+
142+ // Now reconstruct DX : AX from EAX
143+ mov dx , ax
144+ shr eax , 16
145+ xchg dx , ax
146+
147+ add ax , word ptr [ bp + HiddenSectors ] // F AT Sector Number + = HiddenSectors
148+ adc dx , word ptr [ bp + HiddenSectors + 2 ]
149+ add ax , word ptr [ bp + ReservedSectors ] // F AT Sector Number + = ReservedSectors
150+ adc dx , 0
151+
152+ dec bx
153+ and cx , bx // F AT Offset Within Sector = CX % BytesPerSector
154+ // DX : AX holds logical F AT sector number
155+ // CX holds F AT entry offset
146156
147- mov bx , HEX( 7000 )
148- add bx , dx
149- mov es , bx
150- mov bx , ax // Restore F AT entry offset
151- mov ax , es : [ bx ] // Get F AT entry
157+ call LoadFatSector // Get F AT entry in AX
152158
153159 ret
154160
@@ -161,11 +167,25 @@ GetFatEntry12:
161167 mov cx , ax
162168 shr ax , 1
163169 add ax , cx // AX = AX * 1 . 5 ( AX = AX + ( AX / 2 )) , since FAT12 entries are 12 bits
170+ mov cx , ax // Save this for later in CX
171+
172+ xor dx , dx // Dividend
173+ mov bx , word ptr [ bp + BytesPerSector ] // F AT Sector Number = original AX / BytesPerSector
174+ div bx
175+
176+ xor dx , dx
177+ add ax , word ptr [ bp + HiddenSectors ] // F AT Sector Number + = HiddenSectors
178+ adc dx , word ptr [ bp + HiddenSectors + 2 ]
179+ add ax , word ptr [ bp + ReservedSectors ] // F AT Sector Number + = ReservedSectors
180+ adc dx , 0
181+
182+ dec bx
183+ and cx , bx // F AT Offset Within Sector = CX % BytesPerSector
184+ // DX : AX holds logical F AT sector number
185+ // CX holds F AT entry offset
186+
187+ call LoadFatSector // Get F AT entry in AX
164188
165- mov bx , HEX( 7000 )
166- mov es , bx
167- mov bx , ax // Put F AT entry offset into BX
168- mov ax , es : [ bx ] // Get F AT entry
169189 pop cx // Get cluster number from stack
170190 and cx , 1
171191 jz UseLow12Bits
@@ -177,9 +197,54 @@ UseLow12Bits:
177197 and ax , HEX(0fff)
178198
179199GetFatEntry12_Done:
200+ ret
201+
202+
203+ / *
204+ * This code is directly adapted from fat32.S
205+ * BUT: Use DX : AX instead of EAX for the F AT logical sector number.
206+ * CX : F AT entry offset.
207+ * /
208+ LoadFatSector:
209+ push cx // Save F AT entry offset
180210
211+ //
212+ // FIXME: Why loading the sectors at 7000h do fail?
213+ // In the meantime , do as with FAT32 and load the sectors
214+ // at 9000h instead ; this seems to work fine...
215+ //
216+ mov bx , HEX( 9000 ) // We will load it to [ 9000 : 0000h ]
217+ mov es , bx
218+
219+ // DX : AX holds logical F AT sector number
220+ // Check if we have already loaded it
221+ cmp ax , word ptr [ bp + FatSectorInCache ]
222+ jne DoLoad
223+ cmp dx , word ptr [ bp + FatSectorInCache + 2 ]
224+ je LoadFatSectorAlreadyLoaded
225+
226+ DoLoad:
227+ mov word ptr [ bp + FatSectorInCache ], ax
228+ mov word ptr [ bp + FatSectorInCache + 2 ], dx
229+ xor bx , bx
230+ // Read 2 consecutive sectors , so th at , in FAT12 , entry data
231+ // th at may cross sector boundaries , can be correctly read.
232+ // This is not needed in FAT16 and FAT32 where entry data is
233+ // aligned on word boundaries.
234+ mov cx , 2 // mov cx , word ptr [ bp + SectorsPerF at ]
235+
236+ push es // The FAT12/ 16 bootsector ReadSectors destroys ES .
237+ call word ptr [ bp - ReadSectorsOffset ]
238+ pop es
239+
240+ LoadFatSectorAlreadyLoaded:
241+ pop bx // Put F AT entry offset (originally in CX ) into BX
242+ mov ax , word ptr es : [ bx ] // Get F AT entry
181243 ret
182244
245+ FatSectorInCache: // This variable tells us which sector we currently have in memory
246+ .long HEX(0ffffffff) // There is no need to re - read the same sector if we don't have to
247+
183248
184249// Returns CF = 1 if this is a FAT12 file system
185250// Otherwise CF = 0 for FAT16
@@ -189,8 +254,7 @@ IsFat12:
189254 // starting from the beginning of the disk , so subtract hidden sectors
190255 sub ebx , dword ptr [ bp + HiddenSectors ]
191256
192- xor eax , eax
193- mov ax , word ptr [ bp + TotalSectors ]
257+ movzx eax , word ptr [ bp + TotalSectors ]
194258 cmp ax , 0
195259 jnz IsFat12_2
196260 mov eax , dword ptr [ bp + TotalSectorsBig ]
0 commit comments