1

I am writing a bootloader in x86-16 assembly on a floppy disk, meaning that I will have to read from the disk in order to load more of my code, however, every time I attempt to read the disk and check the disk status code, I always get 0x04 - sector not found. I have attempted to read with CX set to 0x0000, 0x0001, and 0x0101, but I don't really know what to do, or what I am doing wrong.
INT 13,1 - Disk Status Codes
INT 13,2 - Read Disk Sectors

BITS 16

%include "C:\x86asm\nasm\nasm.asm"
    ;%macro pad 1-2 0
    ;   times %1 - ($ - $$) db %2
    ;%endmacro
    ;%idefine PUSHW PUSH STRICT WORD
    ;%idefine PUSHD PUSH STRICT DWORD
[org 0x7C00]

; https://stanislavs.org/helppc/        ;; BIOS
; https://c9x.me/x86/                   ;; Instruction Set
; https://wiki.osdev.org/               ;; OS Development

; absolute address = (segment << 4) + address
; to simulate NES/SNES style memory mapping (banks), only use bits[9..15] ($x000)
            
            JMP 0x0000:_start           ; ensure CS = $0000
_start:
            CLI                         ; clear interrupt flag (disable
                                        ;   interrupts, opposite of 6502)
            CLD                         ; clear direction flag
            
            PUSH CS
            POP DS                      ; prepare for puts / puthexbyte
            PUSH CS
            POP SS                      ; set up stack segment
            MOV SP, 0x7C00
            
            ;; set graphics ;;
            
            MOV AX, 0x0012              ; set screen mode
            INT 0x10
            
            MOV AH, 0x0B
            MOV BX, 0x0201
            INT 0x10
            
            MOV DX, 0x0D22              ; display "LOADING..."
            MOV BX, 0x0007
            MOV SI, loadstr
            CALL putsl
            
            MOV AH, 0x86                ; wait a moment...
            MOV CX, 0x000F
            INT 0x15
            
            ;; load floppy disk ;;
            
            MOV BP, 0x0800              ; if fail, read x times
.loadfailure:
                SUB BP, 0x0100          ; decrement # of tries left
                
                MOV AH, 0x02            ; print # of tries left
                XOR DX, DX
                INT 0x10
                MOV DX, BP
                CALL puthexbyte
                
                MOV AH, 0x00            ; reset disk system
                MOV DL, 0x00
                INT 0x13
                
                MOV AX, 0x0201          ; read
                MOV CX, 0x0101
                XOR DX, DX
                PUSHW 0x1800            ; write to $18000 ~ $1FFFF
                POP ES
                XOR BX, BX
                INT 0x13
                
                PUSHF
                
                MOV DH, AH              ; show error code
                CALL puthexbyte
                
                POPF
                
                JNC .loadsuccess
                    TEST BP, BP
                    JNE .loadfailure
                        MOV DX, 0x0D0F      ; read fail;
                        MOV SI, badload     ;   print msg
                        CALL putsl
                        
                        MOV AH, 0x86        ; wait
                        MOV CX, 0x001E
                        INT 0x15
                        
                        INT 0x18        ; boot windows
.loadsuccess:
            
            MOV DX, 0x0D0F          ; read success;
            MOV SI, nosystem        ;   DOS not finished,
            CALL putsl              ;   tell user
            
            MOV AH, 0x86            ; wait
            MOV CX, 0x001E
            INT 0x15
            
            JMP 0x1000:0x8000       ; boot test
            
            
putsl:
    ; [DX]    : (Y,X)
    ; (AH)
            MOV AH, 0x02
            INT 0x10                ; set cursor position
puts:
    ; [DS:SI] : String
    ; (AX, BX, SI)
            MOV AH, 0x0E            ; teletype mode
            MOV BX, 0x000F          ; set white text attribute
.putsloop:
                LODSB               ; load character from [DS:SI++]
                TEST AL, AL         ; check if NULL (x86 MOV does not
                JE .endputs         ;   change zero-flag unlike 6502 LDA/LDX/LDY)
                    INT 0x10        ; print character
                    JMP .putsloop   ; loop until NULL
.endputs:
            RET
            
            
puthexbyte:
    ; [DH] : Value
    ; (AX, DH, BX)
            MOV AH, 0x0E
            
            MOV BX, asciihex
            MOV AL, DH
            SHR AL, 4
            XLAT
            MOV BX, 0x000F
            INT 0x10                ; print character
            
            MOV BX, asciihex
            MOV AL, DH
            AND AL, 0x0F
            XLAT
            MOV BX, 0x000F
            INT 0x10
            
            RET
asciihex:
    db "0123456789ABCDEF", 0
            
            
loadstr:
    db "LOADING...", 0
badload:
    db "Unable to load disk. Attempting to load Windows...", 0
nosystem:
    db "Operating System is incomplete. Loading Windows...", 0
