FAT16 bootloader

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.
User avatar
cakehonolulu
Member
Member
Posts: 37
Joined: Thu Jun 16, 2016 9:35 am
Libera.chat IRC: cakehonolulu

FAT16 bootloader

Post by cakehonolulu »

Hello!
I'm trying to figure out a problem I'm having with a two-stage bootloader designated to be used on a FAT16 disk.
Bochs throws this error constantly: int13_harddisk: function 42. LBA out of range
So my initial guess is that something is going up either with the DAP setup or with the way I'm setting up the stack (I've read somewhere it needs to be aligned for this to work) or if segments are going crazy (I really hate Real Mode, but everyday I try doing my best to embrace it hahah) or if my BPB is wrong so I'll try to give as much info as I can.

I'm using i386-elf-as for compiling (AT%T Syntax)

For the initial code setup (Including the BPB) I do it this way:

Code: Select all

.code16
.global boot0
.global init0_fat16
.section .text
init0_fat16:	
# TODO/HACK: Do we really need: .intel_syntax noprefix and .att_syntax prefix in jmp short boot0 ? (EDIT for osdev forum, I've inspected both outcomes jmp short & normal jmp on a dissasembler and they both seem to produce 0xEB instead of 0xEE; so I'm debating on what to leave this like)
.intel_syntax noprefix
	jmp short boot0
.att_syntax prefix
	nop

bpb:
  oem_string:				.ascii	"INITIUM1"
  sector_size:				.word	0x200
  sectors_per_cluster:				.byte	4
  reserved_sectors:			.word	4
  number_of_fats:				.byte	2
  total_fat_directory_entries:			.word	512
  total_sectors:			.word	20160
  media_descriptor_type:			.byte	0xF8
  sectors_per_fat:					.word	20
  spt:						.word	63
  heads_count:				.word	16
  hidden_sector_count:		.int	0
  high_sector_count:		.int	0
  bios_boot_drive:			.byte	0x80
  reserved:					.byte	0
  extended_bpb_signature:	.byte	0x29
  volumeid_name:			.int	0xd7450e5
  volume_label:				.ascii	"BOOTLOAD   "
  fs_type:					.ascii	"FAT16   "

boot0:
	xor %ax, %ax
	mov %ax, %ds
	mov %ax, %es
	mov $0x0900, %bx
	cli
	mov %bx, %ss
	mov %ax, %sp
	mov %sp, %bp
	sti
	cld

	mov %dl, bios_boot_drive

	xor %dx, %dx
	xor %ax, %ax
	
	mov bios_boot_drive, %dl
	
	mov number_of_fats, %ax
	mulw sectors_per_fat
	add reserved_sectors, %ax
	mov %ax, root_dir_offset

	xchg %bx, %ax

	mov sector_size, %ax
	mov $0x20, %cx
	div %cx

	xchg %cx, %ax
	mov total_fat_directory_entries, %ax
	div %cx
	add %bx, %ax
	mov %ax, data_cluster_offset

	xor %dx, %dx

.loop:
	xchg %bx, %bx
	mov root_dir_offset, %ax
	add %dx, %ax
	mov $0x200, %bx
	mov $0x01, %cx
	push %dx
	call read_sectors

	mov $0x200, %bx
	mov %bx, %ax
	add sector_size, %ax
.loop_dir_entries:
	mov stage2_name, %di
	mov $0x06, %cx
	mov %bx, %si
	rep cmpsb
	je .match

	add $0x20, %bx
	cmp %bx, %ax
	jne .loop_dir_entries

	pop %dx
	inc %dx
	cmp $0x80, %dx
	jne .loop
	jmp error

.match:
	movw 0x1A(%bx),%ax

	sub $0x02, %ax
	mulb sectors_per_cluster
	add data_cluster_offset, %ax

	mov $1, %cx # STAGE 2 Size, hardcoded for now
	mov $0x0400, %bx

	call read_sectors
	jmp $0x0, $0x1000


error:
	cli
	hlt

read_sectors:
	pusha
	mov %eax, dap_sector_low
	mov %es, dap_segment
	mov %bx, dap_offset
.extended_read:
	mov $0x42, %ah
	mov bios_boot_drive, %dl
	mov dap, %si
	int $0x13
	jnc .read_ok

	mov $0x0e, %ah
	mov $0x41, %al
	int $0x10

	xor %ax, %ax
	int $0x13
	jmp .extended_read

.read_ok:
	popa
	inc %eax
	add $0x200, %bx
	jnc .no_carry

	mov %es, %dx
	add $0x10, %dh
	mov %dx, %es
.no_carry:
	dec %cx
	jz read_sectors_exit
	jmp read_sectors

read_sectors_exit:
	ret


