GPF or QEMU crash when entering Ring 3
GPF or QEMU crash when entering Ring 3
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.
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.
- BrightLight
- 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
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.
Re: GPF or QEMU crash when entering Ring 3
OK, that's a GDT and TSS installing code.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.
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
}
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.
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.
Re: GPF or QEMU crash when entering Ring 3
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.
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.
Re: GPF or QEMU crash when entering Ring 3
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.
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.
Re: GPF or QEMU crash when entering Ring 3
It doesn't mean, that there's no problem in the GDT.catnikita255 wrote:Looks like the problem isn't in GDT, because if I remove jump_usermode call, it'll run and work well.
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
- Alan Kay
- Alan Kay
Re: GPF or QEMU crash when entering Ring 3
My GDT is from Bran's tutorial (ring0) and from Getting to Ring 3 (ring3).Roman wrote:It doesn't mean, that there's no problem in the GDT.catnikita255 wrote: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.
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.
Re: GPF or QEMU crash when entering Ring 3
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.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.
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.
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.
Re: GPF or QEMU crash when entering Ring 3
What's that? A NULL selector?catnikita255 wrote:Code: Select all
tss_entry.ss0 = 2; // Set the kernel stack segment.
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 set_kernel_stack(uint32_t stack) //this will update the ESP0 stack used when an interrupt occurs { tss_entry.esp0 = stack; }
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?catnikita255 wrote:Code: Select all
void gdt_install() { gp.limit = (sizeof(struct gdt_entry_bits) * 3) - 1;
Where else do you have weird code that you haven't proofread?
Re: GPF or QEMU crash when entering Ring 3
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).catnikita255 wrote:I'm trying to just enter it, so it's empty test_user_function.
Re: GPF or QEMU crash when entering Ring 3
I don't know.iansjack wrote: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).catnikita255 wrote:I'm trying to just enter it, so it's empty test_user_function.
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.
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.
Re: GPF or QEMU crash when entering Ring 3
My guess is that it would present a GPF or reset the computer via a triple fault.
Re: GPF or QEMU crash when entering Ring 3
My _start calls kernel_main and halts if it returns.iansjack wrote:My guess is that it would present a GPF or reset the computer via a triple fault.
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.
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.
Re: GPF or QEMU crash when entering Ring 3
I'd advise that you run the OS under a debugger to determine the cause of the failure.
Re: GPF or QEMU crash when entering Ring 3
Ok, I'll try and write here.iansjack wrote:I'd advise that you run the OS under a debugger to determine the cause of the failure.
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.
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.