18c2ecf20Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ciUsing FS and GS segments in user space applications 48c2ecf20Sopenharmony_ci=================================================== 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ciThe x86 architecture supports segmentation. Instructions which access 78c2ecf20Sopenharmony_cimemory can use segment register based addressing mode. The following 88c2ecf20Sopenharmony_cinotation is used to address a byte within a segment: 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci Segment-register:Byte-address 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ciThe segment base address is added to the Byte-address to compute the 138c2ecf20Sopenharmony_ciresulting virtual address which is accessed. This allows to access multiple 148c2ecf20Sopenharmony_ciinstances of data with the identical Byte-address, i.e. the same code. The 158c2ecf20Sopenharmony_ciselection of a particular instance is purely based on the base-address in 168c2ecf20Sopenharmony_cithe segment register. 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciIn 32-bit mode the CPU provides 6 segments, which also support segment 198c2ecf20Sopenharmony_cilimits. The limits can be used to enforce address space protections. 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ciIn 64-bit mode the CS/SS/DS/ES segments are ignored and the base address is 228c2ecf20Sopenharmony_cialways 0 to provide a full 64bit address space. The FS and GS segments are 238c2ecf20Sopenharmony_cistill functional in 64-bit mode. 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciCommon FS and GS usage 268c2ecf20Sopenharmony_ci------------------------------ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciThe FS segment is commonly used to address Thread Local Storage (TLS). FS 298c2ecf20Sopenharmony_ciis usually managed by runtime code or a threading library. Variables 308c2ecf20Sopenharmony_cideclared with the '__thread' storage class specifier are instantiated per 318c2ecf20Sopenharmony_cithread and the compiler emits the FS: address prefix for accesses to these 328c2ecf20Sopenharmony_civariables. Each thread has its own FS base address so common code can be 338c2ecf20Sopenharmony_ciused without complex address offset calculations to access the per thread 348c2ecf20Sopenharmony_ciinstances. Applications should not use FS for other purposes when they use 358c2ecf20Sopenharmony_ciruntimes or threading libraries which manage the per thread FS. 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ciThe GS segment has no common use and can be used freely by 388c2ecf20Sopenharmony_ciapplications. GCC and Clang support GS based addressing via address space 398c2ecf20Sopenharmony_ciidentifiers. 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciReading and writing the FS/GS base address 428c2ecf20Sopenharmony_ci------------------------------------------ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciThere exist two mechanisms to read and write the FS/GS base address: 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci - the arch_prctl() system call 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci - the FSGSBASE instruction family 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciAccessing FS/GS base with arch_prctl() 518c2ecf20Sopenharmony_ci-------------------------------------- 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci The arch_prctl(2) based mechanism is available on all 64-bit CPUs and all 548c2ecf20Sopenharmony_ci kernel versions. 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci Reading the base: 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci arch_prctl(ARCH_GET_FS, &fsbase); 598c2ecf20Sopenharmony_ci arch_prctl(ARCH_GET_GS, &gsbase); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci Writing the base: 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci arch_prctl(ARCH_SET_FS, fsbase); 648c2ecf20Sopenharmony_ci arch_prctl(ARCH_SET_GS, gsbase); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci The ARCH_SET_GS prctl may be disabled depending on kernel configuration 678c2ecf20Sopenharmony_ci and security settings. 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciAccessing FS/GS base with the FSGSBASE instructions 708c2ecf20Sopenharmony_ci--------------------------------------------------- 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci With the Ivy Bridge CPU generation Intel introduced a new set of 738c2ecf20Sopenharmony_ci instructions to access the FS and GS base registers directly from user 748c2ecf20Sopenharmony_ci space. These instructions are also supported on AMD Family 17H CPUs. The 758c2ecf20Sopenharmony_ci following instructions are available: 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci =============== =========================== 788c2ecf20Sopenharmony_ci RDFSBASE %reg Read the FS base register 798c2ecf20Sopenharmony_ci RDGSBASE %reg Read the GS base register 808c2ecf20Sopenharmony_ci WRFSBASE %reg Write the FS base register 818c2ecf20Sopenharmony_ci WRGSBASE %reg Write the GS base register 828c2ecf20Sopenharmony_ci =============== =========================== 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci The instructions avoid the overhead of the arch_prctl() syscall and allow 858c2ecf20Sopenharmony_ci more flexible usage of the FS/GS addressing modes in user space 868c2ecf20Sopenharmony_ci applications. This does not prevent conflicts between threading libraries 878c2ecf20Sopenharmony_ci and runtimes which utilize FS and applications which want to use it for 888c2ecf20Sopenharmony_ci their own purpose. 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ciFSGSBASE instructions enablement 918c2ecf20Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 928c2ecf20Sopenharmony_ci The instructions are enumerated in CPUID leaf 7, bit 0 of EBX. If 938c2ecf20Sopenharmony_ci available /proc/cpuinfo shows 'fsgsbase' in the flag entry of the CPUs. 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci The availability of the instructions does not enable them 968c2ecf20Sopenharmony_ci automatically. The kernel has to enable them explicitly in CR4. The 978c2ecf20Sopenharmony_ci reason for this is that older kernels make assumptions about the values in 988c2ecf20Sopenharmony_ci the GS register and enforce them when GS base is set via 998c2ecf20Sopenharmony_ci arch_prctl(). Allowing user space to write arbitrary values to GS base 1008c2ecf20Sopenharmony_ci would violate these assumptions and cause malfunction. 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci On kernels which do not enable FSGSBASE the execution of the FSGSBASE 1038c2ecf20Sopenharmony_ci instructions will fault with a #UD exception. 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci The kernel provides reliable information about the enabled state in the 1068c2ecf20Sopenharmony_ci ELF AUX vector. If the HWCAP2_FSGSBASE bit is set in the AUX vector, the 1078c2ecf20Sopenharmony_ci kernel has FSGSBASE instructions enabled and applications can use them. 1088c2ecf20Sopenharmony_ci The following code example shows how this detection works:: 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci #include <sys/auxv.h> 1118c2ecf20Sopenharmony_ci #include <elf.h> 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci /* Will be eventually in asm/hwcap.h */ 1148c2ecf20Sopenharmony_ci #ifndef HWCAP2_FSGSBASE 1158c2ecf20Sopenharmony_ci #define HWCAP2_FSGSBASE (1 << 1) 1168c2ecf20Sopenharmony_ci #endif 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci .... 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci unsigned val = getauxval(AT_HWCAP2); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (val & HWCAP2_FSGSBASE) 1238c2ecf20Sopenharmony_ci printf("FSGSBASE enabled\n"); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciFSGSBASE instructions compiler support 1268c2ecf20Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ciGCC version 4.6.4 and newer provide instrinsics for the FSGSBASE 1298c2ecf20Sopenharmony_ciinstructions. Clang 5 supports them as well. 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci =================== =========================== 1328c2ecf20Sopenharmony_ci _readfsbase_u64() Read the FS base register 1338c2ecf20Sopenharmony_ci _readfsbase_u64() Read the GS base register 1348c2ecf20Sopenharmony_ci _writefsbase_u64() Write the FS base register 1358c2ecf20Sopenharmony_ci _writegsbase_u64() Write the GS base register 1368c2ecf20Sopenharmony_ci =================== =========================== 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ciTo utilize these instrinsics <immintrin.h> must be included in the source 1398c2ecf20Sopenharmony_cicode and the compiler option -mfsgsbase has to be added. 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ciCompiler support for FS/GS based addressing 1428c2ecf20Sopenharmony_ci------------------------------------------- 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciGCC version 6 and newer provide support for FS/GS based addressing via 1458c2ecf20Sopenharmony_ciNamed Address Spaces. GCC implements the following address space 1468c2ecf20Sopenharmony_ciidentifiers for x86: 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci ========= ==================================== 1498c2ecf20Sopenharmony_ci __seg_fs Variable is addressed relative to FS 1508c2ecf20Sopenharmony_ci __seg_gs Variable is addressed relative to GS 1518c2ecf20Sopenharmony_ci ========= ==================================== 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciThe preprocessor symbols __SEG_FS and __SEG_GS are defined when these 1548c2ecf20Sopenharmony_ciaddress spaces are supported. Code which implements fallback modes should 1558c2ecf20Sopenharmony_cicheck whether these symbols are defined. Usage example:: 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci #ifdef __SEG_GS 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci long data0 = 0; 1608c2ecf20Sopenharmony_ci long data1 = 1; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci long __seg_gs *ptr; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* Check whether FSGSBASE is enabled by the kernel (HWCAP2_FSGSBASE) */ 1658c2ecf20Sopenharmony_ci .... 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* Set GS base to point to data0 */ 1688c2ecf20Sopenharmony_ci _writegsbase_u64(&data0); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Access offset 0 of GS */ 1718c2ecf20Sopenharmony_ci ptr = 0; 1728c2ecf20Sopenharmony_ci printf("data0 = %ld\n", *ptr); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* Set GS base to point to data1 */ 1758c2ecf20Sopenharmony_ci _writegsbase_u64(&data1); 1768c2ecf20Sopenharmony_ci /* ptr still addresses offset 0! */ 1778c2ecf20Sopenharmony_ci printf("data1 = %ld\n", *ptr); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ciClang does not provide the GCC address space identifiers, but it provides 1818c2ecf20Sopenharmony_ciaddress spaces via an attribute based mechanism in Clang 2.6 and newer 1828c2ecf20Sopenharmony_civersions: 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci ==================================== ===================================== 1858c2ecf20Sopenharmony_ci __attribute__((address_space(256)) Variable is addressed relative to GS 1868c2ecf20Sopenharmony_ci __attribute__((address_space(257)) Variable is addressed relative to FS 1878c2ecf20Sopenharmony_ci ==================================== ===================================== 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ciFS/GS based addressing with inline assembly 1908c2ecf20Sopenharmony_ci------------------------------------------- 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ciIn case the compiler does not support address spaces, inline assembly can 1938c2ecf20Sopenharmony_cibe used for FS/GS based addressing mode:: 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci mov %fs:offset, %reg 1968c2ecf20Sopenharmony_ci mov %gs:offset, %reg 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci mov %reg, %fs:offset 1998c2ecf20Sopenharmony_ci mov %reg, %gs:offset 200