wok diff BootProg/stuff/boot16.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/boot16.asm Fri Feb 18 09:29:30 2022 +0000 1.3 @@ -0,0 +1,593 @@ 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 boot16.asm -f bin -o boot16.bin ;; 1.13 +;; ;; 1.14 +;; ;; 1.15 +;; Features: ;; 1.16 +;; ~~~~~~~~~ ;; 1.17 +;; - FAT12 and FAT16 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 635KB 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 +;; - cpu 8086 is supported ;; 1.30 +;; ;; 1.31 +;; ;; 1.32 +;; Known Limitations: ;; 1.33 +;; ~~~~~~~~~~~~~~~~~~ ;; 1.34 +;; - Works only on the 1st MBR partition which must be a PRI DOS partition ;; 1.35 +;; with FAT12 (File System ID: 1) and FAT16 (File System ID: 4, 6) ;; 1.36 +;; ;; 1.37 +;; ;; 1.38 +;; Known Bugs: ;; 1.39 +;; ~~~~~~~~~~~ ;; 1.40 +;; - All bugs are fixed as far as I know. The boot sector has been tested ;; 1.41 +;; on the following types of diskettes (FAT12): ;; 1.42 +;; - 360KB 5"25 ;; 1.43 +;; - 1.2MB 5"25 ;; 1.44 +;; - 1.44MB 3"5 ;; 1.45 +;; on my HDD (FAT16). ;; 1.46 +;; ;; 1.47 +;; ;; 1.48 +;; Memory Layout: ;; 1.49 +;; ~~~~~~~~~~~~~~ ;; 1.50 +;; The diagram below shows the typical memory layout. The actual location ;; 1.51 +;; of the boot sector and its stack may be lower than A0000H if the BIOS ;; 1.52 +;; reserves memory for its Extended BIOS Data Area just below A0000H and ;; 1.53 +;; reports less than 640 KB of RAM via its Int 12H function. ;; 1.54 +;; ;; 1.55 +;; physical address ;; 1.56 +;; +------------------------+ 00000H ;; 1.57 +;; | Interrupt Vector Table | ;; 1.58 +;; +------------------------+ 00400H ;; 1.59 +;; | BIOS Data Area | ;; 1.60 +;; +------------------------+ 00500H ;; 1.61 +;; | PrtScr Status / Unused | ;; 1.62 +;; +------------------------+ 00600H ;; 1.63 +;; | Loaded Image | ;; 1.64 +;; +------------------------+ nnnnnH ;; 1.65 +;; | Available Memory | ;; 1.66 +;; +------------------------+ A0000H - 512 - 3KB ;; 1.67 +;; | Boot Sector | ;; 1.68 +;; +------------------------+ A0000H - 3KB ;; 1.69 +;; | 3KB Boot Stack | ;; 1.70 +;; +------------------------+ A0000H ;; 1.71 +;; | Video RAM | ;; 1.72 +;; ;; 1.73 +;; ;; 1.74 +;; Boot Image Startup (register values): ;; 1.75 +;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ;; 1.76 +;; dl = BIOS boot drive number (e.g. 0, 80H) ;; 1.77 +;; cs:ip = program entry point ;; 1.78 +;; ss:sp = program stack (don't confuse with boot sector's stack) ;; 1.79 +;; COM program defaults: cs = ds = es = ss = 50h, sp = 0, ip = 100h ;; 1.80 +;; EXE program defaults: ds = es = EXE data - 10h (fake MS-DOS psp), ;; 1.81 +;; ax = 0ffffh (both FCB in the PSP don't have a valid drive identifier), ;; 1.82 +;; cs:ip and ss:sp depends on EXE header ;; 1.83 +;; Magic numbers: ;; 1.84 +;; si = 16381 (prime number 2**14-3) ;; 1.85 +;; di = 32749 (prime number 2**15-19) ;; 1.86 +;; bp = 65521 (prime number 2**16-15) ;; 1.87 +;; The magic numbers let the program know whether it has been loaded by ;; 1.88 +;; this boot sector or by MS-DOS, which may be handy for universal, bare- ;; 1.89 +;; metal and MS-DOS programs. ;; 1.90 +;; ;; 1.91 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.92 + 1.93 +%define bx(label) bx+label-boot 1.94 + 1.95 +[BITS 16] 1.96 +[CPU 8086] 1.97 + 1.98 +? equ 0 1.99 +ImageLoadSeg equ 60h 1.100 +StackSize equ 3072 ; Stack + cluster list 1.101 + 1.102 +[SECTION .text] 1.103 +[ORG 0] 1.104 + 1.105 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.106 +;; Boot sector starts here ;; 1.107 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.108 + 1.109 +boot: 1.110 + jmp short start ; MS-DOS/Windows checks for this jump 1.111 + nop 1.112 +bsOemName DB "BootProg" ; 0x03 1.113 + 1.114 +;;;;;;;;;;;;;;;;;;;;; 1.115 +;; BPB starts here ;; 1.116 +;;;;;;;;;;;;;;;;;;;;; 1.117 + 1.118 +bpbBytesPerSector DW ? ; 0x0B 1.119 +bpbSectorsPerCluster DB ? ; 0x0D 1.120 +bpbReservedSectors DW ? ; 0x0E 1.121 +bpbNumberOfFATs DB ? ; 0x10 1.122 +bpbRootEntries DW ? ; 0x11 1.123 +bpbTotalSectors DW ? ; 0x13 1.124 +bpbMedia DB ? ; 0x15 1.125 +bpbSectorsPerFAT DW ? ; 0x16 1.126 +bpbSectorsPerTrack DW ? ; 0x18 1.127 +bpbHeadsPerCylinder DW ? ; 0x1A 1.128 +bpbHiddenSectors DD ? ; 0x1C 1.129 +bpbTotalSectorsBig DD ? ; 0x20 1.130 + 1.131 +;;;;;;;;;;;;;;;;;;; 1.132 +;; BPB ends here ;; 1.133 +;;;;;;;;;;;;;;;;;;; 1.134 + 1.135 +bsDriveNumber DB ? ; 0x24 1.136 +bsUnused DB ? ; 0x25 1.137 +bsExtBootSignature DB ? ; 0x26 1.138 +bsSerialNumber DD ? ; 0x27 1.139 +bsVolumeLabel DB "NO NAME " ; 0x2B 1.140 +bsFileSystem DB "FAT12 " ; 0x36 1.141 + 1.142 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.143 +;; Boot sector code starts here ;; 1.144 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.145 + 1.146 +start: 1.147 + cld 1.148 + 1.149 +;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.150 +;; How much RAM is there? ;; 1.151 +;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.152 + 1.153 + int 12h ; get conventional memory size (in KBs) 1.154 + mov cx, 106h 1.155 + shl ax, cl ; and convert it to 16-byte paragraphs 1.156 + 1.157 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.158 +;; Reserve memory for the boot sector and its stack ;; 1.159 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.160 + 1.161 + sub ax, (512+StackSize) /16 ; reserve bytes for the code and the stack 1.162 + mov es, ax ; cs:0 = ds:0 = ss:0 -> top - 512 - StackSize 1.163 + mov ss, ax 1.164 + mov sp, 512+StackSize ; bytes 0-511 are reserved for the boot code 1.165 + 1.166 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.167 +;; Copy ourselves to top of memory ;; 1.168 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.169 + 1.170 + mov si, 7C00h 1.171 + xor di, di 1.172 + mov ds, di 1.173 + mov [si], dx ; store BIOS boot drive number 1.174 + rep movsw ; move 512 bytes (+ 12) 1.175 + 1.176 +;;;;;;;;;;;;;;;;;;;;;; 1.177 +;; Jump to the copy ;; 1.178 +;;;;;;;;;;;;;;;;;;;;;; 1.179 + 1.180 + push es 1.181 + mov cl, byte main 1.182 + push cx 1.183 + retf 1.184 + 1.185 +main: 1.186 + %if ImageLoadSeg != main-boot 1.187 + %if ImageLoadSeg >= 100h 1.188 + mov cx, ImageLoadSeg 1.189 + %else 1.190 + mov cl, ImageLoadSeg 1.191 + %endif 1.192 + %endif 1.193 + push cx 1.194 + 1.195 +;;;;;;;;;;;;;;;;;;;;;;;;;; 1.196 +;; Get drive parameters ;; 1.197 +;; Update heads count ;; 1.198 +;; for current BIOS ;; 1.199 +;;;;;;;;;;;;;;;;;;;;;;;;;; 1.200 + 1.201 + mov ah, 8 1.202 + int 13h ; may destroy SI,BP, and DS registers 1.203 + ; update AX,BL,CX,DX,DI, and ES registers 1.204 + push cs 1.205 + pop ds 1.206 + xor bx, bx 1.207 + 1.208 + and cx, 3Fh 1.209 + cmp [bx(bpbSectorsPerTrack)], cx 1.210 + jne BadParams ; verify updated and validity 1.211 + mov al, dh 1.212 + inc ax 1.213 + mov [bpbHeadsPerCylinder], ax 1.214 +BadParams: 1.215 + 1.216 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.217 +;; Load FAT (FAT12: 6KB max, FAT16: 128KB max) ;; 1.218 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.219 + 1.220 + pop es ; ImageLoadSeg 1.221 + push es 1.222 + 1.223 + mul bx ; dx:ax = 0 = LBA (LBA are relative to FAT) 1.224 + mov cx, word [bx(bpbSectorsPerFAT)] 1.225 + 1.226 + call ReadCXSectors ; read fat and clear cx 1.227 + 1.228 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.229 +;; load the root directory in ;; 1.230 +;; its entirety (16KB max) ;; 1.231 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.232 + 1.233 + mov ax, 32 1.234 + 1.235 + mul word [bx(bpbRootEntries)] 1.236 + div word [bx(bpbBytesPerSector)] 1.237 + xchg ax, cx ; cx = root directory size in sectors, clear ax 1.238 + 1.239 + mov al, [bpbNumberOfFATs] 1.240 + mul bp ; [bx(bpbSectorsPerFAT)], set by ReadCXSectors 1.241 + 1.242 + push es 1.243 + call ReadCXSectors ; read root directory, clear cx and di 1.244 + pop es 1.245 + 1.246 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.247 +;; Look for the COM/EXE file to load and run ;; 1.248 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.249 + 1.250 + ; es:di -> root entries array 1.251 + 1.252 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.253 +;; Looks for the file/dir ProgramName ;; 1.254 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.255 +;; Input: ES:DI -> root directory array ;; 1.256 +;; Output: SI = cluster number ;; 1.257 +;; AX = file sector count ;; 1.258 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.259 + 1.260 +FindNameCycle: 1.261 + cmp byte [es:di], ch 1.262 + je FindNameFailed ; end of root directory (NULL entry found) 1.263 + push di 1.264 + mov cl, 11 1.265 + mov si, ProgramName ; ds:si -> program name 1.266 + repe cmpsb 1.267 + pop di 1.268 + je FindNameFound 1.269 + add di, 32 1.270 + dec word [bx(bpbRootEntries)] 1.271 + jnz FindNameCycle ; next root entry 1.272 + 1.273 +FindNameFailed: 1.274 + call Error 1.275 + db "File not found." 1.276 + 1.277 +FindNameFound: 1.278 + push si 1.279 + mov si, [es:di+1Ah] ; si = cluster no. 1.280 + les ax, [es:di+1Ch] ; file size 1.281 + mov dx, es 1.282 + div word [bx(bpbBytesPerSector)] 1.283 + cmp bx, dx ; sector aligned ? 1.284 + adc ax, bx ; file last sector 1.285 + pop di ; di = ClusterList 1.286 + 1.287 + pop es ; ImageLoadSeg 1.288 + push ax 1.289 + 1.290 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.291 +;; build cluster list ;; 1.292 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.293 +;; Input: ES:0 -> FAT ;; 1.294 +;; SI = first cluster ;; 1.295 +;; DI = cluster list :; 1.296 +;; CH = 0 ;; 1.297 +;; Output: SI = cluster list ;; 1.298 +;; CH = 0 ;; 1.299 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.300 + 1.301 + push di ; up to 2 * 635K / BytesPerCluster bytes 1.302 + mov cl, 12 1.303 +ClusterLoop: 1.304 + mov [di], si 1.305 + 1.306 + mov ax, es ; ax = FAT segment = ImageLoadSeg 1.307 + add si, si ; si = cluster * 2 1.308 + jnc First64 1.309 + mov ah, (1000h+ImageLoadSeg)>>8 ; adjust segment for 2nd part of FAT16 1.310 +First64: 1.311 + cmp [bx(bpbSectorsPerFAT)], cx ; 1..12 = FAT12, 16..256 = FAT16 1.312 + mov ds, ax 1.313 + jbe ReadClusterFat12 1.314 + 1.315 + lodsw ; ax = next cluster 1.316 + cmp ax, 0FFF8h 1.317 + jmp ReadClusterDone 1.318 + 1.319 +ReadClusterFat12: 1.320 + add si, [cs:di] 1.321 + shr si, 1 ; si = cluster * 3 / 2 1.322 + 1.323 + lodsw ; ax = next cluster 1.324 + jnc ReadClusterEven 1.325 + 1.326 + rol ax, cl 1.327 + 1.328 +ReadClusterEven: 1.329 + and ax, 0FFFh ; mask cluster value 1.330 + cmp ax, 0FF8h 1.331 + 1.332 +ReadClusterDone: 1.333 + push cs 1.334 + pop ds 1.335 + inc di 1.336 + inc di 1.337 + xchg ax, si 1.338 + jc ClusterLoop 1.339 + pop si 1.340 + pop di ; file size in sectors 1.341 + 1.342 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.343 +;; Load the entire file ;; 1.344 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.345 +;; Input: ES:0 -> buffer ;; 1.346 +;; SI = cluster list ;; 1.347 +;; DI = file sectors ;; 1.348 +;; CH = 0 ;; 1.349 +;; Output: BP:0 -> buffer ;; 1.350 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.351 + 1.352 + push es 1.353 + 1.354 +ReadClusters: 1.355 + lodsw 1.356 + dec ax 1.357 + dec ax 1.358 + 1.359 + mov cl, [bx(bpbSectorsPerCluster)] 1.360 + mul cx ; cx = sector count (ch = 0) 1.361 + 1.362 + add ax, bp ; LBA for cluster data 1.363 + adc dx, bx ; dx:ax = LBA 1.364 + 1.365 + call ReadSector ; clear cx 1.366 + 1.367 + jne ReadClusters 1.368 + 1.369 + pop bp ; ImageLoadSeg 1.370 + 1.371 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.372 +;; Type detection, .COM or .EXE? ;; 1.373 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.374 + 1.375 + mov ds, bp ; bp=ds=seg the file is loaded to 1.376 + 1.377 + add bp, [bx+08h] ; bp = image base 1.378 + mov ax, [bx+06h] ; ax = reloc items 1.379 + mov di, [bx+18h] ; di = reloc table pointer 1.380 + 1.381 + cmp word [bx], 5A4Dh ; "MZ" signature? 1.382 + je RelocateEXE ; yes, it's an EXE program 1.383 + 1.384 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.385 +;; Setup and run a .COM program ;; 1.386 +;; Set CS=DS=ES=SS SP=0 IP=100h ;; 1.387 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.388 + 1.389 + mov bp, ImageLoadSeg-10h ; "org 100h" stuff :) 1.390 + mov ss, bp 1.391 + xor sp, sp 1.392 + push bp ; cs, ds and es 1.393 + mov bh, 1 ; ip 1.394 + jmp short Run 1.395 + 1.396 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.397 +;; Relocate, setup and run a .EXE program ;; 1.398 +;; Set CS:IP, SS:SP, DS, ES and AX according ;; 1.399 +;; to wiki.osdev.org/MZ#Initial_Program_State ;; 1.400 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.401 + 1.402 +ReloCycle: 1.403 + add [di+2], bp ; item seg (abs) 1.404 + les si, [di] ; si = item ofs, es = item seg 1.405 + add [es:si], bp ; fixup 1.406 + scasw ; di += 2 1.407 + scasw ; point to next entry 1.408 + 1.409 +RelocateEXE: 1.410 + dec ax ; 32768 max (128KB table) 1.411 + jns ReloCycle ; leave with ax=0ffffh: both FCB in the 1.412 + ; PSP don't have a valid drive identifier 1.413 + les si, [bx+0Eh] 1.414 + add si, bp 1.415 + mov ss, si ; ss for EXE 1.416 + mov sp, es ; sp for EXE 1.417 + 1.418 + lea si, [bp-10h] ; ds and es both point to the segment 1.419 + push si ; containing the PSP structure 1.420 + 1.421 + add bp, [bx+16h] ; cs for EXE 1.422 + mov bx, [bx+14h] ; ip for EXE 1.423 +Run: 1.424 + pop ds 1.425 + push bp 1.426 + push bx 1.427 + push ds 1.428 + pop es 1.429 + 1.430 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.431 +;; Set the magic numbers so the program knows that it ;; 1.432 +;; has been loaded by this bootsector and not by MS-DOS ;; 1.433 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.434 + mov si, 16381 ; prime number 2**14-3 1.435 + mov di, 32749 ; prime number 2**15-19 1.436 + mov bp, 65521 ; prime number 2**16-15 1.437 + 1.438 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.439 +;; All done, transfer control to the program now ;; 1.440 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.441 + retf 1.442 + 1.443 +ReadCXSectors: 1.444 + mov bp, cx 1.445 + add bp, ax ; adjust LBA for cluster data 1.446 + 1.447 + mov di, cx ; no file size limit 1.448 + 1.449 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.450 +;; Reads sectors using BIOS Int 13h ;; 1.451 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.452 +;; Input: DX:AX = LBA relative to FAT ;; 1.453 +;; BX = 0 ;; 1.454 +;; CX = sector count ;; 1.455 +;; DI = file sectors ;; 1.456 +;; ES:BX -> buffer address ;; 1.457 +;; Output: ES:BX -> next address ;; 1.458 +;; BX = 0 ;; 1.459 +;; CX or DI = 0 ;; 1.460 +;; DL = drive number ;; 1.461 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.462 + 1.463 +ReadSector: 1.464 + add ax, [bx(bpbHiddenSectors)] 1.465 + adc dx, [bx(bpbHiddenSectors)+2] 1.466 + add ax, [bx(bpbReservedSectors)] 1.467 + 1.468 + push si 1.469 +ReadSectorNext: 1.470 + adc dx, bx 1.471 + push di 1.472 + push cx 1.473 + 1.474 + push bx 1.475 + push bx 1.476 + push dx ; 32-bit LBA: up to 2TB 1.477 + push ax 1.478 + push es 1.479 + push bx 1.480 + inc bx ; sector count word = 1 1.481 + push bx 1.482 + dec bx 1.483 + mov di, 16 ; packet size byte = 16, reserved byte = 0 1.484 + push di 1.485 + 1.486 + xchg ax, cx ; save low LBA 1.487 + xchg ax, dx ; get high LBA 1.488 + cwd ; clear dx (LBA offset <2TB) 1.489 + div word [bx(bpbSectorsPerTrack)] ; up to 8GB disks 1.490 + 1.491 + xchg ax, cx ; restore low LBA, save high LBA / SPT 1.492 + div word [bx(bpbSectorsPerTrack)] 1.493 + ; ax = LBA / SPT 1.494 + ; dx = LBA % SPT = sector - 1 1.495 + inc dx 1.496 + 1.497 + xchg cx, dx ; restore high LBA / SPT, save sector no. 1.498 + div word [bx(bpbHeadsPerCylinder)] 1.499 + ; ax = (LBA / SPT) / HPC = cylinder 1.500 + ; dx = (LBA / SPT) % HPC = head 1.501 + mov ch, al 1.502 + ; ch = LSB 0...7 of cylinder no. 1.503 + mov al, 64 1.504 + mul ah 1.505 + or cl, al 1.506 + ; cl = MSB 8...9 of cylinder no. + sector no. 1.507 + mov dh, dl 1.508 + ; dh = head no. 1.509 + 1.510 +ReadSectorRetry: 1.511 + mov dl, [bx] 1.512 + ; dl = drive no. 1.513 + mov ah, 42h ; ah = 42h = extended read function no. 1.514 + mov si, sp 1.515 + int 13h ; extended read sectors (DL, DS:SI) 1.516 + jnc ReadSectorNextSegment 1.517 + 1.518 + mov ax, 201h ; al = sector count = 1 1.519 + ; ah = 2 = read function no. 1.520 + int 13h ; read sectors (AL, CX, DX, ES:BX) 1.521 + 1.522 + jnc ReadSectorNextSegment 1.523 + cbw ; ah = 0 = reset function 1.524 + int 13h ; reset drive (DL) 1.525 + 1.526 + dec di 1.527 + jnz ReadSectorRetry ; extra attempt 1.528 + 1.529 + call Error 1.530 + db "Read error." 1.531 + 1.532 +ReadSectorNextSegment: 1.533 + 1.534 + pop ax ; al = 16 1.535 + mul byte [bx(bpbBytesPerSector)+1] ; = (bpbBytesPerSector/256)*16 1.536 + pop cx ; sector count = 1 1.537 + pop bx 1.538 + add [si+6], ax ; adjust segment for next sector 1.539 + pop es ; es:0 updated 1.540 + pop ax 1.541 + pop dx 1.542 + pop di 1.543 + pop di 1.544 + 1.545 + add ax, cx ; adjust LBA for next sector 1.546 + 1.547 + pop cx ; cluster sectors to read 1.548 + pop di ; file sectors to read 1.549 + dec di ; keep C 1.550 + loopne ReadSectorNext ; until cluster sector count or file sector count is reached 1.551 + pop si 1.552 + mov dx, [bx] ; pass the BIOS boot drive to Run or Error 1.553 + 1.554 + ret 1.555 + 1.556 +;;;;;;;;;;;;;;;;;;;;;;;;;; 1.557 +;; Error Messaging Code ;; 1.558 +;;;;;;;;;;;;;;;;;;;;;;;;;; 1.559 + 1.560 +Error: 1.561 + pop si 1.562 + mov ah, 0Eh 1.563 + mov bl, 7 1.564 + 1.565 +PutStr: 1.566 + lodsb 1.567 + int 10h 1.568 + cmp al, "." 1.569 + jne PutStr 1.570 + 1.571 + cbw 1.572 + int 16h ; wait for a key... 1.573 + int 19h ; bootstrap 1.574 + 1.575 +Stop: 1.576 + hlt 1.577 + jmp short Stop 1.578 + 1.579 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.580 +;; Fill free space with zeroes ;; 1.581 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.582 + 1.583 + times (512-13-($-$$)) db 0 1.584 + 1.585 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.586 +;; Name of the file to load and run ;; 1.587 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1.588 + 1.589 +ProgramName db "STARTUP BIN" ; name and extension each must be 1.590 + ; padded with spaces (11 bytes total) 1.591 + 1.592 +;;;;;;;;;;;;;;;;;;;;;;;;;; 1.593 +;; End of the sector ID ;; 1.594 +;;;;;;;;;;;;;;;;;;;;;;;;;; 1.595 + 1.596 +ClusterList dw 0AA55h ; BIOS checks for this ID