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