bejiitas_wrath

Windows NT 4.0 fatboot.asm

Nov 4th, 2025
2,475
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ;++
  2. ;
  3. ;Copyright (c) 1991  Microsoft Corporation
  4. ;
  5. ;Module Name:
  6. ;
  7. ; fatboot.asm
  8. ;
  9. ;Abstract:
  10. ;
  11. ; The ROM in the IBM PC starts the boot process by performing a hardware
  12. ; initialization and a verification of all external devices.  If all goes
  13. ; well, it will then load from the boot drive the sector from track 0, head 0,
  14. ; sector 1.  This sector is placed at physical address 07C00h.
  15. ;
  16. ; The code in this sector is responsible for locating NTLDR, loading the
  17. ; first sector of NTLDR into memory at 2000:0000, and branching to it.  The
  18. ; first sector of NTLDR is special code which knows enough about FAT and
  19. ; BIOS to load the rest of NTLDR into memory.
  20. ;
  21. ; There are only two errors possible during execution of this code.
  22. ;       1 - NTLDR does not exist
  23. ;       2 - BIOS read error
  24. ;
  25. ; In both cases, a short message is printed, and the user is prompted to
  26. ; reboot the system.
  27. ;
  28. ; At the beginning of the boot sector, there is a table which describes the
  29. ; structure of the media.  This is equivalent to the BPB with some
  30. ; additional information describing the physical layout of the driver (heads,
  31. ; tracks, sectors)
  32. ;
  33. ;
  34. ;Author:
  35. ;
  36. ;    John Vert (jvert) 31-Aug-1991
  37. ;
  38. ;Environment:
  39. ;
  40. ;    Sector has been loaded at 7C0:0000 by BIOS.
  41. ;    Real mode
  42. ;    FAT file system
  43. ;
  44. ;Revision History:
  45. ;
  46. ;--
  47.         page    ,132
  48.         title   boot - NTLDR FAT loader
  49.         name    fatboot
  50.  
  51. DIR_ENT struc
  52.         Filename        db 11 dup(?)
  53.         Attribute       db ?
  54.         Reserved        db 10 dup(?)
  55.         Time            dw 2 dup(?)
  56.         StartCluster    dw ?
  57.         FileSize        dd ?
  58. DIR_ENT ends
  59.  
  60. ;
  61. ; This is the structure used to pass all shared data between the boot sector
  62. ; and NTLDR.
  63. ;
  64.  
  65. SHARED  struc
  66.         ReadClusters            dd      ?               ; function pointer
  67.         ReadSectors             dd      ?               ; function pointer
  68.         SectorBase              dd      ?               ; starting sector
  69. SHARED  ends
  70.  
  71.  
  72.  
  73. DoubleWord      struc
  74. lsw     dw      ?
  75. msw     dw      ?
  76. DoubleWord      ends
  77.  
  78. SectorSize      equ     512             ; sector size
  79.  
  80. BootSeg segment at 07c0h
  81. BootSeg ends
  82.  
  83. DirSeg  segment at 1000h
  84. DirSeg  ends
  85.  
  86. NtLdrSeg segment at 2000h
  87. NtLdrSeg ends
  88.  
  89. BootCode        segment ;would like to use BootSeg here, but LINK flips its lid
  90.     ASSUME  CS:BootCode,DS:NOTHING,ES:NOTHING,SS:NOTHING
  91.  
  92.         public  FATBOOT
  93. FATBOOT proc    far
  94.  
  95.         jmp     Start
  96.  
  97. ;
  98. ;       THE FOLLOWING DATA CONFIGURES THE BOOT PROGRAM
  99. ;       FOR ANY TYPE OF DRIVE OR HARDFILE
  100. ;
  101. ; Note that this data is just a place-holder here.  The actual values will
  102. ; be filled in by FORMAT or SYS.  When installing the boot sector, only the
  103. ; code following the BPB (from Start to the end) should be copied into the
  104. ; first sector.
  105. ;
  106.  
  107. Version                 db      "MSDOS5.0"
  108. BPB                     label   byte
  109. BytesPerSector          dw      SectorSize      ; Size of a physical sector
  110. SectorsPerCluster       db      8               ; Sectors per allocation unit
  111. ReservedSectors         dw      1               ; Number of reserved sectors
  112. Fats                    db      2               ; Number of fats
  113. DirectoryEntries        dw      512             ; Number of directory entries
  114. Sectors                 dw      4*17*305-1      ; No. of sectors - no. of hidden sectors
  115. Media                   db      0F8H            ; Media byte
  116. FatSectors              dw      8               ; Number of fat sectors
  117. SectorsPerTrack         dw      17              ; Sectors per track
  118. Heads                   dw      4               ; Number of surfaces
  119. HiddenSectors           dd      1               ; Number of hidden sectors
  120. SectorsLong             dd      0               ; Number of sectors iff Sectors = 0
  121.  
  122. ;
  123. ; The following byte is NOT part of the BPB but is set by SYS and format
  124. ; We should NOT change its position.
  125. ;
  126.  
  127. ; keep order of DriveNumber and CurrentHead!
  128. DriveNumber     db      80h             ; Physical drive number (0 or 80h)
  129. CurrentHead     db      ?               ; Unitialized
  130.  
  131. Signature       db      41              ; Signature Byte for bootsector
  132. BootID          dd      ?               ; Boot ID field.
  133. Boot_Vol_Label  db      11 dup (?)
  134. Boot_System_ID  db      'FAT     '  ;"FAT     " or "OTHER_FS"
  135.  
  136.  
  137. Start:
  138.         xor     ax,ax                   ; Setup the stack to a known good spot
  139.         mov     ss,ax
  140.         mov     sp,7c00h
  141.  
  142. .386
  143.         push    BootSeg
  144. .8086
  145.         pop     ds
  146. assume DS:BootCode
  147.  
  148. ; The system is now prepared for us to begin reading.  First, determine
  149. ; logical sector numbers of the start of the directory and the start of the
  150. ; data area.
  151. ;
  152.         MOV     AL,Fats         ;Determine sector root directory starts on
  153.         MUL     FatSectors
  154. ;##### what if result > 65535 ?????
  155.         ADD     AX,ReservedSectors
  156. ;##### what if result > 65535 ?????
  157.         PUSH    AX              ; AX = Fats*FatSectors + ReservedSectors + HiddenSectors
  158.         XCHG    CX,AX           ; (CX) = start of DIR
  159. ;
  160. ; Take into account size of directory (only know number of directory entries)
  161. ;
  162.         MOV     AX,size DIR_ENT         ; bytes per directory entry
  163.         MUL     DirectoryEntries        ; convert to bytes in directory
  164.         MOV     BX,BytesPerSector       ; add in sector size
  165.         ADD     AX,BX
  166.         DEC     AX                      ; decrement so that we round up
  167.         DIV     BX                      ; convert to sector number
  168.         ADD     CX,AX
  169.         MOV     ClusterBase,CX          ; save it for later
  170. ;
  171. ; Load in the root directory.
  172. ;
  173. .386
  174.         push    DirSeg                  ; es:bx -> directory segment
  175. .8086
  176.         pop     es
  177. ASSUME  ES:DirSeg
  178.         xor     bx,bx
  179.         pop     Arguments.SectorBase.lsw
  180.         mov     Arguments.SectorBase.msw,bx
  181.  
  182. ;
  183. ; DoRead does a RETF, but LINK pukes if we do a FAR call in a /tiny program.
  184. ;
  185. ; (al) = # of sectors to read
  186. ;
  187.         push    cs
  188.         call    DoRead
  189.         jc      BootErr$he
  190.  
  191. ; Now we scan for the presence of NTLDR
  192.  
  193.         xor     bx,bx
  194.         mov     cx,DirectoryEntries
  195. L10:
  196.         mov     di,bx
  197.         push    cx
  198.         mov     cx,11
  199.         mov     si, offset LOADERNAME
  200.         repe    cmpsb
  201.         pop     cx
  202.         jz      L10end
  203.  
  204.         add     bx,size DIR_ENT
  205.         loop  L10
  206. L10end:
  207.  
  208.         jcxz    BootErr$bnf
  209.  
  210.         mov     dx,es:[bx].StartCluster ; (dx) = starting cluster number
  211.         push    dx
  212.         mov     ax,1                    ; (al) = sectors to read
  213. ;
  214. ; Now, go read the file
  215. ;
  216.  
  217. .386
  218.         push    NtLdrSeg
  219. .8086
  220.         pop     es
  221.     ASSUME  ES:NtLdrSeg
  222.         xor     bx,bx                   ; (es:bx) -> start of NTLDR
  223.  
  224.  
  225. ;
  226. ; LINK barfs if we do a FAR call in a TINY program, so we have to fake it
  227. ; out by pushing CS.
  228. ;
  229.  
  230.         push    cs
  231.         call    ClusterRead
  232.         jc      BootErr$he
  233.  
  234. ;
  235. ; NTLDR requires:
  236. ;   BX = Starting Cluster Number of NTLDR
  237. ;   DL = INT 13 drive number we booted from
  238. ;   DS:SI -> the boot media's BPB
  239. ;   DS:DI -> argument structure
  240. ;   1000:0000 - entire FAT is loaded
  241. ;
  242.  
  243.         pop     BX                      ; (bx) = Starting Cluster Number
  244.         lea     si,BPB                  ; ds:si -> BPB
  245.         lea     di,Arguments            ; ds:di -> Arguments
  246.  
  247.         push    ds
  248.         pop     [di].ReadClusters.msw
  249.         mov     [di].ReadClusters.lsw, offset ClusterRead
  250.         push    ds
  251.         pop     [di].ReadSectors.msw
  252.         mov     [di].ReadSectors.lsw, offset DoRead
  253.         MOV     dl,DriveNumber          ; dl = boot drive
  254.  
  255. ;
  256. ; FAR JMP to 2000:0003.  This is hand-coded, because I can't figure out
  257. ; how to make MASM do this for me.  By entering NTLDR here, we skip the
  258. ; initial jump and execute the FAT-specific code to load the rest of
  259. ; NTLDR.
  260. ;
  261.         db      0EAh                    ; JMP FAR PTR
  262.         dw      3                       ; 2000:3
  263.         dw      02000h
  264. FATBOOT endp
  265.  
  266. ; BootErr - print error message and hang the system.
  267. ;
  268. BootErr proc
  269. BootErr$bnf:
  270.         MOV     SI,OFFSET MSG_NO_NTLDR
  271.         jmp short BootErr2
  272. BootErr$he:
  273.         MOV     SI,OFFSET MSG_READ_ERROR
  274. BootErr2:
  275.         call    BootErrPrint
  276.         MOV     SI,OFFSET MSG_REBOOT_ERROR
  277.         call    BootErrPrint
  278.         sti
  279.         jmp     $                       ;Wait forever
  280.  
  281. BootErrPrint:
  282.           LODSB                         ; Get next character
  283.           or    al,al
  284.           jz    BEdone
  285.  
  286.           MOV     AH,14                   ; Write teletype
  287.           MOV     BX,7                    ; Attribute
  288.           INT     10H                     ; Print it
  289.           jmp   BootErrPrint
  290. BEdone:
  291.  
  292.         ret
  293. BootErr endp
  294.  
  295. ; ClusterRead - read AL sectors into ES:BX starting from
  296. ;       cluster DX
  297. ;
  298. ClusterRead proc
  299.         push    ax                      ; (TOS) = # of sectors to read
  300.         dec     dx
  301.         dec     dx                      ; adjust for reserved clusters 0 and 1
  302.         mov     al,SectorsPerCluster
  303.         xor     ah,ah
  304.         mul     dx                      ; DX:AX = starting sector number
  305.         add     ax,ClusterBase          ; adjust for FATs, root dir, boot sec.
  306.         adc     dx,0
  307.         mov     Arguments.SectorBase.lsw,ax
  308.         mov     Arguments.SectorBase.msw,dx
  309.         pop     ax                      ; (al) = # of sectors to read
  310.  
  311. ;
  312. ; Now we've converted the cluster number to a SectorBase, so just fall
  313. ; through into DoRead
  314. ;
  315.  
  316. ClusterRead endp
  317.  
  318.  
  319. ;
  320. ; DoRead - read AL sectors into ES:BX starting from sector
  321. ;          SectorBase.
  322. ;
  323. DoRead  proc
  324.  
  325.         mov     SectorCount,AL
  326. DRloop:
  327.         MOV     AX,Arguments.SectorBase.lsw     ; Starting sector
  328.         MOV     DX,Arguments.SectorBase.msw     ; Starting sector
  329. ;
  330. ; DoDiv - convert logical sector number in AX to physical Head/Track/Sector
  331. ;         in CurrentHead/CurrentTrack/CurrentSector.
  332. ;
  333.         ADD     AX,HiddenSectors.lsw    ;adjust for partition's base sector
  334.         ADC     DX,HiddenSectors.msw
  335.         DIV     SectorsPerTrack
  336.         INC     DL                      ; sector numbers are 1-based
  337.         MOV     CurrentSector,DL
  338.         XOR     DX,DX
  339.         DIV     Heads
  340.         MOV     CurrentHead,DL
  341.         MOV     CurrentTrack,AX
  342. ;
  343. ;DoDiv   endp
  344. ;
  345.  
  346.  
  347. ; CurrentHead is the head for this next disk request
  348. ; CurrentTrack is the track for this next request
  349. ; CurrentSector is the beginning sector number for this request
  350.  
  351. ; Compute the number of sectors that we may be able to read in a single ROM
  352. ; request.
  353.  
  354.         MOV     AX,SectorsPerTrack
  355.         SUB     AL,CurrentSector
  356.         INC     AX
  357.         cmp   al,SectorCount
  358.         jbe   DoCall
  359.         mov   al,SectorCount
  360.         xor   ah,ah
  361.  
  362. ; AX is the number of sectors that we may read.
  363.  
  364. ;
  365. ; DoCall - call ROM BIOS to read AL sectors into ES:BX.
  366. ;
  367. DoCall:
  368.         PUSH    AX
  369.         MOV     AH,2
  370.         MOV     cx,CurrentTrack
  371. .386
  372.         SHL     ch,6
  373. .8086
  374.         OR      ch,CurrentSector
  375.         XCHG    CH,CL
  376.         MOV     DX,WORD PTR DriveNumber
  377.         INT     13H
  378. ;
  379. ;DoCall  endp
  380. ;
  381.  
  382. .386
  383.         jnc     DcNoErr
  384.         add     sp,2
  385.         stc
  386.         retf
  387. .8086
  388.  
  389. DcNoErr:
  390.         POP     AX
  391.         SUB     SectorCount,AL          ; Are we finished?
  392.         jbe     DRdone
  393.         ADD     Arguments.SectorBase.lsw,AX       ; increment logical sector position
  394.         ADC     Arguments.SectorBase.msw,0
  395.         MUL     BytesPerSector          ; determine next offset for read
  396.         ADD     BX,AX                   ; (BX)=(BX)+(SI)*(Bytes per sector)
  397.  
  398.         jmp     DRloop
  399. DRdone:
  400.         mov     SectorCount,al
  401.         clc
  402.         retf
  403. DoRead  endp
  404.  
  405.         include fatboot.inc             ;suck in the message text
  406.  
  407. LOADERNAME      DB      "NTLDR      "
  408.  
  409.     .errnz  ($-FATBOOT) GT 510,<FATAL PROBLEM: boot sector is too large>
  410.  
  411.         org     510
  412.         db      55h,0aah
  413.  
  414. BootSectorEnd   label   dword
  415.  
  416. BootCode        ends
  417.  
  418. ;Unitialized variables go here--beyond the end of the boot sector in free memory
  419. CurrentTrack    equ word ptr BootSectorEnd + 4  ; current track
  420. CurrentSector   equ byte ptr BootSectorEnd + 6  ; current sector
  421. SectorCount     equ byte ptr BootSectorEnd + 7  ; number of sectors to read
  422. ClusterBase     equ word ptr BootSectorEnd + 8  ; first sector of cluster # 2
  423. Retries         equ byte ptr BootSectorEnd + 10
  424. Arguments       equ byte ptr BootSectorEnd + 11 ; structure passed to NTLDR
  425.  
  426.         END     FATBOOT
  427.  
Advertisement
Add Comment
Please, Sign In to add comment