]>
Commit | Line | Data |
---|---|---|
819958c6 | 1 | #------------------------------------------------------------------------------\r |
2 | #*\r | |
b1f700a8 HT |
3 | #* Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>\r |
4 | #* This program and the accompanying materials \r | |
819958c6 | 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 |
ae3d1e91 | 46 | .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 | |
b29a823d | 132 | cmpl $LOADER_FILENAME_PART1, (%di) # Compare to "EFIL"\r |
819958c6 | 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 |