1 /*
2  * Copyright (c) 2019, Google Inc. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <err.h>
25 #include <kernel/event.h>
26 #include <kernel/thread.h>
27 #include <lib/trusty/ipc.h>
28 #include <lk/init.h>
29 #include <lk/trace.h>
30 #include <stdbool.h>
31 #include <stdio.h>
32 
33 #define LOCAL_TRACE (0)
34 
35 static struct event busy_test_event =
36         EVENT_INITIAL_VALUE(busy_test_event, false, 0);
37 
busy_test_connected(struct handle * chandle)38 static void busy_test_connected(struct handle* chandle) {
39     int ret;
40     uint32_t event;
41 
42     LTRACEF("event wait count: %d\n", busy_test_event.wait.count);
43 
44     ret = event_signal(&busy_test_event, true);
45     if (ret) {
46         TRACEF("event_signal failed %d\n", ret);
47         goto err;
48     }
49     ret = handle_wait(chandle, &event, INFINITE_TIME);
50     LTRACEF("got channel event (ret=%d): ev=%x\n", ret, event);
51 
52 err:
53     ret = event_unsignal(&busy_test_event);
54     if (ret) {
55         TRACEF("event_unsignal failed %d\n", ret);
56     }
57     handle_close(chandle);
58 }
59 
busy_test_server(void * arg)60 static int busy_test_server(void* arg) {
61     struct handle* phandle = arg;
62     struct handle* chandle;
63     const uuid_t* unused_uuid_p;
64     uint32_t event;
65     int ret;
66 
67     while (true) {
68         ret = handle_wait(phandle, &event, INFINITE_TIME);
69         if (ret < 0) {
70             TRACEF("handle_wait failed: %d\n", ret);
71             break;
72         }
73         LTRACEF("got port event (ret=%d): ev=%x\n", ret, event);
74         if (event & IPC_HANDLE_POLL_READY) {
75             /* get connection request */
76             ret = ipc_port_accept(phandle, &chandle, &unused_uuid_p);
77             LTRACEF("accept returned %d\n", ret);
78             if (ret >= 0) {
79                 busy_test_connected(chandle);
80             }
81         }
82     }
83     return 0;
84 }
85 
busy_test_init(uint level)86 static void busy_test_init(uint level) {
87     int ret;
88     thread_t* thread;
89     struct handle* phandle;
90 
91     ret = ipc_port_create(&kernel_uuid, "com.android.kernel.busy-test", 1, 1,
92                           IPC_PORT_ALLOW_NS_CONNECT, &phandle);
93     if (ret) {
94         goto err_port_create;
95     }
96 
97     ret = ipc_port_publish(phandle);
98     if (ret) {
99         goto err_port_publish;
100     }
101 
102     thread = thread_create("busy-test-server", busy_test_server, phandle,
103                            DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
104     if (!thread) {
105         ret = ERR_NO_MEMORY;
106         goto err_thread_create;
107     }
108     thread_resume(thread);
109     return;
110 
111 err_thread_create:
112     handle_close(phandle);
113 err_port_publish:
114     handle_close(phandle);
115 err_port_create:
116     TRACEF("Failed to add busy_test: %d\n", ret);
117     return;
118 }
119 
120 LK_INIT_HOOK(busy_test_init, busy_test_init, LK_INIT_LEVEL_APPS);
121 
busy_test_busy_func(void * arg)122 static int busy_test_busy_func(void* arg) {
123     LTRACEF("cpu %d ready\n", arch_curr_cpu_num());
124     while (true) {
125         event_wait(&busy_test_event);
126     }
127     return 0;
128 }
129 
busy_test_cpu_init(uint level)130 static void busy_test_cpu_init(uint level) {
131     thread_t* thread;
132     char thread_name[32];
133     uint cpu = arch_curr_cpu_num();
134     snprintf(thread_name, sizeof(thread_name), "busy-test-%d", cpu);
135     thread = thread_create(thread_name, busy_test_busy_func, NULL, LOW_PRIORITY,
136                            DEFAULT_STACK_SIZE);
137 #if WITH_SMP
138     thread->pinned_cpu = cpu;
139 #endif
140     thread_resume(thread);
141 }
142 
143 LK_INIT_HOOK_FLAGS(busy_test_cpu_init,
144                    busy_test_cpu_init,
145                    LK_INIT_LEVEL_APPS,
146                    LK_INIT_FLAG_ALL_CPUS);
147