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