1 #------------------------------------------------------------------------------
3 #* Copyright 2006 - 2007, Intel Corporation
4 #* All rights reserved. This program and the accompanying materials
5 #* are licensed and made available under the terms and conditions of the BSD License
6 #* which accompanies this distribution. The full text of the license may be found at
7 #* http://opensource.org/licenses/bsd-license.php
9 #* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 #* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #------------------------------------------------------------------------------
23 .equ FAT_DIRECTORY_ENTRY_SIZE, 0x020
24 .equ FAT_DIRECTORY_ENTRY_SHIFT, 5
25 .equ BLOCK_SIZE, 0x0200
26 .equ BLOCK_MASK, 0x01ff
29 .equ LOADER_FILENAME_PART1, 0x04c494645 # "EFIL"
30 .equ LOADER_FILENAME_PART2, 0x020205244 # "DR__"
31 .equ LOADER_FILENAME_PART3, 0x020202020 # "____"
35 jmp BootSectorEntryPoint # JMP inst - 3 bytes
38 OemId: .ascii "INTEL " # OemId - 8 bytes
39 # BPB data below will be fixed by tool
40 SectorSize: .word 0 # Sector Size - 16 bits
41 SectorsPerCluster: .byte 0 # Sector Per Cluster - 8 bits
42 ReservedSectors: .word 0 # Reserved Sectors - 16 bits
43 NoFats: .byte 0 # Number of FATs - 8 bits
44 RootEntries: .word 0 # Root Entries - 16 bits
45 Sectors: .word 0 # Number of Sectors - 16 bits
46 Media: .byte 0 # Media - 8 bits - ignored
47 SectorsPerFat: .word 0 # Sectors Per FAT - 16 bits
48 SectorsPerTrack: .word 0 # Sectors Per Track - 16 bits - ignored
49 Heads: .word 0 # Heads - 16 bits - ignored
50 HiddenSectors: .long 0 # Hidden Sectors - 32 bits - ignored
51 LargeSectors: .long 0 # Large Sectors - 32 bits
52 PhysicalDrive: .byte 0 # PhysicalDriveNumber - 8 bits - ignored
53 CurrentHead: .byte 0 # Current Head - 8 bits
54 Signature: .byte 0 # Signature - 8 bits - ignored
55 VolId: .ascii " " # Volume Serial Number- 4 bytes
56 FatLabel: .ascii " " # Label - 11 bytes
57 SystemId: .ascii "FAT12 " # SystemId - 8 bytes
63 # ****************************************************************************
65 # ****************************************************************************
66 leaw %cs:StartString, %si
69 # ****************************************************************************
71 # ****************************************************************************
73 movw %cs, %ax # ax = 0
74 movw %ax, %ss # ss = 0
78 movw $0x7c00, %sp # sp = 0x7c00
79 movw %sp, %bp # bp = 0x7c00
81 movb $8, %ah # ah = 8 - Get Drive Parameters Function
82 movb %dl, PhysicalDrive(%bp) # BBS defines that BIOS would pass the booting driver number to the loader through DL
83 int $0x13 # Get Drive Parameters
84 xorw %ax, %ax # ax = 0
85 movb %dh, %al # al = dh
86 incb %al # MaxHead = al + 1
87 pushw %ax # 0000:7bfe = MaxHead
88 movb %cl, %al # al = cl
89 andb $0x3f, %al # MaxSector = al & 0x3f
90 pushw %ax # 0000:7bfc = MaxSector
92 cmpw $0xaa55, SectorSignature(%bp) # Verify Boot Sector Signature
94 movw RootEntries(%bp), %cx # cx = RootEntries
95 shlw $FAT_DIRECTORY_ENTRY_SHIFT, %cx # cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes
96 movw %cx, %bx # bx = size of the Root Directory in bytes
97 andw $BLOCK_MASK, %bx # See if it is an even number of sectors long
98 jne BadBootSector # If is isn't, then the boot sector is bad.
99 movw %cx, %bx # bx = size of the Root Directory in bytes
100 shrw $BLOCK_SHIFT, %bx # bx = size of Root Directory in sectors
101 movb NoFats(%bp), %al # al = NoFats
102 xorb %ah, %ah # ah = 0 ==> ax = NoFats
103 mulw SectorsPerFat(%bp) # ax = NoFats * SectorsPerFat
104 addw ReservedSectors(%bp), %ax # ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA
107 xorw %di, %di # Store directory in es:di = 1000:0000
108 call ReadBlocks # Read entire Root Directory
109 addw %bx, %ax # ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA (FirstDataSector)
110 movw %ax, (%bp) # Save FirstClusterLBA (FirstDataSector) for later use
112 # dx - variable storage (initial value is 0)
113 # bx - loader (initial value is 0)
118 cmpl $LOADER_FILENAME_PART1, (%di) # Compare to "EFIL"
120 cmpl $LOADER_FILENAME_PART2, 4(%di)
122 cmpl $LOADER_FILENAME_PART3, 7(%di)
124 movw 26(%di), %bx # bx = Start Cluster for EFILDR <----------------------------------
126 je FindNext # Efivar.bin is not loaded
130 ## if the file is not loader file, see if it's "EFIVAR BIN"
131 cmpl $0x56494645, (%di) # Compare to "EFIV"
133 cmpl $0x20205241, 4(%di) # Compare to "AR "
135 cmpl $0x4e494220, 7(%di) # Compare to " BIN"
137 movw %di, %dx # dx = Offset of Start Cluster for Efivar.bin <---------------------
140 je FindNext # Efildr is not loaded
145 addw $FAT_DIRECTORY_ENTRY_SIZE, %di # Increment di
146 subw $FAT_DIRECTORY_ENTRY_SIZE, %cx # Decrement cx
147 # TODO: jump to FindVarStore if ...
153 movw %bx, %cx # cx = Start Cluster for EFILDR <----------------------------------
154 movw %cs, %ax # Destination = 2000:0000
158 ReadFirstClusterOfEFILDR:
159 movw %cx, %ax # ax = StartCluster
160 subw $2, %ax # ax = StartCluster - 2
162 movb SectorsPerCluster(%bp), %bl # bx = SectorsPerCluster
165 popw %dx # ax = (StartCluster - 2) * SectorsPerCluster
166 addw (%bp), %ax # ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
168 movb SectorsPerCluster(%bp), %bl # bx = Number of Sectors in a cluster
172 JumpIntoFirstSectorOfEFILDR:
173 movw %ax, JumpSegment(%bp)
192 # ****************************************************************************
193 # ReadBlocks - Reads a set of blocks from a block device
196 # BX = Number of Blocks to Read
197 # ES:DI = Buffer to store sectors read from disk
198 # ****************************************************************************
201 # bx = NumberOfBlocks
206 addl LBAOffsetForBootSector(%bp), %eax # Add LBAOffsetForBootSector to Start LBA
207 addl HiddenSectors(%bp), %eax # Add HiddenSectors to Start LBA
208 movl %eax, %esi # esi = Start LBA
209 movw %bx, %cx # cx = Number of blocks to read
211 movw $0x7bfc, %bp # bp = 0x7bfc
212 movl %esi, %eax # eax = Start LBA
213 xorl %edx, %edx # edx = 0
214 movzwl (%bp), %ebx # bx = MaxSector
215 divl %ebx # ax = StartLBA / MaxSector
216 incw %dx # dx = (StartLBA % MaxSector) + 1
217 subw %dx, %bx # bx = MaxSector - Sector
218 incw %bx # bx = MaxSector - Sector + 1
219 cmpw %bx, %cx # Compare (Blocks) to (MaxSector - Sector + 1)
221 movw %cx, %bx # bx = Blocks
224 movb %dl, %cl # cl = (StartLBA % MaxSector) + 1 = Sector
225 xorw %dx, %dx # dx = 0
226 divw 2(%bp) # ax = ax / (MaxHead + 1) = Cylinder
227 # dx = ax % (MaxHead + 1) = Head
229 pushw %bx # Save number of blocks to transfer
230 movb %dl, %dh # dh = Head
231 movw $0x7c00, %bp # bp = 0x7c00
232 movb PhysicalDrive(%bp), %dl # dl = Drive Number
233 movb %al, %ch # ch = Cylinder
234 movb %bl, %al # al = Blocks
235 movb $2, %ah # ah = Function 2
236 movw %di, %bx # es:bx = Buffer address
242 addl %ebx, %esi # StartLBA = StartLBA + NumberOfBlocks
243 subw %bx, %cx # Blocks = Blocks - NumberOfBlocks
245 shlw $(BLOCK_SHIFT-4), %bx
247 movw %ax, %es # es:di = es:di + NumberOfBlocks*BLOCK_SIZE
253 # ****************************************************************************
255 # ****************************************************************************
257 ## if we found EFILDR, continue
262 leaw %cs:ErrorString, %si
268 .byte 'B', 0x0c, 'S', 0x0c, 't', 0x0c, 'a', 0x0c, 'r', 0x0c, 't', 0x0c, '!', 0x0c
270 .byte 'B', 0x0c, 'E', 0x0c, 'r', 0x0c, 'r', 0x0c, 'o', 0x0c, 'r', 0x0c, '!', 0x0c
272 # ****************************************************************************
273 # LBA Offset for BootSector, need patched by tool for HD boot.
274 # ****************************************************************************
276 # .org 0x01fa # Comment it for pass build. Should optimise code size.
277 LBAOffsetForBootSector:
280 # ****************************************************************************
282 # ****************************************************************************
284 # .org 0x01fe # Comment it for pass build.
286 .word 0xaa55 # Boot Sector Signature