1/*
2 * Copyright 2013, winocm. <winocm@icloud.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 *   Redistributions of source code must retain the above copyright notice, this
9 *   list of conditions and the following disclaimer.
10 *
11 *   Redistributions in binary form must reproduce the above copyright notice, this
12 *   list of conditions and the following disclaimer in the documentation and/or
13 *   other materials provided with the distribution.
14 *
15 *   If you are going to use this software in any form that does not involve
16 *   releasing the source to this project or improving it, let me know beforehand.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29/*
30 * Shouldn't we use mach/arm/asm.h instead? Just wondering.
31 */
32/*
33 * ASM helper functions
34 */
35
36#ifndef _ARM_ASM_HELP_H_
37#define _ARM_ASM_HELP_H_
38
39#include <arm/arch.h>
40
41/*
42 * LLVM-AS is a horrible sin upon humanity.
43 */
44#define LoadConstantToReg(_Data, _Reg)  \
45  ldr  _Reg, [pc, #0]   ;               \
46  b    1f               ;               \
47  .long (_Data)         ;               \
481:
49
50/*
51 * Procedure enter and exit for both ARM and thumb states.
52 */
53#define EnterARM(function)              \
54    .code 32                        ;   \
55    .globl _ ##function             ;   \
56    .align  4                       ;   \
57    _##function:                    ;   \
58
59#define EnterThumb(function)        ;   \
60    .code 16                        ;   \
61    .thumb_func _ ##function        ;   \
62    .globl _ ##function             ;   \
63    .align  4                       ;   \
64    _##function:                    ;   \
65
66#define EnterARM_NoAlign(function)      \
67    .code 32                        ;   \
68    .globl _ ##function             ;   \
69    _##function:                    ;   \
70
71#define EnterThumb_NoAlign(function)    \
72    .code 16                        ;   \
73    .thumb_func _ ##function        ;   \
74    .globl _ ##function             ;   \
75    _##function:                    ;   \
76
77/* AArch64 stuff */
78#ifdef _ARM_ARCH_8
79#undef EnterARM
80#undef EnterThumb
81#undef EnterARM_NoAlign
82#undef EnterThumb_NoAlign
83
84#define EnterAArch64(function)          \
85    .align 6                        ;   \
86    .globl _ ##function             ;   \
87    _##function:                    ;
88
89#define EnterAArch64_NoAlign(function)  \
90    .align 6                        ;   \
91    .globl _ ##function             ;   \
92    _##function:                    ;
93
94#define EnterARM_NoAlign    EnterAArch64_NoAlign
95#define EnterThumb_NoAlign  EnterAArch64_NoAlign
96#define EnterARM            EnterAArch64
97#define EnterThumb          EnterAArch64
98#endif
99
100/*
101 * ARM atomic function helper macro.
102 */
103#define AtomicMachine(name, instr)  \
104    EnterARM(hw_atomic_ ##name)     \
105        mov     r12, r0         ;   \
106    try_ ##name:                ;   \
107        ldrex   r0, [r12]       ;   \
108        instr   r0, r0, r1      ;   \
109        strex   r3, r0, [r12]   ;   \
110        movs    r3, r3          ;   \
111        bxeq    lr              ;   \
112        b       try_ ##name     ;
113
114/* These are used for platforms that do not support LDREX/STREX properly. */
115#define AtomicPrologue              \
116        mrs     r3, cpsr        ;   \
117        orr     r2, r3, #0xC0   ;   \
118        msr     cpsr_cf, r2
119
120#define AtomicEpilogue              \
121        msr     cpsr_cf, r3
122
123#define AtomicMachineNoExclusive(name, instr)  \
124    EnterARM(hw_atomic_ ##name)     \
125        AtomicPrologue          ;   \
126        mov     r12, r0         ;   \
127    try_ ##name:                ;   \
128        ldr     r0, [r12]       ;   \
129        instr   r0, r0, r1      ;   \
130        str     r0, [r12]       ;   \
131        AtomicEpilogue          ;   \
132        bx      lr              ;   \
133
134/*
135 * Helper macro to get physical address mapping in virtual address space.
136 */
137#define GetPhysAddr(rX) \
138    LoadConstantToReg(_gPhysBase, r4); \
139    ldr     r4, [r4]; \
140    sub     rX, rX, r4; \
141    LoadConstantToReg(_gVirtBase, r4); \
142    ldr     r4, [r4]; \
143    add     rX, rX, r4
144
145/*
146 * Thread crap.
147 */
148
149#define _1KB                1024
150#define _1MB                1024 * _1KB
151
152#define LoadLockHardwareRegister(register) \
153    mrc     p15, 0, register, c13, c0, 4
154
155#define LoadThreadRegister(register) \
156    mrc     p15, 0, register, c13, c0, 4
157
158#define IncrementPreemptLevel(register, scratch)                      \
159    ldr     scratch, [register, MACHINE_THREAD_PREEMPT_COUNT]     ;   \
160    adds    scratch, scratch, #1                                  ;   \
161    str     scratch, [register, MACHINE_THREAD_PREEMPT_COUNT]     ;
162
163#define DecrementPreemptLevel(register, scratch)                      \
164    ldr     scratch, [register, MACHINE_THREAD_PREEMPT_COUNT]     ;   \
165    subs    scratch, scratch, #1                                  ;   \
166    str     scratch, [register, MACHINE_THREAD_PREEMPT_COUNT]     ;
167
168#endif
169