blob: 472fa2d8e4f1aefb95a80794237e5530a17d51e5 [file] [log] [blame]
Madhukar Pappireddy81237692024-01-04 17:32:23 -06001/*
2 * Copyright 2024 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
J-Alves3a9510e2024-09-04 14:34:00 +01009#include "hf/arch/irq.h"
10#include "hf/arch/vm/interrupts.h"
11#include "hf/arch/vm/interrupts_gicv3.h"
Daniel Boulby377defd2024-08-22 10:48:23 +010012#include "hf/arch/vm/power_mgmt.h"
13
Madhukar Pappireddy81237692024-01-04 17:32:23 -060014#include "vmapi/hf/call.h"
15
J-Alves3a9510e2024-09-04 14:34:00 +010016#include "gicv3.h"
Madhukar Pappireddy81237692024-01-04 17:32:23 -060017#include "primary_with_secondary.h"
18#include "test/hftest.h"
Daniel Boulby377defd2024-08-22 10:48:23 +010019#include "test/semaphore.h"
20
21/**
22 * Structure defined for usage in tests with multiple cores.
23 * Used to pass arguments from primary to secondary core.
24 */
25struct ipi_cpu_entry_args {
26 ffa_id_t service_id;
27 ffa_vcpu_count_t vcpu_count;
28 ffa_vcpu_index_t vcpu_id;
29 ffa_vcpu_index_t target_vcpu_id;
30 struct mailbox_buffers mb;
31 struct semaphore work_done;
32};
Madhukar Pappireddy81237692024-01-04 17:32:23 -060033
34/*
35 * Test secure interrupt handling while the Secure Partition runs in FFA_RUN
36 * partition runtime model with virtual interrupts potentially masked. This
37 * test helps to validate the functionality of the SPMC, which is to:
38 * - Intercept a FFA_MSG_WAIT invocation by the current SP in FFA_RUN partition
39 * runtime model, if there are pending virtual secure interrupts.
40 * - Resume the SP to handle the pending secure virtual interrupt.
41 *
42 * For orchestrating the above scenario, we leverage indirect messaging
43 * interface and allocate CPU cycles to the Secure Partition through FFA_RUN
44 * interface.
45 */
46TEST_PRECONDITION(secure_interrupts, preempted_by_secure_interrupt,
47 service1_is_not_vm)
48{
49 struct ffa_value ret;
50 struct mailbox_buffers mb = set_up_mailbox();
51 const uint32_t delay = 100;
52 const uint32_t echo_payload;
53 ffa_id_t echo_sender;
54 ffa_id_t own_id = hf_vm_get_id();
55 struct ffa_partition_info *service1_info = service1(mb.recv);
56
57 SERVICE_SELECT(service1_info->vm_id, "sec_interrupt_preempt_msg",
58 mb.send);
59
60 /*
61 * Send an indirect message to convey the Secure Watchdog timer delay
62 * which serves as the source of the secure interrupt.
63 */
64 ret = send_indirect_message(own_id, service1_info->vm_id, mb.send,
65 &delay, sizeof(delay), 0);
66 EXPECT_EQ(ret.func, FFA_SUCCESS_32);
67
68 /* Schedule message receiver through FFA_RUN interface. */
69 ret = ffa_run(service1_info->vm_id, 0);
70 EXPECT_EQ(ret.func, FFA_MSG_WAIT_32);
71
72 receive_indirect_message((void *)&echo_payload, sizeof(echo_payload),
73 mb.recv, &echo_sender);
74
75 HFTEST_LOG("Message echoed back: %#x", echo_payload);
76 EXPECT_EQ(echo_payload, delay);
77 EXPECT_EQ(echo_sender, service1_info->vm_id);
78}
J-Alves3e9f6052024-07-23 13:41:56 +010079
80/**
81 * This test expects SP1 to have pended an interrupt for SP2, before SP2 has
82 * booted, following the boot protocol.
83 *
84 * TODO: Make this test applicable to S-EL0 and S-EL1 UP partitions.
85 */
86TEST_PRECONDITION(secure_interrupts, handle_interrupt_rtm_init,
87 service2_is_mp_sp)
88{
89 struct ffa_value ret;
90 struct mailbox_buffers mb = set_up_mailbox();
91 struct ffa_partition_info *service2_info = service2(mb.recv);
92
93 SERVICE_SELECT(service2_info->vm_id, "check_interrupt_rtm_init_handled",
94 mb.send);
95
96 /* Schedule message receiver through FFA_RUN interface. */
97 ret = ffa_run(service2_info->vm_id, 0);
98 EXPECT_EQ(ret.func, FFA_YIELD_32);
99}
Daniel Boulby377defd2024-08-22 10:48:23 +0100100
101/**
J-Alves3a9510e2024-09-04 14:34:00 +0100102 * Setups up SRI and returns the interrupt ID.
103 */
104uint32_t enable_sri(void)
105{
106 struct ffa_value ret;
107 uint32_t sri_id;
108
109 dlog_verbose("Enabling the SRI");
110
111 gicv3_system_setup();
112
113 ret = ffa_features(FFA_FEATURE_SRI);
114
115 sri_id = ffa_feature_intid(ret);
116
117 interrupt_enable(sri_id, true);
118 interrupt_set_priority(sri_id, 0x10);
119 interrupt_set_edge_triggered(sri_id, false);
120 interrupt_set_priority_mask(0xff);
121
122 arch_irq_enable();
123
124 return sri_id;
125}
126
127/**
Daniel Boulby377defd2024-08-22 10:48:23 +0100128 * Secondary CPU entrypoint.
129 * Requests the 'send_ipi' function in the designated FF-A endpoint.
130 * Sends the vCPU to be targeted by the IPI via indirect messaging.
131 */
132static void cpu_entry_send_ipi(uintptr_t arg)
133{
134 struct ipi_cpu_entry_args *args =
135 // NOLINTNEXTLINE(performance-no-int-to-ptr)
136 (struct ipi_cpu_entry_args *)arg;
137 struct ffa_value ret;
138 const ffa_id_t own_id = hf_vm_get_id();
139
140 ASSERT_TRUE(args != NULL);
141 ASSERT_TRUE(args->vcpu_count > 1);
142
143 HFTEST_LOG("%s: Within secondary core... %u", __func__, args->vcpu_id);
144
145 SERVICE_SELECT_MP(args->service_id, "send_ipi", args->mb.send,
146 args->vcpu_id);
147
148 /* Run service. */
149 ret = ffa_run(args->service_id, args->vcpu_id);
150 EXPECT_EQ(ret.func, FFA_MSG_WAIT_32);
151
152 /* Send it the target vCPU ID. */
153 ret = send_indirect_message(own_id, args->service_id, args->mb.send,
154 &args->target_vcpu_id,
155 sizeof(args->target_vcpu_id), 0);
156
157 ASSERT_EQ(ret.func, FFA_SUCCESS_32);
158 EXPECT_EQ(ffa_run(args->service_id, args->vcpu_id).func, FFA_YIELD_32);
159
160 HFTEST_LOG("%s cpu done...", __func__);
161
162 /* Signal to primary core that test is complete.*/
163 semaphore_signal(&args->work_done);
164
165 arch_cpu_stop();
166}
167
168/**
169 * Test that Service1 can send IPI to vCPU0 from vCPU1, whilst vCPU0 is in
170 * running state.
171 * Test Sequence:
172 * - Bootstrap vCPU0 in the respective test service, such that it can initialise
173 * the IPI state.
174 * - Service1 vCPU0 terminates and leaves the IPI state not READY.
175 * - Start CPU1 and within it, invoke test service to send IPI. Test service
176 * waits for state machine to transition into READY state.
177 * - Resume Service1 vCPU0 such that it can set IPI state to READY.
178 *
179 * Failure in this test would be captured by timeout as Service1 vCPU0 would
180 * hang waiting for the IPI.
181 */
182TEST_PRECONDITION(ipi, receive_ipi_running_vcpu, service1_is_mp_sp)
183{
184 struct mailbox_buffers mb = set_up_mailbox();
185 struct ffa_partition_info *service1_info = service1(mb.recv);
186 struct ffa_value ret;
187 struct ipi_cpu_entry_args vcpu1_args = {
188 .service_id = service1_info->vm_id,
189 .vcpu_count = service1_info->vcpu_count,
190 .vcpu_id = 1,
191 .target_vcpu_id = 0,
192 .mb = mb};
193
194 /* Initialize semaphores to sync primary and secondary cores. */
195 semaphore_init(&vcpu1_args.work_done);
196
197 SERVICE_SELECT(service1_info->vm_id, "receive_ipi_running", mb.send);
198
199 ret = ffa_run(service1_info->vm_id, 0);
200 EXPECT_EQ(ret.func, FFA_YIELD_32);
201
202 /* Bring-up the core that sends the IPI. */
203 ASSERT_TRUE(hftest_cpu_start(
204 hftest_get_cpu_id(vcpu1_args.vcpu_id),
205 hftest_get_secondary_ec_stack(vcpu1_args.vcpu_id),
206 cpu_entry_send_ipi, (uintptr_t)&vcpu1_args));
207
208 /*
209 * Resumes service1 in target vCPU0 so it sets IPI state to READY and
210 * handles IPI.
211 */
212 ret = ffa_run(service1_info->vm_id, 0);
213 EXPECT_EQ(ret.func, FFA_YIELD_32);
214
215 /* Wait for secondary core to return before finishing the test. */
216 semaphore_wait(&vcpu1_args.work_done);
217}