1 /*
2  * Copyright 2021 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 "hf/arch/vm/delay.h"
10 #include "hf/arch/vm/power_mgmt.h"
11 
12 #include "hf/dlog.h"
13 #include "hf/ffa.h"
14 #include "hf/mm.h"
15 
16 #include "vmapi/hf/call.h"
17 
18 #include "ffa_secure_partitions.h"
19 #include "partition_services.h"
20 #include "test/hftest.h"
21 #include "test/vmapi/ffa.h"
22 
23 #define SP_SLEEP_LONG 2000U
24 
25 struct secondary_cpu_entry_args {
26 	ffa_id_t receiver_id;
27 	ffa_vcpu_count_t vcpu_count;
28 };
29 
30 /**
31  * Communicates with partition via direct messaging to validate functioning of
32  * direct request/response interfaces.
33  */
TEST(ffa_msg_send_direct_req,succeeds_nwd_to_sp_echo)34 TEST(ffa_msg_send_direct_req, succeeds_nwd_to_sp_echo)
35 {
36 	const uint32_t msg[] = {0x22223333, 0x44445555, 0x66667777, 0x88889999};
37 	const ffa_id_t receiver_id = SP_ID(1);
38 	struct ffa_value res;
39 	ffa_id_t own_id = hf_vm_get_id();
40 
41 	res = sp_echo_cmd_send(own_id, receiver_id, msg[0], msg[1], msg[2],
42 			       msg[3]);
43 
44 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
45 
46 	EXPECT_EQ(res.arg4, msg[0]);
47 	EXPECT_EQ(res.arg5, msg[1]);
48 	EXPECT_EQ(res.arg6, msg[2]);
49 	EXPECT_EQ(res.arg7, msg[3]);
50 }
51 
52 /**
53  * Validate SP to SP direct messaging is functioning as expected.
54  */
TEST(ffa_msg_send_direct_req,succeeds_sp_to_sp_echo)55 TEST(ffa_msg_send_direct_req, succeeds_sp_to_sp_echo)
56 {
57 	const uint32_t msg[] = {0x22223333, 0x44445555, 0x66667777, 0x88889999};
58 	const ffa_id_t receiver_id = SP_ID(1);
59 	struct ffa_value res;
60 	ffa_id_t own_id = hf_vm_get_id();
61 
62 	res = sp_req_echo_cmd_send(own_id, receiver_id, msg[0], msg[1], msg[2],
63 				   msg[3]);
64 
65 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
66 	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
67 }
68 
69 /**
70  * Test that if a direct message request is sent to an SP that is already
71  * waiting for a direct message response an FFA_BUSY error code is returned.
72  */
TEST(ffa_msg_send_direct_req,fails_direct_req_to_waiting_sp)73 TEST(ffa_msg_send_direct_req, fails_direct_req_to_waiting_sp)
74 {
75 	const ffa_id_t receiver_id = SP_ID(1);
76 	struct ffa_value res;
77 	ffa_id_t own_id = hf_vm_get_id();
78 
79 	res = sp_req_echo_busy_cmd_send(own_id, receiver_id);
80 
81 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
82 	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
83 }
84 
85 /**
86  * Test various state transitions requested by an SP under RTM_FFA_DIR_REQ
87  * partition runtime model
88  */
TEST(partition_runtime_model,rtm_ffa_dir_req)89 TEST(partition_runtime_model, rtm_ffa_dir_req)
90 {
91 	const ffa_id_t receiver_id = SP_ID(1);
92 	const ffa_id_t companion_sp_id = SP_ID(2);
93 	struct ffa_value res;
94 	ffa_id_t own_id = hf_vm_get_id();
95 
96 	res = sp_check_state_transitions_cmd_send(own_id, receiver_id,
97 						  companion_sp_id);
98 
99 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
100 }
101 
migrate_busy_up_sp(uintptr_t arg)102 static void migrate_busy_up_sp(uintptr_t arg)
103 {
104 	ffa_id_t own_id = hf_vm_get_id();
105 	struct ffa_value res;
106 	const uint32_t msg[] = {SP_ECHO_CMD, 0x1, 0x2, 0x3, 0x4};
107 	struct secondary_cpu_entry_args *args =
108 		// NOLINTNEXTLINE(performance-no-int-to-ptr)
109 		(struct secondary_cpu_entry_args *)arg;
110 
111 	/*
112 	 * Wait till the primary VM on boot CPU has established the
113 	 * call chain with receiver SP.
114 	 */
115 	waitms(200);
116 
117 	/*
118 	 * A direct request message cannot be serviced by the receiver SP
119 	 * since it is in a BLOCKED state on a boot CPU.
120 	 */
121 	res = sp_echo_cmd_send(own_id, args->receiver_id, msg[0], msg[1],
122 			       msg[2], msg[3]);
123 
124 	EXPECT_EQ(ffa_func_id(res), FFA_ERROR_32);
125 
126 	/*
127 	 * An attempt to migrate the UP SP from boot CPU to current CPU using
128 	 * FFA_RUN interface should fail.
129 	 */
130 	res = ffa_run(args->receiver_id, 0);
131 
132 	EXPECT_EQ(ffa_func_id(res), FFA_ERROR_32);
133 
134 	arch_cpu_stop();
135 }
136 
137 /**
138  * Test to make sure the vCPU of an UP SP cannot be migrated from current CPU
139  * to a different physical CPU while the vCPU is in BLOCKED state as part of an
140  * SP call chain.
141  */
TEST_PRECONDITION_LONG_RUNNING(ffa_call_chain,disallow_migration_blocked_sp,service2_is_up_sp)142 TEST_PRECONDITION_LONG_RUNNING(ffa_call_chain, disallow_migration_blocked_sp,
143 			       service2_is_up_sp)
144 {
145 	struct ffa_value res;
146 	ffa_id_t own_id = hf_vm_get_id();
147 	struct secondary_cpu_entry_args args;
148 	struct mailbox_buffers mb = set_up_mailbox();
149 	struct ffa_partition_info *receiver_info = service2(mb.recv);
150 	struct ffa_partition_info *companion_info = service1(mb.recv);
151 	ffa_id_t receiver_id = receiver_info->vm_id;
152 	ffa_id_t companion_id = companion_info->vm_id;
153 
154 	args.receiver_id = receiver_id;
155 	args.vcpu_count = receiver_info->vcpu_count;
156 
157 	for (size_t i = 1; i < MAX_CPUS; i++) {
158 		uintptr_t id;
159 
160 		id = hftest_get_cpu_id(i);
161 		HFTEST_LOG("Booting CPU %zu - %lx", i, id);
162 
163 		EXPECT_EQ(
164 			hftest_cpu_start(id, hftest_get_secondary_ec_stack(i),
165 					 migrate_busy_up_sp, (uintptr_t)&args),
166 			true);
167 
168 		HFTEST_LOG("Done with CPU %zu", i);
169 	}
170 
171 	/*
172 	 * Send command to receiver SP to send command to companion SP to sleep
173 	 * there by putting receiver SP in BLOCKED state.
174 	 */
175 	res = sp_fwd_sleep_cmd_send(own_id, receiver_id, companion_id,
176 				    SP_SLEEP_LONG, 0);
177 
178 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
179 	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
180 }
181