1;------------------------------------------------------------------------------ 2;* 3;* Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR> 4;* 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 8;* 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. 11;* 12;* bootsect.asm 13;* 14;* bootsect.asm is built as 16-bit binary file in 512 bytes and patched to disk/partition's 15;* first section - boot sector. 16;* 17;* The startup sequence for DUET disk boot sector is: 18;* 19;* 1, LegacyBios check 0xAA55 signature at boot sectore offset 0x1FE to judget 20;* whether disk/partition is bootable. 21;* 2, LegacyBios will load boot sector to 0x7c00 in real mode, pass BPB data and 22;* hand off control to 0x7c00 code. 23;* 3, boot sector code simply parse FAT format in boot disk and find EfiLdr binary file 24;* and EfiVar.bin if exists. For first boot, EfiVar.bin does not exist. 25;* 4, boot sector load the first sector of EfiLdr binary which is start.com to 26;* 0x2000:0x0000 address. 27;* 5, boot sector handoff control to 0x2000:0x0000 for start.com binary. 28;* 29;------------------------------------------------------------------------------ 30 31 .model small 32 .stack 33 .486p 34 .code 35 36FAT_DIRECTORY_ENTRY_SIZE EQU 020h 37FAT_DIRECTORY_ENTRY_SHIFT EQU 5 38BLOCK_SIZE EQU 0200h 39BLOCK_MASK EQU 01ffh 40BLOCK_SHIFT EQU 9 41 ; "EFILDR_____" 42LOADER_FILENAME_PART1 EQU 04c494645h ; "EFIL" 43LOADER_FILENAME_PART2 EQU 020205244h ; "DR__" 44LOADER_FILENAME_PART3 EQU 020202020h ; "____" 45 46 org 0h 47Ia32Jump: 48 jmp BootSectorEntryPoint ; JMP inst - 3 bytes 49 nop 50 51OemId db "INTEL " ; OemId - 8 bytes 52; BPB data below will be fixed by tool 53SectorSize dw 0 ; Sector Size - 16 bits 54SectorsPerCluster db 0 ; Sector Per Cluster - 8 bits 55ReservedSectors dw 0 ; Reserved Sectors - 16 bits 56NoFats db 0 ; Number of FATs - 8 bits 57RootEntries dw 0 ; Root Entries - 16 bits 58Sectors dw 0 ; Number of Sectors - 16 bits 59Media db 0 ; Media - 8 bits - ignored 60SectorsPerFat dw 0 ; Sectors Per FAT - 16 bits 61SectorsPerTrack dw 0 ; Sectors Per Track - 16 bits - ignored 62Heads dw 0 ; Heads - 16 bits - ignored 63HiddenSectors dd 0 ; Hidden Sectors - 32 bits - ignored 64LargeSectors dd 0 ; Large Sectors - 32 bits 65PhysicalDrive db 0 ; PhysicalDriveNumber - 8 bits - ignored 66CurrentHead db 0 ; Current Head - 8 bits 67Signature db 0 ; Signature - 8 bits - ignored 68Id db " " ; Id - 4 bytes 69FatLabel db " " ; Label - 11 bytes 70SystemId db "FAT12 " ; SystemId - 8 bytes 71 72BootSectorEntryPoint: 73 ASSUME ds:@code 74 ASSUME ss:@code 75 76; **************************************************************************** 77; Start Print 78; **************************************************************************** 79 lea si, cs:[StartString] 80 call PrintString 81 82; **************************************************************************** 83; Print over 84; **************************************************************************** 85 86 mov ax,cs ; ax = 0 87 mov ss,ax ; ss = 0 88 add ax,1000h 89 mov ds,ax 90 91 mov sp,07c00h ; sp = 0x7c00 92 mov bp,sp ; bp = 0x7c00 93 94 mov ah,8 ; ah = 8 - Get Drive Parameters Function 95 mov byte ptr [bp+PhysicalDrive],dl ; BBS defines that BIOS would pass the booting driver number to the loader through DL 96 int 13h ; Get Drive Parameters 97 xor ax,ax ; ax = 0 98 mov al,dh ; al = dh (number of sides (0 based)) 99 inc al ; MaxHead = al + 1 100 push ax ; 0000:7bfe = MaxHead 101 mov al,cl ; al = cl (CL = sectors per track) 102 and al,03fh ; MaxSector = al & 0x3f 103 push ax ; 0000:7bfc = MaxSector 104 105 cmp word ptr [bp+SectorSignature],0aa55h ; Verify Boot Sector Signature 106 jne BadBootSector 107 mov cx,word ptr [bp+RootEntries] ; cx = RootEntries 108 shl cx,FAT_DIRECTORY_ENTRY_SHIFT ; cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes 109 mov bx,cx ; bx = size of the Root Directory in bytes 110 and bx,BLOCK_MASK ; See if it is an even number of sectors long 111 jne BadBootSector ; If is isn't, then the boot sector is bad. 112 mov bx,cx ; bx = size of the Root Directory in bytes 113 shr bx,BLOCK_SHIFT ; bx = size of Root Directory in sectors 114 mov al,byte ptr [bp+NoFats] ; al = NoFats 115 xor ah,ah ; ah = 0 ==> ax = NoFats 116 mul word ptr [bp+SectorsPerFat] ; ax = NoFats * SectorsPerFat 117 add ax,word ptr [bp+ReservedSectors] ; ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA 118 push ds 119 pop es 120 xor di,di ; Store directory in es:di = 1000:0000 121 call ReadBlocks ; Read entire Root Directory 122 add ax,bx ; ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA (FirstDataSector) 123 mov word ptr [bp],ax ; Save FirstClusterLBA (FirstDataSector) for later use 124 125 ; dx - variable storage (initial value is 0) 126 ; bx - loader (initial value is 0) 127 xor dx, dx 128 xor bx, bx 129 130FindEFILDR: 131 cmp dword ptr [di],LOADER_FILENAME_PART1 ; Compare to "EFIL" 132 jne FindVARSTORE 133 cmp dword ptr [di+4],LOADER_FILENAME_PART2 134 jne FindVARSTORE 135 cmp dword ptr [di+7],LOADER_FILENAME_PART3 136 jne FindVARSTORE 137 mov bx, word ptr [di+26] ; bx = Start Cluster for EFILDR <---------------------------------- 138 test dx, dx 139 je FindNext ; Efivar.bin is not loaded 140 jmp FoundAll 141 142FindVARSTORE: 143 ; if the file is not loader file, see if it's "EFIVAR BIN" 144 cmp dword ptr [di], 056494645h ; Compare to "EFIV" 145 jne FindNext 146 cmp dword ptr [di+4], 020205241h ; Compare to "AR " 147 jne FindNext 148 cmp dword ptr [di+7], 04e494220h ; Compare to " BIN" 149 jne FindNext 150 mov dx, di ; dx = Offset of Start Cluster for Efivar.bin <--------------------- 151 add dx, 26 152 test bx, bx 153 je FindNext ; Efildr is not loaded 154 jmp FoundAll 155 156FindNext: 157 ; go to next find 158 add di,FAT_DIRECTORY_ENTRY_SIZE ; Increment di 159 sub cx,FAT_DIRECTORY_ENTRY_SIZE ; Decrement cx 160 ; TODO: jump to FindVarStore if ... 161 jne FindEFILDR 162 jmp NotFoundAll 163 164FoundAll: 165FoundEFILDR: ; 0x7cfe 166 mov cx,bx ; cx = Start Cluster for EFILDR <---------------------------------- 167 mov ax,cs ; Destination = 2000:0000 168 add ax,2000h 169 mov es,ax 170 xor di,di 171ReadFirstClusterOfEFILDR: 172 mov ax,cx ; ax = StartCluster 173 sub ax,2 ; ax = StartCluster - 2 174 xor bh,bh 175 mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster 176 push dx 177 mul bx 178 pop dx ; ax = (StartCluster - 2) * SectorsPerCluster 179 add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster 180 xor bh,bh 181 mov bl,byte ptr [bp+SectorsPerCluster] ; bx = Number of Sectors in a cluster 182 push es 183 call ReadBlocks 184 pop ax 185JumpIntoFirstSectorOfEFILDR: 186 mov word ptr [bp+JumpSegment],ax ; 0x7d26 187JumpFarInstruction: ; 0x7d2a 188 db 0eah 189JumpOffset: 190 dw 0000h 191JumpSegment: 192 dw 2000h 193 194 195PrintString: 196 mov ax,0b800h 197 mov es,ax 198 mov ax, 07c0h 199 mov ds, ax 200 mov cx, 7 201 mov di, 160 202 rep movsw 203 ret 204; **************************************************************************** 205; ReadBlocks - Reads a set of blocks from a block device 206; 207; AX = Start LBA 208; BX = Number of Blocks to Read 209; ES:DI = Buffer to store sectors read from disk 210; **************************************************************************** 211 212; cx = Blocks 213; bx = NumberOfBlocks 214; si = StartLBA 215 216ReadBlocks: 217 pusha 218 add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA 219 add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA 220 mov esi,eax ; esi = Start LBA 221 mov cx,bx ; cx = Number of blocks to read 222ReadCylinderLoop: 223 mov bp,07bfch ; bp = 0x7bfc 224 mov eax,esi ; eax = Start LBA 225 xor edx,edx ; edx = 0 226 movzx ebx,word ptr [bp] ; bx = MaxSector 227 div ebx ; ax = StartLBA / MaxSector 228 inc dx ; dx = (StartLBA % MaxSector) + 1 229 sub bx,dx ; bx = MaxSector - Sector 230 inc bx ; bx = MaxSector - Sector + 1 231 cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1) 232 jg LimitTransfer 233 mov bx,cx ; bx = Blocks 234LimitTransfer: 235 push cx 236 mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector 237 xor dx,dx ; dx = 0 238 div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder 239 ; dx = ax % (MaxHead + 1) = Head 240 241 push bx ; Save number of blocks to transfer 242 mov dh,dl ; dh = Head 243 mov bp,07c00h ; bp = 0x7c00 244 mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number 245 mov ch,al ; ch = Cylinder 246 mov al,bl ; al = Blocks 247 mov ah,2 ; ah = Function 2 248 mov bx,di ; es:bx = Buffer address 249 int 013h 250 jc DiskError 251 pop bx 252 pop cx 253 movzx ebx,bx 254 add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks 255 sub cx,bx ; Blocks = Blocks - NumberOfBlocks 256 mov ax,es 257 shl bx,(BLOCK_SHIFT-4) 258 add ax,bx 259 mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE 260 cmp cx,0 261 jne ReadCylinderLoop 262 popa 263 ret 264 265; **************************************************************************** 266; ERROR Condition: 267; **************************************************************************** 268NotFoundAll: ; 0x7da6 269 ; if we found EFILDR, continue 270 test bx,bx 271 jne FoundEFILDR 272BadBootSector: 273DiskError: 274 lea si, cs:[ErrorString] 275 call PrintString 276Halt: 277 jmp Halt 278 279StartString: 280 db 'B', 0ch, 'S', 0ch, 't', 0ch, 'a', 0ch, 'r', 0ch, 't', 0ch, '!', 0ch 281ErrorString: 282 db 'B', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch 283 284; **************************************************************************** 285; LBA Offset for BootSector, need patched by tool for HD boot. 286; **************************************************************************** 287 288 org 01fah 289LBAOffsetForBootSector: 290 dd 0h 291 292; **************************************************************************** 293; Sector Signature 294; **************************************************************************** 295 296 org 01feh 297SectorSignature: 298 dw 0aa55h ; Boot Sector Signature 299 300 end 301 302