Virtual Addressing...
OK,
Bochs is screaming about the RPL of SS not being equal to CPL. Check the priorities of your stack segment.
Also, your screen dump is incorrect - it says you are using the code segment (0x08) as data segments, whereas the Bochs dump indicates that you are using 0x10 as your data segment and 0x08 as your code segment.
Cheers,
Adam
Bochs is screaming about the RPL of SS not being equal to CPL. Check the priorities of your stack segment.
Also, your screen dump is incorrect - it says you are using the code segment (0x08) as data segments, whereas the Bochs dump indicates that you are using 0x10 as your data segment and 0x08 as your code segment.
Cheers,
Adam
Ok,
One more niggle about your exception handler - please could you get it to print in hex - it's a lot easier to think about the PL bits that way.
I make your SS->DS 0x23. That looks fine, as long as segment index 4 contains your data segment
Next, CS = 27=0x1B which also looks OK.
What I don't like the look of is CS = 0x08 (which I assume is your kernel mode code segment) which is next to SS = 35 (0x23). When the fault occurs, the SS is loaded from your TSS. This should be a kernel-privilege (RPL=0) stack segment selector. Could you check what's going on there?
Cheers,
Adam
One more niggle about your exception handler - please could you get it to print in hex - it's a lot easier to think about the PL bits that way.
I make your SS->DS 0x23. That looks fine, as long as segment index 4 contains your data segment
Next, CS = 27=0x1B which also looks OK.
What I don't like the look of is CS = 0x08 (which I assume is your kernel mode code segment) which is next to SS = 35 (0x23). When the fault occurs, the SS is loaded from your TSS. This should be a kernel-privilege (RPL=0) stack segment selector. Could you check what's going on there?
Cheers,
Adam
Hi,
I'm glad you don't get the GPF now. Heres basically what should be happening:
Your task is running happily in ring 3 (CPL3) when an interrupt happens.
In all likelyhood, the DPL of your interrupt descriptor (say, the timer interrupt (IRQ0)) is ring 0. This is sensible as it allows you to access kernel data.
but
As you are running in ring 3, you currently have a CS and SS with a PL of 3. Your kernel needs to run with CS and SS PL 0.
so
The kernel loads SS0 and ESP0 from your TSS *at the same time* as loading your ring 0 code segment descriptor. It then pushes the ring 3 SS, ESP, EFLAGS and CS on to the ring 0 stack. As SS and CS *must* always be the same PL, this is the only way it can be done.
If your TSS had a SS with PL3, it will fail as CPL now = 0 bur RPL of the SS is 3.
In the same way, when your task is restored, the only way to do this (in software multitasking) is using iret - an instruction which can simultaneously load SS, CS, ESP, EIP and EFLAGS!
As this all happens automagically, the bottom of your ring 0 stack *must* be in the order:
[stack base]
ring 3 SS
ring 3 ESP
EFLAGS
CS
EIP
...
[stack top]
THe other registers can be stored any way you like, as long as your C code and ASM code treat them in the same way(!). For example, if you want to use PUSHA/POPA, your general purpose registers will need to be in the correct order.
Remember to change SS0 in your TSS each time you switch to a new task, bearing in mind the information above. That's a possible cause of the kernel freezing, if you are using the wrong ring 0 stack for task switching.
HTH
Adam
I'm glad you don't get the GPF now. Heres basically what should be happening:
Your task is running happily in ring 3 (CPL3) when an interrupt happens.
In all likelyhood, the DPL of your interrupt descriptor (say, the timer interrupt (IRQ0)) is ring 0. This is sensible as it allows you to access kernel data.
but
As you are running in ring 3, you currently have a CS and SS with a PL of 3. Your kernel needs to run with CS and SS PL 0.
so
The kernel loads SS0 and ESP0 from your TSS *at the same time* as loading your ring 0 code segment descriptor. It then pushes the ring 3 SS, ESP, EFLAGS and CS on to the ring 0 stack. As SS and CS *must* always be the same PL, this is the only way it can be done.
If your TSS had a SS with PL3, it will fail as CPL now = 0 bur RPL of the SS is 3.
In the same way, when your task is restored, the only way to do this (in software multitasking) is using iret - an instruction which can simultaneously load SS, CS, ESP, EIP and EFLAGS!
As this all happens automagically, the bottom of your ring 0 stack *must* be in the order:
[stack base]
ring 3 SS
ring 3 ESP
EFLAGS
CS
EIP
...
[stack top]
THe other registers can be stored any way you like, as long as your C code and ASM code treat them in the same way(!). For example, if you want to use PUSHA/POPA, your general purpose registers will need to be in the correct order.
Remember to change SS0 in your TSS each time you switch to a new task, bearing in mind the information above. That's a possible cause of the kernel freezing, if you are using the wrong ring 0 stack for task switching.
HTH
Adam
yes, you need 1 stack for each ring you are using
however, most people use separate data segment discriptors for different rings -- that way they can restrict access to the kernel stack (normally, tasks will only run in ring3, ring0 is reserved for kernel usage only)
imho, the NASM manual is only good for a quick reference, not research, make sure you check with the intel manuals (volume 2A does list this information) -- the intel manuals are longer and much more detailed
without looking closely at your EFLAGS, it looks correct (ref: intel 3A:5.12.1:fig 5-4)How is this for a stack structure:
however, most people use separate data segment discriptors for different rings -- that way they can restrict access to the kernel stack (normally, tasks will only run in ring3, ring0 is reserved for kernel usage only)
imho, the NASM manual is only good for a quick reference, not research, make sure you check with the intel manuals (volume 2A does list this information) -- the intel manuals are longer and much more detailed