1 #------------------------------------------------------------------------------
\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
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
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
17 #* The startup sequence for DUET disk boot sector is:
\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
29 #------------------------------------------------------------------------------
\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
41 .equ LOADER_FILENAME_PART1, 0x04c494645 # "EFIL"
\r
42 .equ LOADER_FILENAME_PART2, 0x020205244 # "DR__"
\r
43 .equ LOADER_FILENAME_PART3, 0x020202020 # "____"
\r
49 jmp BootSectorEntryPoint # JMP inst - 3 bytes
\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
73 BootSectorEntryPoint:
\r
77 # ****************************************************************************
\r
79 # ****************************************************************************
\r
80 movw $StartString, %si
\r
83 # ****************************************************************************
\r
85 # ****************************************************************************
\r
87 movw %cs, %ax # ax = 0
\r
88 movw %ax, %ss # ss = 0
\r
92 movw $0x7c00, %sp # sp = 0x7c00
\r
93 movw %sp, %bp # bp = 0x7c00
\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
106 cmpw $0xaa55, SectorSignature(%bp) # Verify Boot Sector Signature
\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
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
126 # dx - variable storage (initial value is 0)
\r
127 # bx - loader (initial value is 0)
\r
132 cmpl $LOADER_FILENAME_PART1, (%di) # Compare to "EFIL"
\r
134 cmpl $LOADER_FILENAME_PART2, 4(%di)
\r
136 cmpl $LOADER_FILENAME_PART3, 7(%di)
\r
138 movw 26(%di), %bx # bx = Start Cluster for EFILDR <----------------------------------
\r
140 je FindNext # Efivar.bin is not loaded
\r
144 ## if the file is not loader file, see if it's "EFIVAR BIN"
\r
145 cmpl $0x56494645, (%di) # Compare to "EFIV"
\r
147 cmpl $0x20205241, 4(%di) # Compare to "AR "
\r
149 cmpl $0x4e494220, 7(%di) # Compare to " BIN"
\r
151 movw %di, %dx # dx = Offset of Start Cluster for Efivar.bin <---------------------
\r
154 je FindNext # Efildr is not loaded
\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
167 movw %bx, %cx # cx = Start Cluster for EFILDR <----------------------------------
\r
168 movw %cs, %ax # Destination = 2000:0000
\r
172 ReadFirstClusterOfEFILDR:
\r
173 movw %cx, %ax # ax = StartCluster
\r
174 subw $2, %ax # ax = StartCluster - 2
\r
176 movb SectorsPerCluster(%bp), %bl # bx = SectorsPerCluster
\r
179 popw %dx # ax = (StartCluster - 2) * SectorsPerCluster
\r
180 addw (%bp), %ax # ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
\r
182 movb SectorsPerCluster(%bp), %bl # bx = Number of Sectors in a cluster
\r
186 JumpIntoFirstSectorOfEFILDR:
\r
187 movw %ax, JumpSegment(%bp)
\r
188 JumpFarInstruction:
\r
206 # ****************************************************************************
\r
207 # ReadBlocks - Reads a set of blocks from a block device
\r
210 # BX = Number of Blocks to Read
\r
211 # ES:DI = Buffer to store sectors read from disk
\r
212 # ****************************************************************************
\r
215 # bx = NumberOfBlocks
\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
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
235 movw %cx, %bx # bx = Blocks
\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
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
256 addl %ebx, %esi # StartLBA = StartLBA + NumberOfBlocks
\r
257 subw %bx, %cx # Blocks = Blocks - NumberOfBlocks
\r
259 shlw $(BLOCK_SHIFT-4), %bx
\r
261 movw %ax, %es # es:di = es:di + NumberOfBlocks*BLOCK_SIZE
\r
263 jne ReadCylinderLoop
\r
267 # ****************************************************************************
\r
269 # ****************************************************************************
\r
271 ## if we found EFILDR, continue
\r
276 movw $ErrorString, %si
\r
282 .byte 'B', 0x0c, 'S', 0x0c, 't', 0x0c, 'a', 0x0c, 'r', 0x0c, 't', 0x0c, '!', 0x0c
\r
284 .byte 'B', 0x0c, 'E', 0x0c, 'r', 0x0c, 'r', 0x0c, 'o', 0x0c, 'r', 0x0c, '!', 0x0c
\r
286 # ****************************************************************************
\r
287 # LBA Offset for BootSector, need patched by tool for HD boot.
\r
288 # ****************************************************************************
\r
290 .org 0x01fa # Comment it for pass build. Should optimise code size.
\r
291 LBAOffsetForBootSector:
\r
294 # ****************************************************************************
\r
296 # ****************************************************************************
\r
298 .org 0x01fe # Comment it for pass build.
\r
300 .word 0xaa55 # Boot Sector Signature
\r