user23674605
user23674605

Reputation: 41

General Protection Fault encountered when executing SYSRET

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

Answers (1)

user23674605
user23674605

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

Related Questions