Reputation: 41
I am currently working on my own 64-bit x86-64 kernel, and now trying to get to ring 3 by executing the instruction SYSRET. However it fails and I could not figure out the reason
Here is how I set up my get:
uint64 gdt[6]; // gdt data struct
gdt[0] = 0UL; // dummy
gdt[1] = 0x00a0980000000000UL; // kernel code
gdt[2] = 0x00c0920000000000UL; // kernel data
gdt[3] = 0UL; // reserved
gdt[4] = 0x00c0f20000000000UL; // user data
gdt[5] = 0x00a0f80000000000UL; // user code
struct gdtp {
uint16 size;
uint64 addr;
} __attribute__((packed)) _gdtp; // gdt pointer
_gdtp.size = 8 * 6 - 1;
_gdtp.addr = (uint64)&gdt[0]; // setting gdt pointer
__asm__ __volatile__ ("lgdt 0x1031d0"); // load the gdt pointer, 0x1031d0 is the gdt pointer address
After that I try to execute the instruction SYSRET:
global jump_usermode
extern user_test
jump_usermode:
;enable system call extensions that enables sysret and syscall
mov rcx, 0xc0000082 ; LSTAR
wrmsr
mov rcx, 0xc0000080 ; ENABLE SYSCALL/SYSRET
rdmsr
or eax, 1
wrmsr
mov rcx, 0xc0000081 ; SETTING STAR[63:48], for SS & CS
rdmsr
mov edx, 0x00180008
wrmsr
mov rcx, user_test ; to be loaded into RIP
mov r11, 0x202 ; to be loaded into EFLAGS
o64 sysret
I ran the code using qemu, here is the registers output:
BEFORE SYSRET:
Servicing hardware INT=0x20
192: v=20 e=0000 i=0 cpl=0 IP=0008:0000000000101852 pc=0000000000101852 SP=0000:0000000000110ef0 env->regs[R_EAX]=0000000000000010
RAX=0000000000000010 RBX=0000000000000000 RCX=0000000000000008 RDX=00000000000003f8
RSI=0000000000000030 RDI=00000000000003f8 RBP=0000000000110fe0 RSP=0000000000110ef0
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=0000000000101852 RFL=00000212 [----A--] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =0008 0000000000000000 00000000 00209800 DPL=0 CS64 [---]
SS =0000 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA]
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= 0000000000100284 0000000f
IDT= 00000000001031e0 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000105000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000010 CCD=0000000000000001 CCO=EFLAGS
EFER=0000000000000500
0xd(#GP) and 0xc(#SS) after SYSRET:
check_exception old: 0xffffffff new 0xd
193: v=0d e=0000 i=0 cpl=3 IP=002b:00000000001013bd pc=00000000001013bd SP=0023:0000000000110e90 env->regs[R_EAX]=00000000000003fd
RAX=00000000000003fd RBX=0000000000000000 RCX=00000000001019ee RDX=00000000000003fd
RSI=0000000000000030 RDI=00000000000003fd RBP=0000000000110e90 RSP=0000000000110e90
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000202
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=00000000001013bd RFL=00000202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =002b 0000000000000000 ffffffff 00a0fb00 DPL=3 CS64 [-RA]
SS =0023 0000000000000000 ffffffff 00c0f300 DPL=3 DS [-WA]
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= 00000000001031a0 0000002f
IDT= 00000000001031e0 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000105000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000005 CCD=00000000000003fd CCO=ADDL
EFER=0000000000000501
check_exception old: 0xd new 0xc
194: v=08 e=0000 i=0 cpl=3 IP=002b:00000000001013bd pc=00000000001013bd SP=0023:0000000000110e90 env->regs[R_EAX]=00000000000003fd
RAX=00000000000003fd RBX=0000000000000000 RCX=00000000001019ee RDX=00000000000003fd
RSI=0000000000000030 RDI=00000000000003fd RBP=0000000000110e90 RSP=0000000000110e90
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000202
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=00000000001013bd RFL=00000202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =002b 0000000000000000 ffffffff 00a0fb00 DPL=3 CS64 [-RA]
SS =0023 0000000000000000 ffffffff 00c0f300 DPL=3 DS [-WA]
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= 00000000001031a0 0000002f
IDT= 00000000001031e0 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000105000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000005 CCD=00000000000003fd CCO=ADDL
EFER=0000000000000501
check_exception old: 0x8 new 0xc
After modification:
void user_test() {
for (;;) ;
}
Error message:
280: v=0c e=0000 i=0 cpl=3 IP=002b:00000000001019c2 pc=00000000001019c2 SP=0023:0000000000110fd0 env->regs[R_EAX]=0000000000000000
RAX=0000000000000000 RBX=0000000000000000 RCX=00000000001019be RDX=0000000000180008
RSI=000000000000000a RDI=00000000000003f8 RBP=0000000000110fd0 RSP=0000000000110fd0
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000202
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=00000000001019c2 RFL=00000202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =002b 0000000000000000 ffffffff 00a0fb00 DPL=3 CS64 [-RA]
SS =0023 0000000000000000 ffffffff 00c0f300 DPL=3 DS [-WA]
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= 00000000001031a0 0000002f
IDT= 00000000001031e0 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000105000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000000 CCD=0000000000000501 CCO=EFLAGS
EFER=0000000000000501
check_exception old: 0xc new 0xc
281: v=08 e=0000 i=0 cpl=3 IP=002b:00000000001019c2 pc=00000000001019c2 SP=0023:0000000000110fd0 env->regs[R_EAX]=0000000000000000
RAX=0000000000000000 RBX=0000000000000000 RCX=00000000001019be RDX=0000000000180008
RSI=000000000000000a RDI=00000000000003f8 RBP=0000000000110fd0 RSP=0000000000110fd0
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000202
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=00000000001019c2 RFL=00000202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0
ES =0000 0000000000000000 00000000 00000000
CS =002b 0000000000000000 ffffffff 00a0fb00 DPL=3 CS64 [-RA]
SS =0023 0000000000000000 ffffffff 00c0f300 DPL=3 DS [-WA]
DS =0000 0000000000000000 00000000 00000000
FS =0000 0000000000000000 00000000 00000000
GS =0000 0000000000000000 00000000 00000000
LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT
TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy
GDT= 00000000001031a0 0000002f
IDT= 00000000001031e0 00000fff
CR0=80000011 CR2=0000000000000000 CR3=0000000000105000 CR4=00000020
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=0000000000000000 CCD=0000000000000501 CCO=EFLAGS
EFER=0000000000000501
OBJDUMP output:
00000000001019be <user_test>:
1019be: 55 pushq %rbp
1019bf: 48 89 e5 movq %rsp, %rbp
1019c2: eb fe jmp 0x1019c2 <user_test+0x4>
Upvotes: 2
Views: 230
Reputation: 41
It turns out that I have not set up TSS correctly. Notice that in 64-bit mode TSS-pointer is 16byte, while CS/SS Selector from STAR registers are 8byte. Thank you so much, Michael Petch and Peter Cordes!
Upvotes: 2