blob: 13e573be4e886c90da5d62fdd988f683183aaca9 [file] [log] [blame]
Andrew Scull2e7a76d2019-01-24 11:47:26 +00001/*
Andrew Walbran692b3252019-03-07 15:51:31 +00002 * Copyright 2019 The Hafnium Authors.
Andrew Scull2e7a76d2019-01-24 11:47:26 +00003 *
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 * https://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#include <stdint.h>
18
Andrew Scull8d9e1212019-04-05 13:52:55 +010019#include "hf/std.h"
Andrew Scull2e7a76d2019-01-24 11:47:26 +000020
21#include "vmapi/hf/call.h"
22
Andrew Scull2e7a76d2019-01-24 11:47:26 +000023#include "primary_with_secondary.h"
Andrew Walbran1e7c7742019-12-13 17:10:02 +000024#include "test/hftest.h"
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010025#include "test/vmapi/ffa.h"
Andrew Scull2e7a76d2019-01-24 11:47:26 +000026
Andrew Walbrana0168d52019-12-16 11:55:06 +000027TEAR_DOWN(interrupts)
28{
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010029 EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
Andrew Walbrana0168d52019-12-16 11:55:06 +000030}
31
Andrew Scull2e7a76d2019-01-24 11:47:26 +000032/**
33 * Send a message to the interruptible VM, which will interrupt itself to send a
34 * response back.
35 */
36TEST(interrupts, interrupt_self)
37{
38 const char message[] = "Ping";
39 const char expected_response[] = "Got IRQ 05.";
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010040 struct ffa_value run_res;
Andrew Scull2e7a76d2019-01-24 11:47:26 +000041 struct mailbox_buffers mb = set_up_mailbox();
42
Fuad Tabba7bd14132019-11-07 14:18:52 +000043 SERVICE_SELECT(SERVICE_VM1, "interruptible", mb.send);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000044
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010045 run_res = ffa_run(SERVICE_VM1, 0);
46 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
47 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000048
49 /* Set the message, echo it and wait for a response. */
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010050 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
Andrew Walbran70bc8622019-10-07 14:15:58 +010051 EXPECT_EQ(
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010052 ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +010053 .func,
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010054 FFA_SUCCESS_32);
55 run_res = ffa_run(SERVICE_VM1, 0);
56 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
57 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +010058 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +000059 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010060 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000061}
62
63/**
64 * Inject an interrupt to the interrupt VM, which will send a message back.
65 * Repeat this twice to make sure it doesn't get into a bad state after the
66 * first one.
67 */
68TEST(interrupts, inject_interrupt_twice)
69{
70 const char expected_response[] = "Got IRQ 07.";
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010071 struct ffa_value run_res;
Andrew Scull2e7a76d2019-01-24 11:47:26 +000072 struct mailbox_buffers mb = set_up_mailbox();
73
Fuad Tabba7bd14132019-11-07 14:18:52 +000074 SERVICE_SELECT(SERVICE_VM1, "interruptible", mb.send);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000075
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010076 run_res = ffa_run(SERVICE_VM1, 0);
77 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
78 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000079
80 /* Inject the interrupt and wait for a message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +000081 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010082 run_res = ffa_run(SERVICE_VM1, 0);
83 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
84 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +010085 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +000086 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010087 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000088
89 /* Inject the interrupt again, and wait for the same message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +000090 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010091 run_res = ffa_run(SERVICE_VM1, 0);
92 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
93 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +010094 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +000095 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010096 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000097}
98
99/**
100 * Inject two different interrupts to the interrupt VM, which will send a
101 * message back each time.
102 */
103TEST(interrupts, inject_two_interrupts)
104{
105 const char expected_response[] = "Got IRQ 07.";
106 const char expected_response_2[] = "Got IRQ 08.";
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100107 struct ffa_value run_res;
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000108 struct mailbox_buffers mb = set_up_mailbox();
109
Fuad Tabba7bd14132019-11-07 14:18:52 +0000110 SERVICE_SELECT(SERVICE_VM1, "interruptible", mb.send);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000111
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100112 run_res = ffa_run(SERVICE_VM1, 0);
113 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
114 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000115
116 /* Inject the interrupt and wait for a message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000117 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100118 run_res = ffa_run(SERVICE_VM1, 0);
119 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
120 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100121 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000122 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100123 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000124
125 /* Inject a different interrupt and wait for a different message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000126 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_B);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100127 run_res = ffa_run(SERVICE_VM1, 0);
128 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
129 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(expected_response_2));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100130 EXPECT_EQ(memcmp(mb.recv, expected_response_2,
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000131 sizeof(expected_response_2)),
132 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100133 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000134}
135
136/**
137 * Inject an interrupt then send a message to the interrupt VM, which will send
138 * a message back each time. This is to test that interrupt injection doesn't
139 * interfere with message reception.
140 */
141TEST(interrupts, inject_interrupt_message)
142{
143 const char expected_response[] = "Got IRQ 07.";
144 const char message[] = "Ping";
145 const char expected_response_2[] = "Got IRQ 05.";
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100146 struct ffa_value run_res;
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000147 struct mailbox_buffers mb = set_up_mailbox();
148
Fuad Tabba7bd14132019-11-07 14:18:52 +0000149 SERVICE_SELECT(SERVICE_VM1, "interruptible", mb.send);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000150
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100151 run_res = ffa_run(SERVICE_VM1, 0);
152 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
153 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000154
155 /* Inject the interrupt and wait for a message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000156 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100157 run_res = ffa_run(SERVICE_VM1, 0);
158 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
159 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100160 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000161 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100162 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000163
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100164 run_res = ffa_run(SERVICE_VM1, 0);
165 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
166 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000167
168 /* Now send a message to the secondary. */
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100169 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100170 EXPECT_EQ(
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100171 ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +0100172 .func,
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100173 FFA_SUCCESS_32);
174 run_res = ffa_run(SERVICE_VM1, 0);
175 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
176 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(expected_response_2));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100177 EXPECT_EQ(memcmp(mb.recv, expected_response_2,
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000178 sizeof(expected_response_2)),
179 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100180 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000181}
182
183/**
184 * Inject an interrupt which the target VM has not enabled, and then send a
185 * message telling it to enable that interrupt ID. It should then (and only
186 * then) send a message back.
187 */
188TEST(interrupts, inject_interrupt_disabled)
189{
190 const char expected_response[] = "Got IRQ 09.";
191 const char message[] = "Enable interrupt C";
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100192 struct ffa_value run_res;
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000193 struct mailbox_buffers mb = set_up_mailbox();
194
Fuad Tabba7bd14132019-11-07 14:18:52 +0000195 SERVICE_SELECT(SERVICE_VM1, "interruptible", mb.send);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000196
197 /* Inject the interrupt and expect not to get a message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000198 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_C);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100199 run_res = ffa_run(SERVICE_VM1, 0);
200 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
201 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000202
203 /*
204 * Now send a message to the secondary to enable the interrupt ID, and
205 * expect the response from the interrupt we sent before.
206 */
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100207 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100208 EXPECT_EQ(
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100209 ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +0100210 .func,
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100211 FFA_SUCCESS_32);
212 run_res = ffa_run(SERVICE_VM1, 0);
213 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
214 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100215 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000216 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100217 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000218}
Andrew Walbran9311c9a2019-03-12 16:59:04 +0000219
220/**
221 * If a secondary VM has an enabled and pending interrupt, even if interrupts
222 * are disabled globally via PSTATE, then hf_mailbox_receive should not block
223 * even if `block` is true.
224 */
225TEST(interrupts, pending_interrupt_no_blocking_receive)
226{
227 const char expected_response[] = "Done waiting";
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100228 struct ffa_value run_res;
Andrew Walbran9311c9a2019-03-12 16:59:04 +0000229 struct mailbox_buffers mb = set_up_mailbox();
230
Fuad Tabba7bd14132019-11-07 14:18:52 +0000231 SERVICE_SELECT(SERVICE_VM1, "receive_block", mb.send);
Andrew Walbran9311c9a2019-03-12 16:59:04 +0000232
233 /*
234 * Inject the interrupt and run the VM. It should disable interrupts
235 * globally, enable the specific interrupt, and then send us a message
236 * back after failing to receive a message a few times.
237 */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000238 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100239 run_res = ffa_run(SERVICE_VM1, 0);
240 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
241 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100242 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Walbran9311c9a2019-03-12 16:59:04 +0000243 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100244 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Walbran9311c9a2019-03-12 16:59:04 +0000245}
Andrew Walbran2d10e882019-03-14 18:17:42 +0000246
247/**
248 * If a secondary VM has an enabled and pending interrupt, even if interrupts
249 * are disabled globally via PSTATE, then WFI should be treated as a no-op and
250 * not return to the primary.
251 */
252TEST(interrupts, pending_interrupt_wfi_not_trapped)
253{
254 const char expected_response[] = "Done waiting";
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100255 struct ffa_value run_res;
Andrew Walbran2d10e882019-03-14 18:17:42 +0000256 struct mailbox_buffers mb = set_up_mailbox();
257
Fuad Tabba7bd14132019-11-07 14:18:52 +0000258 SERVICE_SELECT(SERVICE_VM1, "wfi", mb.send);
Andrew Walbran2d10e882019-03-14 18:17:42 +0000259
260 /*
261 * Inject the interrupt and run the VM. It should disable interrupts
262 * globally, enable the specific interrupt, and then send us a message
263 * back after running WFI a few times.
264 */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000265 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100266 run_res = ffa_run(SERVICE_VM1, 0);
267 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
268 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100269 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Walbran2d10e882019-03-14 18:17:42 +0000270 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100271 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Walbran2d10e882019-03-14 18:17:42 +0000272}
Andrew Scullb06d1752019-02-04 10:15:48 +0000273
274/*
275 * Deliver an interrupt and a message to the same vCPU and check that both are
276 * delivered the next time the vCPU is run.
277 */
278TEST(interrupts, deliver_interrupt_and_message)
279{
280 const char message[] = "I\'ll see you again.";
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100281 struct ffa_value run_res;
Andrew Scullb06d1752019-02-04 10:15:48 +0000282 struct mailbox_buffers mb = set_up_mailbox();
283
Fuad Tabba7bd14132019-11-07 14:18:52 +0000284 SERVICE_SELECT(SERVICE_VM1, "interruptible_echo", mb.send);
Andrew Scullb06d1752019-02-04 10:15:48 +0000285
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100286 run_res = ffa_run(SERVICE_VM1, 0);
287 EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
288 EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
Andrew Scullb06d1752019-02-04 10:15:48 +0000289
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100290 memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100291 EXPECT_EQ(
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100292 ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +0100293 .func,
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100294 FFA_SUCCESS_32);
Fuad Tabba7bd14132019-11-07 14:18:52 +0000295 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100296 run_res = ffa_run(SERVICE_VM1, 0);
297 EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
298 EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(message));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100299 EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
Andrew Walbranb5ab43c2020-04-30 11:32:54 +0100300 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
Andrew Scullb06d1752019-02-04 10:15:48 +0000301}