Code crashing on function call in higher half kernel

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
richi18007
Member
Member
Posts: 35
Joined: Mon Mar 07, 2011 1:41 pm

Code crashing on function call in higher half kernel

Post by richi18007 »

Please help me find the problem out.I searched the forum , maybe it's the keywords but I cannot find anything relevant.

i got the basic paging (identity mapping) working .Now , i wanted to load the kernel into the upper half and tried using Tim Robinson's GDT trick. The code works fine .
I linked my kernel to 0xC0000C00 and code.base = 0x40000000 which wrapped around perfectly .

But as soon as I call the main , the code crashes with the error.

Code: Select all

qemu: fatal: Trying to execute code outside RAM or ROM at 0x40000000
Bochs also gave a similar error.
The code is pretty simple . This is what I do after the control reaches to the higher half kernel from the far jump .I verified that GDTs and segments are set correctly :-

Code: Select all

__asm__("push %ebx");
__asm__("push %eax");
__asm__("call main");
The code crashes on the call instruction. The dump also looks fine except the EIP register which has been set to zero. I know that's where the problem lies . But how to solve it .

Code: Select all

EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000064 EBP=00000000 ESP=0008ffb0
EIP=00000000 EFL=00000202 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 40000000 ffffffff 40cf9300 DPL=0 DS   [-WA]
CS =0008 40000000 ffffffff 40cf9a00 DPL=0 CS32 [-R-]
SS =0010 40000000 ffffffff 40cf9300 DPL=0 DS   [-WA]
DS =0010 40000000 ffffffff 40cf9300 DPL=0 DS   [-WA]
I even tried removing the inline assembly and linking one more file which executes the above inline *lines* . But that too crashes. It's eating up my brain.
Last edited by richi18007 on Tue Sep 04, 2012 1:46 pm, edited 1 time in total.
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: Code crashing on function call in higher half kernel

Post by Combuster »

The common x86 jump instructions are relative to the original instruction pointer. So if your original code was not executing at the IP it was linked at, the difference will not be correct and the instruction pointer will be pointing nowhere.

The typical way to fix is to force an absolute jump:

Code: Select all

mov eax, main
call eax
"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 ]
richi18007
Member
Member
Posts: 35
Joined: Mon Mar 07, 2011 1:41 pm

Re: Code crashing on function call in higher half kernel

Post by richi18007 »

Thank you Combuster for the feedback
No , still no help . the code still crashes .
This time I created a separate assembly file and wrote those instructions to call main from there , linked everything up But still it crashes .
Heck , I even tried adding EIP to the list of clobbered registers . The same error and the same dump. The bochs emulator gives an error as
"physical memory read error". These are the options I use to link my gcc. Don't think they are the culprit but still, I'm sleepless

Code: Select all

nasm -f elf -o 
gcc -c -g -Os -march=i686 -ffreestanding -Wall -Werror -fno-toplevel-reorder -I. -o 
ld -static -Tlink.ld -nostdlib --nmagic 
Why should the EIP turn to zero. Bochs gives an error like :

Code: Select all

bx_dbg_read_linear: physical memory read error <phy=0x3fffffff, lin=0x3ffffffff>
And then a far jump to the start. Cannot make much sense out of this error.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Code crashing on function call in higher half kernel

Post by bluemoon »

By any chance you call main and it returns, and you execute junks?
Since bochs try to read phy: 0x3fffffff (1GB), there is also possibility that you have problem in the page table.

My experience to debug "higher half" issue is:
1. setup identity paging and higher paging, but do not jump to high and jump to a location with cli+hlt - this verify the lowest nodes of page structure are correct and rule out any offset disagreement in linker and loader (to further verify the offset you should debug the kmain address in emu, and compare with objdump).
2. now, jump higher half, this actually pretty straight forward and hardly failure, for 32-bit old fashion paging this involve setting one PDE entry only.

By the way, after you enabled paging and setup higher half, there are things to do before jumping to kmain directly - for example, reload GDT with high address, unlink low address, setup C-friendly conditions(stack point to high address, ebp=0, other register states).
richi18007
Member
Member
Posts: 35
Joined: Mon Mar 07, 2011 1:41 pm

Re: Code crashing on function call in higher half kernel

Post by richi18007 »

The prototype of main is

Code: Select all

void __attribute__((noreturn)) main(uint32_t eax , uint32_t ebx) // EAX and EBX are just there for multiboot specific data 
Main has an infinite while loop at the end too. So , it won't return .
And I have not yet enabled paging.

Code: Select all

CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
But after your reply I realized that I having been hitting on every function call . So , I pressed s this time , and realized that the problem was not with the call but the return statement.
The first function that gets called is the init_vid_mem(). The emulator triple faults as soon as I try to return from this function . So , this time , I changed the stack segment to the normal segment (not the one which uses some tricks ) and the code was working fine. But why did this happen ? why was the stack segment set up by the trick gdt one not valid ? What do I need to do for making the data segments too appear at virtual addresses. The linker script places the data , rodata and other segments after code segment.
I added one more line of code (this time , trick gdt was used , it works fine with trivial gdt ), pop eax (which was pushed again in the next line ) and code again crashes right before call to main . The value of ESP has been set to 0x9000. Please explain the behavior.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Code crashing on function call in higher half kernel

Post by bluemoon »

