can't get my fat12 bootloader to work

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
PgrAm
Posts: 20
Joined: Fri Sep 26, 2014 12:19 pm

can't get my fat12 bootloader to work

Post by PgrAm »

I'm trying to get my bootloader to load my kernel from a file on a fat12 floppy but its not exactly working. My code for the fat12 loading is based on this tutorial http://www.brokenthorn.com/Resources/OSDev6.html, but my boot loader does some other stuff outside the scope of my problems. The bootlader will find the file while looking through the directory but it crashes when it actually tries to load the file. Bochs will give me this error and then it will get stuck
int13_cdrom: function 02, ELDL out of range ff
, when it tries to load the clusters where the file is.

anyway here is my code, maybe someone can help me figure out why this isn't working.

boot_sect.asm:

Code: Select all

[org 0x7c00]

start: jmp begin
nop

%assign _bytes_per_sector		512
%assign _sectors_per_cluster	1
%assign _reserved_sectors		1
%assign _number_of_FATs			2
%assign _root_entries			224
%assign _total_sectors			2880
%assign _media					0xf8
%assign _sectors_per_FAT		9
%assign _sectors_per_track		18
%assign _heads_per_cylinder		2
%assign _hidden_sectors			0
%assign _total_sectors_big		0
%assign _drive_number			0
%assign _unused					0
%assign _ext_boot_signature		0x29
%assign _serial_number			0xa0a1a2a3

; BIOS Parameter Block
bp_OEM					db "EMS OS  "
bp_bytes_per_sector:  	dw _bytes_per_sector
bp_sectors_per_cluster: db _sectors_per_cluster
bp_reserved_sectors: 	dw _reserved_sectors
bp_number_of_FATs: 		db _number_of_FATs
bp_root_entries: 		dw _root_entries 	
bp_total_sectors: 		dw _total_sectors
bp_media: 				db _media	
bp_sectors_per_FAT: 	dw _sectors_per_FAT
bp_sectors_per_track: 	dw _sectors_per_track
bp_heads_per_cylinder: 	dw _heads_per_cylinder
bp_hidden_sectors: 		dd _hidden_sectors
bp_total_sectors_big:   dd _total_sectors_big
bs_drive_number: 	   	db _drive_number 
bs_unused: 				db _unused		
bs_ext_boot_signature: 	db _ext_boot_signature
bs_serial_number:	    dd _serial_number	    
bs_volume_label: 	    db "EMS FLOPPY "
bs_file_system: 	    db "FAT12   "

KERNEL_OFFSET 	equ 0x1000 ; This is the memory address where our kernel goes

begin:
	mov 	[boot_info + multiboot_info.bootDevice], dl 	; Save the index of the boot drive
	
	mov 	bp, 0x9000 		; Set up the stack.
	mov 	sp, bp
	
	call 	getmem
	
	call	fat_load
	
	mov		ax, 0x01
	int		0x10
	
	jmp		switch_to_pm 	; Switch to protected mode

%include "disk.asm"
%include "gdt.asm"
%include "switchtopm.asm"
%include "memmap.asm"
%include "multiboot.asm"
%include "fatload.asm"

[bits 32]

; In protected mode now
BEGIN_PM :
	mov 	eax, 0x2badb002			;multiboot magic
	push 	dword boot_info
	
	call 	KERNEL_OFFSET 			; Jumping into C and Kernel land
	
