1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#pragma once 8 9#include <config.h> 10#include <arch/types.h> 11#include <util.h> 12#include <assert.h> 13 14#include <mode/machine/registerset.h> 15 16/* Minimum hardware-enforced alignment needed for FPU state. */ 17#define MIN_FPU_ALIGNMENT 64 18 19#ifdef CONFIG_HARDWARE_DEBUG_API 20/* X86 Debug register context */ 21struct user_debug_state { 22 /* DR0-3 = Breakpoint linear address. 23 * DR4-5 = reserved or aliased, depending on value of CR4.DE. 24 * DR6 = Debug status register. 25 * DR7 = Debug control register. 26 */ 27 word_t dr[6]; 28 /* For each breakpoint currently being used by a thread, a bit in this 29 * bitfield is set, and for each breakpoint that is cleared, a bit is 30 * cleared. This enables an optimization: when a thread is being context- 31 * switched to, we can check to see if it's using breakpoints, and 32 * if so, we pop the whole register context. 33 * 34 * If it's not using breakpoints, we just pop all 0s into the ENABLED 35 * bits in DR7. 36 */ 37 uint32_t used_breakpoints_bf; 38 39 /* The API supports stepping N instructions forward, where N can 1..N. 40 * That feature is provided using this counter. Everytime a debug exception 41 * occurs, the kernel will decrement, then check the counter, and only when 42 * the counter is 0 will we deliver the fault to the userspace thread. 43 */ 44 word_t n_instructions; 45 46 /* This is part of the state machine that allows a thread to make 47 * syscalls while being single-stepped. Basically helps the kernel to 48 * disable single-stepping while executing the syscall, and then re-enable 49 * it just before returning from the syscall into userspace. 50 */ 51 bool_t single_step_enabled; 52}; 53typedef struct user_debug_state user_breakpoint_state_t; 54#endif /* CONFIG_HARDWARE_DEBUG_API */ 55 56/* X86 FPU context. */ 57struct user_fpu_state { 58 uint8_t state[CONFIG_XSAVE_SIZE]; 59}; 60typedef struct user_fpu_state user_fpu_state_t; 61 62/* X86 user-code context */ 63struct user_context { 64 user_fpu_state_t fpuState; 65 word_t registers[n_contextRegisters]; 66#if defined(ENABLE_SMP_SUPPORT) && defined(CONFIG_ARCH_IA32) 67 /* stored pointer to kernel stack used when kernel run in current TCB context. */ 68 word_t kernelSP; 69#endif 70#ifdef CONFIG_HARDWARE_DEBUG_API 71 user_breakpoint_state_t breakpointState; 72#endif 73}; 74typedef struct user_context user_context_t; 75 76void Mode_initContext(user_context_t *context); 77void Arch_initContext(user_context_t *context); 78word_t Mode_sanitiseRegister(register_t reg, word_t v); 79 80/* Ensure FPU state is aligned within user context. */ 81unverified_compile_assert(fpu_state_alignment_valid, 82 OFFSETOF(user_context_t, fpuState) % MIN_FPU_ALIGNMENT == 0) 83 84#if defined(ENABLE_SMP_SUPPORT) && defined(CONFIG_ARCH_IA32) 85/* Ensure kernelSP is the first member following the registers. */ 86unverified_compile_assert( 87 kernelSP_alignment_valid, 88 OFFSETOF(user_context_t, kernelSP) - OFFSETOF(user_context_t, registers) == sizeof(word_t) * n_contextRegisters 89) 90#endif 91 92