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