Page 1 of 1

Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 3:44 am
by Sourcer
Hey, this is my first attempt in running a user-mode code.

I followed some tutorials in the web, but still can't figure out why this won't work(32 bit btw)
My GDT is:
[null segment][ring0-data-segment][ring0-code-segment][ring3-data-segment][ring3-code-segment][tss_selector]

Trying to run:

Code: Select all

mov ax, 0x18
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

push (0x18 | 3) 
push 4095
pushf
push (0x20 | 3)
push 1
iret
I mapped Entry#0 in PT#0 to a physical page(with read, write, present, user permissions).
In address 1 theres a valid function, I get a fault everytime the code reaches 'iret'.

Anyway, if i'm already asking, why do i have the OR the GDT segement indices when when loading them to the registers? i haven't done that when i loaded the kernel GDT segements.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 3:59 am
by Octocontrabass
Sourcer wrote:I get a fault everytime the code reaches 'iret'.
Which one? If you're using an emulator (Bochs, qemu, ...) you should be able to find this information in the logs.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 4:06 am
by StephanvanSchaik
Sourcer wrote:Hey, this is my first attempt in running a user-mode code.

I followed some tutorials in the web, but still can't figure out why this won't work(32 bit btw)
My GDT is:
[null segment][ring0-data-segment][ring0-code-segment][ring3-data-segment][ring3-code-segment][tss_selector]
Your GDT lay-out is a bit inconvenient when you want to support instructions like SYSENTER/SYSEXIT later on, because those instructions have the following assumptions: KERNEL_DS = KERNEL_CS + 8, USER_CS = KERNEL_CS + 16 and USER_DS = KERNEL_CS + 24.

Furthermore, I think you are approaching this in a weird order anyway. If you get a triple fault, then that is clearly an indication you haven't set up an IDT with more user friendly exception handlers that at least tell you what went wrong together with a dump of the registers. At the very minimum you should use a tool like QEMU and Bochs for this, so that you can at least get an indication of what lead to the triple fault (in case you don't have your own more convenient exception handlers). Besides the exception handlers, you definitely need some kind of system call handler for user mode to be useful.
Sourcer wrote: Trying to run:

Code: Select all

mov ax, 0x18
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

push (0x18 | 3) 
push 4095
pushf
push (0x20 | 3)
push 1
iret
Setting esp to 4095 for the user stack seems to be a bit odd to me. First of all, I would align the address to a 4-byte, 8-byte or even a 16-byte boundary, which means that 0x1000 (= 4096) makes a lot more sense. Furthermore, I wouldn't locate the user stack at 0x0000 - 0x1000, because you don't really want dereferencing NULL-pointers to be a valid operation, which again makes me wonder in what kind of order you are trying to approach things: having a physical and virtual memory manager would really be convenient here.
Sourcer wrote: Anyway, if i'm already asking, why do i have the OR the GDT segement indices when when loading them to the registers? i haven't done that when i loaded the kernel GDT segements.
The two least significant bits represent the Requested Privilege Level, which should equal to 3 since you want to switch to ring 3.

Do note that I added a few edits.


Yours sincerely,
Stephan.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 4:09 am
by Sourcer
StephanvanSchaik wrote:
Sourcer wrote:Hey, this is my first attempt in running a user-mode code.

I followed some tutorials in the web, but still can't figure out why this won't work(32 bit btw)
My GDT is:
[null segment][ring0-data-segment][ring0-code-segment][ring3-data-segment][ring3-code-segment][tss_selector]
Your GDT lay-out is a bit inconvenient when you want to support instructions like SYSENTER/SYSEXIT later on, because those instructions have the following assumptions: KERNEL_DS = KERNEL_CS + 8, USER_CS = KERNEL_CS + 16 and USER_DS = KERNEL_CS + 24.

Furthermore, I think you are approaching this in a weird order anyway. If you get a triple fault, then that is clearly an indication you haven't set up an IDT with more user friendly exception handlers that at least tell you what went wrong together with a dump of the registers. At the very minimum you should use a tool like QEMU and Bochs for this, so that you can at least get an indication of what lead to the triple fault (in case you don't have your own more convenient exception handlers).
Sourcer wrote: Trying to run:

