1 /*
2  * Copyright (c) 2017 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Per-arch thread definition
10  *
11  * This file contains definitions for
12  *
13  *  struct _thread_arch
14  *  struct _callee_saved
15  *
16  * necessary to instantiate instances of struct k_thread.
17  */
18 
19 #ifndef ZEPHYR_INCLUDE_ARCH_X86_IA32_THREAD_H_
20 #define ZEPHYR_INCLUDE_ARCH_X86_IA32_THREAD_H_
21 
22 /**
23  * Floating point register set alignment.
24  *
25  * If support for SSEx extensions is enabled a 16 byte boundary is required,
26  * since the 'fxsave' and 'fxrstor' instructions require this. In all other
27  * cases a 4 byte boundary is sufficient.
28  */
29 #if defined(CONFIG_EAGER_FPU_SHARING) || defined(CONFIG_LAZY_FPU_SHARING)
30 #ifdef CONFIG_X86_SSE
31 #define FP_REG_SET_ALIGN  16
32 #else
33 #define FP_REG_SET_ALIGN  4
34 #endif
35 #else
36 /* Unused, no special alignment requirements, use default alignment for
37  * char buffers on this arch
38  */
39 #define FP_REG_SET_ALIGN  1
40 #endif /* CONFIG_*_FP_SHARING */
41 
42 /*
43  * Bits for _thread_arch.flags, see their use in intstub.S et al.
44  */
45 
46 #define X86_THREAD_FLAG_INT 0x01
47 #define X86_THREAD_FLAG_EXC 0x02
48 #define X86_THREAD_FLAG_ALL (X86_THREAD_FLAG_INT | X86_THREAD_FLAG_EXC)
49 
50 #ifndef _ASMLANGUAGE
51 #include <stdint.h>
52 #include <zephyr/arch/x86/mmustructs.h>
53 
54 /*
55  * The following structure defines the set of 'non-volatile' integer registers.
56  * These registers must be preserved by a called C function.  These are the
57  * only registers that need to be saved/restored when a cooperative context
58  * switch occurs.
59  */
60 
61 struct _callee_saved {
62 	unsigned long esp;
63 
64 	/*
65 	 * The following registers are considered non-volatile, i.e.
66 	 * callee-save,
67 	 * but their values are pushed onto the stack rather than stored in the
68 	 * TCS
69 	 * structure:
70 	 *
71 	 *  unsigned long ebp;
72 	 *  unsigned long ebx;
73 	 *  unsigned long esi;
74 	 *  unsigned long edi;
75 	 */
76 
77 };
78 
79 typedef struct _callee_saved _callee_saved_t;
80 
81 /*
82  * The macros CONFIG_{LAZY|EAGER}_FPU_SHARING shall be set to indicate that the
83  * saving/restoring of the traditional x87 floating point (and MMX) registers
84  * are supported by the kernel's context swapping code. The macro
85  * CONFIG_X86_SSE shall _also_ be set if saving/restoring of the XMM
86  * registers is also supported in the kernel's context swapping code.
87  */
88 
89 #if defined(CONFIG_EAGER_FPU_SHARING) || defined(CONFIG_LAZY_FPU_SHARING)
90 
91 /* definition of a single x87 (floating point / MMX) register */
92 
93 typedef struct s_FpReg {
94 	unsigned char reg[10]; /* 80 bits: ST[0-7] */
95 } tFpReg;
96 
97 /*
98  * The following is the "normal" floating point register save area, or
99  * more accurately the save area required by the 'fnsave' and 'frstor'
100  * instructions.  The structure matches the layout described in the
101  * "Intel(r) 64 and IA-32 Architectures Software Developer's Manual
102  * Volume 1: Basic Architecture": Protected Mode x87 FPU State Image in
103  * Memory, 32-Bit Format.
104  */
105 
106 typedef struct s_FpRegSet {  /* # of bytes: name of register */
107 	unsigned short fcw;      /* 2  : x87 FPU control word */
108 	unsigned short pad1;     /* 2  : N/A */
109 	unsigned short fsw;      /* 2  : x87 FPU status word */
110 	unsigned short pad2;     /* 2  : N/A */
111 	unsigned short ftw;      /* 2  : x87 FPU tag word */
112 	unsigned short pad3;     /* 2  : N/A */
113 	unsigned int fpuip;      /* 4  : x87 FPU instruction pointer offset */
114 	unsigned short cs;       /* 2  : x87 FPU instruction pointer selector */
115 	unsigned short fop : 11; /* 2  : x87 FPU opcode */
116 	unsigned short pad4 : 5; /*    : 5 bits = 00000 */
117 	unsigned int fpudp;      /* 4  : x87 FPU instr operand ptr offset */
118 	unsigned short ds;       /* 2  : x87 FPU instr operand ptr selector */
119 	unsigned short pad5;     /* 2  : N/A */
120 	tFpReg fpReg[8];	 /* 80 : ST0 -> ST7 */
121 } tFpRegSet __aligned(FP_REG_SET_ALIGN);
122 
123 #ifdef CONFIG_X86_SSE
124 
125 /* definition of a single x87 (floating point / MMX) register */
126 
127 typedef struct s_FpRegEx {
128 	unsigned char reg[10];  /* 80 bits: ST[0-7] or MM[0-7] */
129 	unsigned char rsrvd[6]; /* 48 bits: reserved */
130 } tFpRegEx;
131 
132 /* definition of a single XMM register */
133 
134 typedef struct s_XmmReg {
135 	unsigned char reg[16]; /* 128 bits: XMM[0-7] */
136 } tXmmReg;
137 
138 /*
139  * The following is the "extended" floating point register save area, or
140  * more accurately the save area required by the 'fxsave' and 'fxrstor'
141  * instructions.  The structure matches the layout described in the
142  * "Intel 64 and IA-32 Architectures Software Developer's Manual
143  * Volume 2A: Instruction Set Reference, A-M", except for the bytes from offset
144  * 464 to 511 since these "are available to software use. The processor does
145  * not write to bytes 464:511 of an FXSAVE area".
146  *
147  * This structure must be aligned on a 16 byte boundary when the instructions
148  * fxsave/fxrstor are used to write/read the data to/from the structure.
149  */
150 
151 typedef struct s_FpRegSetEx /* # of bytes: name of register */
152 {
153 	unsigned short fcw;     /* 2  : x87 FPU control word */
154 	unsigned short fsw;     /* 2  : x87 FPU status word */
155 	unsigned char ftw;      /* 1  : x87 FPU abridged tag word */
156 	unsigned char rsrvd0;   /* 1  : reserved */
157 	unsigned short fop;     /* 2  : x87 FPU opcode */
158 	unsigned int fpuip;     /* 4  : x87 FPU instruction pointer offset */
159 	unsigned short cs;      /* 2  : x87 FPU instruction pointer selector */
160 	unsigned short rsrvd1;  /* 2  : reserved */
161 	unsigned int fpudp;     /* 4  : x87 FPU instr operand ptr offset */
162 	unsigned short ds;      /* 2  : x87 FPU instr operand ptr selector */
163 	unsigned short rsrvd2;  /* 2  : reserved */
164 	unsigned int mxcsr;     /* 4  : MXCSR register state */
165 	unsigned int mxcsrMask; /* 4  : MXCSR register mask */
166 	tFpRegEx fpReg[8];      /* 128 : x87 FPU/MMX registers */
167 	tXmmReg xmmReg[8];      /* 128 : XMM registers */
168 	unsigned char rsrvd3[176]; /* 176 : reserved */
169 } tFpRegSetEx __aligned(FP_REG_SET_ALIGN);
170 
171 #else /* CONFIG_X86_SSE == 0 */
172 
173 typedef struct s_FpRegSetEx {
174 } tFpRegSetEx;
175 
176 #endif /* CONFIG_X86_SSE == 0 */
177 
178 #else /* !CONFIG_LAZY_FPU_SHARING && !CONFIG_EAGER_FPU_SHARING */
179 
180 /* empty floating point register definition */
181 
182 typedef struct s_FpRegSet {
183 } tFpRegSet;
184 
185 typedef struct s_FpRegSetEx {
186 } tFpRegSetEx;
187 
188 #endif /* CONFIG_LAZY_FPU_SHARING || CONFIG_EAGER_FPU_SHARING */
189 
190 /*
191  * The following structure defines the set of 'volatile' x87 FPU/MMX/SSE
192  * registers.  These registers need not be preserved by a called C function.
193  * Given that they are not preserved across function calls, they must be
194  * save/restored (along with s_coopFloatReg) when a preemptive context
195  * switch occurs.
196  */
197 
198 typedef struct s_preempFloatReg {
199 	union {
200 		/* threads with K_FP_REGS utilize this format */
201 		tFpRegSet fpRegs;
202 		/* threads with K_SSE_REGS utilize this format */
203 		tFpRegSetEx fpRegsEx;
204 	} floatRegsUnion;
205 } tPreempFloatReg;
206 
207 /*
208  * The thread control structure definition.  It contains the
209  * various fields to manage a _single_ thread. The TCS will be aligned
210  * to the appropriate architecture specific boundary via the
211  * arch_new_thread() call.
212  */
213 
214 struct _thread_arch {
215 	uint8_t flags;
216 
217 #ifdef CONFIG_USERSPACE
218 #ifndef CONFIG_X86_COMMON_PAGE_TABLE
219 	/* Physical address of the page tables used by this thread */
220 	uintptr_t ptables;
221 #endif /* CONFIG_X86_COMMON_PAGE_TABLE */
222 
223 	/* Initial privilege mode stack pointer when doing a system call.
224 	 * Un-set for supervisor threads.
225 	 */
226 	char *psp;
227 #endif
228 
229 #if defined(CONFIG_LAZY_FPU_SHARING)
230 	/*
231 	 * Nested exception count to maintain setting of EXC_ACTIVE flag across
232 	 * outermost exception.  EXC_ACTIVE is used by z_swap() lazy FP
233 	 * save/restore and by debug tools.
234 	 */
235 	unsigned excNestCount; /* nested exception count */
236 #endif /* CONFIG_LAZY_FPU_SHARING */
237 
238 	tPreempFloatReg preempFloatReg; /* volatile float register storage */
239 };
240 
241 typedef struct _thread_arch _thread_arch_t;
242 
243 #endif /* _ASMLANGUAGE */
244 
245 #endif /* ZEPHYR_INCLUDE_ARCH_X86_IA32_THREAD_H_ */
246