GPF or QEMU crash when entering Ring 3

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
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

GPF or QEMU crash when entering Ring 3

Post by osdever »

So, I tried to make the userspace. Neither code from Getting to Ring 3, nor ToaruOS code doesn't seem to work with me. Code from Wiki is instantly GPFs, from ToaruOS it's crashing QEMU with error "Trying to execute code outside RAM or ROM at xxxxxxxx". If you need some additional info, I'll provide it.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: GPF or QEMU crash when entering Ring 3

Post by BrightLight »

Of course we'll need more information. Show us your GDT. Show us what you try to do in user mode. Are interrupts enabled while in user mode? If yes, show us your TSS.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: GPF or QEMU crash when entering Ring 3

Post by osdever »

omarrx024 wrote:Of course we'll need more information. Show us your GDT. Show us what you try to do in user mode. Are interrupts enabled while in user mode? If yes, show us your TSS.
OK, that's a GDT and TSS installing code.

Code: Select all

uint32_t ksp;
extern void tss_flush();
// A struct describing a Task State Segment.
struct tss_entry_struct
{
   uint32_t prev_tss;   // The previous TSS - if we used hardware task switching this would form a linked list.
   uint32_t esp0;       // The stack pointer to load when we change to kernel mode.
   uint32_t ss0;        // The stack segment to load when we change to kernel mode.
   uint32_t esp1;       // everything below here is unusued now.. 
   uint32_t ss1;
   uint32_t esp2;
   uint32_t ss2;
   uint32_t cr3;
   uint32_t eip;
   uint32_t eflags;
   uint32_t eax;
   uint32_t ecx;
   uint32_t edx;
   uint32_t ebx;
   uint32_t esp;
   uint32_t ebp;
   uint32_t esi;
   uint32_t edi;
   uint32_t es;         
   uint32_t cs;        
   uint32_t ss;        
   uint32_t ds;        
   uint32_t fs;       
   uint32_t gs;         
   uint32_t ldt;      
   uint16_t trap;
   uint16_t iomap_base;
} __attribute__((packed));
 
typedef struct tss_entry_struct tss_entry_t;
struct gdt_entry_bits
{
	unsigned int limit_low:16;
	unsigned int base_low : 24;
     //attribute byte split into bitfields
	unsigned int accessed :1;
	unsigned int read_write :1; //readable for code, writable for data
	unsigned int conforming_expand_down :1; //conforming for code, expand down for data
	unsigned int code :1; //1 for code, 0 for data
	unsigned int always_1 :1; //should be 1 for everything but TSS and LDT
	unsigned int DPL :2; //priviledge level
	unsigned int present :1;
     //and now into granularity
	unsigned int limit_high :4;
	unsigned int available :1;
	unsigned int always_0 :1; //should always be 0
	unsigned int big :1; //32bit opcodes for code, uint32_t stack for data
	unsigned int gran :1; //1 to use 4k page addressing, 0 for byte addressing
	unsigned int base_high :8;
} __attribute__((packed)); //or __attribute__((packed))
struct gdt_entry_bits gdt[6];
struct gdt_ptr
{
    uint16_t limit;
    uint32_t base;
} __attribute__((packed));

struct gdt_ptr gp;
/**Ok, this is going to be hackish, but we will salvage the gdt_entry_bits struct to form our TSS descriptor
So some of these names of the fields will actually be different.. maybe I'll fix this later..**/
tss_entry_t tss_entry;
 
