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