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