Windows NT 4.0 source code leak
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

;++
;
;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