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
11/*
12 * We cannot allow async aborts in the verified kernel, but
13 * they are useful in identifying invalid memory access bugs
14 * so we enable them in debug mode.
15 */
16#ifdef CONFIG_DEBUG_BUILD
17#define CPSR_EXTRA_FLAGS 0
18#else
19#define CPSR_EXTRA_FLAGS PMASK_ASYNC_ABORT
20#endif
21
22#define CPSR_USER            ( PMASK_FIRQ         \
23                             | PMODE_USER         \
24                             | CPSR_EXTRA_FLAGS   )
25
26#define CPSR_KERNEL          ( PMASK_FIRQ         \
27                             | PMASK_IRQ          \
28                             | PMODE_KERNEL       \
29                             | CPSR_EXTRA_FLAGS   )
30
31#define CPSR_IDLETHREAD      ( PMASK_FIRQ         \
32                             | PMODE_IDLE         \
33                             | CPSR_EXTRA_FLAGS   )
34
35/* Offsets within the user context, these need to match the order in
36 * register_t below */
37#define PT_SP               (13  * 4)
38#define PT_NextIP           (15 * 4)
39#define PT_ELR_hyp          (15 * 4)
40#define PT_FaultIP          (17 * 4)
41#define PT_TPIDRURW         (18 * 4)
42#define PT_R8               (8  * 4)
43
44#ifdef CONFIG_KERNEL_GLOBALS_FRAME
45/*
46 * Virtualise the TPIDRURW register in the globals frame.
47 */
48#define GLOBALS_TPIDRURW 0
49#endif
50
51#ifndef __ASSEMBLER__ /* C only definitions */
52
53#include <config.h>
54#include <stdint.h>
55#include <assert.h>
56#include <util.h>
57#include <arch/types.h>
58#include <arch/machine/debug_conf.h>
59#include <sel4/plat/api/constants.h>
60
61/* These are the indices of the registers in the
62 * saved thread context.  The values are determined
63 * by the order in which they're saved in the trap
64 * handler. */
65enum _register {
66    R0 = 0,
67    capRegister = 0,
68    badgeRegister = 0,
69
70    R1 = 1,
71    msgInfoRegister = 1,
72
73    R2 = 2,
74    R3 = 3,
75    R4 = 4,
76    R5 = 5,
77    R6 = 6,
78#ifdef CONFIG_KERNEL_MCS
79    replyRegister = 6,
80#endif
81    R7 = 7,
82    R8 = 8,
83#ifdef CONFIG_KERNEL_MCS
84    nbsendRecvDest = 8,
85#endif
86
87    R9 = 9,
88    R10 = 10,
89    R11 = 11,
90    R12 = 12,
91
92    R13 = 13,
93    SP = 13,
94
95    R14 = 14,
96    LR = 14,
97
98    /* End of GP registers, the following are additional kernel-saved state. */
99
100    NextIP = 15, /* LR_svc */
101#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
102    ELR_hyp = 15,
103#endif
104    CPSR = 16,
105
106    FaultIP  = 17,
107    /* user readable/writable thread ID register.
108     * name comes from the ARM manual */
109    TPIDRURW = 18,
110    TLS_BASE = TPIDRURW,
111    /* user readonly thread ID register. */
112    TPIDRURO = 19,
113    n_contextRegisters = 20,
114};
115
116#define NEXT_PC_REG NextIP
117
118compile_assert(sp_offset_correct, SP *sizeof(word_t) == PT_SP)
119compile_assert(lr_svc_offset_correct, NextIP *sizeof(word_t) == PT_NextIP)
120#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
121compile_assert(elr_hyp_offset_correct, ELR_hyp *sizeof(word_t) == PT_ELR_hyp)
122#endif
123compile_assert(faultinstruction_offset_correct, FaultIP *sizeof(word_t) == PT_FaultIP)
124compile_assert(r8_offset_correct, R8 *sizeof(word_t) == PT_R8)
125
126typedef word_t register_t;
127
128enum messageSizes {
129    n_msgRegisters = seL4_FastMessageRegisters,
130    n_frameRegisters = 10,
131    n_gpRegisters = 9,
132    n_exceptionMessage = 3,
133    n_syscallMessage = 12,
134#ifdef CONFIG_KERNEL_MCS
135    n_timeoutMessage = 17,
136#endif
137};
138
139#define EXCEPTION_MESSAGE \
140 {\
141    [seL4_UserException_FaultIP] = FaultIP,\
142    [seL4_UserException_SP] = SP,\
143    [seL4_UserException_CPSR] = CPSR\
144 }
145
146#define SYSCALL_MESSAGE \
147{\
148    [seL4_UnknownSyscall_R0] = R0,\
149    [seL4_UnknownSyscall_R1] = R1,\
150    [seL4_UnknownSyscall_R2] = R2,\
151    [seL4_UnknownSyscall_R3] = R3,\
152    [seL4_UnknownSyscall_R4] = R4,\
153    [seL4_UnknownSyscall_R5] = R5,\
154    [seL4_UnknownSyscall_R6] = R6,\
155    [seL4_UnknownSyscall_R7] = R7,\
156    [seL4_UnknownSyscall_FaultIP] = FaultIP,\
157    [seL4_UnknownSyscall_SP] = SP,\
158    [seL4_UnknownSyscall_LR] = LR,\
159    [seL4_UnknownSyscall_CPSR] = CPSR\
160}
161
162#define TIMEOUT_REPLY_MESSAGE \
163{\
164    [seL4_TimeoutReply_FaultIP] = FaultIP,\
165    [seL4_TimeoutReply_SP] = SP, \
166    [seL4_TimeoutReply_CPSR] = CPSR,\
167    [seL4_TimeoutReply_R0] = R0,\
168    [seL4_TimeoutReply_R1] = R1,\
169    [seL4_TimeoutReply_R8] = R8,\
170    [seL4_TimeoutReply_R9] = R9,\
171    [seL4_TimeoutReply_R10] = R10,\
172    [seL4_TimeoutReply_R11] = R11,\
173    [seL4_TimeoutReply_R12] = R12,\
174    [seL4_TimeoutReply_R2] = R2,\
175    [seL4_TimeoutReply_R3] = R3,\
176    [seL4_TimeoutReply_R4] = R4,\
177    [seL4_TimeoutReply_R5] = R5,\
178    [seL4_TimeoutReply_R6] = R6,\
179    [seL4_TimeoutReply_R7] = R7,\
180    [seL4_TimeoutReply_R14] = R14,\
181}
182
183extern const register_t msgRegisters[];
184extern const register_t frameRegisters[];
185extern const register_t gpRegisters[];
186
187#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE
188typedef struct debug_register_pair {
189    word_t cr, vr;
190} debug_register_pair_t;
191
192/*
193 * This padding ensures that there is reasonable leeway when determining
194 * the size of the untyped needed for a TCB when watchpoint handling is
195 * involved.
196 */
197#define EXLUSIVE_WATCHPOINT_PADING 6
198#define EXLUSIVE_WATCHPOINT_PADDED \
199    (seL4_NumExclusiveWatchpoints > EXLUSIVE_WATCHPOINT_PADING) \
200        ? seL4_NumExclusiveWatchpoints \
201        : EXLUSIVE_WATCHPOINT_PADING
202
203typedef struct user_breakpoint_state {
204    /* We don't use context comparisons. */
205    debug_register_pair_t breakpoint[seL4_NumExclusiveBreakpoints],
206                          watchpoint[EXLUSIVE_WATCHPOINT_PADDED];
207    uint32_t used_breakpoints_bf;
208    word_t n_instructions;
209    bool_t single_step_enabled;
210    uint16_t single_step_hw_bp_num;
211} user_breakpoint_state_t;
212#endif
213
214#ifdef CONFIG_HAVE_FPU
215typedef struct user_fpu_state {
216    uint64_t fpregs[32];
217    uint32_t fpexc;
218    uint32_t fpscr;
219} user_fpu_state_t;
220#endif /* CONFIG_HAVE_FPU */
221
222/* ARM user-code context: size = 72 bytes
223 * Or with hardware debug support built in:
224 *      72 + sizeof(word_t) * (NUM_BPS + NUM_WPS) * 2
225 *
226 * The "word_t registers" member of this struct must come first, because in
227 * head.S, we assume that an "ldr %0, =ksCurThread" will point to the beginning
228 * of the current thread's registers. The assert below should help.
229 */
230struct user_context {
231    word_t registers[n_contextRegisters];
232#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE
233    user_breakpoint_state_t breakpointState;
234#endif /* CONFIG_HARDWARE_DEBUG_API */
235#ifdef CONFIG_HAVE_FPU
236    user_fpu_state_t fpuState;
237#endif /* CONFIG_HAVE_FPU */
238};
239typedef struct user_context user_context_t;
240
241unverified_compile_assert(registers_are_first_member_of_user_context,
242                          OFFSETOF(user_context_t, registers) == 0)
243
244#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE
245void Arch_initBreakpointContext(user_context_t *context);
246#endif
247
248static inline void Arch_initContext(user_context_t *context)
249{
250    context->registers[CPSR] = CPSR_USER;
251#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE
252    Arch_initBreakpointContext(context);
253#endif
254}
255
256#endif /* !__ASSEMBLER__ */
257
258