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