1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <lib/unittest/unittest.h>
18 #include <lib/coverage/common/cov_shm.h>
19 #include <interface/line-coverage/aggregator.h>
20 #include <lib/line-coverage/shm.h>
21 #include <lib/coverage/common/ipc.h>
22 #include <lib/tipc/tipc.h>
23 #include <lib/tipc/tipc_srv.h>
24 #include <lk/macros.h>
25 #include <stdarg.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <trusty/time.h>
31 #include <trusty_ipc.h>
32 #include <uapi/err.h>
33
34 #define LOG_TAG "unittest"
35
36 #include <lk/trace.h>
37
38 #define MAX_PORT_BUF_SIZE 4096 /* max size of per port buffer */
39
40 /*
41 * We can't use the normal TLOG functions because they send data through the
42 * channel managed by this code.
43 */
44
45 #define TLOGI(fmt, ...) \
46 do { \
47 fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__, ##__VA_ARGS__); \
48 } while (0)
49
50 static handle_t ipc_printf_handle = INVALID_IPC_HANDLE;
51
send_msg_wait(handle_t handle,struct ipc_msg * msg)52 static int send_msg_wait(handle_t handle, struct ipc_msg* msg) {
53 int ret;
54 struct uevent ev;
55
56 ret = send_msg(handle, msg);
57 if (ret != ERR_NOT_ENOUGH_BUFFER) {
58 return ret;
59 }
60
61 ret = wait(handle, &ev, INFINITE_TIME);
62 if (ret < 0) {
63 return ret;
64 }
65
66 if (ev.event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
67 return send_msg(handle, msg);
68 }
69
70 if (ev.event & IPC_HANDLE_POLL_MSG) {
71 return ERR_BUSY;
72 }
73
74 if (ev.event & IPC_HANDLE_POLL_HUP) {
75 return ERR_CHANNEL_CLOSED;
76 }
77
78 return ret;
79 }
80
get_current_time_ns(void)81 uint64_t get_current_time_ns(void) {
82 int64_t res;
83 trusty_gettime(0, &res);
84 return (uint64_t)res;
85 }
86
87 enum test_message_header {
88 TEST_PASSED = 0,
89 TEST_FAILED = 1,
90 TEST_MESSAGE = 2,
91 TEST_MESSAGE_HEADER_COUNT = 3,
92 };
93
_vtlog(const char * fmt,va_list args)94 int _vtlog(const char* fmt, va_list args) {
95 char buf[256];
96 struct iovec tx_iov = {buf, 1};
97 ipc_msg_t tx_msg = {1, &tx_iov, 0, NULL};
98 va_list ap;
99 int ret;
100 int slen;
101
102 /* Print to stderr as normal */
103 va_copy(ap, args);
104 ret = vfprintf(stderr, fmt, ap);
105 va_end(ap);
106 if (ret < 0) {
107 return ret;
108 }
109
110 /* Send over IPC */
111 if (ipc_printf_handle == INVALID_IPC_HANDLE) {
112 return 0;
113 }
114
115 va_copy(ap, args);
116 /* use filtered version for consistency with stderr logging */
117 ret = vsnprintf_filtered(buf + 1, sizeof(buf) - 1, fmt, ap);
118 va_end(ap);
119
120 if (ret < 0) {
121 return ret;
122 }
123 slen = MIN(ret, (int)sizeof(buf) - 1 - 1);
124
125 buf[0] = TEST_MESSAGE;
126 tx_iov.iov_len = 1 + slen;
127 ret = send_msg_wait(ipc_printf_handle, &tx_msg);
128 if (ret < 0) {
129 return ret;
130 }
131
132 return slen;
133 }
134
135 /*
136 * Application entry point
137 */
unittest_main(struct unittest ** tests,size_t test_count)138 int unittest_main(struct unittest** tests, size_t test_count) {
139 int ret;
140 handle_t hset;
141 uevent_t evt = {
142 .event = ~0U,
143 };
144 struct unittest* test;
145 uuid_t unused_uuid;
146
147 ret = handle_set_create();
148 if (ret < 0) {
149 TLOGI("failed to create handle set: %d\n", ret);
150 return ret;
151 }
152 hset = ret;
153
154 /* create control port and just wait on it */
155 for (; test_count; test_count--) {
156 test = *tests++;
157 ret = port_create(
158 test->port_name, 1, MAX_PORT_BUF_SIZE,
159 IPC_PORT_ALLOW_NS_CONNECT | IPC_PORT_ALLOW_TA_CONNECT);
160 if (ret < 0) {
161 TLOGI("failed to create port %s: %d\n", test->port_name, ret);
162 return ret;
163 }
164 test->_port_handle = (handle_t)ret;
165 evt.handle = test->_port_handle;
166 evt.cookie = test;
167 ret = handle_set_ctrl(hset, HSET_ADD, &evt);
168 if (ret < 0) {
169 TLOGI("failed to add %s to handle set: %d\n", test->port_name, ret);
170 return ret;
171 }
172 }
173
174 setup_mailbox(&((struct tipc_port){ .name = test->port_name }), 1);
175
176 /* and just wait forever for now */
177 for (;;) {
178 ret = wait(hset, &evt, INFINITE_TIME);
179 test = evt.cookie;
180 TLOGI("got event (ret=%d): ev=%x handle=%d port=%s\n", ret, evt.event,
181 evt.handle, test->port_name);
182 if (ret < 0)
183 break;
184 if (evt.event & IPC_HANDLE_POLL_READY) {
185 /* get connection request */
186 setup_shm();
187 ret = accept(evt.handle, &unused_uuid);
188 TLOGI("accept returned %d\n", ret);
189 if (ret >= 0) {
190 char tx_buffer[1];
191 struct iovec tx_iov = {
192 tx_buffer,
193 sizeof(tx_buffer),
194 };
195 ipc_msg_t tx_msg = {1, &tx_iov, 0, NULL};
196
197 /* then run unittest test */
198 ipc_printf_handle = ret;
199 tx_buffer[0] = test->run_test(test) ? TEST_PASSED : TEST_FAILED;
200 ipc_printf_handle = INVALID_IPC_HANDLE;
201
202 send_msg_wait(ret, &tx_msg);
203
204 /* and close it */
205 close(ret);
206
207 dump_shm();
208 }
209 }
210 }
211
212 return ret;
213 }
214