;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; General-purpose bootsector ; Chris Giese http://SisAndHappy.com/ChrisGiese/ ; ; I, the copyright holder of this work, hereby release it into the ; public domain. This applies worldwide. If this is not legally possible: ; I grant any entity the right to use this work for any purpose, ; without any conditions, unless such conditions are required by law. ; ; 20 Jan. 2015: ; - read_sectors_chs and read_sectors_lba no longer save/restore ; the registers they modify ; - Error messages are now short strings instead of single letters ; - Moved data to between BPB and code; allowing use of BP-relative ; addressing (and hence, smaller code) ; - Added a default NTFS BPB ; - Assemble-time options now select BPB other than FAT12: FAT16, FAT32, NTFS ; - Second stage defaults changed to: SS_NUM_SECTS=16 (8K), SS_FIRST_SECT=0, ; load address is 0000:8000 ; ; 9 Jul. 2012: ; - Initial release ; ;;;;;;;;;;;;;;;;;; ; BUILD ;;;;;;;;;;;;;;;;;; ; ; Assemble with NASM: ; nasm -f bin -o boot.bin boot.asm ; ; Possibly-useful assemble-time options: ; FAT16, FAT32, or NTFS BPB instead of FAT12: ; nasm -dFAT16=1 ... ; nasm -dFAT32=1 ... ; nasm -dNTFS=1 ... ; (default BPB values came from my C:, D:, and E: drives to simplify testing) ; ; Use CHS geometry in BPB if INT 13h AH=08h fails ; nasm -dUSE_HD_BPB=1 ... ; ; Make a DOS .COM file for test purposes: ; nasm -dDOS=1 -o boot.com ... ; ;;;;;;;;;;;;;;;;;; ; INSTALL ;;;;;;;;;;;;;;;;;; ; ; DOS, install to 1.44 meg floppy disk, BPB overwritten: ; partcopy fat12.bin 0 200 -f0 ; -or- ; debug fat12.bin ; -w 100 0 0 1 ('-' is DEBUG prompt. Type ? for help.) ; -q ; ; DOS, install to floppy disk, existing BPB preserved: ; partcopy boot.bin 0 3 -f0 ; partcopy boot.bin 5A 1A6 -f0 5A ; ; DOS, install to C: drive, existing BPB preserved (CAUTION): ; partcopy boot.bin 0 3 -aC ; partcopy boot.bin 5A 1A6 -aC 5A ; ; Linux, install to 1.44 meg floppy disk, BPB overwritten: ; cat boot.bin >/dev/fd0 ; ; Linux, install to floppy disk, existing BPB preserved: ; dd bs=1 if=boot.bin skip=0 count=3 of=/dev/fd0 ; dd bs=1 if=boot.bin skip=90 count=422 of=/dev/fd0 seek=90 ; ; Linux, install to 1st partition, existing BPB preserved (CAUTION): ; dd bs=1 if=boot.bin skip=0 count=3 of=/dev/hda0 ; dd bs=1 if=boot.bin skip=90 count=422 of=/dev/hda0 seek=90 ; ;;;;;;;;;;;;;;;;;; ; FEATURES ;;;;;;;;;;;;;;;;;; ; ; - Contains BPB compatible with FAT or NTFS filesystems. ; - Loads second stage into conventional memory (below 640K) and jumps to it ; - Will not load second stage below itself (prevents overwriting IVT, BIOS ; data area, or itself) ; - Will not load second stage if there's not enough conventional memory ; - Uses LBA BIOS disk-read function (INT 13h AH=42h) if BIOS and ; drive support it; else uses CHS BIOS function (INT 13h AH=02h) ; - Supports 64-bit sector values with LBA ; - Code is compatible with ye olde 8088 CPU ; - Short messages are displayed on the screen if something goes wrong: ; "Geom err" Error getting hard disk geometry ; (INT 13h AH=08h failed) ; "Too low" Second stage is below 0x7E00 (the first stage) ; "Too big" Second stage won't fit into conventional memory ; "Disk err" Error reading from disk; or possibly attempt to read ; beyond end of disk ; ; Limitations: ; - Second stage must be stored in contiguous disk sectors ; (i.e. it must be "defragged") ; - Size and starting sector of second stage must be stored in this ; bootsector after it's installed -- this code does not use the ; filesystem to find the second stage or determine it's size. ; ;;;;;;;;;;;;;;;;;; ; TO DO/IDEAS ;;;;;;;;;;;;;;;;;; ; ; - Creating more space for code: ; - Shorten the error message strings ; - Rewrite using 32-bit (386+ CPU) registers and instructions ; - Store 0 byte at file offset 42h in FAT32 BPB; to disable the ; VSN, volume label, and "FAT32" FS type. This will free up 23 bytes ; (of which, only 10 can be used if you also want NTFS compatability). ; - Store 0 byte at file offset 26h in FAT12/FAT16 BPB; to disable the ; VSN, volume label, and "FAT12"/"FAT16" FS type. This will free up ; 23 bytes (none of which can be used if you also need NTFS...). ; - Code in the Microsoft NTFS bootsector starts at file offset 5Dh ; (NT 4.0) or 54h (XP, Win 7), with zero bytes between the code and file ; offset 50h (end of the volume serial number). Are these zero bytes ; significant? ; - Combined bootsector/MBR? ; - I'm calling INT 13h AH=48h without first calling INT 13h AH=41h. ; Problem? ; - Make sure (SS_FIRST_SECT + SS_NUM_SECTS) <= partition_size. ; Note that NTFS partition size is a 64-bit value. ; - SS_NUM_SECTS is given in sectors -- which may be 512, 2K, 4K bytes, ; or some other value. Problem? ; - Turn off floppy motor before jumping to loaded code ; - Beep if error ; - Write an MBR version ; - Omit the BPB. Move BPB variables elsewhere (...yes?) ; - Omit floppy support (but retain the CHS code!) ; - Omit code to check 2nd-stage size and load address ; - Add code to copy self from 7C00h to 600h ; - Leave bytes from offset 440-443 inclusive free for Windows NT ; "disk signature" ; - Leave bytes from offset 446-510 inclusive free for partition table ; - Leave SI pointing to partition table entry for the active partition ; (MS-DOS MBR does this, but new MS-DOS and Windows bootsectors no ; longer need it.) ; - Maybe probe floppy disk geometry instead of using FAT BPB? ; If you do that, see how slow probing hard disk geometry is. ; (probably not enough room for the code to do this) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; These are user-definable values. They are also stored at known file ; offsets in the bootsector (see label "_lba_cmd_pkt") so they can be ; changed after this file has been assembled: ; (16-bit) how many (contiguous) sectors to load: %define SS_NUM_SECTS 16 ; (16-bit) segment of far address where second stage is loaded %define SS_LOAD_SEG 0 ; (16-bit) offset of far address where second stage is loaded %define SS_LOAD_OFF 8000h ; (64-bit!) LBA value of first sector to be loaded ; (relative to partition start): %define SS_FIRST_SECT 0 ; >> operator on 64-bit value doesn't work with NASM 0.98 ; I don't know which version of NASM fixed this. ; Also, I need a version of NASM that supports the "CPU" directive. ; I don't know which version of NASM first supported this. %if __NASM_MAJOR__ < 1 %error Sorry, NASM 1.0 or newer required %endif %ifndef NTFS %ifndef FAT32 %ifndef FAT16 %define FAT12 1 %endif %endif %endif CPU 8086 %ifdef DOS ORG 100h %else ORG 7C00h %endif start: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; For smaller code, use byte-offset addressing from BP register ; to access variables (below 7C00h) and BPB (above 7C00h) %define VAR(x) ((x) - start) + bp ; (1 byte) drive we booted from: ; 0=(emulated) floppy disk, 80h=(emulated) hard disk _int13_drive_num EQU (start - 1) ; (2 bytes) number of 16-byte paragraphs per sector _para_per_sector EQU (_int13_drive_num - 2) ; (26 bytes) buffer used for INT 13h AH=48h _lba_info EQU (_para_per_sector - 26) ; ;Format of IBM/MS INT 13 Extensions drive parameters: ;Offset Size Description (Table 00273) ; 00h WORD (call) size of buffer ; (001Ah for v1.x, 001Eh for v2.x, 42h for v3.0) ; (ret) size of returned data ; 02h WORD information flags (see #00274) ; 04h DWORD number of physical cylinders on drive ; 08h DWORD number of physical heads on drive ; 0Ch DWORD number of physical sectors per track ; 10h QWORD total number of sectors on drive ; 18h WORD bytes per sector ; top of stack goes here _stack EQU _lba_info ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; BIOS parameter block (BPB). Though the BPB is considered a feature ; of FAT filesystems, this code requires that parts of it be present; ; even if a non-FAT filesystem is used. ; ; Field Floppy disk CHS hard disk LBA hard disk ; --------------- ------------- ------------- ------------- ; _spt MUST be valid May be used[1] (not used) ; _heads MUST be valid May be used[1] (not used) ; _bps MUST be valid (not used)[2] (not used)[3] ; _part_start_31_0 MUST be 0 MUST be valid MUST be valid ; _part_start_63_32 MUST be 0 MUST be 0 MUST be valid ; ; [1] BPB values may be used if INT 13h AH=08h fails (if USE_HD_BPB) ; [2] Value is assumed to be 512 if BIOS or drive do not support LBA ; [3] INT 13h AH=48h is used to obtain this value ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; File ; off- ; set Description jmp skip_bpb ; 0 Must be 16-bit JMP (0xE9) or 8-bit JMP ; (0xEB) followed by NOP (0x90) %if (($-$$) != 3) %error BPB does not start at file offset 3 %endif %ifdef NTFS db "NTFS " ; 03h Not OEM ID; this MUST equal "NTFS " _bps: dw 512 ; 0Bh bytes per sector db 16 ; 0Dh sectors per cluster times 7 db 0 ; 0Eh reserved db 0F8h ; 15h media ID byte dw 0 ; 16h reserved _spt: dw 63 ; 18h CHS geometry (spt=sectors per track) _heads: dw 255 ; 1Ah CHS geometry _part_start_31_0: dd 261 * 255 * 63 ; 1Ch ="number of hidden sectors" dd 0 ; 20h reserved db 80h ; 24h INT 13h drive num (0 = floppy, 80h = HD) db 0 ; 25h ? db 80h ; 26h ? db 0 ; 27h ? _part_size_32: _part_size_64: dq 3FBC03h ; 28h 64-bit number of sectors dq 0FDFh ; 30h 64-bit LCN of the $MFT dq 1FDE01h ; 38h 64-bit LCN of the $MFTMirr dd 2 ; 40h clusters per MFT record dd 8 ; 44h clusters per index record dq 0F4D08957D08920CAh ; 48h volume serial number (8 bytes for NTFS???) ; 50h %elifdef FAT32 db "_GEEZER_" ; 03h OEM ID. Win9x will scribble here. _bps: dw 512 ; 0Bh bytes per sector db 16 ; 0Dh sectors per cluster dw 32 ; 0Eh number of reserved (boot) sectors db 2 ; 10h number of FATs dw 0 ; 11h maximum number of root directory entries _part_size_16: dw 0 ; 13h 16-bit total sectors db 0F8h ; 15h media ID byte dw 0 ; 16h 16-bit sectors per FAT _spt: dw 63 ; 18h CHS geometry (spt=sectors per track) _heads: dw 255 ; 1Ah CHS geometry _part_start_31_0: dd 3133 * 255 * 63 ; 1Ch ="number of hidden sectors" _part_size_32: dd 1A9CB88h ; 20h 32-bit total sectors dd 352Dh ; 24h 32-bit sectors per FAT dw 0 ; 28h b3-b0 = active FAT dw 0 ; 2Ah FS version (0 = Win95-OSR2) dd 2 ; 2Ch first cluster of root directory dw 1 ; 30h filesystem info sector number (0FFFFh = none) dw 6 ; 32h backup boot sector number (0FFFFh = none) times 14 db 0 ; 34h unused ; this isn't in fatgen103.pdf but it's in the bootsector of my FAT32 part'n: db 29h ; 42h extended boot sig.; qualifies next three fields dd 0 ; 43h volume serial number db "NO NAME "; 47h volume label db "FAT32 " ; 52h FS type (useless) ; 5Ah %elifdef FAT16 db "_GEEZER_" ; 03h OEM ID. Win9x will scribble here. _bps: dw 512 ; 0Bh bytes per sector db 64 ; 0Dh sectors per cluster dw 1 ; 0Eh number of reserved (boot) sectors db 2 ; 10h number of FATs dw 512 ; 11h maximum number of root directory entries _part_size_16: dw 0 ; 13h 16-bit total sectors db 0F8h ; 15h media ID byte dw 256 ; 16h 16-bit sectors per FAT _spt: dw 63 ; 18h CHS geometry (spt=sectors per track) _heads: dw 255 ; 1Ah CHS geometry _part_start_31_0: dd 63 ; 1Ch ="number of hidden sectors" _part_size_32: dd 3FFA86h ; 20h 32-bit total sectors db 80h ; 24h INT 13h drive num (0 = floppy, 80h = HD) db 0 ; 25h reserved for use by Windows NT db 29h ; 26h extended boot sig.; qualifies next three fields dd 0 ; 27h volume serial number db "NO NAME "; 2Bh volume label (might also be stored in root dir) db "FAT16 " ; 36h FS type (useless) ; 3Eh %else ; FAT12 db "_GEEZER_" ; 03h OEM ID. Win9x will scribble here. _bps: dw 512 ; 0Bh bytes per sector db 1 ; 0Dh sectors per cluster dw 1 ; 0Eh number of reserved (boot) sectors db 2 ; 10h number of FATs dw 224 ; 11h maximum number of root directory entries _part_size_16: dw 18 * 2 * 80 ; 13h 16-bit total sectors db 0F0h ; 15h media ID byte dw 9 ; 16h 16-bit sectors per FAT _spt: dw 18 ; 18h CHS geometry (spt=sectors per track) _heads: dw 2 ; 1Ah CHS geometry _part_start_31_0: dd 0 ; 1Ch ="number of hidden sectors" _part_size_32: dd 0 ; 20h 32-bit total sectors db 0 ; 24h INT 13h drive num (0 = floppy, 80h = HD) db 0 ; 25h reserved for use by Windows NT db 29h ; 26h extended boot sig.; qualifies next three fields dd 0 ; 27h volume serial number db "NO NAME "; 2Bh volume label (might also be stored in root dir) db "FAT12 " ; 36h FS type (useless) ; 3Eh %endif ; FAT32 has the biggest BPB -- pad with nops to offset 5Ah times (5Ah + $$ - $) nop ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; File ; off- ; set Description _read_sectors: dw read_sectors_chs ; 5Ah can also point to read_sectors_lba _part_start_63_32: dd 0 ; 5Ch high 32 bits of 64-bit part'n start _lba_cmd_pkt: db 10h ; 60h size of this packet db 0 ; 61h reserved dw SS_NUM_SECTS ; 62h number of sectors of 2nd stage to load dw SS_LOAD_OFF ; 64h offset of load address dw SS_LOAD_SEG ; 66h segment of load address dq SS_FIRST_SECT ; 68h (64-bit value) first sector of 2nd ; 70h stage; relative to start of partition _geom_err_msg: db "Geom err", 0 _too_low_msg: db "Too low", 0 _too_big_msg: db "Too big", 0 _disk_read_msg: db "Disk err", 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; skip_bpb: %ifdef DOS %ifdef FAT12 mov dl,0 %else mov dl,80h ; 80h = C: drive %endif mov bp,start mov [VAR(_lba_cmd_pkt + 6)],ds %else xor ax,ax mov ds,ax mov es,ax ; "mov ss,..." followed immediately by "mov sp,..." ; should be atomic on all x86 CPUs mov ss,ax mov sp,_stack ; currently, _stack=7BE3h mov bp,start %endif ; Save INT 13h drive num provided by the BIOS mov [VAR(_int13_drive_num)],dl ; (Emulated) hard disk or (emulated) floppy disk? If floppy disk, nothing ; to do here: use CHS geometry, number of sectors, and bytes per sector ; values in BPB (INT 13h AH=08h is unreliable for floppies); and use CHS ; disk-read subroutine. cmp dl,80h jb check_mem ; xxx - maybe call INT 13h AH=41h here (with BX=55AAh) ; after this interrupt call, want CY=0, BX=0AA55h, ((CX & 01h) == 01h) hard_disk: ; Check if LBA supported mov si,_lba_info mov ax,001Ah ; v1.0 of INT 13h extensions --> 26 bytes of data mov [si],ax mov ah,48h int 13h jc hd_chs ; LBA hard disk: get disk size (sectors) and bytes per sector from BIOS ; (INT 13h AH=48h) mov ax,[si + 24] mov [VAR(_bps)],ax mov ax,read_sectors_lba ; use LBA disk-read function mov [VAR(_read_sectors)],ax jmp short check_mem ; CHS hard disk: get geometry (number of heads and sectors per track) ; and disk size from BIOS (INT 13h AH=08h) and assume 512 bytes/sector. hd_chs: mov ah,08h int 13h %ifdef USE_HD_BPB jc check_mem ; use geometry already in BPB if INT 13h AH=08h fails ; xxx - maybe sanity-check those values %else mov si,_geom_err_msg jc error %endif mov al,cl shl ax,1 ; AH was zeroed by INT 13h AH=08h shl ax,1 ; shl ax,2 doesn't work on 8088 CPU mov al,ch add ax, byte 2 ; max_cyl_minus_1 -> num_cyls mov bx,ax ; BX=number of cylinders inc dh ; max_head -> num_heads mov [VAR(_heads)],dh and cl,3Fh mov [VAR(_spt)],cl mov ax,512 ; assume 512 bytes/sector for CHS hard disk mov [VAR(_bps)],ax check_mem: ; calculate linear start address of 2nd stage mov dx,[VAR(_lba_cmd_pkt + 6)] ; =SS_LOAD_SEG mov ax,16 mul dx add ax,[VAR(_lba_cmd_pkt + 4)] ; =SS_LOAD_OFF adc dx,byte 0 mov bx,ax mov di,dx ; error if 2nd stage below 1st sub ax,7E00h sbb dx,byte 0 mov si,_too_low_msg jc error ; calculate size (in bytes) of 2nd stage; add to load address mov ax,[VAR(_bps)] mov dx,[VAR(_lba_cmd_pkt + 2)] ; =SS_NUM_SECTS mul dx add ax,bx adc dx,di ; round up & convert to Kbytes = (bytes + 1023) / 1024 mov bx,1023 add ax,bx adc dx,byte 0 inc bx div bx mov bx,ax ; get conventional memory size (also in Kbytes) and compare int 12h cmp bx,ax mov si,_too_big_msg ja error load: ; we need the number of paragraphs per sector (one 'paragraph' = 16 bytes) mov ax,[VAR(_bps)] mov cl,4 ; no "shr ax,4" on 8088 CPU shr ax,cl mov [VAR(_para_per_sector)],ax ; add partition start to SS_FIRST_SECT mov ax,[VAR(_part_start_31_0 + 0)] add [VAR(_lba_cmd_pkt + 8)],ax mov ax,[VAR(_part_start_31_0 + 2)] adc [VAR(_lba_cmd_pkt + 10)],ax mov ax,[VAR(_part_start_63_32 + 0)] adc [VAR(_lba_cmd_pkt + 12)],ax mov ax,[VAR(_part_start_63_32 + 2)] adc [VAR(_lba_cmd_pkt + 14)],ax ; load second stage call [VAR(_read_sectors)] mov si,_disk_read_msg jc error ; Jump to second stage. Ideally, the second stage should make ; absolutely no assumptions about register values, including segment ; register values and size and location of the stack. jmp far [VAR(_lba_cmd_pkt + 4)] ; =SS_LOAD_OFF:SS_LOAD_SEG ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Displays 0-terminated error message pointed to by SI, then exits ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; error0: mov ah,0Eh mov bx,0007h ; BH=page=0, BL=foreground color (7=white) int 10h error: mov al,[si] inc si or al,al jne error0 %ifdef DOS mov ax,4C00h ; exit to DOS int 21h %else mov ah,0 ; await key pressed int 16h int 19h ; try booting again %endif ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Reads word [_lba_cmd_pkt + 2] sectors ; starting with sector number dword [_lba_cmd_pkt + 8] into memory ; starting at far address dword [_lba_cmd_pkt + 4] ; from drive number byte [_int13_drive_num] ; Returns carry set if error. Modifies AX, BX, CX, DX, SI, ES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; read_sectors_chs: mov cx,[VAR(_lba_cmd_pkt + 2)] or cx,cx je short rsc_4 les bx,[VAR(_lba_cmd_pkt + 4)] mov ax,[VAR(_lba_cmd_pkt + 8)] mov dx,[VAR(_lba_cmd_pkt + 10)] rsc_1: push dx push cx push ax ; DX:AX=LBA sector number ; Divide by number of sectors per track to get sector number. ; Use 32:16 DIV instead of 64:32 DIV for 8088 compatability. ; Use two-step 32:16 divide to avoid overflow. ; (See Randall Hyde's "Art of Assembly") mov cx,ax mov ax,dx xor dx,dx div word [VAR(_spt)] xchg cx,ax div word [VAR(_spt)] xchg cx,dx ; DX:AX=quotient, CX=remainder=sector (S) - 1 ; Divide quotient by number of heads: mov di,ax mov ax,dx xor dx,dx div word [VAR(_heads)] xchg di,ax div word [VAR(_heads)] xchg di,dx ; DX:AX=quotient=cylinder (C), DI=remainder=head (H) ; Error if cylinder >=1024 or dx,dx ; DX != 0; so cyl >= 65536 stc jne rsc_2 cmp ah,4 ; AH >= 4; so cyl >= 1024 cmc jb rsc_2 ; move variables into registers for INT 13h AH=02h mov dx,di mov dh,dl ; DH=head inc cx ; CL5:0=sector mov ch,al ; CH=cylinder 7:0 shl cl,1 shl cl,1 shr ah,1 rcr cl,1 shr ah,1 rcr cl,1 ; CL7:6=cylinder 9:8 mov dl,[VAR(_int13_drive_num)] ; INT 13h AH=02h is called once for each sector. Multi-sector reads ; may fail if we cross a track or 64K boundary mov ax,0201h ; AH=02h, AL=num_sectors int 13h jnc rsc_2 ; reset drive xor ax,ax int 13h jc rsc_2 ; try read one more time mov ax,0201h int 13h rsc_2: pop ax pop cx pop dx jc rsc_4 ; increment segment part of address, increment LBA sector number, and loop mov di,es add di,[VAR(_para_per_sector)] mov es,di inc ax jne rsc_3 inc dx rsc_3: loop rsc_1 rsc_4: ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Reads word [_lba_cmd_pkt + 2] sectors ; starting with sector number qword [_lba_cmd_pkt + 8] into memory ; starting at far address dword [_lba_cmd_pkt + 4] ; from drive number byte [_int13_drive_num] ; Returns carry set if error. Modifies AX, DX, SI ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; read_sectors_lba: mov si,_lba_cmd_pkt mov dl,[VAR(_int13_drive_num)] mov ah,42h int 13h jnc rsl_1 ; reset drive xor ax,ax int 13h jc rsl_1 ; try read one more time mov ah,42h int 13h rsl_1: ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; times (510 + $$ - $) nop db 55h, 0AAh ; 510 bootsector magic values