richi18007 wrote:And I have not yet enabled paging.
I'm confused. Are you doing higher-half without paging? That's amazing.
richi18007 wrote:I changed the stack segment to the normal segment and the code was working fine. But why did this happen ? was the stack segment set up by the gdt one not valid ?
You should write down the stack selector, base, limit, esp, and linear addresses of "GDT trick" vs "normal GDT", and how you set it up (by a mov of hardcoded immediate address, or offset or an BSS entry that was fixed by linker) and you'll see the difference.

EDIT: Oh, I am totally against the GDT trick, it may seem to give you a easier start but no, it will create more confusion. And you will quickly throw away the trick and replace it with normal GDT anyway, and as far as I can tell, normal GDT is easier than the trick.
richi18007
Member
Member
Posts: 35
Joined: Mon Mar 07, 2011 1:41 pm

Re: Code crashing on function call in higher half kernel

Post by richi18007 »

I am not doing higher half without paging. I am using the GDT trick so that the actual address would wrap around. And I would get a similar mapping as I would get without paging. This was what I planned to use until I have paging enabled. Sorry for using the term higher half

The current segments are

Code: Select all

ES =0010 40000000 ffffffff 40cf9300 DPL=0 DS   [-WA]
CS =0008 40000000 ffffffff 40cf9a00 DPL=0 CS32 [-R-]
SS =0010 40000000 ffffffff 40cf9300 DPL=0 DS   [-WA]
DS =0010 40000000 ffffffff 40cf9300 DPL=0 DS   [-WA]
FS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
GS =0000 00000000 0000ffff 00009300 DPL=0 DS16 [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00000a44 00000027
The code to set up these addresses is :-

Code: Select all

        mov		ax, 0x10	; set data segments to data selector (0x10)
	mov		ds, ax
	mov		ss, ax
	mov		es, ax
	mov		esp, 90000h		; stack begins from 90000h
	;Write something to the video memory 
	mov byte [0xC00B8000], 'P'
	mov byte [0xC00B8001], 1Bh
	mov eax , 0x2BADB000 
	push ebx ; The multiboot header structure is pushed onto the stack
	mov ecx , 0xC0000C00
	jmp 0x08:0xC0000C00
And now I am against GDT trick as well , I would make a simple paging system in the bootloader itself , enable paging in it. Keep the last PTE and PDE as their physical addresses and will work this way .I just want to know the problem and learn my lesson and maybe grab a little sleep before office in the morning.

The GDT is

Code: Select all

gdt_data: 
	dd 0 				; null descriptor
	dd 0 
 
; Offset 0x8 bytes from start of GDT: Descriptor code therfore is 8
 
; gdt code:				; code descriptor
	dw 0FFFFh 			; limit low
	dw 0x00 			; base low
	db 0				; base middle
	db 10011010b 			; access
	db 11001111b 			; granularity
	db 0x40 			; base high
 
; Offset 16 bytes (0x10) from start of GDT. Descriptor code therfore is 0x10.
 
; gdt data:				; data descriptor
	dw 0FFFFh 			; limit low (Same as code)
	dw 0x000 			; base low
	db 0 				; base middle
	db 10010010b 			; access
	db 11001111b 			; granularity
	db 0x40				; base high
; gdt temp data 
	dw 0xFFFF
	dw 0x0
	db 0
	db 10010010b
	db 11001111b
	db 0
; gdt temp code
	dw 0xFFFF
	dw 0x0
	db 0x0
	db 10011010b
	db 11001111b
	db 0x0
The GDT is loaded as below

Code: Select all

end_of_gdt:
toc: 
	dw end_of_gdt - gdt_data - 1 	; limit (Size of GDT)
	dd gdt_data 			; base of GDT
lgdt_load_asm :
	mov si , lgdt_load_asm_string
	call print_string
	cli			; make sure to clear interrupts first!
	lgdt	[toc]		; load GDT into GDTR
	;call pmode_enter
	sti 
	ret
lgdt_load_asm_string db "Loading the decriptor tables",0
I am sorry for cluttering it all with too much of code but I wanted to be complete.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Code crashing on function call in higher half kernel

Post by bluemoon »

Code: Select all

mov      esp, 90000h      ; stack begins from 90000h
So, the stack is setup in a different way than other segment(*). The stack linear address would be:

Code: Select all

stack linear address = SS.base + ESP = 0x40000000 + 0x90000 = 0x40900000, which is 1GB above the expected address.
* The linear address of code is CS.base + kmain, since you link with higher half we take kmain = 0x80100000 as example

Code: Select all

kmain linear address = CS.base + kmain = 0x40000000 + 0x80100000 = 0x00100000
richi18007
Member
Member
Posts: 35
Joined: Mon Mar 07, 2011 1:41 pm

Re: Code crashing on function call in higher half kernel

Post by richi18007 »

bluemoon wrote:

Code: Select all

mov      esp, 90000h      ; stack begins from 90000h
So, the stack is setup in a different way than other segment(*). The stack linear address would be:

Code: Select all

stack linear address = SS.base + ESP = 0x40000000 + 0x90000 = 0x40900000, which is 1GB above the expected address.
* The linear address of code is CS.base + kmain, since you link with higher half we take kmain = 0x80100000 as example

Code: Select all

kmain linear address = CS.base + kmain = 0x40000000 + 0x80100000 = 0x00100000
Oops !! now I see it . Thanks bluemoon. I modified the value with 0xc0090000 and now the code works fine.
Post Reply