OSDev.org

The Place to Start for Operating System Developers
It is currently Tue Apr 23, 2024 3:37 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: [Fully Solved] GPF while ISR in User Mode
PostPosted: Wed Feb 01, 2017 6:16 am 
Offline
Member
Member
User avatar

Joined: Sun Nov 20, 2016 7:26 am
Posts: 155
Location: Somewhere
Hi again.

I was moving to userspace. :|

I created 2 more GDT entries for user code and data with DPL = 3. Then I created a TSS. Segments of TSS is RPL = 3 and points to kernel code and data in GDT. I use flat model, so base is 0, limit is 0xFFFFFFFF.

So I setup TSS with es, ds, fs, gs, ss = 0x13, cs = 0x0B.
While entering user mode I setup segments with es, ds, fs, gs, ss = 0x23, cs = 0x1B.

ISR code segment is 0x08, also I tried with 0x0B with no luck.

When I use a syscall, I got a general protection fault. In error code, External bit is 0, Table bits are 01, Index is 116 (my syscall handler, 0x74)

What could be problem? Probably it is about esp0 setup in tss, in fact I don't know what should I put to esp0. Then I tried with allocating a 4 KB stack and just setting with current esp.

Code:
switch_usermode:
     mov $0x23, %ax
     mov %ax, %ds
     mov %ax, %es
     mov %ax, %fs
     mov %ax, %gs

     mov %esp, %eax
     push $0x23
     push %eax
     pushf
     pop %eax
     or %eax, $0x200
     push %eax
     push $0x1B
     push user_mode_return
     iret


And that is how I set up the GDT and TSS:

Code:
void gdt_install()
{
    gdtr.limit = (sizeof(gdt_entry_t) * GDT_SIZE) - 1;
    gdtr.base = (uintptr_t) &gdt;

    gdt_set_gate(0, 0, 0, 0, 0); //Null

    gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Kernel Code Segment
    gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Kernel Data Segment

    gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User Code Segment
    gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User Data Segment

    add_tss0_in_gdt(5, 0x10, read_esp());

    gdt_flush((uintptr_t) &gdtr);
    tss_flush();
}

void add_tss0_in_gdt (uint16_t num, uint16_t ss0, uint32_t esp0)
{
   uintptr_t base = (uintptr_t) &tss0;
   uint32_t limit = base + sizeof(tss_entry_t);

   gdt_set_gate(num, base, limit, 0xE9, 0x00);

   memset(&tss0, 0, sizeof(tss_entry_t));

   tss0.ss0 = ss0;
   tss0.esp0 = esp0;

   tss0.cs = 0x0B;
   tss0.ss = 0x13;
   tss0.ds = 0x13;
   tss0.es = 0x13;
   tss0.fs = 0x13;
   tss0.gs = 0x13;

   tss0.iomap_base = sizeof(tss_entry_t);
}

void set_kernel_stack(uintptr_t stack)
{
    tss0.esp0 = stack;
}


I couldn't see a problem except esp0, kernel stack in esp0. I don't know what should I set it to.
And the interesting part is IRQs are working. So strange. :|

Thanks

_________________
Keyboard not found!

Press F1 to run setup.
Press F2 to continue.


Last edited by Agola on Thu Feb 02, 2017 5:35 am, edited 2 times in total.

Top
 Profile  
 
 Post subject: Re: General Protection Fault while ISR in User Mode
PostPosted: Wed Feb 01, 2017 1:44 pm 
Offline
Member
Member
User avatar

Joined: Sat Dec 27, 2014 9:11 am
Posts: 901
Location: Maadi, Cairo, Egypt
You should allocate a new stack for the kernel in your TSS. Notice that the stack grows upwards on x86, and so it should be something like:
Code:
tss.esp0 = (uint32_t)kmalloc(STACK_SIZE) + STACK_SIZE;

I haven't reviewed your code in detail, but the segment registers in the TSS should be 0x10 for data and 0x08 for code (not 0x13 and 0x0B). Also, how are you installing your syscall handler? Make sure the IDT entry is set to "user" (using gate type 0xEE instead of 0x8E.)

