blob: 10b2652d90272a70641b1680aa9f5c3568f4c013 [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();
J-Alves5d6926a2022-12-08 14:44:28 +0000119 struct mailbox_buffers mb = set_up_mailbox();
120 struct ffa_partition_info *service2_info = service2(mb.recv);
Madhukar Pappireddy457af4c2022-12-22 16:13:37 -0600121 const ffa_vm_id_t receiver_id = service2_info->vm_id;
122
123 enable_trigger_trusted_wdog_timer(own_id, receiver_id, 400);
124
125 /* Send request to the SP to sleep. */
126 res = sp_sleep_cmd_send(own_id, receiver_id, SP_SLEEP_TIME);
127
128 /*
129 * Secure interrupt should trigger during this time, SP will handle the
130 * trusted watchdog timer interrupt.
131 */
132 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
133 EXPECT_EQ(sp_resp(res), SP_SUCCESS);
134
135 /* Make sure elapsed time not less than sleep time. */
136 EXPECT_GE(sp_resp_value(res), SP_SLEEP_TIME);
137
138 check_and_disable_trusted_wdog_timer(own_id, receiver_id);
139}
Madhukar Pappireddy4d16db62022-12-22 16:38:10 -0600140
141/*
142 * Test secure interrupt handling while the Secure Partition is in WAITING
143 * state.
144 */
145TEST(secure_interrupts, sp_waiting)
146{
147 ffa_vm_id_t own_id = hf_vm_get_id();
J-Alves5d6926a2022-12-08 14:44:28 +0000148 struct mailbox_buffers mb = set_up_mailbox();
149 struct ffa_partition_info *service2_info = service2(mb.recv);
Madhukar Pappireddy4d16db62022-12-22 16:38:10 -0600150 const ffa_vm_id_t receiver_id = service2_info->vm_id;
151 uint64_t time1;
152 volatile uint64_t time_lapsed;
153 uint64_t timer_freq = read_msr(cntfrq_el0);
154
155 enable_trigger_trusted_wdog_timer(own_id, receiver_id, 100);
156 time1 = syscounter_read();
157
158 /*
159 * Sleep for NS_SLEEP_TIME ms. This ensures secure wdog timer triggers
160 * during this time.
161 */
162 waitms(NS_SLEEP_TIME);
163
164 /* Lapsed time should be at least equal to sleep time. */
165 time_lapsed = ((syscounter_read() - time1) * 1000) / timer_freq;
166
167 EXPECT_GE(time_lapsed, NS_SLEEP_TIME);
168
169 check_and_disable_trusted_wdog_timer(own_id, receiver_id);
170}
Madhukar Pappireddy8cc6deb2022-12-22 16:46:04 -0600171
172/*
173 * Test secure interrupt handling while the Secure Partition is in BLOCKED
174 * state.
175 */
176TEST(secure_interrupts, sp_blocked)
177{
178 struct ffa_value res;
179 ffa_vm_id_t own_id = hf_vm_get_id();
J-Alves5d6926a2022-12-08 14:44:28 +0000180 struct mailbox_buffers mb = set_up_mailbox();
181 struct ffa_partition_info *service1_info = service1(mb.recv);
182 struct ffa_partition_info *service2_info = service2(mb.recv);
Madhukar Pappireddy8cc6deb2022-12-22 16:46:04 -0600183 const ffa_vm_id_t receiver_id = service2_info->vm_id;
184 const ffa_vm_id_t companion_id = service1_info->vm_id;
185
186 enable_trigger_trusted_wdog_timer(own_id, receiver_id, 400);
187
188 /*
189 * Send command to receiver SP to send command to companion SP to sleep
190 * there by putting receiver SP in BLOCKED state.
191 */
192 res = sp_fwd_sleep_cmd_send(own_id, receiver_id, companion_id,
193 SP_SLEEP_TIME, false);
194
195 /*
196 * Secure interrupt should trigger during this time, receiver SP will
197 * handle the trusted watchdog timer and sends direct response message.
198 */
199 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
200 EXPECT_EQ(sp_resp(res), SP_SUCCESS);
201
202 check_and_disable_trusted_wdog_timer(own_id, receiver_id);
203}
Madhukar Pappireddy66421182022-12-22 16:50:09 -0600204
205TEST(secure_interrupts, sp_preempted)
206{
207 struct ffa_value res;
208 ffa_vm_id_t own_id = hf_vm_get_id();
J-Alves5d6926a2022-12-08 14:44:28 +0000209 struct mailbox_buffers mb = set_up_mailbox();
210 struct ffa_partition_info *service2_info = service2(mb.recv);
Madhukar Pappireddy66421182022-12-22 16:50:09 -0600211 const ffa_vm_id_t receiver_id = service2_info->vm_id;
212
213 gicv3_system_setup();
214 interrupt_enable(PHYSICAL_TIMER_IRQ, true);
215 interrupt_set_priority(PHYSICAL_TIMER_IRQ, 0x80);
216 interrupt_set_edge_triggered(PHYSICAL_TIMER_IRQ, true);
217 interrupt_set_priority_mask(0xff);
218 arch_irq_enable();
219
220 /* Set physical timer for 20 ms and enable. */
221 write_msr(CNTP_TVAL_EL0, ns_to_ticks(20000000));
222 write_msr(CNTP_CTL_EL0, CNTx_CTL_ENABLE_MASK);
223
224 enable_trigger_trusted_wdog_timer(own_id, receiver_id, 200);
225
226 /* Send request to receiver SP to sleep. */
227 res = sp_sleep_cmd_send(own_id, receiver_id, 50);
228
229 /* SP is pre-empted by the non-secure timer interrupt. */
230 EXPECT_EQ(res.func, FFA_INTERRUPT_32);
231
232 /* VM id/vCPU index are passed through arg1. */
233 EXPECT_EQ(res.arg1, ffa_vm_vcpu(receiver_id, 0));
234
235 /* Waiting for interrupt to be serviced in normal world. */
236 while (last_interrupt_id == 0) {
237 EXPECT_EQ(io_read32_array(GICD_ISPENDR, 0), 0);
238 EXPECT_EQ(io_read32(GICR_ISPENDR0), 0);
239 EXPECT_EQ(io_read32_array(GICD_ISACTIVER, 0), 0);
240 EXPECT_EQ(io_read32(GICR_ISACTIVER0), 0);
241 }
242
243 /* Check that we got the interrupt. */
244 EXPECT_EQ(last_interrupt_id, PHYSICAL_TIMER_IRQ);
245
246 /* Check timer status. */
247 EXPECT_EQ(read_msr(CNTP_CTL_EL0),
248 CNTx_CTL_ISTS_MASK | CNTx_CTL_ENABLE_MASK);
249
250 /*
251 * NS Interrupt has been serviced and receiver SP is now in PREEMPTED
252 * state. Wait for trusted watchdog timer to be fired. SPMC queues
253 * the secure virtual interrupt.
254 */
255 waitms(NS_SLEEP_TIME);
256
257 /*
258 * Resume the SP to complete the busy loop, handle the secure virtual
259 * interrupt and return with success.
260 */
261 res = ffa_run(ffa_vm_id(res), ffa_vcpu_index(res));
262 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
263 EXPECT_EQ(res.arg3, SP_SUCCESS);
264
265 check_and_disable_trusted_wdog_timer(own_id, receiver_id);
266}