1 /*
2  * Copyright 2023 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/dlog.h"
10 #include "hf/ffa.h"
11 
12 #include "vmapi/hf/call.h"
13 
14 #include "ffa_secure_partitions.h"
15 #include "partition_services.h"
16 #include "test/hftest.h"
17 #include "test/vmapi/ffa.h"
18 
19 #define SP2_ESPI_TEST_INTID 5000
20 
21 /*
22  * The following is a precondition function, for the current system set-up.
23  * Check that SP 1 is configured to fail at boot in this setup.
24  */
sp1_fail_at_boot(void)25 bool sp1_fail_at_boot(void)
26 {
27 	return (FAILING_SP == 1);
28 }
29 
30 /*
31  * The following is a precondition function, for the current system set-up.
32  * Check that SP 2 is configured to fail at boot in this setup.
33  */
sp2_fail_at_boot(void)34 bool sp2_fail_at_boot(void)
35 {
36 	return (FAILING_SP == 2);
37 }
38 
39 /*
40  * The following is a precondition function, for the current system set-up.
41  * Check that SP 3 is configured to fail at boot in this setup.
42  */
sp3_fail_at_boot(void)43 bool sp3_fail_at_boot(void)
44 {
45 	return (FAILING_SP == 3);
46 }
47 
nwd_to_sp_echo(ffa_id_t receiver_id)48 static void nwd_to_sp_echo(ffa_id_t receiver_id)
49 {
50 	const uint32_t msg[] = {0x22223333, 0x44445555, 0x66667777, 0x88889999};
51 	struct ffa_value res;
52 	ffa_id_t own_id = hf_vm_get_id();
53 
54 	res = sp_echo_cmd_send(own_id, receiver_id, msg[0], msg[1], msg[2],
55 			       msg[3]);
56 
57 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
58 
59 	EXPECT_EQ(res.arg4, msg[0]);
60 	EXPECT_EQ(res.arg5, msg[1]);
61 	EXPECT_EQ(res.arg6, msg[2]);
62 	EXPECT_EQ(res.arg7, msg[3]);
63 }
64 /**
65  * This test uses a setup in which the SP providing service1 reports an error
66  * during initialization. The test checks that the SP returns an error with
67  * FFA_ABORTED error code when ffa_run attempts to allocate CPU cycles to the
68  * aborted SP.
69  *
70  * It also ensure that the subsequent services (2 and 3) are still
71  * able to successfully boot by performing a direct message/direct response
72  * echo test.
73  */
TEST_PRECONDITION(boot_fail,sp1_fails_to_init,sp1_fail_at_boot)74 TEST_PRECONDITION(boot_fail, sp1_fails_to_init, sp1_fail_at_boot)
75 {
76 	struct mailbox_buffers mb = set_up_mailbox();
77 	struct ffa_partition_info *service1_info = service1(mb.recv);
78 	struct ffa_partition_info *service2_info = service2(mb.recv);
79 	struct ffa_partition_info *service3_info = service3(mb.recv);
80 	struct ffa_value ret;
81 
82 	ret = ffa_run(service1_info->vm_id, 0);
83 	EXPECT_FFA_ERROR(ret, FFA_ABORTED);
84 
85 	nwd_to_sp_echo(service2_info->vm_id);
86 	nwd_to_sp_echo(service3_info->vm_id);
87 }
88 
89 /**
90  * This test uses a setup in which the SP providing service2 reports an error
91  * during initialization. The test checks that SP 2 returns an error with
92  * FFA_ABORTED error code when ffa_run attempts to allocate CPU cycles to the
93  * aborted SP.
94  *
95  * It also ensure that the other services, (1 and 3) are still
96  * able to successfully boot by performing a direct message/direct response
97  * echo test.
98  */
TEST_PRECONDITION(boot_fail,sp2_fails_to_init,sp2_fail_at_boot)99 TEST_PRECONDITION(boot_fail, sp2_fails_to_init, sp2_fail_at_boot)
100 {
101 	struct mailbox_buffers mb = set_up_mailbox();
102 	struct ffa_partition_info *service1_info = service1(mb.recv);
103 	struct ffa_partition_info *service2_info = service2(mb.recv);
104 	struct ffa_partition_info *service3_info = service3(mb.recv);
105 	struct ffa_value ret;
106 
107 	ret = ffa_run(service2_info->vm_id, 0);
108 	EXPECT_FFA_ERROR(ret, FFA_ABORTED);
109 
110 	nwd_to_sp_echo(service1_info->vm_id);
111 	nwd_to_sp_echo(service3_info->vm_id);
112 }
113 
114 /**
115  * This test is an extension of the prior test, sp2_fails_to_init. It aims to
116  * validate the functionality of SPMC to reclaim resources, such as interrupts,
117  * belonging to an aborted SP. It does so by sending a command to SP1 to pend
118  * an espi interrupt belonging to the aborted SP2.
119  *
120  * The SPMC shall not resume the execution context of aborted SP2. Similar to
121  * the prior test, it ensures SP1 and SP3 boot successfully by performing echo
122  * tests.
123  */
TEST_PRECONDITION(boot_fail,secure_interrupt_targets_aborted_sp2,sp2_fail_at_boot)124 TEST_PRECONDITION(boot_fail, secure_interrupt_targets_aborted_sp2,
125 		  sp2_fail_at_boot)
126 {
127 	struct mailbox_buffers mb = set_up_mailbox();
128 	struct ffa_partition_info *service1_info = service1(mb.recv);
129 	struct ffa_partition_info *service2_info = service2(mb.recv);
130 	struct ffa_partition_info *service3_info = service3(mb.recv);
131 	struct ffa_value ret;
132 
133 	ret = sp_trigger_espi_cmd_send(hf_vm_get_id(), service1_info->vm_id,
134 				       SP2_ESPI_TEST_INTID);
135 	EXPECT_EQ(ret.func, FFA_MSG_SEND_DIRECT_RESP_32);
136 	EXPECT_EQ(sp_resp(ret), SP_SUCCESS);
137 
138 	nwd_to_sp_echo(service1_info->vm_id);
139 	nwd_to_sp_echo(service3_info->vm_id);
140 
141 	/* The aborted SP shall not be resumed by a direct request message. */
142 	ret = sp_get_last_interrupt_cmd_send(hf_vm_get_id(),
143 					     service2_info->vm_id);
144 	EXPECT_FFA_ERROR(ret, FFA_ABORTED);
145 }
146 
147 /**
148  * This test uses a setup in which the SP providing service3 reports an error
149  * during initialization. The test checks that SP 3 returns an error with
150  * FFA_ABORTED error code when ffa_run attempts to allocate CPU cycles to the
151  * aborted SP.
152  *
153  * It also ensure that the other services (1 and 2) are still
154  * able to successfully boot by performing a direct message/direct response
155  * echo test.
156  */
TEST_PRECONDITION(boot_fail,sp3_fails_to_init,sp3_fail_at_boot)157 TEST_PRECONDITION(boot_fail, sp3_fails_to_init, sp3_fail_at_boot)
158 {
159 	struct mailbox_buffers mb = set_up_mailbox();
160 	struct ffa_partition_info *service1_info = service1(mb.recv);
161 	struct ffa_partition_info *service2_info = service2(mb.recv);
162 	struct ffa_partition_info *service3_info = service3(mb.recv);
163 	struct ffa_value ret;
164 
165 	ret = ffa_run(service3_info->vm_id, 0);
166 	EXPECT_FFA_ERROR(ret, FFA_ABORTED);
167 
168 	nwd_to_sp_echo(service1_info->vm_id);
169 	nwd_to_sp_echo(service2_info->vm_id);
170 }
171 
172 /**
173  * This test confirms that an service which has been aborted due to an
174  * initilaization failure cannot be resumed by a direct messaging interface.
175  */
TEST_PRECONDITION(boot_fail,dir_msg_to_failed_sp,sp1_fail_at_boot)176 TEST_PRECONDITION(boot_fail, dir_msg_to_failed_sp, sp1_fail_at_boot)
177 {
178 	const uint32_t msg[] = {0x22223333, 0x44445555, 0x66667777, 0x88889999};
179 	const ffa_id_t receiver_id = SP_ID(1);
180 	struct ffa_value ret;
181 	ffa_id_t own_id = hf_vm_get_id();
182 
183 	ret = sp_echo_cmd_send(own_id, receiver_id, msg[0], msg[1], msg[2],
184 			       msg[3]);
185 
186 	EXPECT_FFA_ERROR(ret, FFA_ABORTED);
187 }
188