Sync with trunk (48237)
[reactos.git] / boot / freeldr / freeldr / arch / i386 / fathelp.asm
1 ; FATHELP.ASM
2 ; FAT12/16 Boot Sector Helper Code
3 ; Copyright (c) 1998, 2001, 2002, 2003 Brian Palmer
4
5
6
7 ;org 8000h
8
9 segment .text
10
11 bits 16
12
13
14 BootSectorStackTop equ 0x7bf2
15 DataAreaStartHigh equ 0x2
16 DataAreaStartLow equ 0x4
17 BiosCHSDriveSizeHigh equ 0x6
18 BiosCHSDriveSizeLow equ 0x8
19 BiosCHSDriveSize equ 0x8
20 ReadSectorsOffset equ 0xa
21 ReadClusterOffset equ 0xc
22 PutCharsOffset equ 0xe
23
24 OEMName equ 3
25 BytesPerSector equ 11
26 SectsPerCluster equ 13
27 ReservedSectors equ 14
28 NumberOfFats equ 16
29 MaxRootEntries equ 17
30 TotalSectors equ 19
31 MediaDescriptor equ 21
32 SectorsPerFat equ 22
33 SectorsPerTrack equ 24
34 NumberOfHeads equ 26
35 HiddenSectors equ 28
36 TotalSectorsBig equ 32
37 BootDrive equ 36
38 Reserved equ 37
39 ExtendSig equ 38
40 SerialNumber equ 39
41 VolumeLabel equ 43
42 FileSystem equ 54
43
44 BootPartition equ 0x7dfd
45
46
47 ; This code will be stored in the first 512 bytes
48 ; of freeldr.sys. The first 3 bytes will be a jmp
49 ; instruction to skip past the FAT helper code
50 ; that is stored in the rest of the 512 bytes.
51 ;
52 ; This code is loaded at 0000:8000 so we have to
53 ; encode a jmp instruction to jump to 0000:8200
54
55 global _mainCRTStartup ; For Mingw32 builds where the linker looks for this symbol
56 _mainCRTStartup:
57 global start
58 start:
59 db 0xe9
60 db 0xfd
61 db 0x01
62
63 ; Now starts the extra boot code that we will store
64 ; in the first 512 bytes of freeldr.sys. This code
65 ; allows the FAT12/16 bootsector to navigate the
66 ; FAT table so that we can still load freeldr.sys
67 ; even if it is fragmented.
68
69
70 FatHelperEntryPoint:
71
72 push ax ; First save AX - the start cluster of freeldr.sys
73
74
75 ; Display "Loading FreeLoader..." message
76 mov esi,msgLoading ; Loading message
77 call [bp-PutCharsOffset] ; Display it
78
79
80 call ReadFatIntoMemory
81
82 pop ax ; Restore AX (start cluster)
83 ; AX has start cluster of freeldr.sys
84
85 mov bx,800h
86 mov es,bx
87
88 LoadFile:
89 push ax
90 call IsFat12
91 pop ax
92 jnc LoadFile2
93 cmp ax,0ff8h ; Check to see if this is the last cluster in the chain
94 jmp LoadFile3
95 LoadFile2:
96 cmp ax,0fff8h
97 LoadFile3:
98 jae LoadFile_Done ; If so continue, if not then read then next one
99 push ax
100 xor bx,bx ; Load ROSLDR starting at 0000:8000h
101 push es
102 call [bp-ReadClusterOffset]
103 pop es
104
105 xor bx,bx
106 mov bl,BYTE [BYTE bp+SectsPerCluster]
107 shl bx,5 ; BX = BX * 512 / 16
108 mov ax,es ; Increment the load address by
109 add ax,bx ; The size of a cluster
110 mov es,ax
111
112 call IsFat12
113 pop ax
114 push es
115 jnc LoadFile4
116 call GetFatEntry12 ; Get the next entry
117 jmp LoadFile5
118 LoadFile4:
119 call GetFatEntry16
120 LoadFile5:
121 pop es
122
123 jmp LoadFile ; Load the next cluster (if any)
124
125 LoadFile_Done:
126 mov dl,BYTE [BYTE bp+BootDrive] ; Load the boot drive into DL
127 mov dh,[BootPartition] ; Load the boot partition into DH
128
129 push 0 ; push segment (0x0000)
130 mov bx, [0x8000 + 0xA8] ; load the RVA of the EntryPoint into eax
131 add bx, 0x8000 ; RVA -> VA and skip 3 bytes (jump to fathelper code)
132 push bx ; push offset
133 retf ; Transfer control to FreeLoader
134
135 ; Reads the entire FAT into memory at 7000:0000
136 ReadFatIntoMemory:
137 mov ax,WORD [BYTE bp+HiddenSectors]
138 mov dx,WORD [BYTE bp+HiddenSectors+2]
139 add ax,WORD [BYTE bp+ReservedSectors]
140 adc dx,byte 0
141 mov cx,WORD [BYTE bp+SectorsPerFat]
142 mov bx,7000h
143 mov es,bx
144 xor bx,bx
145 call [bp-ReadSectorsOffset]
146 ret
147
148
149 ; Returns the FAT entry for a given cluster number for 16-bit FAT
150 ; On entry AX has cluster number
151 ; On return AX has FAT entry for that cluster
152 GetFatEntry16:
153
154 mov cx,2 ; AX = AX * 2 (since FAT16 entries are 2 bytes)
155 mul cx
156 shl dx,12
157
158 mov bx,7000h
159 add bx,dx
160 mov es,bx
161 mov bx,ax ; Restore FAT entry offset
162 mov ax,WORD [es:bx] ; Get FAT entry
163
164 ret
165
166
167 ; Returns the FAT entry for a given cluster number for 12-bit FAT
168 ; On entry AX has cluster number
169 ; On return AX has FAT entry for that cluster
170 GetFatEntry12:
171
172 push ax
173 mov cx,ax
174 shr ax,1
175 add ax,cx ; AX = AX * 1.5 (AX = AX + (AX / 2)) (since FAT12 entries are 12 bits)
176
177 mov bx,7000h
178 mov es,bx
179 mov bx,ax ; Put FAT entry offset into BX
180 mov ax,WORD [es:bx] ; Get FAT entry
181 pop cx ; Get cluster number from stack
182 and cx,1
183 jz UseLow12Bits
184 and ax,0fff0h
185 shr ax,4
186 jmp GetFatEntry12_Done
187
188 UseLow12Bits:
189 and ax,0fffh
190
191 GetFatEntry12_Done:
192
193 ret
194
195
196 ; Returns CF = 1 if this is a FAT12 file system
197 ; Otherwise CF = 0 for FAT16
198 IsFat12:
199
200 mov ebx,DWORD [BYTE bp-DataAreaStartLow]
201 ; EBX now has the number of the starting sector of the data area
202 ; starting from the beginning of the disk, so subtrace hidden sectors
203 sub ebx,DWORD [BYTE bp+HiddenSectors]
204
205
206 xor eax,eax
207 mov ax,WORD [BYTE bp+TotalSectors]
208 cmp ax,byte 0
209 jnz IsFat12_2
210 mov eax,DWORD [BYTE bp+TotalSectorsBig]
211
212 ; EAX now contains the number of sectors on the volume
213
214 IsFat12_2:
215 sub eax,ebx ; Subtract data area start sector
216 xor edx,edx ; from total sectors of volume
217
218 ; EDX:EAX now contains the number of data sectors on the volume
219 movzx ebx,BYTE [BYTE bp+SectsPerCluster]
220 div ebx
221 ; EAX now has the number of clusters on the volume
222 stc
223 cmp eax,4085
224 jb IsFat12_Done
225 clc
226
227 IsFat12_Done:
228 ret
229
230
231
232 msgLoading db 'Loading FreeLoader...',0dh,0ah,0
233
234 times 510-($-$$) db 0 ; Pad to 510 bytes
235 dw 0aa55h ; BootSector signature