[SOLVED] Kernel segments not restored on software interrupt

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.
Post Reply
tabz
Member
Member
Posts: 35
Joined: Fri Apr 20, 2018 9:15 am
Location: Cambridge, UK

[SOLVED] Kernel segments not restored on software interrupt

Post by tabz »

I'm having an issue where the segment registers aren't being set to the proper values when attempting to return to return to ring 0 from ring 3 via a syscall interrupt (int 0x80). After entering a function in user mode (via arch_switch_user_task in multitasking.s) the cs register is 27 (0x1B) corresponding to the user code segment with DPL 3 and the ds register is 35 (0x23) corresponding to the user data segment with DPL 3.

However when I attempt the syscall (here) and enter the handler for isr 128 and execute cli I get a protection fault, whose handler also tries to execute cli, which faults and it goes on recursively for a while before rebooting. This GPF is happening because when entering the isr 128 handler the ds register is 35 (user data segment with DPL3) and the cs register is 11 (kernel code segment with DPL 3). This is weird to me as I was under the impression that when an interrupt occurs, the CPU takes the ss0 value from the TSS and restores the segment registers to the kernel version, which is of course not happening.

My isr 128 handler has DPL 3 (flags are 0xEE) and selector 0x8. My TSS has a valid esp0, ss0 = 0x10, cs = 0x08 with the remaining segment values being 0x10.

Useful links:
* GDT
* IDT
* task switching

Their relevant header files are in src/arch/inc. Does anyone know what I could be doing wrong?
Last edited by tabz on Thu Feb 21, 2019 11:19 am, edited 1 time in total.
quirck
Member
Member
Posts: 42
Joined: Sun Nov 23, 2008 5:56 am
Location: Russia, Saint-Petersburg

Re: Kernel segments aren't restored on software interrupt

Post by quirck »

It seems that you make the kernel code segment conforming.. Try to clear that bit. If the code segment is conforming, the processor does not change the CPL when transferring control to it.
tabz
Member
Member
Posts: 35
Joined: Fri Apr 20, 2018 9:15 am
Location: Cambridge, UK

Re: Kernel segments aren't restored on software interrupt

Post by tabz »

quirck wrote:It seems that you make the kernel code segment conforming.. Try to clear that bit. If the code segment is conforming, the processor does not change the CPL when transferring control to it.
That makes sense. I've tried it am now getting an invalid TSS exception without even entering the handler for ISR 128. The error code is e8d8 which to me doesn't look like a segment selector, like the wiki says it should be :p

EDIT: Read further in the wiki and the error code is much more than just a segment selector, as I thought previously.
tabz
Member
Member
Posts: 35
Joined: Fri Apr 20, 2018 9:15 am
Location: Cambridge, UK

Re: Kernel segments aren't restored on software interrupt

Post by tabz »

quirck wrote:It seems that you make the kernel code segment conforming.. Try to clear that bit. If the code segment is conforming, the processor does not change the CPL when transferring control to it.
After reading the Intel manual's section about TSS exceptions, I see that such an exception can be triggered if:

* The nonconforming code segment DPL ≠ CPL
* The stack segment DPL ≠ CPL

At the point of the syscall CPL (assuming it means current privilege level) is 3 but the DPL (assuming it means desired privilege level) is 0, could that be the cause of the exception?

I've updated the linked code by the way.

