INT 13, AH=42h fails with AH=1, CF=1

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
evgok
Posts: 3
Joined: Sat Sep 06, 2025 3:51 am

INT 13, AH=42h fails with AH=1, CF=1

Post by evgok »

I am trying to write a simple bootloader which loads my program from LBA=1 into memory and jumps to its start. I emulate my bootloader in qemu with -drive flag passed. When I try to read blocks from disk with int 13, ah=42h, I fail for some reason. What's the issue? How can I solve it? I looked up my issue in osdev forum but most of the times the members had their problem miraculously solved. Source (compiled with gnu as):

Code: Select all

.code16

.include "source/constants.S"

.global _start0
.global PRINT_STRING
.global HALT

.section .text
.global _start0
_start0:
        ljmp $0, $L0                # Canonicalize (%CS):%IP.
L0:
        xorw %ax, %ax
        movw %ax, %ds                # Load Segment Registers.
        movw %ax, %es
        movw %ax, %ss
        movw %ax, %fs
        movw %ax, %gs

        movw $STACK_TOP, %sp        # Prepare stack.

        sti                         # Set interrupt flag.
        
        movw $BOOT0SEQ_STR, %si
        movb $0x07, %dh
        call PRINT_STRING

INIT_ATTEMPT1:
        movb $0, %ah                # Reset drive controller.
        int $0x13
        jnc INIT_SUCCESS

INIT_ATTEMPT2:
        movb $0, %ah                # Try again.
        int $0x13
        jc FAILURE

INIT_SUCCESS:
        cmpb $0x80, %dl             # Check whether we boot from hard drive or floppy.
        jl LBA_FAILURE_OR_FLOPPY

HARDDRIVE:                          # We boot from a hard-drive.
        movb $0x41, %ah             # Check whether we support Disk Address Packet.
        movw $0x55AA, %bx
        int $0x13
        jc LBA_FAILURE_OR_FLOPPY
        cmpw $0xAA55, %bx
        jne LBA_FAILURE_OR_FLOPPY
        test $1, %cx
        jz LBA_FAILURE_OR_FLOPPY

LBA_SUCCESS:                        # We can read from a disk using Disk Address Packet.
        movb $0x42, %ah
        movw $DAP, %si              # %ds is arleady set to zero.
        int $0x13
        jc FAILURE                  # Test whether read was successful.

        jmp SUCCESS

LBA_FAILURE_OR_FLOPPY:              # We boot from a floppy disk or the extension check failed.
FLOPPY_ATTEMPT1:
        movw $0x0210, %ax
        movw $0x0001, %cx
        movb $0, %dh
        movw $BOOT1_START, %bx      # %es is arleady set to zero.
        int $0x13
        jnc FLOPPY_SUCCESS

FLOPPY_ATTEMPT2:                    # Try reading for a second time!
        movw $0x0210, %ax
        movw $0x0001, %cx
        movw $BOOT1_START, %bx
        int $0x13
        jc FAILURE

FLOPPY_SUCCESS:
        jmp SUCCESS

SUCCESS:
        movw $BOOT0_SUCCESS_STR, %si
        movb $0x0A, %dh             # 0x0A -- Light Green.
        call PRINT_STRING
        jmp BOOT1_START

FAILURE:                            # Something went wrong!
        movw $ERROR_MESSAGE, %si 
        movb $0x04, %dh             # 0x04 -- Red.
        call PRINT_STRING
        jmp HALT

HALT:
        cli
1:      hlt 
        jmp 1b

PRINT_STRING:                       # PRINT_STRING(string : %si, color : %dh)
        movb (%si), %al
        inc %si
        orb %al, %al
        jz PRINT_RET
        call PRINT_CHAR
        jmp PRINT_STRING

PRINT_RET:
        ret

PRINT_CHAR:
        movb $0x0E, %ah
        movb $0x00, %bh
        movb %dh, %bl
        int $0x10
        ret

.balign 4
DAP:        # Disk Adress Packet structure.
DAP_packet_size:    .byte 0x10
DAP_zero:           .byte 0x00
DAP_Nsectors:       .word 0x01
DAP_buffer:         .long BOOT1_START
DAP_lower_bits:     .long 0x01
DAP_upper_bits:     .long 0x00

.byte 0x00

BOOT0SEQ_STR:       .asciz "[[ BootSeq0 ]]: "
BOOT0_SUCCESS_STR:  .asciz "Succes!\n\r"
ERROR_MESSAGE:      .asciz "Error: Could not find Boot1!\n\r"

.space 510 - (. - _start0)
.word 0xAA55    # Boot Signature.
Program state prior to executing int13, ah=42h:

Code: Select all