void write_tss(gdt_entry_bits *g)
{
   // Firstly, let's compute the base and limit of our entry into the GDT.
   uint32_t base = (uint32_t) &tss_entry;
   uint32_t limit = sizeof(tss_entry);
 
   // Now, add our TSS descriptor's address to the GDT.
   g->base_low=base&0xFFFFFF; //isolate bottom 24 bits
   g->accessed=1; //This indicates it's a TSS and not a LDT. This is a changed meaning
   g->read_write=0; //This indicates if the TSS is busy or not. 0 for not busy
   g->conforming_expand_down=0; //always 0 for TSS
   g->code=1; //For TSS this is 1 for 32bit usage, or 0 for 16bit.
   g->always_1=0; //indicate it is a TSS
   g->DPL=3; //same meaning
   g->present=1; //same meaning
   g->limit_high=(limit&0xF0000)>>16; //isolate top nibble
   g->available=0;
   g->always_0=0; //same thing
   g->big=0; //should leave zero according to manuals. No effect
   g->gran=0; //so that our computed GDT limit is in bytes, not pages
   g->base_high=(base&0xFF000000)>>24; //isolate top byte.
 
   // Ensure the TSS is initially zero'd.
   memset(&tss_entry, 0, sizeof(tss_entry));
 
   tss_entry.ss0  = 2;  // Set the kernel stack segment.
   tss_entry.esp0 = ksp; // Set the kernel stack pointer.
   //note that CS is loaded from the IDT entry and should be the regular kernel code segment
}
 
void set_kernel_stack(uint32_t stack) //this will update the ESP0 stack used when an interrupt occurs
{
   tss_entry.esp0 = stack;
}
void gdt_install()
{    
	gp.limit = (sizeof(struct gdt_entry_bits) * 3) - 1;
    gp.base = &gdt;
		    gdt[0].base_low = (0 & 0xFFFF);
    gdt[0].base_high = (0 >> 24) & 0xFF;

    /* Setup the descriptor limits */
    gdt[0].limit_low = (0 & 0xFFFF);
    gdt[0].gran = ((0 >> 16) & 0x0F);

    /* Finally, set up the granularity and access flags */
    gdt[0].gran |= (0 & 0xF0);
    gdt[0].accessed = 0;
    
    
	
	    gdt[1].base_low = (0 & 0xFFFF);
    gdt[1].base_high = (0 >> 24) & 0xFF;

    /* Setup the descriptor limits */
    gdt[1].limit_low = (0xffffffff & 0xFFFF);
    gdt[1].gran = ((0xffffffff >> 16) & 0x0F);

    /* Finally, set up the granularity and access flags */
    gdt[1].gran |= (0xCF & 0xF0);
    gdt[1].accessed = 0x9A;
    
    
    	    gdt[2].base_low = (0 & 0xFFFF);
    gdt[2].base_high = (0 >> 24) & 0xFF;

    /* Setup the descriptor limits */
    gdt[2].limit_low = (0xffffffff & 0xFFFF);
    gdt[2].gran = ((0xffffffff >> 16) & 0x0F);

    /* Finally, set up the granularity and access flags */
    gdt[2].gran |= (0xCF & 0xF0);
    gdt[2].accessed = 0x92;
	//....insert your ring 0 segments here or whatever
gdt_entry_bits *code;
gdt_entry_bits *data;
//I assume your ring 0 segments are in gdt[1] and gdt[2] (0 is null segment)
code=(void*)&gdt[3]; //gdt is a static array of gdt_entry_bits or equivalent
data=(void*)&gdt[4];
code->limit_low=0xFFFF;
code->base_low=0;
code->accessed=0;
code->read_write=1; //make it readable for code segments
code->conforming_expand_down=0; //don't worry about this.. 
code->code=1; //this is to signal its a code segment
code->always_1=1;
code->DPL=3; //set it to ring 3
code->present=1;
code->limit_high=0xF;
code->available=1;
code->always_0=0;
code->big=1; //signal it's 32 bits
code->gran=1; //use 4k page addressing
code->base_high=0;
*data=*code; //copy it all over, cause most of it is the same
data->code=0; //signal it's not code; so it's data.
 
write_tss(&gdt[5]); //we'll implement this function later... 
 
//...go on to install GDT segments and such
//after those are installed we'll tell the CPU where our TSS is:
tss_flush(); //implement this later
}
Interrupts are enabled, but why it doesn't shows my panic?
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: GPF or QEMU crash when entering Ring 3

Post by osdever »

