xref: /netbsd-src/sys/arch/x86/include/cpu_extended_state.h (revision a89583ca1cb8249fd826deb81e58a5ee5b3866f5)
1*a89583caSriastradh /*	$NetBSD: cpu_extended_state.h,v 1.18 2023/02/25 13:57:37 riastradh Exp $	*/
227a8f3e1Sdsl 
327a8f3e1Sdsl #ifndef _X86_CPU_EXTENDED_STATE_H_
427a8f3e1Sdsl #define _X86_CPU_EXTENDED_STATE_H_
527a8f3e1Sdsl 
627a8f3e1Sdsl #ifdef __lint__
727a8f3e1Sdsl /* Lint has different packing rules and doesn't understand __aligned() */
827a8f3e1Sdsl #define __CTASSERT_NOLINT(x) __CTASSERT(1)
927a8f3e1Sdsl #else
1027a8f3e1Sdsl #define __CTASSERT_NOLINT(x) __CTASSERT(x)
1127a8f3e1Sdsl #endif
1227a8f3e1Sdsl 
1327a8f3e1Sdsl /*
1434c4cf73Smaxv  * This file contains definitions of structures that match the memory layouts
1534c4cf73Smaxv  * used on x86 processors to save floating point registers and other extended
1634c4cf73Smaxv  * cpu states.
1734c4cf73Smaxv  *
1834c4cf73Smaxv  * This includes registers (etc) used by SSE/SSE2/SSE3/SSSE3/SSE4 and the later
1934c4cf73Smaxv  * AVX instructions.
2034c4cf73Smaxv  *
217d804506Smaxv  * The definitions are such that any future 'extended state' should be handled,
227d804506Smaxv  * provided the kernel doesn't need to know the actual contents.
2334c4cf73Smaxv  *
2434c4cf73Smaxv  * The actual structures the cpu accesses must be aligned to 16 bytes for FXSAVE
2534c4cf73Smaxv  * and 64 for XSAVE. The types aren't aligned because copies do not need extra
2634c4cf73Smaxv  * alignment.
2734c4cf73Smaxv  *
2834c4cf73Smaxv  * The slightly different layout saved by the i387 fsave is also defined.
2934c4cf73Smaxv  * This is only normally written by pre Pentium II type cpus that don't
3034c4cf73Smaxv  * support the fxsave instruction.
3134c4cf73Smaxv  *
3234c4cf73Smaxv  * Associated save instructions:
337d804506Smaxv  * FNSAVE:   Saves x87 state in 108 bytes (original i387 layout). Then
347d804506Smaxv  *           reinitializes the fpu.
3534c4cf73Smaxv  * FSAVE:    Encodes to FWAIT followed by FNSAVE.
367d804506Smaxv  * FXSAVE:   Saves the x87 state and XMM (aka SSE) registers to the first
377d804506Smaxv  *           448 (max) bytes of a 512 byte area. This layout does not match
387d804506Smaxv  *           that written by FNSAVE.
397d804506Smaxv  * XSAVE:    Uses the same layout for the x87 and XMM registers, followed by
407d804506Smaxv  *           a 64byte header and separate save areas for additional extended
417d804506Smaxv  *           cpu states. The x87 state is always saved, the others
427d804506Smaxv  *           conditionally.
437d804506Smaxv  * XSAVEOPT: Same as XSAVE but only writes the registers blocks that have
447d804506Smaxv  *           been modified.
4534c4cf73Smaxv  */
4634c4cf73Smaxv 
4734c4cf73Smaxv /*
4834c4cf73Smaxv  * Layout for code/data pointers relating to FP exceptions. Marked 'packed'
4934c4cf73Smaxv  * because they aren't always 64bit aligned. Since the x86 cpu supports
5034c4cf73Smaxv  * misaligned accesses it isn't worth avoiding the 'packed' attribute.
5127a8f3e1Sdsl  */
5227a8f3e1Sdsl union fp_addr {
5327a8f3e1Sdsl 	uint64_t fa_64;	/* Linear address for 64bit systems */
5427a8f3e1Sdsl 	struct {
5527a8f3e1Sdsl 		uint32_t fa_off;	/* linear address for 32 bit */
5627a8f3e1Sdsl 		uint16_t fa_seg;	/* code/data (etc) segment */
5727a8f3e1Sdsl 		uint16_t fa_opcode;	/* last opcode (sometimes) */
5827a8f3e1Sdsl 	} fa_32;
591a42f747Sdsl } __packed __aligned(4);
6027a8f3e1Sdsl 
6127a8f3e1Sdsl /* The x87 registers are 80 bits */
6227a8f3e1Sdsl struct fpacc87 {
6327a8f3e1Sdsl 	uint64_t f87_mantissa;	/* mantissa */
6427a8f3e1Sdsl 	uint16_t f87_exp_sign;	/* exponent and sign */
651a42f747Sdsl } __packed __aligned(2);
6627a8f3e1Sdsl 
6727a8f3e1Sdsl /* The x87 registers padded out to 16 bytes for fxsave */
6827a8f3e1Sdsl struct fpaccfx {
6927a8f3e1Sdsl 	struct fpacc87 r __aligned(16);
7027a8f3e1Sdsl };
7127a8f3e1Sdsl 
7227a8f3e1Sdsl /* The SSE/SSE2 registers are 128 bits */
7327a8f3e1Sdsl struct xmmreg {
7427a8f3e1Sdsl 	uint8_t xmm_bytes[16];
7527a8f3e1Sdsl };
7627a8f3e1Sdsl 
7727a8f3e1Sdsl /* The AVX registers are 256 bits, but the low bits are the xmmregs */
7827a8f3e1Sdsl struct ymmreg {
7927a8f3e1Sdsl 	uint8_t ymm_bytes[16];
8027a8f3e1Sdsl };
8127a8f3e1Sdsl 
82c2ad96ffSmgorny /* The AVX-512 registers are 512 bits but the low bits are in xmmregs
83c2ad96ffSmgorny  * and ymmregs */
84c2ad96ffSmgorny struct zmmreg {
85c2ad96ffSmgorny 	uint8_t zmm_bytes[32];
86c2ad96ffSmgorny };
87c2ad96ffSmgorny 
88c2ad96ffSmgorny /* 512-bit ZMM register. */
89c2ad96ffSmgorny struct hi16_zmmreg {
90c2ad96ffSmgorny 	uint8_t zmm_bytes[64];
91c2ad96ffSmgorny };
92c2ad96ffSmgorny 
9327a8f3e1Sdsl /*
947d804506Smaxv  * Floating point unit registers (FSAVE instruction).
957d804506Smaxv  *
967d804506Smaxv  * The s87_ac[] and fx_87_ac[] are relative to the stack top. The 'tag word'
977d804506Smaxv  * contains 2 bits per register and refers to absolute register numbers.
987d804506Smaxv  *
9927a8f3e1Sdsl  * The cpu sets the tag values 0b01 (zero) and 0b10 (special) when a value
10027a8f3e1Sdsl  * is loaded. The software need only set 0b00 (used) and 0xb11 (unused).
10127a8f3e1Sdsl  * The fxsave 'Abridged tag word' in inverted.
10227a8f3e1Sdsl  */
10327a8f3e1Sdsl struct save87 {
10434c4cf73Smaxv 	uint16_t s87_cw __aligned(4);	/* control word */
10534c4cf73Smaxv 	uint16_t s87_sw __aligned(4);	/* status word  */
10634c4cf73Smaxv 	uint16_t s87_tw __aligned(4);	/* tag word */
10727a8f3e1Sdsl 	union fp_addr s87_ip;		/* floating point instruction pointer */
10827a8f3e1Sdsl #define s87_opcode s87_ip.fa_32.fa_opcode	/* opcode last executed (11bits) */
10927a8f3e1Sdsl 	union fp_addr s87_dp;		/* floating operand offset */
11034c4cf73Smaxv 	struct fpacc87 s87_ac[8];	/* accumulator contents */
11127a8f3e1Sdsl };
11227a8f3e1Sdsl __CTASSERT_NOLINT(sizeof(struct save87) == 108);
11327a8f3e1Sdsl 
11434c4cf73Smaxv /*
1157d804506Smaxv  * FPU/MMX/SSE/SSE2 context (FXSAVE instruction).
11634c4cf73Smaxv  */
11727a8f3e1Sdsl struct fxsave {
11834c4cf73Smaxv 	uint16_t fx_cw;		/* FPU Control Word */
11927a8f3e1Sdsl 	uint16_t fx_sw;		/* FPU Status Word */
12027a8f3e1Sdsl 	uint8_t fx_tw;		/* FPU Tag Word (abridged) */
1215905ff7fSmaxv 	uint8_t fx_zero;	/* zero */
12227a8f3e1Sdsl 	uint16_t fx_opcode;	/* FPU Opcode */
12327a8f3e1Sdsl 	union fp_addr fx_ip;	/* FPU Instruction Pointer */
12434c4cf73Smaxv 	union fp_addr fx_dp;	/* FPU Data pointer */
12527a8f3e1Sdsl 	uint32_t fx_mxcsr;	/* MXCSR Register State */
12627a8f3e1Sdsl 	uint32_t fx_mxcsr_mask;
12727a8f3e1Sdsl 	struct fpaccfx fx_87_ac[8];	/* 8 x87 registers */
12843beae7cSdsl 	struct xmmreg fx_xmm[16];	/* XMM regs (8 in 32bit modes) */
12923966a93Smaxv 	uint8_t fx_rsvd[96];
13027a8f3e1Sdsl } __aligned(16);
13127a8f3e1Sdsl __CTASSERT_NOLINT(sizeof(struct fxsave) == 512);
13227a8f3e1Sdsl 
13334c4cf73Smaxv /*
13434c4cf73Smaxv  * For XSAVE, a 64byte header follows the fxsave data.
13527a8f3e1Sdsl  */
13627a8f3e1Sdsl struct xsave_header {
1377d804506Smaxv 	uint8_t xsh_fxsave[512];	/* struct fxsave */
13827a8f3e1Sdsl 	uint64_t xsh_xstate_bv;		/* bitmap of saved sub structures */
1395905ff7fSmaxv 	uint64_t xsh_xcomp_bv;		/* bitmap of compact sub structures */
1405905ff7fSmaxv 	uint8_t xsh_rsrvd[8];		/* must be zero */
1415905ff7fSmaxv 	uint8_t xsh_reserved[40];	/* best if zero */
14227a8f3e1Sdsl };
1433a107b0aSdsl __CTASSERT(sizeof(struct xsave_header) == 512 + 64);
14427a8f3e1Sdsl 
14527a8f3e1Sdsl /*
14627a8f3e1Sdsl  * The ymm save area actually follows the xsave_header.
14727a8f3e1Sdsl  */
14827a8f3e1Sdsl struct xsave_ymm {
14927a8f3e1Sdsl 	struct ymmreg xs_ymm[16];	/* High bits of YMM registers */
15027a8f3e1Sdsl };
15127a8f3e1Sdsl __CTASSERT(sizeof(struct xsave_ymm) == 256);
15227a8f3e1Sdsl 
1533a107b0aSdsl /*
154c2ad96ffSmgorny  * AVX-512: opmask state.
155c2ad96ffSmgorny  */
156c2ad96ffSmgorny struct xsave_opmask {
157c2ad96ffSmgorny 	uint64_t xs_k[8];			/* k0..k7 registers. */
158c2ad96ffSmgorny };
159c2ad96ffSmgorny __CTASSERT(sizeof(struct xsave_opmask) == 64);
160c2ad96ffSmgorny 
161c2ad96ffSmgorny /*
162c2ad96ffSmgorny  * AVX-512: ZMM_Hi256 state.
163c2ad96ffSmgorny  */
164c2ad96ffSmgorny struct xsave_zmm_hi256 {
165c2ad96ffSmgorny 	struct zmmreg xs_zmm[16];	/* High bits of zmm0..zmm15 registers. */
166c2ad96ffSmgorny };
167c2ad96ffSmgorny __CTASSERT(sizeof(struct xsave_zmm_hi256) == 512);
168c2ad96ffSmgorny 
169c2ad96ffSmgorny /*
170c2ad96ffSmgorny  * AVX-512: Hi16_ZMM state.
171c2ad96ffSmgorny  */
172c2ad96ffSmgorny struct xsave_hi16_zmm {
173c2ad96ffSmgorny 	struct hi16_zmmreg xs_hi16_zmm[16];	/* zmm16..zmm31 registers. */
174c2ad96ffSmgorny };
175c2ad96ffSmgorny __CTASSERT(sizeof(struct xsave_hi16_zmm) == 1024);
176c2ad96ffSmgorny 
177c2ad96ffSmgorny /*
178c2ad96ffSmgorny  * Structure used to hold all interesting data from XSAVE, in predictable form.
179c2ad96ffSmgorny  * Note that this structure can have new members added to the end.
180c2ad96ffSmgorny  */
181c2ad96ffSmgorny struct xstate {
182c2ad96ffSmgorny 	/*
183c2ad96ffSmgorny 	 * The two following fields are bitmaps of XSAVE components.  They can be
184c2ad96ffSmgorny 	 * matched against XCR0_* constants from <machine/specialreg.h>).
185c2ad96ffSmgorny 	 */
186c2ad96ffSmgorny 	/*
187c2ad96ffSmgorny 	 * XSAVE/XRSTOR RFBM parameter.
188c2ad96ffSmgorny 	 *
189c2ad96ffSmgorny 	 * PT_GETXSTATE: 1 indicates that the respective XSAVE component is
190c2ad96ffSmgorny 	 * supported and has been enabled for saving.  0 indicates that it is not
191c2ad96ffSmgorny 	 * supported by the platform or kernel.
192c2ad96ffSmgorny 	 *
193c2ad96ffSmgorny 	 * PT_SETXSTATE: 1 indicates that the respective XSAVE component should
194c2ad96ffSmgorny 	 * be updated to the value of respective field (or reset if xs_xsave_bv
195c2ad96ffSmgorny 	 * bit is 0).  0 indicates that it should be left intact.  It is an error
196c2ad96ffSmgorny 	 * to enable bits that are not supported by the platform or kernel.
197c2ad96ffSmgorny 	 */
198c2ad96ffSmgorny 	uint64_t xs_rfbm;
199c2ad96ffSmgorny 	/*
200c2ad96ffSmgorny 	 * XSAVE/XRSTOR xstate header.
201c2ad96ffSmgorny 	 *
202c2ad96ffSmgorny 	 * PT_GETXSTATE: 1 indicates that the respective XSAVE component has been
203c2ad96ffSmgorny 	 * saved.  0 indicates that it had been in its CPU-defined initial value
204c2ad96ffSmgorny 	 * at the time of saving (i.e. was not used by the program).
205c2ad96ffSmgorny 	 *
206c2ad96ffSmgorny 	 * PT_SETXSTATE: 1 indicates that the respective XSAVE component (if present
207c2ad96ffSmgorny 	 * in xs_rfbm) should be set to the values in respective field.  0 indicates
208c2ad96ffSmgorny 	 * that it should be reset to CPU-defined initial value.
209c2ad96ffSmgorny 	 */
210c2ad96ffSmgorny 	uint64_t xs_xstate_bv;
211c2ad96ffSmgorny 
212c2ad96ffSmgorny 	/* legacy FXSAVE area (used for x87 & SSE state) */
213c2ad96ffSmgorny 	struct fxsave xs_fxsave;
214c2ad96ffSmgorny 	/* AVX state: high bits of ymm0..ymm15 registers */
215c2ad96ffSmgorny 	struct xsave_ymm xs_ymm_hi128;
216c2ad96ffSmgorny 	/* AVX-512: opmask */
217c2ad96ffSmgorny 	struct xsave_opmask xs_opmask;
218c2ad96ffSmgorny 	/* AVX-512: high bits of zmm0..zmm15 registers */
219c2ad96ffSmgorny 	struct xsave_zmm_hi256 xs_zmm_hi256;
220c2ad96ffSmgorny 	/* AVX-512: whole zmm16..zmm31 registers */
221c2ad96ffSmgorny 	struct xsave_hi16_zmm xs_hi16_zmm;
222c2ad96ffSmgorny };
223c2ad96ffSmgorny 
224c2ad96ffSmgorny /*
2253a107b0aSdsl  * The following union is placed at the end of the pcb.
2263a107b0aSdsl  * It is defined this way to separate the definitions and to
2273a107b0aSdsl  * minimise the number of union/struct selectors.
2283a107b0aSdsl  * NB: Some userspace stuff (eg firefox) uses it to parse ucontext.
2293a107b0aSdsl  */
2303a107b0aSdsl union savefpu {
2313a107b0aSdsl 	struct save87 sv_87;
2323a107b0aSdsl 	struct fxsave sv_xmm;
2333a107b0aSdsl #ifdef _KERNEL
2343a107b0aSdsl 	struct xsave_header sv_xsave_hdr;
2353a107b0aSdsl #endif
2363a107b0aSdsl };
23727a8f3e1Sdsl 
23827a8f3e1Sdsl /*
23927a8f3e1Sdsl  * 80387 control and status word bits
24027a8f3e1Sdsl  *
24136d63726Sdsl  * The only reference I can find to bits 0x40 and 0x80 in the control word
24236d63726Sdsl  * is for the Weitek 1167/3167.
24327a8f3e1Sdsl  * I (dsl) can't find why the default word has 0x40 set.
24436d63726Sdsl  *
24536d63726Sdsl  * A stack error is signalled as an INVOP that also sets STACK_FAULT
24636d63726Sdsl  * (other INVOP do not clear STACK_FAULT).
24727a8f3e1Sdsl  */
24827a8f3e1Sdsl /* Interrupt masks (set masks interrupt) and status bits */
24927a8f3e1Sdsl #define EN_SW_INVOP		0x0001  /* Invalid operation */
25027a8f3e1Sdsl #define EN_SW_DENORM		0x0002  /* Denormalized operand */
25127a8f3e1Sdsl #define EN_SW_ZERODIV		0x0004  /* Divide by zero */
25227a8f3e1Sdsl #define EN_SW_OVERFLOW		0x0008  /* Overflow */
25327a8f3e1Sdsl #define EN_SW_UNDERFLOW		0x0010  /* Underflow */
25427a8f3e1Sdsl #define EN_SW_PRECLOSS		0x0020  /* Loss of precision */
25536d63726Sdsl /* Status word bits (reserved in control word) */
25636d63726Sdsl #define EN_SW_STACK_FAULT	0x0040	/* Stack under/overflow */
25734c4cf73Smaxv #define EN_SW_ERROR_SUMMARY	0x0080	/* Unmasked error has occurred */
25827a8f3e1Sdsl /* Control bits (badly named) */
25927a8f3e1Sdsl #define EN_SW_CTL_PREC		0x0300	/* Precision control */
26027a8f3e1Sdsl #define EN_SW_PREC_24		0x0000	/* Single precision */
26127a8f3e1Sdsl #define EN_SW_PREC_53		0x0200	/* Double precision */
26227a8f3e1Sdsl #define EN_SW_PREC_64		0x0300	/* Extended precision */
26327a8f3e1Sdsl #define EN_SW_CTL_ROUND		0x0c00	/* Rounding control */
26427a8f3e1Sdsl #define EN_SW_ROUND_EVEN	0x0000	/* Round to nearest even */
26527a8f3e1Sdsl #define EN_SW_ROUND_DOWN	0x0400	/* Round towards minus infinity */
26627a8f3e1Sdsl #define EN_SW_ROUND_UP		0x0800	/* Round towards plus infinity */
26727a8f3e1Sdsl #define EN_SW_ROUND_ZERO	0x0c00	/* Round towards zero (truncates) */
26827a8f3e1Sdsl #define EN_SW_CTL_INF		0x1000	/* Infinity control, not used  */
26927a8f3e1Sdsl 
27027a8f3e1Sdsl /*
27127a8f3e1Sdsl  * The standard 0x87 control word from finit is 0x37F, giving:
27227a8f3e1Sdsl  *	round to nearest
27327a8f3e1Sdsl  *	64-bit precision
27427a8f3e1Sdsl  *	all exceptions masked.
27527a8f3e1Sdsl  *
27627a8f3e1Sdsl  * NetBSD used to select:
27727a8f3e1Sdsl  *	round to nearest
27827a8f3e1Sdsl  *	53-bit precision
27927a8f3e1Sdsl  *	all exceptions masked.
28027a8f3e1Sdsl  * Stating: 64-bit precision often gives bad results with high level
28127a8f3e1Sdsl  * languages because it makes the results of calculations depend on whether
28227a8f3e1Sdsl  * intermediate values are stored in memory or in FPU registers.
28327a8f3e1Sdsl  * Also some 'pathological divisions' give an error in the LSB because
28427a8f3e1Sdsl  * the value is first rounded up when the 64bit mantissa is generated,
28527a8f3e1Sdsl  * and then again when it is truncated to 53 bits.
28627a8f3e1Sdsl  *
28727a8f3e1Sdsl  * However the C language explicitly allows the extra precision.
28827a8f3e1Sdsl  */
28927a8f3e1Sdsl #define	__INITIAL_NPXCW__	0x037f
29027a8f3e1Sdsl /* Modern NetBSD uses the default control word.. */
29127a8f3e1Sdsl #define	__NetBSD_NPXCW__	__INITIAL_NPXCW__
29227a8f3e1Sdsl /* NetBSD before 6.99.26 forced IEEE double precision. */
29327a8f3e1Sdsl #define	__NetBSD_COMPAT_NPXCW__	0x127f
29427a8f3e1Sdsl /* FreeBSD leaves some exceptions unmasked as well. */
29527a8f3e1Sdsl #define	__FreeBSD_NPXCW__	0x1272
29627a8f3e1Sdsl /* Linux just uses the default control word. */
29727a8f3e1Sdsl #define	__Linux_NPXCW__		__INITIAL_NPXCW__
29827a8f3e1Sdsl 
29927a8f3e1Sdsl /*
30027a8f3e1Sdsl  * The default MXCSR value at reset is 0x1f80, IA-32 Instruction
30127a8f3e1Sdsl  * Set Reference, pg. 3-369.
30227a8f3e1Sdsl  *
30327a8f3e1Sdsl  * The low 6 bits of the mxcsr are the fp status bits (same order as x87).
30427a8f3e1Sdsl  * Bit 6 is 'denormals are zero' (speeds up calculations).
30527a8f3e1Sdsl  * Bits 7-16 are the interrupt mask bits (same order, 1 to mask).
30627a8f3e1Sdsl  * Bits 13 and 14 are rounding control.
30727a8f3e1Sdsl  * Bit 15 is 'flush to zero' - affects underflow.
30827a8f3e1Sdsl  * Bits 16-31 must be zero.
309*a89583caSriastradh  *
310*a89583caSriastradh  * The safe MXCSR is fit for constant-time use, e.g. in crypto.  Some
311*a89583caSriastradh  * CPU instructions take input- dependent time if an exception status
312*a89583caSriastradh  * bit is not set; __SAFE_MXCSR__ has the exception status bits all set
313*a89583caSriastradh  * already to mitigate this.  See:
314*a89583caSriastradh  * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/best-practices/mxcsr-configuration-dependent-timing.html
31527a8f3e1Sdsl  */
31627a8f3e1Sdsl #define	__INITIAL_MXCSR__	0x1f80
317519a6119Sdsl #define	__INITIAL_MXCSR_MASK__	0xffbf
318*a89583caSriastradh #define	__SAFE_MXCSR__		0x1fbf
319519a6119Sdsl 
32027a8f3e1Sdsl #endif /* _X86_CPU_EXTENDED_STATE_H_ */
321