Skip to content

Commit 11cd52f

Browse files
HBeluscabinarymaster
authored andcommitted
** WIP ** [FREELDR] Don't load a full FAT12/16 table when loading FREELDR.SYS.
CORE-15427, CORE-14558, CORE-16195, CORE-13740 Supersedes PR reactos#2182 At least the way we currently do it and have our data layed out in memory. Otherwise we risk corrupting either the FAT-loading code, or the contents of FREELDR.SYS being loaded, when said FAT table is quite large.
1 parent 7fc8496 commit 11cd52f

File tree

1 file changed

+101
-37
lines changed

1 file changed

+101
-37
lines changed

boot/freeldr/freeldr/arch/realmode/fathelp.inc

Lines changed: 101 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
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 FAT 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+SectorsPerFat]
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 FAT entry for a given cluster number for 16-bit FAT
140-
// On entry AX has cluster number
128+
// On entry DX:AX has cluster number
141129
// On return AX has FAT entry for that cluster
142130
GetFatEntry16:
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] // FAT 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] // FAT Sector Number += HiddenSectors
148+
adc dx, word ptr [bp+HiddenSectors+2]
149+
add ax, word ptr [bp+ReservedSectors] // FAT Sector Number += ReservedSectors
150+
adc dx, 0
151+
152+
dec bx
153+
and cx, bx // FAT Offset Within Sector = CX % BytesPerSector
154+
// DX:AX holds logical FAT sector number
155+
// CX holds FAT entry offset
146156

147-
mov bx, HEX(7000)
148-
add bx,dx
149-
mov es,bx
150-
mov bx,ax // Restore FAT entry offset
151-
mov ax, es:[bx] // Get FAT entry
157+
call LoadFatSector // Get FAT 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] // FAT Sector Number = original AX / BytesPerSector
174+
div bx
175+
176+
xor dx, dx
177+
add ax, word ptr [bp+HiddenSectors] // FAT Sector Number += HiddenSectors
178+
adc dx, word ptr [bp+HiddenSectors+2]
179+
add ax, word ptr [bp+ReservedSectors] // FAT Sector Number += ReservedSectors
180+
adc dx, 0
181+
182+
dec bx
183+
and cx, bx // FAT Offset Within Sector = CX % BytesPerSector
184+
// DX:AX holds logical FAT sector number
185+
// CX holds FAT entry offset
186+
187+
call LoadFatSector // Get FAT entry in AX
164188

165-
mov bx, HEX(7000)
166-
mov es,bx
167-
mov bx,ax // Put FAT entry offset into BX
168-
mov ax, es:[bx] // Get FAT 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

179199
GetFatEntry12_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 FAT logical sector number.
206+
* CX: FAT entry offset.
207+
*/
208+
LoadFatSector:
209+
push cx // Save FAT 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 FAT 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 that, in FAT12, entry data
231+
// that 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+SectorsPerFat]
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 FAT entry offset (originally in CX) into BX
242+
mov ax, word ptr es:[bx] // Get FAT 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

Comments
 (0)