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#ifdef CONFIG_REFOS_RUN_TESTS
15
16#include <stdlib.h>
17#include <string.h>
18#include <autoconf.h>
19#include <refos/test.h>
20#include "test.h"
21#include "test_process.h"
22#include "../system/process/pid.h"
23#include "../system/process/thread.h"
24#include "../system/process/proc_client_watch.h"
25#include "../state.h"
26#include "../common.h"
27
28/* ------------------------------- PID / ASID module test ------------------------------- */
29
30static void
31test_pid_iteration_callback(struct proc_pcb *pcb, void *cookie)
32{
33    assert(cookie);
34    int *result = (int*) cookie;
35    (*result)++;
36}
37
38int
39test_pid(void)
40{
41    test_start("PID");
42
43    uint32_t testPID;
44    uint32_t emptyIndex = 0;
45    uint32_t pidTable[PID_MAX];
46    struct proc_pcb *pcb;
47    int count = 0, expectedCount = 0;
48
49    /* Assign _ALL_ the ID. */
50    for (int i = 0; i < (PID_MAX - 1); i++) {
51        testPID = pid_alloc(&procServ.PIDList);
52        test_assert(testPID != PID_NULL);
53
54        /* Check no duplication. */
55        for (int j = 0; j < i; j++) {
56            test_assert(pidTable[j] != testPID);
57        }
58
59        pidTable[i] = testPID;
60        expectedCount++;
61    }
62
63    /* Free all the even indexed ID. */
64    for (int i = 0; i < (PID_MAX - 1); i += 2) {
65        pid_free(&procServ.PIDList, pidTable[i]);
66        pidTable[i] = PID_NULL;
67        expectedCount--;
68    }
69
70    /* Test PID iteration. */
71    pid_iterate(&procServ.PIDList, test_pid_iteration_callback, (void*)(&count));
72    test_assert(count == expectedCount);
73
74    /* Test find. */
75    for (int i = 0; i < (PID_MAX - 1); i++) {
76        pcb = pid_get_pcb(&procServ.PIDList, pidTable[i]);
77        if (pidTable[i] == PID_NULL) {
78            test_assert(pcb == NULL);
79        } else {
80            test_assert(pcb != NULL);
81        }
82    }
83
84    /* Assign all the even ID again. */
85    for (int i = 0; i < (PID_MAX - 1); i += 2) {
86        testPID = pid_alloc(&procServ.PIDList);
87        test_assert(testPID != PID_NULL);
88
89        /* Check no duplication. */
90        for (int j = 0; j < (PID_MAX - 1); j++) {
91            if (pidTable[j] == PID_NULL) {
92                emptyIndex = j;
93            }
94            test_assert(pidTable[j] != testPID);
95        }
96
97        pidTable[emptyIndex] = testPID;
98    }
99
100    /* Test find again. */
101    for (int i = 0; i < (PID_MAX - 1); i++) {
102        pcb = pid_get_pcb(&procServ.PIDList, pidTable[i]);
103        test_assert(pcb != NULL);
104    }
105
106    /* Free all the IDs. */
107    for (int i = 0; i < (PID_MAX - 1); i++) {
108        pid_free(&procServ.PIDList, pidTable[i]);
109    }
110
111    return test_success();
112}
113
114/* ------------------------------------- Thread module test ------------------------------------- */
115
116int
117test_thread(void)
118{
119    test_start("thread");
120    const int numTestThreads = 32;
121    struct proc_tcb thr[numTestThreads];
122
123    /* Create a vspace for threads to go into. */
124    struct vs_vspace vs;
125    int error = vs_initialise(&vs, 31337);
126    test_assert(error == ESUCCESS);
127    test_assert(vs.magic == REFOS_VSPACE_MAGIC);
128
129    /* Create the threads. */
130    for (int i = 0; i < numTestThreads; i++) {
131        int error = thread_config(&thr[i], 12, 1337, &vs);
132        test_assert(error == ESUCCESS);
133        test_assert(thr[i].magic == REFOS_PROCESS_THREAD_MAGIC);
134        test_assert(thr[i].priority == 12);
135        test_assert(thr[i].vspaceRef == &vs);
136        test_assert(thr[i].entryPoint == 1337);
137
138        /* Test that the vspace has been referenced. */
139        test_assert(vs.magic == REFOS_VSPACE_MAGIC);
140        test_assert(vs.ref == 1 + 1 + i);
141    }
142
143    /* We can't really test starting them without causing a horrible mess of things. */
144
145    /* Free all the threads. */
146    for (int i = 0; i < numTestThreads; i++) {
147        thread_release(&thr[i]);
148        test_assert(thr[i].magic != REFOS_PROCESS_THREAD_MAGIC);
149    }
150
151    /* Free the vspace. */
152    test_assert(vs.ref == 1);
153    vs_unref(&vs);
154    test_assert(vs.ref == 0);
155    test_assert(vs.magic != REFOS_VSPACE_MAGIC);
156
157    return test_success();
158}
159
160/* ------------------------------- Proc Watch Client module test -------------------------------- */
161
162int
163test_proc_client_watch(void)
164{
165    test_start("client watch");
166    struct proc_watch_list wl;
167    client_watch_init(&wl);
168
169    const uint32_t dummyPIDs[] = {0x312, 0x32, 0xF2, 0x6F};
170    vka_object_t dummyEP[4];
171    cspacepath_t dummyEPMinted[4];
172
173    /* Create dummy async EPs to test with. */
174    for (int i = 0; i < 4; i++) {
175        /* Create endpoint. */
176        int error = vka_alloc_notification(&procServ.vka, &dummyEP[i]);
177        test_assert(!error);
178        test_assert(dummyEP[i].cptr != 0);
179
180        /* Copy a copy of the endpoint. */
181        cspacepath_t srcPath;
182        vka_cspace_make_path(&procServ.vka, dummyEP[i].cptr, &srcPath);
183        error = vka_cspace_alloc_path(&procServ.vka, &dummyEPMinted[i]);
184        test_assert(!error);
185        error = vka_cnode_mint(&dummyEPMinted[i], &srcPath, seL4_AllRights,
186                               seL4_CapData_Badge_new(123));
187        test_assert(!error);
188    }
189
190    /* Watch a bunch of test clients and dummy notify EPs. */
191    for (int i = 0; i < 4; i++) {
192        int error = client_watch(&wl, dummyPIDs[i], dummyEPMinted[i].capPtr);
193        test_assert(error == ESUCCESS);
194    }
195
196    /* Test that getting an invalid PID results in a NULL CPtr. */
197    seL4_CPtr cpInvalid = client_watch_get(&wl, 0x2FF);
198    test_assert(cpInvalid == 0);
199
200    /* Get our PIDs and see if we get out EPs back. */
201    for (int i = 0; i < 4; i++) {
202        seL4_CPtr cp = client_watch_get(&wl, dummyPIDs[i]);
203        test_assert(cp == dummyEPMinted[i].capPtr);
204        /* Unwatch the client and see if we still get it. */
205        client_unwatch(&wl, dummyPIDs[i]);
206        cp = client_watch_get(&wl, dummyPIDs[i]);
207        test_assert(cp == 0);
208    }
209
210    /* Release all allocated endpoints. Note that the client_watch call takes ownership of the
211       minted caps along with their cslots, so we do NOT need to free those here. */
212    for (int i = 0; i < 4; i++) {
213        cspacepath_t path;
214        vka_cspace_make_path(&procServ.vka, dummyEP[i].cptr, &path);
215        vka_cnode_revoke(&path);
216        vka_cnode_delete(&path);
217        vka_free_object(&procServ.vka, &dummyEP[i]);
218    }
219
220    client_watch_release(&wl);
221    return test_success();
222}
223
224#endif /* CONFIG_REFOS_RUN_TESTS */
225