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 Kconfig variables. */
14#include <autoconf.h>
15#include <sel4test-driver/gen_config.h>
16
17#include <assert.h>
18#include <stdio.h>
19
20/* Our headers are not C++ friendly */
21extern "C" {
22
23#include <sel4/sel4.h>
24
25#include "../helpers.h"
26
27}
28
29#define POLL_DELAY_NS 4000000
30
31typedef int (*test_func_t)(seL4_Word /* id */, env_t env /* env */);
32
33static int
34own_domain_success(struct env *env)
35{
36    int error;
37
38    error = seL4_DomainSet_Set(env->domain, CONFIG_NUM_DOMAINS - 1,
39                               env->tcb);
40    return (error == seL4_NoError) ? SUCCESS : FAILURE;
41}
42
43static int
44own_domain_baddom(struct env *env)
45{
46    int error;
47
48    error = seL4_DomainSet_Set(env->domain, CONFIG_NUM_DOMAINS + 10,
49                               env->tcb);
50    return (error == seL4_InvalidArgument) ? SUCCESS : FAILURE;
51}
52
53static int
54own_domain_badcap(struct env *env)
55{
56    int error;
57
58    error = seL4_DomainSet_Set(env->tcb, 0,
59                               env->tcb);
60    return (error == seL4_IllegalOperation) ? SUCCESS : FAILURE;
61}
62
63int fdom1(seL4_Word id, env_t env)
64{
65    int countdown = 50;
66
67    while (countdown > 0) {
68        sleep_busy(env, POLL_DELAY_NS);
69        --countdown;
70        ZF_LOGD("%2d, ", (int)id);
71    }
72
73    return sel4test_get_result();
74}
75
76/* This is a very simple (and rather stupid) C++ usage. Proves that a template
77 * can be defined but is not good C++ */
78template<bool shift, typename F>
79static int
80test_domains(struct env *env, F func)
81{
82
83    UNUSED int error;
84    helper_thread_t thread[CONFIG_NUM_DOMAINS];
85
86    for (int i = 0; i < CONFIG_NUM_DOMAINS; ++i) {
87        create_helper_thread(env, &thread[i]);
88        set_helper_priority(env, &thread[i], 64);
89        error = seL4_DomainSet_Set(env->domain, (seL4_Word)i, get_helper_tcb(&thread[i]));
90        assert(error == seL4_NoError);
91    }
92
93    for (int i = 0; i < CONFIG_NUM_DOMAINS; ++i) {
94        start_helper(env, &thread[i], (helper_fn_t) func, i, (seL4_Word) env, 0, 0);
95    }
96
97    if (CONFIG_NUM_DOMAINS > 1 && shift) {
98        sel4test_sleep(env, POLL_DELAY_NS * 2);
99        error = seL4_DomainSet_Set(env->domain, CONFIG_NUM_DOMAINS - 1, get_helper_tcb(&thread[0]));
100        assert(error == seL4_NoError);
101    }
102
103    for (int i = 0; i < CONFIG_NUM_DOMAINS; ++i) {
104        wait_for_helper(&thread[i]);
105        cleanup_helper(env, &thread[i]);
106    }
107
108    return sel4test_get_result();
109}
110
111/* The output from this test should show alternating "domain blocks", with,
112 * within each, a single thread printing. For example:
113 *
114 * 00, 00, ..., 00, 01, 01, ..., 01, 00, 00, ..., 00, 01, 01, ..., 01, etc.
115 * +-------------+  +-------------+  +-------------+  +-------------+
116 *  block 0           block 1          block 0          block 1
117 */
118static int
119test_run_domains(struct env* env)
120{
121    return test_domains<false>(env, fdom1);
122}
123DEFINE_TEST(DOMAINS0004, "Run threads in domains()", test_run_domains, config_set(CONFIG_HAVE_TIMER))
124
125/* The output of this test differs from that of DOMAINS0004 in that the thread
126 * in domain 0 is moved into domain 1 after a short delay. This should be
127 * visible in the output, where the "domain block" for domain 1 should contain
128 * the alternating output of threads 0 and 1. For example:
129 *
130 * 00, 00, ..., 00, 01, 00, 01, 00, ..., 01, 01, 01, 01
131 * +-------------+  +------------------+ +------------+
132 *  initial block    alterations           final block
133 *  (due to delay)   (after shift)         (01 catches up)
134 */
135static int
136test_run_domains_shift(struct env* env)
137{
138    return test_domains<true>(env, fdom1);
139}
140DEFINE_TEST(DOMAINS0005, "Move thread between domains()", test_run_domains_shift, config_set(CONFIG_HAVE_TIMER) && CONFIG_NUM_DOMAINS > 1)
141
142static int
143test_own_domain1(struct env* env)
144{
145    return own_domain_success(env);
146}
147DEFINE_TEST(DOMAINS0001, "Change domain successfully()", test_own_domain1, true)
148
149static int
150test_own_domain2(struct env* env)
151{
152    return own_domain_baddom(env);
153}
154DEFINE_TEST(DOMAINS0002, "Try non-existant domain()", test_own_domain2, true)
155
156static int
157test_own_domain3(struct env* env)
158{
159    return own_domain_badcap(env);
160}
161DEFINE_TEST(DOMAINS0003, "Invoke non-domain cap()", test_own_domain3, true)
162