blob: e315b9e3249322043c3a673febf61f33a7274fee [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
23#include "hftest.h"
24#include "primary_with_secondary.h"
Andrew Walbran53d9d042019-03-28 11:35:49 +000025#include "util.h"
Andrew Scull2e7a76d2019-01-24 11:47:26 +000026
27/**
28 * Send a message to the interruptible VM, which will interrupt itself to send a
29 * response back.
30 */
31TEST(interrupts, interrupt_self)
32{
33 const char message[] = "Ping";
34 const char expected_response[] = "Got IRQ 05.";
Andrew Walbran27faff32019-10-02 18:20:57 +010035 struct spci_value run_res;
Andrew Scull2e7a76d2019-01-24 11:47:26 +000036 struct mailbox_buffers mb = set_up_mailbox();
37
Fuad Tabba7bd14132019-11-07 14:18:52 +000038 SERVICE_SELECT(SERVICE_VM1, "interruptible", mb.send);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000039
Fuad Tabba7bd14132019-11-07 14:18:52 +000040 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +010041 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
42 EXPECT_EQ(run_res.arg2, SPCI_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000043
44 /* Set the message, echo it and wait for a response. */
Andrew Walbran70bc8622019-10-07 14:15:58 +010045 memcpy_s(mb.send, SPCI_MSG_PAYLOAD_MAX, message, sizeof(message));
46 EXPECT_EQ(
Fuad Tabba7bd14132019-11-07 14:18:52 +000047 spci_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +010048 .func,
49 SPCI_SUCCESS_32);
Fuad Tabba7bd14132019-11-07 14:18:52 +000050 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +010051 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
52 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +010053 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +000054 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +000055 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000056}
57
58/**
59 * Inject an interrupt to the interrupt VM, which will send a message back.
60 * Repeat this twice to make sure it doesn't get into a bad state after the
61 * first one.
62 */
63TEST(interrupts, inject_interrupt_twice)
64{
65 const char expected_response[] = "Got IRQ 07.";
Andrew Walbran27faff32019-10-02 18:20:57 +010066 struct spci_value run_res;
Andrew Scull2e7a76d2019-01-24 11:47:26 +000067 struct mailbox_buffers mb = set_up_mailbox();
68
Fuad Tabba7bd14132019-11-07 14:18:52 +000069 SERVICE_SELECT(SERVICE_VM1, "interruptible", mb.send);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000070
Fuad Tabba7bd14132019-11-07 14:18:52 +000071 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +010072 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
73 EXPECT_EQ(run_res.arg2, SPCI_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000074
75 /* Inject the interrupt and wait for a message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +000076 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
77 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +010078 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
79 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +010080 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +000081 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +000082 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000083
84 /* Inject the interrupt again, and wait for the same message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +000085 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
86 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +010087 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
88 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +010089 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +000090 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +000091 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000092}
93
94/**
95 * Inject two different interrupts to the interrupt VM, which will send a
96 * message back each time.
97 */
98TEST(interrupts, inject_two_interrupts)
99{
100 const char expected_response[] = "Got IRQ 07.";
101 const char expected_response_2[] = "Got IRQ 08.";
Andrew Walbran27faff32019-10-02 18:20:57 +0100102 struct spci_value run_res;
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000103 struct mailbox_buffers mb = set_up_mailbox();
104
Fuad Tabba7bd14132019-11-07 14:18:52 +0000105 SERVICE_SELECT(SERVICE_VM1, "interruptible", mb.send);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000106
Fuad Tabba7bd14132019-11-07 14:18:52 +0000107 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100108 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
109 EXPECT_EQ(run_res.arg2, SPCI_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000110
111 /* Inject the interrupt and wait for a message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000112 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
113 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100114 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
115 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100116 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000117 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +0000118 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000119
120 /* Inject a different interrupt and wait for a different message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000121 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_B);
122 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100123 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
124 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(expected_response_2));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100125 EXPECT_EQ(memcmp(mb.recv, expected_response_2,
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000126 sizeof(expected_response_2)),
127 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +0000128 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000129}
130
131/**
132 * Inject an interrupt then send a message to the interrupt VM, which will send
133 * a message back each time. This is to test that interrupt injection doesn't
134 * interfere with message reception.
135 */
136TEST(interrupts, inject_interrupt_message)
137{
138 const char expected_response[] = "Got IRQ 07.";
139 const char message[] = "Ping";
140 const char expected_response_2[] = "Got IRQ 05.";
Andrew Walbran27faff32019-10-02 18:20:57 +0100141 struct spci_value run_res;
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000142 struct mailbox_buffers mb = set_up_mailbox();
143
Fuad Tabba7bd14132019-11-07 14:18:52 +0000144 SERVICE_SELECT(SERVICE_VM1, "interruptible", mb.send);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000145
Fuad Tabba7bd14132019-11-07 14:18:52 +0000146 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100147 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
148 EXPECT_EQ(run_res.arg2, SPCI_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000149
150 /* Inject the interrupt and wait for a message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000151 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
152 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100153 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
154 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100155 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000156 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +0000157 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000158
Fuad Tabba7bd14132019-11-07 14:18:52 +0000159 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100160 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
161 EXPECT_EQ(run_res.arg2, SPCI_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000162
163 /* Now send a message to the secondary. */
Andrew Walbran70bc8622019-10-07 14:15:58 +0100164 memcpy_s(mb.send, SPCI_MSG_PAYLOAD_MAX, message, sizeof(message));
165 EXPECT_EQ(
Fuad Tabba7bd14132019-11-07 14:18:52 +0000166 spci_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +0100167 .func,
168 SPCI_SUCCESS_32);
Fuad Tabba7bd14132019-11-07 14:18:52 +0000169 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100170 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
171 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(expected_response_2));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100172 EXPECT_EQ(memcmp(mb.recv, expected_response_2,
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000173 sizeof(expected_response_2)),
174 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +0000175 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000176}
177
178/**
179 * Inject an interrupt which the target VM has not enabled, and then send a
180 * message telling it to enable that interrupt ID. It should then (and only
181 * then) send a message back.
182 */
183TEST(interrupts, inject_interrupt_disabled)
184{
185 const char expected_response[] = "Got IRQ 09.";
186 const char message[] = "Enable interrupt C";
Andrew Walbran27faff32019-10-02 18:20:57 +0100187 struct spci_value run_res;
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000188 struct mailbox_buffers mb = set_up_mailbox();
189
Fuad Tabba7bd14132019-11-07 14:18:52 +0000190 SERVICE_SELECT(SERVICE_VM1, "interruptible", mb.send);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000191
192 /* Inject the interrupt and expect not to get a message. */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000193 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_C);
194 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100195 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
196 EXPECT_EQ(run_res.arg2, SPCI_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000197
198 /*
199 * Now send a message to the secondary to enable the interrupt ID, and
200 * expect the response from the interrupt we sent before.
201 */
Andrew Walbran70bc8622019-10-07 14:15:58 +0100202 memcpy_s(mb.send, SPCI_MSG_PAYLOAD_MAX, message, sizeof(message));
203 EXPECT_EQ(
Fuad Tabba7bd14132019-11-07 14:18:52 +0000204 spci_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +0100205 .func,
206 SPCI_SUCCESS_32);
Fuad Tabba7bd14132019-11-07 14:18:52 +0000207 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100208 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
209 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100210 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000211 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +0000212 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000213}
Andrew Walbran9311c9a2019-03-12 16:59:04 +0000214
215/**
216 * If a secondary VM has an enabled and pending interrupt, even if interrupts
217 * are disabled globally via PSTATE, then hf_mailbox_receive should not block
218 * even if `block` is true.
219 */
220TEST(interrupts, pending_interrupt_no_blocking_receive)
221{
222 const char expected_response[] = "Done waiting";
Andrew Walbran27faff32019-10-02 18:20:57 +0100223 struct spci_value run_res;
Andrew Walbran9311c9a2019-03-12 16:59:04 +0000224 struct mailbox_buffers mb = set_up_mailbox();
225
Fuad Tabba7bd14132019-11-07 14:18:52 +0000226 SERVICE_SELECT(SERVICE_VM1, "receive_block", mb.send);
Andrew Walbran9311c9a2019-03-12 16:59:04 +0000227
228 /*
229 * Inject the interrupt and run the VM. It should disable interrupts
230 * globally, enable the specific interrupt, and then send us a message
231 * back after failing to receive a message a few times.
232 */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000233 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
234 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100235 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
236 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100237 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Walbran9311c9a2019-03-12 16:59:04 +0000238 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +0000239 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Walbran9311c9a2019-03-12 16:59:04 +0000240}
Andrew Walbran2d10e882019-03-14 18:17:42 +0000241
242/**
243 * If a secondary VM has an enabled and pending interrupt, even if interrupts
244 * are disabled globally via PSTATE, then WFI should be treated as a no-op and
245 * not return to the primary.
246 */
247TEST(interrupts, pending_interrupt_wfi_not_trapped)
248{
249 const char expected_response[] = "Done waiting";
Andrew Walbran27faff32019-10-02 18:20:57 +0100250 struct spci_value run_res;
Andrew Walbran2d10e882019-03-14 18:17:42 +0000251 struct mailbox_buffers mb = set_up_mailbox();
252
Fuad Tabba7bd14132019-11-07 14:18:52 +0000253 SERVICE_SELECT(SERVICE_VM1, "wfi", mb.send);
Andrew Walbran2d10e882019-03-14 18:17:42 +0000254
255 /*
256 * Inject the interrupt and run the VM. It should disable interrupts
257 * globally, enable the specific interrupt, and then send us a message
258 * back after running WFI a few times.
259 */
Fuad Tabba7bd14132019-11-07 14:18:52 +0000260 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
261 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100262 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
263 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(expected_response));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100264 EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
Andrew Walbran2d10e882019-03-14 18:17:42 +0000265 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +0000266 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Walbran2d10e882019-03-14 18:17:42 +0000267}
Andrew Scullb06d1752019-02-04 10:15:48 +0000268
269/*
270 * Deliver an interrupt and a message to the same vCPU and check that both are
271 * delivered the next time the vCPU is run.
272 */
273TEST(interrupts, deliver_interrupt_and_message)
274{
275 const char message[] = "I\'ll see you again.";
Andrew Walbran27faff32019-10-02 18:20:57 +0100276 struct spci_value run_res;
Andrew Scullb06d1752019-02-04 10:15:48 +0000277 struct mailbox_buffers mb = set_up_mailbox();
278
Fuad Tabba7bd14132019-11-07 14:18:52 +0000279 SERVICE_SELECT(SERVICE_VM1, "interruptible_echo", mb.send);
Andrew Scullb06d1752019-02-04 10:15:48 +0000280
Fuad Tabba7bd14132019-11-07 14:18:52 +0000281 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100282 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
283 EXPECT_EQ(run_res.arg2, SPCI_SLEEP_INDEFINITE);
Andrew Scullb06d1752019-02-04 10:15:48 +0000284
Andrew Walbran70bc8622019-10-07 14:15:58 +0100285 memcpy_s(mb.send, SPCI_MSG_PAYLOAD_MAX, message, sizeof(message));
286 EXPECT_EQ(
Fuad Tabba7bd14132019-11-07 14:18:52 +0000287 spci_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +0100288 .func,
289 SPCI_SUCCESS_32);
Fuad Tabba7bd14132019-11-07 14:18:52 +0000290 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
291 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100292 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
293 EXPECT_EQ(spci_msg_send_size(run_res), sizeof(message));
Andrew Walbran70bc8622019-10-07 14:15:58 +0100294 EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
Andrew Walbran8a0f5ca2019-11-05 13:12:23 +0000295 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scullb06d1752019-02-04 10:15:48 +0000296}