_________________
You know your OS is advanced when you stop using the Intel programming guide as a reference.


Top
 Profile  
 
 Post subject: Re: General Protection Fault while ISR in User Mode
PostPosted: Wed Feb 01, 2017 2:12 pm 
Offline
Member
Member
User avatar

Joined: Sun Nov 20, 2016 7:26 am
Posts: 155
Location: Somewhere
omarrx024 wrote:
You should allocate a new stack for the kernel in your TSS. Notice that the stack grows upwards on x86, and so it should be something like:
Code:
tss.esp0 = (uint32_t)kmalloc(STACK_SIZE) + STACK_SIZE;

I haven't reviewed your code in detail, but the segment registers in the TSS should be 0x10 for data and 0x08 for code (not 0x13 and 0x0B). Also, how are you installing your syscall handler? Make sure the IDT entry is set to "user" (using gate type 0xEE instead of 0x8E.)


Oh, it is my bad, again. It was a typo, I was using 0xDE instead of 0xEE, probably I pressed wrong key and didn't notice it.
Problem solved, thanks.

_________________
Keyboard not found!

Press F1 to run setup.
Press F2 to continue.


Last edited by Agola on Wed Feb 01, 2017 3:00 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: General Protection Fault while ISR in User Mode
PostPosted: Wed Feb 01, 2017 2:50 pm 
Offline
Member
Member
User avatar

Joined: Sun Nov 20, 2016 7:26 am
Posts: 155
Location: Somewhere
But... I don't understand some point.

0xEE is DPL = 3 version is 0x8E.
So it means I can perform the interrupt from user mode.

But, while I was looking at some open source os' code to verify that, I saw nobody is using 0xEE.

This is ToaruOS' code:
idt_set_gate(isrs[i].index, isrs[i].stub, 0x08, 0x8E);

Also the JamesM tutorial is using 0x8E, but I don't have very much knowledge about this tutorial because of http://wiki.osdev.org/James_Molloy's_Tu ... Known_Bugs , I didn't follow any other tutorials also in most parts of my os. And I don't need them while I have Intel Manuals, yay! :D

What in these OSes 0x8E is working, and in my os it isnt?
Also I can remember I used 0x8E syscalls with user mode in very very early stages of my os. It was working. Very strange :|

I used http://wiki.osdev.org/Interrupt_Descriptor_Table this time for writing it this time, that is because I wanted to use 0xEE, but used 0xDE because of typo.

And why it should be 0x8 and 0x10 in TSS? In structs RPL is "Requestor Privilege Level", and TSS requestor will be in Ring 3. That is why I used 0x0B and 0x13.

Thanks

_________________
Keyboard not found!

Press F1 to run setup.
Press F2 to continue.


Top
 Profile  
 
 Post subject: Re: [Partially solved] GPF while ISR in User Mode
PostPosted: Thu Feb 02, 2017 5:07 am 
Offline
Member
Member
User avatar

Joined: Sun Nov 20, 2016 7:26 am
Posts: 155
Location: Somewhere
Oh, I found what I missing.

Firstly I noticed idt_set_gate function doesn't or with 0x60, but many of other OS'es do.
Then converted 0x60 to binary, result was 0b01100000, then 0x8E | 0x60 is 0xEE.

But using it for all interrupt handlers is not a good design I think.
Then a program can call double fault handler from itself. Or a program can call int 32 (IRQ 0, PIT) in a loop, that will probably broke the system timer for other tasks/programs. Using 0xEE with *only* syscall handler is better.

Thanks everyone.

And the reason of it was working in very early stage of my os is I was directly linking newlib syscalls to kernel, now I don't.
It wasn't a good design. So I never used int instruction from my kernel when it was in "very early stage".

_________________
Keyboard not found!

Press F1 to run setup.
Press F2 to continue.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot], Majestic-12 [Bot], SemrushBot [Bot] and 118 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group