1 /*
2 * Copyright 2022 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
9 #include "partition_services.h"
10
11 #include "hf/arch/irq.h"
12 #include "hf/arch/types.h"
13 #include "hf/arch/vm/interrupts.h"
14
15 #include "hf/dlog.h"
16
17 #include "vmapi/hf/call.h"
18
19 #include "test/hftest.h"
20 #include "test/vmapi/ffa.h"
21
22 extern bool sel1_secure_service;
23
sp_echo_cmd(ffa_vm_id_t receiver,uint32_t val1,uint32_t val2,uint32_t val3,uint32_t val4,uint32_t val5)24 struct ffa_value sp_echo_cmd(ffa_vm_id_t receiver, uint32_t val1, uint32_t val2,
25 uint32_t val3, uint32_t val4, uint32_t val5)
26 {
27 ffa_vm_id_t own_id = hf_vm_get_id();
28 return ffa_msg_send_direct_resp(own_id, receiver, val1, val2, val3,
29 val4, val5);
30 }
31
sp_req_echo_cmd(ffa_vm_id_t test_source,uint32_t val1,uint32_t val2,uint32_t val3,uint32_t val4)32 struct ffa_value sp_req_echo_cmd(ffa_vm_id_t test_source, uint32_t val1,
33 uint32_t val2, uint32_t val3, uint32_t val4)
34 {
35 struct ffa_value res;
36 ffa_vm_id_t own_id = hf_vm_get_id();
37
38 res = sp_echo_cmd_send(own_id, own_id + 1, val1, val2, val3, val4);
39
40 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
41 EXPECT_EQ(res.arg4, val1);
42 EXPECT_EQ(res.arg5, val2);
43 EXPECT_EQ(res.arg6, val3);
44 EXPECT_EQ(res.arg7, val4);
45
46 return sp_success(own_id, test_source, 0);
47 }
48
sp_req_echo_denied_cmd(ffa_vm_id_t test_source)49 struct ffa_value sp_req_echo_denied_cmd(ffa_vm_id_t test_source)
50 {
51 ffa_vm_id_t own_id = hf_vm_get_id();
52 struct ffa_value res;
53
54 if (IS_SP_ID(test_source)) {
55 res = ffa_msg_send_direct_req(own_id, test_source, 0, 0, 0, 0,
56 0);
57 EXPECT_FFA_ERROR(res, FFA_DENIED);
58 } else {
59 res = sp_req_echo_denied_cmd_send(own_id, own_id + 1);
60
61 EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
62 EXPECT_EQ(sp_resp(res), SP_SUCCESS);
63 }
64
65 return sp_success(own_id, test_source, 0);
66 }
67
68 /**
69 * VM asking an SP to send an indirect message to another endpoint.
70 * Message is sent via FFA_MSG_SEND2 ABI, and the receiver is notified through
71 * a direct message.
72 * The message is expected to be echoed back by an indirect message.
73 */
sp_indirect_msg_cmd(ffa_vm_id_t test_source,ffa_vm_id_t receiver_id,uint32_t payload)74 struct ffa_value sp_indirect_msg_cmd(ffa_vm_id_t test_source,
75 ffa_vm_id_t receiver_id, uint32_t payload)
76 {
77 ffa_vm_id_t own_id = hf_vm_get_id();
78 struct mailbox_buffers mb = set_up_mailbox();
79 struct ffa_partition_msg *message;
80 const uint32_t *echo_payload;
81 struct ffa_value ret;
82
83 ret = send_indirect_message(own_id, receiver_id, mb.send, &payload,
84 sizeof(payload),
85 FFA_NOTIFICATIONS_FLAG_DELAY_SRI);
86 EXPECT_EQ(ret.func, FFA_SUCCESS_32);
87
88 /*
89 * Notify the receiver that got an indirect message using a direct
90 * message.
91 */
92 ret = sp_echo_indirect_msg_cmd_send(own_id, receiver_id);
93 EXPECT_EQ(ret.func, FFA_MSG_SEND_DIRECT_RESP_32);
94 EXPECT_EQ(sp_resp(ret), SP_SUCCESS);
95
96 /* Check notification. */
97 ret = ffa_notification_get(own_id, 0, FFA_NOTIFICATION_FLAG_BITMAP_SPM);
98 ASSERT_EQ(ret.func, FFA_SUCCESS_32);
99 ASSERT_TRUE(is_ffa_spm_buffer_full_notification(
100 ffa_notification_get_from_framework(ret)));
101
102 /* Ensure echoed message is the same as sent. */
103 message = (struct ffa_partition_msg *)mb.recv;
104 echo_payload = (const uint32_t *)message->payload;
105 ASSERT_EQ(payload, *echo_payload);
106
107 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
108
109 return sp_success(own_id, test_source, 0);
110 }
111
check_rx_buffer_full_notification(void)112 static void check_rx_buffer_full_notification(void)
113 {
114 ffa_vm_id_t own_id = hf_vm_get_id();
115 struct ffa_value ret;
116 ffa_notifications_bitmap_t framework_notifications;
117
118 ret = ffa_notification_get(own_id, 0,
119 FFA_NOTIFICATION_FLAG_BITMAP_HYP |
120 FFA_NOTIFICATION_FLAG_BITMAP_SPM);
121 framework_notifications = ffa_notification_get_from_framework(ret);
122 ASSERT_EQ(ret.func, FFA_SUCCESS_32);
123 ASSERT_TRUE(
124 is_ffa_hyp_buffer_full_notification(framework_notifications) ||
125 is_ffa_spm_buffer_full_notification(framework_notifications));
126 }
127
irq(void)128 static void irq(void)
129 {
130 ASSERT_EQ(hf_interrupt_get(), HF_NOTIFICATION_PENDING_INTID);
131 check_rx_buffer_full_notification();
132 }
133
134 /**
135 * Echo the indirect message back to sender.
136 */
sp_echo_indirect_msg_cmd(ffa_vm_id_t test_source)137 struct ffa_value sp_echo_indirect_msg_cmd(ffa_vm_id_t test_source)
138 {
139 ffa_vm_id_t own_id = hf_vm_get_id();
140 ffa_vm_id_t target_vm_id;
141 ffa_vm_id_t source_vm_id;
142 struct mailbox_buffers mb = set_up_mailbox();
143 struct ffa_partition_msg *message;
144 const uint32_t *payload;
145
146 if (sel1_secure_service) {
147 /* S-EL1 partition, register interrupt handler for NPI. */
148 exception_setup(irq, NULL);
149 arch_irq_enable();
150 } else {
151 /*
152 * S-EL0 partition, can't get interrupts, check notification
153 * is set.
154 */
155 check_rx_buffer_full_notification();
156 (void)irq;
157 }
158
159 message = (struct ffa_partition_msg *)mb.recv;
160 source_vm_id = ffa_rxtx_header_sender(&message->header);
161 target_vm_id = ffa_rxtx_header_receiver(&message->header);
162 EXPECT_EQ(own_id, target_vm_id);
163
164 payload = (const uint32_t *)message->payload;
165
166 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
167
168 /* Echo message back. */
169 send_indirect_message(target_vm_id, source_vm_id, mb.send, payload,
170 sizeof(*payload),
171 FFA_NOTIFICATIONS_FLAG_DELAY_SRI);
172
173 return sp_success(own_id, test_source, 0);
174 }
175
176 /**
177 * This test illustrates the checks performed by the RTM_FFA_DIR_REQ partition
178 * runtime model for various transitions requested by SP through invocation of
179 * FFA ABIs.
180 */
sp_check_state_transitions_cmd(ffa_vm_id_t test_source,ffa_vm_id_t companion_sp_id)181 struct ffa_value sp_check_state_transitions_cmd(ffa_vm_id_t test_source,
182 ffa_vm_id_t companion_sp_id)
183 {
184 struct ffa_value res;
185 ffa_vm_id_t own_id = hf_vm_get_id();
186
187 /*
188 * The invocation of FFA_MSG_SEND_DIRECT_REQ under RTM_FFA_DIR_REQ is
189 * already part of the `succeeds_sp_to_sp_echo` test belonging to the
190 * `ffa_msg_send_direct_req` testsuite.
191 */
192
193 /*
194 * Test invocation of FFA_MSG_SEND_DIRECT_RESP to an endpoint other
195 * than the one that allocated CPU cycles.
196 */
197 res = ffa_msg_send_direct_resp(own_id, companion_sp_id, 0, 0, 0, 0, 0);
198 EXPECT_FFA_ERROR(res, FFA_DENIED);
199
200 /* Test invocation of FFA_MSG_WAIT. */
201 res = ffa_msg_wait();
202 EXPECT_FFA_ERROR(res, FFA_DENIED);
203
204 /* Test invocation of FFA_YIELD. */
205 res = ffa_yield();
206 EXPECT_FFA_ERROR(res, FFA_DENIED);
207
208 /* TODO: test the invocation of FFA_RUN ABI.*/
209 /* Perform legal invocation of FFA_MSG_SEND_DIRECT_RESP. */
210 return sp_success(own_id, test_source, 0);
211 }
212