Switching Segments Causes Page Fault

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.
TheChuckster

Re:Switching Segments Causes Page Fault

Post by TheChuckster »

I think I'm on to something!

Looking at the Bochs log, I was able to find this gem of information: 00007381864e[CPU0 ] iret: SS selector null

Does this have to do with my TSS?

I modified my descriptor to be:

Code: Select all

gdt_set_gate(5, tss, 103, 0x89, 0); // TSS descriptor
To clear up the confusion about how I'm setting my GDT entries, here's the gdt_set_gate function:

Code: Select all

void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran)
{
    // Setup the descriptor base address
    gdt[num].base_low = (base & 0xFFFF);
    gdt[num].base_middle = (base >> 16) & 0xFF;
    gdt[num].base_high = (base >> 24) & 0xFF;

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

    // Set up the granularity and access flags
    gdt[num].granularity |= (gran & 0xF0);
    gdt[num].access = access;
}
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Switching Segments Causes Page Fault

Post by Candy »

TheChuckster wrote: Okay, looking at the Bochs log, I was able to find this gem of information: 00007381864e[CPU0 ] iret: SS selector null

Does this have to do with my TSS?
Do you use TSS based switching, if so did you set the SS in the TSS to something non-zero?
TheChuckster

Re:Switching Segments Causes Page Fault

Post by TheChuckster »

Remember, I mentioned earlier that I use software-based task switching. I'm trying to implement protection for my apps and if you look at my TSS in my previous post, you see:

dw 10h, 0 ; SS0, reserved

Why is it NULL, then?

Is my new descriptor bad, too?
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Switching Segments Causes Page Fault

Post by Candy »

TheChuckster wrote: Remember, I mentioned earlier that I use software-based task switching. I'm trying to implement protection for my apps and if you look at my TSS in my previous post, you see:

dw 10h, 0 ; SS0, reserved

Why is it NULL, then?

