执行SYSRET时遇到一般保护故障

问题描述 投票:0回答:1

我目前正在开发自己的 64 位 x86-64 内核,现在尝试通过执行 SYSRET 指令来进入环 3。然而它失败了,我无法找出原因

这是我如何设置我的获取:

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

之后我尝试执行指令 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

我使用 qemu 运行代码,这是寄存器输出:

系统恢复前:

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

SYSRET 之后的 0xd(#GP) 和 0xc(#SS):

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

修改后:

void user_test() {
  for (;;) ;
}

错误信息:

   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 输出:

00000000001019be <user_test>:
  1019be: 55                            pushq   %rbp
  1019bf: 48 89 e5                      movq    %rsp, %rbp
  1019c2: eb fe                         jmp     0x1019c2 <user_test+0x4>
assembly x86-64 qemu osdev
1个回答
0
投票

原来是我没有正确设置TSS。请注意,在 64 位模式下,TSS 指针为 16 字节,而 STAR 寄存器中的 CS/SS 选择器为 8 字节。非常感谢迈克尔·佩奇和彼得·科德斯!

© www.soinside.com 2019 - 2024. All rights reserved.