Quoted below is the QEMU interrupt log:
0: v=80 e=0000 i=1 cpl=3 IP=001b:c0104d68 pc=c0104d68 SP=0023:c0523d5b env->regs[R_EAX]=00000001
EAX=00000001 EBX=00000000 ECX=00000001 EDX=c052459f
ESI=00000000 EDI=00000000 EBP=c0523d73 ESP=c0523d5b
EIP=c0104d68 EFL=00000292 [--S-A--] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
CS =001b 00000000 ffffffff 00cffa00 DPL=3 CS32 [-R-]
SS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
FS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
GS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =002b c000bc00 00000068 0000e900 DPL=3 TSS32-avl
GDT= c010bbc0 0000002f
IDT= c010b3c0 000007ff
CR0=80000011 CR2=00000000 CR3=00400000 CR4=00000010
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000018 CCD=c0523d5b CCO=SUBL
EFER=0000000000000000
check_exception old: 0xffffffff new 0xa
1: v=0a e=e8d8 i=0 cpl=3 IP=001b:c0104d68 pc=c0104d68 SP=0023:c0523d5b env->regs[R_EAX]=00000001
EAX=00000001 EBX=00000000 ECX=00000001 EDX=c052459f
ESI=00000000 EDI=00000000 EBP=c0523d73 ESP=c0523d5b
EIP=c0104d68 EFL=00000292 [--S-A--] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
CS =001b 00000000 ffffffff 00cffa00 DPL=3 CS32 [-R-]
SS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
FS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
GS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =002b c000bc00 00000068 0000e900 DPL=3 TSS32-avl
GDT= c010bbc0 0000002f
IDT= c010b3c0 000007ff
CR0=80000011 CR2=00000000 CR3=00400000 CR4=00000010
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000018 CCD=c0523d5b CCO=SUBL
EFER=0000000000000000
check_exception old: 0xa new 0xa
2: v=08 e=0000 i=0 cpl=3 IP=001b:c0104d68 pc=c0104d68 SP=0023:c0523d5b env->regs[R_EAX]=00000001
EAX=00000001 EBX=00000000 ECX=00000001 EDX=c052459f
ESI=00000000 EDI=00000000 EBP=c0523d73 ESP=c0523d5b
EIP=c0104d68 EFL=00000292 [--S-A--] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
CS =001b 00000000 ffffffff 00cffa00 DPL=3 CS32 [-R-]
SS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
DS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
FS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
GS =0023 00000000 ffffffff 00cff300 DPL=3 DS [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =002b c000bc00 00000068 0000e900 DPL=3 TSS32-avl
GDT= c010bbc0 0000002f
IDT= c010b3c0 000007ff
CR0=80000011 CR2=00000000 CR3=00400000 CR4=00000010
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000018 CCD=c0523d5b CCO=SUBL
EFER=0000000000000000
check_exception old: 0x8 new 0xa
Octocontrabass
Member
Member
Posts: 5586
Joined: Mon Mar 25, 2013 7:01 pm

Re: Kernel segments aren't restored on software interrupt

Post by Octocontrabass »

tabz wrote:

Code: Select all

     1: v=0a e=e8d8 i=0 cpl=3 IP=001b:c0104d68 pc=c0104d68 SP=0023:c0523d5b env->regs[R_EAX]=00000001
Judging by that error code, something about your TSS is directing the CPU to load a segment way off the end of your GDT. You might want to check the contents of the TSS and see if it's been overwritten. (I'll admit I'm not especially familiar with TSS issues, but I can't think of anything else that would cause such a strange error code.)

Is there any particular reason you've set up the TSS for ring 3 instead of ring 0?
tabz
Member
Member
Posts: 35
Joined: Fri Apr 20, 2018 9:15 am
Location: Cambridge, UK

Re: Kernel segments aren't restored on software interrupt

Post by tabz »

Octocontrabass wrote:
tabz wrote:

Code: Select all

     1: v=0a e=e8d8 i=0 cpl=3 IP=001b:c0104d68 pc=c0104d68 SP=0023:c0523d5b env->regs[R_EAX]=00000001
Judging by that error code, something about your TSS is directing the CPU to load a segment way off the end of your GDT. You might want to check the contents of the TSS and see if it's been overwritten. (I'll admit I'm not especially familiar with TSS issues, but I can't think of anything else that would cause such a strange error code.)
So I checked the contents of the tss right before issuing the int 0x80, and it looks valid to me:

Code: Select all

Breakpoint 1, 0xc0104d4c in cleaner () at src/kernel/multitasking/multitasking.c:39
39	    ARCH_SYSCALL(0x1);
(gdb) p tss
$1 = {prev_tss = 0, esp0 = 3226613111, ss0 = 16, esp1 = 0, ss1 = 0, esp2 = 0, ss2 = 0, cr3 = 0, eip = 0, 
  eflags = 0, eax = 0, ecx = 0, edx = 0, ebx = 0, esp = 0, ebp = 0, esi = 0, edi = 0, es = 16, cs = 8, 
  ss = 16, ds = 16, fs = 16, gs = 16, ldt = 0, trap = 0, iomap_base = 104}
Octocontrabass wrote:Is there any particular reason you've set up the TSS for ring 3 instead of ring 0?
(Assuming you're referring to the DPL in the TSS GDT entry) I did so after looking at toaruOS GDT code, which had it set up for use in ring 3, which makes sense to me as it needs to be accessed by the CPU before it has gone through the privilege level change. Setting the DPL to ring 0 didn't stop the TSS exception from occurring.
tabz
Member
Member
Posts: 35
Joined: Fri Apr 20, 2018 9:15 am
Location: Cambridge, UK

Re: Kernel segments aren't restored on software interrupt

Post by tabz »

I managed to fix the invalid TSS issue by taking another look at my tss base calculations. It turned out that I was using 0xFFFF to mask of the low part of the base instead of 0xFFFFFF. Thanks for the help!
Post Reply