Page 2 of 4
Re:Switching Segments Causes Page Fault
Posted: Sun Nov 20, 2005 3:31 pm
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;
}
Re:Switching Segments Causes Page Fault
Posted: Sun Nov 20, 2005 3:33 pm
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?
Re:Switching Segments Causes Page Fault
Posted: Sun Nov 20, 2005 3:35 pm
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?
Re:Switching Segments Causes Page Fault
Posted: Sun Nov 20, 2005 3:53 pm
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.
Re:Switching Segments Causes Page Fault
Posted: Sun Nov 20, 2005 7:31 pm
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.
Re:Switching Segments Causes Page Fault
Posted: Mon Nov 21, 2005 1:37 am
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
Re:Switching Segments Causes Page Fault
Posted: Mon Nov 21, 2005 5:49 am
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.
Re:Switching Segments Causes Page Fault
Posted: Mon Nov 21, 2005 10:35 am
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)
Re:Switching Segments Causes Page Fault
Posted: Mon Nov 21, 2005 2:45 pm
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
Re:Switching Segments Causes Page Fault
Posted: Mon Nov 21, 2005 3:57 pm
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
Re:Switching Segments Causes Page Fault
Posted: Mon Nov 21, 2005 5:07 pm
by TheChuckster
If the CPU does all of this pushing and popping automatically for me, then how is my code wrong?
Re:Switching Segments Causes Page Fault
Posted: Mon Nov 21, 2005 5:36 pm
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)
Re:Switching Segments Causes Page Fault
Posted: Wed Nov 23, 2005 5:29 pm
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.
Re:Switching Segments Causes Page Fault
Posted: Mon Nov 28, 2005 9:20 am
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
Re:Switching Segments Causes Page Fault
Posted: Mon Nov 28, 2005 11:41 am
by Humble
The limit of TSS should be 104 (68h) not 103 AFAIK