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#pragma once
14/**
15 *
16 * Builder functions for thread configs
17 *
18 */
19
20#include <autoconf.h>
21#include <sel4utils/gen_config.h>
22#include <sel4/types.h>
23#include <simple/simple.h>
24#include <sel4utils/api.h>
25
26/* Threads and processes use this struct as both need scheduling config parameters */
27typedef struct sched_params {
28    /* seL4 priority for the thread to be scheduled with. */
29    uint8_t priority;
30    /* seL4 maximum controlled priority for the thread. */
31    uint8_t mcp;
32    /* TCB to derive MCP from when setting priority/mcp (in future API) */
33    seL4_CPtr auth;
34    /* true if sel4utils should create an sc */
35    bool create_sc;
36    /* sel4 sched control cap for creating sc */
37    seL4_CPtr sched_ctrl;
38    /* scheduling parameters */
39    uint64_t period;
40    uint64_t budget;
41    seL4_Word extra_refills;
42    seL4_Word badge;
43    /* otherwise use this provided sc */
44    seL4_CPtr sched_context;
45    /* affinity for this tcb. Must set sched_ctrl if CONFIG_RT */
46    seL4_Word core;
47} sched_params_t;
48
49typedef struct sel4utils_thread_config {
50    /* fault_endpoint endpoint to set as the threads fault endpoint. Can be seL4_CapNull. */
51    seL4_CPtr fault_endpoint;
52    /* root of the cspace to start the thread in */
53    seL4_CNode cspace;
54    /* data for cspace access */
55    seL4_Word cspace_root_data;
56    /* use a custom stack size? */
57    bool custom_stack_size;
58    /* custom stack size in 4k pages for this thread */
59    seL4_Word stack_size;
60    /* true if this thread should have no ipc buffer */
61    bool no_ipc_buffer;
62    /* scheduling parameters */
63    sched_params_t sched_params;
64    /* true if sel4utils should create a reply */
65    bool create_reply;
66    /* otherwise provide one */
67    seL4_CPtr reply;
68} sel4utils_thread_config_t;
69
70static inline sched_params_t sched_params_periodic(sched_params_t params, simple_t *simple, seL4_Word core,
71                                                   uint64_t period_us,
72                                                   uint64_t budget_us, seL4_Word extra_refills, seL4_Word badge)
73{
74    if (!config_set(CONFIG_KERNEL_MCS)) {
75        ZF_LOGW("Setting sched params on non-RT kernel will have no effect");
76    }
77    params.sched_ctrl = simple_get_sched_ctrl(simple, core);
78    params.period = period_us;
79    params.budget = budget_us;
80    params.extra_refills = extra_refills;
81    params.badge = badge;
82    params.create_sc = true;
83    return params;
84}
85
86static inline sched_params_t sched_params_round_robin(sched_params_t params, simple_t *simple, seL4_Word core,
87                                                      uint64_t timeslice_us)
88{
89    return sched_params_periodic(params, simple, core, timeslice_us, timeslice_us, 0, 0);
90}
91
92static inline sched_params_t sched_params_core(sched_params_t params, seL4_Word core)
93{
94    if (!config_set(CONFIG_KERNEL_MCS)) {
95        ZF_LOGW("Setting core on RT kernel will have no effect - sched ctrl required");
96    }
97    params.core = core;
98    return params;
99}
100
101static inline sel4utils_thread_config_t thread_config_create_reply(sel4utils_thread_config_t config)
102{
103    config.create_reply = true;
104    return config;
105}
106
107static inline sel4utils_thread_config_t thread_config_reply(sel4utils_thread_config_t config, seL4_CPtr reply)
108{
109    config.create_reply = false;
110    config.reply = reply;
111    return config;
112}
113
114static inline sel4utils_thread_config_t thread_config_sched_context(sel4utils_thread_config_t config,
115                                                                    seL4_CPtr sched_context)
116{
117    config.sched_params.create_sc = false;
118    config.sched_params.sched_context = sched_context;
119    return config;
120}
121
122static inline sel4utils_thread_config_t thread_config_cspace(sel4utils_thread_config_t config, seL4_CPtr cspace_root,
123                                                             seL4_Word cspace_root_data)
124{
125    config.cspace = cspace_root;
126    config.cspace_root_data = cspace_root_data;
127    return config;
128}
129
130static inline sel4utils_thread_config_t thread_config_auth(sel4utils_thread_config_t config, seL4_CPtr tcb)
131{
132    config.sched_params.auth = tcb;
133    return config;
134}
135
136static inline sel4utils_thread_config_t thread_config_new(simple_t *simple)
137{
138    sel4utils_thread_config_t config = {0};
139    seL4_Word data = api_make_guard_skip_word(seL4_WordBits - simple_get_cnode_size_bits(simple));
140    config = thread_config_auth(config, simple_get_tcb(simple));
141    return thread_config_cspace(config, simple_get_cnode(simple), data);
142}
143
144static inline sel4utils_thread_config_t thread_config_priority(sel4utils_thread_config_t config, uint8_t priority)
145{
146    config.sched_params.priority = priority;
147    return config;
148}
149
150static inline sel4utils_thread_config_t thread_config_mcp(sel4utils_thread_config_t config, uint8_t mcp)
151{
152    config.sched_params.mcp = mcp;
153    return config;
154}
155
156static inline sel4utils_thread_config_t thread_config_stack_size(sel4utils_thread_config_t config, seL4_Word size)
157{
158    config.stack_size = size;
159    config.custom_stack_size = true;
160    return config;
161}
162
163static inline sel4utils_thread_config_t thread_config_no_ipc_buffer(sel4utils_thread_config_t config)
164{
165    config.no_ipc_buffer = true;
166    return config;
167}
168
169static inline sel4utils_thread_config_t thread_config_fault_endpoint(sel4utils_thread_config_t config,
170                                                                     seL4_CPtr fault_ep)
171{
172    config.fault_endpoint = fault_ep;
173    return config;
174}
175
176static inline sel4utils_thread_config_t thread_config_default(simple_t *simple, seL4_CPtr cnode, seL4_Word data,
177                                                              seL4_CPtr fault_ep, uint8_t prio)
178{
179    sel4utils_thread_config_t config = thread_config_new(simple);
180    config = thread_config_cspace(config, cnode, data);
181    config = thread_config_fault_endpoint(config, fault_ep);
182    config = thread_config_priority(config, prio);
183    if (config_set(CONFIG_KERNEL_MCS)) {
184        uint64_t timeslice = CONFIG_BOOT_THREAD_TIME_SLICE;
185        config.sched_params = sched_params_round_robin(config.sched_params, simple, 0, timeslice * US_IN_MS);
186    }
187    config = thread_config_create_reply(config);
188    return config;
189}
190