blob: a3bf7435e1bccf4ef0f7b70fdf5719e1ea9114fe [file] [log] [blame] [edit]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <autoconf.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sel4/sel4.h>
#include <sel4utils/arch/util.h>
#include <vka/object.h>
#include "../test.h"
#include "../helpers.h"
#ifdef CONFIG_ARCH_X86
#define START_PORT 0
#define END_PORT BIT(16)
#define PORT_STRIDE 256
#define EXPECTED_FAULTS ((END_PORT - START_PORT) / PORT_STRIDE)
static volatile int total_faults = 0;
static void increment_pc(seL4_CPtr tcb, seL4_Word inc)
{
seL4_UserContext ctx;
seL4_Error error = seL4_TCB_ReadRegisters(tcb,
false,
0,
sizeof(ctx) / sizeof(seL4_Word),
&ctx);
test_eq(error, seL4_NoError);
#ifdef CONFIG_ARCH_X86_64
ctx.rax = 1;
ctx.rip += inc;
#else
ctx.eax = 1;
ctx.eip += inc;
#endif
error = seL4_TCB_WriteRegisters(tcb,
true,
0,
sizeof(ctx) / sizeof(seL4_Word),
&ctx);
test_eq(error, seL4_NoError);
}
static int handle_fault(seL4_CPtr fault_ep, seL4_CPtr tcb, seL4_Word expected_fault, seL4_CPtr reply)
{
seL4_MessageInfo_t tag;
seL4_Word sender_badge = 0;
while (1) {
tag = api_recv(fault_ep, &sender_badge, reply);
test_check(seL4_MessageInfo_get_label(tag) == seL4_Fault_UserException);
total_faults++;
increment_pc(tcb, 1);
}
return 0;
}
static int do_ioports(int arg1, int arg2, int arg3, int arg4)
{
unsigned int i;
for (i = START_PORT; i < END_PORT; i += PORT_STRIDE) {
volatile unsigned char dummy = 0;
asm volatile("inb %1,%0"
: "=a"(dummy)
: "dN"((uint16_t)i)
);
test_check(dummy == 1);
}
return 0;
}
static int test_native_ioports(env_t env)
{
helper_thread_t handler_thread;
helper_thread_t faulter_thread;
int error;
seL4_Word handler_arg0, handler_arg1;
/* The endpoint on which faults are received. */
seL4_CPtr fault_ep = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr faulter_vspace, faulter_cspace;
create_helper_thread(env, &faulter_thread);
create_helper_thread(env, &handler_thread);
faulter_cspace = env->cspace_root;
faulter_vspace = env->page_directory;
handler_arg0 = fault_ep;
handler_arg1 = get_helper_tcb(&faulter_thread);
set_helper_priority(env, &handler_thread, 100);
error = api_tcb_set_space(get_helper_tcb(&faulter_thread),
fault_ep,
faulter_cspace,
api_make_guard_skip_word(seL4_WordBits - env->cspace_size_bits),
faulter_vspace, seL4_NilData);
set_helper_priority(env, &faulter_thread, 100);
test_error_eq(error, seL4_NoError);
/* clear the faults */
total_faults = 0;
start_helper(env, &handler_thread, (helper_fn_t) handle_fault,
handler_arg0, handler_arg1, 0, get_helper_reply(&handler_thread));
start_helper(env, &faulter_thread, (helper_fn_t) do_ioports,
0, 0, 0, 0);
wait_for_helper(&faulter_thread);
test_check(total_faults == EXPECTED_FAULTS);
cleanup_helper(env, &handler_thread);
cleanup_helper(env, &faulter_thread);
return (total_faults == EXPECTED_FAULTS) ? SUCCESS : FAILURE;
}
DEFINE_TEST(IOPORTS1000, "Test fault if directly using I/O ports", test_native_ioports, true)
#endif