audk/DuetPkg/BootSector/bootsect.asm

302 lines
13 KiB
NASM
Raw Normal View History

;------------------------------------------------------------------------------
;*
;* Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
;* 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.asm
;*
;* bootsect.asm 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.
;*
;------------------------------------------------------------------------------
.model small
.stack
.486p
.code
FAT_DIRECTORY_ENTRY_SIZE EQU 020h
FAT_DIRECTORY_ENTRY_SHIFT EQU 5
BLOCK_SIZE EQU 0200h
BLOCK_MASK EQU 01ffh
BLOCK_SHIFT EQU 9
; "EFILDR_____"
LOADER_FILENAME_PART1 EQU 04c494645h ; "EFIL"
LOADER_FILENAME_PART2 EQU 020205244h ; "DR__"
LOADER_FILENAME_PART3 EQU 020202020h ; "____"
org 0h
Ia32Jump:
jmp BootSectorEntryPoint ; JMP inst - 3 bytes
nop
OemId db "INTEL " ; OemId - 8 bytes
; BPB data below will be fixed by tool
SectorSize dw 0 ; Sector Size - 16 bits
SectorsPerCluster db 0 ; Sector Per Cluster - 8 bits
ReservedSectors dw 0 ; Reserved Sectors - 16 bits
NoFats db 0 ; Number of FATs - 8 bits
RootEntries dw 0 ; Root Entries - 16 bits
Sectors dw 0 ; Number of Sectors - 16 bits
Media db 0 ; Media - 8 bits - ignored
SectorsPerFat dw 0 ; Sectors Per FAT - 16 bits
SectorsPerTrack dw 0 ; Sectors Per Track - 16 bits - ignored
Heads dw 0 ; Heads - 16 bits - ignored
HiddenSectors dd 0 ; Hidden Sectors - 32 bits - ignored
LargeSectors dd 0 ; Large Sectors - 32 bits
PhysicalDrive db 0 ; PhysicalDriveNumber - 8 bits - ignored
CurrentHead db 0 ; Current Head - 8 bits
Signature db 0 ; Signature - 8 bits - ignored
Id db " " ; Id - 4 bytes
FatLabel db " " ; Label - 11 bytes
SystemId db "FAT12 " ; SystemId - 8 bytes
BootSectorEntryPoint:
ASSUME ds:@code
ASSUME ss:@code
; ****************************************************************************
; Start Print
; ****************************************************************************
lea si, cs:[StartString]
call PrintString
; ****************************************************************************
; Print over
; ****************************************************************************
mov ax,cs ; ax = 0
mov ss,ax ; ss = 0
add ax,1000h
mov ds,ax
mov sp,07c00h ; sp = 0x7c00
mov bp,sp ; bp = 0x7c00
mov ah,8 ; ah = 8 - Get Drive Parameters Function
mov byte ptr [bp+PhysicalDrive],dl ; BBS defines that BIOS would pass the booting driver number to the loader through DL
int 13h ; Get Drive Parameters
xor ax,ax ; ax = 0
mov al,dh ; al = dh (number of sides (0 based))
inc al ; MaxHead = al + 1
push ax ; 0000:7bfe = MaxHead
mov al,cl ; al = cl (CL = sectors per track)
and al,03fh ; MaxSector = al & 0x3f
push ax ; 0000:7bfc = MaxSector
cmp word ptr [bp+SectorSignature],0aa55h ; Verify Boot Sector Signature
jne BadBootSector
mov cx,word ptr [bp+RootEntries] ; cx = RootEntries
shl cx,FAT_DIRECTORY_ENTRY_SHIFT ; cx = cx * 32 = cx * sizeof(FAT_DIRECTORY_ENTRY) = Size of Root Directory in bytes
mov bx,cx ; bx = size of the Root Directory in bytes
and bx,BLOCK_MASK ; See if it is an even number of sectors long
jne BadBootSector ; If is isn't, then the boot sector is bad.
mov bx,cx ; bx = size of the Root Directory in bytes
shr bx,BLOCK_SHIFT ; bx = size of Root Directory in sectors
mov al,byte ptr [bp+NoFats] ; al = NoFats
xor ah,ah ; ah = 0 ==> ax = NoFats
mul word ptr [bp+SectorsPerFat] ; ax = NoFats * SectorsPerFat
add ax,word ptr [bp+ReservedSectors] ; ax = NoFats * SectorsPerFat + ReservedSectors = RootLBA
push ds
pop es
xor di,di ; Store directory in es:di = 1000:0000
call ReadBlocks ; Read entire Root Directory
add ax,bx ; ax = NoFats * SectorsPerFat + ReservedSectors + RootDirSectors = FirstClusterLBA (FirstDataSector)
mov word ptr [bp],ax ; Save FirstClusterLBA (FirstDataSector) for later use
; dx - variable storage (initial value is 0)
; bx - loader (initial value is 0)
xor dx, dx
xor bx, bx
FindEFILDR:
cmp dword ptr [di],LOADER_FILENAME_PART1 ; Compare to "EFIL"
jne FindVARSTORE
cmp dword ptr [di+4],LOADER_FILENAME_PART2
jne FindVARSTORE
cmp dword ptr [di+7],LOADER_FILENAME_PART3
jne FindVARSTORE
mov bx, word ptr [di+26] ; bx = Start Cluster for EFILDR <----------------------------------
test 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"
cmp dword ptr [di], 056494645h ; Compare to "EFIV"
jne FindNext
cmp dword ptr [di+4], 020205241h ; Compare to "AR "
jne FindNext
cmp dword ptr [di+7], 04e494220h ; Compare to " BIN"
jne FindNext
mov dx, di ; dx = Offset of Start Cluster for Efivar.bin <---------------------
add dx, 26
test bx, bx
je FindNext ; Efildr is not loaded
jmp FoundAll
FindNext:
; go to next find
add di,FAT_DIRECTORY_ENTRY_SIZE ; Increment di
sub cx,FAT_DIRECTORY_ENTRY_SIZE ; Decrement cx
; TODO: jump to FindVarStore if ...
jne FindEFILDR
jmp NotFoundAll
FoundAll:
FoundEFILDR: ; 0x7cfe
mov cx,bx ; cx = Start Cluster for EFILDR <----------------------------------
mov ax,cs ; Destination = 2000:0000
add ax,2000h
mov es,ax
xor di,di
ReadFirstClusterOfEFILDR:
mov ax,cx ; ax = StartCluster
sub ax,2 ; ax = StartCluster - 2
xor bh,bh
mov bl,byte ptr [bp+SectorsPerCluster] ; bx = SectorsPerCluster
push dx
mul bx
pop dx ; ax = (StartCluster - 2) * SectorsPerCluster
add ax, word ptr [bp] ; ax = FirstClusterLBA + (StartCluster-2)*SectorsPerCluster
xor bh,bh
mov bl,byte ptr [bp+SectorsPerCluster] ; bx = Number of Sectors in a cluster
push es
call ReadBlocks
pop ax
JumpIntoFirstSectorOfEFILDR:
mov word ptr [bp+JumpSegment],ax ; 0x7d26
JumpFarInstruction: ; 0x7d2a
db 0eah
JumpOffset:
dw 0000h
JumpSegment:
dw 2000h
PrintString:
mov ax,0b800h
mov es,ax
mov ax, 07c0h
mov ds, ax
mov cx, 7
mov di, 160
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
add eax,dword ptr [bp+LBAOffsetForBootSector] ; Add LBAOffsetForBootSector to Start LBA
add eax,dword ptr [bp+HiddenSectors] ; Add HiddenSectors to Start LBA
mov esi,eax ; esi = Start LBA
mov cx,bx ; cx = Number of blocks to read
ReadCylinderLoop:
mov bp,07bfch ; bp = 0x7bfc
mov eax,esi ; eax = Start LBA
xor edx,edx ; edx = 0
movzx ebx,word ptr [bp] ; bx = MaxSector
div ebx ; ax = StartLBA / MaxSector
inc dx ; dx = (StartLBA % MaxSector) + 1
sub bx,dx ; bx = MaxSector - Sector
inc bx ; bx = MaxSector - Sector + 1
cmp cx,bx ; Compare (Blocks) to (MaxSector - Sector + 1)
jg LimitTransfer
mov bx,cx ; bx = Blocks
LimitTransfer:
push cx
mov cl,dl ; cl = (StartLBA % MaxSector) + 1 = Sector
xor dx,dx ; dx = 0
div word ptr [bp+2] ; ax = ax / (MaxHead + 1) = Cylinder
; dx = ax % (MaxHead + 1) = Head
push bx ; Save number of blocks to transfer
mov dh,dl ; dh = Head
mov bp,07c00h ; bp = 0x7c00
mov dl,byte ptr [bp+PhysicalDrive] ; dl = Drive Number
mov ch,al ; ch = Cylinder
mov al,bl ; al = Blocks
mov ah,2 ; ah = Function 2
mov bx,di ; es:bx = Buffer address
int 013h
jc DiskError
pop bx
pop cx
movzx ebx,bx
add esi,ebx ; StartLBA = StartLBA + NumberOfBlocks
sub cx,bx ; Blocks = Blocks - NumberOfBlocks
mov ax,es
shl bx,(BLOCK_SHIFT-4)
add ax,bx
mov es,ax ; es:di = es:di + NumberOfBlocks*BLOCK_SIZE
cmp cx,0
jne ReadCylinderLoop
popa
ret
; ****************************************************************************
; ERROR Condition:
; ****************************************************************************
NotFoundAll: ; 0x7da6
; if we found EFILDR, continue
test bx,bx
jne FoundEFILDR
BadBootSector:
DiskError:
lea si, cs:[ErrorString]
call PrintString
Halt:
jmp Halt
StartString:
db 'B', 0ch, 'S', 0ch, 't', 0ch, 'a', 0ch, 'r', 0ch, 't', 0ch, '!', 0ch
ErrorString:
db 'B', 0ch, 'E', 0ch, 'r', 0ch, 'r', 0ch, 'o', 0ch, 'r', 0ch, '!', 0ch
; ****************************************************************************
; LBA Offset for BootSector, need patched by tool for HD boot.
; ****************************************************************************
org 01fah
LBAOffsetForBootSector:
dd 0h
; ****************************************************************************
; Sector Signature
; ****************************************************************************
org 01feh
SectorSignature:
dw 0aa55h ; Boot Sector Signature
end