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#pragma once
13
14#include <vka/vka.h>
15#include <vspace/vspace.h>
16#include <sel4utils/thread.h>
17#include <sel4utils/process.h>
18#include <sel4utils/mapping.h>
19#include <sel4test/test.h>
20
21#include <sel4platsupport/timer.h>
22#include <platsupport/timer.h>
23
24#include "test.h"
25#include <sel4testsupport/testreporter.h>
26#include <sync/mutex.h>
27
28#define OUR_PRIO (env->priority)
29/* args provided by the user */
30#define HELPER_THREAD_MAX_ARGS 4
31/* metadata helpers adds */
32#define HELPER_THREAD_META     4
33/* total args (user + meta) */
34#define HELPER_THREAD_TOTAL_ARGS (HELPER_THREAD_MAX_ARGS + HELPER_THREAD_META)
35
36#include <sel4test/test.h>
37
38typedef int (*helper_fn_t)(seL4_Word, seL4_Word, seL4_Word, seL4_Word);
39
40typedef struct helper_thread {
41    sel4utils_elf_region_t regions[MAX_REGIONS];
42    int num_regions;
43    sel4utils_process_t process;
44
45    sel4utils_thread_t thread;
46    vka_object_t local_endpoint;
47    seL4_CPtr fault_endpoint;
48
49    void *arg0;
50    void *arg1;
51    char *args[HELPER_THREAD_TOTAL_ARGS];
52    char args_strings[HELPER_THREAD_TOTAL_ARGS][WORD_STRING_SIZE];
53
54    bool is_process;
55} helper_thread_t;
56
57/* Helper thread/process functions */
58
59/* create a helper in the current vspace and current cspace */
60void create_helper_thread(env_t env, helper_thread_t *thread);
61/* create a helper with a custom stack size, useful when creating a lot of threads*/
62void create_helper_thread_custom_stack(env_t env, helper_thread_t *thread, size_t stack_pages);
63
64/* create a helper with a clone of the current vspace loadable elf segments,
65 * and a new cspace */
66void create_helper_process(env_t env, helper_thread_t *thread);
67void create_helper_process_custom_asid(env_t env, helper_thread_t *thread, seL4_CPtr asid);
68/* create and start a passive thread */
69int create_passive_thread(env_t env, helper_thread_t *passive, helper_fn_t fn, seL4_CPtr ep,
70                          seL4_Word arg1, seL4_Word arg2, seL4_Word arg3);
71/* start an existing (created but not running ) passive thread */
72int start_passive_thread(env_t env, helper_thread_t *passive, helper_fn_t fn, seL4_CPtr ep,
73                         seL4_Word arg1, seL4_Word arg2, seL4_Word arg3);
74/* set a helper threads priority */
75void set_helper_priority(env_t env, helper_thread_t *thread, seL4_Word prio);
76
77/* set a helper threads max control priority */
78void set_helper_mcp(env_t env, helper_thread_t *thread, seL4_Word mcp);
79
80/* set a helper threads core affinity. This will have no effect on passive threads. */
81void set_helper_affinity(env_t env, helper_thread_t *thread, seL4_Word affinity);
82
83/* if CONFIG_KERNEL_MCS is set, set the helpers scheduling parameters */
84int set_helper_sched_params(UNUSED env_t env, UNUSED helper_thread_t *thread, UNUSED uint64_t budget,
85                            UNUSED uint64_t period, seL4_Word badge);
86
87/* set a helper threads timeout fault handler */
88void set_helper_tfep(env_t env, helper_thread_t *thread, seL4_CPtr tfep);
89
90/* Start a helper. Note: arguments to helper processes will be copied into
91 * the address space of that process. Do not pass pointers to data only in
92 * the local vspace, this will fail. */
93void start_helper(env_t env, helper_thread_t *thread, helper_fn_t entry_point,
94                  seL4_Word arg0, seL4_Word arg1, seL4_Word arg2, seL4_Word arg3);
95
96/* save a threads seL4_UserContext, increment instruction pointer, and resume */
97int restart_after_syscall(env_t env, helper_thread_t *thread);
98
99/* wait for a helper thread to finish */
100int wait_for_helper(helper_thread_t *thread);
101
102/* free all resources associated with a helper and tear it down */
103void cleanup_helper(env_t env, helper_thread_t *thread);
104
105/* retrieve the TCB of a helper thread */
106seL4_CPtr get_helper_tcb(helper_thread_t *thread);
107/* retrieve the reply object cap of a helper thread (seL4_CapNull if not CONFIG_RT_KERNEL) */
108seL4_CPtr get_helper_reply(helper_thread_t *thread);
109/* retrieve the sched context cap of a helper thread (seL4_CapNull if not CONFIG_RT_KERNEL) */
110seL4_CPtr get_helper_sched_context(helper_thread_t *thread);
111
112/* retrieve the IPC buffer address of a helper thread */
113uintptr_t get_helper_ipc_buffer_addr(helper_thread_t *thread);
114
115uintptr_t get_helper_initial_stack_pointer(helper_thread_t *thread);
116
117/*
118 * Check whether a given region of memory is zeroed out.
119 */
120int check_zeroes(seL4_Word addr, seL4_Word size_bytes);
121
122/* Determine if two TCBs in the init thread's CSpace are not equal. Note that we
123 * assume the thread is not currently executing.
124 *
125 * Serves as != comparator for caps. Returns 1 for not equal, 0 for equal and -1 for syscall error.
126 */
127int are_tcbs_distinct(seL4_CPtr tcb1, seL4_CPtr tcb2);
128
129/* cnode_ops wrappers */
130int cnode_copy(env_t env, seL4_CPtr src, seL4_CPtr dest, seL4_CapRights_t rights);
131int cnode_delete(env_t env, seL4_CPtr slot);
132int cnode_mint(env_t env, seL4_CPtr src, seL4_CPtr dest, seL4_CapRights_t rights, seL4_Word badge);
133int cnode_move(env_t env, seL4_CPtr src, seL4_CPtr dest);
134int cnode_mutate(env_t env, seL4_CPtr src, seL4_CPtr dest);
135int cnode_cancelBadgedSends(env_t env, seL4_CPtr cap);
136int cnode_revoke(env_t env, seL4_CPtr cap);
137int cnode_rotate(env_t env, seL4_CPtr src, seL4_CPtr pivot, seL4_CPtr dest);
138/* non-RT only */ int cnode_savecaller(env_t env, seL4_CPtr cap);
139
140/* IPC buffer operation wrapper */
141/* Set up the IPC Buffer to receive IPC caps in the already allocated slot slot */
142void set_cap_receive_path(env_t env, seL4_CPtr slot);
143
144/* Determine whether a given slot in the init thread's CSpace is empty by
145 * examining the error when moving a slot onto itself.
146 *
147 * Serves as == 0 comparator for caps.
148 */
149int is_slot_empty(env_t env, seL4_Word slot);
150
151/* Get a free slot */
152seL4_Word get_free_slot(env_t env);
153
154/* busy wait for a period of time. This assumes that you have some thread (such as create_timer_interrupt_thread)
155 * handling the timer interrupts. This can be used instead of sleep in circumstances where you want multiple
156 * threads performing waits */
157void sleep_busy(env_t env, uint64_t ns);
158
159/* sel4test RPC helpers - sel4test-tests sel4test-tests requesting services from sel4test-driver*/
160
161/* Request a sleep for at least @ns. Callees to this function will block until
162 * it's waken up and this function then returns. No concurrent calls to sel4test_sleep
163 * are allowed, and trying to do this has undefined behavior.
164 */
165void sel4test_sleep(env_t env, uint64_t ns);
166
167/* Request a timestamp. Timestamps might not be accurate and report
168 * longer time especially if working with multpile domains
169 */
170uint64_t sel4test_timestamp(env_t env);
171
172/* Request periodic signals every @ns, at least.
173 * This function is similar to the sel4test_sleep function above,
174 * but will get periodic notifications.
175 *
176 * Tests that request periodic timer using this function call can, if they want,
177 * wait for signals themselves, unlike sleep, on the env->timer_notification.
178 */
179void sel4test_periodic_start(env_t env, uint64_t ns);
180
181/* Request a timer reset. This should cancel receiving signals from
182 * previous sleep, periodic calls.
183 *
184 * If there were previous calls that set timeouts, sleep or periodic timer,
185 * they will be discarded, and tests will no longer get notifications on
186 * env->timer_notification.
187 *
188 * If this function is not called, and there were previous calls to sleep and/or
189 * periodic timer services, sel4test-driver will keep signaling
190 * the test notification whenever there is a timer interrupt, regardless
191 * of there exists a test waiting on the env->timer_notification or not.
192 */
193void sel4test_timer_reset(env_t env);
194
195/* This is a helper function part of the sel4test_timer interface.
196 * It simply waits on a valid env->timer_notification. Tests that
197 * do calls to sel4test_rpc_timer_* above and expect notifications
198 * from sel4test-driver can choose to use this function.
199 */
200void sel4test_ntfn_timer_wait(env_t env);
201
202/* helper for creating a thread to handle timer interrupts */
203int create_timer_interrupt_thread(env_t env, helper_thread_t *thread);
204