git: c7e5802ab6e6 - main - amd64: do not restore fsbase/gsbase for 32bit processes

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 21 Jun 2026 12:17:41 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=c7e5802ab6e6230a5782a09c914585d055eb5223

commit c7e5802ab6e6230a5782a09c914585d055eb5223
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-06-16 21:44:00 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-06-21 12:17:11 +0000

    amd64: do not restore fsbase/gsbase for 32bit processes
    
    There is no WRFSBASE and WRGSBASE 32bit variants at all. As such, the
    fsbase and gsbase must always be equal to the bases in the corresponding
    segment descriptor, same as on real i386.
    
    If a 32bit program reloads either %fs or %gs using setcontext(9) or
    sigreturn(9), restoring bases from the syscall entry time is wrong.
    In all other cases, hardware already does the right action when the
    segment register is loaded, and the bases for the ufssel/ugssel in GDT
    are updated on the context switch.
    
    Reviewed by:    markj (previous version)
    Tested by:      terehovv@mail.ru
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D57611
---
 sys/amd64/amd64/exception.S | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S
index 5ff75fb65740..4d58e07caf4b 100644
--- a/sys/amd64/amd64/exception.S
+++ b/sys/amd64/amd64/exception.S
@@ -1161,12 +1161,15 @@ do_segs:
 	.globl	ld_fs
 ld_fs:
 	movw	%ax,%fs
+	testl	$PCB_32BIT,PCB_FLAGS(%r8)
+	jnz	after_ld_fsbase
 	movl	$MSR_FSBASE,%ecx
 	movl	PCB_FSBASE(%r8),%eax
 	movl	PCB_FSBASE+4(%r8),%edx
 	.globl	ld_fsbase
 ld_fsbase:
 	wrmsr
+after_ld_fsbase:
 	/* Restore %gs and gsbase */
 	movw	TF_GS(%rsp),%si
 	pushfq
@@ -1179,6 +1182,8 @@ ld_fsbase:
 	.globl	ld_gs
 ld_gs:
 	movw	%si,%gs
+	testl	$PCB_32BIT,PCB_FLAGS(%r8)
+	jnz	ld_gsbase_32
 	/* Restore kernel %gs base */
 	movl	%r12d,%eax
 	movl	%r13d,%edx
@@ -1194,6 +1199,8 @@ ld_gs:
 	.globl	ld_gsbase
 ld_gsbase:
 	wrmsr	/* May trap if non-canonical, but only for TLS. */
+
+after_ld_gsbase:
 	.globl	ld_es
 ld_es:
 	movw	TF_ES(%rsp),%es
@@ -1241,6 +1248,30 @@ ld_regs:
 doreti_iret:
 	iretq
 
+	/*
+	 * 32bit gsbase path.
+	 * The KGSBASE is not loaded from the pcb_gsbase, instead we move
+	 * the GSBASE value into KGSBASE right after loading user %gs, then
+	 * restore kernel gsbase.
+	 */
+ld_gsbase_32:
+	/* Read the user gsbase into %r14d:%r15d. */
+	movl	$MSR_GSBASE,%ecx
+	rdmsr
+	movl	%eax,%r14d
+	movl	%edx,%r15d
+	/* Restore kernel %gs base */
+	movl	%r12d,%eax
+	movl	%r13d,%edx
+	wrmsr
+	popfq
+	/* Load the user gsbase into KGSBASE. */
+	movl	$MSR_KGSBASE,%ecx
+	movl	%r14d,%eax
+	movl	%r15d,%edx
+	wrmsr
+	jmp	after_ld_gsbase
+
 set_segs:
 	movw	$KUDSEL,%ax
 	movw	%ax,TF_DS(%rsp)