eax           	0x4200            16896
ecx            	0x7                 	7
edx            	0x780              1920
ebx            	0xaa55           43605
esp            	0x9000           0x9000
ebp            	0x0                 0x0
esi            	0x7c9c           31900
edi            	0x0                 0
eip            	0x7c48           0x7c48
eflags         	0x202             [ IOPL=0 IF ]
cs            	0x0                 0
ss             	0x0                 0
ds             	0x0                 0
es             	0x0                 0
fs             	0x0                 0
gs             	0x0                 0
Last edited by evgok on Sat Sep 06, 2025 2:51 pm, edited 1 time in total.
MichaelPetch
Member
Member
Posts: 857
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: INT 13, AH=42h fails with AX=1, CF=1

Post by MichaelPetch »

You don't show constants.h. I assume from the register dump you set STACK_TOP to 0x9000. I can't tell what you set BOOT1_START to. You should show us constant.h to know for sure. You should also show us how you build the binary files and disk image. With that being said I set BOOT1_START to 0x7E00 and use this make file and it seems to work for me in QEMU:

Code: Select all

AS = as
LD = ld	
DD = dd
OBJCOPY = objcopy
QEMU = qemu-system-i386

MAIN_SRC = main.s
MAIN_BIN = $(basename $(MAIN_SRC)).bin
MAIN_ELF = $(basename $(MAIN_SRC)).elf
MAIN_OFFSET = 0x7E00

BOOT_SRC = boot.s
BOOT_BIN = $(basename $(BOOT_SRC)).bin
BOOT_ELF = $(basename $(BOOT_SRC)).elf
BOOT_OFFSET = 0x7C00

DISK_IMG = disk.img

.PHONY: clean all run

all: $(DISK_IMG)

%.o : %.s
	$(AS) --32 -o $@ $<

%.bin : %.elf
	$(OBJCOPY) -O binary $< $@

$(MAIN_ELF): $(basename $(MAIN_SRC)).o
	$(LD) -m elf_i386 -Ttext $(MAIN_OFFSET) -o $@ $<

$(BOOT_ELF): $(basename $(BOOT_SRC)).o
	$(LD) -m elf_i386 -Ttext $(BOOT_OFFSET) -o $@ $<

$(DISK_IMG): $(BOOT_BIN) $(MAIN_BIN)
	$(DD) if=/dev/zero of=$@ bs=1M count=10
	$(DD) if=$(BOOT_BIN) of=$@ conv=notrunc
	$(DD) if=$(MAIN_BIN) of=$@ seek=1 conv=notrunc

run: $(DISK_IMG)
	$(QEMU) -drive file=$<,format=raw,if=ide,index=0,media=disk

clean:
	rm -f *.o *.elf $(BOOT_BIN) $(MAIN_BIN) $(DISK_IMG)
evgok
Posts: 3
Joined: Sat Sep 06, 2025 3:51 am

Re: INT 13, AH=42h fails with AX=1, CF=1

Post by evgok »

MichaelPetch wrote: Sat Sep 06, 2025 1:52 pm With that being said I set BOOT1_START to 0x7E00 and use this make file and it seems to work for me in QEMU: ...
Just out of curiousity: on which OS do you built the bootloader? I copied your makefile with a few changes (removed stuff related to main.s) and yet again my bootloader failed to read from disk. I am using Ubuntu under WSL in Windows 10, soon I'll try to built my bootloader on machine with Arch Linux installed. Perhaps something is wrong with WSL?
MichaelPetch
Member
Member
Posts: 857
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: INT 13, AH=42h fails with AH=1, CF=1

Post by MichaelPetch »

The stuff you removed probably made it fail. However your question on stackoverflow showed me your Makefile where I made this comment:
Your disk image will only be 512 bytes in size since you only have a bootsector in it. When int 13h tries to read from it it is beyond the disk image size and will return an error. As a test what happens if you fake a second sector (filled with all zeroes) by doing `truncate -s 1024 $@` right after `$(LD) -T$(SRC_DIR)/linker.ld --format binary -o $@ $<`. The better fix is to add a second sector to bootloader.img with code you actually want to run. This is why in my answer on your OSDev question earlier worked. I created a disk image with a do nothing loop in the second sector
I don't think it is the environment your on building it under, but I use WSL2 Ubuntu 18.04 to answer your question.

Note that the `truncate` will simply expand a file that is less than 1024 bytes to a size of 1024 That will make it exactly 2 sectors long and allow int 13h commands to read LBA sector 1 (second sector) from the disk. In the end you can't read a sector that isn't physically in the image file when running under QEMU
evgok
Posts: 3
Joined: Sat Sep 06, 2025 3:51 am

Re: INT 13, AH=42h fails with AH=1, CF=1

Post by evgok »

Sorry I wasn't posting in a while.
Anyway, thank you for helping me out! My simple bootloader finally works as expected! The problem was indeed with disk sizes (and unfortunetaly, my ignorance).
Post Reply