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