diff --git a/arch/x86/entry.S b/arch/x86/entry.S index f3a6d368..48ac24a5 100644 --- a/arch/x86/entry.S +++ b/arch/x86/entry.S @@ -175,6 +175,10 @@ ENTRY(syscall_exit) SWITCH_STACK POPF + /* Restore default GS (PERCPU) segment selector */ + mov $__KERN_PERCPU, %_ASM_AX + mov %_ASM_AX, %gs + /* Save exit code to return value register (AX) */ mov %_ASM_SI, cpu_regs_ax(%_ASM_SP) RESTORE_ALL_REGS @@ -196,6 +200,9 @@ ENTRY(enter_usermode) SAVE_ALL_REGS PUSHF + /* Disable interrupts for stack switch and swapgs */ + cli + /* Save user stack pointer onto per-cpu */ mov %_ASM_DX, %gs:(usermode_private) @@ -208,8 +215,8 @@ ENTRY(enter_usermode) /* EFLAGS */ PUSHF - - orl $X86_EFLAGS_IOPL, (%_ASM_SP) + /* Set IOPL=3 and re-enable interrupts via IRET */ + orl $(X86_EFLAGS_IOPL | X86_EFLAGS_IF), (%_ASM_SP) /* CS + IP */ push $__USER_CS diff --git a/arch/x86/traps.c b/arch/x86/traps.c index bd76b384..30b3e6d1 100644 --- a/arch/x86/traps.c +++ b/arch/x86/traps.c @@ -114,7 +114,7 @@ static void init_gdt(percpu_t *percpu) { lgdt(&percpu->gdt_ptr); write_ss(__KERN_DS); - write_gs(GDT_PERCPU << 3); + write_gs(__KERN_PERCPU); wrmsr(MSR_KERNEL_GS_BASE, 0x0); init_tss(percpu); diff --git a/include/arch/x86/segment.h b/include/arch/x86/segment.h index 8a5a4a88..454205b0 100644 --- a/include/arch/x86/segment.h +++ b/include/arch/x86/segment.h @@ -136,6 +136,8 @@ #define __USER_DS __USER_DS64 #endif +#define __KERN_PERCPU (GDT_PERCPU << 3) + #define _GDT_ENTRY(flags, base, limit) \ ((((base) &_U64(0xff000000)) << (56 - 24)) | (((flags) &_U64(0x0000f0ff)) << 40) | \ (((limit) &_U64(0x000f0000)) << (48 - 16)) | (((base) &_U64(0x00ffffff)) << 16) | \