Jumping to Kernel Offset

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
brodeur235
Member
Member
Posts: 86
Joined: Sat Jun 06, 2009 11:55 am

Jumping to Kernel Offset

Post by brodeur235 »

My boot loader is all 16 bit code. It enters protected mode, and then jumps to the kernel which is coded in 32 bit. When I jump to my kernel, if the offset of the kernel (in memory) is greater than one WORD, then I get a nasm warning and my kernel isn't run:

Code: Select all

jmp 0x08:0x00010000
I can load the kernel there, but I can't jump to it... How can this be fixed?

Brodeur235
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Jumping to Kernel Offset

Post by Combuster »

Tell nasm to emit a 32 bit jump rather than a 16 bit jump

Code: Select all

jmp dword 0x0008:0x00010000
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
brodeur235
Member
Member
Posts: 86
Joined: Sat Jun 06, 2009 11:55 am

Re: Jumping to Kernel Offset

Post by brodeur235 »

Thanks Combuster that works very well... Apparently I'm also having trouble loading the kernel to anything higher than a WORD address. I am using int 0x13 to raw read the disk image / floppy. The BIOS call reads the specified data on disk to es:bx. This seems simple enough however, until now I have been determining the memory location to load the kernel to like this:

Code: Select all

xor bx,bx
mov es,bx
mov bx,kern_offset
Obviously that won't work to load the kernel to an address larger than 1 word, so I modified it to this:

Code: Select all

mov ebx,kern_offset
shr ebx,0x00000010
mov es,bx
mov ebx,kern_offset
But for one reason or another I am still only able to load the kernel to an address lower than 1 word.
Here is the entire kernel loading procedure:

Code: Select all

kernel_loader:
	
	; determine # of sectors to load
	; dx:ax / bx = ax remainder dx
	mov dx,0x0000
	mov ax,KERNEL_SIZE
	mov bx,SECTOR_SIZE
	div bx
	
	; ensure size is even number of sectors
	cmp dx,0x0000
	jnz .kl_error
	
	; setup to loop thru sectors
	mov cx,ax
	mov BYTE [ BLOC( sector_current ) ], KERNEL_SECTOR
	mov DWORD [ BLOC( offset_current ) ], KERNEL_OFFSET
	.kl_copy_sector:
		push cx
		
		; copy current sector
		; disk loc -> es:bx in mem
		mov dh,KERNEL_DRIVE
		mov dl,KERNEL_HEAD
		mov ch,KERNEL_TRACK
		mov cl,[ BLOC( sector_current ) ]
		
		; setup destination ( es:bx)
		mov eax,DWORD [ BLOC( offset_current ) ]
		shr eax,0x00000010
		mov es,ax
		mov ebx,DWORD [ BLOC( offset_current ) ]
		
		
		mov ah,0x02
		mov al,0x01
		int 0x13
		
		; prepare for next sector
		add DWORD [ BLOC( offset_current ) ],SECTOR_SIZE
		inc BYTE [ BLOC( sector_current ) ]
		
		pop cx
		loop .kl_copy_sector
	
	; completed
	jmp .kl_success
	
	; error section
	.kl_error:
		jmp $
	
	; success section
	.kl_success:
		ret

bl_data:
	
	; kernel_load data
	sector_current db 0x00 ; KERNEL_SECTOR
	offset_current dd 0x00000000 ; KERNEL_OFFSET
KERNEL_SIZE is the size of the kernel in bytes and BLOC() is just a macro that adds 0x7C00 to an input variable. Does anyone see something wrong? Keep in mind this works for loading the kernel to an address lower than 1 word...

Brodeur235
egos
Member
Member
Posts: 612
Joined: Fri Nov 16, 2007 1:59 pm

Re: Jumping to Kernel Offset

Post by egos »

You can reset es on each sector reading or only when 128 sectors (64 kb) have been read:

Code: Select all

  add bx,0200h ; bh,02h
  jnz @f
  mov ax,es
  add ax,1000h ; ah,10h
  mov es,ax
@@:
If you have seen bad English in my words, tell me what's wrong, please.
Post Reply