blob: ddc5f9e5630b4fe69f161f79a3565d801eae1e13 [file] [log] [blame] [edit]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
/* Include Kconfig variables. */
#include <autoconf.h>
#include <sel4test-driver/gen_config.h>
#include <assert.h>
#include <stdio.h>
/* Our headers are not C++ friendly */
extern "C" {
#include <sel4/sel4.h>
#include "../helpers.h"
}
#define POLL_DELAY_NS 4000000
typedef int (*test_func_t)(seL4_Word /* id */, env_t env /* env */);
static int
own_domain_success(struct env *env)
{
int error;
error = seL4_DomainSet_Set(env->domain, CONFIG_NUM_DOMAINS - 1,
env->tcb);
return (error == seL4_NoError) ? SUCCESS : FAILURE;
}
static int
own_domain_baddom(struct env *env)
{
int error;
error = seL4_DomainSet_Set(env->domain, CONFIG_NUM_DOMAINS + 10,
env->tcb);
return (error == seL4_InvalidArgument) ? SUCCESS : FAILURE;
}
static int
own_domain_badcap(struct env *env)
{
int error;
error = seL4_DomainSet_Set(env->tcb, 0,
env->tcb);
return (error == seL4_IllegalOperation) ? SUCCESS : FAILURE;
}
int fdom1(seL4_Word id, env_t env)
{
int countdown = 50;
while (countdown > 0) {
sleep_busy(env, POLL_DELAY_NS);
--countdown;
ZF_LOGD("%2d, ", (int)id);
}
return sel4test_get_result();
}
/* This is a very simple (and rather stupid) C++ usage. Proves that a template
* can be defined but is not good C++ */
template<bool shift, typename F>
static int
test_domains(struct env *env, F func)
{
UNUSED int error;
helper_thread_t thread[CONFIG_NUM_DOMAINS];
for (int i = 0; i < CONFIG_NUM_DOMAINS; ++i) {
create_helper_thread(env, &thread[i]);
set_helper_priority(env, &thread[i], 64);
error = seL4_DomainSet_Set(env->domain, (seL4_Word)i, get_helper_tcb(&thread[i]));
assert(error == seL4_NoError);
}
for (int i = 0; i < CONFIG_NUM_DOMAINS; ++i) {
start_helper(env, &thread[i], (helper_fn_t) func, i, (seL4_Word) env, 0, 0);
}
if (CONFIG_NUM_DOMAINS > 1 && shift) {
sel4test_sleep(env, POLL_DELAY_NS * 2);
error = seL4_DomainSet_Set(env->domain, CONFIG_NUM_DOMAINS - 1, get_helper_tcb(&thread[0]));
assert(error == seL4_NoError);
}
for (int i = 0; i < CONFIG_NUM_DOMAINS; ++i) {
wait_for_helper(&thread[i]);
cleanup_helper(env, &thread[i]);
}
return sel4test_get_result();
}
/* The output from this test should show alternating "domain blocks", with,
* within each, a single thread printing. For example:
*
* 00, 00, ..., 00, 01, 01, ..., 01, 00, 00, ..., 00, 01, 01, ..., 01, etc.
* +-------------+ +-------------+ +-------------+ +-------------+
* block 0 block 1 block 0 block 1
*/
static int
test_run_domains(struct env* env)
{
return test_domains<false>(env, fdom1);
}
DEFINE_TEST(DOMAINS0004, "Run threads in domains()", test_run_domains, config_set(CONFIG_HAVE_TIMER))
/* The output of this test differs from that of DOMAINS0004 in that the thread
* in domain 0 is moved into domain 1 after a short delay. This should be
* visible in the output, where the "domain block" for domain 1 should contain
* the alternating output of threads 0 and 1. For example:
*
* 00, 00, ..., 00, 01, 00, 01, 00, ..., 01, 01, 01, 01
* +-------------+ +------------------+ +------------+
* initial block alterations final block
* (due to delay) (after shift) (01 catches up)
*/
static int
test_run_domains_shift(struct env* env)
{
return test_domains<true>(env, fdom1);
}
DEFINE_TEST(DOMAINS0005, "Move thread between domains()", test_run_domains_shift, config_set(CONFIG_HAVE_TIMER) && CONFIG_NUM_DOMAINS > 1)
static int
test_own_domain1(struct env* env)
{
return own_domain_success(env);
}
DEFINE_TEST(DOMAINS0001, "Change domain successfully()", test_own_domain1, true)
static int
test_own_domain2(struct env* env)
{
return own_domain_baddom(env);
}
DEFINE_TEST(DOMAINS0002, "Try non-existant domain()", test_own_domain2, true)
static int
test_own_domain3(struct env* env)
{
return own_domain_badcap(env);
}
DEFINE_TEST(DOMAINS0003, "Invoke non-domain cap()", test_own_domain3, true)