1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_S_
18#define ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_S_
19
20#include "asm_support_arm64.h"
21#include "interpreter/cfi_asm_support.h"
22
23// Define special registers.
24
25// Register holding Thread::Current().
26#define xSELF x19
27// Frame Pointer
28#define xFP   x29
29// Link Register
30#define xLR   x30
31// Define the intraprocedural linkage temporary registers.
32#define xIP0 x16
33#define wIP0 w16
34#define xIP1 x17
35#define wIP1 w17
36
37#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
38// Marking Register, holding Thread::Current()->GetIsGcMarking().
39// Only used with the Concurrent Copying (CC) garbage
40// collector, with the Baker read barrier configuration.
41#define wMR w20
42#endif
43
44.macro CFI_EXPRESSION_BREG n, b, offset
45    .if (-0x40 <= (\offset)) && ((\offset) < 0x40)
46        CFI_EXPRESSION_BREG_1(\n, \b, \offset)
47    .elseif (-0x2000 <= (\offset)) && ((\offset) < 0x2000)
48        CFI_EXPRESSION_BREG_2(\n, \b, \offset)
49    .else
50        .error "Unsupported offset"
51    .endif
52.endm
53
54.macro CFI_DEF_CFA_BREG_PLUS_UCONST reg, offset, size
55    .if ((\size) < 0)
56        .error "Size should be positive"
57    .endif
58    .if (((\offset) < -0x40) || ((\offset) >= 0x40))
59        .error "Unsupported offset"
60    .endif
61    .if ((\size) < 0x80)
62        CFI_DEF_CFA_BREG_PLUS_UCONST_1_1(\reg, \offset, \size)
63    .elseif ((\size) < 0x4000)
64        CFI_DEF_CFA_BREG_PLUS_UCONST_1_2(\reg, \offset, \size)
65    .else
66        .error "Unsupported size"
67    .endif
68.endm
69
70.macro ENTRY_ALIGNED name, alignment
71    .type \name, #function
72    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
73    .global \name
74    // ART-compiled functions have OatQuickMethodHeader but assembly funtions do not.
75    // Prefix the assembly code with 0xFFs, which means there is no method header.
76    .byte 0xFF, 0xFF, 0xFF, 0xFF
77    // Cache alignment for function entry.
78    // NB: 0xFF because there is a bug in balign where 0x00 creates nop instructions.
79    .balign \alignment, 0xFF
80\name:
81    .cfi_startproc
82.endm
83
84.macro ENTRY name
85    ENTRY_ALIGNED \name, 16
86.endm
87
88.macro END name
89    .cfi_endproc
90    .size \name, .-\name
91.endm
92
93.macro UNIMPLEMENTED name
94    ENTRY \name
95    brk 0
96    END \name
97.endm
98
99// Macro to poison (negate) the reference for heap poisoning.
100.macro POISON_HEAP_REF rRef
101#ifdef USE_HEAP_POISONING
102    neg \rRef, \rRef
103#endif  // USE_HEAP_POISONING
104.endm
105
106// Macro to unpoison (negate) the reference for heap poisoning.
107.macro UNPOISON_HEAP_REF rRef
108#ifdef USE_HEAP_POISONING
109    neg \rRef, \rRef
110#endif  // USE_HEAP_POISONING
111.endm
112
113.macro INCREASE_FRAME frame_adjustment
114    sub sp, sp, #(\frame_adjustment)
115    .cfi_adjust_cfa_offset (\frame_adjustment)
116.endm
117
118.macro DECREASE_FRAME frame_adjustment
119    add sp, sp, #(\frame_adjustment)
120    .cfi_adjust_cfa_offset -(\frame_adjustment)
121.endm
122
123.macro SAVE_REG reg, offset
124    str \reg, [sp, #(\offset)]
125    .cfi_rel_offset \reg, (\offset)
126.endm
127
128.macro RESTORE_REG_BASE base, reg, offset
129    ldr \reg, [\base, #(\offset)]
130    .cfi_restore \reg
131.endm
132
133.macro RESTORE_REG reg, offset
134    RESTORE_REG_BASE sp, \reg, \offset
135.endm
136
137.macro SAVE_TWO_REGS_BASE base, reg1, reg2, offset
138    stp \reg1, \reg2, [\base, #(\offset)]
139    .cfi_rel_offset \reg1, (\offset)
140    .cfi_rel_offset \reg2, (\offset) + 8
141.endm
142
143.macro SAVE_TWO_REGS reg1, reg2, offset
144    SAVE_TWO_REGS_BASE sp, \reg1, \reg2, \offset
145.endm
146
147.macro RESTORE_TWO_REGS_BASE base, reg1, reg2, offset
148    ldp \reg1, \reg2, [\base, #(\offset)]
149    .cfi_restore \reg1
150    .cfi_restore \reg2
151.endm
152
153.macro RESTORE_TWO_REGS reg1, reg2, offset
154    RESTORE_TWO_REGS_BASE sp, \reg1, \reg2, \offset
155.endm
156
157.macro LOAD_RUNTIME_INSTANCE reg
158#if __has_feature(hwaddress_sanitizer) && __clang_major__ >= 10
159    adrp \reg, :pg_hi21_nc:_ZN3art7Runtime9instance_E
160#else
161    adrp \reg, _ZN3art7Runtime9instance_E
162#endif
163    ldr \reg, [\reg, #:lo12:_ZN3art7Runtime9instance_E]
164.endm
165
166// Macro to refresh the Marking Register (W20).
167//
168// This macro must be called at the end of functions implementing
169// entrypoints that possibly (directly or indirectly) perform a
170// suspend check (before they return).
171.macro REFRESH_MARKING_REGISTER
172#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
173    ldr wMR, [xSELF, #THREAD_IS_GC_MARKING_OFFSET]
174#endif
175.endm
176
177    /*
178     * Macro that sets up the callee save frame to conform with
179     * Runtime::CreateCalleeSaveMethod(kSaveRefsOnly).
180     */
181.macro SETUP_SAVE_REFS_ONLY_FRAME
182    // art::Runtime* xIP0 = art::Runtime::instance_;
183    // Our registers aren't intermixed - just spill in order.
184    LOAD_RUNTIME_INSTANCE xIP0
185
186    // ArtMethod* xIP0 = Runtime::instance_->callee_save_methods_[kSaveRefOnly];
187    ldr xIP0, [xIP0, RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET]
188
189    INCREASE_FRAME 96
190
191    // Ugly compile-time check, but we only have the preprocessor.
192#if (FRAME_SIZE_SAVE_REFS_ONLY != 96)
193#error "FRAME_SIZE_SAVE_REFS_ONLY(ARM64) size not as expected."
194#endif
195
196    // GP callee-saves.
197    // x20 paired with ArtMethod* - see below.
198    SAVE_TWO_REGS x21, x22, 16
199    SAVE_TWO_REGS x23, x24, 32
200    SAVE_TWO_REGS x25, x26, 48
201    SAVE_TWO_REGS x27, x28, 64
202    SAVE_TWO_REGS x29, xLR, 80
203
204    // Store ArtMethod* Runtime::callee_save_methods_[kSaveRefsOnly].
205    // Note: We could avoid saving X20 in the case of Baker read
206    // barriers, as it is overwritten by REFRESH_MARKING_REGISTER
207    // later; but it's not worth handling this special case.
208    stp xIP0, x20, [sp]
209    .cfi_rel_offset x20, 8
210
211    // Place sp in Thread::Current()->top_quick_frame.
212    mov xIP0, sp
213    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
214.endm
215
216// TODO: Probably no need to restore registers preserved by aapcs64.
217.macro RESTORE_SAVE_REFS_ONLY_FRAME
218    // Callee-saves.
219    // Note: Likewise, we could avoid restoring X20 in the case of Baker
220    // read barriers, as it is overwritten by REFRESH_MARKING_REGISTER
221    // later; but it's not worth handling this special case.
222    RESTORE_REG x20, 8
223    RESTORE_TWO_REGS x21, x22, 16
224    RESTORE_TWO_REGS x23, x24, 32
225    RESTORE_TWO_REGS x25, x26, 48
226    RESTORE_TWO_REGS x27, x28, 64
227    RESTORE_TWO_REGS x29, xLR, 80
228
229    DECREASE_FRAME 96
230.endm
231
232.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_INTERNAL base
233    // Ugly compile-time check, but we only have the preprocessor.
234#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 224)
235#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(ARM64) size not as expected."
236#endif
237
238    // Stack alignment filler [\base, #8].
239    // FP args.
240    stp d0, d1, [\base, #16]
241    stp d2, d3, [\base, #32]
242    stp d4, d5, [\base, #48]
243    stp d6, d7, [\base, #64]
244
245    // Core args.
246    SAVE_TWO_REGS_BASE \base, x1, x2, 80
247    SAVE_TWO_REGS_BASE \base, x3, x4, 96
248    SAVE_TWO_REGS_BASE \base, x5, x6, 112
249
250    // x7, Callee-saves.
251    // Note: We could avoid saving X20 in the case of Baker read
252    // barriers, as it is overwritten by REFRESH_MARKING_REGISTER
253    // later; but it's not worth handling this special case.
254    SAVE_TWO_REGS_BASE \base, x7, x20, 128
255    SAVE_TWO_REGS_BASE \base, x21, x22, 144
256    SAVE_TWO_REGS_BASE \base, x23, x24, 160
257    SAVE_TWO_REGS_BASE \base, x25, x26, 176
258    SAVE_TWO_REGS_BASE \base, x27, x28, 192
259
260    // x29(callee-save) and LR.
261    SAVE_TWO_REGS_BASE \base, x29, xLR, 208
262.endm
263
264// TODO: Probably no need to restore registers preserved by aapcs64. (That would require
265// auditing all users to make sure they restore aapcs64 callee-save registers they clobber.)
266.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME_INTERNAL base
267    // FP args.
268    ldp d0, d1, [\base, #16]
269    ldp d2, d3, [\base, #32]
270    ldp d4, d5, [\base, #48]
271    ldp d6, d7, [\base, #64]
272
273    // Core args.
274    RESTORE_TWO_REGS_BASE \base, x1, x2, 80
275    RESTORE_TWO_REGS_BASE \base, x3, x4, 96
276    RESTORE_TWO_REGS_BASE \base, x5, x6, 112
277
278    // x7, Callee-saves.
279    // Note: Likewise, we could avoid restoring X20 in the case of Baker
280    // read barriers, as it is overwritten by REFRESH_MARKING_REGISTER
281    // later; but it's not worth handling this special case.
282    RESTORE_TWO_REGS_BASE \base, x7, x20, 128
283    RESTORE_TWO_REGS_BASE \base, x21, x22, 144
284    RESTORE_TWO_REGS_BASE \base, x23, x24, 160
285    RESTORE_TWO_REGS_BASE \base, x25, x26, 176
286    RESTORE_TWO_REGS_BASE \base, x27, x28, 192
287
288    // x29(callee-save) and LR.
289    RESTORE_TWO_REGS_BASE \base, x29, xLR, 208
290.endm
291
292.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME
293    RESTORE_SAVE_REFS_AND_ARGS_FRAME_INTERNAL sp
294    DECREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS
295.endm
296
297.macro SAVE_ALL_CALLEE_SAVES offset
298    // FP callee-saves.
299    stp d8, d9,   [sp, #(0 + \offset)]
300    stp d10, d11, [sp, #(16 + \offset)]
301    stp d12, d13, [sp, #(32 + \offset)]
302    stp d14, d15, [sp, #(48 + \offset)]
303
304    // GP callee-saves
305    SAVE_TWO_REGS x19, x20, (64 + \offset)
306    SAVE_TWO_REGS x21, x22, (80 + \offset)
307    SAVE_TWO_REGS x23, x24, (96 + \offset)
308    SAVE_TWO_REGS x25, x26, (112 + \offset)
309    SAVE_TWO_REGS x27, x28, (128 + \offset)
310    SAVE_TWO_REGS x29, xLR, (144 + \offset)
311.endm
312
313    /*
314     * Macro that sets up the callee save frame to conform with
315     * Runtime::CreateCalleeSaveMethod(kSaveAllCalleeSaves)
316     */
317.macro SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
318    // art::Runtime* xIP0 = art::Runtime::instance_;
319    // Our registers aren't intermixed - just spill in order.
320    LOAD_RUNTIME_INSTANCE xIP0
321
322    // ArtMethod* xIP0 = Runtime::instance_->callee_save_methods_[kSaveAllCalleeSaves];
323    ldr xIP0, [xIP0, RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET]
324
325    INCREASE_FRAME 176
326
327    // Ugly compile-time check, but we only have the preprocessor.
328#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 176)
329#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(ARM64) size not as expected."
330#endif
331
332    // Stack alignment filler [sp, #8].
333    SAVE_ALL_CALLEE_SAVES 16
334
335    // Store ArtMethod* Runtime::callee_save_methods_[kSaveAllCalleeSaves].
336    str xIP0, [sp]
337    // Place sp in Thread::Current()->top_quick_frame.
338    mov xIP0, sp
339    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
340.endm
341
342    /*
343     * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
344     * exception is Thread::Current()->exception_ when the runtime method frame is ready.
345     */
346.macro DELIVER_PENDING_EXCEPTION_FRAME_READY
347    mov x0, xSELF
348
349    // Point of no return.
350    bl artDeliverPendingExceptionFromCode  // artDeliverPendingExceptionFromCode(Thread*)
351    brk 0  // Unreached
352.endm
353
354    /*
355     * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
356     * exception is Thread::Current()->exception_.
357     */
358.macro DELIVER_PENDING_EXCEPTION
359    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
360    DELIVER_PENDING_EXCEPTION_FRAME_READY
361.endm
362
363.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg
364    ldr \reg, [xSELF, # THREAD_EXCEPTION_OFFSET]   // Get exception field.
365    cbnz \reg, 1f
366    ret
3671:
368    DELIVER_PENDING_EXCEPTION
369.endm
370
371.macro RETURN_OR_DELIVER_PENDING_EXCEPTION
372    RETURN_OR_DELIVER_PENDING_EXCEPTION_REG xIP0
373.endm
374
375#endif  // ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_S_
376