tststr:
    db "Disk read success. INT 0x20 set success. Jump success.", 0

    
    pad 0x01FE                          ; pad to end of boot sector
    dw 0xAA55                           ; floppy disk boot sector signature
    
    ; code
            
            PUSHW 0x0000                ; test setting INT
            POP DS                      ;   (tested; works when in
            MOV [4 * 0x20], DWORD putsl ;   boot sector)
            
            MOV DX, 0x0D0D              ; test INT by
            MOV SI, tststr              ;   printing
            INT 0x20                    ;   string
            
            MOV AH, 0x86                ; wait
            MOV CX, 0x001E
            INT 0x15
            
            INT 0x18                    ; boot windows
    
    pad 0x0400                          ; pad to end of sector 1
    
    ;incbin "os.bin"
    
    pad 0x00167FFF                      ; pad to disk end
    db 0x00

Edit:
An explanation on how to convert disk sectors and tracks (ie. CX in INT 13,2) into a "linear address" would be greatly appreciated, as the method I am using to get my code onto a floppy disk has me opening the program HxD and manually copying and pasting my binary onto the the disk.
Also, the disk I am using is 'unformatted' (as far as Windows is concerned). Also, also, if this changes anything, my PC's BIOS is (msinfo32)"American Megatrends Inc. 5.35, 2008-12-16."

はるき
  • 141
  • 1
  • 9
  • I wouldn't do `xor dx, dx` (I'd prefer `xor dh, dh`) as you can use the value in DL that is passed by the BIOS to the bootloader which already contains the boot drive number. – Michael Petch Nov 24 '20 at 19:44
  • How big is your disk image file? What kind of media? Floppy? Hard Disk? If floppy what media size? Some systems may not allow you to do a multitrack read with Int 13h/AH=2 . you seem to be reading 64 at a time. Are you running on an emualtor or real hardware? If an emulator or VM which one? – Michael Petch Nov 24 '20 at 19:56
  • Unclear why you don't just use BP normally and use the value 8 rather than do all the work in the high 8 bits of the register. – Michael Petch Nov 24 '20 at 19:58
  • @MichaelPetch I am actually using both DOSBox and hardware with a 1.44MB floppy. I am using `BP` strangely because I omitted code that prints the # of read attempts left. My subroutine `puthexbyte` uses `DH` as the input, so it was easier to use `BP` this way than move the low byte of `BP` into `DX`. – はるき Nov 25 '20 at 03:04
  • This code probably works on DOSBox I assume? I think it allows number of sectors to be read from a floppy as high as 72 I think . On real hardware you may not have the ability to cross a cylinder boundary. Does the code work if you load as an example 9 or 18 sectors at a time? – Michael Petch Nov 25 '20 at 03:06
  • Not related to your disk read the code assumes that DS is set to zero (because you use ORG 0x7c00). You shouldn't assume the segments have a particular value in them. At the beginning of the bootloader use `xor ax, ax` `mov ds, ax` to zero DS. You should also set the stack somewhere where it won't be clobbered by any disk read. The BIOS could have set the default stack anywhere. You could put the stack below your bootloader when you set DS to zero with `xor ax, ax` `mov ds, ax` `mov ss, ax` `mov sp, 0x7c00`. Now DS=SS=0 and SS:SP is 0x0000:0x7c00 which is a stack that grows down beneath 0x7c00 – Michael Petch Nov 25 '20 at 14:27
  • Oh I just looked you are using DOSBox and not BOCHS. I tried this code with DOSBox by booting using DOSBox command `boot disk.img` and it printed `00` – Michael Petch Nov 25 '20 at 15:57
  • Would it be possible to show your entire bootloader. And which sectors from the disk are you trying to load from? 64 sectors from the boot sector onward? 64 sectors from the sector after the bootloader? And to clarify this gives an error on DOSBox as well? I'm asking for the complete bootloader because I think there is more going on here than the code you are showing. I tried this code in DOSBox and there was no error with a floppy disk image of 1.44MiB in size. If this worked in DOSBox but not on real hardware I'd try reading just one sector (AL=1 rather than 0x40) as a test – Michael Petch Nov 25 '20 at 15:59
  • 1
    @MichaelPetch Using `AL = 0x01` worked. Thanks. I edited the post to show my full code. It had worked in DOSBox before I got it to work on hardware. As you noted in an earlier comment, mode code does assume `DS = 0x0000`. In omitted code, I did `JMP 0x0000:0x7C05` followed by `PUSH CS`, `POP DS`, `PUSH CS`, `POP SS`, `MOV SP, 0x7C00`. Note that I am originally a 6502/NES programmer, so I'm not used to working with disks and code in RAM, but with ROM banks. – はるき Nov 25 '20 at 19:37
  • 2
    My answer here covers the formula to convert a LBA (Linear Block address) to CHS: https://stackoverflow.com/a/45495410/3857942 . This answer has a bit of additional info: https://stackoverflow.com/questions/54313624/reading-more-sectors-than-there-are-on-a-track-with-int-13h . 1.44MiB media has a sector per track (SPT) of 18, and 2 heads. – Michael Petch Nov 25 '20 at 19:45
  • 1
    I have an additional SO answer with more info and it also includes a CHS to LBA translator in C that can help you convert from a Logical Block Address to CHS: https://stackoverflow.com/a/59416266/3857942 – Michael Petch Nov 25 '20 at 19:55
  • 1
    I have deleted my answer because it does not make sense any more given your full code ... – Binarus Nov 26 '20 at 07:15

0 Answers0