From c50ef1526a29f29b65cf353a590ea36b9d2e963a Mon Sep 17 00:00:00 2001 From: Lunaixsky Date: Tue, 8 Oct 2024 00:59:06 +0100 Subject: [PATCH] add implementation of ARM GIC driver. Supported feature: 1. Basic SGI, PPI, SPI, LPI enablement 2. extended ranges (ePPI, eSPI) 3. FEAT_NMI compatibility 4. Per-PE redistributor config 5. MBIs capable. --- .../arch/aarch64/includes/asm/aa64_gic.h | 85 +++ .../arch/aarch64/includes/asm/aa64_isrm.h | 10 + .../arch/aarch64/includes/asm/aa64_mmu.h | 2 +- lunaix-os/arch/aarch64/includes/asm/soc/gic.h | 204 +++++ lunaix-os/arch/aarch64/soc/gic.c | 701 ++++++++++++++++++ lunaix-os/includes/hal/devtree.h | 26 +- lunaix-os/includes/lunaix/bits.h | 11 +- lunaix-os/includes/lunaix/compiler.h | 8 + lunaix-os/includes/lunaix/device_num.h | 1 + lunaix-os/includes/lunaix/ds/bitmap.h | 147 ++++ 10 files changed, 1187 insertions(+), 8 deletions(-) create mode 100644 lunaix-os/arch/aarch64/includes/asm/aa64_gic.h create mode 100644 lunaix-os/arch/aarch64/includes/asm/aa64_isrm.h create mode 100644 lunaix-os/arch/aarch64/includes/asm/soc/gic.h create mode 100644 lunaix-os/arch/aarch64/soc/gic.c create mode 100644 lunaix-os/includes/lunaix/ds/bitmap.h diff --git a/lunaix-os/arch/aarch64/includes/asm/aa64_gic.h b/lunaix-os/arch/aarch64/includes/asm/aa64_gic.h new file mode 100644 index 0000000..ea9f691 --- /dev/null +++ b/lunaix-os/arch/aarch64/includes/asm/aa64_gic.h @@ -0,0 +1,85 @@ +#ifndef __LUNAIX_AA64_GIC_H +#define __LUNAIX_AA64_GIC_H + +#include +#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 */ diff --git a/lunaix-os/arch/aarch64/includes/asm/aa64_isrm.h b/lunaix-os/arch/aarch64/includes/asm/aa64_isrm.h new file mode 100644 index 0000000..2ab1367 --- /dev/null +++ b/lunaix-os/arch/aarch64/includes/asm/aa64_isrm.h @@ -0,0 +1,10 @@ +#ifndef __LUNAIX_AA64_ISRM_H +#define __LUNAIX_AA64_ISRM_H + +#include +#include "soc/gic.h" + +unsigned int +aa64_isrm_ivalloc(struct gic_int_param* ivcfg, isr_cb handler); + +#endif /* __LUNAIX_AA64_ISRM_H */ diff --git a/lunaix-os/arch/aarch64/includes/asm/aa64_mmu.h b/lunaix-os/arch/aarch64/includes/asm/aa64_mmu.h index 25885cf..9f5c914 100644 --- a/lunaix-os/arch/aarch64/includes/asm/aa64_mmu.h +++ b/lunaix-os/arch/aarch64/includes/asm/aa64_mmu.h @@ -33,7 +33,7 @@ #define TCR_G16K (0b10) #define TCR_G64K (0b11) -#define TCR_SHNS (0b01) +#define TCR_SHNS (0b00) #define TCR_SHOS (0b10) #define TCR_SHIS (0b11) diff --git a/lunaix-os/arch/aarch64/includes/asm/soc/gic.h b/lunaix-os/arch/aarch64/includes/asm/soc/gic.h new file mode 100644 index 0000000..35b9dc5 --- /dev/null +++ b/lunaix-os/arch/aarch64/includes/asm/soc/gic.h @@ -0,0 +1,204 @@ +#ifndef __LUNAIX_GIC_H +#define __LUNAIX_GIC_H + +#include +#include +#include +#include +#include + +#define NR_CPU 1 +#define gic_bmp PREP_BITMAP(gicreg_t, gic_intr, BMP_ORIENT_LSB) + +#define INITID_SGI_BASE 0 +#define INITID_SGI_END 15 + +#define INITID_PPI_BASE 16 +#define INITID_PPI_END 31 + +#define INITID_SPI_BASE 32 +#define INITID_SPI_END 1019 + +#define INITID_SPEC_BASE 1020 +#define INITID_SPEC_END 1023 + +#define INITID_ePPI_BASE 1056 +#define INITID_ePPI_END 1119 + +#define INITID_eSPI_BASE 4096 +#define INITID_eSPI_END 5119 + +#define INITID_LPI_BASE 8192 + +#define INITID_SPI_NR (INITID_SPEC_BASE - INITID_SPI_BASE) + +enum gic_int_type +{ + GIC_IDL, + GIC_LPI, + GIC_SPI, + GIC_PPI, + GIC_SGI, + GIC_RSV +} compact; + +enum gic_tri_type +{ + GIC_TRIG_EDGE, + GIC_TRIG_LEVEL +} compact; + +enum gic_grp_type +{ + GIC_G0, + GIC_G1S, + GIC_G1NS +} compact; + +DECLARE_BITMAP(gic_bmp); + +struct gic_int_param +{ + enum gic_int_type class; + enum gic_tri_type trigger; + enum gic_grp_type group; + unsigned int priority; + int cpu_id; + bool as_nmi; + bool ext_range; +}; + +struct gic_intcfg { + enum gic_int_type class; + enum gic_tri_type trigger; + enum gic_grp_type group; + bool as_nmi; +}; + +struct gic_idomain +{ + DECLARE_HASHTABLE(recs, 32); + BITMAP(gic_bmp) ivmap; + unsigned int base; + bool extended; +}; + +struct gic_interrupt +{ + struct hlist_node node; + + struct gic_idomain* domain; + + unsigned int intid; + struct gic_intcfg config; + + isr_cb handler; + void* payload; +}; + +struct gic_distributor +{ + BITMAP(gic_bmp) group; + BITMAP(gic_bmp) grpmod; + BITMAP(gic_bmp) enable; + BITMAP(gic_bmp) disable; + BITMAP(gic_bmp) icfg; + BITMAP(gic_bmp) nmi; +}; + +struct gic_rd +{ + gicreg_t base[FRAME_LEN]; + gicreg_t sgi_base[FRAME_LEN]; +} compact align(4); + +struct gic_cpuif +{ + gicreg_t base[FRAME_LEN]; +} compact align(4); + +#define gic_reg64(base, index) (*(gicreg64_t*)(&base[index])) +#define gic_regptr(base, index) (__ptr(&base[index])) + +struct gic_pe +{ + struct gic_interrupt* active; + reg_t iar_val; + unsigned int priority; + + struct gic_rd* _rd; + struct gic_cpuif* _if; + + struct gic_distributor rdist; + + struct { + struct gic_idomain* local_ints; + struct gic_idomain* eppi; + } idomain; + + struct { + unsigned int affinity; + unsigned int ppi_nr; + bool eppi_ready; + }; +}; + +struct gic_its +{ + gicreg_t base[FRAME_LEN]; // control regs + gicreg_t trn_space[FRAME_LEN]; // translation space +} compact align(4); + +struct gic_its_v41 +{ + gicreg_t base[FRAME_LEN]; // control regs + gicreg_t trn_space[FRAME_LEN]; // translation space + gicreg_t vsgi_space[FRAME_LEN]; // vSGI space (v4.1+) +} compact align(4); + +typedef unsigned char lpi_entry_t; + +struct arm_gic +{ + unsigned int max_intid; + struct gic_pe pes[NR_CPU]; + + struct { + unsigned int lpi_nr; + unsigned int spi_nr; + unsigned int espi_nr; + bool lpi_ready; + bool nmi_ready; + bool has_espi; + bool msi_via_spi; + }; + + struct { + gicreg_t* dist_base; + union { + struct gic_its* its; + struct gic_its_v41* its_v41; + }; + } mmrs; + + struct { + union { + ptr_t prop; + lpi_entry_t* property; + }; + + ptr_t pend; + BITMAP(gic_bmp) pendings; + } lpi_tables; + + struct gic_distributor dist; + struct gic_distributor dist_e; + + struct { + struct gic_idomain* lpi; + struct gic_idomain* spi; + struct gic_idomain* espi; + } idomain; +}; + +#endif /* __LUNAIX_GIC_H */ diff --git a/lunaix-os/arch/aarch64/soc/gic.c b/lunaix-os/arch/aarch64/soc/gic.c new file mode 100644 index 0000000..ce666ea --- /dev/null +++ b/lunaix-os/arch/aarch64/soc/gic.c @@ -0,0 +1,701 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +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 diff --git a/lunaix-os/includes/hal/devtree.h b/lunaix-os/includes/hal/devtree.h index 3a92116..0a132da 100644 --- a/lunaix-os/includes/hal/devtree.h +++ b/lunaix-os/includes/hal/devtree.h @@ -319,11 +319,11 @@ dt_decode(struct dt_prop_iter* dtpi, struct dt_node_base* node, } #define dt_decode_reg(dtpi, node, field) \ - dt_decode(dtpi, &(node)->base, (node)->(field), \ + dt_decode(dtpi, &(node)->base, &(node)->field, \ (node)->base.sz_c + (node)->base.addr_c); #define dt_decode_range(dtpi, node, field) \ - dt_decode(dtpi, &(node)->base, (node)->field, \ + dt_decode(dtpi, &(node)->base, &(node)->field, \ (node)->base.sz_c * 2 + (node)->base.addr_c); static inline void @@ -410,12 +410,34 @@ dtprop_reg_addr(struct dt_prop_iter* dtpi) return dtprop_extract(dtpi, 0); } +static inline ptr_t +dtprop_reg_nextaddr(struct dt_prop_iter* dtpi) +{ + ptr_t t; + + t = (ptr_t)dtprop_to_u64(dtprop_reg_addr(dtpi)); + dtprop_next(dtpi); + + return t; +} + static inline dt_enc_t dtprop_reg_len(struct dt_prop_iter* dtpi) { return dtprop_extract(dtpi, dtpi->node->addr_c); } +static inline size_t +dtprop_reg_nextlen(struct dt_prop_iter* dtpi) +{ + size_t t; + + t = (size_t)dtprop_to_u64(dtprop_reg_len(dtpi)); + dtprop_next(dtpi); + + return t; +} + static inline dt_enc_t dtprop_range_childbus(struct dt_prop_iter* dtpi) { diff --git a/lunaix-os/includes/lunaix/bits.h b/lunaix-os/includes/lunaix/bits.h index ddc2800..65a6ef8 100644 --- a/lunaix-os/includes/lunaix/bits.h +++ b/lunaix-os/includes/lunaix/bits.h @@ -4,14 +4,15 @@ #include #include -#define BITFIELD(h, l) (h), (l) +#define BITFIELD(h, l) (h), (l) -#define BIT(p) BITFIELD(p, p) +#define BIT(p) BITFIELD(p, p) +#define BITFLAG(p) (1UL << (p)) -#define BITS_GENMASK(bits) _BITS_GENMASK(bits) +#define BITS_GENMASK(bitfield) _BITS_GENMASK(bitfield) -#define BITS_GET(from, bits) _BITS_EXTRACT(from, bits) +#define BITS_GET(from, bitfield) _BITS_EXTRACT(from, bitfield) -#define BITS_SET(to, bits, val) _BITS_INSERT(to, val, bits) +#define BITS_SET(to, bitfield, val) _BITS_INSERT(to, val, bitfield) #endif /* __LUNAIX_BITS_H */ diff --git a/lunaix-os/includes/lunaix/compiler.h b/lunaix-os/includes/lunaix/compiler.h index f644112..d498f53 100644 --- a/lunaix-os/includes/lunaix/compiler.h +++ b/lunaix-os/includes/lunaix/compiler.h @@ -13,6 +13,7 @@ #define must_emit __attribute__((used)) #define unreachable __builtin_unreachable() #define no_inline __attribute__((noinline)) +#define asmlinkage #define _default weak @@ -35,6 +36,8 @@ #define umul_of(a, b, of) __builtin_umul_overflow(a, b, of) #define umull_of(a, b, of) __builtin_umull_overflow(a, b, of) #define offsetof(f, m) __builtin_offsetof(f, m) +#define select(cond, y, n) __builtin_choose_expr(cond, y, n) +#define is_const(v) __builtin_constant_p(v) #define prefetch_rd(ptr, ll) __builtin_prefetch((ptr), 0, ll) #define prefetch_wr(ptr, ll) __builtin_prefetch((ptr), 1, ll) @@ -61,4 +64,9 @@ spin() unreachable; } +#ifdef CONFIG_ARCH_X86_32 +#undef asmlinkage +#define asmlinkage __attribute__((regparm(0))) +#endif + #endif /* __LUNAIX_COMPILER_H */ diff --git a/lunaix-os/includes/lunaix/device_num.h b/lunaix-os/includes/lunaix/device_num.h index b59c857..6e9f7f9 100644 --- a/lunaix-os/includes/lunaix/device_num.h +++ b/lunaix-os/includes/lunaix/device_num.h @@ -109,6 +109,7 @@ #define DEV_GFXA 12 #define DEV_VGA 13 #define DEV_ACPI 14 +#define DEV_INTC 15 struct devident { diff --git a/lunaix-os/includes/lunaix/ds/bitmap.h b/lunaix-os/includes/lunaix/ds/bitmap.h new file mode 100644 index 0000000..68d98ba --- /dev/null +++ b/lunaix-os/includes/lunaix/ds/bitmap.h @@ -0,0 +1,147 @@ +#ifndef __LUNAIX_BITMAP_H +#define __LUNAIX_BITMAP_H + +#include +#include +#include + +// 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 */ -- 2.27.0