root_dir_offset: .word 0x0000
data_cluster_offset: .word 0x0000
stage2_name: 	.ascii "STAGE2"
stage2_cur_offset: .word 0x0000
stage2_cur_segment: .word 0x0000

.align 4
dap:
dap_size:		.byte 0x10
dap_reserved:		.byte 0x00	
dap_block_count:	.word 0x01
dap_offset:		.word 0x1000
dap_segment:		.word 0x00
dap_sector_low:		.int 0x01
dap_sector_high:	.int 0x00

.fill 510-(.-init0_fat16), 1, 0
.word 0xAA55
My link script goes like this:

Code: Select all

ENTRY(init0_fat16)

OUTPUT_FORMAT(elf32-i386)

OUTPUT_ARCH(i386)

SECTIONS {

    . = 0x7C00;

    .text :
    {
        *(.text)
    }

    .rodata :
    {
        *(.rodata)
    }

    .data :
    {
        *(.data)
    }

    .bss :
    {
        *(.bss)
    }
}
And I build the image like this (In case this messes up something):
bximage -mode=create -hd=10M -q hdd.img
mkfs.fat -F 16 hdd.img
mkdir disk/
dd conv=notrunc if=bootloader/boot0.bin of=hdd.img bs=512 seek=0 status=none
sudo mount -t msdos -o loop hdd.img disk/
sudo cp bootloader/boot1.bin disk/STAGE2
sudo umount disk/
rm -r disk/

I really can't figure exactly what's wrong, but I've double-checked the BPB info using Ultimate64 and a few bits more that I don't remember as of writing but still, same output.

Any directions you guys recommend?
Thanks for your time!
Hope you have a nice day!
Octocontrabass
Member
Member
Posts: 5567
Joined: Mon Mar 25, 2013 7:01 pm

Re: FAT16 bootloader

Post by Octocontrabass »

cakehonolulu wrote:Bochs throws this error constantly: int13_harddisk: function 42. LBA out of range
Since you're using Bochs, try using its debugger. Set a breakpoint (or insert a magic breakpoint) at the "int $0x13" instruction, then dump all of the registers and the contents of your DAP. Don't forget segment registers!

If you don't see the problem in the register dump, post it here.
User avatar
cakehonolulu
Member
Member
Posts: 37
Joined: Thu Jun 16, 2016 9:35 am
Libera.chat IRC: cakehonolulu

Re: FAT16 bootloader

Post by cakehonolulu »

Octocontrabass wrote:
cakehonolulu wrote:Bochs throws this error constantly: int13_harddisk: function 42. LBA out of range
Since you're using Bochs, try using its debugger. Set a breakpoint (or insert a magic breakpoint) at the "int $0x13" instruction, then dump all of the registers and the contents of your DAP. Don't forget segment registers!

If you don't see the problem in the register dump, post it here.
Before int13

Code: Select all

rax: 00000000_0000422c
rbx: 00000000_00000200
rcx: 00000000_00090001
rdx: 00000000_00000080
rsp: 00000000_0000ffec
rbp: 00000000_00000000
rsi: 00000000_000e0010
rdi: 00000000_0000ffac
r8 : 00000000_00000000
r9 : 00000000_00000000
r10: 00000000_00000000
r11: 00000000_00000000
r12: 00000000_00000000
r13: 00000000_00000000
r14: 00000000_00000000
r15: 00000000_00000000
rip: 00000000_00007cf4
eflags 0x00000202: id vip vif ac vm rf nt IOPL=0 of df IF tf sf zf af pf cf
Before calling int13, I can see that ah=42 (Extended Read), dl contains the bios drive number, and i have the buffer prepared, but something looks wrong to me, the buffer, am I right?

After calling int13:

Code: Select all

rax: 00000000_0000012c
rbx: 00000000_00000200
rcx: 00000000_00090001
rdx: 00000000_00000080
rsp: 00000000_0000ffec
rbp: 00000000_00000000
rsi: 00000000_000e0010
rdi: 00000000_0000ffac
r8 : 00000000_00000000
r9 : 00000000_00000000
r10: 00000000_00000000
r11: 00000000_00000000
r12: 00000000_00000000
r13: 00000000_00000000
r14: 00000000_00000000
r15: 00000000_00000000
rip: 00000000_00007cf8
eflags 0x00000203: id vip vif ac vm rf nt IOPL=0 of df IF tf sf zf af pf CF
ah shows the error code "01", according to ralph's interrupt list, 01 stands for "invalid function in AH or invalid parameter"; which kinda confirms that the issue is with how I setup the buffer.

But by the looks of it, I don't exactly know how to fix it, to me, it looks good; but again, I could 100% be missing something about real mode segment:offset addressing which is a pain for me.

