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 */
21 struct 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 };
53 typedef struct user_debug_state user_breakpoint_state_t;
54 #endif /* CONFIG_HARDWARE_DEBUG_API */
55 
56 /* X86 FPU context. */
57 struct user_fpu_state {
58     uint8_t state[CONFIG_XSAVE_SIZE];
59 };
60 typedef struct user_fpu_state user_fpu_state_t;
61 
62 /* X86 user-code context */
63 struct 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 };
74 typedef struct user_context user_context_t;
75 
76 void Mode_initContext(user_context_t *context);
77 void Arch_initContext(user_context_t *context);
78 word_t Mode_sanitiseRegister(register_t reg, word_t v);
79 
80 /* Ensure FPU state is aligned within user context. */
81 unverified_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. */
86 unverified_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