blob: dce89ab5e6d82578baaf032dd79909931479a6c3 [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 Walbran0e7a1c32019-12-13 17:24:35 +000025#include "test/vmapi/spci.h"
Andrew Scull2e7a76d2019-01-24 11:47:26 +000026
Andrew Walbrana0168d52019-12-16 11:55:06 +000027TEAR_DOWN(interrupts)
28{
29 EXPECT_SPCI_ERROR(spci_rx_release(), SPCI_DENIED);
30}
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 Walbran27faff32019-10-02 18:20:57 +010040 struct spci_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
Fuad Tabba7bd14132019-11-07 14:18:52 +000045 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +010046 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
47 EXPECT_EQ(run_res.arg2, SPCI_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +000048
49 /* Set the message, echo it and wait for a response. */
Andrew Walbran70bc8622019-10-07 14:15:58 +010050 memcpy_s(mb.send, SPCI_MSG_PAYLOAD_MAX, message, sizeof(message));
51 EXPECT_EQ(
Fuad Tabba7bd14132019-11-07 14:18:52 +000052 spci_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +010053 .func,
54 SPCI_SUCCESS_32);
Fuad Tabba7bd14132019-11-07 14:18:52 +000055 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +010056 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
57 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +000060 EXPECT_EQ(spci_rx_release().func, SPCI_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 Walbran27faff32019-10-02 18:20:57 +010071 struct spci_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
Fuad Tabba7bd14132019-11-07 14:18:52 +000076 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +010077 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
78 EXPECT_EQ(run_res.arg2, SPCI_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);
82 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +010083 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
84 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +000087 EXPECT_EQ(spci_rx_release().func, SPCI_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);
91 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +010092 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
93 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +000096 EXPECT_EQ(spci_rx_release().func, SPCI_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 Walbran27faff32019-10-02 18:20:57 +0100107 struct spci_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
Fuad Tabba7bd14132019-11-07 14:18:52 +0000112 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100113 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
114 EXPECT_EQ(run_res.arg2, SPCI_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);
118 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100119 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
120 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +0000123 EXPECT_EQ(spci_rx_release().func, SPCI_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);
127 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100128 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
129 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +0000133 EXPECT_EQ(spci_rx_release().func, SPCI_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 Walbran27faff32019-10-02 18:20:57 +0100146 struct spci_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
Fuad Tabba7bd14132019-11-07 14:18:52 +0000151 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100152 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
153 EXPECT_EQ(run_res.arg2, SPCI_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);
157 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100158 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
159 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +0000162 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000163
Fuad Tabba7bd14132019-11-07 14:18:52 +0000164 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100165 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
166 EXPECT_EQ(run_res.arg2, SPCI_SLEEP_INDEFINITE);
Andrew Scull2e7a76d2019-01-24 11:47:26 +0000167
168 /* Now send a message to the secondary. */
Andrew Walbran70bc8622019-10-07 14:15:58 +0100169 memcpy_s(mb.send, SPCI_MSG_PAYLOAD_MAX, message, sizeof(message));
170 EXPECT_EQ(
Fuad Tabba7bd14132019-11-07 14:18:52 +0000171 spci_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +0100172 .func,
173 SPCI_SUCCESS_32);
Fuad Tabba7bd14132019-11-07 14:18:52 +0000174 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100175 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
176 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +0000180 EXPECT_EQ(spci_rx_release().func, SPCI_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 Walbran27faff32019-10-02 18:20:57 +0100192 struct spci_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);
199 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100200 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
201 EXPECT_EQ(run_res.arg2, SPCI_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 Walbran70bc8622019-10-07 14:15:58 +0100207 memcpy_s(mb.send, SPCI_MSG_PAYLOAD_MAX, message, sizeof(message));
208 EXPECT_EQ(
Fuad Tabba7bd14132019-11-07 14:18:52 +0000209 spci_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +0100210 .func,
211 SPCI_SUCCESS_32);
Fuad Tabba7bd14132019-11-07 14:18:52 +0000212 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100213 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
214 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +0000217 EXPECT_EQ(spci_rx_release().func, SPCI_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 Walbran27faff32019-10-02 18:20:57 +0100228 struct spci_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);
239 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100240 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
241 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +0000244 EXPECT_EQ(spci_rx_release().func, SPCI_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 Walbran27faff32019-10-02 18:20:57 +0100255 struct spci_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);
266 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100267 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
268 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +0000271 EXPECT_EQ(spci_rx_release().func, SPCI_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 Walbran27faff32019-10-02 18:20:57 +0100281 struct spci_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
Fuad Tabba7bd14132019-11-07 14:18:52 +0000286 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100287 EXPECT_EQ(run_res.func, SPCI_MSG_WAIT_32);
288 EXPECT_EQ(run_res.arg2, SPCI_SLEEP_INDEFINITE);
Andrew Scullb06d1752019-02-04 10:15:48 +0000289
Andrew Walbran70bc8622019-10-07 14:15:58 +0100290 memcpy_s(mb.send, SPCI_MSG_PAYLOAD_MAX, message, sizeof(message));
291 EXPECT_EQ(
Fuad Tabba7bd14132019-11-07 14:18:52 +0000292 spci_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
Andrew Walbran70bc8622019-10-07 14:15:58 +0100293 .func,
294 SPCI_SUCCESS_32);
Fuad Tabba7bd14132019-11-07 14:18:52 +0000295 hf_interrupt_inject(SERVICE_VM1, 0, EXTERNAL_INTERRUPT_ID_A);
296 run_res = spci_run(SERVICE_VM1, 0);
Andrew Walbran27faff32019-10-02 18:20:57 +0100297 EXPECT_EQ(run_res.func, SPCI_MSG_SEND_32);
298 EXPECT_EQ(spci_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 Walbran8a0f5ca2019-11-05 13:12:23 +0000300 EXPECT_EQ(spci_rx_release().func, SPCI_SUCCESS_32);
Andrew Scullb06d1752019-02-04 10:15:48 +0000301}