819958c6 |
1 | #------------------------------------------------------------------------------\r |
2 | #*\r |
3 | #* Copyright 2006 - 2007, Intel Corporation \r |
4 | #* All rights reserved. This program and the accompanying materials \r |
5 | #* are licensed and made available under the terms and conditions of the BSD License \r |
6 | #* which accompanies this distribution. The full text of the license may be found at \r |
7 | #* http://opensource.org/licenses/bsd-license.php \r |
8 | #* \r |
9 | #* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r |
10 | #* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r |
11 | #* \r |
8141eea5 |
12 | #* bootsect.S\r |
819958c6 |
13 | #* \r |
8141eea5 |
14 | #* bootsect.S is built as 16-bit binary file in 512 bytes and patched to disk/partition's \r |
15 | #* first section - boot sector. \r |
16 | #*\r |
17 | #* The startup sequence for DUET disk boot sector is:\r |
18 | #*\r |
19 | #* 1, LegacyBios check 0xAA55 signature at boot sectore offset 0x1FE to judget \r |
20 | #* whether disk/partition is bootable.\r |
21 | #* 2, LegacyBios will load boot sector to 0x7c00 in real mode, pass BPB data and\r |
22 | #* hand off control to 0x7c00 code.\r |
23 | #* 3, boot sector code simply parse FAT format in boot disk and find EfiLdr binary file \r |
24 | #* and EfiVar.bin if exists. For first boot, EfiVar.bin does not exist.\r |
25 | #* 4, boot sector load the first sector of EfiLdr binary which is start.com to\r |
26 | #* 0x2000:0x0000 address.\r |
27 | #* 5, boot sector handoff control to 0x2000:0x0000 for start.com binary.\r |
819958c6 |
28 | #*\r |
29 | #------------------------------------------------------------------------------\r |
30 | \r |
819958c6 |
31 | .stack: \r |
32 | .486p: \r |
20193e01 |
33 | .code16\r |
819958c6 |
34 | \r |
35 | .equ FAT_DIRECTORY_ENTRY_SIZE, 0x020\r |
36 | .equ FAT_DIRECTORY_ENTRY_SHIFT, 5\r |
37 | .equ BLOCK_SIZE, 0x0200\r |
38 | .equ BLOCK_MASK, 0x01ff\r |
39 | .equ BLOCK_SHIFT, 9\r |
40 | # "EFILDR_____"\r |
41 | .equ LOADER_FILENAME_PART1, 0x04c494645 # "EFIL"\r |
42 | .equ LOADER_FILENAME_PART2, 0x020205244 # "DR__"\r |
43 | .equ LOADER_FILENAME_PART3, 0x020202020 # "____"\r |
44 | \r |
d5172f91 |
45 | .org 0x0\r |
46 | ASM_GLOBAL _start\r |
fd549a4d |
47 | _start:\r |
819958c6 |
48 | Ia32Jump: \r |
49 | jmp BootSectorEntryPoint # JMP inst - 3 bytes\r |
50 | nop\r |
51 | \r |
52 | OemId: .ascii "INTEL " # OemId - 8 bytes\r |
53 | # BPB data below will be fixed by tool\r |
54 | SectorSize: .word 0 # Sector Size - 16 bits\r |
55 | SectorsPerCluster: .byte 0 # Sector Per Cluster - 8 bits\r |
56 | ReservedSectors: .word 0 # Reserved Sectors - 16 bits\r |
57 | NoFats: .byte 0 # Number of FATs - 8 bits\r |
58 | RootEntries: .word 0 # Root Entries - 16 bits\r |
59 | Sectors: .word 0 # Number of Sectors - 16 bits\r |
60 | Media: .byte 0 # Media - 8 bits - ignored\r |
61 | SectorsPerFat: .word 0 # Sectors Per FAT - 16 bits\r |
62 | SectorsPerTrack: .word 0 # Sectors Per Track - 16 bits - ignored\r |
63 | Heads: .word 0 # Heads - 16 bits - ignored\r |
64 | HiddenSectors: .long 0 # Hidden Sectors - 32 bits - ignored\r |
65 | LargeSectors: .long 0 # Large Sectors - 32 bits \r |
66 | PhysicalDrive: .byte 0 # PhysicalDriveNumber - 8 bits - ignored\r |
67 | CurrentHead: .byte 0 # Current Head - 8 bits\r |
68 | Signature: .byte 0 # Signature - 8 bits - ignored\r |
69 | VolId: .ascii " " # Volume Serial Number- 4 bytes\r |
70 | FatLabel: .ascii " " # Label - 11 bytes\r |
71 | SystemId: .ascii "FAT12 " # SystemId - 8 bytes\r |
72 | \r |
73 | BootSectorEntryPoint: \r |
74 | #ASSUME ds:@code\r |
75 | #ASSUME ss:@code\r |
76 | \r |
77 | # ****************************************************************************\r |
78 | # Start Print\r |
79 | # ****************************************************************************\r |
57b6de77 |
80 | movw $StartString, %si\r |
819958c6 |
81 | call PrintString\r |
82 | \r |
83 | # ****************************************************************************\r |
84 | # Print over\r |
85 | # ****************************************************************************\r |
86 | \r |
87 | movw %cs, %ax # ax = 0\r |
88 | movw %ax, %ss # ss = 0\r |
89 | addw $0x1000, %ax\r |
90 | movw %ax, %ds\r |
91 | \r |
92 | movw $0x7c00, %sp # sp = 0x7c00\r |
93 | movw %sp, %bp # bp = 0x7c00\r |
94 | \r |
95 | movb $8, %ah # ah = 8 - Get Drive Parameters Function\r |
96 | movb %dl, PhysicalDrive(%bp) # BBS defines that BIOS would pass the booting driver number to the loader through DL\r |
97 | int $0x13 # Get Drive Parameters\r |
98 | xorw %ax, %ax # ax = 0\r |
99 | movb %dh, %al # al = dh\r |
100 | incb %al # MaxHead = al + 1\r |
101 | pushw %ax # 0000:7bfe = MaxHead\r |
102 | movb %cl, %al # al = cl\r |
103 | andb $0x3f, %al # MaxSector = al & 0x3f\r |
104 | pushw %ax # 0000:7bfc = MaxSector\r |
105 | \r |
106 | cmpw $0xaa55, SectorSignature(%bp) # Verify Boot Sector Signature\r |
107 | jne BadBootSector\r |
108 | movw RootEntries(%bp), %cx # cx = RootEntries\r |
109 | shlw $FAT_DIRECTORY_ENTRY_SHIFT, %cx # cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes\r |
110 | movw %cx, %bx # bx = size of the Root Directory in bytes\r |
111 | andw $BLOCK_MASK, %bx # See if it is an even number of sectors long\r |
112 | jne BadBootSector # If is isn't, then the boot sector is bad.\r |
113 | movw %cx, %bx # bx = size of the Root Directory in bytes\r |
114 | shrw $BLOCK_SHIFT, %bx # bx = size of Root Directory in sectors\r |
115 | movb NoFats(%bp), %al # al = NoFats\r |
116 | xorb %ah, %ah # ah = 0 ==> ax = NoFats\r |
117 | mulw SectorsPerFat(%bp) # ax = NoFats * SectorsPerFat\r |
118 | addw ReservedSectors(%bp), %ax # ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA\r |
119 | pushw %ds\r |
120 | popw %es\r |
121 | xorw %di, %di # Store directory in es:di = 1000:0000\r |
122 | call ReadBlocks # Read entire Root Directory\r |
123 | addw %bx, %ax # ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA (FirstDataSector)\r |
124 | movw %ax, (%bp) # Save FirstClusterLBA (FirstDataSector) for later use\r |
125 | \r |
126 | # dx - variable storage (initial value is 0)\r |
127 | # bx - loader (initial value is 0)\r |
128 | xorw %dx, %dx\r |
129 | xorw %bx, %bx\r |
130 | \r |
131 | FindEFILDR: \r |
132 | cmpl $LOADER_FILENAME_PART1, (%di) # Compare to "EFIL"\r |
133 | jne FindVARSTORE\r |
134 | cmpl $LOADER_FILENAME_PART2, 4(%di) \r |
135 | jne FindVARSTORE\r |
136 | cmpl $LOADER_FILENAME_PART3, 7(%di) \r |
137 | jne FindVARSTORE\r |
138 | movw 26(%di), %bx # bx = Start Cluster for EFILDR <----------------------------------\r |
139 | testw %dx, %dx\r |
140 | je FindNext # Efivar.bin is not loaded\r |
141 | jmp FoundAll\r |
142 | \r |
143 | FindVARSTORE: \r |
144 | ## if the file is not loader file, see if it's "EFIVAR BIN"\r |
145 | cmpl $0x56494645, (%di) # Compare to "EFIV"\r |
146 | jne FindNext\r |
147 | cmpl $0x20205241, 4(%di) # Compare to "AR "\r |
148 | jne FindNext\r |
149 | cmpl $0x4e494220, 7(%di) # Compare to " BIN"\r |
150 | jne FindNext\r |
151 | movw %di, %dx # dx = Offset of Start Cluster for Efivar.bin <---------------------\r |
152 | addw $26, %dx\r |
153 | testw %bx, %bx\r |
154 | je FindNext # Efildr is not loaded\r |
155 | jmp FoundAll\r |
156 | \r |
157 | FindNext: \r |
158 | # go to next find\r |
159 | addw $FAT_DIRECTORY_ENTRY_SIZE, %di # Increment di\r |
160 | subw $FAT_DIRECTORY_ENTRY_SIZE, %cx # Decrement cx\r |
161 | # TODO: jump to FindVarStore if ...\r |
162 | jne FindEFILDR\r |
163 | jmp NotFoundAll\r |
164 | \r |
165 | FoundAll: \r |
166 | FoundEFILDR: \r |
167 | movw %bx, %cx # cx = Start Cluster for EFILDR <----------------------------------\r |
168 | movw %cs, %ax # Destination = 2000:0000\r |
169 | addw $0x2000, %ax\r |
170 | movw %ax, %es\r |
171 | xorw %di, %di\r |
172 | ReadFirstClusterOfEFILDR: \r |
173 | movw %cx, %ax # ax = StartCluster\r |
174 | subw $2, %ax # ax = StartCluster - 2\r |
175 | xorb %bh, %bh\r |
176 | movb SectorsPerCluster(%bp), %bl # bx = SectorsPerCluster\r |
177 | pushw %dx\r |
178 | mulw %bx\r |
179 | popw %dx # ax = (StartCluster - 2) * SectorsPerCluster\r |
180 | addw (%bp), %ax # ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster\r |
181 | xorb %bh, %bh\r |
182 | movb SectorsPerCluster(%bp), %bl # bx = Number of Sectors in a cluster\r |
183 | pushw %es\r |
184 | call ReadBlocks\r |
185 | popw %ax\r |
186 | JumpIntoFirstSectorOfEFILDR: \r |
187 | movw %ax, JumpSegment(%bp)\r |
188 | JumpFarInstruction: \r |
189 | .byte 0xea\r |
190 | JumpOffset: \r |
191 | .word 0x000\r |
192 | JumpSegment: \r |
193 | .word 0x2000\r |
194 | \r |
195 | \r |
196 | PrintString: \r |
197 | movw $0xb800, %ax\r |
198 | movw %ax, %es\r |
199 | movw $0x7c0, %ax\r |
200 | movw %ax, %ds\r |
201 | movw $7, %cx\r |
202 | movw $160, %di\r |
203 | rep\r |
204 | movsw\r |
205 | ret\r |
206 | # ****************************************************************************\r |
207 | # ReadBlocks - Reads a set of blocks from a block device\r |
208 | #\r |
209 | # AX = Start LBA\r |
210 | # BX = Number of Blocks to Read\r |
211 | # ES:DI = Buffer to store sectors read from disk\r |
212 | # ****************************************************************************\r |
213 | \r |
214 | # cx = Blocks\r |
215 | # bx = NumberOfBlocks\r |
216 | # si = StartLBA\r |
217 | \r |
218 | ReadBlocks: \r |
219 | pusha\r |
220 | addl LBAOffsetForBootSector(%bp), %eax # Add LBAOffsetForBootSector to Start LBA\r |
221 | addl HiddenSectors(%bp), %eax # Add HiddenSectors to Start LBA\r |
222 | movl %eax, %esi # esi = Start LBA\r |
223 | movw %bx, %cx # cx = Number of blocks to read\r |
224 | ReadCylinderLoop: \r |
225 | movw $0x7bfc, %bp # bp = 0x7bfc\r |
226 | movl %esi, %eax # eax = Start LBA\r |
227 | xorl %edx, %edx # edx = 0\r |
228 | movzwl (%bp), %ebx # bx = MaxSector\r |
229 | divl %ebx # ax = StartLBA / MaxSector\r |
230 | incw %dx # dx = (StartLBA % MaxSector) + 1\r |
231 | subw %dx, %bx # bx = MaxSector - Sector\r |
232 | incw %bx # bx = MaxSector - Sector + 1\r |
233 | cmpw %bx, %cx # Compare (Blocks) to (MaxSector - Sector + 1)\r |
234 | jg LimitTransfer\r |
235 | movw %cx, %bx # bx = Blocks\r |
236 | LimitTransfer: \r |
237 | pushw %cx\r |
238 | movb %dl, %cl # cl = (StartLBA % MaxSector) + 1 = Sector\r |
239 | xorw %dx, %dx # dx = 0\r |
240 | divw 2(%bp) # ax = ax / (MaxHead + 1) = Cylinder \r |
241 | # dx = ax % (MaxHead + 1) = Head\r |
242 | \r |
243 | pushw %bx # Save number of blocks to transfer\r |
244 | movb %dl, %dh # dh = Head\r |
245 | movw $0x7c00, %bp # bp = 0x7c00\r |
246 | movb PhysicalDrive(%bp), %dl # dl = Drive Number\r |
247 | movb %al, %ch # ch = Cylinder\r |
248 | movb %bl, %al # al = Blocks\r |
249 | movb $2, %ah # ah = Function 2\r |
250 | movw %di, %bx # es:bx = Buffer address\r |
251 | int $0x13\r |
252 | jc DiskError\r |
253 | popw %bx\r |
254 | popw %cx\r |
255 | movzwl %bx, %ebx\r |
256 | addl %ebx, %esi # StartLBA = StartLBA + NumberOfBlocks\r |
257 | subw %bx, %cx # Blocks = Blocks - NumberOfBlocks\r |
258 | movw %es, %ax\r |
259 | shlw $(BLOCK_SHIFT-4), %bx\r |
260 | addw %bx, %ax\r |
261 | movw %ax, %es # es:di = es:di + NumberOfBlocks*BLOCK_SIZE\r |
262 | cmpw $0, %cx\r |
263 | jne ReadCylinderLoop\r |
264 | popa\r |
265 | ret\r |
266 | \r |
267 | # ****************************************************************************\r |
268 | # ERROR Condition:\r |
269 | # ****************************************************************************\r |
270 | NotFoundAll: \r |
271 | ## if we found EFILDR, continue\r |
272 | testw %bx, %bx\r |
273 | jne FoundEFILDR\r |
274 | BadBootSector: \r |
275 | DiskError: \r |
57b6de77 |
276 | movw $ErrorString, %si\r |
819958c6 |
277 | call PrintString\r |
278 | Halt: \r |
279 | jmp Halt\r |
280 | \r |
281 | StartString: \r |
282 | .byte 'B', 0x0c, 'S', 0x0c, 't', 0x0c, 'a', 0x0c, 'r', 0x0c, 't', 0x0c, '!', 0x0c\r |
283 | ErrorString: \r |
284 | .byte 'B', 0x0c, 'E', 0x0c, 'r', 0x0c, 'r', 0x0c, 'o', 0x0c, 'r', 0x0c, '!', 0x0c\r |
285 | \r |
286 | # ****************************************************************************\r |
287 | # LBA Offset for BootSector, need patched by tool for HD boot.\r |
288 | # ****************************************************************************\r |
289 | \r |
20193e01 |
290 | .org 0x01fa # Comment it for pass build. Should optimise code size. \r |
819958c6 |
291 | LBAOffsetForBootSector: \r |
292 | .long 0x0\r |
293 | \r |
294 | # ****************************************************************************\r |
295 | # Sector Signature\r |
296 | # ****************************************************************************\r |
297 | \r |
20193e01 |
298 | .org 0x01fe # Comment it for pass build.\r |
819958c6 |
299 | SectorSignature: \r |
300 | .word 0xaa55 # Boot Sector Signature\r |
301 | \r |
302 | \r |
303 | \r |