From 99c808796a066e7c812944b4a61ac839ccc33170 Mon Sep 17 00:00:00 2001 From: guenther Date: Sat, 6 Jan 2018 22:03:12 +0000 Subject: [PATCH] Handle %gs like %[def]s and reset set it in cpu_switchto() instead of on every return to userspace. ok kettenis@ mlarkin@ --- sys/arch/amd64/amd64/locore.S | 8 ++++++-- sys/arch/amd64/amd64/machdep.c | 20 +++++++++++--------- sys/arch/amd64/include/frameasm.h | 8 +++----- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/sys/arch/amd64/amd64/locore.S b/sys/arch/amd64/amd64/locore.S index 5a2450b1164..2b85fc65dab 100644 --- a/sys/arch/amd64/amd64/locore.S +++ b/sys/arch/amd64/amd64/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.91 2017/10/10 07:04:05 mlarkin Exp $ */ +/* $OpenBSD: locore.S,v 1.92 2018/01/06 22:03:12 guenther Exp $ */ /* $NetBSD: locore.S,v 1.13 2004/03/25 18:33:17 drochner Exp $ */ /* @@ -369,11 +369,15 @@ switch_exited: btrl $CPUF_USERSEGS_BIT, CPUVAR(FLAGS) jnc restore_saved - /* set %ds, %es, and %fs to expected value to prevent info leak */ + /* set %ds, %es, %fs, and %gs to expected value to prevent info leak */ movw $(GSEL(GUDATA_SEL, SEL_UPL)),%ax movw %ax,%ds movw %ax,%es movw %ax,%fs + cli /* block interrupts when on user GS.base */ + swapgs /* switch from kernel to user GS.base */ + movw %ax,%gs /* set %gs to UDATA and GS.base to 0 */ + swapgs /* back to kernel GS.base */ restore_saved: /* diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 33bef001d4f..33d1d38395b 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.236 2017/12/11 05:27:40 deraadt Exp $ */ +/* $OpenBSD: machdep.c,v 1.237 2018/01/06 22:03:12 guenther Exp $ */ /* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ /*- @@ -999,25 +999,27 @@ dumpsys(void) /* * Force the userspace FS.base to be reloaded from the PCB on return from - * the kernel, and reset most the segment registers (%ds, %es, and %fs) + * the kernel, and reset the segment registers (%ds, %es, %fs, and %gs) * to their expected userspace value. */ void reset_segs(void) { /* - * Segment registers (%ds, %es, %fs, %gs) aren't in the trapframe. - * %gs is reset on return to userspace to avoid having to deal with - * swapgs; others are reset on context switch and here. This - * operates like the cpu_switchto() sequence: if we haven't reset - * %[def]s already, do so now. - */ + * This operates like the cpu_switchto() sequence: if we + * haven't reset %[defg]s already, do so now. + */ if (curcpu()->ci_flags & CPUF_USERSEGS) { curcpu()->ci_flags &= ~CPUF_USERSEGS; __asm volatile( "movw %%ax,%%ds\n\t" "movw %%ax,%%es\n\t" - "movw %%ax,%%fs" : : "a"(GSEL(GUDATA_SEL, SEL_UPL))); + "movw %%ax,%%fs\n\t" + "cli\n\t" /* block intr when on user GS.base */ + "swapgs\n\t" /* swap from kernel to user GS.base */ + "movw %%ax,%%gs\n\t"/* set %gs to UDATA and GS.base to 0 */ + "swapgs\n\t" /* back to kernel GS.base */ + "sti" : : "a"(GSEL(GUDATA_SEL, SEL_UPL))); } } diff --git a/sys/arch/amd64/include/frameasm.h b/sys/arch/amd64/include/frameasm.h index b48d11f4e2d..88309d1dd4f 100644 --- a/sys/arch/amd64/include/frameasm.h +++ b/sys/arch/amd64/include/frameasm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: frameasm.h,v 1.10 2016/09/04 09:22:28 mpi Exp $ */ +/* $OpenBSD: frameasm.h,v 1.11 2018/01/06 22:03:12 guenther Exp $ */ /* $NetBSD: frameasm.h,v 1.1 2003/04/26 18:39:40 fvdl Exp $ */ #ifndef _AMD64_MACHINE_FRAMEASM_H @@ -65,10 +65,8 @@ shrq $32,%rdx ; \ movl $MSR_FSBASE,%ecx ; \ wrmsr ; \ -99: movw $(GSEL(GUDATA_SEL, SEL_UPL)),%ax ; \ - cli ; \ - swapgs ; \ - movw %ax,%gs +99: cli ; \ + swapgs #define INTR_FAKE_TRAP 0xbadabada -- 2.20.1