wok view BootProg/stuff/boot32.asm @ rev 25706

BootProg/boot32.asm: add int 21h services 02h, 09h, 25h, 35h
author Pascal Bellard <pascal.bellard@slitaz.org>
date Wed Jun 26 17:36:15 2024 +0000 (3 months ago)
parents 7db7b7aaf63e
children
line source
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; ;;
3 ;; "BootProg" Loader v 1.5 by Alexey Frunze (c) 2000-2015 ;;
4 ;; 2-clause BSD license. ;;
5 ;; ;;
6 ;; ;;
7 ;; How to Compile: ;;
8 ;; ~~~~~~~~~~~~~~~ ;;
9 ;; nasm boot32.asm -f bin -o boot32.bin ;;
10 ;; ;;
11 ;; ;;
12 ;; Features: ;;
13 ;; ~~~~~~~~~ ;;
14 ;; - FAT32 supported using BIOS int 13h function 42h (IOW, it will only ;;
15 ;; work with modern BIOSes supporting HDDs bigger than 8 GB) ;;
16 ;; ;;
17 ;; - Loads a 16-bit executable file in the MS-DOS .COM or .EXE format ;;
18 ;; from the root directory of a disk and transfers control to it ;;
19 ;; (the "ProgramName" variable holds the name of the file to be loaded) ;;
20 ;; Its maximum size can be up to 637KB without Extended BIOS Data area. ;;
21 ;; ;;
22 ;; - Prints an error if the file isn't found or couldn't be read ;;
23 ;; ("No bootfile" or "Read error") ;;
24 ;; and waits for a key to be pressed, then executes the Int 19h ;;
25 ;; instruction and lets the BIOS continue bootstrap. ;;
26 ;; ;;
27 ;; ;;
28 ;; Known Limitation: ;;
29 ;; ~~~~~~~~~~~~~~~~~ ;;
30 ;; - Need a up to date field bpbHiddenSectors to work in a partition ; ;;
31 ;; most formatters don't update it correcly in extended partitions. ;;
32 ;; ;;
33 ;; - Requires i80386 or better CPU. ;;
34 ;; ;;
35 ;; ;;
36 ;; Known Bugs: ;;
37 ;; ~~~~~~~~~~~ ;;
38 ;; - All bugs are fixed as far as I know. The boot sector has been tested ;;
39 ;; on my HDD and an 8GB USB stick. ;;
40 ;; ;;
41 ;; ;;
42 ;; Memory Layout: ;;
43 ;; ~~~~~~~~~~~~~~ ;;
44 ;; The diagram below shows the typical memory layout. The actual location ;;
45 ;; of the boot sector and its stack may be lower than A0000H if the BIOS ;;
46 ;; reserves memory for its Extended BIOS Data Area just below A0000H and ;;
47 ;; reports less than 640 KB of RAM via its Int 12H function. ;;
48 ;; ;;
49 ;; physical address ;;
50 ;; +------------------------+ 00000H ;;
51 ;; | Interrupt Vector Table | ;;
52 ;; +------------------------+ 00400H ;;
53 ;; | BIOS Data Area | ;;
54 ;; +------------------------+ 00500H ;;
55 ;; | PrtScr Status / Unused | ;;
56 ;; +------------------------+ 00600H ;;
57 ;; | Loaded Image | ;;
58 ;; +------------------------+ nnnnnH ;;
59 ;; | Available Memory | ;;
60 ;; +------------------------+ A0000H - 1KB ;;
61 ;; | Boot Sector | ;;
62 ;; +------------------------+ A0000H - 0.5KB ;;
63 ;; | 0.5KB Boot Stack | ;;
64 ;; +------------------------+ A0000H ;;
65 ;; | Video RAM | ;;
66 ;; ;;
67 ;; ;;
68 ;; Boot Image Startup (register values): ;;
69 ;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ;;
70 ;; ax = 0ffffh (both FCB in the PSP don't have a valid drive identifier), ;;
71 ;; bx = 0, dl = BIOS boot drive number (e.g. 0, 80H) ;;
72 ;; cs:ip = program entry point ;;
73 ;; ss:sp = program stack (don't confuse with boot sector's stack) ;;
74 ;; COM program defaults: cs = ds = es = ss = 50h, sp = 0, ip = 100h ;;
75 ;; EXE program defaults: ds = es = EXE data - 10h (fake MS-DOS psp), ;;
76 ;; cs:ip and ss:sp depends on EXE header ;;
77 ;; Magic numbers: ;;
78 ;; si = 16381 (prime number 2**14-3) ;;
79 ;; di = 32749 (prime number 2**15-19) ;;
80 ;; bp = 65521 (prime number 2**16-15) ;;
81 ;; The magic numbers let the program know whether it has been loaded by ;;
82 ;; this boot sector or by MS-DOS, which may be handy for universal, bare- ;;
83 ;; metal and MS-DOS programs. ;;
84 ;; The command line contains no arguments. ;;
85 ;; ;;
86 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
88 %define bx(label) bx+label-boot
89 %define si(label) si+label-boot
90 ExtraBootSector equ 1
91 ClusterMask equ 1 ; +9 bytes
92 NullEntryCheck equ 1 ; +5 bytes
93 CheckAttrib equ 0 ; +6 bytes
94 NonMirroredFATs equ 1 ; +20 bytes
95 ReadRetry equ 1 ; +6/7 bytes
96 LBA48bits equ 1 ; +10 bytes
97 CHSsupport equ 1 ; +35 bytes max 8GB
98 CHSgeometryCheck equ 1 ; +20 bytes
99 CHSsanityCheck equ 1 ; +9 bytes
100 SectorOf512Bytes equ 0 ; -4 bytes
101 Always2FATs equ 0 ; -4 bytes
102 WaitForKey equ 0 ; +5 bytes
103 AnyWhere equ 1 ; +3 bytes
104 Int21h equ 1 ; +70 bytes
106 [BITS 16]
107 [CPU 386]
109 ImageLoadSeg equ 60h ; <=07Fh because of "push byte ImageLoadSeg" instructions
110 StackSize equ 512
112 [SECTION .text]
113 [ORG 0]
115 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
116 ;; Boot sector starts here ;;
117 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
119 boot:
120 DriveNumber equ boot+0
121 HiLBA equ boot+2
122 jmp short start ; MS-DOS/Windows checks for this jump
123 nop
124 bsOemName DB "BootProg" ; 0x03
126 ;;;;;;;;;;;;;;;;;;;;;;
127 ;; BPB1 starts here ;;
128 ;;;;;;;;;;;;;;;;;;;;;;
130 bpbBytesPerSector DW 0 ; 0x0B 512, 1024, 2048 or 4096
131 bpbSectorsPerCluster DB 0 ; 0x0D 1, 2, 4, 8, 16, 32, 64 or 128
132 bpbReservedSectors DW 0 ; 0x0E 32
133 bpbNumberOfFATs DB 0 ; 0x10 2
134 bpbRootEntries DW 0 ; 0x11 0
135 bpbTotalSectors DW 0 ; 0x13 0
136 bpbMedia DB 0 ; 0x15 F8, F0
137 bpbSectorsPerFAT DW 0 ; 0x16 0
138 bpbSectorsPerTrack DW 0 ; 0x18
139 bpbHeadsPerCylinder DW 0 ; 0x1A
140 bpbHiddenSectors DD 0 ; 0x1C
141 bpbTotalSectorsBig DD 0 ; 0x20
143 ;;;;;;;;;;;;;;;;;;;;
144 ;; BPB1 ends here ;;
145 ;;;;;;;;;;;;;;;;;;;;
147 ;;;;;;;;;;;;;;;;;;;;;;
148 ;; BPB2 starts here ;;
149 ;;;;;;;;;;;;;;;;;;;;;;
151 bsSectorsPerFAT32 DD 0 ; 0x24
152 bsExtendedFlags DW 0 ; 0x28
153 bsFSVersion DW 0 ; 0x2A
154 bsRootDirectoryClusterNo DD 0 ; 0x2C
155 bsFSInfoSectorNo DW 0 ; 0x30
156 bsBackupBootSectorNo DW 0 ; 0x32
157 bsreserved times 12 DB 0 ; 0x34
158 bsDriveNumber DB 0 ; 0x40
159 bsreserved1 DB 0 ; 0x41
160 bsExtendedBootSignature DB 0 ; 0x42 29
161 bsVolumeSerialNumber DD 0 ; 0x43
162 bsVolumeLabel times 11 DB " " ; 0x47 "NO NAME "
163 bsFileSystemName times 8 DB " " ; 0x52 "FAT32 "
165 ;;;;;;;;;;;;;;;;;;;;
166 ;; BPB2 ends here ;;
167 ;;;;;;;;;;;;;;;;;;;;
169 %macro Abort 1
170 call Error
171 db %1
172 db '.'
173 %if Int21h
174 db '$'
175 %endif
176 %endm
178 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
179 ;; Boot sector code starts here ;;
180 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
182 start:
184 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
185 ;; How much RAM is there? ;;
186 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
188 int 12h ; get conventional memory size (in KBs)
189 %if AnyWhere
190 call here
191 here:
192 pop si
193 sub si, here - boot - 2 ; exclude DriveNumber
194 %endif
195 dec ax ; reserve 1K bytes for the code and the stack
196 mov cx, 106h
197 shl ax, cl ; and convert it to 16-byte paragraphs
199 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
200 ;; Reserve memory for the boot sector and its stack ;;
201 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
203 mov es, ax ; cs:0 = ds:0 = ss:0 -> top - 512 - StackSize
204 %if ExtraBootSector != 0
205 add al, 32
206 %else
207 mov ss, ax
208 mov sp, 512+StackSize ; bytes 0-511 are reserved for the boot code
209 %endif
211 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
212 ;; Copy ourselves to top of memory ;;
213 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
215 xor di, di
216 %if AnyWhere == 0
217 mov si, 7C02h ; exclude DriveNumber
218 mov ds, di
219 %endif
220 push es
221 cld
222 xchg ax, dx
223 stosw ; store BIOS boot drive number
224 %if AnyWhere
225 rep cs movsw ; move 512 bytes (+ 12)
226 %else
227 rep movsw ; move 512 bytes (+ 12)
228 %endif
230 ;;;;;;;;;;;;;;;;;;;;;;
231 ;; Jump to the copy ;;
232 ;;;;;;;;;;;;;;;;;;;;;;
234 %if ExtraBootSector != 0
235 push word main
236 %else
237 push byte main
238 %endif
239 retf
241 %if ExtraBootSector != 0
242 %macro MovedCode 0
243 main:
244 push dx
245 %else
246 main:
247 %endif
248 ;;;;;;;;;;;;;;;;;;;;;;;;;;
249 ;; Get drive parameters ;;
250 ;; Update heads count ;;
251 ;; for current BIOS ;;
252 ;;;;;;;;;;;;;;;;;;;;;;;;;;
254 %if CHSgeometryCheck != 0
255 mov ah, 8 ; update AX,BL,CX,DX,DI, and ES registers
256 int 13h ; may destroy SI,BP, and DS registers
257 %endif
258 push cs
259 pop ds
260 xor ebx, ebx
262 %if CHSgeometryCheck != 0
263 and cx, byte 3Fh
264 je BadParams ; verify updated and validity
265 mov [bx(bpbSectorsPerTrack)], cx
266 mov cl, dh
267 inc cx
268 mov [bx(bpbHeadsPerCylinder)], cx
269 xor cx, cx
270 BadParams:
271 %endif
272 %if ExtraBootSector != 0
273 pop es
274 mul ebx ; edx:eax = 0
275 inc ax
276 call ReadSectorBoot
277 push ds
278 pop ss
279 mov sp, 512+StackSize ; bytes 0-511 are reserved for the boot code
280 %endif
282 %if Int21h
283 mov ax, 3521h
284 mov dx, Int21xx
285 pushf
286 push cs
287 call dx
288 %endif
290 %if ClusterMask != 0
291 and byte [bx(bsRootDirectoryClusterNo+3)], 0Fh ; mask cluster value
292 %endif
293 mov esi, [bx(bsRootDirectoryClusterNo)] ; esi=cluster # of root dir
295 push byte ImageLoadSeg
296 pop es
298 RootDirReadContinue:
299 call ReadClusterSector ; read one sector of the root dir
301 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
302 ;; Look for the COM/EXE file to load and run ;;
303 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
305 xor di, di ; es:di -> root entries array
307 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
308 ;; Looks for a file/dir by its name ;;
309 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
310 ;; Input: DS:SI -> file name (11 chars) ;;
311 ;; ES:DI -> root directory array ;;
312 ;; BP = paragraphs in sector ;;
313 ;; Output: ESI = cluster number ;;
314 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
316 FindNameCycle:
317 %if NullEntryCheck != 0
318 cmp byte [es:di], bh
319 je ErrFind ; end of root directory (NULL entry found)
320 %endif
321 pusha
322 mov cl, NameLength
323 mov si, ProgramName ; ds:si -> program name
324 repe cmpsb
325 VolumeLabel equ 8
326 SubDirectory equ 10h
327 %if CheckAttrib != 0
328 jnz SkipFindName
329 test byte [es:di], VolumeLabel+SubDirectory
330 SkipFindName:
331 %endif
332 je FindNameFound
333 popa
334 add di, byte 32
335 dec bp
336 dec bp
337 jnz FindNameCycle ; next root entry
338 loop RootDirReadContinue ; next sector in cluster
339 cmp esi, 0FFFFFF6h ; carry=0 if last cluster, and carry=1 otherwise
340 jnc RootDirReadContinue ; continue to the next root dir cluster
341 ErrFind:
342 Abort "No bootfile" ; end of root directory (dir end reached)
343 %if ExtraBootSector != 0
344 %endm
345 %macro BootFileName 0
346 %endif
347 FindNameFound:
348 push word [es:di+14h-11]
349 push word [es:di+1Ah-11]
350 pop esi ; esi = cluster no. cx = 0
352 dec dword [es:di+1Ch-11] ; load ((n - 1)/256)*16 +1 paragraphs
353 imul di, [es:di+1Ch+1-11], byte 16 ; file size in paragraphs (full pages)
355 ;;;;;;;;;;;;;;;;;;;;;;;;;;
356 ;; Load the entire file ;;
357 ;;;;;;;;;;;;;;;;;;;;;;;;;;
359 push es
360 FileReadContinue:
361 push di
362 call ReadClusterSector ; read one sector of the boot file
363 dec cx
364 mov di, es
365 add di, bp
366 mov es, di ; es:bx updated
367 pop di
369 sub di, bp
370 jae FileReadContinue
371 xor ax, ax
372 pop bp
374 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
375 ;; Type detection, .COM or .EXE? ;;
376 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
378 mov ds, bp ; bp=ds=seg the file is loaded to
380 add bp, [bx+08h] ; bp = image base
381 mov di, [bx+18h] ; di = reloc table pointer
383 cmp word [bx], 5A4Dh ; "MZ" signature?
384 je RelocateEXE ; yes, it's an EXE program
386 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
387 ;; Setup and run a .COM program ;;
388 ;; Set CS=DS=ES=SS SP=0 IP=100h ;;
389 ;; AX=0ffffh BX=0 DX=drive and ;;
390 ;; cmdline=void ;;
391 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
393 mov di, 100h ; ip
394 mov bp, ImageLoadSeg-10h ; "org 100h" stuff :)
395 mov ss, bp
396 xor sp, sp
397 push bp ; cs, ds and es
398 jmp short Run
400 %if Int21h
401 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
402 ;; DOS service ah=02h,09h,25h,35h ;;
403 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
405 Int21xx:
406 cld
407 push si
408 mov si, dx
409 push ds
410 push ax
411 xchg al, ah
412 push bx
413 xor bx, bx
414 cmp al, 09h
415 je putslp
416 cmp al, 02h
417 jne I21x5
418 dec bx
419 mov al, dl
421 putc: mov ah, 0Eh
422 inc bx
423 int 10h
424 dec bx
425 jnz Iret1
427 putslp: lodsb
428 cmp al,'$'
429 jnz putc
430 xchg ax, bx
432 I21x5: push ds
433 mov ds, bx
434 mov bl, ah
435 shl bx, 2
436 cmp al, 35h
437 je I2135
438 pop ds
439 cmp al, 25h
440 jne Iret1
442 I2125: les bx, [bx]
443 pop ax
444 jmp Iret2
446 I2135: push dx
447 pop dword [bx]
448 Iret1: pop bx
449 Iret2: pop ax
450 pop ds
451 pop si
452 iret
454 %endif
456 %if ExtraBootSector != 0
457 %endm
458 %macro BootCode 0
459 %endif
461 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
462 ;; Relocate, setup and run a .EXE program ;;
463 ;; Set CS:IP, SS:SP, DS, ES and AX according ;;
464 ;; to wiki.osdev.org/MZ#Initial_Program_State ;;
465 ;; AX=0ffffh BX=0 DX=drive cmdline=void ;;
466 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
468 ReloCycle:
469 add [di+2], bp ; item seg (abs)
470 les si, [di] ; si = item ofs, es = item seg
471 add [es:si], bp ; fixup
472 scasw ; di += 2
473 scasw ; point to next entry
475 RelocateEXE:
476 dec word [bx+06h] ; reloc items, 32768 max (128KB table)
477 jns ReloCycle
479 les si, [bx+0Eh]
480 add si, bp
481 mov ss, si ; ss for EXE
482 mov sp, es ; sp for EXE
484 lea si, [bp-10h] ; ds and es both point to the segment
485 push si ; containing the PSP structure
487 add bp, [bx+16h] ; cs for EXE
488 mov di, [bx+14h] ; ip for EXE
489 Run:
490 pop ds
491 push bp
492 push di
493 push ds
494 pop es
495 mov [80h], ax ; clear cmdline
496 dec ax ; both FCB in the PSP don't have a valid drive identifier
498 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
499 ;; Set the magic numbers so the program knows that it ;;
500 ;; has been loaded by this bootsector and not by MS-DOS ;;
501 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
502 mov si, 16381 ; prime number 2**14-3
503 mov di, 32749 ; prime number 2**15-19
504 mov bp, 65521 ; prime number 2**16-15
506 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
507 ;; All done, transfer control to the program now ;;
508 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
509 retf
511 %if ExtraBootSector != 0
512 %endm
513 %endif
515 ;;;;;;;;;;;;;;;;;;;;;;;;;;
516 ;; Error Messaging Code ;;
517 ;;;;;;;;;;;;;;;;;;;;;;;;;;
519 Error:
520 %if Int21h
521 pop dx
522 %if WaitForKey != 0
523 mov ax, 0900h
524 %else
525 mov ah, 09h
526 %endif
527 int 21h
528 %else
529 pop si
530 puts:
531 mov ah, 0Eh
532 mov bl, 7
533 lodsb
534 int 10h
535 cmp al, '.'
536 jne puts
537 %endif
538 %if WaitForKey != 0
539 %if Int21h == 0
540 cbw
541 %endif
542 int 16h ; wait for a key...
543 int 19h ; bootstrap
544 %endif
546 Stop:
547 hlt
548 jmp short Stop
550 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
551 ;; Reads a FAT32 sector ;;
552 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
553 ;; Inout: ES:BX -> buffer ;;
554 ;; EAX = prev sector ;;
555 ;; CX = rem sectors in cluster ;;
556 ;; ESI = next cluster ;;
557 ;; Output: EAX = current sector ;;
558 ;; CX = rem sectors in cluster ;;
559 ;; ESI = next cluster ;;
560 ;; BP -> para / sector ;;
561 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
563 ReadClusterSector:
564 %if SectorOf512Bytes != 0
565 mov bp, 32 ; bp = paragraphs per sector
566 %else
567 mov bp, [bx(bpbBytesPerSector)]
568 shr bp, 4 ; bp = paragraphs per sector
569 %endif
570 inc eax ; adjust LBA for next sector
571 inc cx
572 loop ReadSectorLBA
574 mul ebx ; edx:eax = 0
575 %if SectorOf512Bytes != 0
576 mov al, 128 ; ax=# of FAT32 entries per sector
577 %else
578 imul ax, bp, byte 4 ; ax=# of FAT32 entries per sector
579 %endif
580 lea edi, [esi-2] ; esi=cluster #
581 xchg eax, esi
582 div esi ; eax=FAT sector #, edx=entry # in sector
584 imul si, dx, byte 4 ; si=entry # in sector, clear C
585 %if NonMirroredFATs != 0
586 cdq
587 or dl, byte [bx(bsExtendedFlags)]
588 jns MirroredFATs ; Non-mirrored FATs ?
589 and dl, 0Fh
590 imul edx, dword [bx(bsSectorsPerFAT32)] ; we need to read the active one
591 add eax, edx
592 MirroredFATs:
593 cdq
594 %else
595 %if LBA48bits != 0
596 cdq
597 %endif
598 %endif
599 call ReadSectorLBAfromFAT ; read 1 FAT32 sector
601 %if ClusterMask != 0
602 and byte [es:si+3], 0Fh ; mask cluster value
603 %endif
604 mov esi, [es:si] ; esi=next cluster #
606 %if Always2FATs != 0
607 imul eax, dword [bx(bsSectorsPerFAT32)], 2
608 %else
609 movzx eax, byte [bx(bpbNumberOfFATs)]
610 mul dword [bx(bsSectorsPerFAT32)]
611 %endif
613 xchg eax, edi
614 movzx ecx, byte [bx(bpbSectorsPerCluster)] ; 8..128
615 mul ecx ; edx:eax=sector number in data area
616 add eax, edi
618 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
619 ;; Reads a sector form the start of FAT ;;
620 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
622 ReadSectorLBAfromFAT:
623 %if LBA48bits != 0
624 push dx
625 %endif
626 mov dx, [bx(bpbReservedSectors)]
627 add eax, edx
628 %if LBA48bits != 0
629 pop dx ; 16TB FAT32 max
630 adc dx, bx
631 ReadSectorBoot:
632 mov [bx(HiLBA)], dx
633 %endif
635 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
636 ;; Reads a sector using BIOS Int 13h fn 42h ;;
637 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
638 ;; Input: EAX+EDX = LBA ;;
639 ;; ES:BX -> buffer address ;;
640 ;; Keep: ESI = next cluster ;;
641 ;; EDI = data cluster ;;
642 ;; BP = paragraphs / sector ;;
643 ;; CX = sector count ;;
644 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
646 ReadSectorLBA:
647 %if LBA48bits != 0
648 mov dx, [bx(HiLBA)]
649 %else
650 xor dx, dx ; 2TB FAT32 max
651 ReadSectorBoot:
652 %endif
653 pushad
655 add eax, [bx(bpbHiddenSectors)]
656 adc dx, bx ; 2TB partition offset max
658 push edx
659 push eax
660 push es
661 push bx
662 push byte 1 ; sector count word = 1
663 push byte 16 ; packet size byte = 16, reserved byte = 0
665 %if CHSsupport != 0
666 ; Busybox mkdosfs creates fat32 for floppies.
667 ; Floppies may support CHS only.
668 %if LBA48bits != 0
669 ; The following check is only useful with bpbSectorsPerTrack < 8 with disk > 4TB...
670 ; setnz dl ; force cylinder overflow without divide error
671 %endif
672 movzx ecx, word [bx(bpbSectorsPerTrack)]
673 idiv ecx
674 ; eax = LBA / SPT
675 ; edx = LBA % SPT = sector - 1
676 inc dx
677 push dx ; save sector no.
678 cdq
679 mov cx, word [bx(bpbHeadsPerCylinder)]
680 idiv ecx
681 pop cx
682 ; eax = (LBA / SPT) / HPC = cylinder
683 ; dl = (LBA / SPT) % HPC = head
685 xchg ch, al ; clear al
686 ; ch = LSB 0...7 of cylinder no.
687 %if CHSsanityCheck != 0
688 shl eax, 6
689 %else
690 shl ax, 6
691 %endif
692 or cl, ah
693 ; cl = MSB 8...9 of cylinder no. + sector no.
694 mov dh, dl
695 ; dh = head no.
696 %endif
698 ReadSectorRetry:
699 mov dl, [bx(DriveNumber)] ; restore BIOS boot drive number
700 mov si, sp
701 mov ah, 42h ; ah = 42h = extended read function no.
702 int 13h ; extended read sectors (DL, DS:SI)
703 jnc ReadSuccess ; CF = 0 if no error
705 %if CHSsupport != 0
706 mov ax, 201h ; al = sector count = 1
707 ; ah = 2 = read function no.
708 %if CHSsanityCheck != 0
709 cmp eax, 0FFFFh ; max cylinder = 1023
710 ja SkipCHS
711 %endif
712 int 13h ; read sectors (AL, CX, DX, ES:BX)
714 jnc ReadSuccess ; CF = 0 if no error
715 SkipCHS:
716 %endif
717 %if ReadRetry != 0
718 %if CHSsupport != 0
719 cbw ; ah = 0 = reset function
720 %else
721 xor ax, ax ; ah = 0 = reset function
722 %endif
723 int 13h ; reset drive (DL)
725 dec bp ; up to 32 retries
726 jnz ReadSectorRetry
727 %endif
728 Abort "Read error"
730 ReadSuccess:
732 popa ; sp += 16
733 popad
734 mov dx, [bx(DriveNumber)] ; restore BIOS boot drive number
735 ret
737 %if ExtraBootSector != 0
738 MovedCode
739 BootCode
740 %endif
742 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
743 ;; Fill free space with zeroes ;;
744 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
746 times (512-13-($-$$)) db 0
748 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
749 ;; Name of the file to load and run ;;
750 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
752 NameLength equ 11
753 ProgramName times NameLength db 0 ; name and extension
755 ;;;;;;;;;;;;;;;;;;;;;;;;;;
756 ;; End of the sector ID ;;
757 ;;;;;;;;;;;;;;;;;;;;;;;;;;
759 dw 0AA55h ; BIOS checks for this ID
761 %if ExtraBootSector != 0
762 dd 61415252h ; "RRaA"
763 BootFileName
764 times (996-($-$$)) db 0
765 ; dd 41617272h ; "rrAa"
766 %endif