1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <string.h>
14#include <stdio.h>
15
16#include <sel4/sel4.h>
17#include <vka/capops.h>
18#include <sel4utils/thread.h>
19#include <serial_server/parent.h>
20#include <serial_server/client.h>
21
22#include <sel4test/test.h>
23#include <sel4test/testutil.h>
24
25#define SERSERV_TEST_PRIO_SERVER    (seL4_MaxPrio - 1)
26
27static const char *test_str = "Hello, world!\n";
28
29void get_serial_server_parent_tests()
30{
31}
32
33static int
34test_server_spawn(struct env *env)
35{
36    int        error;
37
38    error = serial_server_parent_spawn_thread(&env->simple,
39                                              &env->vka, &env->vspace,
40                                              SERSERV_TEST_PRIO_SERVER);
41
42    test_eq(error, 0);
43    return sel4test_get_result();
44}
45DEFINE_TEST(SERSERV_PARENT_001, "Serial server spawn test", test_server_spawn, true)
46
47static int
48test_parent_connect(struct env *env)
49{
50    int error;
51    serial_client_context_t conn;
52    cspacepath_t badged_server_ep_cspath;
53
54    error = serial_server_parent_spawn_thread(&env->simple,
55                                              &env->vka, &env->vspace,
56                                              SERSERV_TEST_PRIO_SERVER);
57
58    test_eq(error, 0);
59
60    error = serial_server_parent_vka_mint_endpoint(&env->vka, &badged_server_ep_cspath);
61    test_eq(error, 0);
62
63    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
64                                         &env->vka, &env->vspace, &conn);
65    test_eq(error, 0);
66
67    return  sel4test_get_result();
68}
69DEFINE_TEST(SERSERV_PARENT_002, "Test connecting to the server from a parent thread", test_parent_connect, true)
70
71static int
72test_parent_printf(struct env *env)
73{
74    int error;
75    serial_client_context_t conn;
76    cspacepath_t badged_server_ep_cspath;
77
78    error = serial_server_parent_spawn_thread(&env->simple,
79                                              &env->vka, &env->vspace,
80                                              SERSERV_TEST_PRIO_SERVER);
81
82    test_eq(error, 0);
83
84    error = serial_server_parent_vka_mint_endpoint(&env->vka, &badged_server_ep_cspath);
85    test_eq(error, 0);
86
87    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
88                                         &env->vka, &env->vspace, &conn);
89    test_eq(error, 0);
90
91    error = serial_server_printf(&conn, test_str);
92    test_eq(error, (int)strlen(test_str));
93    return sel4test_get_result();
94}
95DEFINE_TEST(SERSERV_PARENT_003, "Printf() from a connected parent thread", test_parent_printf, true)
96
97static int
98test_parent_write(struct env *env)
99{
100    int error;
101    serial_client_context_t conn;
102    cspacepath_t badged_server_ep_cspath;
103
104    error = serial_server_parent_spawn_thread(&env->simple,
105                                              &env->vka, &env->vspace,
106                                              SERSERV_TEST_PRIO_SERVER);
107
108    test_eq(error, 0);
109
110    error = serial_server_parent_vka_mint_endpoint(&env->vka, &badged_server_ep_cspath);
111    test_eq(error, 0);
112
113    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
114                                         &env->vka, &env->vspace, &conn);
115    test_eq(error, 0);
116
117    error = serial_server_write(&conn, test_str, strlen(test_str));
118    test_eq(error, (int)strlen(test_str));
119
120    return sel4test_get_result();
121}
122DEFINE_TEST(SERSERV_PARENT_004, "Write() from a connected parent thread", test_parent_write, true)
123
124static int
125test_parent_disconnect_reconnect_write_and_printf(struct env *env)
126{
127    int error;
128    serial_client_context_t conn;
129    cspacepath_t badged_server_ep_cspath;
130
131    error = serial_server_parent_spawn_thread(&env->simple,
132                                              &env->vka, &env->vspace,
133                                              SERSERV_TEST_PRIO_SERVER);
134
135    test_eq(error, 0);
136
137    error = serial_server_parent_vka_mint_endpoint(&env->vka, &badged_server_ep_cspath);
138    test_eq(error, 0);
139
140    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
141                                         &env->vka, &env->vspace, &conn);
142    test_eq(error, 0);
143
144    error = serial_server_printf(&conn, test_str);
145    test_eq(error, (int)strlen(test_str));
146    error = serial_server_write(&conn, test_str, strlen(test_str));
147    test_eq(error, (int)strlen(test_str));
148
149    /* Disconnect then reconnect and attempt to print */
150    serial_server_disconnect(&conn);
151
152    /* Need to re-obtain new badge values, as the Server may not hand out the
153     * same badge values the second time. Free the previous Endpoint cap.
154     */
155    vka_cnode_delete(&badged_server_ep_cspath);
156    error = serial_server_parent_vka_mint_endpoint(&env->vka, &badged_server_ep_cspath);
157    test_eq(error, 0);
158
159    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
160                                         &env->vka, &env->vspace, &conn);
161    test_eq(error, 0);
162
163    error = serial_server_write(&conn, test_str, strlen(test_str));
164    test_eq(error, (int)strlen(test_str));
165    error = serial_server_printf(&conn, test_str);
166    test_eq(error, (int)strlen(test_str));
167
168    return sel4test_get_result();
169}
170DEFINE_TEST(SERSERV_PARENT_005,
171            "Test printf() and write() from a parent thread when after a "
172            "connection reset (disconnect/reconnect)",
173            test_parent_disconnect_reconnect_write_and_printf,
174            true)
175
176static int
177test_kill_from_parent(struct env *env)
178{
179    int error;
180    serial_client_context_t conn;
181    cspacepath_t badged_server_ep_cspath;
182
183    error = serial_server_parent_spawn_thread(&env->simple,
184                                              &env->vka, &env->vspace,
185                                              SERSERV_TEST_PRIO_SERVER);
186    test_eq(error, 0);
187
188    error = serial_server_parent_vka_mint_endpoint(&env->vka, &badged_server_ep_cspath);
189    test_eq(error, 0);
190
191    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
192                                         &env->vka, &env->vspace, &conn);
193    test_eq(error, 0);
194
195    /* Kill the Server from the parent. */
196    error = serial_server_kill(&conn);
197    test_eq(error, 0);
198
199    return sel4test_get_result();
200}
201DEFINE_TEST(SERSERV_PARENT_006, "Kill the Server from the Parent thread",
202            test_kill_from_parent, true)
203
204static int
205test_spawn_thread_inputs(struct env *env)
206{
207    int error;
208
209    /* Test NULL inputs to spawn_thread(). */
210    error = serial_server_parent_spawn_thread(NULL, &env->vka,
211                                              &env->vspace,
212                                              SERSERV_TEST_PRIO_SERVER);
213    test_neq(error, 0);
214    error = serial_server_parent_spawn_thread(&env->simple, NULL,
215                                              &env->vspace,
216                                              SERSERV_TEST_PRIO_SERVER);
217    test_neq(error, 0);
218    error = serial_server_parent_spawn_thread(&env->simple, &env->vka,
219                                              NULL,
220                                              SERSERV_TEST_PRIO_SERVER);
221    test_neq(error, 0);
222
223    return sel4test_get_result();
224}
225DEFINE_TEST(SERSERV_PARENT_007, "Test a series of unexpected input values to spawn_thread",
226            test_spawn_thread_inputs, true)
227
228static int
229test_connect_inputs(struct env *env)
230{
231    int error;
232    serial_client_context_t conn;
233    cspacepath_t badged_server_ep_cspath;
234
235    /* Test NULL inputs to connect(). */
236    error = serial_server_parent_spawn_thread(&env->simple, &env->vka,
237                                              &env->vspace,
238                                              SERSERV_TEST_PRIO_SERVER);
239    test_eq(error, 0);
240    error = serial_server_parent_vka_mint_endpoint(NULL, &badged_server_ep_cspath);
241    test_neq(error, 0);
242    error = serial_server_parent_vka_mint_endpoint(&env->vka, NULL);
243    test_neq(error, 0);
244    error = serial_server_parent_vka_mint_endpoint(&env->vka, &badged_server_ep_cspath);
245    test_eq(error, 0);
246
247    error = serial_server_client_connect(0,
248                                         &env->vka, &env->vspace, &conn);
249    test_neq(error, 0);
250    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
251                                         NULL, &env->vspace, &conn);
252    test_neq(error, 0);
253    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
254                                         &env->vka, NULL, &conn);
255    test_neq(error, 0);
256    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
257                                         &env->vka, &env->vspace, NULL);
258    test_neq(error, 0);
259
260    return sel4test_get_result();
261}
262DEFINE_TEST(SERSERV_PARENT_008, "Test a series of unexpected input values to connect()",
263            test_connect_inputs, true)
264
265static int
266test_printf_inputs(struct env *env)
267{
268    int error;
269    serial_client_context_t conn;
270    cspacepath_t badged_server_ep_cspath;
271
272    /* Test NULL inputs to printf(). */
273    error = serial_server_parent_spawn_thread(&env->simple, &env->vka,
274                                              &env->vspace,
275                                              SERSERV_TEST_PRIO_SERVER);
276    test_eq(error, 0);
277    error = serial_server_parent_vka_mint_endpoint(&env->vka, &badged_server_ep_cspath);
278    test_eq(error, 0);
279    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
280                                         &env->vka, &env->vspace, &conn);
281    test_eq(error, 0);
282
283    error = serial_server_printf(NULL, test_str);
284    test_neq(error, (int)strlen(test_str));
285    error = serial_server_printf(&conn, NULL);
286    test_neq(error, (int)strlen(test_str));
287
288    return sel4test_get_result();
289}
290DEFINE_TEST(SERSERV_PARENT_009, "Test a series of unexpected input values to printf()",
291            test_printf_inputs, true)
292
293static int
294test_write_inputs(struct env *env)
295{
296    int error;
297    serial_client_context_t conn;
298    cspacepath_t badged_server_ep_cspath;
299
300    /* Test NULL inputs to printf(). */
301    error = serial_server_parent_spawn_thread(&env->simple, &env->vka,
302                                              &env->vspace,
303                                              SERSERV_TEST_PRIO_SERVER);
304    test_eq(error, 0);
305    error = serial_server_parent_vka_mint_endpoint(&env->vka, &badged_server_ep_cspath);
306    test_eq(error, 0);
307    error = serial_server_client_connect(badged_server_ep_cspath.capPtr,
308                                         &env->vka, &env->vspace, &conn);
309    test_eq(error, 0);
310
311    error = serial_server_write(NULL, test_str, strlen(test_str));
312    test_neq(error, (int)strlen(test_str));
313    error = serial_server_write(&conn, NULL, 500);
314    test_neq(error, (int)strlen(test_str));
315    error = serial_server_write(&conn, test_str, 0);
316    test_neq(error, (int)strlen(test_str));
317
318    return sel4test_get_result();
319}
320DEFINE_TEST(SERSERV_PARENT_010, "Test a series of unexpected input values to write()",
321            test_write_inputs, true)
322
323