I am writing a kernel for my operating system and I have ran into a problem while loading a sector of a disk to memory.
Here is the portion of the code of the function that loads the sector from the disk:
mov ax, #0x3000
mov es, ax
mov ax, #0x0201
mov bx, word ptr [bp - 6] ; bx = 0x000, 0x200, 0x400, ...
xor ch, ch
mov cl, byte ptr [bp - 8] ; cl = target cluster to read
xor dx, dx
int 0x13
jc load_cluster_carry ; carry == 1 when error
xor ax, ax
inc ax
jmp load_cluster_end
load_cluster_carry:
xor ax, ax
load_cluster_end:
mov word ptr [bp - 10], ax
And the function cannot read from sector 19. So I checked AH register and its value was 0x01.
mov ax, #0x0201 mov bx, word ptr [bp - 6] ; bx = 0x000, 0x200, 0x400, ... xor ch, ch mov cl, byte ptr [bp - 8] ; cl = target cluster to read xor dx, dx int 0x13
The comment ; bx = 0x000, 0x200, 0x400, ...
tells us that you want to read multiple sectors. From xor ch, ch
(CH for Cylinder) and xor dx, dx
(DH for Head), we can conclude that you seem to expect to find all of those sectors on the same Cylinder (0) and Head (0). This will not be the case: at some point you will have read all the available sectors on the current track and you will need to advance to the next track.
The answer at How are all disk sectors iterated in assembly? has a working code that shows how to do that correctly. The code does not guess about the disk's geometry and asks BIOS for these values.
Your xor dx, dx
also zeroes the DL register that specifies the drive to use. Unless you are very sure that it needs to be 0, I would advice that instead you use the value that BIOS gave you when your bootloader got started. The drive id is passed to you in the DL register, and BTW it's the only information that BIOS provides when your bootloader begins.
jc load_cluster_carry ; carry == 1 when error xor ax, ax inc ax jmp load_cluster_end load_cluster_carry: xor ax, ax load_cluster_end: mov word ptr [bp - 10], ax
You can replace the above by next simpler/cleaner code:
cmc
sbb ax, ax
neg ax
mov [bp - 10], ax