VirtualBox

source: vbox/trunk/include/iprt/asm-arm.h@ 106880

Last change on this file since 106880 was 106672, checked in by vboxsync, 5 weeks ago

iprt/asm-arm.h: Added ASMGetThreadIdRoEL0. [scm fix] jiraref:VBP-1253

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/** @file
2 * IPRT - ARM Specific Assembly Functions.
3 */
4
5/*
6 * Copyright (C) 2015-2024 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35
36#ifndef IPRT_INCLUDED_asm_arm_h
37#define IPRT_INCLUDED_asm_arm_h
38#ifndef RT_WITHOUT_PRAGMA_ONCE
39# pragma once
40#endif
41
42#include <iprt/types.h>
43#if !defined(RT_ARCH_ARM64) && !defined(RT_ARCH_ARM32)
44# error "Not on ARM64 or ARM32"
45#endif
46
47#if defined(_MSC_VER) && RT_INLINE_ASM_USES_INTRIN
48/* Emit the intrinsics at all optimization levels. */
49# include <iprt/sanitized/intrin.h>
50# pragma intrinsic(_ReadStatusReg)
51# pragma intrinsic(_WriteStatusReg)
52# pragma intrinsic(_disable)
53# pragma intrinsic(_enable)
54# pragma intrinsic(__hvc)
55
56/*
57 * MSVC insists on having these defined using ARM64_SYSREG or it will
58 * fail to compile with "error C2284: "_ReadStatusReg": invalid argument for internal function, parameter 1"
59 * if we use our own definitions from iprt/armv8.h
60 *
61 * The reason for this, is that ARM64_SYSREG masks off the top bit (bit 15)
62 * whereas our macro doesn't. So the reason is probably the implicitness
63 * of the top bit in the MRS/MSR encoding.
64 */
65# define ARM64_SYSREG_DAIF ARM64_SYSREG(3, 3, 4, 2, 1)
66# define ARM64_SYSREG_CNTFRQ_EL0 ARM64_SYSREG(3, 3, 14, 0, 0)
67# define ARM64_SYSREG_CNTCVT_EL0 ARM64_SYSREG(3, 3, 14, 0, 2)
68# define ARM64_SYSREG_TPIDRRO_EL0 ARM64_SYSREG(3, 3, 13, 0, 3)
69#endif
70
71/** @defgroup grp_rt_asm_arm ARM Specific ASM Routines
72 * @ingroup grp_rt_asm
73 * @{
74 */
75
76/**
77 * Gets the content of the CNTVCT_EL0 (or CNTPCT) register.
78 *
79 * @returns CNTVCT_EL0 value.
80 * @note We call this TSC to better fit in with existing x86/amd64 based code.
81 */
82#if RT_INLINE_ASM_EXTERNAL
83DECLASM(uint64_t) ASMReadTSC(void);
84#else
85DECLINLINE(uint64_t) ASMReadTSC(void)
86{
87# if RT_INLINE_ASM_GNU_STYLE
88 uint64_t u64;
89# ifdef RT_ARCH_ARM64
90 __asm__ __volatile__("Lstart_ASMReadTSC_%=:\n\t"
91 "isb\n\t"
92 "mrs %0, CNTVCT_EL0\n\t"
93 : "=r" (u64));
94# else
95 uint32_t u32Spill;
96 uint32_t u32Comp;
97 __asm__ __volatile__("Lstart_ASMReadTSC_%=:\n\t"
98 "isb\n"
99 "Ltry_again_ASMReadTSC_%=:\n\t"
100 "mrrc p15, 0, %[uSpill], %H[uRet], c14\n\t" /* CNTPCT high into uRet.hi */
101 "mrrc p15, 0, %[uRet], %[uSpill], c14\n\t" /* CNTPCT low into uRet.lo */
102 "mrrc p15, 0, %[uSpill], %[uHiComp], c14\n\t" /* CNTPCT high into uHiComp */
103 "cmp %H[uRet], %[uHiComp]\n\t"
104 "b.eq Ltry_again_ASMReadTSC_%=\n\t" /* Redo if high value changed. */
105 : [uRet] "=r" (u64)
106 , "=r" (uHiComp)
107 , "=r" (uSpill));
108# endif
109 return u64;
110
111#elif RT_INLINE_ASM_USES_INTRIN
112 return (uint64_t)_ReadStatusReg(ARM64_SYSREG_CNTCVT_EL0);
113# else
114# error "Unsupported compiler"
115# endif
116}
117#endif
118
119
120/**
121 * Gets the content of the CNTFRQ_EL0 register.
122 *
123 * @returns CNTFRQ_EL0 value.
124 */
125#if RT_INLINE_ASM_EXTERNAL
126DECLASM(uint64_t) ASMReadCntFrqEl0(void);
127#else
128DECLINLINE(uint64_t) ASMReadCntFrqEl0(void)
129{
130# if RT_INLINE_ASM_GNU_STYLE
131 uint64_t u64;
132# ifdef RT_ARCH_ARM64
133 __asm__ __volatile__("Lstart_ASMReadCntFrqEl0_%=:\n\t"
134 "isb\n\t"
135 "mrs %0, CNTFRQ_EL0\n\t"
136 : "=r" (u64));
137# else
138 u64 = 0;
139 __asm__ __volatile__("Lstart_ASMReadCntFrqEl0_%=:\n\t"
140 "isb\n\t"
141 "mrc p15, 0, %[uRet], c14, 0, 0\n\t" /* CNTFRQ */
142 : [uRet] "=r" (u64));
143# endif
144 return u64;
145
146#elif RT_INLINE_ASM_USES_INTRIN
147 return (uint64_t)_ReadStatusReg(ARM64_SYSREG_CNTFRQ_EL0);
148# else
149# error "Unsupported compiler"
150# endif
151}
152#endif
153
154
155/**
156 * Enables interrupts (IRQ and FIQ).
157 */
158#if RT_INLINE_ASM_EXTERNAL
159DECLASM(void) ASMIntEnable(void);
160#else
161DECLINLINE(void) ASMIntEnable(void)
162{
163# if RT_INLINE_ASM_GNU_STYLE
164# ifdef RT_ARCH_ARM64
165 __asm__ __volatile__("Lstart_ASMIntEnable_%=:\n\t"
166 "msr daifclr, #0xf\n\t");
167# else
168 RTCCUINTREG uFlags;
169 __asm__ __volatile__("Lstart_ASMIntEnable_%=:\n\t"
170 "mrs %0, cpsr\n\t"
171 "bic %0, %0, #0xc0\n\t"
172 "msr cpsr_c, %0\n\t"
173 : "=r" (uFlags));
174# endif
175# elif RT_INLINE_ASM_USES_INTRIN
176 _enable();
177# else
178# error "Unsupported compiler"
179# endif
180}
181#endif
182
183
184/**
185 * Disables interrupts (IRQ and FIQ).
186 */
187#if RT_INLINE_ASM_EXTERNAL
188DECLASM(void) ASMIntDisable(void);
189#else
190DECLINLINE(void) ASMIntDisable(void)
191{
192# if RT_INLINE_ASM_GNU_STYLE
193# ifdef RT_ARCH_ARM64
194 __asm__ __volatile__("Lstart_ASMIntDisable_%=:\n\t"
195 "msr daifset, #0xf\n\t");
196# else
197 RTCCUINTREG uFlags;
198 __asm__ __volatile__("Lstart_ASMIntDisable_%=:\n\t"
199 "mrs %0, cpsr\n\t"
200 "orr %0, %0, #0xc0\n\t"
201 "msr cpsr_c, %0\n\t"
202 : "=r" (uFlags));
203# endif
204# elif RT_INLINE_ASM_USES_INTRIN
205 _disable();
206# else
207# error "Unsupported compiler"
208# endif
209}
210#endif
211
212
213/**
214 * Disables interrupts and returns previous uFLAGS.
215 */
216#if RT_INLINE_ASM_EXTERNAL
217DECLASM(RTCCUINTREG) ASMIntDisableFlags(void);
218#else
219DECLINLINE(RTCCUINTREG) ASMIntDisableFlags(void)
220{
221 RTCCUINTREG uFlags;
222# if RT_INLINE_ASM_GNU_STYLE
223# ifdef RT_ARCH_ARM64
224 __asm__ __volatile__("Lstart_ASMIntDisableFlags_%=:\n\t"
225 "mrs %[uRet], daif\n\t"
226 "msr daifset, #0xf\n\t"
227 : [uRet] "=r" (uFlags));
228# else
229 RTCCUINTREG uNewFlags;
230 __asm__ __volatile__("Lstart_ASMIntDisableFlags_%=:\n\t"
231 "mrs %0, cpsr\n\t"
232 "orr %1, %0, #0xc0\n\t"
233 "msr cpsr_c, %1\n\t"
234 : "=r" (uFlags)
235 , "=r" (uNewFlags));
236# endif
237# elif RT_INLINE_ASM_USES_INTRIN
238 uFlags = _ReadStatusReg(ARM64_SYSREG_DAIF);
239 _disable();
240# else
241# error "Unsupported compiler"
242# endif
243 return uFlags;
244}
245#endif
246
247
248/**
249 * Get the CPSR/PSTATE register.
250 * @returns CPSR/PSTATE.
251 */
252#if RT_INLINE_ASM_EXTERNAL
253DECLASM(RTCCUINTREG) ASMGetFlags(void);
254#else
255DECLINLINE(RTCCUINTREG) ASMGetFlags(void)
256{
257 RTCCUINTREG uFlags;
258# if RT_INLINE_ASM_GNU_STYLE
259# ifdef RT_ARCH_ARM64
260 __asm__ __volatile__("Lstart_ASMGetFlags_%=:\n\t"
261 "isb\n\t"
262 "mrs %0, daif\n\t"
263 : "=r" (uFlags));
264# else
265# error "Implementation required for arm32"
266# endif
267# elif RT_INLINE_ASM_USES_INTRIN
268 uFlags = _ReadStatusReg(ARM64_SYSREG_DAIF);
269# else
270# error "Unsupported compiler"
271# endif
272 return uFlags;
273}
274#endif
275
276
277/**
278 * Get the CPSR/PSTATE register.
279 */
280#if RT_INLINE_ASM_EXTERNAL
281DECLASM(void) ASMSetFlags(RTCCUINTREG uFlags);
282#else
283DECLINLINE(void) ASMSetFlags(RTCCUINTREG uFlags)
284{
285# if RT_INLINE_ASM_GNU_STYLE
286# ifdef RT_ARCH_ARM64
287 __asm__ __volatile__("Lstart_ASMSetFlags_%=:\n\t"
288 "isb\n\t"
289 "msr daif, %[uFlags]\n\t"
290 : : [uFlags] "r" (uFlags));
291# else
292# error "Implementation required for arm32"
293# endif
294# elif RT_INLINE_ASM_USES_INTRIN
295 _WriteStatusReg(ARM64_SYSREG_DAIF, uFlags);
296# else
297# error "Unsupported compiler"
298# endif
299}
300#endif
301
302
303/**
304 * Are interrupts enabled?
305 *
306 * @returns true / false.
307 */
308DECLINLINE(bool) ASMIntAreEnabled(void)
309{
310 return ASMGetFlags() & 0xc0 /* IRQ and FIQ bits */ ? true : false;
311}
312
313
314#if 0 /* Later */
315/**
316 * Issue HVC call with a single argument.
317 */
318#if RT_INLINE_ASM_EXTERNAL
319DECLASM(void) ASMHvc(uint16_t u16Imm, uint32_t u32Arg0);
320#else
321DECLINLINE(void) ASMHvc(uint16_t u16Imm, uint32_t u32Arg0)
322{
323# if RT_INLINE_ASM_GNU_STYLE
324# error "Later"
325# elif RT_INLINE_ASM_USES_INTRIN
326 __hvc(u16Imm, u32Val);
327# else
328# error "Unsupported compiler"
329# endif
330}
331#endif
332#endif
333
334
335/**
336 * Halts the CPU until interrupted.
337 */
338#if RT_INLINE_ASM_EXTERNAL || defined(_MSC_VER)
339DECLASM(void) ASMHalt(void);
340#else
341DECLINLINE(void) ASMHalt(void)
342{
343# if RT_INLINE_ASM_GNU_STYLE
344 __asm__ __volatile__ ("Lstart_ASMHalt_%=:\n\t"
345 "wfi\n\t"); /* wait for interrupt */
346# else
347# error "Unsupported compiler"
348# endif
349}
350#endif
351
352#if 0
353/**
354 * Gets the CPU ID of the current CPU.
355 *
356 * @returns the CPU ID.
357 * @note the name of this method is a bit misleading but serves the purpose
358 * and prevents #ifdef orgies in other places.
359 */
360#if RT_INLINE_ASM_EXTERNAL
361DECLASM(uint8_t) ASMGetApicId(void);
362#else
363DECLINLINE(uint8_t) ASMGetApicId(void)
364{
365# if RT_INLINE_ASM_GNU_STYLE
366 RTCCUINTREG uCpuId;
367 __asm__ ("Lstart_ASMGetApicId_%=:\n\t"
368 "mrc p15, 0, %0, c0, c0, 5\n\t" /* CPU ID Register, privileged */
369 : "=r" (uCpuId));
370 return uCpuId;
371# else
372# error "Unsupported compiler"
373# endif
374}
375#endif
376#endif
377
378#if 0
379
380/**
381 * Invalidate page.
382 *
383 * @param pv Address of the page to invalidate.
384 */
385#if RT_INLINE_ASM_EXTERNAL
386DECLASM(void) ASMInvalidatePage(void *pv);
387#else
388DECLINLINE(void) ASMInvalidatePage(void *pv)
389{
390# if RT_INLINE_ASM_GNU_STYLE
391
392# else
393# error "Unsupported compiler"
394# endif
395}
396#endif
397
398
399/**
400 * Write back the internal caches and invalidate them.
401 */
402#if RT_INLINE_ASM_EXTERNAL
403DECLASM(void) ASMWriteBackAndInvalidateCaches(void);
404#else
405DECLINLINE(void) ASMWriteBackAndInvalidateCaches(void)
406{
407# if RT_INLINE_ASM_GNU_STYLE
408
409# else
410# error "Unsupported compiler"
411# endif
412}
413#endif
414
415
416/**
417 * Invalidate internal and (perhaps) external caches without first
418 * flushing dirty cache lines. Use with extreme care.
419 */
420#if RT_INLINE_ASM_EXTERNAL
421DECLASM(void) ASMInvalidateInternalCaches(void);
422#else
423DECLINLINE(void) ASMInvalidateInternalCaches(void)
424{
425# if RT_INLINE_ASM_GNU_STYLE
426
427# else
428# error "Unsupported compiler"
429# endif
430}
431#endif
432
433#endif
434
435
436/**
437 * Get the TPIDRRO_EL0 register.
438 */
439#if RT_INLINE_ASM_EXTERNAL
440DECLASM(RTCCUINTREG) ASMGetThreadIdRoEL0(void);
441#else
442DECLINLINE(RTCCUINTREG) ASMGetThreadIdRoEL0(void)
443{
444# if RT_INLINE_ASM_GNU_STYLE
445 RTCCUINTREG uRet;
446# ifdef RT_ARCH_ARM64
447 __asm__ __volatile__("Lstart_ASMGetThreadIdEl0_%=:\n\t"
448 "mrs %[uRet], TPIDRRO_EL0\n\t"
449 : [uRet] "=r" (uRet));
450# else
451 __asm__ __volatile__("Lstart_ASMGetThreadIdEl0_%=:\n\t"
452 "mrc p15, 0, %[uRet], c13, c0, 3\n\t" /* TPIDRURO */
453 : [uRet] "=r" (uRet));
454# endif
455 return uRet;
456# elif RT_INLINE_ASM_USES_INTRIN
457 return _ReadStatusReg(ARM64_SYSREG_TPIDRRO_EL0);
458# else
459# error "Unsupported compiler"
460# endif
461}
462#endif
463
464
465/** @} */
466#endif /* !IPRT_INCLUDED_asm_arm_h */
467
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette