1 /*
2 * Copyright 2024 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/power_mgmt.h"
10
11 #include "primary_with_secondary.h"
12 #include "test/hftest.h"
13 #include "test/semaphore.h"
14
console_log_str(const char * msg)15 void console_log_str(const char *msg)
16 {
17 size_t len = strnlen_s(msg, STRING_MAX_SIZE);
18 struct ffa_value ret = ffa_console_log_64(msg, len);
19 ASSERT_EQ(ret.func, FFA_SUCCESS_32);
20 }
21
console_log_int(uint64_t value)22 void console_log_int(uint64_t value)
23 {
24 const char *digits = "0123456789";
25 char str[64] = {0};
26 char *ptr = &str[sizeof(str) - 1];
27 do {
28 --ptr;
29 *ptr = digits[value % 10];
30 value /= 10;
31 } while (value);
32 console_log_str(ptr);
33 }
34
35 #define CONSOLE_LOG1(v1) \
36 (_Generic((v1), char *: console_log_str, default: console_log_int))(v1)
37
38 #define CONSOLE_LOG2(v1, v2) \
39 do { \
40 CONSOLE_LOG1(v1); \
41 CONSOLE_LOG1(v2); \
42 } while (0)
43 #define CONSOLE_LOG3(v1, v2, v3) \
44 do { \
45 CONSOLE_LOG1(v1); \
46 CONSOLE_LOG1(v2); \
47 CONSOLE_LOG1(v3); \
48 } while (0)
49 #define CONSOLE_LOG4(v1, v2, v3, v4) \
50 do { \
51 CONSOLE_LOG1(v1); \
52 CONSOLE_LOG1(v2); \
53 CONSOLE_LOG1(v3); \
54 CONSOLE_LOG1(v4); \
55 } while (0)
56 #define CONSOLE_LOG5(v1, v2, v3, v4, v5) \
57 do { \
58 CONSOLE_LOG1(v1); \
59 CONSOLE_LOG1(v2); \
60 CONSOLE_LOG1(v3); \
61 CONSOLE_LOG1(v4); \
62 CONSOLE_LOG1(v5); \
63 } while (0)
64
65 struct print_args {
66 struct ffa_partition_info *service_info;
67 size_t num_lines;
68 struct mailbox_buffers mb;
69 struct semaphore sync;
70 ffa_vcpu_index_t vcpu;
71 };
72
print_entry(uintptr_t arg)73 static void print_entry(uintptr_t arg)
74 {
75 ffa_vcpu_count_t vcpu;
76 size_t num_lines;
77
78 // NOLINTNEXTLINE(performance-no-int-to-ptr)
79 struct print_args *args = (struct print_args *)arg;
80 ASSERT_TRUE(args != NULL);
81
82 vcpu = args->vcpu;
83 num_lines = args->num_lines;
84
85 CONSOLE_LOG3("print: started core ", vcpu, "\n");
86
87 for (size_t line = 0; line < num_lines; line++) {
88 CONSOLE_LOG5("print: core ", vcpu, " line ", line, "\n");
89 }
90
91 CONSOLE_LOG3("print: done with core ", vcpu, "\n");
92
93 /* Signal to primary core that test is complete.*/
94 semaphore_signal(&args->sync);
95 CONSOLE_LOG3("print: stopping core ", vcpu, "\n");
96 arch_cpu_stop();
97 CONSOLE_LOG3("unreachable: stopped core ", vcpu, "\n");
98 }
99
print_test(bool concurrent,size_t num_cores,size_t num_lines)100 static void print_test(bool concurrent, size_t num_cores, size_t num_lines)
101 {
102 struct mailbox_buffers mb_mp = set_up_mailbox();
103 struct ffa_partition_info *service1_info = service1(mb_mp.recv);
104 struct print_args args[MAX_CPUS] = {0};
105
106 ASSERT_LE(num_cores, MAX_CPUS);
107
108 for (size_t i = 0; i < num_cores; i++) {
109 ffa_vcpu_index_t vcpu = i + 1;
110
111 args[i] = (struct print_args){
112 .service_info = service1_info,
113 .vcpu = vcpu,
114 .mb = mb_mp,
115 .num_lines = num_lines,
116 };
117
118 semaphore_init(&args[i].sync);
119 if (concurrent) {
120 CONSOLE_LOG3("concurrent: starting core ", vcpu, "\n");
121 } else {
122 CONSOLE_LOG3("sequential: starting core ", vcpu, "\n");
123 }
124
125 ASSERT_TRUE(hftest_cpu_start(hftest_get_cpu_id(vcpu),
126 hftest_get_secondary_ec_stack(i),
127 print_entry, (uintptr_t)&args[i]));
128
129 if (!concurrent) {
130 CONSOLE_LOG3("sequential: waiting for core ", vcpu,
131 "\n");
132 semaphore_wait(&args[i].sync);
133 CONSOLE_LOG3("sequential: done with core ", vcpu, "\n");
134 }
135 }
136
137 if (concurrent) {
138 for (size_t i = 0; i < num_cores; i++) {
139 ffa_vcpu_index_t vcpu = i + 1;
140
141 CONSOLE_LOG3("concurrent: waiting for core ", vcpu,
142 "\n");
143 semaphore_wait(&args[i].sync);
144 CONSOLE_LOG3("concurrent: done with core ", vcpu, "\n");
145 }
146 }
147 }
148
TEST_PRECONDITION_LONG_RUNNING(ffa_console_log,print_sequentially_4_cores_100_lines,service1_is_not_vm)149 TEST_PRECONDITION_LONG_RUNNING(ffa_console_log,
150 print_sequentially_4_cores_100_lines,
151 service1_is_not_vm)
152 {
153 print_test(false, 4, 100);
154 }
155
TEST_PRECONDITION_LONG_RUNNING(ffa_console_log,print_concurrently_4_cores_100_lines,service1_is_not_vm)156 TEST_PRECONDITION_LONG_RUNNING(ffa_console_log,
157 print_concurrently_4_cores_100_lines,
158 service1_is_not_vm)
159 {
160 print_test(true, 4, 100);
161 }
162