/*
 * Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once
/**
 *
 * Builder functions for thread configs
 *
 */

#include <autoconf.h>
#include <sel4utils/gen_config.h>
#include <sel4/types.h>
#include <simple/simple.h>
#include <sel4utils/api.h>

/* Threads and processes use this struct as both need scheduling config parameters */
typedef struct sched_params {
    /* seL4 priority for the thread to be scheduled with. */
    uint8_t priority;
    /* seL4 maximum controlled priority for the thread. */
    uint8_t mcp;
    /* TCB to derive MCP from when setting priority/mcp (in future API) */
    seL4_CPtr auth;
    /* true if sel4utils should create an sc */
    bool create_sc;
    /* sel4 sched control cap for creating sc */
    seL4_CPtr sched_ctrl;
    /* scheduling parameters */
    uint64_t period;
    uint64_t budget;
    seL4_Word extra_refills;
    seL4_Word badge;
    /* otherwise use this provided sc */
    seL4_CPtr sched_context;
    /* affinity for this tcb. Must set sched_ctrl if CONFIG_RT */
    seL4_Word core;
} sched_params_t;

typedef struct sel4utils_thread_config {
    /* fault_endpoint endpoint to set as the threads fault endpoint. Can be seL4_CapNull. */
    seL4_CPtr fault_endpoint;
    /* root of the cspace to start the thread in */
    seL4_CNode cspace;
    /* data for cspace access */
    seL4_Word cspace_root_data;
    /* use a custom stack size? */
    bool custom_stack_size;
    /* custom stack size in 4k pages for this thread */
    seL4_Word stack_size;
    /* true if this thread should have no ipc buffer */
    bool no_ipc_buffer;
    /* scheduling parameters */
    sched_params_t sched_params;
    /* true if sel4utils should create a reply */
    bool create_reply;
    /* otherwise provide one */
    seL4_CPtr reply;
} sel4utils_thread_config_t;

static inline sched_params_t sched_params_periodic(sched_params_t params, simple_t *simple, seL4_Word core,
                                                   uint64_t period_us,
                                                   uint64_t budget_us, seL4_Word extra_refills, seL4_Word badge)
{
    if (!config_set(CONFIG_KERNEL_MCS)) {
        ZF_LOGW("Setting sched params on non-RT kernel will have no effect");
    }
    params.sched_ctrl = simple_get_sched_ctrl(simple, core);
    params.period = period_us;
    params.budget = budget_us;
    params.extra_refills = extra_refills;
    params.badge = badge;
    params.create_sc = true;
    return params;
}

static inline sched_params_t sched_params_round_robin(sched_params_t params, simple_t *simple, seL4_Word core,
                                                      uint64_t timeslice_us)
{
    return sched_params_periodic(params, simple, core, timeslice_us, timeslice_us, 0, 0);
}

static inline sched_params_t sched_params_core(sched_params_t params, seL4_Word core)
{
    if (!config_set(CONFIG_KERNEL_MCS)) {
        ZF_LOGW("Setting core on RT kernel will have no effect - sched ctrl required");
    }
    params.core = core;
    return params;
}

static inline sel4utils_thread_config_t thread_config_create_reply(sel4utils_thread_config_t config)
{
    config.create_reply = true;
    return config;
}

static inline sel4utils_thread_config_t thread_config_reply(sel4utils_thread_config_t config, seL4_CPtr reply)
{
    config.create_reply = false;
    config.reply = reply;
    return config;
}

static inline sel4utils_thread_config_t thread_config_sched_context(sel4utils_thread_config_t config,
                                                                    seL4_CPtr sched_context)
{
    config.sched_params.create_sc = false;
    config.sched_params.sched_context = sched_context;
    return config;
}

static inline sel4utils_thread_config_t thread_config_cspace(sel4utils_thread_config_t config, seL4_CPtr cspace_root,
                                                             seL4_Word cspace_root_data)
{
    config.cspace = cspace_root;
    config.cspace_root_data = cspace_root_data;
    return config;
}

static inline sel4utils_thread_config_t thread_config_auth(sel4utils_thread_config_t config, seL4_CPtr tcb)
{
    config.sched_params.auth = tcb;
    return config;
}

static inline sel4utils_thread_config_t thread_config_new(simple_t *simple)
{
    sel4utils_thread_config_t config = {0};
    seL4_Word data = api_make_guard_skip_word(seL4_WordBits - simple_get_cnode_size_bits(simple));
    config = thread_config_auth(config, simple_get_tcb(simple));
    return thread_config_cspace(config, simple_get_cnode(simple), data);
}

static inline sel4utils_thread_config_t thread_config_priority(sel4utils_thread_config_t config, uint8_t priority)
{
    config.sched_params.priority = priority;
    return config;
}

static inline sel4utils_thread_config_t thread_config_mcp(sel4utils_thread_config_t config, uint8_t mcp)
{
    config.sched_params.mcp = mcp;
    return config;
}

static inline sel4utils_thread_config_t thread_config_stack_size(sel4utils_thread_config_t config, seL4_Word size)
{
    config.stack_size = size;
    config.custom_stack_size = true;
    return config;
}

static inline sel4utils_thread_config_t thread_config_no_ipc_buffer(sel4utils_thread_config_t config)
{
    config.no_ipc_buffer = true;
    return config;
}

static inline sel4utils_thread_config_t thread_config_fault_endpoint(sel4utils_thread_config_t config,
                                                                     seL4_CPtr fault_ep)
{
    config.fault_endpoint = fault_ep;
    return config;
}

static inline sel4utils_thread_config_t thread_config_default(simple_t *simple, seL4_CPtr cnode, seL4_Word data,
                                                              seL4_CPtr fault_ep, uint8_t prio)
{
    sel4utils_thread_config_t config = thread_config_new(simple);
    config = thread_config_cspace(config, cnode, data);
    config = thread_config_fault_endpoint(config, fault_ep);
    config = thread_config_priority(config, prio);
    if (config_set(CONFIG_KERNEL_MCS)) {
        uint64_t timeslice = CONFIG_BOOT_THREAD_TIME_SLICE;
        config.sched_params = sched_params_round_robin(config.sched_params, simple, 0, timeslice * US_IN_MS);
    }
    config = thread_config_create_reply(config);
    return config;
}
