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