; Multiboot header
boot_info:
istruc multiboot_info
	at multiboot_info.flags,				dd 0
	at multiboot_info.memoryLo,				dd 0
	at multiboot_info.memoryHi,				dd 0
	at multiboot_info.bootDevice,			dd 0
	at multiboot_info.cmdLine,				dd 0
	at multiboot_info.mods_count,			dd 0
	at multiboot_info.mods_addr,			dd 0
	at multiboot_info.syms0,				dd 0
	at multiboot_info.syms1,				dd 0
	at multiboot_info.syms2,				dd 0
	at multiboot_info.mmap_length,			dd 0
	at multiboot_info.mmap_addr,			dd 0
	at multiboot_info.drives_length,		dd 0
	at multiboot_info.drives_addr,			dd 0
	at multiboot_info.config_table,			dd 0
	at multiboot_info.bootloader_name,		dd 0
	at multiboot_info.apm_table,			dd 0
	at multiboot_info.vbe_control_info,		dd 0
	at multiboot_info.vbe_mode_info,		dw 0
	at multiboot_info.vbe_interface_seg,	dw 0
	at multiboot_info.vbe_interface_off,	dw 0
	at multiboot_info.vbe_interface_len,	dw 0
iend

; Bootsector padding
times 510 -( $ - $$ ) db 0

; magic number
dw 0xaa55
fatload.asm:

Code: Select all

%assign root_size 		(32 * _root_entries) / _bytes_per_sector
%assign fats_size		(_number_of_FATs * _sectors_per_FAT)
%assign root_location 	fats_size + _reserved_sectors
%assign datasector  	root_location + root_size
%assign cluster_size	_sectors_per_cluster * _bytes_per_sector

fat_load : 

    ; read root directory into memory (0x200)
		mov     cx, root_size    					
		mov  	ax, root_location            		
		mov   	bx, 0x0200
		call  	disk_load
		
    ; browse root directory for binary image
		mov		cx, _root_entries             		; load loop counter
		mov		di, 0x0200                          ; locate first root entry
		
    .LOOP:
		push 	cx
		mov		cx, 0x000B                          ; eleven character name
		mov		si, file_name                       ; image name to find
		push	di
		rep  	cmpsb                               ; test for entry match
		pop		di
		je		LOAD_FAT
		pop		cx
		add		di, 0x0020                          ; queue next directory entry
		loop	.LOOP
		
FAILURE:
		jmp $										; did not find kernel image

		
LOAD_FAT:
    
	; save starting cluster of boot image
		mov     dx, WORD [di + 0x001A]
		mov     WORD [cluster], dx                  ; file's first cluster
		
	; read FAT into memory (0x0200)
		mov   	cx, fats_size          				; sectors used by FATs		
		mov     ax, _reserved_sectors       		; adjust for bootsector
		mov     bx, 0x0200                          
		call  	disk_load
		
		push	KERNEL_OFFSET						; push kernel destination address onto the stack
		
	LOAD_IMAGE:
		pop		bx
		mov     ax, WORD [cluster]                  ; cluster to read
		
	; convert cluster to LBA
		sub     ax, 0x0002                          ; zero base cluster number
		mov     cx, _sectors_per_cluster   			; convert byte to word
		mul     cx
		add     ax, datasector						; base data sector
		
		call  	disk_load
		push 	bx
		
	; compute next cluster
		mov     ax, WORD [cluster]                  ; cluster + cluster / 2 
		mov     bx, ax
		shr     bx, 0x0001                          ; divide by two
		add     bx, ax                              
		mov     dx, WORD [bx + 0x0200]				; read two bytes from FAT (0x0200)
		test    ax, 0x0001
		jnz     .ODD_CLUSTER
		
	.EVEN_CLUSTER:
		and     dx, 0000111111111111b				; take low twelve bits
		jmp     .DONE
		
	.ODD_CLUSTER:
		shr     dx, 0x0004                          ; take high twelve bits
		
	.DONE:     
		mov     WORD [cluster], dx                  ; store new cluster
		cmp     dx, 0x0FF0                          ; test for end of file
		jb      LOAD_IMAGE
		
	DONE:
		ret											; kernel image is loaded at KERNEL_OFFSET
		
cluster     dw 0x0000
file_name   db "KERNAL  SYS"
disk.asm:

Code: Select all

