1/*
2 * Copyright 2016, 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(D61_BSD)
11 */
12
13#include <autoconf.h>
14
15#ifdef CONFIG_REFOS_RUN_TESTS
16
17#include <assert.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22#include <refos/refos.h>
23#include <refos/test.h>
24#include <refos/error.h>
25#include <refos/share.h>
26#include <refos/vmlayout.h>
27#include <refos-io/morecore.h>
28#include <refos-io/stdio.h>
29#include <refos-rpc/name_client.h>
30#include <refos-rpc/name_client_helper.h>
31#include <refos-rpc/proc_client.h>
32#include <refos-rpc/proc_client_helper.h>
33#include <refos-rpc/data_client.h>
34#include <refos-rpc/data_client_helper.h>
35#include <refos-rpc/serv_client.h>
36#include <refos-util/cspace.h>
37#include <refos-util/init.h>
38#include <refos-util/walloc.h>
39
40#include "test_fileserv.h"
41#include "test_anon_ram.h"
42
43/* Debug printing. */
44#include <refos-util/dprintf.h>
45
46#define MMAP_SIZE 0x100000 // 16MB.
47static char mmapRegion[MMAP_SIZE];
48
49extern uintptr_t __vsyscall_ptr;
50
51#define BSS_MAGIC 0xBA13DD37
52#define BSS_ARRAY_SIZE 0x20000
53#define TEST_KERNEL_VM_RESERVED_START 0xE0000000
54#define TEST_USERLAND_TEST_APP "/fileserv/test_user"
55
56char bssArray[BSS_ARRAY_SIZE];
57int bssVar = BSS_MAGIC;
58int bssVar2;
59
60const char* dprintfServerName = "OS_TEST";
61int dprintfServerColour = 37;
62
63/* ---------------------------------- Memory tests ---------------------------------------- */
64
65static int
66test_bss(void)
67{
68    test_start("bss zero");
69    test_assert(bssVar == BSS_MAGIC);
70    test_assert(bssVar2 == 0);
71    for (int i = 0; i < BSS_ARRAY_SIZE; i++) {
72        test_assert(bssArray[i] == 0);
73        bssArray[i] = (char)((i*7)%250);
74    }
75    test_assert(bssVar == BSS_MAGIC);
76    test_assert(bssVar2 == 0);
77    for (int i = 0; i < BSS_ARRAY_SIZE; i++) {
78        test_assert(bssArray[i] == (char)((i*7)%250));
79    }
80    return test_success();
81}
82
83static int
84test_stack(void)
85{
86    test_start("stack");
87    const size_t stackAllocSize = 0x2000;
88    char stackArray[stackAllocSize];
89    for (int i = 0; i < stackAllocSize; i++) {
90        stackArray[i] = (char)(i * 1234);
91    }
92    for (int i = 0; i < stackAllocSize; i++) {
93        test_assert( stackArray[i] == (char)(i * 1234));
94    }
95    return test_success();
96}
97
98static int
99test_heap(void)
100{
101    test_start("heap");
102    /* Test heap malloc actually works. */
103    const size_t heapAllocSize = 0x16000;
104    char *heapArray = malloc(heapAllocSize);
105    test_assert(heapArray);
106    for (int i = 0; i < heapAllocSize; i++) {
107        heapArray[i] = (i%2)?'z':'a';
108    }
109    for (int i = 0; i < heapAllocSize; i++) {
110        test_assert(heapArray[i] == (i%2)?'z':'a');
111    }
112    free(heapArray);
113    /* Test that free works by continually allocating and free-ing a large block. */
114    for (int i = 0; i < 10000; i++) {
115        char *heapArray2 = malloc(heapAllocSize);
116        test_assert(heapArray2);
117        heapArray2[4] = 123;
118        test_assert(heapArray2[4] == 123);
119        free(heapArray);
120    }
121    return test_success();
122}
123
124/* -------------------------------- Process server tests -------------------------------------- */
125
126static int
127test_process_server_ping(void)
128{
129    test_start("process server ping");
130    for (int i = 0; i < 8; i++) {
131        int error = proc_ping();
132        test_assert(error == ESUCCESS);
133    }
134    return test_success();
135}
136
137static int
138test_process_server_endpoints(void)
139{
140    test_start("process server endpoints");
141
142    seL4_CPtr ep = proc_new_endpoint();
143    test_assert(ep && ROS_ERRNO() == ESUCCESS);
144
145    seL4_CPtr aep = proc_new_async_endpoint();
146    test_assert(aep && ROS_ERRNO() == ESUCCESS);
147
148    seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 1);
149    seL4_SetMR(0, 0x31336);
150    seL4_NBSend(aep, tag);
151
152    seL4_Word badge;
153    seL4_Recv(aep, &badge);
154
155    test_assert(badge == 0);
156    test_assert(seL4_GetMR(0) == 0x31336);
157
158    proc_del_endpoint(ep);
159    proc_del_async_endpoint(aep);
160
161    return test_success();
162}
163
164static int
165test_process_server_window(void)
166{
167    test_start("process server memwindows");
168    seL4_Word testBase = 0x20000000;
169
170    /* Create invalid window in kernel memory. */
171    seL4_CPtr invalidKernelMemWindow = proc_create_mem_window(
172            TEST_KERNEL_VM_RESERVED_START + 100, 0x1000);
173    test_assert(invalidKernelMemWindow == 0 && ROS_ERRNO() == EINVALIDPARAM);
174
175    /* Create valid test windows. */
176    int windowBases[] = {0x2000, 0x4000, 0x6000, 0x8000, 0x10000};
177    seL4_CPtr validWindows[5];
178    int nWindows = 5;
179    for (int i = 0; i < nWindows; i++) {
180        validWindows[i] = proc_create_mem_window(testBase + windowBases[i], 10);
181        test_assert(validWindows[i] != 0 && ROS_ERRNO() == ESUCCESS);
182    }
183
184    int testWin[] = {0x2000, 1, 0x4001, 20, 0x7000, 10, 0x6002, 50, 0, 0x9FFF};
185    int expectedResult[] = {EINVALIDWINDOW, EINVALIDWINDOW, ESUCCESS, EINVALIDWINDOW, EINVALIDWINDOW};
186    int numTestWin = 5;
187    for (int i = 0; i < numTestWin; i++) {
188        seL4_CPtr testWindow = proc_create_mem_window(testBase + testWin[i*2], testWin[i*2+1]);
189        test_assert(ROS_ERRNO() == expectedResult[i]);
190        if (expectedResult[i] == ESUCCESS) {
191            test_assert(testWindow);
192        }
193        if (testWindow) {
194            int error = proc_delete_mem_window(testWindow);
195            test_assert(error == ESUCCESS);
196        }
197    }
198
199    for (int i = 0; i < nWindows; i++) {
200        if (validWindows[i]) {
201            int error = proc_delete_mem_window(validWindows[i]);
202            test_assert(error == ESUCCESS);
203        }
204    }
205
206    return test_success();
207}
208
209static int
210test_process_server_window_resize(void)
211{
212    test_start("process server memwindow resize");
213    seL4_Word testBase = 0x20000000;
214
215    /* Test window resize. */
216    seL4_CPtr testRWindow = proc_create_mem_window(testBase + 0x1000, 0x2000);
217    test_assert(testRWindow && ROS_ERRNO() == ESUCCESS);
218
219    seL4_CPtr testCheckWindow = proc_create_mem_window(testBase + 0x3000, 0x1000);
220    test_assert(testCheckWindow && ROS_ERRNO() == ESUCCESS);
221
222    /* Resizing the latter window should succeed. */
223    int error = proc_resize_mem_window(testCheckWindow, 0x2000);
224    test_assert(error == ESUCCESS);
225    /* Increasing the previous window should cause overlap error. */
226    error = proc_resize_mem_window(testRWindow, 0x2100);
227    test_assert(error == EINVALIDPARAM);
228    /* Zero size not allowed. */
229    error = proc_resize_mem_window(testRWindow, 0);
230    test_assert(error == EINVALIDPARAM);
231    /* Shrinking window is OK. */
232    error = proc_resize_mem_window(testRWindow, 0x1900);
233    test_assert(error == ESUCCESS);
234    /* Invalid window. */
235    error = proc_resize_mem_window(0x0, 0x2100);
236    test_assert(error == EINVALIDWINDOW);
237
238
239    /* Delete the latter window. */
240    error = proc_delete_mem_window(testCheckWindow);
241    test_assert(error == ESUCCESS);
242
243    /* Increasing the previous window should now succeed, as the latter window causing the overlap
244       is now gone. */
245    error = proc_resize_mem_window(testRWindow, 0x2100);
246    test_assert(error == ESUCCESS);
247    error = proc_delete_mem_window(testRWindow);
248    test_assert(error == ESUCCESS);
249
250    return test_success();
251}
252
253static int
254test_process_server_param_buffer(void)
255{
256    test_start("process server param sharing");
257    int error;
258    seL4_CPtr ds = data_open(REFOS_PROCSERV_EP, "anon",
259            0x0, 0x0, PROCESS_PARAM_DEFAULTSIZE, &error);
260    test_assert(error == ESUCCESS);
261    test_assert(ds);
262    error = proc_set_parambuffer(ds, PROCESS_PARAM_DEFAULTSIZE);
263    test_assert(error == ESUCCESS);
264    return test_success();
265}
266
267static int
268test_process_server_nameserv(void)
269{
270    test_start("process server registration");
271    int error;
272    nsv_mountpoint_t mp;
273    char *testServerName = "os_test_dummy_server";
274    char *testServerPath = "/os_test_dummy_server/foo.txt";
275
276    /* Should not find this server. */
277    mp = nsv_resolve(testServerPath);
278    test_assert(ROS_ERRNO() == ESERVERNOTFOUND);
279    test_assert(mp.success == false);
280    test_assert(mp.serverAnon == 0);
281
282    /* Make a quick anon cap. */
283    seL4_CPtr aep = proc_new_async_endpoint();
284    test_assert(aep && ROS_ERRNO() == ESUCCESS);
285
286    /* We register ourselves now under this server name. */
287    error = nsv_register(REFOS_NAMESERV_EP, testServerName, aep);
288    test_assert(error == ESUCCESS);
289
290    /* We should find ourself now. */
291    mp = nsv_resolve(testServerPath);
292    test_assert(ROS_ERRNO() == ESUCCESS);
293    test_assert(mp.success == true);
294    test_assert(mp.serverAnon != 0);
295    test_assert(strcmp(mp.dspaceName, "foo.txt") == 0);
296    test_assert(strcmp(mp.nameservPathPrefix, "/os_test_dummy_server/") == 0);
297
298    /* Test this anon cap we recieved and make sure it is actually the one we passed in. */
299    seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 1);
300    seL4_SetMR(0, 0xabbadadd);
301    seL4_NBSend(mp.serverAnon, tag);
302
303    seL4_Word badge;
304    seL4_Recv(aep, &badge);
305    test_assert(badge == 0);
306    test_assert(seL4_GetMR(0) == 0xabbadadd);
307
308    /* Release the resources stored in the valid mountpoint. */
309    nsv_mountpoint_release(&mp);
310    test_assert(mp.success == false);
311    test_assert(mp.serverAnon == 0);
312
313    /* We now unregister ourselves. */
314    error = nsv_unregister(REFOS_NAMESERV_EP, testServerName);
315    test_assert(error == ESUCCESS);
316
317    /* We should not be able to find this server again. */
318    mp = nsv_resolve(testServerPath);
319    test_assert(ROS_ERRNO() == ESERVERNOTFOUND);
320    test_assert(mp.success == false);
321    test_assert(mp.serverAnon == 0);
322
323    proc_del_async_endpoint(aep);
324    return test_success();
325}
326
327static int
328test_start_userland_test(void)
329{
330    tprintf("TEST_OS | Starting RefOS userland environment unit tests...\n");
331    int status = EINVALID;
332    int error;
333    (void) error;
334
335    /* Start the application */
336    error = proc_new_proc(TEST_USERLAND_TEST_APP, "", true, 70, &status);
337    assert(error == ESUCCESS);
338    assert(status == 0x1234);
339    return 0;
340}
341
342
343static void
344test_process_server(void)
345{
346    test_process_server_ping();
347    test_process_server_endpoints();
348    test_process_server_window();
349    test_process_server_window_resize();
350    test_process_server_param_buffer();
351    test_process_server_nameserv();
352}
353
354/* -------------------------------- RefOSUtil tests -------------------------------------- */
355
356static int
357test_rosutil_calloc(void)
358{
359    test_start("rosutil calloc");
360    for (int i = 0; i <= 64; i++) {
361        seL4_CPtr c = csalloc();
362        test_assert(c);
363        csfree(c);
364    }
365    return test_success();
366}
367
368static int
369test_rosutil_walloc(void)
370{
371    test_start("rosutil walloc");
372    for (int i = 0; i < 8; i++) {
373        int npages = i % 2 ? 2 : 3;
374        seL4_CPtr windowCap;
375        seL4_Word vaddr = walloc(npages, &windowCap);
376        test_assert(vaddr && windowCap);
377        walloc_free(vaddr, npages);
378    }
379    return test_success();
380}
381
382static void
383test_rosutil(void)
384{
385    test_rosutil_calloc();
386    test_rosutil_walloc();
387}
388
389static int
390test_share(void)
391{
392    test_start("share");
393
394    char *testBuf = malloc(4096 * 3);
395    char *srcBuf = malloc(4096 * 3);
396    char *sharedBuf = malloc(4096 * 3 + 9);
397    int i;
398    unsigned int bytesRead = 0;
399    unsigned int start = 0;
400    unsigned int end = 0;
401
402    for (i = 0; i < 4096 * 3; i++) {
403        srcBuf[i] = 'a' + (i / 4096);
404        testBuf[i] = 0;
405    }
406
407    for (i = 0; i < 4096 * 3 + 9; i++) {
408        sharedBuf[i] = 0;
409    }
410
411    int ret = refos_share_write(srcBuf, 4096 * 3, sharedBuf, 4096 * 3 + 9, &end);
412    tvprintf("return is %d\n", ret);
413    tvprintf("end is %d\n", end);
414    test_assert(ret == 0 && end == 4096 * 3);
415
416    ret = refos_share_read(testBuf, 4096 * 3, sharedBuf, 4096 * 3 + 9, &start, &bytesRead);
417    tvprintf("return is %d\n", ret);
418    tvprintf("bytesRead is %d\n", bytesRead);
419    test_assert(ret == 0 && bytesRead == 4096 * 3);
420
421    for (i = 0; i < 4096 * 3; i++) {
422        test_assert(testBuf[i] == srcBuf[i]);
423    }
424
425    for (i = 0; i < 4096 * 3; i++) {
426        srcBuf[i] = 0;
427        testBuf[i] = 0;
428    }
429
430    for (i = 0; i < 4096 * 3 + 9; i++) {
431        sharedBuf[i] = 0;
432    }
433
434    for (i = 0; i < 4096; i++) {
435        srcBuf[i] = 'a';
436    }
437    for (i = 8192; i < 4096 * 3; i++) {
438        srcBuf[i] = 'a';
439    }
440
441    end = 8192;
442    start = 8192;
443    bytesRead = 0;
444    unsigned int *ptr = (unsigned int*)sharedBuf;
445    ptr[0] = start;
446    ptr[1] = end;
447
448    char *srcBuf2 = malloc(4096 * 2);
449    for (i = 0; i < 4096 * 2; i++) {
450        srcBuf2[i] = 'a';
451    }
452
453    ret = refos_share_write(srcBuf2, 4096 * 2, sharedBuf, 4096 * 3 + 9, &end);
454    ret = refos_share_read(testBuf, 4096 * 2, sharedBuf, 4096 * 3 + 9, &start, &bytesRead);
455    for (i = 0; i < 4096 * 2; i++) {
456        test_assert(testBuf[i] == srcBuf2[i]);
457    }
458
459    return test_success();
460
461}
462
463/* ---------------------------------- OS Level tests ---------------------------------------- */
464
465static void
466test_OS_level(void)
467{
468    test_bss();
469    test_stack();
470    test_heap();
471    test_process_server();
472    test_anon_dataspace();
473    test_file_server();
474    test_rosutil();
475    test_share();
476}
477
478#endif /* CONFIG_REFOS_RUN_TESTS */
479
480int
481main()
482{
483#ifdef CONFIG_REFOS_RUN_TESTS
484    /* Future Work 4:
485       Eventually RefOS should be changed so that processes that are started
486       by the process server do not require that the their system call table be
487       explicitly referenced in the code like this. Without expliciting referencing
488       __vsyscall_ptr in main(), the compiler optimizes away __vsyscall_ptr
489       and then processes started by the process server can't find their system call
490       table. Each of the four places in RefOS where this explicit reference is
491       required is affected by a custom linker script (linker.lds), so it is possible
492       that the custom linker script (and then likely other things too) needs to be
493       modified. Also note that the ROS_ERROR() and assert() inside this if statement
494       would not actually be able to execute if __vsyscall_ptr() were ever not set.
495       The purpose of these calls to ROS_ERROR() and assert() is to show future
496       developers that __vsyscall_ptr needs to be defined.
497    */
498    if (! __vsyscall_ptr) {
499        ROS_ERROR("Test OS server could not find system call table.");
500        assert("!Test OS server could not find system call table.");
501        return 0;
502    }
503
504    refosio_setup_morecore_override(mmapRegion, MMAP_SIZE);
505    refos_initialise_os_minimal();
506    refos_setup_dataspace_stdio(REFOS_DEFAULT_STDIO_DSPACE);
507
508    tprintf("OS_TESTS | Running RefOS OS-level tests.\n");
509    test_title = "OS_TESTS";
510    test_OS_level();
511    test_print_log();
512
513    test_start_userland_test();
514    tprintf("OS_TESTS | Back to Refos OS-level. Running userland second time.\n");
515    test_start_userland_test();
516    tprintf("OS_TESTS | Back to Refos OS-level. Quitting.\n");
517#endif /* CONFIG_REFOS_RUN_TESTS */
518
519    return 0;
520}
521