/* * Copyright (c) 2017 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief Per-arch thread definition * * This file contains definitions for * * struct _thread_arch * struct _callee_saved * * necessary to instantiate instances of struct k_thread. */ #ifndef ZEPHYR_ARCH_X86_INCLUDE_IA32_KERNEL_ARCH_THREAD_H_ #define ZEPHYR_ARCH_X86_INCLUDE_IA32_KERNEL_ARCH_THREAD_H_ /** * Floating point register set alignment. * * If support for SSEx extensions is enabled a 16 byte boundary is required, * since the 'fxsave' and 'fxrstor' instructions require this. In all other * cases a 4 byte boundary is sufficient. */ #ifdef CONFIG_SSE #define FP_REG_SET_ALIGN 16 #else #define FP_REG_SET_ALIGN 4 #endif /* * Bits for _thread_arch.flags, see their use in intstub.S et al. */ #define X86_THREAD_FLAG_INT 0x01 #define X86_THREAD_FLAG_EXC 0x02 #define X86_THREAD_FLAG_ALL (X86_THREAD_FLAG_INT | X86_THREAD_FLAG_EXC) #ifndef _ASMLANGUAGE #include #include /* * The following structure defines the set of 'non-volatile' integer registers. * These registers must be preserved by a called C function. These are the * only registers that need to be saved/restored when a cooperative context * switch occurs. */ struct _callee_saved { unsigned long esp; /* * The following registers are considered non-volatile, i.e. * callee-save, * but their values are pushed onto the stack rather than stored in the * TCS * structure: * * unsigned long ebp; * unsigned long ebx; * unsigned long esi; * unsigned long edi; */ }; typedef struct _callee_saved _callee_saved_t; /* * The macros CONFIG_{LAZY|EAGER}_FP_SHARING shall be set to indicate that the * saving/restoring of the traditional x87 floating point (and MMX) registers * are supported by the kernel's context swapping code. The macro * CONFIG_SSE shall _also_ be set if saving/restoring of the XMM * registers is also supported in the kernel's context swapping code. */ #if defined(CONFIG_EAGER_FP_SHARING) || defined(CONFIG_LAZY_FP_SHARING) /* definition of a single x87 (floating point / MMX) register */ typedef struct s_FpReg { unsigned char reg[10]; /* 80 bits: ST[0-7] */ } tFpReg; /* * The following is the "normal" floating point register save area, or * more accurately the save area required by the 'fnsave' and 'frstor' * instructions. The structure matches the layout described in the * "Intel(r) 64 and IA-32 Architectures Software Developer's Manual * Volume 1: Basic Architecture": Protected Mode x87 FPU State Image in * Memory, 32-Bit Format. */ typedef struct s_FpRegSet { /* # of bytes: name of register */ unsigned short fcw; /* 2 : x87 FPU control word */ unsigned short pad1; /* 2 : N/A */ unsigned short fsw; /* 2 : x87 FPU status word */ unsigned short pad2; /* 2 : N/A */ unsigned short ftw; /* 2 : x87 FPU tag word */ unsigned short pad3; /* 2 : N/A */ unsigned int fpuip; /* 4 : x87 FPU instruction pointer offset */ unsigned short cs; /* 2 : x87 FPU instruction pointer selector */ unsigned short fop : 11; /* 2 : x87 FPU opcode */ unsigned short pad4 : 5; /* : 5 bits = 00000 */ unsigned int fpudp; /* 4 : x87 FPU instr operand ptr offset */ unsigned short ds; /* 2 : x87 FPU instr operand ptr selector */ unsigned short pad5; /* 2 : N/A */ tFpReg fpReg[8]; /* 80 : ST0 -> ST7 */ } tFpRegSet __aligned(FP_REG_SET_ALIGN); #ifdef CONFIG_SSE /* definition of a single x87 (floating point / MMX) register */ typedef struct s_FpRegEx { unsigned char reg[10]; /* 80 bits: ST[0-7] or MM[0-7] */ unsigned char rsrvd[6]; /* 48 bits: reserved */ } tFpRegEx; /* definition of a single XMM register */ typedef struct s_XmmReg { unsigned char reg[16]; /* 128 bits: XMM[0-7] */ } tXmmReg; /* * The following is the "extended" floating point register save area, or * more accurately the save area required by the 'fxsave' and 'fxrstor' * instructions. The structure matches the layout described in the * "Intel 64 and IA-32 Architectures Software Developer's Manual * Volume 2A: Instruction Set Reference, A-M", except for the bytes from offset * 464 to 511 since these "are available to software use. The processor does * not write to bytes 464:511 of an FXSAVE area". * * This structure must be aligned on a 16 byte boundary when the instructions * fxsave/fxrstor are used to write/read the data to/from the structure. */ typedef struct s_FpRegSetEx /* # of bytes: name of register */ { unsigned short fcw; /* 2 : x87 FPU control word */ unsigned short fsw; /* 2 : x87 FPU status word */ unsigned char ftw; /* 1 : x87 FPU abridged tag word */ unsigned char rsrvd0; /* 1 : reserved */ unsigned short fop; /* 2 : x87 FPU opcode */ unsigned int fpuip; /* 4 : x87 FPU instruction pointer offset */ unsigned short cs; /* 2 : x87 FPU instruction pointer selector */ unsigned short rsrvd1; /* 2 : reserved */ unsigned int fpudp; /* 4 : x87 FPU instr operand ptr offset */ unsigned short ds; /* 2 : x87 FPU instr operand ptr selector */ unsigned short rsrvd2; /* 2 : reserved */ unsigned int mxcsr; /* 4 : MXCSR register state */ unsigned int mxcsrMask; /* 4 : MXCSR register mask */ tFpRegEx fpReg[8]; /* 128 : x87 FPU/MMX registers */ tXmmReg xmmReg[8]; /* 128 : XMM registers */ unsigned char rsrvd3[176]; /* 176 : reserved */ } tFpRegSetEx __aligned(FP_REG_SET_ALIGN); #else /* CONFIG_SSE == 0 */ typedef struct s_FpRegSetEx { } tFpRegSetEx; #endif /* CONFIG_SSE == 0 */ #else /* !CONFIG_LAZY_FP_SHARING && !CONFIG_EAGER_FP_SHARING */ /* empty floating point register definition */ typedef struct s_FpRegSet { } tFpRegSet; typedef struct s_FpRegSetEx { } tFpRegSetEx; #endif /* CONFIG_LAZY_FP_SHARING || CONFIG_EAGER_FP_SHARING */ /* * The following structure defines the set of 'volatile' x87 FPU/MMX/SSE * registers. These registers need not be preserved by a called C function. * Given that they are not preserved across function calls, they must be * save/restored (along with s_coopFloatReg) when a preemptive context * switch occurs. */ typedef struct s_preempFloatReg { union { /* threads with K_FP_REGS utilize this format */ tFpRegSet fpRegs; /* threads with K_SSE_REGS utilize this format */ tFpRegSetEx fpRegsEx; } floatRegsUnion; } tPreempFloatReg; /* * The thread control structure definition. It contains the * various fields to manage a _single_ thread. The TCS will be aligned * to the appropriate architecture specific boundary via the * z_arch_new_thread() call. */ struct _thread_arch { u8_t flags; #if defined(CONFIG_LAZY_FP_SHARING) /* * Nested exception count to maintain setting of EXC_ACTIVE flag across * outermost exception. EXC_ACTIVE is used by z_swap() lazy FP * save/restore and by debug tools. */ unsigned excNestCount; /* nested exception count */ #endif /* CONFIG_LAZY_FP_SHARING */ /* * The location of all floating point related structures/fields MUST be * located at the end of struct k_thread. This way only the * threads that actually utilize non-integer capabilities need to * account for the increased memory required for storing FP state when * sizing stacks. * * Given that stacks "grow down" on IA-32, and the TCS is located * at the start of a thread's "workspace" memory, the stacks of * threads that do not utilize floating point instruction can * effectively consume the memory occupied by the 'tPreempFloatReg' * struct without ill effect. */ tPreempFloatReg preempFloatReg; /* volatile float register storage */ #ifdef CONFIG_USERSPACE /* Per-thread page directory pointer table when a thread is running * in user mode. * * With KPTI enabled, any privilege elevation while that thread is * running, or ISR will switch to the master kernel pdpt at * z_x86_kernel_pdpt; the memory domain policy will not apply at * all. * * With KPTI disabled, this pdpt will be active at all times when * the thread is running. This has implications for memory domain * partitions that are read-only!! * * See #17833 for more discussion. */ __aligned(0x20) struct x86_mmu_pdpt user_pdpt; #endif /* CONFIG_USERSPACE */ }; typedef struct _thread_arch _thread_arch_t; #endif /* _ASMLANGUAGE */ #endif /* ZEPHYR_ARCH_X86_INCLUDE_IA32_KERNEL_ARCH_THREAD_H_ */