mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
426 lines
12 KiB
426 lines
12 KiB
;++
|
|
;
|
|
;Copyright (c) 1991 Microsoft Corporation
|
|
;
|
|
;Module Name:
|
|
;
|
|
; fatboot.asm
|
|
;
|
|
;Abstract:
|
|
;
|
|
; The ROM in the IBM PC starts the boot process by performing a hardware
|
|
; initialization and a verification of all external devices. If all goes
|
|
; well, it will then load from the boot drive the sector from track 0, head 0,
|
|
; sector 1. This sector is placed at physical address 07C00h.
|
|
;
|
|
; The code in this sector is responsible for locating NTLDR, loading the
|
|
; first sector of NTLDR into memory at 2000:0000, and branching to it. The
|
|
; first sector of NTLDR is special code which knows enough about FAT and
|
|
; BIOS to load the rest of NTLDR into memory.
|
|
;
|
|
; There are only two errors possible during execution of this code.
|
|
; 1 - NTLDR does not exist
|
|
; 2 - BIOS read error
|
|
;
|
|
; In both cases, a short message is printed, and the user is prompted to
|
|
; reboot the system.
|
|
;
|
|
; At the beginning of the boot sector, there is a table which describes the
|
|
; structure of the media. This is equivalent to the BPB with some
|
|
; additional information describing the physical layout of the driver (heads,
|
|
; tracks, sectors)
|
|
;
|
|
;
|
|
;Author:
|
|
;
|
|
; John Vert (jvert) 31-Aug-1991
|
|
;
|
|
;Environment:
|
|
;
|
|
; Sector has been loaded at 7C0:0000 by BIOS.
|
|
; Real mode
|
|
; FAT file system
|
|
;
|
|
;Revision History:
|
|
;
|
|
;--
|
|
page ,132
|
|
title boot - NTLDR FAT loader
|
|
name fatboot
|
|
|
|
DIR_ENT struc
|
|
Filename db 11 dup(?)
|
|
Attribute db ?
|
|
Reserved db 10 dup(?)
|
|
Time dw 2 dup(?)
|
|
StartCluster dw ?
|
|
FileSize dd ?
|
|
DIR_ENT ends
|
|
|
|
;
|
|
; This is the structure used to pass all shared data between the boot sector
|
|
; and NTLDR.
|
|
;
|
|
|
|
SHARED struc
|
|
ReadClusters dd ? ; function pointer
|
|
ReadSectors dd ? ; function pointer
|
|
SectorBase dd ? ; starting sector
|
|
SHARED ends
|
|
|
|
|
|
|
|
DoubleWord struc
|
|
lsw dw ?
|
|
msw dw ?
|
|
DoubleWord ends
|
|
|
|
SectorSize equ 512 ; sector size
|
|
|
|
BootSeg segment at 07c0h
|
|
BootSeg ends
|
|
|
|
DirSeg segment at 1000h
|
|
DirSeg ends
|
|
|
|
NtLdrSeg segment at 2000h
|
|
NtLdrSeg ends
|
|
|
|
BootCode segment ;would like to use BootSeg here, but LINK flips its lid
|
|
ASSUME CS:BootCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
|
|
|
|
public FATBOOT
|
|
FATBOOT proc far
|
|
|
|
jmp Start
|
|
|
|
;
|
|
; THE FOLLOWING DATA CONFIGURES THE BOOT PROGRAM
|
|
; FOR ANY TYPE OF DRIVE OR HARDFILE
|
|
;
|
|
; Note that this data is just a place-holder here. The actual values will
|
|
; be filled in by FORMAT or SYS. When installing the boot sector, only the
|
|
; code following the BPB (from Start to the end) should be copied into the
|
|
; first sector.
|
|
;
|
|
|
|
Version db "MSDOS5.0"
|
|
BPB label byte
|
|
BytesPerSector dw SectorSize ; Size of a physical sector
|
|
SectorsPerCluster db 8 ; Sectors per allocation unit
|
|
ReservedSectors dw 1 ; Number of reserved sectors
|
|
Fats db 2 ; Number of fats
|
|
DirectoryEntries dw 512 ; Number of directory entries
|
|
Sectors dw 4*17*305-1 ; No. of sectors - no. of hidden sectors
|
|
Media db 0F8H ; Media byte
|
|
FatSectors dw 8 ; Number of fat sectors
|
|
SectorsPerTrack dw 17 ; Sectors per track
|
|
Heads dw 4 ; Number of surfaces
|
|
HiddenSectors dd 1 ; Number of hidden sectors
|
|
SectorsLong dd 0 ; Number of sectors iff Sectors = 0
|
|
|
|
;
|
|
; The following byte is NOT part of the BPB but is set by SYS and format
|
|
; We should NOT change its position.
|
|
;
|
|
|
|
; keep order of DriveNumber and CurrentHead!
|
|
DriveNumber db 80h ; Physical drive number (0 or 80h)
|
|
CurrentHead db ? ; Unitialized
|
|
|
|
Signature db 41 ; Signature Byte for bootsector
|
|
BootID dd ? ; Boot ID field.
|
|
Boot_Vol_Label db 11 dup (?)
|
|
Boot_System_ID db 'FAT ' ;"FAT " or "OTHER_FS"
|
|
|
|
|
|
Start:
|
|
xor ax,ax ; Setup the stack to a known good spot
|
|
mov ss,ax
|
|
mov sp,7c00h
|
|
|
|
.386
|
|
push BootSeg
|
|
.8086
|
|
pop ds
|
|
assume DS:BootCode
|
|
|
|
; The system is now prepared for us to begin reading. First, determine
|
|
; logical sector numbers of the start of the directory and the start of the
|
|
; data area.
|
|
;
|
|
MOV AL,Fats ;Determine sector root directory starts on
|
|
MUL FatSectors
|
|
;##### what if result > 65535 ?????
|
|
ADD AX,ReservedSectors
|
|
;##### what if result > 65535 ?????
|
|
PUSH AX ; AX = Fats*FatSectors + ReservedSectors + HiddenSectors
|
|
XCHG CX,AX ; (CX) = start of DIR
|
|
;
|
|
; Take into account size of directory (only know number of directory entries)
|
|
;
|
|
MOV AX,size DIR_ENT ; bytes per directory entry
|
|
MUL DirectoryEntries ; convert to bytes in directory
|
|
MOV BX,BytesPerSector ; add in sector size
|
|
ADD AX,BX
|
|
DEC AX ; decrement so that we round up
|
|
DIV BX ; convert to sector number
|
|
ADD CX,AX
|
|
MOV ClusterBase,CX ; save it for later
|
|
;
|
|
; Load in the root directory.
|
|
;
|
|
.386
|
|
push DirSeg ; es:bx -> directory segment
|
|
.8086
|
|
pop es
|
|
ASSUME ES:DirSeg
|
|
xor bx,bx
|
|
pop Arguments.SectorBase.lsw
|
|
mov Arguments.SectorBase.msw,bx
|
|
|
|
;
|
|
; DoRead does a RETF, but LINK pukes if we do a FAR call in a /tiny program.
|
|
;
|
|
; (al) = # of sectors to read
|
|
;
|
|
push cs
|
|
call DoRead
|
|
jc BootErr$he
|
|
|
|
; Now we scan for the presence of NTLDR
|
|
|
|
xor bx,bx
|
|
mov cx,DirectoryEntries
|
|
L10:
|
|
mov di,bx
|
|
push cx
|
|
mov cx,11
|
|
mov si, offset LOADERNAME
|
|
repe cmpsb
|
|
pop cx
|
|
jz L10end
|
|
|
|
add bx,size DIR_ENT
|
|
loop L10
|
|
L10end:
|
|
|
|
jcxz BootErr$bnf
|
|
|
|
mov dx,es:[bx].StartCluster ; (dx) = starting cluster number
|
|
push dx
|
|
mov ax,1 ; (al) = sectors to read
|
|
;
|
|
; Now, go read the file
|
|
;
|
|
|
|
.386
|
|
push NtLdrSeg
|
|
.8086
|
|
pop es
|
|
ASSUME ES:NtLdrSeg
|
|
xor bx,bx ; (es:bx) -> start of NTLDR
|
|
|
|
|
|
;
|
|
; LINK barfs if we do a FAR call in a TINY program, so we have to fake it
|
|
; out by pushing CS.
|
|
;
|
|
|
|
push cs
|
|
call ClusterRead
|
|
jc BootErr$he
|
|
|
|
;
|
|
; NTLDR requires:
|
|
; BX = Starting Cluster Number of NTLDR
|
|
; DL = INT 13 drive number we booted from
|
|
; DS:SI -> the boot media's BPB
|
|
; DS:DI -> argument structure
|
|
; 1000:0000 - entire FAT is loaded
|
|
;
|
|
|
|
pop BX ; (bx) = Starting Cluster Number
|
|
lea si,BPB ; ds:si -> BPB
|
|
lea di,Arguments ; ds:di -> Arguments
|
|
|
|
push ds
|
|
pop [di].ReadClusters.msw
|
|
mov [di].ReadClusters.lsw, offset ClusterRead
|
|
push ds
|
|
pop [di].ReadSectors.msw
|
|
mov [di].ReadSectors.lsw, offset DoRead
|
|
MOV dl,DriveNumber ; dl = boot drive
|
|
|
|
;
|
|
; FAR JMP to 2000:0003. This is hand-coded, because I can't figure out
|
|
; how to make MASM do this for me. By entering NTLDR here, we skip the
|
|
; initial jump and execute the FAT-specific code to load the rest of
|
|
; NTLDR.
|
|
;
|
|
db 0EAh ; JMP FAR PTR
|
|
dw 3 ; 2000:3
|
|
dw 02000h
|
|
FATBOOT endp
|
|
|
|
; BootErr - print error message and hang the system.
|
|
;
|
|
BootErr proc
|
|
BootErr$bnf:
|
|
MOV SI,OFFSET MSG_NO_NTLDR
|
|
jmp short BootErr2
|
|
BootErr$he:
|
|
MOV SI,OFFSET MSG_READ_ERROR
|
|
BootErr2:
|
|
call BootErrPrint
|
|
MOV SI,OFFSET MSG_REBOOT_ERROR
|
|
call BootErrPrint
|
|
sti
|
|
jmp $ ;Wait forever
|
|
|
|
BootErrPrint:
|
|
LODSB ; Get next character
|
|
or al,al
|
|
jz BEdone
|
|
|
|
MOV AH,14 ; Write teletype
|
|
MOV BX,7 ; Attribute
|
|
INT 10H ; Print it
|
|
jmp BootErrPrint
|
|
BEdone:
|
|
|
|
ret
|
|
BootErr endp
|
|
|
|
; ClusterRead - read AL sectors into ES:BX starting from
|
|
; cluster DX
|
|
;
|
|
ClusterRead proc
|
|
push ax ; (TOS) = # of sectors to read
|
|
dec dx
|
|
dec dx ; adjust for reserved clusters 0 and 1
|
|
mov al,SectorsPerCluster
|
|
xor ah,ah
|
|
mul dx ; DX:AX = starting sector number
|
|
add ax,ClusterBase ; adjust for FATs, root dir, boot sec.
|
|
adc dx,0
|
|
mov Arguments.SectorBase.lsw,ax
|
|
mov Arguments.SectorBase.msw,dx
|
|
pop ax ; (al) = # of sectors to read
|
|
|
|
;
|
|
; Now we've converted the cluster number to a SectorBase, so just fall
|
|
; through into DoRead
|
|
;
|
|
|
|
ClusterRead endp
|
|
|
|
|
|
;
|
|
; DoRead - read AL sectors into ES:BX starting from sector
|
|
; SectorBase.
|
|
;
|
|
DoRead proc
|
|
|
|
mov SectorCount,AL
|
|
DRloop:
|
|
MOV AX,Arguments.SectorBase.lsw ; Starting sector
|
|
MOV DX,Arguments.SectorBase.msw ; Starting sector
|
|
;
|
|
; DoDiv - convert logical sector number in AX to physical Head/Track/Sector
|
|
; in CurrentHead/CurrentTrack/CurrentSector.
|
|
;
|
|
ADD AX,HiddenSectors.lsw ;adjust for partition's base sector
|
|
ADC DX,HiddenSectors.msw
|
|
DIV SectorsPerTrack
|
|
INC DL ; sector numbers are 1-based
|
|
MOV CurrentSector,DL
|
|
XOR DX,DX
|
|
DIV Heads
|
|
MOV CurrentHead,DL
|
|
MOV CurrentTrack,AX
|
|
;
|
|
;DoDiv endp
|
|
;
|
|
|
|
|
|
; CurrentHead is the head for this next disk request
|
|
; CurrentTrack is the track for this next request
|
|
; CurrentSector is the beginning sector number for this request
|
|
|
|
; Compute the number of sectors that we may be able to read in a single ROM
|
|
; request.
|
|
|
|
MOV AX,SectorsPerTrack
|
|
SUB AL,CurrentSector
|
|
INC AX
|
|
cmp al,SectorCount
|
|
jbe DoCall
|
|
mov al,SectorCount
|
|
xor ah,ah
|
|
|
|
; AX is the number of sectors that we may read.
|
|
|
|
;
|
|
; DoCall - call ROM BIOS to read AL sectors into ES:BX.
|
|
;
|
|
DoCall:
|
|
PUSH AX
|
|
MOV AH,2
|
|
MOV cx,CurrentTrack
|
|
.386
|
|
SHL ch,6
|
|
.8086
|
|
OR ch,CurrentSector
|
|
XCHG CH,CL
|
|
MOV DX,WORD PTR DriveNumber
|
|
INT 13H
|
|
;
|
|
;DoCall endp
|
|
;
|
|
|
|
.386
|
|
jnc DcNoErr
|
|
add sp,2
|
|
stc
|
|
retf
|
|
.8086
|
|
|
|
DcNoErr:
|
|
POP AX
|
|
SUB SectorCount,AL ; Are we finished?
|
|
jbe DRdone
|
|
ADD Arguments.SectorBase.lsw,AX ; increment logical sector position
|
|
ADC Arguments.SectorBase.msw,0
|
|
MUL BytesPerSector ; determine next offset for read
|
|
ADD BX,AX ; (BX)=(BX)+(SI)*(Bytes per sector)
|
|
|
|
jmp DRloop
|
|
DRdone:
|
|
mov SectorCount,al
|
|
clc
|
|
retf
|
|
DoRead endp
|
|
|
|
include fatboot.inc ;suck in the message text
|
|
|
|
LOADERNAME DB "NTLDR "
|
|
|
|
.errnz ($-FATBOOT) GT 510,<FATAL PROBLEM: boot sector is too large>
|
|
|
|
org 510
|
|
db 55h,0aah
|
|
|
|
BootSectorEnd label dword
|
|
|
|
BootCode ends
|
|
|
|
;Unitialized variables go here--beyond the end of the boot sector in free memory
|
|
CurrentTrack equ word ptr BootSectorEnd + 4 ; current track
|
|
CurrentSector equ byte ptr BootSectorEnd + 6 ; current sector
|
|
SectorCount equ byte ptr BootSectorEnd + 7 ; number of sectors to read
|
|
ClusterBase equ word ptr BootSectorEnd + 8 ; first sector of cluster # 2
|
|
Retries equ byte ptr BootSectorEnd + 10
|
|
Arguments equ byte ptr BootSectorEnd + 11 ; structure passed to NTLDR
|
|
|
|
END FATBOOT
|