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 <assert.h>
14#include <sel4/sel4.h>
15
16#include "../helpers.h"
17
18static int test_retype(env_t env)
19{
20    int error;
21    int i;
22    vka_object_t untyped;
23    vka_object_t cnode;
24
25    error = vka_alloc_cnode_object(&env->vka, 2, &cnode);
26    test_error_eq(error, 0);
27
28    error = vka_alloc_untyped(&env->vka, seL4_TCBBits + 3, &untyped);
29    test_error_eq(error, 0);
30
31    /* Try to insert 0. */
32    error = seL4_Untyped_Retype(untyped.cptr,
33                                seL4_TCBObject, 0,
34                                env->cspace_root, cnode.cptr, seL4_WordBits,
35                                1, 0);
36    test_error_eq(error, seL4_RangeError);
37
38    /* Check we got useful min/max error codes. */
39    test_eq(seL4_GetMR(0), 1ul);
40    test_eq(seL4_GetMR(1), (unsigned long)CONFIG_RETYPE_FAN_OUT_LIMIT);
41
42    /* Try to drop two caps in, at the end of the cnode, overrunning it. */
43    error = seL4_Untyped_Retype(untyped.cptr,
44                                seL4_TCBObject, 0,
45                                env->cspace_root, cnode.cptr, seL4_WordBits,
46                                (1 << 2) - 1, 2);
47    test_error_eq(error, seL4_RangeError);
48
49    /* Drop some caps in. This should be successful. */
50    for (i = 0; i < (1 << 2); i++) {
51        error = seL4_Untyped_Retype(untyped.cptr,
52                                    seL4_TCBObject, 0,
53                                    env->cspace_root, cnode.cptr, seL4_WordBits,
54                                    i, 1);
55        test_error_eq(error, seL4_NoError);
56    }
57
58    /* Try to drop one in beyond the end of the cnode. */
59    error = seL4_Untyped_Retype(untyped.cptr,
60                                seL4_TCBObject, 0,
61                                env->cspace_root, cnode.cptr, seL4_WordBits,
62                                i, 2);
63    test_error_eq(error, seL4_RangeError);
64
65    /* Try putting caps over the top. */
66    for (i = 0; i < (1 << 2); i++) {
67        error = seL4_Untyped_Retype(untyped.cptr,
68                                    seL4_TCBObject, 0,
69                                    env->cspace_root, cnode.cptr, seL4_WordBits,
70                                    i, 1);
71        test_error_eq(error, seL4_DeleteFirst);
72    }
73
74    /* Delete them all. */
75    for (i = 0; i < (1 << 2); i++) {
76        error = seL4_CNode_Delete(cnode.cptr, i, 2);
77        test_error_eq(error, seL4_NoError);
78    }
79
80    /* Try to insert too many. */
81    error = seL4_Untyped_Retype(untyped.cptr,
82                                seL4_TCBObject, 0,
83                                env->cspace_root, cnode.cptr, seL4_WordBits,
84                                0, 1U << 31);
85    test_error_eq(error, seL4_RangeError);
86
87    error = seL4_Untyped_Retype(untyped.cptr,
88                                seL4_TCBObject, 0,
89                                env->cspace_root, cnode.cptr, seL4_WordBits,
90                                0, (1 << 2) + 1);
91    test_error_eq(error, seL4_RangeError);
92
93    /* Insert them in one fell swoop but one. */
94    error = seL4_Untyped_Retype(untyped.cptr,
95                                seL4_TCBObject, 0,
96                                env->cspace_root, cnode.cptr, seL4_WordBits,
97                                0, (1 << 2) - 1);
98    test_error_eq(error, seL4_NoError);
99
100    /* Try inserting over the top. Only the last should succeed. */
101    for (i = 0; i < (1 << 2); i++) {
102        error = seL4_Untyped_Retype(untyped.cptr,
103                                    seL4_TCBObject, 0,
104                                    env->cspace_root, cnode.cptr, seL4_WordBits,
105                                    i, 1);
106        if (i == (1 << 2) - 1) {
107            test_error_eq(error, seL4_NoError);
108        } else {
109            test_error_eq(error, seL4_DeleteFirst);
110        }
111    }
112
113    vka_free_object(&env->vka, &untyped);
114    vka_free_object(&env->vka, &cnode);
115    return sel4test_get_result();
116}
117DEFINE_TEST(RETYPE0000, "Retype test", test_retype, true)
118
119static int
120test_incretype(env_t env)
121{
122    int error;
123    vka_object_t untyped;
124    int size_bits;
125
126    /* Find an untyped of some size. */
127    for (size_bits = 13; size_bits > 0; size_bits--) {
128        error = vka_alloc_untyped(&env->vka, size_bits, &untyped);
129        if (error == 0) {
130            break;
131        }
132    }
133    test_error_eq(error, 0);
134    test_assert(untyped.cptr != 0);
135
136    /* Try retyping anything bigger than the object into it. */
137    int i;
138    for (i = 40; i > 0; i--) {
139        error = seL4_Untyped_Retype(untyped.cptr,
140                                    seL4_CapTableObject, size_bits - seL4_SlotBits + i,
141                                    env->cspace_root, env->cspace_root, seL4_WordBits,
142                                    0, 1);
143        test_assert(error);
144    }
145
146    /* Try retyping an object of the correct size in. */
147    error = seL4_Untyped_Retype(untyped.cptr,
148                                seL4_CapTableObject, size_bits - seL4_SlotBits + 0,
149                                env->cspace_root, env->cspace_root, seL4_WordBits,
150                                0, 1);
151    test_error_eq(error, seL4_NoError);
152
153    /* clean up */
154    vka_free_object(&env->vka, &untyped);
155
156    return sel4test_get_result();
157}
158DEFINE_TEST(RETYPE0001, "Incremental retype test", test_incretype, true)
159
160static int
161test_incretype2(env_t env)
162{
163    int error;
164    seL4_Word slot[17];
165    vka_object_t untyped;
166
167    /* Get a bunch of free slots. */
168    for (int i = 0; i < sizeof(slot) / sizeof(slot[0]); i++) {
169        error = vka_cspace_alloc(&env->vka, &slot[i]);
170        test_error_eq(error, 0);
171    }
172
173    /* And an untyped big enough to allocate 16 4-k pages into. */
174    error = vka_alloc_untyped(&env->vka, 16, &untyped);
175    test_error_eq(error, 0);
176    test_assert(untyped.cptr != 0);
177
178    /* Try allocating precisely 16 pages. These should all work. */
179    int i;
180    for (i = 0; i < 16; i++) {
181        error = seL4_Untyped_Retype(untyped.cptr,
182                                    seL4_ARCH_4KPage, 0,
183                                    env->cspace_root, env->cspace_root, seL4_WordBits,
184                                    slot[i], 1);
185        test_error_eq(error, seL4_NoError);
186    }
187
188    /* An obscenely large allocation should fail (note that's 2^(2^20)). */
189    error = seL4_Untyped_Retype(untyped.cptr,
190                                seL4_ARCH_4KPage, 0,
191                                env->cspace_root, env->cspace_root, seL4_WordBits,
192                                slot[i], 1024 * 1024);
193    test_error_eq(error, seL4_RangeError);
194
195    /* Allocating to an existing slot should fail. */
196    error = seL4_Untyped_Retype(untyped.cptr,
197                                seL4_ARCH_4KPage, 0,
198                                env->cspace_root, env->cspace_root, seL4_WordBits,
199                                slot[0], 8);
200    test_error_eq(error, seL4_DeleteFirst);
201
202    /* Allocating another item should also fail as the untyped is full. */
203    error = seL4_Untyped_Retype(untyped.cptr,
204                                seL4_ARCH_4KPage, 0,
205                                env->cspace_root, env->cspace_root, seL4_WordBits,
206                                slot[i++], 1);
207    test_error_eq(error, seL4_NotEnoughMemory);
208
209    vka_free_object(&env->vka, &untyped);
210
211    return sel4test_get_result();
212}
213DEFINE_TEST(RETYPE0002, "Incremental retype test #2", test_incretype2, true)
214