From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.alien8.de (mail.alien8.de [65.109.113.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A6A6C40D56D for ; Thu, 18 Jun 2026 01:09:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=65.109.113.108 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781744964; cv=none; b=PxiGlmuFsI/DRQxdGlocE7tSfQyJgAblz+iuUmH/OmQj+cHhjoYXttzcmQCceL6Qdh5ANdIRHGqBhlHIqyXbbwn+7dZRYoMR5tzQ7lAcrGsALRb/jLnYTSwIYtlKpgwtKtXyVuqBaT2p4JnRUl3y9rUbZhyWtMnwGpxVS5jwjgU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781744964; c=relaxed/simple; bh=KjOG3s7DrVcp7NAH65ovDPzy7StuUtn5YoYLlt4uF8w=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=DLENIrch79uX4DisGmc+5YhvSMWmotr3jVeTWJLV9B4al78AGvpAMaS12jOauMgQxOnwTQyYON/7smbra/r6afuCt5DqfBOH4O27qjEjplCje7D/DY812bN8Pc8qKg6DYf/CTbmPLwE96kttXy5Uv3hjmraTdisZITfoWPrWgFQ= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=alien8.de; spf=pass smtp.mailfrom=alien8.de; dkim=fail (4096-bit key) header.d=alien8.de header.i=@alien8.de header.b=hm3SeJkL reason="signature verification failed"; arc=none smtp.client-ip=65.109.113.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=alien8.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=alien8.de Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="signature verification failed" (4096-bit key) header.d=alien8.de header.i=@alien8.de header.b="hm3SeJkL" Received: from localhost (localhost.localdomain [127.0.0.1]) by mail.alien8.de (SuperMail on ZX Spectrum 128k) with ESMTP id C3EBD40E01C9; Thu, 18 Jun 2026 01:09:20 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at mail.alien8.de Authentication-Results: mail.alien8.de (amavisd-new); dkim=fail (4096-bit key) reason="fail (body has been altered)" header.d=alien8.de Received: from mail.alien8.de ([127.0.0.1]) by localhost (mail.alien8.de [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id mSG3y1q7eEKH; Thu, 18 Jun 2026 01:09:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alien8.de; s=alien8; t=1781744949; bh=6mbG+Ksf8lyOjSxNERPVnIqJESkeN5md75JRNqRF1co=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=hm3SeJkLf21Hi/2tRT9/bU4UWrOQYu7vCY/ykxs6T0EHjjexdxldgRw3qWs7d/lpC lbVSzyu3/9/2BHVX+IGM47m8jAIyW8CbctGlj9AM2k9lrx52ite6mkXPZtT442nTl0 THoHGS2KTBMC5Y+EyqdGuS1XpFSlF/ncFHrKOubOmIKA6juxrTfv+9d1xYVCrGbWS1 FTS49XPzEZVpOOFFKMKtSEpNvmTKiGJCB97eqRcpAz4H5ZJZa8CUNNNp6lFJL9aPuI UyUkjZPYTANfqw3GKXppg9zYTf1eYvZTml9YDUJAIRtNBk0l2nJiO2EYBx2oPpwbOZ 6OyHBzPmegtNvrT9vn7Juhi+fxQN972ZFrTp1MKhipA6zJ7uCUokvH+3rQbJ8wFI67 plO26qzW6Kllmn5bdzr/oOe8Y/aVxAW8jn3qU6UpnK6pq25R2QpTb3SVKgl2PFchAv rVdpJPODRl8NvczeTT6a7yQ22OHCAbTBjsRQ1wQ9blJefE6jvi1EnRayb6yTL8o4Cc bkgWTWmeTl8LubLQLBmSE16nUAf/SaBJXETtiQvJD4+kJSthwxHuhN+Z5zQMHR8Vm+ E9gt2q97UxkwIyeYrk0nG5/LihbFxhCu0MNo7avUN3EzQGuMcYwln6EiWvicKCxqIY niq+Sxg+S9A0GQt8FNpjf3wk= Received: from stx.tnic (unknown [IPv6:2600:1700:38ca:c00::3a]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature ECDSA (P-256) server-digest SHA256) (No client certificate requested) by mail.alien8.de (SuperMail on ZX Spectrum 128k) with ESMTPSA id 62AA740E015B; Thu, 18 Jun 2026 01:09:05 +0000 (UTC) Date: Wed, 17 Jun 2026 18:09:02 -0700 From: Borislav Petkov To: Andrew Cooper , "H. Peter Anvin" Cc: x86-ML , LKML Subject: Re: Save a WRMSR GS.base? Message-ID: <20260618010902.GAajNFLjwKOM-Cdj5l@fat_crate.local> References: <1E2599FB-0A39-4637-B042-EE36DA224264@zytor.com> <2f297456-d6c6-4cc8-95d8-2dac6bea99ec@citrix.com> <20260605171711.GAaiMEl_CahU4oHpMk@fat_crate.local> <079850DB-52FE-4545-825F-E01E918B085D@zytor.com> <20260608143835.GAaibT6_Ypd2OzVkWD@fat_crate.local> <87cfce38-4b5a-4014-a098-2c43e3067df1@zytor.com> <20260608200528.GDaicgiFydU8LVUGL2@fat_crate.local> <20260608212100.GEaicyPO65ii0InnFa@fat_crate.local> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: Content-Transfer-Encoding: quoted-printable Ok, I think I incorporated them all: --- From: "Borislav Petkov (AMD)" Date: Mon, 8 Jun 2026 18:59:14 -0700 Subject: [PATCH] Documentation/x86: Document the intricacies of GS contex= t switching Summarized from the thread at Link by AI, with additions and improvements by H. Peter Anvin and Andrew Cooper. Signed-off-by: Borislav Petkov (AMD) Assisted-by: Claude Code:claude-sonnet-4-6 Link: https://lore.kernel.org/all/20260604015303.GEaiDafyuU0bwP4Y05@fat_c= rate.local --- Documentation/arch/x86/x86_64/fsgs.rst | 97 ++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/Documentation/arch/x86/x86_64/fsgs.rst b/Documentation/arch/= x86/x86_64/fsgs.rst index 6bda4d16d3f7..fa3d4b065423 100644 --- a/Documentation/arch/x86/x86_64/fsgs.rst +++ b/Documentation/arch/x86/x86_64/fsgs.rst @@ -197,3 +197,100 @@ be used for FS/GS based addressing mode:: =20 mov %reg, %fs:offset mov %reg, %gs:offset + + +Complexities with GS handling on context switches +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +History +------- + +In 32-bit, data segments need reloading on entry to the kernel, and rest= oring +on exit to userspace.=C2=A0 Only the segment selector is necessary, as a= ll segment +data resides in the GDT/LDT.=C2=A0 Bases in the GDT/LDT are 32 bits wide= .=C2=A0 The +segment selector values are user-chosen, and effectively arbitrary. + +The 32-bit mechanism is slow, so in 64-bit, segments were made mostly fl= at so +as to not need reloading on entry/exit.=C2=A0=C2=A0FS and GS segment bas= es were extended +to 64 bits, and became accessible via MSRs. Also, a separate GS_SHADOW v= alue +was introduced.=C2=A0 The SWAPGS instruction swaps GS_BASE and GS_SHADOW= , as the +only action needed on entry/exit. + +64-bit userspace needed to make the prctl() ARCH_SET_GS have a base valu= e +greater than 32 bits, and a side effect of this syscall was to zero the = GS +selector. + +Then the FSGSBASE instructions came along, and userspace could finally c= hoose +an arbitrary base address not previously registered via the syscall.=C2=A0= Linux's +ABI promises to preserve both the selector value and the full base, even= when +they are disconnected. + +When looking at the hardware capabilities, there are multiple x86 instru= ctions +which modify GS: + +* SWAPGS + +Swaps the value in MSR_KERNEL_GS_BASE with the active GS.base in the hid= den +portion of the GS selector register. + +* MOV , GS + +(legacy path, non-FRED) Loads GS with the selector specified in and fetches the GS descriptor attributes, limit and base from = the +GDT/LDT. Writes a 32-bit base into the active GS.base, zero-extending i= t into +the 64-bit base register. It does not touch MSR_KERNEL_GS_BASE. + +The problem with this is that because it writes the *current* GS.base, i= t +corrupts the active kernel per-CPU pointer (in %gs). + +* LKGS + +(FRED path, replaces MOV GS) Like MOV GS in that it loads the selector a= nd +descriptor attributes, but it redirects the base write =E2=80=94 instead= of updating +the active GS.base, it writes the descriptor base into IA32_KERNEL_GS_BA= SE +(i.e. MSR_KERNEL_GS_BASE). + +Critical caveat: it only writes a zero-extended 32-bit value, because GD= T/LDT +descriptors only encode 32-bit bases. This means it cannot correctly rep= resent +a full 64-bit user-space GS base (e.g. a TLS pointer), so a full 64-bit = WRMSR +is still required afterwards. + +This instruction ensures that the kernel's per-CPU pointer stays good, a= nd +does not need custom error handling. + +MOV GS and LKGS are the only way to update the other fields of the GS +descriptor. + +* WRGSBASE + +In 64-bit mode, it writes a full 64-bit value directly into the currentl= y +active GS.base as FS.base and GS.base in 64-bit mode are expanded to 64-= bit to +cover the full address space. + +The problem in kernel context: the currently active GS.base belongs to t= he +kernel, not the user task. So using this during context switching would +corrupt the kernel's own GS.base, unless surrounded by SWAPGS (only safe= in +IDT mode). + +In the remaining modes, the upper 32 bits of the base are cleared instea= d. + +* WRMSR MSR_KERNEL_GS_BASE / WRMSRNS MSR_KERNEL_GS_BASE + +Writes a full 64-bit value into MSR_KERNEL_GS_BASE, which holds the inac= tive +(user-space) GS.base =E2=80=94 the one that gets swapped into the active= GS.base on +SWAPGS. This is the only instruction that can correctly set a 64-bit use= r +GS.base during a context switch from kernel mode. + +The non-serializing nature of the write was accomplished by the two vend= ors +differently. AMD, starting with Zen4, made it the default through: + + CPUID_Fn80000021_EAX [Extended Feature 2 EAX] + (Core::X86::Cpuid::FeatureExt2Eax)[1], FsGsKernelGsBaseNonSerializing = which is + fixed to 1 + +and Intel through the WRMSRNS instruction which is the non-serializing +variant. + +Btw, while running in kernel mode, MSR_KERNEL_GS_BASE contains actually = the +*user* GS.base. Thus, the naming can be confusing. Unless one thinks of = it as +the kernel's access to GS.base as MSRs are accessible only in CPL0. --=20 2.53.0 --=20 Regards/Gruss, Boris. https://people.kernel.org/tglx/notes-about-netiquette