Code: Select all

mov ax, 0x18
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

push (0x18 | 3) 
push 4095
pushf
push (0x20 | 3)
push 1
iret
Setting esp to 4095 for the user stack seems to be a bit odd to me. First of all, I would align the address to a 4-byte, 8-byte or even a 16-byte boundary, which means that 0x1000 (= 4096) makes a lot more sense. Furthermore, I wouldn't locate the user stack at 0x0000 - 0x1000, because you don't really want dereferencing NULL-pointers to be a valid operation.
Sourcer wrote: Anyway, if i'm already asking, why do i have the OR the GDT segement indices when when loading them to the registers? i haven't done that when i loaded the kernel GDT segements.
The two least significant bits represent the Requested Privilege Level, which should equal to 3 since you want to switch to ring 3.


Yours sincerely,
Stephan.
But there are also bits in the GDT selector itself which determine if the selector is ring 3 or ring 0, so why do i need this one?

Also, 4095 is the end of the page that was mapped, and the stack grows down. I'm aware of NULL pointers, this is only a sanity check. and 0 is the first address that came to my mind. I have a virtual memory manager and a physical memory manager(NOTE again, this is only a SANITY check) Regardless, i don't need to think about alignment issues in x86 as far as i know.

I haven't set the exception handlers yet, i'm using qemu's log to find out what happens. Will set them in the future. Anyway QEMU only throws "CPU Reset 0" to the screen.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 4:20 am
by Octocontrabass
Sourcer wrote:But there are also bits in the GDT selector itself which determine if the selector is ring 3 or ring 0, so why do i need this one?
The GDT only specifies which rings are allowed to use each segment. The lowest two bits of the segment registers specify which ring you are reading/writing/executing from.
Sourcer wrote:Also, 4095 is the end of the page that was mapped, and the stack grows down.
ESP points to the last item pushed to the stack. If the stack is empty, then it should point just past the first place where data may be stored. In this case, you want ESP to be 4096.
Sourcer wrote:Regardless, i don't need to think about alignment issues in x86 as far as i know.
Alignment is very important in modern x86. Unaligned accesses are much slower than aligned accesses, and many SIMD instructions have alignment requirements.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 4:26 am
by StephanvanSchaik
Sourcer wrote: But there are also bits in the GDT selector itself which determine if the selector is ring 3 or ring 0, so why do i need this one?
The Descriptor Privilege Level only tells what privilege levels are allowed to access the segment. If your privilege level is higher than the Descriptor Privilege Level of the segment you are trying to access, then you end up with a general protection fault. Simply loading the segments do not cause the privilege level to be changed, this is what the Requested Privilege Level is for. The only exception here is the segment stack register, for which the privilege level of the segment descriptor should always match with the privilege level you are running in, which means that you cannot simply set the ss register, but have to use iret to change it.
Sourcer wrote: Also, 4095 is the end of the page that was mapped, and the stack grows down. I'm aware of NULL pointers, this is only a sanity check. and 0 is the first address that came to my mind. Regardless, i don't need to think about alignment issues in x86 as far as i know.
A page is 4 kiB or 4096 bytes: 0x0000 + 4096 = 0x1000, so the end of the page is 0x1000 (= 4096) and not 0xFFF (= 4095). I am aware of the fact that x86(-64) is very forgiving compared to other architectures in the sense that unaligned access is actually tolerated by the architecture, at a high cost of performance, but that doesn't mean you should do it like that.
Sourcer wrote: I haven't set the exception handlers yet, i'm using qemu's log to find out what happens. Will set them in the future. Anyway QEMU only throws "CPU Reset 0" to the screen.
Usually QEMU should show you three faults where the final one is the triple fault that lead to a CPU reset. Are you invoking QEMU with " -d int -no-reboot"?