Any inputs?

Thanks for your previous answer and for your time!
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: FAT16 bootloader

Post by MichaelPetch »

Seems to me:

Code: Select all

mov dap, %si
should be

Code: Select all

mov $dap, %si
since you want the address of DAP in SI not the word value stored at memory location DAP in SI.
User avatar
cakehonolulu
Member
Member
Posts: 37
Joined: Thu Jun 16, 2016 9:35 am
Libera.chat IRC: cakehonolulu

Re: FAT16 bootloader

Post by cakehonolulu »

MichaelPetch wrote:Seems to me:

Code: Select all

mov dap, %si
should be

Code: Select all

mov $dap, %si
since you want the address of DAP in SI not the word value stored at memory location DAP in SI.
After carefully changing that line of code, bochs now complains about a different error:

int13_harddisk: function 42, error 01 !

Which suggests that I've fixed one bug that I didn't take into account at first glance but the main and bigger one remains, my guess remains the same, to me, it looks like something is wrong with the buffer.
Octocontrabass
Member
Member
Posts: 5567
Joined: Mon Mar 25, 2013 7:01 pm

Re: FAT16 bootloader

Post by Octocontrabass »

Use the Bochs debugger to dump the registers (including segment registers) and the contents of the DAP and post them here.
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: FAT16 bootloader

Post by MichaelPetch »

I'm just eyeballing things and have no intention to run it. But what I told you is a problem but looking at it a bit further this appears to be a problem too:

Code: Select all

mov $0x0400, %bx
You seem to be starting at 0x0000:0x0400 . 0x0000:0x0400 is on top of the BDA (BIOS Data Area). Clobbering that could very well cause Int 13h to fail after the first read. Try starting at 0x600 (or 0x500 on almost all systems will be safe).
User avatar
cakehonolulu
Member
Member
Posts: 37
Joined: Thu Jun 16, 2016 9:35 am
Libera.chat IRC: cakehonolulu

Re: FAT16 bootloader

Post by cakehonolulu »

MichaelPetch wrote:I'm just eyeballing things and have no intention to run it. But what I told you is a problem but looking at it a bit further this appears to be a problem too:

Code: Select all

mov $0x0400, %bx
You seem to be starting at 0x0000:0x0400 . 0x0000:0x0400 is on top of the BDA (BIOS Data Area). Clobbering that could very well cause Int 13h to fail after the first read. Try starting at 0x600 (or 0x500 on almost all systems will be safe).
Same result, but a step in the right direction
User avatar
cakehonolulu
Member
Member
Posts: 37
Joined: Thu Jun 16, 2016 9:35 am
Libera.chat IRC: cakehonolulu

Re: FAT16 bootloader

Post by cakehonolulu »

Octocontrabass wrote:Use the Bochs debugger to dump the registers (including segment registers) and the contents of the DAP and post them here.
Segment registers:

Code: Select all

es:0x0000, dh=0x00009300, dl=0x0000ffff, valid=3                                                                                Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed                                           cs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1                                                                                Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed                                           ss:0x0900, dh=0x00009300, dl=0x9000ffff, valid=7                                                                                Data segment, base=0x00009000, limit=0x0000ffff, Read/Write, Accessed                                           ds:0x0000, dh=0x00009300, dl=0x0000ffff, valid=3                                                                                Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed                                           fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1                                                                                Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed                                           gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1                                                                                Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed                                           ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1                                                                      tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1                                                                        gdtr:base=0x00000000000f9af7, limit=0x30                                                                                idtr:base=0x0000000000000000, limit=0x3ff
Regular registers:

Code: Select all

rax: 00000000_00000444
rbx: 00000000_00000600
rcx: 00000000_00090001
rdx: 00000000_00000000
rsp: 00000000_0000fffe
rbp: 00000000_00000000
rsi: 00000000_000e0226
rdi: 00000000_00005459
r8 : 00000000_00000000
r9 : 00000000_00000000
r10: 00000000_00000000
r11: 00000000_00000000
r12: 00000000_00000000
r13: 00000000_00000000
r14: 00000000_00000000
r15: 00000000_00000000
rip: 00000000_00007cd3
DAP:

Code: Select all

<bochs:12> x /16bx 0x7D29
[bochs]:
0x0000000000007d29 <bogus+       0>:    0x00    0x01    0x00    0x00    0x02    0x00    0x00    0x2c
0x0000000000007d31 <bogus+       8>:    0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
Octocontrabass
Member
Member
Posts: 5567
Joined: Mon Mar 25, 2013 7:01 pm

Re: FAT16 bootloader

Post by Octocontrabass »

cakehonolulu wrote:

Code: Select all

