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