blob: 156707e0b8959a3a5a3db742576c30c9502dd153 [file] [log] [blame]
Madhukar Pappireddy457af4c2022-12-22 16:13:37 -06001/*
2 * Copyright 2023 The Hafnium Authors.
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
7 */
8
Madhukar Pappireddy4d16db62022-12-22 16:38:10 -06009#include "hf/arch/barriers.h"
Madhukar Pappireddy66421182022-12-22 16:50:09 -060010#include "hf/arch/irq.h"
11#include "hf/arch/vm/interrupts_gicv3.h"
12#include "hf/arch/vm/timer.h"
Madhukar Pappireddy4d16db62022-12-22 16:38:10 -060013
Madhukar Pappireddy457af4c2022-12-22 16:13:37 -060014#include "ffa_secure_partitions.h"
Madhukar Pappireddy66421182022-12-22 16:50:09 -060015#include "gicv3.h"
Madhukar Pappireddy4d16db62022-12-22 16:38:10 -060016#include "msr.h"
Madhukar Pappireddy457af4c2022-12-22 16:13:37 -060017#include "partition_services.h"
18#include "sp_helpers.h"
19
20#define SP_SLEEP_TIME 400U
Madhukar Pappireddy4d16db62022-12-22 16:38:10 -060021#define NS_SLEEP_TIME 200U
22
23static inline uint64_t syscounter_read(void)
24{
25 isb();
26 return read_msr(cntvct_el0);
27}
28
29static void waitus(uint64_t us)
30{
31 uint64_t start_count_val = syscounter_read();
32 uint64_t wait_cycles = (us * read_msr(cntfrq_el0)) / 1000000;
33
34 while ((syscounter_read() - start_count_val) < wait_cycles) {
35 /* Busy wait... */;
36 }
37}
38
39static void waitms(uint64_t ms)
40{
41 while (ms > 0) {
42 waitus(1000);
43 ms--;
44 }
45}
Madhukar Pappireddy457af4c2022-12-22 16:13:37 -060046
47static void configure_trusted_wdog_interrupt(ffa_vm_id_t source,
48 ffa_vm_id_t dest, bool enable)
49{
50 struct ffa_value res;
51
52 res = sp_virtual_interrupt_cmd_send(source, dest, IRQ_TWDOG_INTID,
53 enable, 0);
54
55 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
56 EXPECT_EQ(sp_resp(res), SP_SUCCESS);
57}
58
59static void enable_trusted_wdog_interrupt(ffa_vm_id_t source, ffa_vm_id_t dest)
60{
61 configure_trusted_wdog_interrupt(source, dest, true);
62}
63
64static void disable_trusted_wdog_interrupt(ffa_vm_id_t source, ffa_vm_id_t dest)
65{
66 configure_trusted_wdog_interrupt(source, dest, false);
67}
68
69static void enable_trigger_trusted_wdog_timer(ffa_vm_id_t own_id,
70 ffa_vm_id_t receiver_id,
71 uint32_t timer_ms)
72{
73 struct ffa_value res;
74
75 /* Enable trusted watchdog interrupt as vIRQ in the secure side. */
76 enable_trusted_wdog_interrupt(own_id, receiver_id);
77
78 res = sp_twdog_map_cmd_send(own_id, receiver_id);
79
80 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
81 EXPECT_EQ(sp_resp(res), SP_SUCCESS);
82
83 /*
84 * Send a message to the SP through direct messaging requesting it to
85 * start the trusted watchdog timer.
86 */
87 res = sp_twdog_cmd_send(own_id, receiver_id, timer_ms);
88
89 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
90 EXPECT_EQ(sp_resp(res), SP_SUCCESS);
91}
92
93static void check_and_disable_trusted_wdog_timer(ffa_vm_id_t own_id,
94 ffa_vm_id_t receiver_id)
95{
96 struct ffa_value res;
97
98 /* Check for the last serviced secure virtual interrupt. */
99 res = sp_get_last_interrupt_cmd_send(own_id, receiver_id);
100
101 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
102 EXPECT_EQ(sp_resp(res), SP_SUCCESS);
103
104 /* Make sure Trusted Watchdog timer interrupt was serviced. */
105 EXPECT_EQ(sp_resp_value(res), IRQ_TWDOG_INTID);
106
107 /* Disable Trusted Watchdog interrupt. */
108 disable_trusted_wdog_interrupt(own_id, receiver_id);
109}
110
111/*
112 * Test secure interrupt handling while the Secure Partition is in RUNNING
113 * state.
114 */
115TEST(secure_interrupts, sp_running)
116{
117 struct ffa_value res;
118 ffa_vm_id_t own_id = hf_vm_get_id();
119 struct ffa_partition_info *service2_info = service2();
120 const ffa_vm_id_t receiver_id = service2_info->vm_id;
121
122 enable_trigger_trusted_wdog_timer(own_id, receiver_id, 400);
123
124 /* Send request to the SP to sleep. */
125 res = sp_sleep_cmd_send(own_id, receiver_id, SP_SLEEP_TIME);
126
127 /*
128 * Secure interrupt should trigger during this time, SP will handle the
129 * trusted watchdog timer interrupt.
130 */
131 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
132 EXPECT_EQ(sp_resp(res), SP_SUCCESS);
133
134 /* Make sure elapsed time not less than sleep time. */
135 EXPECT_GE(sp_resp_value(res), SP_SLEEP_TIME);
136
137 check_and_disable_trusted_wdog_timer(own_id, receiver_id);
138}
Madhukar Pappireddy4d16db62022-12-22 16:38:10 -0600139
140/*
141 * Test secure interrupt handling while the Secure Partition is in WAITING
142 * state.
143 */
144TEST(secure_interrupts, sp_waiting)
145{
146 ffa_vm_id_t own_id = hf_vm_get_id();
147 struct ffa_partition_info *service2_info = service2();
148 const ffa_vm_id_t receiver_id = service2_info->vm_id;
149 uint64_t time1;
150 volatile uint64_t time_lapsed;
151 uint64_t timer_freq = read_msr(cntfrq_el0);
152
153 enable_trigger_trusted_wdog_timer(own_id, receiver_id, 100);
154 time1 = syscounter_read();
155
156 /*
157 * Sleep for NS_SLEEP_TIME ms. This ensures secure wdog timer triggers
158 * during this time.
159 */
160 waitms(NS_SLEEP_TIME);
161
162 /* Lapsed time should be at least equal to sleep time. */
163 time_lapsed = ((syscounter_read() - time1) * 1000) / timer_freq;
164
165 EXPECT_GE(time_lapsed, NS_SLEEP_TIME);
166
167 check_and_disable_trusted_wdog_timer(own_id, receiver_id);
168}
Madhukar Pappireddy8cc6deb2022-12-22 16:46:04 -0600169
170/*
171 * Test secure interrupt handling while the Secure Partition is in BLOCKED
172 * state.
173 */
174TEST(secure_interrupts, sp_blocked)
175{
176 struct ffa_value res;
177 ffa_vm_id_t own_id = hf_vm_get_id();
178 struct ffa_partition_info *service1_info = service1();
179 struct ffa_partition_info *service2_info = service2();
180 const ffa_vm_id_t receiver_id = service2_info->vm_id;
181 const ffa_vm_id_t companion_id = service1_info->vm_id;
182
183 enable_trigger_trusted_wdog_timer(own_id, receiver_id, 400);
184
185 /*
186 * Send command to receiver SP to send command to companion SP to sleep
187 * there by putting receiver SP in BLOCKED state.
188 */
189 res = sp_fwd_sleep_cmd_send(own_id, receiver_id, companion_id,
190 SP_SLEEP_TIME, false);
191
192 /*
193 * Secure interrupt should trigger during this time, receiver SP will
194 * handle the trusted watchdog timer and sends direct response message.
195 */
196 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
197 EXPECT_EQ(sp_resp(res), SP_SUCCESS);
198
199 check_and_disable_trusted_wdog_timer(own_id, receiver_id);
200}
Madhukar Pappireddy66421182022-12-22 16:50:09 -0600201
202TEST(secure_interrupts, sp_preempted)
203{
204 struct ffa_value res;
205 ffa_vm_id_t own_id = hf_vm_get_id();
206 struct ffa_partition_info *service2_info = service2();
207 const ffa_vm_id_t receiver_id = service2_info->vm_id;
208
209 gicv3_system_setup();
210 interrupt_enable(PHYSICAL_TIMER_IRQ, true);
211 interrupt_set_priority(PHYSICAL_TIMER_IRQ, 0x80);
212 interrupt_set_edge_triggered(PHYSICAL_TIMER_IRQ, true);
213 interrupt_set_priority_mask(0xff);
214 arch_irq_enable();
215
216 /* Set physical timer for 20 ms and enable. */
217 write_msr(CNTP_TVAL_EL0, ns_to_ticks(20000000));
218 write_msr(CNTP_CTL_EL0, CNTx_CTL_ENABLE_MASK);
219
220 enable_trigger_trusted_wdog_timer(own_id, receiver_id, 200);
221
222 /* Send request to receiver SP to sleep. */
223 res = sp_sleep_cmd_send(own_id, receiver_id, 50);
224
225 /* SP is pre-empted by the non-secure timer interrupt. */
226 EXPECT_EQ(res.func, FFA_INTERRUPT_32);
227
228 /* VM id/vCPU index are passed through arg1. */
229 EXPECT_EQ(res.arg1, ffa_vm_vcpu(receiver_id, 0));
230
231 /* Waiting for interrupt to be serviced in normal world. */
232 while (last_interrupt_id == 0) {
233 EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
234 EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
235 EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
236 EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
237 }
238
239 /* Check that we got the interrupt. */
240 EXPECT_EQ(last_interrupt_id, PHYSICAL_TIMER_IRQ);
241
242 /* Check timer status. */
243 EXPECT_EQ(read_msr(CNTP_CTL_EL0),
244 CNTx_CTL_ISTS_MASK | CNTx_CTL_ENABLE_MASK);
245
246 /*
247 * NS Interrupt has been serviced and receiver SP is now in PREEMPTED
248 * state. Wait for trusted watchdog timer to be fired. SPMC queues
249 * the secure virtual interrupt.
250 */
251 waitms(NS_SLEEP_TIME);
252
253 /*
254 * Resume the SP to complete the busy loop, handle the secure virtual
255 * interrupt and return with success.
256 */
257 res = ffa_run(ffa_vm_id(res), ffa_vcpu_index(res));
258 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
259 EXPECT_EQ(res.arg3, SP_SUCCESS);
260
261 check_and_disable_trusted_wdog_timer(own_id, receiver_id);
262}