UPD: Now it's just reboots. No info, no panic screen, nothing.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: GPF or QEMU crash when entering Ring 3

Post by osdever »

Looks like the problem isn't in GDT, because if I remove jump_usermode call, it'll run and work well.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
Roman
Member
Member
Posts: 568
Joined: Thu Mar 27, 2014 3:57 am
Location: Moscow, Russia
Contact:

Re: GPF or QEMU crash when entering Ring 3

Post by Roman »

catnikita255 wrote:Looks like the problem isn't in GDT, because if I remove jump_usermode call, it'll run and work well.
It doesn't mean, that there's no problem in the GDT.
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
- Alan Kay
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: GPF or QEMU crash when entering Ring 3

Post by osdever »

Roman wrote:
catnikita255 wrote:Looks like the problem isn't in GDT, because if I remove jump_usermode call, it'll run and work well.
It doesn't mean, that there's no problem in the GDT.
My GDT is from Bran's tutorial (ring0) and from Getting to Ring 3 (ring3).
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: GPF or QEMU crash when entering Ring 3

Post by osdever »

omarrx024 wrote:Of course we'll need more information. Show us your GDT. Show us what you try to do in user mode. Are interrupts enabled while in user mode? If yes, show us your TSS.
GDT - showed. I'm trying to just enter it, so it's empty test_user_function. Interrupts are enabled, but if I disable them, nothing will change.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: GPF or QEMU crash when entering Ring 3

Post by alexfru »

catnikita255 wrote:

Code: Select all

   tss_entry.ss0  = 2;  // Set the kernel stack segment.
What's that? A NULL selector?
catnikita255 wrote:

Code: Select all

void set_kernel_stack(uint32_t stack) //this will update the ESP0 stack used when an interrupt occurs
{
   tss_entry.esp0 = stack;
}
This is odd. When an interrupt occurs while in ring 3, SS:ESP will be loaded from the TSS automatically. In ring 0, you continue using the current SS:ESP. Why this code? Is is a part of a landmine?
catnikita255 wrote:

Code: Select all

void gdt_install()
{    
	gp.limit = (sizeof(struct gdt_entry_bits) * 3) - 1;
So, you swear to the CPU that you only have 3 segment descriptors in the GDT, one of which is a NULL descriptor and two are for the kernel code and data/stack segments?

Where else do you have weird code that you haven't proofread?
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: GPF or QEMU crash when entering Ring 3

Post by iansjack »

catnikita255 wrote:I'm trying to just enter it, so it's empty test_user_function.
So if you do enter your empty function, what's going to happen when it returns? You need more than just an empty function (which the compiler may optimize to nothing).
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: GPF or QEMU crash when entering Ring 3

Post by osdever »

iansjack wrote:
catnikita255 wrote:I'm trying to just enter it, so it's empty test_user_function.
So if you do enter your empty function, what's going to happen when it returns? You need more than just an empty function (which the compiler may optimize to nothing).
I don't know.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: GPF or QEMU crash when entering Ring 3

Post by iansjack »

My guess is that it would present a GPF or reset the computer via a triple fault.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: GPF or QEMU crash when entering Ring 3

Post by osdever »

iansjack wrote:My guess is that it would present a GPF or reset the computer via a triple fault.
My _start calls kernel_main and halts if it returns.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: GPF or QEMU crash when entering Ring 3

Post by iansjack »

I'd advise that you run the OS under a debugger to determine the cause of the failure.
User avatar
osdever
Member
Member
Posts: 492
Joined: Fri Apr 03, 2015 9:41 am
Contact:

Re: GPF or QEMU crash when entering Ring 3

Post by osdever »

iansjack wrote:I'd advise that you run the OS under a debugger to determine the cause of the failure.
Ok, I'll try and write here.
Developing U365.
Source:
only testing: http://gitlab.com/bps-projs/U365/tree/testing

OSDev newbies can copy any code from my repositories, just leave a notice that this code was written by U365 development team, not by you.
Post Reply