Yours sincerely,
Stephan.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 4:27 am
by Sourcer
Octocontrabass wrote:
Sourcer wrote:But there are also bits in the GDT selector itself which determine if the selector is ring 3 or ring 0, so why do i need this one?
The GDT only specifies which rings are allowed to use each segment. The lowest two bits of the segment registers specify which ring you are reading/writing/executing from.
Sourcer wrote:Also, 4095 is the end of the page that was mapped, and the stack grows down.
ESP points to the last item pushed to the stack. If the stack is empty, then it should point just past the first place where data may be stored. In this case, you want ESP to be 4096.
Sourcer wrote:Regardless, i don't need to think about alignment issues in x86 as far as i know.
Alignment is very important in modern x86. Unaligned accesses are much slower than aligned accesses, and many SIMD instructions have alignment requirements.
Interseting :)
Anyway i don't see how changing the stack from 4095 to 4096 should solve my problem, but indeed i tried it. Didn't solve it :( It seems that the SS, CS do not change, and all of the other segment registers do change. They stay as they are(kernel segment selectors). The EIP still points to kernel code, which makes me suspect the 'iret' fails somehow, and not the code in the userspace.

I invoked qemu with '-d cpu_reset'. I tried '-d int -no-reboot'. Where is the exception identifier written?

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 4:32 am
by StephanvanSchaik
[quote="Sourcer"]

Code: Select all

mov ax, 0x18
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

push (0x18 | 3) 
push 4095
pushf
push (0x20 | 3)
push 1
iret
Why are you having IRET return to EIP = 1? I am quite sure your user mode code isn't located at that address, or is it?


Yours sincerely,
Stephan.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 4:33 am
by Sourcer
StephanvanSchaik wrote:
Sourcer wrote:

Code: Select all

mov ax, 0x18
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax

push (0x18 | 3) 
push 4095
pushf
push (0x20 | 3)
push 1
iret
Why are you having IRET return to EIP = 1? I am quite sure your user mode code isn't located at that address, or is it?


Yours sincerely,
Stephan.

Yes it is located in that address. As i've said, i just picked a random address and mapped a physical page into it, when the appropriate flags in the page table entry, just to make a sanity check. Address 1 contains 'int 0x80'. And yes, i have a interrupt handler located in 0x80 in the IDT, and i have set ss0 and esp0 in the TSS for the kernel stack. It seems the CPU won't even reach the user code. Something happens before, in the 'iret'.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 4:39 am
by StephanvanSchaik
Sourcer wrote: I invoked qemu with '-d cpu_reset'. I tried '-d int -no-reboot'. Where is the exception identifier written?
You should see something like:

Code: Select all

     0: v=03 e=0000 i=1 cpl=0 IP=0010:0000000000100019 pc=0000000000100019 SP=0018:000000000007ff00 env->regs[R_EAX]=0000000036d76289
EAX=36d76289 EBX=00113430 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=0007ff00
EIP=00100019 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0010 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000010b0 00000020
IDT=     00000000 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00000000 CCO=LOGICL  
EFER=0000000000000000
check_exception old: 0xffffffff new 0xd
     1: v=0d e=001a i=0 cpl=0 IP=0010:0000000000100019 pc=0000000000100019 SP=0018:000000000007ff00 env->regs[R_EAX]=0000000036d76289
EAX=36d76289 EBX=00113430 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=0007ff00
EIP=00100019 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0010 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000010b0 00000020
IDT=     00000000 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00000000 CCO=LOGICL  
EFER=0000000000000000
check_exception old: 0xd new 0xd
     2: v=08 e=0000 i=0 cpl=0 IP=0010:0000000000100019 pc=0000000000100019 SP=0018:000000000007ff00 env->regs[R_EAX]=0000000036d76289
EAX=36d76289 EBX=00113430 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=0007ff00
EIP=00100019 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0010 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000010b0 00000020
IDT=     00000000 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00000000 CCO=LOGICL  
EFER=0000000000000000
check_exception old: 0x8 new 0xd
So here we can see by looking at the line with "check exception" that a double fault and GPF occurred.
Sourcer wrote: Yes it is located in that address. As i've said, i just picked a random address and mapped a physical page into it, when the appropriate flags in the page table entry, just to make a sanity check. Address 1 contains 'int 0x80'. And yes, i have a interrupt handler located in 0x80 in the IDT, and i have set ss0 and esp0 in the TSS for the kernel stack. It seems the CPU won't even reach the user code. Something happens before, in the 'iret'.
The TSS is only needed when you are in user mode and want to switch back. It would probably be wise to check if your user code and data segment descriptors are in fact correct.


Yours sincerely,
Stephan.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 4:43 am
by Sourcer
StephanvanSchaik wrote:
Sourcer wrote: I invoked qemu with '-d cpu_reset'. I tried '-d int -no-reboot'. Where is the exception identifier written?
You should see something like:

Code: Select all

     0: v=03 e=0000 i=1 cpl=0 IP=0010:0000000000100019 pc=0000000000100019 SP=0018:000000000007ff00 env->regs[R_EAX]=0000000036d76289
EAX=36d76289 EBX=00113430 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=0007ff00
EIP=00100019 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0010 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000010b0 00000020
IDT=     00000000 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00000000 CCO=LOGICL  
EFER=0000000000000000
check_exception old: 0xffffffff new 0xd
     1: v=0d e=001a i=0 cpl=0 IP=0010:0000000000100019 pc=0000000000100019 SP=0018:000000000007ff00 env->regs[R_EAX]=0000000036d76289
EAX=36d76289 EBX=00113430 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=0007ff00
EIP=00100019 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0010 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000010b0 00000020
IDT=     00000000 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00000000 CCO=LOGICL  
EFER=0000000000000000
check_exception old: 0xd new 0xd
     2: v=08 e=0000 i=0 cpl=0 IP=0010:0000000000100019 pc=0000000000100019 SP=0018:000000000007ff00 env->regs[R_EAX]=0000000036d76289
EAX=36d76289 EBX=00113430 ECX=00000000 EDX=00000000
ESI=00000000 EDI=00000000 EBP=00000000 ESP=0007ff00
EIP=00100019 EFL=00000046 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0010 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0018 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000010b0 00000020
IDT=     00000000 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000004 CCD=00000000 CCO=LOGICL  
EFER=0000000000000000
check_exception old: 0x8 new 0xd
So here we can see by looking at the line with "check exception" that a double fault and GPF occurred.
Sourcer wrote: Yes it is located in that address. As i've said, i just picked a random address and mapped a physical page into it, when the appropriate flags in the page table entry, just to make a sanity check. Address 1 contains 'int 0x80'. And yes, i have a interrupt handler located in 0x80 in the IDT, and i have set ss0 and esp0 in the TSS for the kernel stack. It seems the CPU won't even reach the user code. Something happens before, in the 'iret'.
The TSS is only needed when you are in user mode and want to switch back. It would probably be wise to check if your user code and data segment descriptors are in fact correct.


Yours sincerely,
Stephan.
a #GPF occured in my code aswell. I'll try to investigate why... this is weird.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 4:59 am
by StephanvanSchaik
To give you a bit of a reference, I have tried a jump to usermode in my kernel as follows:

Without a TSS and If the iret succeeds you should get something like this if you invoke an interrupt in user mode:

Code: Select all

qemu: fatal: invalid tss type
EAX=00000023 EBX=ffbfffd8 ECX=00000039 EDX=00001000
ESI=c0104fd8 EDI=00106000 EBP=00000000 ESP=00004000
EIP=00001000 EFL=00000046 [---Z-P-] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0023 00000000 000fffff 004ff300 DPL=3 DS   [-WA]
CS =001b 00000000 000fffff 004ffa00 DPL=3 CS32 [-R-]
SS =0023 00000000 000fffff 004ff300 DPL=3 DS   [-WA]
DS =0023 00000000 000fffff 004ff300 DPL=3 DS   [-WA]
FS =0023 00000000 000fffff 004ff300 DPL=3 DS   [-WA]
GS =0023 00000000 000fffff 004ff300 DPL=3 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
In my kmain(), I added the following code to switch to user mode:

Code: Select all

    mmap((void *)0x1000, 4096, VM_READ | VM_WRITE | VM_EXEC | VM_USER);
    mmap((void *)0x4000, 0, VM_READ | VM_WRITE | VM_USER | VM_GROWS_DOWN);
    memcpy((void *)0x1000, umain, 4096);

    asm volatile(
        "movw $0x23, %%ax;"
        "movw %%ax, %%ds;"
        "movw %%ax, %%es;"
        "movw %%ax, %%fs;"
        "movw %%ax, %%gs;"
        "pushl $0x23;"
        "pushl $0x4000;"
        "pushf;"
        "pushl $0x1b;"
        "pushl $0x1000;"
        "iret" ::: "%eax");
My umain() looks like this:

Code: Select all

void umain(void)
{
    asm volatile("int $3");
}
And finally this is what my segment descriptors look like:

Code: Select all

#define GDT_ACCESSED (1 << 0)
#define GDT_RW (1 << 1)
#define GDT_DIR (1 << 2)
#define GDT_EXEC (1 << 3)
#define GDT_DEFAULT (1 << 4)
#define GDT_PRIVL(x) (((x) & 0x3) << 5)
#define GDT_PRESENT (1 << 7)
#define GDT_LIMIT(x) (((x) & 0xF) << 8)
#define GDT_SIZE (1 << 14)
#define GDT_GRANULARITY (1 << 15)

#define GDT_KCODE_FLAGS \
	(GDT_RW | GDT_EXEC | GDT_DEFAULT | GDT_PRESENT)
#define GDT_KDATA_FLAGS \
	(GDT_RW | GDT_DEFAULT | GDT_PRESENT)
#define GDT_UCODE_FLAGS \
	(GDT_KCODE_FLAGS | GDT_PRIVL(3))
#define GDT_UDATA_FLAGS \
	(GDT_KDATA_FLAGS | GDT_PRIVL(3))

struct gdt_entry gdt_entries[] = {
	/* Null descriptor. */
	{ 0 },

	/* Kernel code descriptor. */
	{
		.limit_low = 0xFFFF,
		.flags = GDT_KCODE_FLAGS | GDT_SIZE | GDT_LIMIT(0xF),
	},

	/* Kernel data descriptor. */
	{
		.limit_low = 0xFFFF,
		.flags = GDT_KDATA_FLAGS | GDT_SIZE | GDT_LIMIT(0xF),
	},

	/* User code descriptor. */
	{
		.limit_low = 0xFFFF,
		.flags = GDT_UCODE_FLAGS | GDT_SIZE | GDT_LIMIT(0xF),
	},

	/* User data descriptor. */
	{
		.limit_low = 0xFFFF,
		.flags = GDT_UDATA_FLAGS | GDT_SIZE | GDT_LIMIT(0xF),
	},
};

Yours sincerely,
Stephan.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 7:10 am
by BrightLight
It's odd enough that you set your data segment registers to 0x18 while they (obviously) should be 0x18 | 0x03.

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 10:39 am
by Sourcer
omarrx024 wrote:It's odd enough that you set your data segment registers to 0x18 while they (obviously) should be 0x18 | 0x03.
Well obviously this isn't the problem, i'll be just executing code in ring 0 again. Thank you anyway :)

Re: Triple fault when attemping a jump to ring 3.

Posted: Sat Oct 01, 2016 1:07 pm
by BrightLight
Sourcer wrote:
omarrx024 wrote:It's odd enough that you set your data segment registers to 0x18 while they (obviously) should be 0x18 | 0x03.
Well obviously this isn't the problem, i'll be just executing code in ring 0 again. Thank you anyway :)
No. When the CPL in CS is 3 and DS, ES or SS are ring 0, the system raises a GPF. The GPF causes it to read values from the TSS; and your TSS may be corrupt, thus raising a corrupt TSS exception; which as well can't be handle, ultimately causing a triple fault.