HelenOS sources
This source file includes following definitions.
- io_apic_read
- io_apic_write
- irq_to_pin
- apic_enable_irq
- apic_connection
- apic_add
- apic_remove
- apic_gone
#include <ipc/irc.h>
#include <loc.h>
#include <sysinfo.h>
#include <as.h>
#include <ddf/driver.h>
#include <ddf/log.h>
#include <ddi.h>
#include <stdbool.h>
#include <errno.h>
#include <str_error.h>
#include <async.h>
#include <stdio.h>
#include "apic.h"
#define NAME "apic"
#define APIC_MAX_IRQ 15
#define IOREGSEL (0x00U / sizeof(uint32_t))
#define IOWIN (0x10U / sizeof(uint32_t))
#define IOREDTBL 0x10U
typedef union {
uint32_t value;
struct {
uint8_t reg_addr;
unsigned int : 24;
} __attribute__((packed));
} io_regsel_t;
typedef struct io_redirection_reg {
union {
uint32_t lo;
struct {
uint8_t intvec;
unsigned int delmod : 3;
unsigned int destmod : 1;
unsigned int delivs : 1;
unsigned int intpol : 1;
unsigned int irr : 1;
unsigned int trigger_mode : 1;
unsigned int masked : 1;
unsigned int : 15;
} __attribute__((packed));
};
union {
uint32_t hi;
struct {
unsigned int : 24;
uint8_t dest : 8;
} __attribute__((packed));
};
} __attribute__((packed)) io_redirection_reg_t;
#define IO_APIC_SIZE 20
static uint32_t io_apic_read(apic_t *apic, uint8_t address)
{
io_regsel_t regsel;
regsel.value = pio_read_32(&apic->regs[IOREGSEL]);
regsel.reg_addr = address;
pio_write_32(&apic->regs[IOREGSEL], regsel.value);
return pio_read_32(&apic->regs[IOWIN]);
}
static void io_apic_write(apic_t *apic, uint8_t address, uint32_t val)
{
io_regsel_t regsel;
regsel.value = pio_read_32(&apic->regs[IOREGSEL]);
regsel.reg_addr = address;
pio_write_32(&apic->regs[IOREGSEL], regsel.value);
pio_write_32(&apic->regs[IOWIN], val);
}
static int irq_to_pin(int irq)
{
if (irq == 0)
return 2;
return irq;
}
static errno_t apic_enable_irq(apic_t *apic, sysarg_t irq)
{
io_redirection_reg_t reg;
if (irq > APIC_MAX_IRQ)
return ELIMIT;
int pin = irq_to_pin(irq);
if (pin == -1)
return ENOENT;
reg.lo = io_apic_read(apic, (uint8_t) (IOREDTBL + pin * 2));
reg.masked = false;
io_apic_write(apic, (uint8_t) (IOREDTBL + pin * 2), reg.lo);
return EOK;
}
static void apic_connection(ipc_call_t *icall, void *arg)
{
ipc_call_t call;
apic_t *apic;
async_accept_0(icall);
apic = (apic_t *) ddf_dev_data_get(ddf_fun_get_dev((ddf_fun_t *) arg));
while (true) {
async_get_call(&call);
if (!ipc_get_imethod(&call)) {
async_answer_0(&call, EOK);
return;
}
switch (ipc_get_imethod(&call)) {
case IRC_ENABLE_INTERRUPT:
async_answer_0(&call, apic_enable_irq(apic,
ipc_get_arg1(&call)));
break;
case IRC_DISABLE_INTERRUPT:
async_answer_0(&call, EOK);
break;
case IRC_CLEAR_INTERRUPT:
async_answer_0(&call, EOK);
break;
default:
async_answer_0(&call, EINVAL);
break;
}
}
}
errno_t apic_add(apic_t *apic, apic_res_t *res)
{
sysarg_t have_apic;
ddf_fun_t *fun_a = NULL;
void *regs;
errno_t rc;
bool bound = false;
if ((sysinfo_get_value("apic", &have_apic) != EOK) || (!have_apic)) {
printf("%s: No APIC found\n", NAME);
return ENOTSUP;
}
rc = pio_enable((void *) res->base, IO_APIC_SIZE, ®s);
if (rc != EOK) {
printf("%s: Failed to enable PIO for APIC: %s\n", NAME, str_error(rc));
return EIO;
}
apic->regs = (ioport32_t *)regs;
fun_a = ddf_fun_create(apic->dev, fun_exposed, "a");
if (fun_a == NULL) {
ddf_msg(LVL_ERROR, "Failed creating function 'a'.");
rc = ENOMEM;
goto error;
}
ddf_fun_set_conn_handler(fun_a, apic_connection);
rc = ddf_fun_bind(fun_a);
if (rc != EOK) {
ddf_msg(LVL_ERROR, "Failed binding function 'a': %s", str_error(rc));
goto error;
}
bound = true;
rc = ddf_fun_add_to_category(fun_a, "irc");
if (rc != EOK)
goto error;
return EOK;
error:
if (bound)
ddf_fun_unbind(fun_a);
if (fun_a != NULL)
ddf_fun_destroy(fun_a);
return rc;
}
errno_t apic_remove(apic_t *apic)
{
return ENOTSUP;
}
errno_t apic_gone(apic_t *apic)
{
return ENOTSUP;
}
HelenOS homepage, sources at GitHub