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