1 /*
2 * Copyright (C) 2019 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 <stddef.h>
18 #include <stdio.h>
19 #include <uapi/err.h>
20
21 #include <lib/uirq/uirq.h>
22 #include <trusty_ipc.h>
23 #include <trusty_uio.h>
24
25 #define TLOG_TAG "uirq-unittest"
26 #include <trusty_unittest.h>
27
28 #define MAX_UIRQ_CNT 100
29 #define TEST_UIRQ_10MS "test-uirq-10ms"
30 #define TEST_UIRQ_NO_ACCESS "test-uirq-no-access"
31 #define TEST_UIRQ_PORT "test-uirq-port"
32
33 #define FAIL_TIMEOUT 5000
34
35 typedef struct uirq {
36 handle_t hset;
37 handle_t hevts;
38 handle_t hevt1;
39 handle_t hevt2;
40 } uirq_t;
41
TEST_F_SETUP(uirq)42 TEST_F_SETUP(uirq) {
43 _state->hset = INVALID_IPC_HANDLE;
44 _state->hevts = INVALID_IPC_HANDLE;
45 _state->hevt1 = INVALID_IPC_HANDLE;
46 _state->hevt2 = INVALID_IPC_HANDLE;
47 }
48
TEST_F_TEARDOWN(uirq)49 TEST_F_TEARDOWN(uirq) {
50 (void)close(_state->hset);
51 (void)close(_state->hevts);
52 (void)close(_state->hevt1);
53 (void)close(_state->hevt2);
54 }
55
TEST_F(uirq,uirq_test_open_no_access)56 TEST_F(uirq, uirq_test_open_no_access) {
57 /* open unaccessible uirq event */
58 _state->hevt1 = uirq_open(TEST_UIRQ_NO_ACCESS, 0);
59 EXPECT_EQ(ERR_NOT_FOUND, _state->hevt1, "open no-access uirq event");
60
61 test_abort:;
62 }
63
TEST_F(uirq,uirq_test_handle_single)64 TEST_F(uirq, uirq_test_handle_single) {
65 int rc;
66 uevent_t uevt;
67 uint32_t evt_cnt = 0;
68
69 /* open uirq */
70 _state->hevt1 = uirq_open(TEST_UIRQ_10MS, 0);
71 ASSERT_GE(_state->hevt1, 0, "open uirq");
72
73 /* handle test uirq event MAX_UIRQ_CNT times */
74 while (evt_cnt < MAX_UIRQ_CNT) {
75 rc = wait(_state->hevt1, &uevt, FAIL_TIMEOUT);
76 ASSERT_EQ(0, rc, "wait for uirq");
77 ASSERT_EQ(uevt.handle, _state->hevt1);
78
79 evt_cnt++;
80 rc = uirq_ack_handled(_state->hevt1);
81 ASSERT_EQ(0, rc, "ack uirq");
82 }
83 EXPECT_EQ(MAX_UIRQ_CNT, evt_cnt, "evt1 count");
84
85 test_abort:;
86 }
87
TEST_F(uirq,uirq_test_handle_multiple)88 TEST_F(uirq, uirq_test_handle_multiple) {
89 int rc;
90 uevent_t uevt;
91 uint32_t ttl_cnt = 0;
92 uint32_t evt1_cnt = 0;
93 uint32_t evt2_cnt = 0;
94
95 /* create handle set */
96 _state->hset = handle_set_create();
97 ASSERT_GE(_state->hset, 0, "create handle set");
98
99 /* open uirq event */
100 _state->hevt1 = uirq_open(TEST_UIRQ_10MS, 0);
101 ASSERT_GE(_state->hevt1, 0, "open uirq");
102
103 /* open the same uirq event */
104 _state->hevt2 = uirq_open(TEST_UIRQ_10MS, 0);
105 ASSERT_GE(_state->hevt2, 0, "open uirq");
106
107 /* Add all uirq events to handle set */
108 uevt.handle = _state->hevt1;
109 uevt.event = ~0U;
110 uevt.cookie = NULL;
111 rc = handle_set_ctrl(_state->hset, HSET_ADD, &uevt);
112 ASSERT_EQ(0, rc);
113
114 uevt.handle = _state->hevt2;
115 uevt.event = ~0U;
116 uevt.cookie = NULL;
117 rc = handle_set_ctrl(_state->hset, HSET_ADD, &uevt);
118 ASSERT_EQ(0, rc);
119
120 /* trigger and handle uirq event MAX_UIRQ_CNT times */
121 while (ttl_cnt < MAX_UIRQ_CNT * 2) {
122 rc = wait(_state->hset, &uevt, FAIL_TIMEOUT);
123 ASSERT_EQ(0, rc, "wait for uirq");
124
125 if (uevt.handle == _state->hevt1) {
126 evt1_cnt++;
127 rc = uirq_ack_handled(_state->hevt1);
128 ASSERT_EQ(0, rc, "ack uirq");
129
130 } else if (uevt.handle == _state->hevt2) {
131 evt2_cnt++;
132 rc = uirq_ack_handled(_state->hevt2);
133 ASSERT_EQ(0, rc, "ack uirq");
134 } else {
135 break;
136 }
137 ttl_cnt++;
138 }
139 EXPECT_EQ(MAX_UIRQ_CNT * 2, ttl_cnt, "total count");
140 EXPECT_EQ(MAX_UIRQ_CNT, evt1_cnt, "evt1 count");
141 EXPECT_EQ(MAX_UIRQ_CNT, evt2_cnt, "evt2 count");
142
143 test_abort:;
144 }
145
TEST(uirq,invalid_ack_handled)146 TEST(uirq, invalid_ack_handled) {
147 int rc;
148 uint32_t cmd;
149 handle_t port;
150
151 /* Create port to use it as target for this test */
152 rc = port_create(TEST_UIRQ_PORT, 1, 1, IPC_PORT_ALLOW_TA_CONNECT);
153 ASSERT_GE(rc, 0);
154 port = (handle_t)rc;
155
156 /* ack existing but invalid handle: should return ERR_NOT_SUPPORTED */
157 rc = uirq_ack_handled(port);
158 EXPECT_EQ(ERR_NOT_SUPPORTED, rc);
159
160 /* use direct write to invalid handle: should return ERR_NOT_SUPPORTED */
161 cmd = 1;
162 rc = trusty_write(port, &cmd, sizeof(cmd));
163 EXPECT_EQ(ERR_NOT_SUPPORTED, rc);
164
165 /* use direct read from invalid handle: should return ERR_NOT_SUPPORTED */
166 rc = trusty_read(port, &cmd, sizeof(cmd));
167 EXPECT_EQ(ERR_NOT_SUPPORTED, rc);
168
169 close(port);
170 test_abort:;
171 }
172
173 PORT_TEST(uirq, "com.android.uirq-unittest");
174