; load cx sectors to ES:BX from boot drive at sector ax
disk_load:
     .MAIN:
        push    ax
        push    cx
	.LBACHS:
		xor     dx, dx                              ; prepare dx:ax for operation
		div     word [bp_sectors_per_track]		; calculate
		inc     dl                                  ; adjust for sector 0
		mov     cl, dl
		
		xor     dx, dx                              ; prepare dx:ax for operation
		div     word [bp_heads_per_cylinder]         ; calculate
		mov     dh, dl
		mov     ch, al

        mov     ah, 0x02                            ; BIOS read sector
        mov     al, 0x01                            ; read one sector

        mov     dl, BYTE [boot_info + multiboot_info.bootDevice]            ; drive
        int     0x13                                ; invoke BIOS
     .SUCCESS:
        pop     cx
        pop     ax
        add     bx, _bytes_per_sector			    ; queue next buffer
        inc     ax                                  ; queue next sector
        loop    .MAIN                               ; read next sector
        ret
FallenAvatar
Member
Member
Posts: 283
Joined: Mon Jan 03, 2011 6:58 pm

Re: can't get my fat12 bootloader to work

Post by FallenAvatar »

Commands you used to compile your bootloader? How did you create your fat12 image? How did you copy your bootloader onto it?

Beyond that, all selectors (ss, cs, ds, etc) are uninitialized.

- Monk
PgrAm
Posts: 20
Joined: Fri Sep 26, 2014 12:19 pm

Re: can't get my fat12 bootloader to work

Post by PgrAm »

here's the command

Code: Select all

nasm boot_sect.asm -f bin -o ../build/boot_sect.bin
using fat_imgen for vfd images

Code: Select all

fat_imgen -c -f "os.vfd"
fat_imgen -m -f "os.vfd" -s "build/boot_sect.bin"
fat_imgen -m -f "os.vfd" -i "build/kernal.sys"
all images also work with winimage
Octocontrabass
Member
Member
Posts: 5587
Joined: Mon Mar 25, 2013 7:01 pm

Re: can't get my fat12 bootloader to work

Post by Octocontrabass »

Every memory access involves a segment register. Since you never initialize the segment registers, every memory access is going to some random location. I'm honestly surprised your code doesn't crash sooner!

Your code probably has some other issues too, but segment registers are your biggest problem right now.
User avatar
sleephacker
Member
Member
Posts: 97
Joined: Thu Aug 06, 2015 6:41 am
Location: Netherlands

Re: can't get my fat12 bootloader to work

Post by sleephacker »

Are you trying to load the root directory to 0x200? Because that's also where the IVT is located...
Also after calling a BIOS interrupt especially when trying to do anything with a floppy you should always check for errors, in this case test the CF flag.
I recommend http://stanislavs.org/helppc/int_13.html for info on INT 13h, and maybe take a look at other bootsectors that already work if you haven't already done so, since they usually contain some helpful comments.
I also advice you to load your kernel above your bootsector because by loading it to 0x1000 your kernel can't be much bigger than 27kb without conflicting with your bootsector.
PgrAm
Posts: 20
Joined: Fri Sep 26, 2014 12:19 pm

Re: can't get my fat12 bootloader to work

Post by PgrAm »

yes I think I'm accidentally overwriting my bootloader, if I jump right into my kernel from fat_load it works but if I return and then jump it crashes. I think what happens is when it returns the code behind it has been overwritten so it crashes. My kernel is actually about 27kb in size. I'll play around with the addresses and see if I can get it to work.
PgrAm
Posts: 20
Joined: Fri Sep 26, 2014 12:19 pm

Re: can't get my fat12 bootloader to work

Post by PgrAm »

Ok I found my problem, I accidentally screwed up the stack when I forgot to pop a value I pushed onto the stack and the function tried to return to it.

I should have done this

Code: Select all

	
pop		di
pop		cx
je		LOAD_FAT
but I accidentally did this

Code: Select all

	
pop		di
je		LOAD_FAT
pop		cx
Post Reply