Commit | Line | Data |
---|---|---|
5ba3f43e A |
1 | /* |
2 | * Copyright (c) 2007 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | /* | |
29 | * FILE_ID: thread_status.h | |
30 | */ | |
31 | ||
32 | ||
33 | #ifndef _ARM_THREAD_STATUS_H_ | |
34 | #define _ARM_THREAD_STATUS_H_ | |
35 | ||
36 | #include <mach/machine/_structs.h> | |
37 | #include <mach/message.h> | |
94ff46dc | 38 | #include <mach/vm_types.h> |
5ba3f43e A |
39 | #include <mach/arm/thread_state.h> |
40 | ||
41 | /* | |
42 | * Support for determining the state of a thread | |
43 | */ | |
44 | ||
45 | ||
46 | /* | |
47 | * Flavors | |
48 | */ | |
49 | ||
cb323159 | 50 | #define ARM_THREAD_STATE 1 |
5ba3f43e | 51 | #define ARM_UNIFIED_THREAD_STATE ARM_THREAD_STATE |
cb323159 A |
52 | #define ARM_VFP_STATE 2 |
53 | #define ARM_EXCEPTION_STATE 3 | |
54 | #define ARM_DEBUG_STATE 4 /* pre-armv8 */ | |
55 | #define THREAD_STATE_NONE 5 | |
56 | #define ARM_THREAD_STATE64 6 | |
57 | #define ARM_EXCEPTION_STATE64 7 | |
58 | // ARM_THREAD_STATE_LAST 8 /* legacy */ | |
59 | #define ARM_THREAD_STATE32 9 | |
5ba3f43e | 60 | |
f427ee49 A |
61 | #ifdef XNU_KERNEL_PRIVATE |
62 | #define X86_THREAD_STATE_NONE 13 /* i386/thread_status.h THREAD_STATE_NONE */ | |
63 | #endif /* XNU_KERNEL_PRIVATE */ | |
64 | ||
5ba3f43e | 65 | /* API */ |
cb323159 A |
66 | #define ARM_DEBUG_STATE32 14 |
67 | #define ARM_DEBUG_STATE64 15 | |
68 | #define ARM_NEON_STATE 16 | |
69 | #define ARM_NEON_STATE64 17 | |
70 | #define ARM_CPMU_STATE64 18 | |
5ba3f43e A |
71 | |
72 | #ifdef XNU_KERNEL_PRIVATE | |
73 | /* For kernel use */ | |
cb323159 A |
74 | #define ARM_SAVED_STATE32 20 |
75 | #define ARM_SAVED_STATE64 21 | |
76 | #define ARM_NEON_SAVED_STATE32 22 | |
77 | #define ARM_NEON_SAVED_STATE64 23 | |
5ba3f43e A |
78 | #endif /* XNU_KERNEL_PRIVATE */ |
79 | ||
cb323159 A |
80 | |
81 | #define ARM_STATE_FLAVOR_IS_OTHER_VALID(_flavor_) 0 | |
82 | ||
83 | #define ARM_PAGEIN_STATE 27 | |
84 | ||
0a7de745 | 85 | #define VALID_THREAD_STATE_FLAVOR(x) \ |
cb323159 A |
86 | ((x == ARM_THREAD_STATE) || \ |
87 | (x == ARM_VFP_STATE) || \ | |
88 | (x == ARM_EXCEPTION_STATE) || \ | |
89 | (x == ARM_DEBUG_STATE) || \ | |
90 | (x == THREAD_STATE_NONE) || \ | |
91 | (x == ARM_THREAD_STATE32) || \ | |
92 | (x == ARM_THREAD_STATE64) || \ | |
93 | (x == ARM_EXCEPTION_STATE64) || \ | |
94 | (x == ARM_NEON_STATE) || \ | |
95 | (x == ARM_NEON_STATE64) || \ | |
96 | (x == ARM_DEBUG_STATE32) || \ | |
97 | (x == ARM_DEBUG_STATE64) || \ | |
98 | (x == ARM_PAGEIN_STATE) || \ | |
99 | (ARM_STATE_FLAVOR_IS_OTHER_VALID(x))) | |
5ba3f43e A |
100 | |
101 | struct arm_state_hdr { | |
0a7de745 A |
102 | uint32_t flavor; |
103 | uint32_t count; | |
5ba3f43e A |
104 | }; |
105 | typedef struct arm_state_hdr arm_state_hdr_t; | |
106 | ||
cb323159 A |
107 | typedef _STRUCT_ARM_THREAD_STATE arm_thread_state_t; |
108 | typedef _STRUCT_ARM_THREAD_STATE arm_thread_state32_t; | |
109 | typedef _STRUCT_ARM_THREAD_STATE64 arm_thread_state64_t; | |
5ba3f43e | 110 | |
d9a64523 A |
111 | #if !defined(KERNEL) |
112 | #if __DARWIN_C_LEVEL >= __DARWIN_C_FULL && defined(__arm64__) | |
cb323159 A |
113 | |
114 | /* Accessor macros for arm_thread_state64_t pointer fields */ | |
115 | ||
116 | /* Return pc field of arm_thread_state64_t as a data pointer value */ | |
d9a64523 | 117 | #define arm_thread_state64_get_pc(ts) \ |
0a7de745 | 118 | __darwin_arm_thread_state64_get_pc(ts) |
cb323159 A |
119 | /* Return pc field of arm_thread_state64_t as a function pointer. May return |
120 | * NULL if a valid function pointer cannot be constructed, the caller should | |
121 | * fall back to the arm_thread_state64_get_pc() macro in that case. */ | |
d9a64523 | 122 | #define arm_thread_state64_get_pc_fptr(ts) \ |
0a7de745 | 123 | __darwin_arm_thread_state64_get_pc_fptr(ts) |
cb323159 | 124 | /* Set pc field of arm_thread_state64_t to a function pointer */ |
d9a64523 | 125 | #define arm_thread_state64_set_pc_fptr(ts, fptr) \ |
0a7de745 | 126 | __darwin_arm_thread_state64_set_pc_fptr(ts, fptr) |
cb323159 | 127 | /* Return lr field of arm_thread_state64_t as a data pointer value */ |
d9a64523 | 128 | #define arm_thread_state64_get_lr(ts) \ |
0a7de745 | 129 | __darwin_arm_thread_state64_get_lr(ts) |
cb323159 A |
130 | /* Return lr field of arm_thread_state64_t as a function pointer. May return |
131 | * NULL if a valid function pointer cannot be constructed, the caller should | |
132 | * fall back to the arm_thread_state64_get_lr() macro in that case. */ | |
d9a64523 | 133 | #define arm_thread_state64_get_lr_fptr(ts) \ |
0a7de745 | 134 | __darwin_arm_thread_state64_get_lr_fptr(ts) |
cb323159 | 135 | /* Set lr field of arm_thread_state64_t to a function pointer */ |
d9a64523 | 136 | #define arm_thread_state64_set_lr_fptr(ts, fptr) \ |
0a7de745 | 137 | __darwin_arm_thread_state64_set_lr_fptr(ts, fptr) |
cb323159 | 138 | /* Return sp field of arm_thread_state64_t as a data pointer value */ |
d9a64523 | 139 | #define arm_thread_state64_get_sp(ts) \ |
0a7de745 | 140 | __darwin_arm_thread_state64_get_sp(ts) |
cb323159 | 141 | /* Set sp field of arm_thread_state64_t to a data pointer value */ |
d9a64523 | 142 | #define arm_thread_state64_set_sp(ts, ptr) \ |
0a7de745 | 143 | __darwin_arm_thread_state64_set_sp(ts, ptr) |
cb323159 | 144 | /* Return fp field of arm_thread_state64_t as a data pointer value */ |
d9a64523 | 145 | #define arm_thread_state64_get_fp(ts) \ |
0a7de745 | 146 | __darwin_arm_thread_state64_get_fp(ts) |
cb323159 | 147 | /* Set fp field of arm_thread_state64_t to a data pointer value */ |
d9a64523 | 148 | #define arm_thread_state64_set_fp(ts, ptr) \ |
0a7de745 | 149 | __darwin_arm_thread_state64_set_fp(ts, ptr) |
f427ee49 A |
150 | /* Strip ptr auth bits from pc, lr, sp and fp field of arm_thread_state64_t */ |
151 | #define arm_thread_state64_ptrauth_strip(ts) \ | |
152 | __darwin_arm_thread_state64_ptrauth_strip(ts) | |
cb323159 | 153 | |
d9a64523 A |
154 | #endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL && defined(__arm64__) */ |
155 | #endif /* !defined(KERNEL) */ | |
156 | ||
5ba3f43e A |
157 | struct arm_unified_thread_state { |
158 | arm_state_hdr_t ash; | |
159 | union { | |
160 | arm_thread_state32_t ts_32; | |
161 | arm_thread_state64_t ts_64; | |
162 | } uts; | |
163 | }; | |
cb323159 A |
164 | #define ts_32 uts.ts_32 |
165 | #define ts_64 uts.ts_64 | |
5ba3f43e A |
166 | typedef struct arm_unified_thread_state arm_unified_thread_state_t; |
167 | ||
168 | #define ARM_THREAD_STATE_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 169 | (sizeof (arm_thread_state_t)/sizeof(uint32_t))) |
5ba3f43e | 170 | #define ARM_THREAD_STATE32_COUNT ((mach_msg_type_number_t) \ |
cb323159 | 171 | (sizeof (arm_thread_state32_t)/sizeof(uint32_t))) |
5ba3f43e | 172 | #define ARM_THREAD_STATE64_COUNT ((mach_msg_type_number_t) \ |
cb323159 | 173 | (sizeof (arm_thread_state64_t)/sizeof(uint32_t))) |
5ba3f43e | 174 | #define ARM_UNIFIED_THREAD_STATE_COUNT ((mach_msg_type_number_t) \ |
cb323159 A |
175 | (sizeof (arm_unified_thread_state_t)/sizeof(uint32_t))) |
176 | ||
5ba3f43e | 177 | |
cb323159 A |
178 | typedef _STRUCT_ARM_VFP_STATE arm_vfp_state_t; |
179 | typedef _STRUCT_ARM_NEON_STATE arm_neon_state_t; | |
180 | typedef _STRUCT_ARM_NEON_STATE arm_neon_state32_t; | |
181 | typedef _STRUCT_ARM_NEON_STATE64 arm_neon_state64_t; | |
5ba3f43e | 182 | |
5ba3f43e | 183 | |
cb323159 A |
184 | typedef _STRUCT_ARM_EXCEPTION_STATE arm_exception_state_t; |
185 | typedef _STRUCT_ARM_EXCEPTION_STATE arm_exception_state32_t; | |
186 | typedef _STRUCT_ARM_EXCEPTION_STATE64 arm_exception_state64_t; | |
5ba3f43e | 187 | |
cb323159 A |
188 | typedef _STRUCT_ARM_DEBUG_STATE32 arm_debug_state32_t; |
189 | typedef _STRUCT_ARM_DEBUG_STATE64 arm_debug_state64_t; | |
190 | ||
191 | typedef _STRUCT_ARM_PAGEIN_STATE arm_pagein_state_t; | |
5ba3f43e A |
192 | |
193 | #if defined(XNU_KERNEL_PRIVATE) && defined(__arm64__) | |
194 | /* See below for ARM64 kernel structure definition for arm_debug_state. */ | |
cb323159 | 195 | #else /* defined(XNU_KERNEL_PRIVATE) && defined(__arm64__) */ |
5ba3f43e A |
196 | /* |
197 | * Otherwise not ARM64 kernel and we must preserve legacy ARM definitions of | |
198 | * arm_debug_state for binary compatability of userland consumers of this file. | |
199 | */ | |
200 | #if defined(__arm__) | |
cb323159 | 201 | typedef _STRUCT_ARM_DEBUG_STATE arm_debug_state_t; |
5ba3f43e | 202 | #elif defined(__arm64__) |
cb323159 A |
203 | typedef _STRUCT_ARM_LEGACY_DEBUG_STATE arm_debug_state_t; |
204 | #else /* defined(__arm__) */ | |
5ba3f43e | 205 | #error Undefined architecture |
cb323159 A |
206 | #endif /* defined(__arm__) */ |
207 | #endif /* defined(XNU_KERNEL_PRIVATE) && defined(__arm64__) */ | |
5ba3f43e A |
208 | |
209 | #define ARM_VFP_STATE_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 210 | (sizeof (arm_vfp_state_t)/sizeof(uint32_t))) |
5ba3f43e A |
211 | |
212 | #define ARM_EXCEPTION_STATE_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 213 | (sizeof (arm_exception_state_t)/sizeof(uint32_t))) |
5ba3f43e A |
214 | |
215 | #define ARM_EXCEPTION_STATE64_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 216 | (sizeof (arm_exception_state64_t)/sizeof(uint32_t))) |
5ba3f43e A |
217 | |
218 | #define ARM_DEBUG_STATE_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 219 | (sizeof (arm_debug_state_t)/sizeof(uint32_t))) |
5ba3f43e A |
220 | |
221 | #define ARM_DEBUG_STATE32_COUNT ((mach_msg_type_number_t) \ | |
cb323159 A |
222 | (sizeof (arm_debug_state32_t)/sizeof(uint32_t))) |
223 | ||
224 | #define ARM_PAGEIN_STATE_COUNT ((mach_msg_type_number_t) \ | |
225 | (sizeof (arm_pagein_state_t)/sizeof(uint32_t))) | |
5ba3f43e A |
226 | |
227 | #define ARM_DEBUG_STATE64_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 228 | (sizeof (arm_debug_state64_t)/sizeof(uint32_t))) |
5ba3f43e A |
229 | |
230 | #define ARM_NEON_STATE_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 231 | (sizeof (arm_neon_state_t)/sizeof(uint32_t))) |
5ba3f43e A |
232 | |
233 | #define ARM_NEON_STATE64_COUNT ((mach_msg_type_number_t) \ | |
cb323159 A |
234 | (sizeof (arm_neon_state64_t)/sizeof(uint32_t))) |
235 | ||
236 | #define MACHINE_THREAD_STATE ARM_THREAD_STATE | |
237 | #define MACHINE_THREAD_STATE_COUNT ARM_UNIFIED_THREAD_STATE_COUNT | |
5ba3f43e | 238 | |
5ba3f43e A |
239 | |
240 | /* | |
241 | * Largest state on this machine: | |
242 | */ | |
cb323159 | 243 | #define THREAD_MACHINE_STATE_MAX THREAD_STATE_MAX |
5ba3f43e A |
244 | |
245 | #ifdef XNU_KERNEL_PRIVATE | |
246 | ||
247 | static inline boolean_t | |
248 | is_thread_state32(const arm_unified_thread_state_t *its) | |
249 | { | |
0a7de745 | 250 | return its->ash.flavor == ARM_THREAD_STATE32; |
5ba3f43e A |
251 | } |
252 | ||
253 | static inline boolean_t | |
254 | is_thread_state64(const arm_unified_thread_state_t *its) | |
255 | { | |
0a7de745 | 256 | return its->ash.flavor == ARM_THREAD_STATE64; |
5ba3f43e A |
257 | } |
258 | ||
259 | static inline arm_thread_state32_t* | |
260 | thread_state32(arm_unified_thread_state_t *its) | |
261 | { | |
262 | return &its->ts_32; | |
263 | } | |
264 | ||
265 | static inline arm_thread_state64_t* | |
266 | thread_state64(arm_unified_thread_state_t *its) | |
267 | { | |
268 | return &its->ts_64; | |
269 | } | |
270 | ||
271 | static inline const arm_thread_state32_t* | |
272 | const_thread_state32(const arm_unified_thread_state_t *its) | |
273 | { | |
274 | return &its->ts_32; | |
275 | } | |
276 | ||
277 | static inline const arm_thread_state64_t* | |
278 | const_thread_state64(const arm_unified_thread_state_t *its) | |
279 | { | |
280 | return &its->ts_64; | |
281 | } | |
282 | ||
283 | #if defined(__arm__) | |
284 | #include <arm/proc_reg.h> | |
285 | ||
cb323159 | 286 | #define ARM_SAVED_STATE (THREAD_STATE_NONE + 1) |
5ba3f43e | 287 | |
94ff46dc A |
288 | #if __ARM_VFP__ |
289 | #define VFPSAVE_ALIGN 16 | |
290 | #define VFPSAVE_ATTRIB __attribute__((aligned (VFPSAVE_ALIGN))) | |
291 | #define THREAD_ALIGN VFPSAVE_ALIGN | |
292 | ||
293 | /* | |
294 | * vector floating point saved state | |
295 | */ | |
296 | struct arm_vfpsaved_state { | |
297 | uint32_t r[64]; | |
298 | uint32_t fpscr; | |
299 | uint32_t fpexc; | |
300 | }; | |
301 | #endif | |
302 | ||
5ba3f43e | 303 | struct arm_saved_state { |
cb323159 A |
304 | uint32_t r[13]; /* General purpose register r0-r12 */ |
305 | uint32_t sp; /* Stack pointer r13 */ | |
306 | uint32_t lr; /* Link register r14 */ | |
307 | uint32_t pc; /* Program counter r15 */ | |
308 | uint32_t cpsr; /* Current program status register */ | |
309 | uint32_t fsr; /* Fault status */ | |
310 | uint32_t far; /* Virtual Fault Address */ | |
311 | uint32_t exception; /* exception number */ | |
94ff46dc A |
312 | |
313 | #if __ARM_VFP__ | |
314 | /* VFP state */ | |
315 | struct arm_vfpsaved_state VFPdata VFPSAVE_ATTRIB; | |
316 | // for packing reasons chtread_self and DebugData | |
317 | // are inside the the PcbData when __ARM_VFP__ is set | |
318 | arm_debug_state_t *VFPpadding_DebugData; | |
319 | vm_address_t VFPpadding_cthread_self; | |
320 | #endif | |
5ba3f43e A |
321 | }; |
322 | typedef struct arm_saved_state arm_saved_state_t; | |
323 | ||
324 | /* | |
325 | * Just for coexistence with AArch64 code. | |
326 | */ | |
327 | typedef struct arm_saved_state arm_saved_state32_t; | |
328 | ||
cb323159 A |
329 | static inline void |
330 | copy_signed_thread_state(arm_saved_state_t *dst, const arm_saved_state_t *src) | |
331 | { | |
332 | *dst = *src; | |
333 | } | |
334 | ||
5ba3f43e A |
335 | static inline arm_saved_state32_t* |
336 | saved_state32(arm_saved_state_t *iss) | |
337 | { | |
0a7de745 | 338 | return iss; |
5ba3f43e A |
339 | } |
340 | ||
341 | static inline boolean_t | |
342 | is_saved_state32(const arm_saved_state_t *iss __unused) | |
343 | { | |
0a7de745 | 344 | return TRUE; |
5ba3f43e A |
345 | } |
346 | ||
347 | ||
348 | struct arm_saved_state_tagged { | |
cb323159 A |
349 | uint32_t tag; |
350 | struct arm_saved_state state; | |
5ba3f43e A |
351 | }; |
352 | typedef struct arm_saved_state_tagged arm_saved_state_tagged_t; | |
353 | ||
354 | #define ARM_SAVED_STATE32_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 355 | (sizeof (arm_saved_state_t)/sizeof(unsigned int))) |
5ba3f43e A |
356 | |
357 | ||
358 | static inline register_t | |
359 | get_saved_state_pc(const arm_saved_state_t *iss) | |
360 | { | |
361 | return iss->pc; | |
362 | } | |
363 | ||
cb323159 A |
364 | static inline void |
365 | add_saved_state_pc(arm_saved_state_t *iss, int diff) | |
366 | { | |
f427ee49 | 367 | iss->pc += (unsigned int)diff; |
cb323159 A |
368 | } |
369 | ||
5ba3f43e A |
370 | static inline void |
371 | set_saved_state_pc(arm_saved_state_t *iss, register_t pc) | |
372 | { | |
f427ee49 | 373 | iss->pc = (typeof(iss->pc))pc; |
5ba3f43e A |
374 | } |
375 | ||
376 | static inline register_t | |
377 | get_saved_state_sp(const arm_saved_state_t *iss) | |
378 | { | |
379 | return iss->sp; | |
380 | } | |
381 | ||
382 | static inline void | |
383 | set_saved_state_sp(arm_saved_state_t *iss, register_t sp) | |
384 | { | |
385 | iss->sp = sp; | |
386 | } | |
387 | ||
388 | static inline register_t | |
389 | get_saved_state_fp(const arm_saved_state_t *iss) | |
390 | { | |
391 | return iss->r[7]; | |
392 | } | |
393 | ||
394 | static inline void | |
395 | set_saved_state_fp(arm_saved_state_t *iss, register_t fp) | |
396 | { | |
397 | iss->r[7] = fp; | |
398 | } | |
399 | ||
400 | static inline register_t | |
401 | get_saved_state_lr(const arm_saved_state_t *iss) | |
402 | { | |
f427ee49 | 403 | return (register_t)iss->lr; |
5ba3f43e A |
404 | } |
405 | ||
406 | static inline void | |
407 | set_saved_state_lr(arm_saved_state_t *iss, register_t lr) | |
408 | { | |
409 | iss->lr = lr; | |
410 | } | |
411 | ||
412 | static inline register_t | |
413 | get_saved_state_cpsr(const arm_saved_state_t *iss) | |
414 | { | |
415 | return iss->cpsr; | |
416 | } | |
417 | ||
cb323159 A |
418 | static inline void |
419 | mask_saved_state_cpsr(arm_saved_state_t *iss, uint32_t set_bits, uint32_t clear_bits) | |
420 | { | |
421 | iss->cpsr |= set_bits; | |
4ba76501 | 422 | iss->cpsr &= ~clear_bits; |
cb323159 A |
423 | } |
424 | ||
5ba3f43e A |
425 | static inline void |
426 | set_saved_state_cpsr(arm_saved_state_t *iss, register_t cpsr) | |
427 | { | |
428 | iss->cpsr = cpsr; | |
429 | } | |
430 | ||
431 | static inline register_t | |
432 | get_saved_state_reg(const arm_saved_state_t *iss, unsigned regno) | |
433 | { | |
434 | return iss->r[regno]; | |
435 | } | |
436 | ||
437 | static inline void | |
438 | set_saved_state_reg(arm_saved_state_t *iss, unsigned regno, register_t val) | |
439 | { | |
440 | iss->r[regno] = val; | |
441 | } | |
442 | ||
443 | #elif defined(__arm64__) | |
444 | ||
445 | #include <kern/assert.h> | |
446 | #include <arm64/proc_reg.h> | |
447 | #define CAST_ASSERT_SAFE(type, val) (assert((val) == ((type)(val))), (type)(val)) | |
448 | ||
449 | /* | |
450 | * GPR context | |
451 | */ | |
452 | ||
453 | struct arm_saved_state32 { | |
cb323159 A |
454 | uint32_t r[13]; /* General purpose register r0-r12 */ |
455 | uint32_t sp; /* Stack pointer r13 */ | |
456 | uint32_t lr; /* Link register r14 */ | |
457 | uint32_t pc; /* Program counter r15 */ | |
458 | uint32_t cpsr; /* Current program status register */ | |
459 | uint32_t far; /* Virtual fault address */ | |
460 | uint32_t esr; /* Exception syndrome register */ | |
461 | uint32_t exception; /* Exception number */ | |
5ba3f43e A |
462 | }; |
463 | typedef struct arm_saved_state32 arm_saved_state32_t; | |
464 | ||
465 | struct arm_saved_state32_tagged { | |
cb323159 A |
466 | uint32_t tag; |
467 | struct arm_saved_state32 state; | |
5ba3f43e A |
468 | }; |
469 | typedef struct arm_saved_state32_tagged arm_saved_state32_tagged_t; | |
470 | ||
471 | #define ARM_SAVED_STATE32_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 472 | (sizeof(arm_saved_state32_t)/sizeof(unsigned int))) |
5ba3f43e A |
473 | |
474 | struct arm_saved_state64 { | |
cb323159 A |
475 | uint64_t x[29]; /* General purpose registers x0-x28 */ |
476 | uint64_t fp; /* Frame pointer x29 */ | |
477 | uint64_t lr; /* Link register x30 */ | |
478 | uint64_t sp; /* Stack pointer x31 */ | |
479 | uint64_t pc; /* Program counter */ | |
480 | uint32_t cpsr; /* Current program status register */ | |
481 | uint32_t reserved; /* Reserved padding */ | |
482 | uint64_t far; /* Virtual fault address */ | |
483 | uint32_t esr; /* Exception syndrome register */ | |
484 | uint32_t exception; /* Exception number */ | |
485 | #if defined(HAS_APPLE_PAC) | |
486 | uint64_t jophash; | |
487 | #endif /* defined(HAS_APPLE_PAC) */ | |
5ba3f43e A |
488 | }; |
489 | typedef struct arm_saved_state64 arm_saved_state64_t; | |
490 | ||
491 | #define ARM_SAVED_STATE64_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 492 | (sizeof(arm_saved_state64_t)/sizeof(unsigned int))) |
5ba3f43e A |
493 | |
494 | struct arm_saved_state64_tagged { | |
cb323159 A |
495 | uint32_t tag; |
496 | struct arm_saved_state64 state; | |
5ba3f43e A |
497 | }; |
498 | typedef struct arm_saved_state64_tagged arm_saved_state64_tagged_t; | |
499 | ||
500 | struct arm_saved_state { | |
501 | arm_state_hdr_t ash; | |
502 | union { | |
503 | struct arm_saved_state32 ss_32; | |
504 | struct arm_saved_state64 ss_64; | |
505 | } uss; | |
506 | } __attribute__((aligned(16))); | |
cb323159 A |
507 | #define ss_32 uss.ss_32 |
508 | #define ss_64 uss.ss_64 | |
5ba3f43e A |
509 | |
510 | typedef struct arm_saved_state arm_saved_state_t; | |
511 | ||
f427ee49 A |
512 | struct arm_kernel_saved_state { |
513 | uint64_t x[12]; /* General purpose registers x16-x28 */ | |
514 | uint64_t fp; /* Frame pointer x29 */ | |
515 | uint64_t lr; /* Link register x30 */ | |
516 | uint64_t sp; /* Stack pointer x31 */ | |
517 | uint64_t pc; /* Program counter */ | |
518 | uint32_t cpsr; /* Current program status register */ | |
519 | uint32_t reserved; /* Reserved padding */ | |
520 | #if defined(HAS_APPLE_PAC) | |
521 | uint64_t jophash; | |
522 | #endif /* defined(HAS_APPLE_PAC) */ | |
523 | } __attribute__((aligned(16))); | |
524 | ||
525 | typedef struct arm_kernel_saved_state arm_kernel_saved_state_t; | |
526 | ||
cb323159 A |
527 | #if defined(XNU_KERNEL_PRIVATE) |
528 | #if defined(HAS_APPLE_PAC) | |
bca245ac A |
529 | |
530 | #include <sys/cdefs.h> | |
531 | ||
532 | /* | |
533 | * Used by MANIPULATE_SIGNED_THREAD_STATE(), potentially from C++ (IOKit) code. | |
534 | * Open-coded to prevent a circular dependency between mach/arm/thread_status.h | |
535 | * and osfmk/arm/machine_routines.h. | |
536 | */ | |
537 | __BEGIN_DECLS | |
538 | extern boolean_t ml_set_interrupts_enabled(boolean_t); | |
539 | __END_DECLS | |
540 | ||
cb323159 A |
541 | /* |
542 | * Methods used to sign and check thread state to detect corruptions of saved | |
543 | * thread state across exceptions and context switches. | |
544 | */ | |
545 | extern void ml_sign_thread_state(arm_saved_state_t *, uint64_t, uint32_t, uint64_t, uint64_t, uint64_t); | |
546 | ||
547 | extern void ml_check_signed_state(const arm_saved_state_t *, uint64_t, uint32_t, uint64_t, uint64_t, uint64_t); | |
548 | ||
549 | /* XXX: including stddef.f here breaks ctfmerge on some builds, so use __builtin_offsetof() instead of offsetof() */ | |
550 | #define ss64_offsetof(x) __builtin_offsetof(struct arm_saved_state, ss_64.x) | |
551 | ||
552 | /** | |
553 | * Verify the signed thread state in _iss, execute the assembly instructions | |
554 | * _instr, and re-sign the modified thread state. Varargs specify additional | |
555 | * inputs. | |
556 | * | |
557 | * _instr may read or modify the thread state in the following registers: | |
558 | * | |
559 | * x0: _iss | |
560 | * x1: authed _iss->ss_64.pc | |
561 | * w2: authed _iss->ss_64.cpsr | |
562 | * x3: authed _iss->ss_64.lr | |
563 | * x4: authed _iss->ss_64.x16 | |
564 | * x5: authed _iss->ss_64.x17 | |
565 | * x6: scratch register | |
566 | * x7: scratch register | |
567 | */ | |
bca245ac A |
568 | #define MANIPULATE_SIGNED_THREAD_STATE(_iss, _instr, ...) \ |
569 | do { \ | |
570 | boolean_t _intr = ml_set_interrupts_enabled(FALSE); \ | |
571 | asm volatile ( \ | |
572 | "mov x8, lr" "\n" \ | |
573 | "mov x0, %[iss]" "\n" \ | |
574 | "ldp x4, x5, [x0, %[SS64_X16]]" "\n" \ | |
575 | "ldr x6, [x0, %[SS64_PC]]" "\n" \ | |
576 | "ldr w7, [x0, %[SS64_CPSR]]" "\n" \ | |
577 | "ldr x3, [x0, %[SS64_LR]]" "\n" \ | |
578 | "mov x1, x6" "\n" \ | |
579 | "mov w2, w7" "\n" \ | |
580 | "bl _ml_check_signed_state" "\n" \ | |
581 | "mov x1, x6" "\n" \ | |
582 | "mov w2, w7" "\n" \ | |
583 | _instr "\n" \ | |
584 | "bl _ml_sign_thread_state" "\n" \ | |
585 | "mov lr, x8" "\n" \ | |
586 | : \ | |
587 | : [iss] "r"(_iss), \ | |
588 | [SS64_X16] "i"(ss64_offsetof(x[16])), \ | |
589 | [SS64_PC] "i"(ss64_offsetof(pc)), \ | |
590 | [SS64_CPSR] "i"(ss64_offsetof(cpsr)), \ | |
591 | [SS64_LR] "i"(ss64_offsetof(lr)),##__VA_ARGS__ \ | |
592 | : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8" \ | |
593 | ); \ | |
594 | ml_set_interrupts_enabled(_intr); \ | |
595 | } while (0) | |
cb323159 A |
596 | |
597 | static inline void | |
598 | check_and_sign_copied_thread_state(arm_saved_state_t *dst, const arm_saved_state_t *src) | |
599 | { | |
600 | MANIPULATE_SIGNED_THREAD_STATE(src, | |
601 | "mov x0, %[dst]", | |
602 | [dst] "r"(dst) | |
603 | ); | |
604 | } | |
605 | #endif /* defined(HAS_APPLE_PAC) */ | |
606 | ||
607 | static inline void | |
608 | copy_signed_thread_state(arm_saved_state_t *dst, const arm_saved_state_t *src) | |
609 | { | |
610 | *dst = *src; | |
611 | #if defined(HAS_APPLE_PAC) | |
612 | check_and_sign_copied_thread_state(dst, src); | |
613 | #endif | |
614 | } | |
615 | ||
616 | #endif /* defined(XNU_KERNEL_PRIVATE) */ | |
5ba3f43e A |
617 | |
618 | static inline boolean_t | |
619 | is_saved_state32(const arm_saved_state_t *iss) | |
620 | { | |
0a7de745 | 621 | return iss->ash.flavor == ARM_SAVED_STATE32; |
5ba3f43e A |
622 | } |
623 | ||
624 | static inline boolean_t | |
625 | is_saved_state64(const arm_saved_state_t *iss) | |
626 | { | |
0a7de745 | 627 | return iss->ash.flavor == ARM_SAVED_STATE64; |
5ba3f43e A |
628 | } |
629 | ||
630 | static inline arm_saved_state32_t* | |
631 | saved_state32(arm_saved_state_t *iss) | |
632 | { | |
633 | return &iss->ss_32; | |
634 | } | |
635 | ||
636 | static inline const arm_saved_state32_t* | |
637 | const_saved_state32(const arm_saved_state_t *iss) | |
638 | { | |
639 | return &iss->ss_32; | |
640 | } | |
641 | ||
642 | static inline arm_saved_state64_t* | |
643 | saved_state64(arm_saved_state_t *iss) | |
644 | { | |
645 | return &iss->ss_64; | |
646 | } | |
647 | ||
648 | static inline const arm_saved_state64_t* | |
649 | const_saved_state64(const arm_saved_state_t *iss) | |
650 | { | |
651 | return &iss->ss_64; | |
652 | } | |
653 | ||
654 | static inline register_t | |
655 | get_saved_state_pc(const arm_saved_state_t *iss) | |
656 | { | |
f427ee49 | 657 | return (register_t)(is_saved_state32(iss) ? const_saved_state32(iss)->pc : const_saved_state64(iss)->pc); |
5ba3f43e A |
658 | } |
659 | ||
cb323159 A |
660 | static inline void |
661 | add_saved_state_pc(arm_saved_state_t *iss, int diff) | |
662 | { | |
663 | if (is_saved_state32(iss)) { | |
f427ee49 | 664 | uint64_t pc = saved_state32(iss)->pc + (uint32_t)diff; |
cb323159 A |
665 | saved_state32(iss)->pc = CAST_ASSERT_SAFE(uint32_t, pc); |
666 | } else { | |
667 | #if defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) | |
668 | MANIPULATE_SIGNED_THREAD_STATE(iss, | |
669 | "mov w6, %w[diff] \n" | |
670 | "add x1, x1, w6, sxtw \n" | |
671 | "str x1, [x0, %[SS64_PC]] \n", | |
672 | [diff] "r"(diff) | |
673 | ); | |
674 | #else | |
f427ee49 | 675 | saved_state64(iss)->pc += (unsigned long)diff; |
cb323159 A |
676 | #endif /* defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) */ |
677 | } | |
678 | } | |
679 | ||
5ba3f43e A |
680 | static inline void |
681 | set_saved_state_pc(arm_saved_state_t *iss, register_t pc) | |
682 | { | |
683 | if (is_saved_state32(iss)) { | |
684 | saved_state32(iss)->pc = CAST_ASSERT_SAFE(uint32_t, pc); | |
685 | } else { | |
cb323159 A |
686 | #if defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) |
687 | MANIPULATE_SIGNED_THREAD_STATE(iss, | |
688 | "mov x1, %[pc] \n" | |
689 | "str x1, [x0, %[SS64_PC]] \n", | |
690 | [pc] "r"(pc) | |
691 | ); | |
692 | #else | |
f427ee49 | 693 | saved_state64(iss)->pc = (unsigned long)pc; |
cb323159 | 694 | #endif /* defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) */ |
5ba3f43e A |
695 | } |
696 | } | |
697 | ||
698 | static inline register_t | |
699 | get_saved_state_sp(const arm_saved_state_t *iss) | |
700 | { | |
f427ee49 | 701 | return (register_t)(is_saved_state32(iss) ? const_saved_state32(iss)->sp : const_saved_state64(iss)->sp); |
5ba3f43e A |
702 | } |
703 | ||
704 | static inline void | |
705 | set_saved_state_sp(arm_saved_state_t *iss, register_t sp) | |
706 | { | |
707 | if (is_saved_state32(iss)) { | |
708 | saved_state32(iss)->sp = CAST_ASSERT_SAFE(uint32_t, sp); | |
709 | } else { | |
f427ee49 | 710 | saved_state64(iss)->sp = (uint64_t)sp; |
5ba3f43e A |
711 | } |
712 | } | |
713 | ||
714 | static inline register_t | |
715 | get_saved_state_lr(const arm_saved_state_t *iss) | |
716 | { | |
f427ee49 | 717 | return (register_t)(is_saved_state32(iss) ? const_saved_state32(iss)->lr : const_saved_state64(iss)->lr); |
5ba3f43e A |
718 | } |
719 | ||
720 | static inline void | |
721 | set_saved_state_lr(arm_saved_state_t *iss, register_t lr) | |
722 | { | |
723 | if (is_saved_state32(iss)) { | |
724 | saved_state32(iss)->lr = CAST_ASSERT_SAFE(uint32_t, lr); | |
725 | } else { | |
cb323159 A |
726 | #if defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) |
727 | MANIPULATE_SIGNED_THREAD_STATE(iss, | |
728 | "mov x3, %[lr] \n" | |
729 | "str x3, [x0, %[SS64_LR]] \n", | |
730 | [lr] "r"(lr) | |
731 | ); | |
732 | #else | |
f427ee49 | 733 | saved_state64(iss)->lr = (unsigned long)lr; |
cb323159 | 734 | #endif /* defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) */ |
5ba3f43e A |
735 | } |
736 | } | |
737 | ||
738 | static inline register_t | |
739 | get_saved_state_fp(const arm_saved_state_t *iss) | |
740 | { | |
f427ee49 | 741 | return (register_t)(is_saved_state32(iss) ? const_saved_state32(iss)->r[7] : const_saved_state64(iss)->fp); |
5ba3f43e A |
742 | } |
743 | ||
744 | static inline void | |
745 | set_saved_state_fp(arm_saved_state_t *iss, register_t fp) | |
746 | { | |
747 | if (is_saved_state32(iss)) { | |
748 | saved_state32(iss)->r[7] = CAST_ASSERT_SAFE(uint32_t, fp); | |
749 | } else { | |
f427ee49 | 750 | saved_state64(iss)->fp = (uint64_t)fp; |
5ba3f43e A |
751 | } |
752 | } | |
753 | ||
754 | static inline int | |
0a7de745 | 755 | check_saved_state_reglimit(const arm_saved_state_t *iss, unsigned reg) |
5ba3f43e | 756 | { |
0a7de745 | 757 | return is_saved_state32(iss) ? (reg < ARM_SAVED_STATE32_COUNT) : (reg < ARM_SAVED_STATE64_COUNT); |
5ba3f43e A |
758 | } |
759 | ||
760 | static inline register_t | |
761 | get_saved_state_reg(const arm_saved_state_t *iss, unsigned reg) | |
762 | { | |
0a7de745 A |
763 | if (!check_saved_state_reglimit(iss, reg)) { |
764 | return 0; | |
765 | } | |
5ba3f43e | 766 | |
f427ee49 | 767 | return (register_t)(is_saved_state32(iss) ? (const_saved_state32(iss)->r[reg]) : (const_saved_state64(iss)->x[reg])); |
5ba3f43e A |
768 | } |
769 | ||
770 | static inline void | |
771 | set_saved_state_reg(arm_saved_state_t *iss, unsigned reg, register_t value) | |
772 | { | |
0a7de745 A |
773 | if (!check_saved_state_reglimit(iss, reg)) { |
774 | return; | |
775 | } | |
5ba3f43e A |
776 | |
777 | if (is_saved_state32(iss)) { | |
778 | saved_state32(iss)->r[reg] = CAST_ASSERT_SAFE(uint32_t, value); | |
779 | } else { | |
cb323159 A |
780 | #if defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) |
781 | /* x16 and x17 are part of the jophash */ | |
782 | if (reg == 16) { | |
783 | MANIPULATE_SIGNED_THREAD_STATE(iss, | |
784 | "mov x4, %[value] \n" | |
785 | "str x4, [x0, %[SS64_X16]] \n", | |
786 | [value] "r"(value) | |
787 | ); | |
788 | return; | |
789 | } else if (reg == 17) { | |
790 | MANIPULATE_SIGNED_THREAD_STATE(iss, | |
791 | "mov x5, %[value] \n" | |
792 | "str x5, [x0, %[SS64_X17]] \n", | |
793 | [value] "r"(value), | |
794 | [SS64_X17] "i"(ss64_offsetof(x[17])) | |
795 | ); | |
796 | return; | |
797 | } | |
798 | #endif | |
f427ee49 | 799 | saved_state64(iss)->x[reg] = (uint64_t)value; |
5ba3f43e A |
800 | } |
801 | } | |
802 | ||
f427ee49 | 803 | |
5ba3f43e A |
804 | static inline uint32_t |
805 | get_saved_state_cpsr(const arm_saved_state_t *iss) | |
806 | { | |
0a7de745 | 807 | return is_saved_state32(iss) ? const_saved_state32(iss)->cpsr : const_saved_state64(iss)->cpsr; |
5ba3f43e A |
808 | } |
809 | ||
cb323159 A |
810 | static inline void |
811 | mask_saved_state_cpsr(arm_saved_state_t *iss, uint32_t set_bits, uint32_t clear_bits) | |
812 | { | |
813 | if (is_saved_state32(iss)) { | |
814 | saved_state32(iss)->cpsr |= set_bits; | |
815 | saved_state32(iss)->cpsr &= ~clear_bits; | |
816 | } else { | |
817 | #if defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) | |
818 | MANIPULATE_SIGNED_THREAD_STATE(iss, | |
819 | "mov w6, %w[set_bits] \n" | |
820 | "orr w2, w2, w6, lsl #0 \n" | |
821 | "mov w6, %w[clear_bits] \n" | |
822 | "bic w2, w2, w6, lsl #0 \n" | |
823 | "str w2, [x0, %[SS64_CPSR]] \n", | |
824 | [set_bits] "r"(set_bits), | |
825 | [clear_bits] "r"(clear_bits) | |
826 | ); | |
827 | #else | |
828 | saved_state64(iss)->cpsr |= set_bits; | |
829 | saved_state64(iss)->cpsr &= ~clear_bits; | |
830 | #endif /* defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) */ | |
831 | } | |
832 | } | |
833 | ||
5ba3f43e A |
834 | static inline void |
835 | set_saved_state_cpsr(arm_saved_state_t *iss, uint32_t cpsr) | |
836 | { | |
837 | if (is_saved_state32(iss)) { | |
838 | saved_state32(iss)->cpsr = cpsr; | |
839 | } else { | |
cb323159 A |
840 | #if defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) |
841 | MANIPULATE_SIGNED_THREAD_STATE(iss, | |
842 | "mov w2, %w[cpsr] \n" | |
843 | "str w2, [x0, %[SS64_CPSR]] \n", | |
844 | [cpsr] "r"(cpsr) | |
845 | ); | |
846 | #else | |
5ba3f43e | 847 | saved_state64(iss)->cpsr = cpsr; |
cb323159 | 848 | #endif /* defined(XNU_KERNEL_PRIVATE) && defined(HAS_APPLE_PAC) */ |
5ba3f43e A |
849 | } |
850 | } | |
851 | ||
852 | static inline register_t | |
853 | get_saved_state_far(const arm_saved_state_t *iss) | |
854 | { | |
f427ee49 | 855 | return (register_t)(is_saved_state32(iss) ? const_saved_state32(iss)->far : const_saved_state64(iss)->far); |
5ba3f43e A |
856 | } |
857 | ||
858 | static inline void | |
859 | set_saved_state_far(arm_saved_state_t *iss, register_t far) | |
860 | { | |
861 | if (is_saved_state32(iss)) { | |
862 | saved_state32(iss)->far = CAST_ASSERT_SAFE(uint32_t, far); | |
863 | } else { | |
f427ee49 | 864 | saved_state64(iss)->far = (uint64_t)far; |
5ba3f43e A |
865 | } |
866 | } | |
867 | ||
868 | static inline uint32_t | |
869 | get_saved_state_esr(const arm_saved_state_t *iss) | |
870 | { | |
0a7de745 | 871 | return is_saved_state32(iss) ? const_saved_state32(iss)->esr : const_saved_state64(iss)->esr; |
5ba3f43e A |
872 | } |
873 | ||
874 | static inline void | |
875 | set_saved_state_esr(arm_saved_state_t *iss, uint32_t esr) | |
876 | { | |
877 | if (is_saved_state32(iss)) { | |
878 | saved_state32(iss)->esr = esr; | |
879 | } else { | |
880 | saved_state64(iss)->esr = esr; | |
881 | } | |
882 | } | |
883 | ||
884 | static inline uint32_t | |
885 | get_saved_state_exc(const arm_saved_state_t *iss) | |
886 | { | |
0a7de745 | 887 | return is_saved_state32(iss) ? const_saved_state32(iss)->exception : const_saved_state64(iss)->exception; |
5ba3f43e A |
888 | } |
889 | ||
890 | static inline void | |
891 | set_saved_state_exc(arm_saved_state_t *iss, uint32_t exc) | |
892 | { | |
893 | if (is_saved_state32(iss)) { | |
894 | saved_state32(iss)->exception = exc; | |
895 | } else { | |
896 | saved_state64(iss)->exception = exc; | |
897 | } | |
898 | } | |
899 | ||
900 | extern void panic_unimplemented(void); | |
901 | ||
902 | static inline int | |
0a7de745 | 903 | get_saved_state_svc_number(const arm_saved_state_t *iss) |
5ba3f43e | 904 | { |
0a7de745 | 905 | return is_saved_state32(iss) ? (int)const_saved_state32(iss)->r[12] : (int)const_saved_state64(iss)->x[ARM64_SYSCALL_CODE_REG_NUM]; /* Only first word counts here */ |
5ba3f43e A |
906 | } |
907 | ||
cb323159 | 908 | typedef _STRUCT_ARM_LEGACY_DEBUG_STATE arm_legacy_debug_state_t; |
5ba3f43e A |
909 | |
910 | struct arm_debug_aggregate_state { | |
cb323159 | 911 | arm_state_hdr_t dsh; |
0a7de745 A |
912 | union { |
913 | arm_debug_state32_t ds32; | |
914 | arm_debug_state64_t ds64; | |
915 | } uds; | |
5ba3f43e A |
916 | } __attribute__((aligned(16))); |
917 | ||
918 | typedef struct arm_debug_aggregate_state arm_debug_state_t; | |
919 | ||
920 | #define ARM_LEGACY_DEBUG_STATE_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 921 | (sizeof (arm_legacy_debug_state_t)/sizeof(uint32_t))) |
5ba3f43e A |
922 | |
923 | /* | |
924 | * NEON context | |
925 | */ | |
926 | typedef __uint128_t uint128_t; | |
927 | typedef uint64_t uint64x2_t __attribute__((ext_vector_type(2))); | |
928 | typedef uint32_t uint32x4_t __attribute__((ext_vector_type(4))); | |
929 | ||
930 | struct arm_neon_saved_state32 { | |
931 | union { | |
cb323159 A |
932 | uint128_t q[16]; |
933 | uint64_t d[32]; | |
934 | uint32_t s[32]; | |
5ba3f43e | 935 | } v; |
cb323159 A |
936 | uint32_t fpsr; |
937 | uint32_t fpcr; | |
5ba3f43e A |
938 | }; |
939 | typedef struct arm_neon_saved_state32 arm_neon_saved_state32_t; | |
940 | ||
941 | #define ARM_NEON_SAVED_STATE32_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 942 | (sizeof (arm_neon_saved_state32_t)/sizeof(unsigned int))) |
5ba3f43e A |
943 | |
944 | struct arm_neon_saved_state64 { | |
945 | union { | |
cb323159 A |
946 | uint128_t q[32]; |
947 | uint64x2_t d[32]; | |
948 | uint32x4_t s[32]; | |
5ba3f43e | 949 | } v; |
cb323159 A |
950 | uint32_t fpsr; |
951 | uint32_t fpcr; | |
5ba3f43e A |
952 | }; |
953 | typedef struct arm_neon_saved_state64 arm_neon_saved_state64_t; | |
954 | ||
955 | #define ARM_NEON_SAVED_STATE64_COUNT ((mach_msg_type_number_t) \ | |
cb323159 | 956 | (sizeof (arm_neon_saved_state64_t)/sizeof(unsigned int))) |
5ba3f43e A |
957 | |
958 | struct arm_neon_saved_state { | |
959 | arm_state_hdr_t nsh; | |
960 | union { | |
961 | struct arm_neon_saved_state32 ns_32; | |
962 | struct arm_neon_saved_state64 ns_64; | |
963 | } uns; | |
964 | }; | |
965 | typedef struct arm_neon_saved_state arm_neon_saved_state_t; | |
cb323159 A |
966 | #define ns_32 uns.ns_32 |
967 | #define ns_64 uns.ns_64 | |
5ba3f43e | 968 | |
f427ee49 A |
969 | struct arm_kernel_neon_saved_state { |
970 | uint64_t d[8]; | |
971 | uint32_t fpcr; | |
972 | }; | |
973 | typedef struct arm_kernel_neon_saved_state arm_kernel_neon_saved_state_t; | |
974 | ||
5ba3f43e A |
975 | static inline boolean_t |
976 | is_neon_saved_state32(const arm_neon_saved_state_t *state) | |
977 | { | |
0a7de745 | 978 | return state->nsh.flavor == ARM_NEON_SAVED_STATE32; |
5ba3f43e A |
979 | } |
980 | ||
981 | static inline boolean_t | |
982 | is_neon_saved_state64(const arm_neon_saved_state_t *state) | |
983 | { | |
0a7de745 | 984 | return state->nsh.flavor == ARM_NEON_SAVED_STATE64; |
5ba3f43e A |
985 | } |
986 | ||
987 | static inline arm_neon_saved_state32_t * | |
988 | neon_state32(arm_neon_saved_state_t *state) | |
989 | { | |
990 | return &state->ns_32; | |
991 | } | |
992 | ||
993 | static inline arm_neon_saved_state64_t * | |
994 | neon_state64(arm_neon_saved_state_t *state) | |
995 | { | |
996 | return &state->ns_64; | |
997 | } | |
998 | ||
999 | ||
1000 | /* | |
1001 | * Aggregated context | |
1002 | */ | |
1003 | ||
1004 | struct arm_context { | |
1005 | struct arm_saved_state ss; | |
1006 | struct arm_neon_saved_state ns; | |
1007 | }; | |
1008 | typedef struct arm_context arm_context_t; | |
1009 | ||
f427ee49 A |
1010 | struct arm_kernel_context { |
1011 | struct arm_kernel_saved_state ss; | |
1012 | struct arm_kernel_neon_saved_state ns; | |
1013 | }; | |
1014 | typedef struct arm_kernel_context arm_kernel_context_t; | |
1015 | ||
5ba3f43e A |
1016 | extern void saved_state_to_thread_state64(const arm_saved_state_t*, arm_thread_state64_t*); |
1017 | extern void thread_state64_to_saved_state(const arm_thread_state64_t*, arm_saved_state_t*); | |
1018 | ||
cb323159 | 1019 | #else /* defined(__arm__) */ |
5ba3f43e | 1020 | #error Unknown arch |
cb323159 | 1021 | #endif /* defined(__arm__) */ |
5ba3f43e A |
1022 | |
1023 | extern void saved_state_to_thread_state32(const arm_saved_state_t*, arm_thread_state32_t*); | |
1024 | extern void thread_state32_to_saved_state(const arm_thread_state32_t*, arm_saved_state_t*); | |
1025 | ||
1026 | #endif /* XNU_KERNEL_PRIVATE */ | |
1027 | ||
cb323159 | 1028 | #endif /* _ARM_THREAD_STATUS_H_ */ |