wok diff BootProg/stuff/boot32.asm @ rev 24476

Add some current_version
author Pascal Bellard <pascal.bellard@slitaz.org>
date Fri Feb 18 09:29:30 2022 +0000 (2022-02-18)
parents
children 04472f031354
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/BootProg/stuff/boot32.asm	Fri Feb 18 09:29:30 2022 +0000
     1.3 @@ -0,0 +1,543 @@
     1.4 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     1.5 +;;                                                                          ;;
     1.6 +;;         "BootProg" Loader v 1.5 by Alexey Frunze (c) 2000-2015           ;;
     1.7 +;;                           2-clause BSD license.                          ;;
     1.8 +;;                                                                          ;;
     1.9 +;;                                                                          ;;
    1.10 +;;                              How to Compile:                             ;;
    1.11 +;;                              ~~~~~~~~~~~~~~~                             ;;
    1.12 +;; nasm boot32.asm -f bin -o boot32.bin                                     ;;
    1.13 +;;                                                                          ;;
    1.14 +;;                                                                          ;;
    1.15 +;;                                 Features:                                ;;
    1.16 +;;                                 ~~~~~~~~~                                ;;
    1.17 +;; - FAT32 supported using BIOS int 13h function 42h or 02h.                ;;
    1.18 +;;                                                                          ;;
    1.19 +;; - Loads a 16-bit executable file in the MS-DOS .COM or .EXE format       ;;
    1.20 +;;   from the root directory of a disk and transfers control to it          ;;
    1.21 +;;   (the "ProgramName" variable holds the name of the file to be loaded)   ;;
    1.22 +;;   Its maximum size can be up to 636KB without Extended BIOS Data area.   ;;
    1.23 +;;                                                                          ;;
    1.24 +;; - Prints an error if the file isn't found or couldn't be read            ;;
    1.25 +;;   ("File not found" or "Read error")                                     ;;
    1.26 +;;   and waits for a key to be pressed, then executes the Int 19h           ;;
    1.27 +;;   instruction and lets the BIOS continue bootstrap.                      ;;
    1.28 +;;                                                                          ;;
    1.29 +;;                                                                          ;;
    1.30 +;;                             Known Limitations:                           ;;
    1.31 +;;                             ~~~~~~~~~~~~~~~~~~                           ;;
    1.32 +;; - Works only on the 1st MBR partition which must be a PRI DOS partition  ;;
    1.33 +;;   with FAT32 (File System ID: 0Bh,0Ch)                                   ;;
    1.34 +;;                                                                          ;;
    1.35 +;;                                                                          ;;
    1.36 +;;                                Known Bugs:                               ;;
    1.37 +;;                                ~~~~~~~~~~~                               ;;
    1.38 +;; - All bugs are fixed as far as I know. The boot sector has been tested   ;;
    1.39 +;;   on my HDD and an 8GB USB stick.                                        ;;
    1.40 +;;                                                                          ;;
    1.41 +;;                                                                          ;;
    1.42 +;;                               Memory Layout:                             ;;
    1.43 +;;                               ~~~~~~~~~~~~~~                             ;;
    1.44 +;; The diagram below shows the typical memory layout. The actual location   ;;
    1.45 +;; of the boot sector and its stack may be lower than A0000H if the BIOS    ;;
    1.46 +;; reserves memory for its Extended BIOS Data Area just below A0000H and    ;;
    1.47 +;; reports less than 640 KB of RAM via its Int 12H function.                ;;
    1.48 +;;                                                                          ;;
    1.49 +;;                                            physical address              ;;
    1.50 +;;                 +------------------------+ 00000H                        ;;
    1.51 +;;                 | Interrupt Vector Table |                               ;;
    1.52 +;;                 +------------------------+ 00400H                        ;;
    1.53 +;;                 |     BIOS Data Area     |                               ;;
    1.54 +;;                 +------------------------+ 00500H                        ;;
    1.55 +;;                 | PrtScr Status / Unused |                               ;;
    1.56 +;;                 +------------------------+ 00600H                        ;;
    1.57 +;;                 |      Loaded Image      |                               ;;
    1.58 +;;                 +------------------------+ nnnnnH                        ;;
    1.59 +;;                 |    Available Memory    |                               ;;
    1.60 +;;                 +------------------------+ A0000H - 2KB                  ;;
    1.61 +;;                 |       Boot Sector      |                               ;;
    1.62 +;;                 +------------------------+ A0000H - 1.5KB                ;;
    1.63 +;;                 |    1.5KB Boot Stack    |                               ;;
    1.64 +;;                 +------------------------+ A0000H                        ;;
    1.65 +;;                 |        Video RAM       |                               ;;
    1.66 +;;                                                                          ;;
    1.67 +;;                                                                          ;;
    1.68 +;;                   Boot Image Startup (register values):                  ;;
    1.69 +;;                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                  ;;
    1.70 +;;  dl = BIOS boot drive number (e.g. 80H)                                  ;;
    1.71 +;;  cs:ip = program entry point                                             ;;
    1.72 +;;  ss:sp = program stack (don't confuse with boot sector's stack)          ;;
    1.73 +;;  COM program defaults: cs = ds = es = ss = 50h, sp = 0, ip = 100h        ;;
    1.74 +;;  EXE program defaults: ds = es = EXE data - 10h (fake MS-DOS psp),       ;;
    1.75 +;;  ax = 0ffffh (both FCB in the PSP don't have a valid drive identifier),  ;;
    1.76 +;;  cs:ip and ss:sp depends on EXE header                                   ;;
    1.77 +;;  Magic numbers:                                                          ;;
    1.78 +;;    si = 16381 (prime number 2**14-3)                                     ;;
    1.79 +;;    di = 32749 (prime number 2**15-19)                                    ;;
    1.80 +;;    bp = 65521 (prime number 2**16-15)                                    ;;
    1.81 +;;  The magic numbers let the program know whether it has been loaded by    ;;
    1.82 +;;  this boot sector or by MS-DOS, which may be handy for universal, bare-  ;;
    1.83 +;;  metal and MS-DOS programs.                                              ;;
    1.84 +;;                                                                          ;;
    1.85 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    1.86 +
    1.87 +%define bx(label)       bx+label-boot
    1.88 +
    1.89 +[BITS 16]
    1.90 +[CPU 8086]
    1.91 +
    1.92 +?                       equ     0
    1.93 +ImageLoadSeg            equ     60h
    1.94 +StackSize               equ     1536
    1.95 +
    1.96 +[SECTION .text]
    1.97 +[ORG 0]
    1.98 +
    1.99 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.100 +;; Boot sector starts here ;;
   1.101 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.102 +
   1.103 +boot:
   1.104 +        jmp     short   start                   ; MS-DOS/Windows checks for this jump
   1.105 +        nop
   1.106 +bsOemName               DB      "BootProg"      ; 0x03
   1.107 +
   1.108 +;;;;;;;;;;;;;;;;;;;;;;
   1.109 +;; BPB1 starts here ;;
   1.110 +;;;;;;;;;;;;;;;;;;;;;;
   1.111 +
   1.112 +bpbBytesPerSector       DW      ?               ; 0x0B
   1.113 +bpbSectorsPerCluster    DB      ?               ; 0x0D
   1.114 +bpbReservedSectors      DW      ?               ; 0x0E
   1.115 +bpbNumberOfFATs         DB      ?               ; 0x10
   1.116 +bpbRootEntries          DW      ?               ; 0x11
   1.117 +bpbTotalSectors         DW      ?               ; 0x13
   1.118 +bpbMedia                DB      ?               ; 0x15
   1.119 +bpbSectorsPerFAT        DW      ?               ; 0x16
   1.120 +bpbSectorsPerTrack      DW      ?               ; 0x18
   1.121 +bpbHeadsPerCylinder     DW      ?               ; 0x1A
   1.122 +bpbHiddenSectors        DD      ?               ; 0x1C
   1.123 +bpbTotalSectorsBig      DD      ?               ; 0x20
   1.124 +
   1.125 +;;;;;;;;;;;;;;;;;;;;
   1.126 +;; BPB1 ends here ;;
   1.127 +;;;;;;;;;;;;;;;;;;;;
   1.128 +
   1.129 +;;;;;;;;;;;;;;;;;;;;;;
   1.130 +;; BPB2 starts here ;;
   1.131 +;;;;;;;;;;;;;;;;;;;;;;
   1.132 +
   1.133 +bsSectorsPerFAT32               DD      ?               ; 0x24
   1.134 +bsExtendedFlags                 DW      ?               ; 0x28
   1.135 +bsFSVersion                     DW      ?               ; 0x2A
   1.136 +bsRootDirectoryClusterNo        DD      ?               ; 0x2C
   1.137 +bsFSInfoSectorNo                DW      ?               ; 0x30
   1.138 +bsBackupBootSectorNo            DW      ?               ; 0x32
   1.139 +bsreserved             times 12 DB      ?               ; 0x34
   1.140 +bsDriveNumber                   DB      ?               ; 0x40
   1.141 +bsreserved1                     DB      ?               ; 0x41
   1.142 +bsExtendedBootSignature         DB      ?               ; 0x42
   1.143 +bsVolumeSerialNumber            DD      ?               ; 0x43
   1.144 +bsVolumeLabel                   DB      "NO NAME    "   ; 0x47
   1.145 +bsFileSystemName                DB      "FAT32   "      ; 0x52
   1.146 +
   1.147 +;;;;;;;;;;;;;;;;;;;;
   1.148 +;; BPB2 ends here ;;
   1.149 +;;;;;;;;;;;;;;;;;;;;
   1.150 +
   1.151 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.152 +;; Boot sector code starts here ;;
   1.153 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.154 +
   1.155 +start:
   1.156 +        cld
   1.157 +
   1.158 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.159 +;; How much RAM is there? ;;
   1.160 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.161 +
   1.162 +        int     12h             ; get conventional memory size (in KBs)
   1.163 +        mov     cx, 106h
   1.164 +        dec     ax
   1.165 +        dec     ax              ; reserve 2K bytes for the code and the stack
   1.166 +        shl     ax, cl          ; and convert it to 16-byte paragraphs
   1.167 +
   1.168 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.169 +;; Reserve memory for the boot sector and its stack ;;
   1.170 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.171 +
   1.172 +        mov     es, ax                  ; cs:0 = ds:0 = ss:0 -> top - 512 - StackSize
   1.173 +        mov     ss, ax
   1.174 +        mov     sp, 512+StackSize       ; bytes 0-511 are reserved for the boot code
   1.175 +
   1.176 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.177 +;; Copy ourselves to top of memory ;;
   1.178 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.179 +
   1.180 +        mov     si, 7C00h
   1.181 +        xor     di, di
   1.182 +        mov     ds, di
   1.183 +        rep     movsw                   ; move 512 bytes (+ 12)
   1.184 +
   1.185 +;;;;;;;;;;;;;;;;;;;;;;
   1.186 +;; Jump to the copy ;;
   1.187 +;;;;;;;;;;;;;;;;;;;;;;
   1.188 +
   1.189 +        push    es
   1.190 +        mov     cl, main
   1.191 +        push    cx
   1.192 +        retf
   1.193 +
   1.194 +main:
   1.195 +        push    cs
   1.196 +        pop     ds
   1.197 +
   1.198 +        xor     bx, bx
   1.199 +        mov     [bx], dx                ; store BIOS boot drive number
   1.200 +
   1.201 +        and     byte [bx(bsRootDirectoryClusterNo)+3], 0Fh ; mask cluster value
   1.202 +        les     si, [bx(bsRootDirectoryClusterNo)] ; si2:si=cluster # of root dir
   1.203 +        mov     si2, es
   1.204 +
   1.205 +        mov     cl, ImageLoadSeg
   1.206 +        mov     es, cx
   1.207 +
   1.208 +RootDirReadContinue:
   1.209 +        call    ReadCluster             ; read one sector of root dir; clear ch
   1.210 +        pushf                           ; save carry="not last sector" flag
   1.211 +
   1.212 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.213 +;; Look for the COM/EXE file to load and run ;;
   1.214 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.215 +
   1.216 +        xor     di, di                  ; es:di -> root entries array
   1.217 +
   1.218 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.219 +;; Looks for the file/dir ProgramName    ;;
   1.220 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.221 +;; Input:  ES:DI -> root directory array ;;
   1.222 +;;         BP = paragraphs count         ;;
   1.223 +;; Output: ESI = cluster number          ;;
   1.224 +;;         DI = file paragraph count     ;;
   1.225 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.226 +
   1.227 +FindNameCycle:
   1.228 +        cmp     byte [es:di], bh
   1.229 +        je      FindNameFailed          ; end of root directory (NULL entry found)
   1.230 +        push    si
   1.231 +        push    di
   1.232 +        mov     cl, 11
   1.233 +        mov     si, ProgramName         ; ds:si -> program name
   1.234 +        repe    cmpsb
   1.235 +        pop     di
   1.236 +        pop     si
   1.237 +        je      FindNameFound
   1.238 +        add     di, 32                  ; max cluster = 64k
   1.239 +        dec     bp
   1.240 +        dec     bp
   1.241 +        jnz     FindNameCycle           ; next root entry
   1.242 +        popf                            ; restore carry="not last sector" flag
   1.243 +        jc      RootDirReadContinue     ; continue to the next root dir cluster
   1.244 +FindNameFailed:                         ; end of root directory (dir end reached)
   1.245 +        call    Error
   1.246 +        db      "File not found."
   1.247 +FindNameFound:
   1.248 +        mov     si2, word [es:di+14h]
   1.249 +        mov     si, word [es:di+1Ah]    ; si2:si = cluster no; cx = 0.
   1.250 +
   1.251 +==============
   1.252 +        dec     dword [es:di+1Ch]       ; load ((n - 1)/256)*16 +1 paragraphs
   1.253 +        imul    di, [es:di+1Dh], 16     ; file size in paragraphs (full pages)
   1.254 +
   1.255 +;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.256 +;; Load the entire file ;;
   1.257 +;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.258 +
   1.259 +        push    es
   1.260 +FileReadContinue:
   1.261 +        push    di
   1.262 +        call    ReadCluster             ; read one more sector
   1.263 +        mov     di, es
   1.264 +        add     di, bp                  ; adjust segment for next sector
   1.265 +        mov     es, di                  ; es:0 updated
   1.266 +        pop     di
   1.267 +        sub     di, bp
   1.268 +        jae     FileReadContinue
   1.269 +==============
   1.270 +        pop     bp
   1.271 +
   1.272 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.273 +;; Type detection, .COM or .EXE? ;;
   1.274 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.275 +
   1.276 +        mov     dl, [bx]                ; pass the BIOS boot drive
   1.277 +        mov     ds, bp                  ; bp=ds=seg the file is loaded to
   1.278 +
   1.279 +        add     bp, [bx+08h]            ; bp = image base
   1.280 +        mov     ax, [bx+06h]            ; ax = reloc items
   1.281 +        mov     di, [bx+18h]            ; di = reloc table pointer
   1.282 +
   1.283 +        cmp     word [bx], 5A4Dh        ; "MZ" signature?
   1.284 +        je      RelocateEXE             ; yes, it's an EXE program
   1.285 +
   1.286 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.287 +;; Setup and run a .COM program ;;
   1.288 +;; Set CS=DS=ES=SS SP=0 IP=100h ;;
   1.289 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.290 +
   1.291 +        mov     bp, ImageLoadSeg-10h    ; "org 100h" stuff :)
   1.292 +        mov     ss, bp
   1.293 +        xor     sp, sp
   1.294 +        push    bp                      ; cs, ds and es
   1.295 +        mov     bh, 1                   ; ip
   1.296 +        jmp     short Run
   1.297 +
   1.298 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.299 +;; Relocate, setup and run a .EXE program     ;;
   1.300 +;; Set CS:IP, SS:SP, DS, ES and AX according  ;;
   1.301 +;; to wiki.osdev.org/MZ#Initial_Program_State ;;
   1.302 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.303 +
   1.304 +ReloCycle:
   1.305 +        add     [di+2], bp              ; item seg (abs)
   1.306 +        les     si, [di]                ; si = item ofs, es = item seg
   1.307 +        add     [es:si], bp             ; fixup
   1.308 +        scasw                           ; di += 2
   1.309 +        scasw                           ; point to next entry
   1.310 +
   1.311 +RelocateEXE:
   1.312 +        dec     ax                      ; 32768 max (128KB table)
   1.313 +        jns     ReloCycle               ; leave with ax=0ffffh: both FCB in the
   1.314 +                                        ; PSP don't have a valid drive identifier
   1.315 +        les     si, [bx+0Eh]
   1.316 +        add     si, bp
   1.317 +        mov     ss, si                  ; ss for EXE
   1.318 +        mov     sp, es                  ; sp for EXE
   1.319 +
   1.320 +        lea     si, [bp-10h]            ; ds and es both point to the segment
   1.321 +        push    si                      ; containing the PSP structure
   1.322 +
   1.323 +        add     bp, [bx+16h]            ; cs for EXE
   1.324 +        mov     bx, [bx+14h]            ; ip for EXE
   1.325 +Run:
   1.326 +        pop     ds
   1.327 +        push    bp
   1.328 +        push    bx
   1.329 +        push    ds
   1.330 +        pop     es
   1.331 +
   1.332 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.333 +;; Set the magic numbers so the program knows that it   ;;
   1.334 +;; has been loaded by this bootsector and not by MS-DOS ;;
   1.335 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.336 +        mov     si, 16381 ; prime number 2**14-3
   1.337 +        mov     di, 32749 ; prime number 2**15-19
   1.338 +        mov     bp, 65521 ; prime number 2**16-15
   1.339 +
   1.340 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.341 +;; All done, transfer control to the program now ;;
   1.342 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.343 +        retf
   1.344 +
   1.345 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.346 +;; Reads a FAT32 cluster         ;;
   1.347 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.348 +;; Input:  ES:0 -> buffer        ;;
   1.349 +;;       EDX:EAX = sector no     ;;
   1.350 +;;          CX = sectors to load ;;
   1.351 +;;           ESI = cluster no    ;;
   1.352 +;;         BX    = 0             ;;
   1.353 +;; Output: ES:0 -> buffer        ;;
   1.354 +;;       EDX:EAX = sector no     ;;
   1.355 +;;          CX = sectors to load ;;
   1.356 +;;           ESI = next cluster  ;;
   1.357 +;;         BX    = 0             ;;
   1.358 +;;         CH    = 0             ;;
   1.359 +;;         BP    = para/sector   ;;
   1.360 +;;         C=0 for last sector   ;;
   1.361 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.362 +
   1.363 +ReadCluster:
   1.364 +==============
   1.365 +        mov     bp, word [bx(bpbBytesPerSector)]
   1.366 +        shr     bp, 4                           ; paragraphs per sector
   1.367 +        inc     cx
   1.368 +        add     ax, 1                           ; adjust LBA for next sector
   1.369 +?        adc     dx, bx
   1.370 +        loop    ReadSectorLBANext
   1.371 +
   1.372 +        imul    ax, bp, 2
   1.373 +        cwde                                    ; eax=# of FAT32 entries per sector
   1.374 +        lea     edi, [esi-2]                    ; edi=cluster #-2
   1.375 +        xchg    eax, esi
   1.376 +        cdq
   1.377 +        div     esi                             ; eax=FAT sector #, edx=entry # in sector < 128
   1.378 +
   1.379 +        imul    si, dx, 4                       ; si=entry # offset in sector
   1.380 +
   1.381 +        call    ReadSectorLBA                   ; read 1 FAT32 sector
   1.382 +
   1.383 +        mov     si2, 0FFFh
   1.384 +        and     si2, [es:si+2]                  ; mask cluster value
   1.385 +        mov     si, [es:si]                     ; si2:si=next cluster #
   1.386 +
   1.387 +        movzx   eax, byte [bx(bpbNumberOfFATs)]
   1.388 +        mul     dword [bx(bsSectorsPerFAT32)]   ; edx < 256
   1.389 +
   1.390 +        xchg    eax, edi                        ; get cluster #-2 ; save data offset
   1.391 +
   1.392 +        movzx   ecx, byte [bx(bpbSectorsPerCluster)]
   1.393 +        mul     ecx
   1.394 +
   1.395 +        add     eax, edi                        ; sector # relative to FAT32
   1.396 +
   1.397 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.398 +;; Reads a sector using BIOS Int 13h ;;
   1.399 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.400 +;; Input:  ES:0 -> buffer address    ;;
   1.401 +;;         EAX   = LBA (FAT based)   ;;
   1.402 +;;         BX    = 0                 ;;
   1.403 +;;         CX    = sector count      ;;
   1.404 +;; Output: ES:0 -> buffer address    ;;
   1.405 +;;       EDX:EAX = absolute LBA      ;;
   1.406 +;;         BX    = 0                 ;;
   1.407 +;;         CX    = next sector count ;;
   1.408 +;;         BP    = paragraphs/sector ;;
   1.409 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.410 +
   1.411 +ReadSectorLBA:
   1.412 +
   1.413 +        mov     dx, word [bx(bpbReservedSectors)]
   1.414 +        add     eax, edx
   1.415 +        mov     dx, bx
   1.416 +        adc     dx, bx
   1.417 +        add     eax, [bx(bpbHiddenSectors)]
   1.418 +
   1.419 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.420 +;; Input:  ES:0 -> buffer address    ;;
   1.421 +;;       EDX:EAX = absolute LBA      ;;
   1.422 +;;         BX    = 0                 ;;
   1.423 +;;         CX    = sector count      ;;
   1.424 +;; Output: ES:0 -> buffer address    ;;
   1.425 +;;       EDX:EAX = absolute LBA      ;;
   1.426 +;;         BX    = 0                 ;;
   1.427 +;;         CX    = next sector count ;;
   1.428 +;;         BP    = paragraphs/sector ;;
   1.429 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.430 +
   1.431 +ReadSectorLBANext:
   1.432 +
   1.433 +        adc     dx, bx  ; FAT32 partition can start up to 2TB
   1.434 +
   1.435 +        pusha
   1.436 +
   1.437 +        push    edx     ; 33-bit LBA only: up to 4TB disks
   1.438 +        push    eax     ; 32-bit LBA: up to 2TB FAT32 partition start
   1.439 +        push    es
   1.440 +        push    bx
   1.441 +        push    byte 1  ; sector count word = 1
   1.442 +        push    byte 16 ; packet size byte = 16, reserved byte = 0
   1.443 +        
   1.444 +        push    eax
   1.445 +        pop     cx                      ; low LBA
   1.446 +        pop     ax                      ; high LBA, dx=0 (<2TB)
   1.447 +        div     word [bx(bpbSectorsPerTrack)] ; up to 8GB disks
   1.448 +
   1.449 +        xchg    ax, cx                  ; restore low LBA, save high LBA / SPT
   1.450 +        div     word [bx(bpbSectorsPerTrack)]
   1.451 +                ; ax = LBA / SPT
   1.452 +                ; dx = LBA % SPT         = sector - 1
   1.453 +        inc     dx
   1.454 +
   1.455 +        xchg    cx, dx                  ; restore high LBA / SPT, save sector no.
   1.456 +        div     word [bx(bpbHeadsPerCylinder)]
   1.457 +                ; ax = (LBA / SPT) / HPC = cylinder
   1.458 +                ; dx = (LBA / SPT) % HPC = head
   1.459 +        shl     ah, 6
   1.460 +        mov     ch, al
   1.461 +                ; ch = LSB 0...7 of cylinder no.
   1.462 +        or      cl, ah
   1.463 +                ; cl = MSB 8...9 of cylinder no. + sector no.
   1.464 +        mov     dh, dl
   1.465 +                ; dh = head no.
   1.466 +
   1.467 +ReadSectorLBARetry:
   1.468 +        mov     dl, [bx]
   1.469 +                ; dl = drive no.
   1.470 +        mov     si, sp
   1.471 +        mov     ah, 42h                 ; ah = 42h = extended read function no.
   1.472 +        int     13h                     ; extended read sectors (DL, DS:SI)
   1.473 +        jnc     ReadSectorNextSegment
   1.474 +
   1.475 +ReadSectorCHSRetry:
   1.476 +        mov     ax, 201h                ; al = sector count = 1
   1.477 +                                        ; ah = 2 = read function no.
   1.478 +        int     13h                     ; read sectors (AL, CX, DX, ES:BX)
   1.479 +        jnc     ReadSectorNextSegment
   1.480 +
   1.481 +        cbw                             ; ah = 0 = reset function
   1.482 +        int     13h                     ; reset drive (DL)
   1.483 +
   1.484 +        dec     bp
   1.485 +        jnz     ReadSectorLBARetry
   1.486 +
   1.487 +        call    Error
   1.488 +        db      "Read error."
   1.489 +
   1.490 +ReadSectorNextSegment:
   1.491 +
   1.492 +        popa                            ; sp += 16
   1.493 +        popa                            ; restore real registers
   1.494 +==============
   1.495 +        stc
   1.496 +        loop    ReadSectorDone
   1.497 +
   1.498 +        cmp     si2, 0FFFh
   1.499 +        jne     ReadSectorDone
   1.500 +        cmp     si, 0FFF8h              ; carry=0 if last cluster, and carry=1 otherwise
   1.501 +
   1.502 +ReadSectorDone:
   1.503 +        ret
   1.504 +
   1.505 +;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.506 +;; Error Messaging Code ;;
   1.507 +;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.508 +
   1.509 +Error:
   1.510 +        pop     si
   1.511 +        mov     dl, [bx]                ; restore BIOS boot drive number
   1.512 +        mov     ah, 0Eh
   1.513 +        mov     bl, 7
   1.514 +
   1.515 +PutStr:
   1.516 +        lodsb
   1.517 +        int     10h
   1.518 +        cmp     al, "."
   1.519 +        jne     PutStr
   1.520 +
   1.521 +        cbw
   1.522 +        int     16h                     ; wait for a key...
   1.523 +        int     19h                     ; bootstrap
   1.524 +
   1.525 +Stop:
   1.526 +        hlt
   1.527 +        jmp     short Stop
   1.528 +
   1.529 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.530 +;; Fill free space with zeroes ;;
   1.531 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.532 +
   1.533 +                times (512-13-($-$$)) db 0
   1.534 +
   1.535 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.536 +;; Name of the file to load and run ;;
   1.537 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.538 +
   1.539 +ProgramName     db      "STARTUP BIN"   ; name and extension each must be
   1.540 +                                        ; padded with spaces (11 bytes total)
   1.541 +
   1.542 +;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.543 +;; End of the sector ID ;;
   1.544 +;;;;;;;;;;;;;;;;;;;;;;;;;;
   1.545 +
   1.546 +                dw      0AA55h          ; BIOS checks for this ID