aos/lib/aos/inthandler.c
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

110 lines
2.9 KiB
C

/**
* \file User-level interrupt handler support
* \brief
*/
/*
* Copyright (c) 2007, 2008, 2009, 2010, 2011, 2020 ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
*/
#include <aos/aos.h>
#include <aos/lmp_endpoints.h>
#include <aos/inthandler.h>
errval_t inthandler_alloc_dest_irq_cap(int vec_hint, struct capref *retcap)
{
errval_t err;
err = slot_alloc(retcap);
if(err_is_fail(err)){
DEBUG_ERR(err, "slot_alloc");
return err;
}
err = invoke_irqtable_alloc_dest_cap(cap_irq, *retcap, vec_hint);
if(err_is_fail(err)) {
DEBUG_ERR(err, "could not allocate dest cap!");
return err;
}
return SYS_ERR_OK;
}
struct interrupt_handler_state {
struct lmp_endpoint *idcep;
struct waitset *ws;
struct event_closure uc;
};
static void generic_interrupt_handler(void *arg)
{
struct interrupt_handler_state *state = arg;
errval_t err;
// consume message
struct lmp_recv_msg buf = LMP_RECV_MSG_INIT;
err = lmp_endpoint_recv(state->idcep, &buf.buf, NULL);
assert(err_is_ok(err));
if (buf.buf.msglen == 1 && buf.words[0] == 1) {
// domain moved notification. Don't do this on AOS
USER_PANIC("Domain got moved, need to reregister for interrupt\n");
} else {
state->uc.handler(state->uc.arg);
}
// re-register
err = lmp_endpoint_register(state->idcep, state->ws,
MKCLOSURE(generic_interrupt_handler, arg));
assert(err_is_ok(err));
}
errval_t inthandler_setup(struct capref dst_cap, struct waitset *ws,
struct event_closure handler)
{
errval_t err;
// alloc state
struct interrupt_handler_state *state;
state = malloc(sizeof(struct interrupt_handler_state));
assert(state != NULL);
state->uc = handler;
state->ws = ws;
// create endpoint to handle interrupts
struct capref epcap;
// use minimum-sized endpoint, because we don't need to buffer >1 interrupt
err = endpoint_create(LMP_RECV_LENGTH, &epcap, &state->idcep);
if (err_is_fail(err)) {
free(state);
return err_push(err, LIB_ERR_ENDPOINT_CREATE);
}
// connect irq_dest with EP
err = invoke_irqdest_connect(dst_cap, epcap);
if (err_is_fail(err)) {
DEBUG_ERR(err, "Could not connect irq_cap and endpoint");
return err;
}
// register to receive on this endpoint
err = lmp_endpoint_register(state->idcep, ws,
MKCLOSURE(generic_interrupt_handler, state));
if (err_is_fail(err)) {
lmp_endpoint_free(state->idcep);
// TODO: release vector
free(state);
return err_push(err, LIB_ERR_LMP_ENDPOINT_REGISTER);
}
return SYS_ERR_OK;
}