Is my new descriptor bad, too?
ok, I can see you set them up right but just provide 3 nibbles too much limit (which isn't bad, but just odd).

I do think you're pushing too little for a cpl-changing stack swap. IIRC, if you iret to a different PL it pops 5 values, if you iret to the same, it pops 3 values.
TheChuckster

Re:Switching Segments Causes Page Fault

Post by TheChuckster »

I tried compensating for the supposed stack problem by trying to add various even numbers to esp one line before iret in my interrupt handler. It still errors out for any number from 2-8.

I couldn't find anything saying that priviledge level irets pop a different amount of values off of the stack either so this might be bust.

I notice my task initialization code never sets SS. Where in the initial stack frame do I set it?

Reason being, I just found this in 4-24 of Intel Manual 3:
(If the return requires a privilege level change.) Checks the contents of DS, ES, FS, and GS segment registers. If any of these registers refer to segments whose DPL is less than the new CPL (excluding conforming code segments), the segment register is loaded with a null segment selector
Nevermind. They didn't say SS in there. :(
JoeKayzA

Re:Switching Segments Causes Page Fault

Post by JoeKayzA »

TheChuckster wrote: I couldn't find anything saying that priviledge level irets pop a different amount of values off of the stack either so this might be bust.

I notice my task initialization code never sets SS. Where in the initial stack frame do I set it?
Just a moment - you mean iret from cpl=0 to cpl=3? The usermode ss and esp must be provided on your stack before you reach iret, and are popped along with the new cs, eip and eflags. So the initial stack layout looks like this (top-down):

user ss
user esp
eflags
user cs
eip

From then on, you can safely do an iret. I just joined this thread now, sorry if I missed something above....

cheers Joe
TheChuckster

Re:Switching Segments Causes Page Fault

Post by TheChuckster »

Well I modified my handler again but it still doesn't work:

Code: Select all

irq0:
 push esp
 push ss
 pusha
 push ds
 push es
 push fs
 push gs
...
SS selector is still null.
JAAman

Re:Switching Segments Causes Page Fault

Post by JAAman »

irq0:
push esp
push ss
this won't do anything because the SS:eSP is pop'd after CS:eIP

so this wont give you a stack, it will give you a new eIP (you will RET to the base of your ring0 stack)
TheChuckster

Re:Switching Segments Causes Page Fault

Post by TheChuckster »

I'm confused by your post because AFAIK, CS:EIP is pushed by the CPU first thing automatically when the interrupt is fired. So if it's popped after, don't I need to some how push it before the interrupt? i.e

push esp ; assume this gets called right before the interrupt is fired
push ss
irq0:
pusha
push ds
push es
push fs
push gs
JAAman

Re:Switching Segments Causes Page Fault

Post by JAAman »

on an interupt, which changes ring, SS:eSP is push before CS:eIP, therefore, the iret will expect to find SS:eSP on the stack after CS:eIP

on a ret, the CPU needs to know if its changing rings before it 'POPs' SS:eSP, therefore it must retreive CS:eIP first (which will indicate the destination ring) then if new_ring != old_ring then also retrieve SS:eSP (if SS:eSP were pushed after CD:eIP then it couldn't possibly know whether it should retrieve SS:eSP or not!)


(see section 5.12.1, and figure 5-4):

Code: Select all

                  handlers stack after privilege change:
                  <- ESP points here before transfer
SS
ESP
EFLAGS
CS
EIP            <- ESP points here for hard, soft, and no-code firm exceptions
Error-Code  <- ESP points here for exceptions with an errorcode

so you can see SS:eSP exist on stack before CS:eIP
TheChuckster

Re:Switching Segments Causes Page Fault

Post by TheChuckster »

If the CPU does all of this pushing and popping automatically for me, then how is my code wrong?
JAAman

Re:Switching Segments Causes Page Fault

Post by JAAman »

the first time you iret into a process (when you first set it up), you must manually place the FLAGS & CS:eIP onto the stack to iret into

if your task is in ring0, you also must place SS:eSP on the stack also, because when the CPU 'POPs' CS:eIP, it will discover you are changing rings, and also 'POP' SS:eSP, if these are not on the stack you may recieve a #SS, #PF, #GF, or garbage in the SS:eSP (depending on how your stack is setup)

a few post ago you referenced intel page 4-24, but the information you were looking for is in section 5 (the section on exception handling)

the section you mentioned, talks about ret not iret, there is a difference on how it is handled (the section you want is 5.12 (page 5-14 - 19 in my copy), pay special note to figure 5-4 (which shows the differing stack setup for ring change, vs no ring change)
TheChuckster

Re:Switching Segments Causes Page Fault

Post by TheChuckster »

All right, that fixed that. I ran into some more trouble with the CPU infinitely looping, but then I saw that figure in the Intel manual and realized that I need to push an error code on to the stack as well.

Now I am getting an LDTR.valid = 0 error from Bochs. Now what's confusing is that I checked with the Intel manual to make sure that I was setting the access and granularity parts of the descriptor correctly and it seems like I am.

gdt_set_gate(5, tss, 103, 0x89, 0x0F); // TSS descriptor

5 being the fifth entry in my GDT, tss being a pointer to the tss in ASM, 103 bytes long,

0x89 is 10001001:
Present, ring 0 DPL, 0, type: 1001 (not busy)
Looks fine to me.

0 is 00000000 for granularity in binary:
1 byte granularity, 0, 0, available to the system, blank limit (gets set by gdt_set_gate)
Again, matches up with the Intel manual.

Perhaps I'm loading my task register incorrectly. As soon as lgdt is called and the segment registers are set including a far jump for CS, I proceed by moving 0x28 into ax and doing a ltr ax. Again, seems 100% fine to me.
JAAman

Re:Switching Segments Causes Page Fault

Post by JAAman »

you shouldn't need an error code for iret: that should be removed before the iret (iirc)

even if you did need an error code that shouldn't cause an inf-loop, but your LDTR.valid=0 error indicates your 'iret'ing the wrong CS -- one that points to an LDT instead of the GDT
Humble

Re:Switching Segments Causes Page Fault

Post by Humble »

The limit of TSS should be 104 (68h) not 103 AFAIK
Post Reply