1// Copyright 2017 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#include "constants_priv.h"
8
9.set CPACR_EL1_FPEN_NO_TRAP, (3 << 20)
10
11// See ARM ARM Table D1.10.2 for more details.
12.set CURRENT_EL_EL0_BASE,    0x000
13.set CURRENT_EL_ELx_BASE,    0x200
14.set LOWER_EL_ARCH64_BASE,   0x400
15.set LOWER_EL_ARCH32_BASE,   0x600
16.set SYNC_EXC_OFFSET,        0x000
17.set IRQ_EXC_OFFSET,         0x080
18.set FIQ_EXC_OFFSET,         0x100
19.set SERROR_EXC_OFFSET,      0x180
20
21.set SPSR_M_BIT_ARCH32,      0x010
22
23// Define new function 'name'.
24// Local label '1:' used by other macros to compute offsets.
25.macro FUNCTION name
26    .global \name
27    .type \name, STT_FUNC
28    \name:
29    1:
30.endm
31
32// Adjusts current text location to position at a specific exception handler.
33.macro exception_vector base offset
34    2:
35    .skip (\base + \offset) - (2b - 1b)
36.endm
37
38// test_complete Signals test completion by writing value (0-255) to
39// EXIT_TEST_ADDR. EXIT_TEST_ADDR is monitored by the test routine for
40// access - indicating test completion.
41.macro test_complete value=0 arch=aarch64
42    .if \value > 255 || \value < 0
43        .err
44    .endif
45
46    .ifeqs "\arch", "aarch64"
47        mov x0, EXIT_TEST_ADDR
48        .if \value == 0
49            str xzr, [x0]
50        .else
51            mov x1, \value
52            str x1, [x0]
53        .endif
54    .else
55        .ifeqs "\arch", "aarch32"
56            .word 0xE3A01000 + \value  // aarch32: movw r1, \value
57            .word 0xE30F0000           // aarch32: movw r0, [lower]EXIT_TEST_ADDR
58            .word 0xE34000FF           // aarch32: movw r0, [upper]EXIT_TEST_ADDR
59            .word 0xE5801000           // aarch32: str  r0, [r1]
60        .else
61            .error "Unsupported architecture"
62        .endif
63    .endif
64.endm
65
66// Drop exception level from EL1 to EL0 and, if requested, switch execution
67// state.
68.macro drop_to_el0 arch=aarch64
69    .ifeqs "\arch", "aarch32"
70        mov x0, SPSR_M_BIT_ARCH32  // for aarch32, set PSTATE to AARCH32
71        msr spsr_el1, x0           // and clear everything else upon eret.
72    .else
73        .ifnes "\arch", "aarch64"  // accept default architecture, do nothing.
74            .error "Unsupported architecture"
75        .endif
76    .endif
77
78    ldr w0, 2f               // resume execution at label '2' ahead
79    msr elr_el1, x0          // store exception link register
80    eret                     // resume at el0 using specified arch.
81    2:
82    .word 2b - 1b + 4
83.endm
84
85.text
86
87// Test vcpu_resume.
88FUNCTION vcpu_resume_start
89    test_complete
90FUNCTION vcpu_resume_end
91
92// Test vcpu_interrupt.
93FUNCTION vcpu_interrupt_start
94    msr daifclr, #2
95    b .
96
97    exception_vector CURRENT_EL_ELx_BASE, IRQ_EXC_OFFSET
98    test_complete
99FUNCTION vcpu_interrupt_end
100
101// Test wfi instruction handling.
102FUNCTION vcpu_wfi_start
103    // Setup the virtual timer by:
104    // 1. Setting the compare value to 0.
105    // 2. Enabling the virtual timer.
106    msr cntv_cval_el0, xzr
107    mov x0, 1
108    msr cntv_ctl_el0, x0
109
110    wfi
111    test_complete
112FUNCTION vcpu_wfi_end
113
114// Test wfi instruction handling.
115// Execution of WFI at EL0 on AARCH32 is propagated to EL1 / AARCH64.
116FUNCTION vcpu_aarch32_wfi_start
117    drop_to_el0 aarch32
118    .word 0xE320F003         // aarch32: wfi
119    test_complete 1 aarch32  // Fail, if instruction was executed
120                             // without raising exception.
121
122    exception_vector LOWER_EL_ARCH32_BASE, SYNC_EXC_OFFSET
123    test_complete
124FUNCTION vcpu_aarch32_wfi_end
125
126// Test floating-point instruction handling with trapping between levels.
127FUNCTION vcpu_fp_start
128    drop_to_el0
129
130    // Access vector registers.
131    mov w0, 0xff
132    dup v0.16b, w0
133    test_complete
134
135    // Handle EL1 floating-point trap.
136    // This is interpreted as a Lower exception level (coming from EL0)
137    // captured by AARCH64. See ARM ARM Table D1.10.2 for more details.
138    exception_vector LOWER_EL_ARCH64_BASE, SYNC_EXC_OFFSET
139    mov x0, CPACR_EL1_FPEN_NO_TRAP
140    msr cpacr_el1, x0
141    eret
142FUNCTION vcpu_fp_end
143
144// Test wfi instruction handling.
145FUNCTION vcpu_aarch32_fp_start
146    drop_to_el0 aarch32
147    // Load double precision register d0 from address 0.
148    // This should trigger floating point exception.
149    .word 0xE3A00000         // aarch32: mov r0, 0
150    .word 0xED900B00         // aarch32: vldr d0, [r0]
151    test_complete 0 aarch32
152
153    exception_vector LOWER_EL_ARCH32_BASE, SYNC_EXC_OFFSET
154    mov x0, CPACR_EL1_FPEN_NO_TRAP
155    msr cpacr_el1, x0
156    eret
157FUNCTION vcpu_aarch32_fp_end
158
159// Test vcpu_read_state and vcpu_write_state.
160FUNCTION vcpu_read_write_state_start
161    add x1, x1, #1
162    add x2, x2, #2
163    add x3, x3, #3
164    add x4, x4, #4
165    add x5, x5, #5
166    add x6, x6, #6
167    add x7, x7, #7
168    add x8, x8, #8
169    add x9, x9, #9
170    add x10, x10, #10
171    add x11, x11, #11
172    add x12, x12, #12
173    add x13, x13, #13
174    add x14, x14, #14
175    add x15, x15, #15
176    add x16, x16, #16
177    add x17, x17, #17
178    add x18, x18, #18
179    add x19, x19, #19
180    add x20, x20, #20
181    add x21, x21, #21
182    add x22, x22, #22
183    add x23, x23, #23
184    add x24, x24, #24
185    add x25, x25, #25
186    add x26, x26, #26
187    add x27, x27, #27
188    add x28, x28, #28
189    add x29, x29, #29
190    add x30, x30, #30
191
192    add sp, sp, #64
193    cmp sp, #128 // Set ZC bits of CPSR.
194
195    test_complete
196FUNCTION vcpu_read_write_state_end
197
198// Test guest_set_trap using a memory-based trap.
199FUNCTION guest_set_trap_start
200    mov x0, TRAP_ADDR
201    str xzr, [x0]
202    test_complete
203FUNCTION guest_set_trap_end
204