162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ciUsing FS and GS segments in user space applications 462306a36Sopenharmony_ci=================================================== 562306a36Sopenharmony_ci 662306a36Sopenharmony_ciThe x86 architecture supports segmentation. Instructions which access 762306a36Sopenharmony_cimemory can use segment register based addressing mode. The following 862306a36Sopenharmony_cinotation is used to address a byte within a segment: 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci Segment-register:Byte-address 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ciThe segment base address is added to the Byte-address to compute the 1362306a36Sopenharmony_ciresulting virtual address which is accessed. This allows to access multiple 1462306a36Sopenharmony_ciinstances of data with the identical Byte-address, i.e. the same code. The 1562306a36Sopenharmony_ciselection of a particular instance is purely based on the base-address in 1662306a36Sopenharmony_cithe segment register. 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciIn 32-bit mode the CPU provides 6 segments, which also support segment 1962306a36Sopenharmony_cilimits. The limits can be used to enforce address space protections. 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciIn 64-bit mode the CS/SS/DS/ES segments are ignored and the base address is 2262306a36Sopenharmony_cialways 0 to provide a full 64bit address space. The FS and GS segments are 2362306a36Sopenharmony_cistill functional in 64-bit mode. 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciCommon FS and GS usage 2662306a36Sopenharmony_ci------------------------------ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ciThe FS segment is commonly used to address Thread Local Storage (TLS). FS 2962306a36Sopenharmony_ciis usually managed by runtime code or a threading library. Variables 3062306a36Sopenharmony_cideclared with the '__thread' storage class specifier are instantiated per 3162306a36Sopenharmony_cithread and the compiler emits the FS: address prefix for accesses to these 3262306a36Sopenharmony_civariables. Each thread has its own FS base address so common code can be 3362306a36Sopenharmony_ciused without complex address offset calculations to access the per thread 3462306a36Sopenharmony_ciinstances. Applications should not use FS for other purposes when they use 3562306a36Sopenharmony_ciruntimes or threading libraries which manage the per thread FS. 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciThe GS segment has no common use and can be used freely by 3862306a36Sopenharmony_ciapplications. GCC and Clang support GS based addressing via address space 3962306a36Sopenharmony_ciidentifiers. 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciReading and writing the FS/GS base address 4262306a36Sopenharmony_ci------------------------------------------ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciThere exist two mechanisms to read and write the FS/GS base address: 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci - the arch_prctl() system call 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci - the FSGSBASE instruction family 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciAccessing FS/GS base with arch_prctl() 5162306a36Sopenharmony_ci-------------------------------------- 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci The arch_prctl(2) based mechanism is available on all 64-bit CPUs and all 5462306a36Sopenharmony_ci kernel versions. 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci Reading the base: 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci arch_prctl(ARCH_GET_FS, &fsbase); 5962306a36Sopenharmony_ci arch_prctl(ARCH_GET_GS, &gsbase); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci Writing the base: 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci arch_prctl(ARCH_SET_FS, fsbase); 6462306a36Sopenharmony_ci arch_prctl(ARCH_SET_GS, gsbase); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci The ARCH_SET_GS prctl may be disabled depending on kernel configuration 6762306a36Sopenharmony_ci and security settings. 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciAccessing FS/GS base with the FSGSBASE instructions 7062306a36Sopenharmony_ci--------------------------------------------------- 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci With the Ivy Bridge CPU generation Intel introduced a new set of 7362306a36Sopenharmony_ci instructions to access the FS and GS base registers directly from user 7462306a36Sopenharmony_ci space. These instructions are also supported on AMD Family 17H CPUs. The 7562306a36Sopenharmony_ci following instructions are available: 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci =============== =========================== 7862306a36Sopenharmony_ci RDFSBASE %reg Read the FS base register 7962306a36Sopenharmony_ci RDGSBASE %reg Read the GS base register 8062306a36Sopenharmony_ci WRFSBASE %reg Write the FS base register 8162306a36Sopenharmony_ci WRGSBASE %reg Write the GS base register 8262306a36Sopenharmony_ci =============== =========================== 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci The instructions avoid the overhead of the arch_prctl() syscall and allow 8562306a36Sopenharmony_ci more flexible usage of the FS/GS addressing modes in user space 8662306a36Sopenharmony_ci applications. This does not prevent conflicts between threading libraries 8762306a36Sopenharmony_ci and runtimes which utilize FS and applications which want to use it for 8862306a36Sopenharmony_ci their own purpose. 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ciFSGSBASE instructions enablement 9162306a36Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 9262306a36Sopenharmony_ci The instructions are enumerated in CPUID leaf 7, bit 0 of EBX. If 9362306a36Sopenharmony_ci available /proc/cpuinfo shows 'fsgsbase' in the flag entry of the CPUs. 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci The availability of the instructions does not enable them 9662306a36Sopenharmony_ci automatically. The kernel has to enable them explicitly in CR4. The 9762306a36Sopenharmony_ci reason for this is that older kernels make assumptions about the values in 9862306a36Sopenharmony_ci the GS register and enforce them when GS base is set via 9962306a36Sopenharmony_ci arch_prctl(). Allowing user space to write arbitrary values to GS base 10062306a36Sopenharmony_ci would violate these assumptions and cause malfunction. 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci On kernels which do not enable FSGSBASE the execution of the FSGSBASE 10362306a36Sopenharmony_ci instructions will fault with a #UD exception. 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci The kernel provides reliable information about the enabled state in the 10662306a36Sopenharmony_ci ELF AUX vector. If the HWCAP2_FSGSBASE bit is set in the AUX vector, the 10762306a36Sopenharmony_ci kernel has FSGSBASE instructions enabled and applications can use them. 10862306a36Sopenharmony_ci The following code example shows how this detection works:: 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci #include <sys/auxv.h> 11162306a36Sopenharmony_ci #include <elf.h> 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* Will be eventually in asm/hwcap.h */ 11462306a36Sopenharmony_ci #ifndef HWCAP2_FSGSBASE 11562306a36Sopenharmony_ci #define HWCAP2_FSGSBASE (1 << 1) 11662306a36Sopenharmony_ci #endif 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci .... 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci unsigned val = getauxval(AT_HWCAP2); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (val & HWCAP2_FSGSBASE) 12362306a36Sopenharmony_ci printf("FSGSBASE enabled\n"); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciFSGSBASE instructions compiler support 12662306a36Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciGCC version 4.6.4 and newer provide instrinsics for the FSGSBASE 12962306a36Sopenharmony_ciinstructions. Clang 5 supports them as well. 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci =================== =========================== 13262306a36Sopenharmony_ci _readfsbase_u64() Read the FS base register 13362306a36Sopenharmony_ci _readfsbase_u64() Read the GS base register 13462306a36Sopenharmony_ci _writefsbase_u64() Write the FS base register 13562306a36Sopenharmony_ci _writegsbase_u64() Write the GS base register 13662306a36Sopenharmony_ci =================== =========================== 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciTo utilize these instrinsics <immintrin.h> must be included in the source 13962306a36Sopenharmony_cicode and the compiler option -mfsgsbase has to be added. 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciCompiler support for FS/GS based addressing 14262306a36Sopenharmony_ci------------------------------------------- 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ciGCC version 6 and newer provide support for FS/GS based addressing via 14562306a36Sopenharmony_ciNamed Address Spaces. GCC implements the following address space 14662306a36Sopenharmony_ciidentifiers for x86: 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci ========= ==================================== 14962306a36Sopenharmony_ci __seg_fs Variable is addressed relative to FS 15062306a36Sopenharmony_ci __seg_gs Variable is addressed relative to GS 15162306a36Sopenharmony_ci ========= ==================================== 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciThe preprocessor symbols __SEG_FS and __SEG_GS are defined when these 15462306a36Sopenharmony_ciaddress spaces are supported. Code which implements fallback modes should 15562306a36Sopenharmony_cicheck whether these symbols are defined. Usage example:: 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci #ifdef __SEG_GS 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci long data0 = 0; 16062306a36Sopenharmony_ci long data1 = 1; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci long __seg_gs *ptr; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Check whether FSGSBASE is enabled by the kernel (HWCAP2_FSGSBASE) */ 16562306a36Sopenharmony_ci .... 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* Set GS base to point to data0 */ 16862306a36Sopenharmony_ci _writegsbase_u64(&data0); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Access offset 0 of GS */ 17162306a36Sopenharmony_ci ptr = 0; 17262306a36Sopenharmony_ci printf("data0 = %ld\n", *ptr); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* Set GS base to point to data1 */ 17562306a36Sopenharmony_ci _writegsbase_u64(&data1); 17662306a36Sopenharmony_ci /* ptr still addresses offset 0! */ 17762306a36Sopenharmony_ci printf("data1 = %ld\n", *ptr); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ciClang does not provide the GCC address space identifiers, but it provides 18162306a36Sopenharmony_ciaddress spaces via an attribute based mechanism in Clang 2.6 and newer 18262306a36Sopenharmony_civersions: 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci ==================================== ===================================== 18562306a36Sopenharmony_ci __attribute__((address_space(256)) Variable is addressed relative to GS 18662306a36Sopenharmony_ci __attribute__((address_space(257)) Variable is addressed relative to FS 18762306a36Sopenharmony_ci ==================================== ===================================== 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ciFS/GS based addressing with inline assembly 19062306a36Sopenharmony_ci------------------------------------------- 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciIn case the compiler does not support address spaces, inline assembly can 19362306a36Sopenharmony_cibe used for FS/GS based addressing mode:: 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci mov %fs:offset, %reg 19662306a36Sopenharmony_ci mov %gs:offset, %reg 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci mov %reg, %fs:offset 19962306a36Sopenharmony_ci mov %reg, %gs:offset 200