--- /dev/null
+#ifndef __LUNAIX_AA64_GIC_H
+#define __LUNAIX_AA64_GIC_H
+
+#include <lunaix/bits.h>
+#include "aa64_msrs.h"
+
+#define FRAME_SIZE 0x10000
+
+typedef unsigned int gicreg_t;
+typedef unsigned long gicreg64_t;
+#define FRAME_LEN (FRAME_SIZE / sizeof(gicreg_t))
+#define REG_INDEX(addr) ((addr) / sizeof(gicreg_t))
+
+#define ICC_CTLR_EL1 __sr_encode(3, 0, 12, 12, 4)
+#define ICC_SRE_EL1 __sr_encode(3, 0, 12, 12, 5)
+#define ICC_IGRPEN0_EL1 __sr_encode(3, 0, 12, 12, 6)
+#define ICC_IGRPEN1_EL1 __sr_encode(3, 0, 12, 12, 7)
+
+#define ICC_IAR1_EL1 __sr_encode(3, 0, 12, 12, 0)
+#define ICC_EOIR1_EL1 __sr_encode(3, 0, 12, 12, 1)
+
+#define INTID_ACKED_S 1020
+#define INTID_ACKED_NS 1021
+#define INTID_IAR1_NMI 1022
+#define INTID_NOTHING 1023
+#define check_special_intid(intid) \
+ ((intid) >= INTID_ACKED_S && (intid) <= INTID_NOTHING)
+
+#define LPI_PRIORITY BITFIELD(7, 2)
+#define LPI_EN 1UL
+
+#define ICC_SRE_SRE BITFLAG(0)
+#define ICC_SRE_DFB BITFLAG(1)
+#define ICC_SRE_DIB BITFLAG(2)
+
+#define ICC_CTRL_EXTRAN BITFLAG(19)
+#define ICC_CTRL_IDbits BITFIELD(13, 11)
+#define ICC_CTRL_PRIbits BITFIELD(10, 8)
+#define ICC_CTRL_PMHE BITFLAG(6)
+#define ICC_CTRL_EOImode BITFLAG(1)
+#define ICC_CTRL_CBPR BITFLAG(0)
+
+#define ICC_IGRPEN_ENABLE BITFLAG(0)
+
+#define GICD_CTLR REG_INDEX(0x0000)
+#define GICD_TYPER REG_INDEX(0x0004)
+#define GICD_IIDR REG_INDEX(0x0008)
+
+#define GICD_IGROUPRn REG_INDEX(0x0080)
+#define GICD_ISENABLER REG_INDEX(0x0100)
+#define GICD_ICENABLER REG_INDEX(0x0180)
+#define GICD_IPRIORITYR REG_INDEX(0x0400)
+#define GICD_ICFGR REG_INDEX(0x0C00)
+#define GICD_IGRPMODRn REG_INDEX(0x0D00)
+#define GICD_INMIR REG_INDEX(0x0F80)
+
+#define GICR_CTLR REG_INDEX(0x0000)
+#define GICR_TYPER REG_INDEX(0x0008)
+#define GICR_PROPBASER REG_INDEX(0x0070)
+#define GICR_PENDBASER REG_INDEX(0x0078)
+
+#define GICD_CTLR_G1SEN BITFLAG(2)
+#define GICD_CTLR_G1NSEN BITFLAG(1)
+#define GICD_CTLR_G0EN BITFLAG(0)
+
+#define GICD_TYPER_nESPI BITFIELD(31, 27)
+#define GICD_TYPER_No1N BITFLAG(25)
+#define GICD_TYPER_LPIS BITFLAG(17)
+#define GICD_TYPER_MBIS BITFLAG(16)
+#define GICD_TYPER_nLPI BITFIELD(15, 11)
+#define GICD_TYPER_NMI BITFLAG(9)
+#define GICD_TYPER_ESPI BITFLAG(8)
+#define GICD_TYPER_nSPI BITFIELD(4, 0)
+#define GICD_TYPER_IDbits BITFIELD(23, 19)
+
+#define GICR_TYPER_AffVal BITFIELD(63, 32)
+#define GICR_TYPER_PPInum BITFIELD(31, 27)
+
+#define GICR_BASER_PAddr BITFIELD(51, 12)
+#define GICR_BASER_Share BITFIELD(11, 10)
+#define GICR_PENDBASER_PTZ BITFLAG(62)
+#define GICR_PROPBASER_IDbits\
+ BITFIELD(4, 0)
+
+#endif /* __LUNAIX_AA64_GIC_H */
--- /dev/null
+#include <lunaix/types.h>
+#include <lunaix/device.h>
+#include <lunaix/spike.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/mmio.h>
+#include <lunaix/syslog.h>
+
+#include <hal/devtree.h>
+
+#include <asm/aa64_isrm.h>
+#include <asm/soc/gic.h>
+
+static struct arm_gic gic;
+
+LOG_MODULE("gic")
+
+DEFINE_BMP_INIT_OP(gic_bmp, valloc);
+
+DEFINE_BMP_QUERY_OP(gic_bmp);
+
+DEFINE_BMP_SET_OP(gic_bmp);
+
+DEFINE_BMP_ALLOCFROM_OP(gic_bmp);
+
+
+/* ++++++ GIC device-tree retrieval ++++++ */
+
+static void
+__setup_pe_rdist(struct dt_prop_iter* prop)
+{
+ ptr_t base;
+ size_t len, off;
+ int i;
+
+ base = dtprop_reg_nextaddr(prop);
+ len = dtprop_reg_nextlen(prop);
+
+ assert(len >= NR_CPU * FRAME_SIZE * 2);
+
+ i = 0;
+ base = ioremap(base, len);
+ off = base;
+
+ for (; i < NR_CPU; i++) {
+ gic.pes[i]._rd = (struct gic_rd*) (base + off);
+ off += sizeof(struct gic_rd);
+ }
+}
+
+static void
+__create_its(struct dt_node* gic_node)
+{
+ struct dt_node* its_node;
+ struct dt_node_iter iter;
+ struct dt_prop_iter prop;
+ ptr_t its_base;
+ size_t its_size;
+
+ dt_begin_find(&iter, gic_node, "its");
+
+ if (!dt_find_next(&iter, (struct dt_node_base**)&its_node)) {
+ return;
+ }
+
+ dt_decode_reg(&prop, its_node, reg);
+
+ its_base = dtprop_reg_nextaddr(&prop);
+ its_size = dtprop_reg_nextlen(&prop);
+
+ assert(its_size >= sizeof(struct gic_its));
+
+ gic.mmrs.its = (struct gic_its*)ioremap(its_base, its_size);
+}
+
+static void
+gic_create_from_dt()
+{
+ struct dt_node* gic_node;
+ struct dt_node_iter iter;
+ struct dt_prop_iter prop;
+ ptr_t ptr;
+ size_t sz;
+
+ dt_begin_find(&iter, NULL, "interrupt-controller");
+
+ if (!dt_find_next(&iter, (struct dt_node_base**)&gic_node)) {
+ fail("expected /interrupt-controller node, but found none");
+ }
+
+ dt_decode_reg(&prop, gic_node, reg);
+
+ ptr = dtprop_reg_nextaddr(&prop);
+ sz = dtprop_reg_nextlen(&prop);
+ gic.mmrs.dist_base = (gicreg_t*)ioremap(ptr, sz);
+
+ __setup_pe_rdist(&prop);
+
+ // ignore cpu_if, as we use sysreg to access them
+ dtprop_next_n(&prop, 2);
+
+ // ignore vcpu_if, as we dont do any EL2 stuff
+
+ __create_its(gic_node);
+}
+
+
+/* ++++++ GIC dirver ++++++ */
+
+static void
+__config_interrupt(struct arm_gic* gic, struct gic_distributor* dist,
+ struct gic_interrupt* ent)
+{
+ unsigned int intid_rel;
+ unsigned long trig_index;
+
+ intid_rel = ent->intid - ent->domain->base;
+
+ if (ent->config.class == GIC_LPI) {
+ lpi_entry_t entry = 0;
+
+ entry |= LPI_EN;
+
+ gic->lpi_tables.property[intid_rel] = entry;
+
+ // clear any pending when we (re-)configuring
+ bitmap_set(gic_bmp, &gic->lpi_tables.pendings, intid_rel, false);
+
+ return;
+ }
+
+
+ bitmap_set(gic_bmp, &dist->group, intid_rel, 0);
+ bitmap_set(gic_bmp, &dist->grpmod, intid_rel, 1);
+
+ trig_index = intid_rel * 2;
+ bitmap_set(gic_bmp, &dist->icfg, trig_index, 0);
+ if (ent->config.trigger == GIC_TRIG_EDGE) {
+ bitmap_set(gic_bmp, &dist->icfg, trig_index + 1, 1);
+ } else {
+ bitmap_set(gic_bmp, &dist->icfg, trig_index + 1, 0);
+ }
+
+ if (gic->nmi_ready) {
+ bitmap_set(gic_bmp, &dist->nmi, intid_rel, ent->config.as_nmi);
+ }
+
+ bitmap_set(gic_bmp, &dist->enable, intid_rel, true);
+}
+
+static void
+__undone_interrupt(struct arm_gic* gic, struct gic_distributor* dist,
+ struct gic_interrupt* ent)
+{
+ unsigned int intid_rel;
+
+ intid_rel = ent->intid - ent->domain->base;
+
+ if (ent->config.class == GIC_LPI) {
+ gic->lpi_tables.property[intid_rel] = 0;
+
+ // clear any pending when we (re-)configuring
+ bitmap_set(gic_bmp, &gic->lpi_tables.pendings, intid_rel, false);
+
+ return;
+ }
+
+ bitmap_set(gic_bmp, &dist->disable, intid_rel, true);
+
+ if (gic->nmi_ready) {
+ bitmap_set(gic_bmp, &dist->nmi, intid_rel, false);
+ }
+}
+
+static struct gic_idomain*
+__idomain(int nr_ints, unsigned int base, bool extended)
+{
+ struct gic_idomain* rec;
+
+ rec = valloc(sizeof(*rec));
+
+ bitmap_init(gic_bmp, &rec->ivmap, nr_ints);
+ hashtable_init(rec->recs);
+
+ rec->base = base;
+ rec->extended = extended;
+
+ return rec;
+}
+
+static inline void
+__init_distributor(struct gic_distributor* d,
+ gicreg_t* base, unsigned int nr_ints)
+{
+ bitmap_init_ptr(gic_bmp,
+ &d->group, nr_ints, gic_regptr(base, GICD_IGROUPRn));
+
+ bitmap_init_ptr(gic_bmp,
+ &d->grpmod, nr_ints, gic_regptr(base, GICD_IGRPMODRn));
+
+ bitmap_init_ptr(gic_bmp,
+ &d->enable, nr_ints, gic_regptr(base, GICD_ISENABLER));
+
+ bitmap_init_ptr(gic_bmp,
+ &d->disable, nr_ints, gic_regptr(base, GICD_ICENABLER));
+
+ bitmap_init_ptr(gic_bmp,
+ &d->icfg, nr_ints * 2, gic_regptr(base, GICD_ICFGR));
+
+ bitmap_init_ptr(gic_bmp,
+ &d->nmi, nr_ints, gic_regptr(base, GICD_INMIR));
+}
+
+static inline struct leaflet*
+__alloc_lpi_table(size_t table_sz)
+{
+ unsigned int val;
+ struct leaflet* tab;
+
+ val = page_aligned(table_sz);
+ tab = alloc_leaflet(count_order(leaf_count(val)));
+ leaflet_wipe(tab);
+
+ return leaflet_addr(tab);
+}
+
+static struct gic_idomain*
+__deduce_domain(unsigned int intid)
+{
+ if (intid <= INITID_SGI_END) {
+ return gic.pes[0].idomain.local_ints;
+ }
+
+ if (intid <= INITID_PPI_END) {
+ return gic.pes[0].idomain.local_ints;
+ }
+
+ if (intid <= INITID_SPI_END) {
+ return gic.idomain.spi;
+ }
+
+ if (INITID_ePPI_BASE <= intid && intid <= INITID_ePPI_END) {
+ return gic.pes[0].idomain.eppi;
+ }
+
+ if (INITID_eSPI_BASE <= intid && intid <= INITID_eSPI_END) {
+ return gic.idomain.espi;
+ }
+
+ if (intid >= INITID_LPI_BASE) {
+ return gic.idomain.lpi;
+ }
+
+ return NULL;
+}
+
+static struct gic_interrupt*
+__find_interrupt_record(unsigned int intid)
+{
+ struct gic_idomain* domain;
+
+ domain = __deduce_domain(intid);
+
+ if (!domain) {
+ return NULL;
+ }
+
+ struct gic_interrupt *pos, *n;
+
+ hashtable_hash_foreach(domain->recs, intid, pos, n, node)
+ {
+ if (pos->intid == intid) {
+ return pos;
+ }
+ }
+
+ return NULL;
+}
+
+static inline struct gic_interrupt*
+__register_interrupt(struct gic_idomain* domain,
+ unsigned int intid, struct gic_int_param* param)
+{
+ struct gic_interrupt* interrupt;
+
+ interrupt = valloc(sizeof(*interrupt));
+ interrupt->config = (struct gic_intcfg) {
+ .class = param->class,
+ .trigger = param->trigger,
+ .group = param->group,
+ .as_nmi = param->as_nmi
+ };
+
+ interrupt->intid = intid;
+ interrupt->domain = domain;
+
+ hashtable_hash_in(domain->recs, &interrupt->node, intid);
+
+ return interrupt;
+}
+
+static struct gic_distributor*
+__attached_distributor(int cpu, struct gic_interrupt* ent)
+{
+ enum gic_int_type iclass;
+
+ iclass = ent->config.class;
+
+ if (iclass == GIC_PPI || iclass == GIC_SGI) {
+ return &gic.pes[cpu].rdist;
+ }
+
+ if (ent->domain->extended) {
+ return &gic.dist_e;
+ }
+
+ return &gic.dist;
+}
+
+static void
+gic_configure_icc()
+{
+ reg_t v;
+
+ v =
+ sysreg_flagging(ICC_SRE_EL1,
+ ICC_SRE_SRE | ICC_SRE_DFB | ICC_SRE_DIB,
+ 0);
+
+
+ v =
+ sysreg_flagging(ICC_CTLR_EL1,
+ ICC_CTRL_CBPR,
+ ICC_CTRL_EOImode | ICC_CTRL_PMHE);
+
+ // disable all group 0 interrupts as those are meant for EL3
+ v=
+ sysreg_flagging(ICC_IGRPEN0_EL1, 0, ICC_IGRPEN_ENABLE);
+
+ // enable all group 1 interrupts, we'll stick with EL1_NS
+ v=
+ sysreg_flagging(ICC_IGRPEN1_EL1, ICC_IGRPEN_ENABLE, 0);
+}
+
+static void
+gic_configure_global(struct arm_gic* gic)
+{
+ gicreg64_t reg;
+ unsigned int val, max_nr_spi;
+
+ reg = gic->mmrs.dist_base[GICD_TYPER];
+
+ // check if eSPI supported
+ gic->has_espi = (reg & GICD_TYPER_ESPI);
+ if (gic->has_espi) {
+ val = BITS_GET(reg, GICD_TYPER_nESPI);
+ gic->espi_nr = 32 * (val + 1);
+ }
+
+ // Parse IDbits
+ val = BITS_GET(reg, GICD_TYPER_IDbits);
+ gic->max_intid = 1 << (val + 1) - 1;
+
+ // LPI is supported
+ if (val + 1 >= 14) {
+ val = BITS_GET(reg, GICD_TYPER_nLPI);
+ if (val) {
+ gic->lpi_nr = 1 << (val + 1);
+ }
+ else {
+ gic->lpi_nr = gic->max_intid - INITID_LPI_BASE + 1;
+ }
+ }
+
+ // check if SPI supported
+ val = BITS_GET(reg, GICD_TYPER_nSPI);
+ if (val) {
+ max_nr_spi = 32 * (val + 1);
+ gic->spi_nr = MIN(max_nr_spi, INITID_SPEC_BASE);
+ gic->spi_nr -= INITID_SPI_BASE;
+ } else {
+ gic->spi_nr = 0;
+ }
+
+ gic->nmi_ready = (reg & GICD_TYPER_NMI);
+ gic->msi_via_spi = (reg & GICD_TYPER_MBIS);
+
+ __init_distributor(&gic->dist, gic->mmrs.dist_base, gic->spi_nr);
+ __init_distributor(&gic->dist_e, gic->mmrs.dist_base, gic->espi_nr);
+
+
+ if (gic->spi_nr) {
+ gic->idomain.spi = __idomain(gic->spi_nr, INITID_SPI_BASE, false);
+ }
+ if (gic->espi_nr) {
+ gic->idomain.espi = __idomain(gic->espi_nr, INITID_eSPI_BASE, true);
+ }
+ if (gic->lpi_nr) {
+ gic->idomain.lpi = __idomain(gic->lpi_nr, INITID_LPI_BASE, false);
+ }
+
+ gic->lpi_tables.prop = __alloc_lpi_table(gic->lpi_nr);
+ gic->lpi_tables.pend = __alloc_lpi_table(gic->lpi_nr / 8);
+
+ bitmap_init_ptr(gic_bmp,
+ &gic->lpi_tables.pendings, gic->lpi_nr, gic->lpi_tables.pend);
+}
+
+static void
+gic_configure_pe(struct arm_gic* gic, struct gic_pe* pe)
+{
+ unsigned int nr_local_ints;
+ gicreg64_t reg;
+
+ reg = gic_reg64(pe->_rd, GICR_TYPER);
+
+ pe->affinity = BITS_GET(reg, GICR_TYPER_AffVal);
+ pe->ppi_nr = INITID_PPI_BASE;
+ switch (BITS_GET(reg, GICR_TYPER_PPInum))
+ {
+ case 1:
+ pe->ppi_nr += 1088 - INITID_ePPI_BASE;
+ pe->eppi_ready = true;
+ break;
+ case 2:
+ pe->ppi_nr += 1120 - INITID_ePPI_BASE;
+ pe->eppi_ready = true;
+ break;
+ }
+
+ nr_local_ints = pe->ppi_nr + INITID_PPI_BASE;
+
+ pe->idomain.local_ints = __idomain(32, 0, false);
+ pe->idomain.eppi = __idomain(nr_local_ints - 32, INITID_ePPI_BASE, true);
+
+ __init_distributor(&pe->rdist, pe->_rd->sgi_base, nr_local_ints);
+
+ reg = 0;
+ BITS_SET(reg, GICR_BASER_PAddr, gic->lpi_tables.prop);
+ BITS_SET(reg, GICR_BASER_Share, 0b01);
+ BITS_SET(reg, GICR_PROPBASER_IDbits, ilog2(gic->max_intid));
+ pe->_rd->sgi_base[GICR_PROPBASER] = reg;
+
+ reg = 0;
+ reg |= GICR_PENDBASER_PTZ;
+ BITS_SET(reg, GICR_BASER_PAddr, gic->lpi_tables.pend);
+ BITS_SET(reg, GICR_BASER_Share, 0b01);
+ pe->_rd->sgi_base[GICR_PENDBASER] = reg;
+}
+
+struct gic_interrupt*
+aa64_isrm_ivalloc(struct gic_int_param* param, isr_cb handler)
+{
+ unsigned int iv;
+ struct gic_idomain* domain;
+ int cpu;
+
+ cpu = param->cpu_id;
+
+ assert(cpu == 0);
+
+ switch (param->class)
+ {
+ case GIC_PPI:
+ if (!param->ext_range) {
+ domain = gic.pes[cpu].idomain.local_ints;
+ }
+ else {
+ domain = gic.pes[cpu].idomain.eppi;
+ }
+ break;
+
+ case GIC_SGI:
+ domain = gic.pes[cpu].idomain.local_ints;
+ break;
+
+ case GIC_SPI:
+ if (!param->ext_range) {
+ assert(gic.spi_nr > 0);
+ domain = gic.idomain.spi;
+ }
+ else {
+ assert(gic.has_espi);
+ domain = gic.idomain.espi;
+ }
+ break;
+
+ case GIC_LPI:
+ assert(gic.lpi_ready);
+ domain = gic.idomain.lpi;
+ break;
+
+ default:
+ fail("unknown interrupt class");
+ break;
+ }
+
+ if (!bitmap_alloc(gic_bmp, &domain->ivmap, 0, &iv)) {
+ FATAL("out of usable iv for class=%d", param->class);
+ }
+
+ iv += domain->base;
+
+ if (param->class == GIC_SPI && !param->ext_range && iv >= INITID_ePPI_BASE)
+ {
+ WARN("PPI vector=%d falls in extended range, while not requested.", iv);
+ param->ext_range = true;
+ }
+
+ struct gic_interrupt* ent;
+ struct gic_distributor* dist;
+
+ ent = __register_interrupt(domain, iv, param);
+ dist = __attached_distributor(cpu, ent);
+
+ __config_interrupt(&gic, dist, ent);
+
+ ent->handler = handler;
+
+ return iv;
+}
+
+static void
+gic_update_active()
+{
+ reg_t val;
+ unsigned int intid;
+ struct gic_interrupt* intr;
+ struct gic_pe* pe;
+
+ pe = &gic.pes[0];
+ val = read_sysreg(ICC_IAR1_EL1);
+ intid = (unsigned int)val & ((1 << 24) - 1);
+
+ if (check_special_intid(intid)) {
+ return;
+ }
+
+ intr = __find_interrupt_record(intid);
+ pe->active = intr;
+ pe->iar_val = val;
+}
+
+static void
+gic_signal_eoi()
+{
+ struct gic_pe* pe;
+
+ pe = &gic.pes[0];
+ if (!pe->active) {
+ return;
+ }
+
+ pe->active = NULL;
+ set_sysreg(ICC_EOIR1_EL1, pe->iar_val);
+}
+
+void
+isrm_init()
+{
+ // nothing to do
+}
+
+void
+isrm_ivfree(int iv)
+{
+ struct gic_interrupt* ent;
+ struct gic_distributor* dist;
+
+ ent = __find_interrupt_record(iv);
+ if (!ent) {
+ return;
+ }
+
+ dist = __attached_distributor(0, ent);
+ __undone_interrupt(&gic, dist, ent);
+
+ hlist_delete(&ent->node);
+ vfree(ent);
+}
+
+int
+isrm_ivosalloc(isr_cb handler)
+{
+ return isrm_ivexalloc(handler);
+}
+
+int
+isrm_ivexalloc(isr_cb handler)
+{
+ struct gic_int_param param;
+ struct gic_interrupt* intr;
+
+ param = (struct gic_int_param) {
+ .class = GIC_SPI,
+ .group = GIC_G1NS,
+ .trigger = GIC_TRIG_EDGE,
+ };
+
+ intr = aa64_isrm_ivalloc(¶m, handler);
+
+ return intr->intid;
+}
+
+int
+isrm_bindirq(int irq, isr_cb irq_handler)
+{
+ // Not supported
+}
+
+void
+isrm_bindiv(int iv, isr_cb handler)
+{
+ // Not supported
+}
+
+isr_cb
+isrm_get(int iv)
+{
+ struct gic_interrupt* intr;
+
+ intr = __find_interrupt_record(iv);
+ if (!intr) {
+ return NULL;
+ }
+
+ return intr->handler;
+}
+
+ptr_t
+isrm_get_payload(const struct hart_state* state)
+{
+ struct gic_interrupt* active;
+
+ active = gic.pes[0].active;
+ assert(active);
+
+ return active->handler;
+}
+
+void
+isrm_set_payload(int iv, ptr_t payload)
+{
+ struct gic_interrupt* intr;
+
+ intr = __find_interrupt_record(iv);
+ if (!intr) {
+ return NULL;
+ }
+
+ intr->payload = payload;
+}
+
+void
+isrm_irq_attach(int irq, int iv, cpu_t dest, u32_t flags)
+{
+ // Not supported
+}
+
+void
+isrm_notify_eoi(cpu_t id, int iv)
+{
+ struct gic_interrupt* active;
+
+ active = gic.pes[0].active;
+ assert(active);
+}
+
+void
+isrm_notify_eos(cpu_t id)
+{
+ isrm_notify_eoi(id, 0);
+}
+
+
+static void
+gic_init()
+{
+ memset(&gic, 0, sizeof(gic));
+
+ gic_create_from_dt();
+
+ // configure the system interfaces
+ gic_configure_icc();
+
+ // configure global distributor
+ gic_configure_global(&gic);
+
+ // configure per-PE local distributor (redistributor)
+ for (int i = 0; i < NR_CPU; i++)
+ {
+ gic_configure_pe(&gic, &gic.pes[i]);
+ }
+}
+
+static struct device_def dev_arm_gic = {
+ .name = "ARM Generic Interrupt Controller",
+ .class = DEVCLASS(DEVIF_SOC, DEVFN_CFG, DEV_INTC),
+ .init = gic_init
+};
+EXPORT_DEVICE(arm_gic, &dev_arm_gic, load_sysconf);
\ No newline at end of file
--- /dev/null
+#ifndef __LUNAIX_BITMAP_H
+#define __LUNAIX_BITMAP_H
+
+#include <lunaix/types.h>
+#include <lunaix/spike.h>
+#include <klibc/string.h>
+
+// first bit of a bitmap chunk placed at the most significant bit
+#define BMP_ORIENT_MSB 0
+// first bit of a bitmap chunk placed at the least significant bit
+#define BMP_ORIENT_LSB 1
+
+#define BMP_NAME(name) bitmap_##name
+#define BMP_PARAM_NAME bmp
+#define BMP_PARAM(name) struct BMP_NAME(name) *BMP_PARAM_NAME
+#define BMP_RAWBYTES(bits) (((bits) + 7) / 8)
+#define BMP_SIZE(t, bits) \
+ (BMP_RAWBYTES(bits) + (BMP_RAWBYTES(bits) % sizeof(t)))
+
+#define BMP_LEN(t, bits) (BMP_SIZE(t, bits) / sizeof(t))
+
+#define _BITMAP_STRUCT(type, size, name, orient) struct BMP_NAME(name)
+
+
+#define _DECLARE_BMP(type, size, name, orient) \
+struct BMP_NAME(name) { \
+ type *_map; \
+ unsigned long nr_bits; \
+}
+
+#define _DECLARE_BMP_STATIC(type, nr_bits, name, orient) \
+struct BMP_NAME(name) { \
+ type _map[BMP_LEN(type, nr_bits)]; \
+}
+
+#define BMP_STRCUT_MAP BMP_PARAM_NAME->_map
+#define BMP_STRCUT_NRB BMP_PARAM_NAME->nr_bits
+
+#define _BMP_OP_CALL(type, size, name, orient, suffix, ...) \
+bitmap_##name##_##suffix##(__VA_ARGS__)
+
+#define _DEFINE_BMP_INIT_OP(type, size, name, orient, allocfn) \
+static inline void \
+bitmap_##name##_init_with(BMP_PARAM(name), unsigned long nr_bits, ptr_t map) \
+{ \
+(void)(is_const(size) ? ({ \
+ BMP_STRCUT_MAP = map; \
+ BMP_STRCUT_NRB = nr_bits; \
+ memset(BMP_STRCUT_MAP, 0, BMP_SIZE(type, nr_bits) * sizeof(type));0; \
+}) : ({ \
+ memset(BMP_STRCUT_MAP, 0, sizeof(BMP_STRCUT_MAP));0; \
+})); \
+} \
+static inline void \
+bitmap_##name##_init(BMP_PARAM(name), unsigned long nr_bits) \
+{ \
+(void)(is_const(size) ? ({ \
+ bitmap_##name##_init_with(BMP_PARAM_NAME, nr_bits, \
+ allocfn(BMP_SIZE(type, nr_bits)));0; \
+}) : ({ \
+ bitmap_##name##_init_with(BMP_PARAM_NAME, nr_bits, NULL);0; \
+})); \
+}
+
+
+#define _DEFINE_BMP_QUERY_OP(type, size, name, orient) \
+static inline bool \
+bitmap_##name##_query(BMP_PARAM(name), unsigned long pos) \
+{ \
+ assert(pos < size); \
+ unsigned long n = pos / (sizeof(type) * 8); \
+ int i = pos % (sizeof(type) * 8); \
+ type at = BMP_STRCUT_MAP[n]; \
+ type msk = 1 << select(orient == BMP_ORIENT_MSB, \
+ sizeof(type) * 8 - 1 - i, i ); \
+ return !!(at & msk); \
+}
+
+
+#define _DEFINE_BMP_SET_OP(type, size, name, orient) \
+static inline void \
+bitmap_##name##_set(BMP_PARAM(name), unsigned long pos, bool val) \
+{ \
+ assert(pos < size); \
+ unsigned long n = pos / (sizeof(type) * 8); \
+ int i = pos % (sizeof(type) * 8); \
+ type at = BMP_STRCUT_MAP[n]; \
+ unsigned int off = select(orient == BMP_ORIENT_MSB, \
+ sizeof(type) * 8 - 1 - i, i ); \
+ BMP_STRCUT_MAP[n] = (at & ~(1 << off)) | (!!val << off); \
+}
+
+
+#define _DEFINE_BMP_ALLOCFROM_OP(type, size, name, orient) \
+static inline bool \
+bitmap_##name##_alloc_from(BMP_PARAM(name), unsigned long start, \
+ unsigned long* _out) \
+{ \
+ unsigned long i, p = 0; \
+ int shift; \
+ type u; \
+ i = start / 8 / sizeof(type); \
+ shift = select(orient == BMP_ORIENT_MSB, sizeof(type) * 8 - 1, 0); \
+ while ((u = BMP_STRCUT_MAP[i]) == (type)-1) i++; \
+ while ((u & (type)(1U << shift)) && p++ < sizeof(type) * 8) \
+ select(orient == BMP_ORIENT_MSB, u <<= 1, u >>= 1); \
+ if (p < sizeof(type) * 8) \
+ return false; \
+ BMP_STRCUT_MAP[i] |= 1UL << shift; \
+ *_out = (i + p); \
+ return true; \
+}
+
+
+#define PREP_STATIC_BITMAP(type, name, nr_bits, orient) \
+ type, (nr_bits), name, orient
+#define PREP_BITMAP(type, name, orient) \
+ type, (BMP_STRCUT_NRB), name, orient
+
+
+#define DECLARE_BITMAP(bmpdef) _DECLARE_BMP(bmpdef)
+#define DECLARE_STATIC_BITMAP(bmpdef) _DECLARE_BMP_STATIC(bmpdef)
+#define BITMAP(bmpdef) _BITMAP_STRUCT(bmpdef)
+
+#define DEFINE_BMP_INIT_OP(bmpdef, allocfn) _DEFINE_BMP_INIT_OP(bmpdef, allocfn)
+
+#define DEFINE_BMP_QUERY_OP(bmpdef) _DEFINE_BMP_QUERY_OP(bmpdef)
+#define DEFINE_BMP_SET_OP(bmpdef) _DEFINE_BMP_SET_OP(bmpdef)
+#define DEFINE_BMP_ALLOCFROM_OP(bmpdef) _DEFINE_BMP_ALLOCFROM_OP(bmpdef)
+
+#define bitmap_query(bitmap, bmp, pos) \
+ _BMP_OP_CALL(bitmap, query, bmp, pos)
+
+#define bitmap_set(bitmap, bmp, pos, val) \
+ _BMP_OP_CALL(bitmap, set, bmp, pos, val)
+
+#define bitmap_alloc(bitmap, bmp, start, out) \
+ _BMP_OP_CALL(bitmap, alloc_from, bmp, start, out)
+
+#define bitmap_init(bitmap, bmp, nr_bits) \
+ _BMP_OP_CALL(bitmap, init, bmp, nr_bits)
+
+#define bitmap_init_ptr(bitmap, bmp, nr_bits, ptr) \
+ _BMP_OP_CALL(bitmap, init_with, bmp, nr_bits, ptr)
+
+
+#endif /* __LUNAIX_BITMAP_H */