rax: 00000000_00000444
Perhaps I wasn't specific enough... I want to see the registers and DAP immediately before you call INT 0x13.
cakehonolulu wrote:

Code: Select all

<bochs:12> x /16bx 0x7D29
Are you sure that's the right address for your DAP?
User avatar
cakehonolulu
Member
Member
Posts: 37
Joined: Thu Jun 16, 2016 9:35 am
Libera.chat IRC: cakehonolulu

Re: FAT16 bootloader

Post by cakehonolulu »

Octocontrabass wrote:
cakehonolulu wrote:

Code: Select all

rax: 00000000_00000444
Perhaps I wasn't specific enough... I want to see the registers and DAP immediately before you call INT 0x13.
cakehonolulu wrote:

Code: Select all

<bochs:12> x /16bx 0x7D29
Are you sure that's the right address for your DAP?
Registers before int13:

Code: Select all

rax: 00000000_0000422c
rbx: 00000000_00000200
rcx: 00000000_00090001
rdx: 00000000_00000080
rsp: 00000000_0000ffec
rbp: 00000000_00000000
rsi: 00000000_000e7d28
rdi: 00000000_0000ffac
r8 : 00000000_00000000
r9 : 00000000_00000000
r10: 00000000_00000000
r11: 00000000_00000000
r12: 00000000_00000000
r13: 00000000_00000000
r14: 00000000_00000000
r15: 00000000_00000000
rip: 00000000_00007cf1
eflags 0x00000202: id vip vif ac vm rf nt IOPL=0 of df IF tf sf zf af pf cf
Segment registers:

Code: Select all

es:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1                                                                                Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed                                           cs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1                                                                                Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed                                           ss:0x0900, dh=0x00009300, dl=0x9000ffff, valid=7                                                                                Data segment, base=0x00009000, limit=0x0000ffff, Read/Write, Accessed                                           ds:0x0000, dh=0x00009300, dl=0x0000ffff, valid=7                                                                                Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed                                           fs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1                                                                                Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed                                           gs:0x0000, dh=0x00009300, dl=0x0000ffff, valid=1                                                                                Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed                                           ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1                                                                      tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1                                                                        gdtr:base=0x00000000000f9af7, limit=0x30                                                                                idtr:base=0x0000000000000000, limit=0x3ff
DAP:

Code: Select all

0x0000000000007d28 <bogus+       0>:    0x10    0x00    0x01    0x00    0x00    0x02    0x00    0x00
0x0000000000007d30 <bogus+       8>:    0x2c    0x00    0x00    0x00    0x00    0x00    0x00    0x00
DAP should be at offset 128h after inspecting the resulting binary file of the loader. 0x7C00 + 0x128 = 0x7D28
DAP is 16 byte long so x /16bx 0x7D28 should do the job
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: FAT16 bootloader

Post by MichaelPetch »

In your DAP the segment and offset is "0x00 0x02 0x00 0x00" . That translates to 0x0000:0x0200 which is not where you want to be loading. Is it possible this DAP we are seeing here is not the one used for the first Int 13h call? How many times did Int 13h get called to do reads before reaching this far? I assume this wasn't from the first call to Int 13h.
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: FAT16 bootloader

Post by MichaelPetch »

For example in .loop you do:

Code: Select all

   mov $0x200, %bx
   mov $0x01, %cx
   push %dx
   call read_sectors
. You move 0x200 into BX and that then gets placed into the DAP as the dap_offset.
User avatar
cakehonolulu
Member
Member
Posts: 37
Joined: Thu Jun 16, 2016 9:35 am
Libera.chat IRC: cakehonolulu

Re: FAT16 bootloader

Post by cakehonolulu »

MichaelPetch wrote:For example in .loop you do:

Code: Select all

   mov $0x200, %bx
   mov $0x01, %cx
   push %dx
   call read_sectors
. You move 0x200 into BX and that then gets placed into the DAP as the dap_offset.
Changed that, but to no avail... I must be missing something

EDIT:

Code: Select all

.loop:
   mov root_dir_offset, %ax
   add %dx, %ax
   mov $0x0600, %bx // CHANGED THIS
   mov $0x01, %cx
   push %dx
   call read_sectors
DAP (Before first INT13):

Code: Select all

0x0000000000007d28 <bogus+       0>:    0x00    0x00    0x00    0x90    0x10    0x00    0x01    0x00
0x0000000000007d30 <bogus+       8>:    0x00    0x10    0x00    0x00    0x01    0x00    0x00    0x00
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: FAT16 bootloader

Post by MichaelPetch »

Your DAP has moved. The bytes you are displaying no longer represent where your DAP now resides. I assume it has moved because you have made modifications to the code and data shifting the location.
Post Reply