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