stack fault after p-mode switch

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
IRBMe

stack fault after p-mode switch

Post by IRBMe »

Hey all, perhaps you could help me with my problem.

I created a boot strap loader, which does nothing more than load a binary from the root directory called LOADER.BIN at 0100h:0000h.

The plan is that LOADER.BIN is then responsible for enabling the A20 line, loading the GDT, switching to PMode, setting up an IDT, setting up task descriptors, enabling paging and all that other equally messy stuff. It would then load the kernel from disk etc.

SO FAR, I have it enabling the A20 line, loading a GDT, then switching to p-mode. But right after the switch, I get a kernel stack fault followed by a hardware reboot. Here's my loader code:

Code: Select all

[bits 16]
[extern c_main]

   ; Set up the segment registers to 0x0100, where the kernel is loaded
   mov      ax,      0x0100
   mov     ds,    ax
   mov     es,    ax
   mov     fs,    ax
   mov     gs,    ax
   
   ; Create a stack
   cli   
   mov      ss,      ax
   mov      sp,      0xFFFF
   sti

   ; enable the A20 gate
   cli
   call enableA20
   sti

   ; Load the global descriptor table
   mov      si,      LoadingGDT
   mov      bl,      GREEN_TXT
   call   DisplayMessage

   cli
   lgdt   [cs:gdt]
   sti

   mov      si,      LoadedGDT
   mov      bl,      GREEN_TXT
   call   DisplayMessage


   ; Switch to protected mode
   mov      si,      SwitchingToPM
   mov      bl,      GREEN_TXT
   call   DisplayMessage
   
   ; Disable all interrupts, including NMIs
   cli
   in      al,      0x70
   or      al,      0x80
   out    0x70,   al

   mov      ecx,   cr0
   inc      cx
   mov      cr0,   ecx
   
   ; Flush the instruction cache
   ;
   ; NOTE: I have no idea where the 0x08 is coming from.
   ; I copied it from some other code, and hope it works
   ; I think it's something to do with the segment descriptors
   ;
   jmp 0x08:clear_pipe
[bits 32]
   clear_pipe:

   ; Set up the segments and the stack
   ;
   ; NOTE: I am not entirely sure about this (mainly because it CRASHES around here)
   ;
   mov      ax,      0x08
   mov      ds,      ax
   mov      ss,      ax
   mov      esp,      0x090000

   
   ; This is where I would then set up interrupt tables, and whatever else
   ; then call c_main

   jmp $


[bits 16]

; Other code like DisplayMessage and EnableA20 goes here
; it all seems to work fine.

gdt   start_gdt
flat_code   desc   0, 0xFFBFF, D_CODE + D_READ  + D_BIG + D_BIG_LIM
flat_data   desc   0, 0xFFFFF, D_DATA + D_WRITE + D_BIG + D_BIG_LIM
end_gdt


It manages to enable the A20 gate ok, then I think the GDT is loaded ok, and the switch to P-Mode successful. However, after I see the "- Switching to Protected Mode (PM)" message (see full loader source), then it faults. I'm guessing I've messed something up with the segment registers, or perhaps it was the jump into the 32 bit code to clear the instruction pipeline (jmp 0x08:clear_pipe)? I really don't know.

What I want to achieve at the moment, is simply being able to link my kernel.c and my loader.asm together, then have the loader call the "main" function in the kernel, just after switching to protected mode. Once I get that working, I think I can move on and start figuring out interrupt descriptor tables and working p-mode. I can't call my c-function until it at least...well....doesn't crash after switching to p-mode, so I'm at a dead end here.

I attached the entire source for the loader program

So if anybody has any idea what's wrong with it, or better yet how to fix it and get it working then I'd very much appreciate it, thanks.
beyondsociety

Re:stack fault after p-mode switch

Post by beyondsociety »

Code: Select all

clear_pipe:

   ; Set up the segments and the stack
   ;
   ; NOTE: I am not entirely sure about this (mainly because it CRASHES around here)
   ;
   mov      ax,      0x08 ; This needs to be 0x10
   mov      ds,      ax
   mov      ss,      ax
   mov      esp,      0x090000
This is your problem. DS has to be loaded with the data selector. To enter protected mode you have to set the code selector which is 0x08h, so jump 0x08:clear_pipe makes sense. The data selector should be 0x10h, so you need to change mov ax, 0x08 to mov ax, 0x10.

Does this make sense.
IRBMe

Re:stack fault after p-mode switch

Post by IRBMe »

Thanks very much for your prompt reply. It made some sense to me. I'm a bit shaky still with the segmentation/GDT stuff. I've read lots of documentation on it, but still trying to understand alot of it. I'll read up some more on that part.

Unfortunately, even after applying the change you suggested, it still crashes with the same error. So there's something else evading me here ???
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:stack fault after p-mode switch

Post by Pype.Clicker »

i suggest you get a look at http://www.osdev.org/osfaq2/index.php/BabyStep6 and http://www.osdev.org/osfaq2/index.php/W ... re%20About ... these are the best 'GDT in a nutshell' stuff we have here ...

just a thing: LGDT does not expect the address of the GDT to be passed, but instead the address of a 6-bytes structures that gives the size (2 bytes) and the linear address (4 bytes = realseg*16+realoffset) of the GDT. I guess the error is around there.

Moreover, a GDT *must* start with a null descriptor (i.e. you should add 8 bytes of zeroes before your 'code' descriptor)...

HTH
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:stack fault after p-mode switch

Post by Candy »

Pype.Clicker wrote: i suggest you get a look at http://www.osdev.org/osfaq2/index.php/BabyStep6 and http://www.osdev.org/osfaq2/index.php/W ... re%20About ... these are the best 'GDT in a nutshell' stuff we have here ...

just a thing: LGDT does not expect the address of the GDT to be passed, but instead the address of a 6-bytes structures that gives the size (2 bytes) and the linear address (4 bytes = realseg*16+realoffset) of the GDT. I guess the error is around there.

Moreover, a GDT *must* start with a null descriptor (i.e. you should add 8 bytes of zeroes before your 'code' descriptor)...

HTH
As for my experience, you don't need the null descriptor to be zeroes, it's just totally ignored but must be present. During 386 times, adding 1 to a number as part of a cycle was expensive.

You can of course (ab)use the null descriptor to hide your GDT loading far pointer, using 2 bytes of padding at the start (so the offset is aligned).

You do the abuse-thing now, but the dword of offset isn't aligned. Try to align it (pad first).
Post Reply