Page 1 of 1

int 13h ah 42h start sector

Posted: Mon Oct 18, 2021 8:34 am
by twixuss
I'm trying to read from disk using int 13h ah 42h and it works fine only if I read the whole kernel in one call.
When reading in chunks it seems like only first call is having effect.
And I guess it works only when source sector in disk address packet is equal to 1.
I tried debugging it in bochs and it showed me that every read except first does not change the memory.
I'm interested to know why this happens.

Here's the boot code:

Code: Select all

kernel_offset equ 0x7E00 ; The same one we used when linking the kernel
port_com1     equ 0x3f8

[bits 16]
org 0x7c00

e_read equ 0

sectors_per_iteration equ 1

boot_main_16:
	mov [boot_disk_id], dl

	mov ax, 0
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax

	mov sp, 0x7c00 ; free memory from 0x500 to 0x7c00
	mov bp, sp

	mov si, 0
	mov ds, si
	mov si, disk_address_packet
	mov ah, 0x42
	mov dl, [boot_disk_id]

	mov bx, kernel_size_in_sectors ; remaining sectors count

.read_next:
	cmp bx, sectors_per_iteration
	jg .more_remaining
	mov word [disk_address_packet.sectors_to_transfer], bx
	jmp .update_remaining_sector_count
.more_remaining:
	mov word [disk_address_packet.sectors_to_transfer], sectors_per_iteration
.update_remaining_sector_count:
	sub bx, word [disk_address_packet.sectors_to_transfer]

	mov di, 3 ; try count
.retry_read:
	stc
	int 0x13
	jnc .read_success

	.read_error:
		dec di
		test di, di
		jnz .retry_read
		jmp shutdown

	.read_success:
		test bx, bx
		jz .read_done
		add dword [disk_address_packet.destination_segment], sectors_per_iteration*512/16
		add dword [disk_address_packet.source_sector], sectors_per_iteration
		jmp .read_next

.read_done:
	call kernel_offset
	call shutdown

shutdown:
	mov dx, 0x604
	mov ax, 0x2000
	out dx, ax
	cli
	hlt
	jmp shutdown

boot_disk_id: db 0

disk_address_packet:
.size:                db 16
.reserved:            db 0
.sectors_to_transfer: dw 1
.destination_offset:  dw 0
.destination_segment: dw kernel_offset/16
.source_sector:       dq 1

times 510-($-$$) db 0
dw 0xaa55

kernel_size_in_sectors equ 63

Re: int 13h ah 42h start sector

Posted: Mon Oct 18, 2021 2:35 pm
by Octocontrabass

Code: Select all

boot_main_16:
	mov [boot_disk_id], dl
You're accessing memory through DS before you've set DS to a known value.

Code: Select all

	mov sp, 0x7c00 ; free memory from 0x500 to 0x7c00
You're setting SP without setting SS, so your stack is at an unknown location.

Code: Select all

		add dword [disk_address_packet.destination_segment], sectors_per_iteration*512/16
That's a word, not a dword.

Code: Select all

kernel_size_in_sectors equ 63
How big is your kernel in bytes?

Re: int 13h ah 42h start sector

Posted: Tue Oct 19, 2021 1:26 am
by twixuss
Octocontrabass wrote:How big is your kernel in bytes?
32256 bytes.
Octocontrabass wrote:You're accessing memory through DS before you've set DS to a known value.
You're setting SP without setting SS, so your stack is at an unknown location.
Yes but qemu and bochs seem to intialize all segment registers with zeros so that's not the problem.
Octocontrabass wrote:That's a word, not a dword.
True, but that didn't matter because x86 is little endian and addition didn't overflow.

I printed sectors_to_transfer, source_sector, and destination_segment before each read and they look correct.

Code: Select all

0001 sectors read from 0001 into 07e0
0001 sectors read from 0002 into 0800
0001 sectors read from 0003 into 0820
...........
But still, memory at 0x8000 remains empty.

I also tried reading from sector 0x2 into segment 0x7e0 and it didn't work.

Re: int 13h ah 42h start sector

Posted: Tue Oct 19, 2021 9:04 am
by Klakap
twixuss wrote:Yes but qemu and bochs seem to intialize all segment registers with zeros so that's not the problem.
Everything you need to fix this is move first line after line mov ds, ax

Code: Select all

	mov si, 0
	mov ds, si
	mov si, disk_address_packet
You already set ds to right value, so you just can remove first and second line.

You are able to read 127 sectors per one packet, so for testing you can just load whole kernel through one packet and test if it was loaded right.

Just control question, are you reading from hard disk?

Re: int 13h ah 42h start sector

Posted: Tue Oct 19, 2021 10:58 am
by quirck
Try setting ah to 0x42 immediately before int 0x13, as each successful call to this BIOS function resets ah to zero.

Re: int 13h ah 42h start sector

Posted: Tue Oct 19, 2021 12:17 pm
by Octocontrabass
twixuss wrote:Yes but qemu and bochs seem to intialize all segment registers with zeros so that's not the problem.
It will be a problem elsewhere.
twixuss wrote:
Octocontrabass wrote:That's a word, not a dword.
True, but that didn't matter because x86 is little endian and addition didn't overflow.
It works, but it wastes at least one byte. Space is limited in a boot sector.

Re: int 13h ah 42h start sector

Posted: Tue Oct 19, 2021 2:56 pm
by BigBuda
twixuss wrote:Yes but qemu and bochs seem to intialize all segment registers with zeros so that's not the problem.
It's not advisable to make this kind of assumptions (as in don't assume anything, always initialize everything). The fact that they do that now, doesn't mean that all versions always will. Per your own words: "seem to", and not "ensure that". Also, if you intend to one day use your kernel outside of the sandbox, you definitely can't make that assumption. If you make that assumption now, especially if you don't document it, you'll forget to fix it later and you'll have one hell of a hard time debugging it when it bites you. Assumptions are the mother of all undefined behaviors.