summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcosarara <cosa@cosarara.me>2024-01-09 00:11:43 +0000
committercosarara <cosa@cosarara.me>2024-01-09 00:11:43 +0000
commitc0ca24e0792cbdabbf725a5bbca8c3a40b7acd29 (patch)
tree7d1d6e87e714b6b45cad7a6d8e62c94ba749041f
parente2978c785ad240e254849ff944294e62651414e3 (diff)
detection worksgicvn
-rw-r--r--sys/src/9/arm64/gic.c324
-rw-r--r--sys/src/9/arm64/gicv2.c265
-rw-r--r--sys/src/9/arm64/gicv3.c310
-rw-r--r--sys/src/9/arm64/io.h3
-rw-r--r--sys/src/9/arm64/qemu2
5 files changed, 643 insertions, 261 deletions
diff --git a/sys/src/9/arm64/gic.c b/sys/src/9/arm64/gic.c
index 40a6167db..44a736b1b 100644
--- a/sys/src/9/arm64/gic.c
+++ b/sys/src/9/arm64/gic.c
@@ -10,113 +10,13 @@
#include "../port/error.h"
enum {
- GICD_CTLR = 0x000/4, /* RW, Distributor Control Register */
- GICD_TYPER = 0x004/4, /* RO, Interrupt Controller Type */
- GICD_IIDR = 0x008/4, /* RO, Distributor Implementer Identification Register */
-
- GICD_IGROUPR0 = 0x080/4, /* RW, Interrupt Group Registers (0x80-0xBC) */
-
- GICD_ISENABLER0 = 0x100/4, /* RW, Interrupt Set-Enable Registers (0x100-0x13C) */
- GICD_ICENABLER0 = 0x180/4, /* RW, Interrupt Clear-Enable Registers (0x180-0x1BC) */
-
- GICD_ISPENDR0 = 0x200/4, /* RW, Interrupt Set-Pending Registers (0x200-0x23C) */
- GICD_ICPENDR0 = 0x280/4, /* RW, Interrupt Clear-Pending Registers (0x280-0x2BC) */
-
- GICD_ISACTIVER0 = 0x300/4, /* RW, Interrupt Set-Active Registers (0x300-0x33C) */
- GICD_ICACTIVER0 = 0x380/4, /* RW, Interrupt Clear-Active Registers (0x380-0x3BC) */
-
- GICD_IPRIORITYR0= 0x400/4, /* RW, Interrupt Priority Registers (0x400-0x5FC) */
- GICD_TARGETSR0 = 0x800/4, /* RW, Interrupt Target Registers (0x800-0x9FC) */
- GICD_ICFGR0 = 0xC00/4, /* RW, Interrupt Configuration Registers (0xC00-0xC7C) */
-
- GICD_ISR0 = 0xD00/4,
- GICD_PPISR = GICD_ISR0, /* RO, Private Peripheral Interrupt Status Register */
- GICD_SPISR0 = GICD_ISR0+1, /* RO, Shared Peripheral Interrupt Status Register */
- GICD_SGIR = 0xF00/4, /* WO, Software Generated Interrupt Register */
-
- GICD_CPENDSGIR0 = 0xF10/4, /* RW, SGI Clear-Pending Registers (0xF10-0xF1C) */
- GICD_SPENDSGIR0 = 0xF20/4, /* RW, SGI Set-Pending Registers (0xF20-0xF2C) */
-
- GICD_PIDR4 = 0xFD0/4, /* RO, Perpheral ID Registers */
- GICD_PIDR5 = 0xFD4/4,
- GICD_PIDR6 = 0xFD8/4,
- GICD_PIDR7 = 0xFDC/4,
- GICD_PIDR0 = 0xFE0/4,
- GICD_PIDR1 = 0xFE4/4,
- GICD_PIDR2 = 0xFE8/4,
- GICD_PIDR3 = 0xFEC/4,
-
- GICD_CIDR0 = 0xFF0/4, /* RO, Component ID Registers */
- GICD_CIDR1 = 0xFF4/4,
- GICD_CIDR2 = 0xFF8/4,
- GICD_CIDR3 = 0xFFC/4,
-
- RD_base = 0x00000,
- GICR_CTLR = (RD_base+0x000)/4,
- GICR_IIDR = (RD_base+0x004)/4,
- GICR_TYPER = (RD_base+0x008)/4,
- GICR_STATUSR = (RD_base+0x010)/4,
- GICR_WAKER = (RD_base+0x014)/4,
- GICR_SETLPIR = (RD_base+0x040)/4,
- GICR_CLRLPIR = (RD_base+0x048)/4,
- GICR_PROPBASER = (RD_base+0x070)/4,
- GICR_PENDBASER = (RD_base+0x078)/4,
- GICR_INVLPIR = (RD_base+0x0A0)/4,
- GICR_INVALLR = (RD_base+0x0B0)/4,
- GICR_SYNCR = (RD_base+0x0C0)/4,
-
- SGI_base = 0x10000,
- GICR_IGROUPR0 = (SGI_base+0x080)/4,
- GICR_ISENABLER0 = (SGI_base+0x100)/4,
- GICR_ICENABLER0 = (SGI_base+0x180)/4,
- GICR_ISPENDR0 = (SGI_base+0x200)/4,
- GICR_ICPENDR0 = (SGI_base+0x280)/4,
- GICR_ISACTIVER0 = (SGI_base+0x300)/4,
- GICR_ICACTIVER0 = (SGI_base+0x380)/4,
- GICR_IPRIORITYR0= (SGI_base+0x400)/4,
- GICR_ICFGR0 = (SGI_base+0xC00)/4,
- GICR_ICFGR1 = (SGI_base+0xC04)/4,
- GICR_IGRPMODR0 = (SGI_base+0xD00)/4,
- GICR_NSACR = (SGI_base+0xE00)/4,
-};
-
-typedef struct Vctl Vctl;
-struct Vctl {
- Vctl *next;
- void (*f)(Ureg*, void*);
- void *a;
- int irq;
- u32int intid;
+ GICD_CTLR = 0,
+ GICD_PIDR2_v2 = 0xFE8/4,
+ GICD_PIDR2_v3 = 0xFFE8/4,
};
-static Lock vctllock;
-static Vctl *vctl[MAXMACH][32], *vfiq;
-static u32int *dregs = (u32int*)VIRTIO;
-
-static u32int*
-getrregs(int machno)
-{
- u32int *rregs = (u32int*)(VIRTIO + 0xa0000);
-
- for(;;){
- if((rregs[GICR_TYPER] & 0xFFFF00) == (machno << 8))
- return rregs;
- if(rregs[GICR_TYPER] & (1<<4))
- break;
- rregs += (0x20000/4);
- }
- panic("getrregs: no re-distributor for cpu %d\n", machno);
- return nil;
-}
-
-void
-intrcpushutdown(void)
-{
- /* disable cpu interface */
- syswr(ICC_IGRPEN0_EL1, 0);
- syswr(ICC_IGRPEN1_EL1, 0);
- coherence();
-}
+static int gic_version = 0;
+static u32int *dregs = (u32int*)DREGS;
void
intrsoff(void)
@@ -128,193 +28,97 @@ intrsoff(void)
;
}
+void intrcpushutdown2(void);
+void intrcpushutdown3(void);
void
-intrinit(void)
+intrcpushutdown(void)
{
- u32int *rregs;
- int i, n;
- if(m->machno == 0){
- intrsoff();
-
- /* clear all interrupts */
- n = ((dregs[GICD_TYPER] & 0x1F)+1) << 5;
- for(i = 32; i < n; i += 32){
- dregs[GICD_IGROUPR0 + (i/32)] = -1;
-
- dregs[GICD_ISENABLER0 + (i/32)] = -1;
- while(dregs[GICD_CTLR]&(1<<31))
- ;
- dregs[GICD_ICENABLER0 + (i/32)] = -1;
- while(dregs[GICD_CTLR]&(1<<31))
- ;
- dregs[GICD_ICACTIVER0 + (i/32)] = -1;
+ if (gic_version == 0) {
+ print("going to read the stupid version\n");
+ gic_version = (dregs[GICD_PIDR2_v2] & 0xF0) >> 4;
+ if (gic_version != 2) {
+ gic_version = (dregs[GICD_PIDR2_v3] & 0xF0) >> 4;
}
- for(i = 0; i < n; i += 4){
- dregs[GICD_IPRIORITYR0 + (i/4)] = 0;
- dregs[GICD_TARGETSR0 + (i/4)] = 0;
+ print("detected GIC version %d\n", gic_version);
+ if (gic_version == 4) {
+ gic_version = 3; // 4 is compatible with 3
}
- for(i = 32; i < n; i += 16){
- dregs[GICD_ICFGR0 + (i/16)] = 0;
- }
- coherence();
- while(dregs[GICD_CTLR]&(1<<31))
- ;
- dregs[GICD_CTLR] = (1<<0) | (1<<1) | (1<<4);
}
- rregs = getrregs(m->machno);
- n = 32;
- for(i = 0; i < n; i += 32){
- rregs[GICR_IGROUPR0 + (i/32)] = -1;
-
- rregs[GICR_ISENABLER0 + (i/32)] = -1;
- while(rregs[GICR_CTLR]&(1<<3))
- ;
- rregs[GICR_ICENABLER0 + (i/32)] = -1;
- while(dregs[GICD_CTLR]&(1<<31))
- ;
- rregs[GICR_ICACTIVER0 + (i/32)] = -1;
+ //gic_version = 2;
+ if (gic_version == 3) {
+ intrcpushutdown3();
+ return;
}
- for(i = 0; i < n; i += 4){
- rregs[GICR_IPRIORITYR0 + (i/4)] = 0;
+ if (gic_version == 2) {
+ intrcpushutdown2();
+ return;
}
- coherence();
- while(rregs[GICR_CTLR]&(1<<3))
- ;
-
- coherence();
+ panic("unsupported gic version %d\n", gic_version);
+}
- /* enable cpu interface */
- syswr(ICC_CTLR_EL1, 0);
- syswr(ICC_BPR1_EL1, 7);
- syswr(ICC_PMR_EL1, 0xFF);
+void intrinit2(void);
+void intrinit3(void);
- coherence();
+void
+intrinit(void)
+{
+ if (gic_version == 3) {
+ intrinit3();
+ } else {
+ intrinit2();
+ }
}
+int irq2(Ureg*);
+int irq3(Ureg*);
-/*
- * called by trap to handle irq interrupts.
- * returns true iff a clock interrupt, thus maybe reschedule.
- */
int
irq(Ureg* ureg)
{
- Vctl *v;
- int clockintr;
- u32int intid;
-
- m->intr++;
- intid = sysrd(ICC_IAR1_EL1) & 0xFFFFFF;
-// iprint("i<%d>", intid);
- if((intid & ~3) == 1020)
- return 0; // spurious
- clockintr = 0;
- for(v = vctl[m->machno][intid%32]; v != nil; v = v->next)
- if(v->intid == intid){
- coherence();
- v->f(ureg, v->a);
- coherence();
- if(v->irq == IRQcntvns)
- clockintr = 1;
- }
- coherence();
- syswr(ICC_EOIR1_EL1, intid);
- return clockintr;
+ if (gic_version == 3) {
+ return irq3(ureg);
+ } else {
+ return irq2(ureg);
+ }
}
-/*
- * called direct from lexception.s to handle fiq interrupt.
- */
+void fiq2(Ureg*);
+void fiq3(Ureg*);
+
void
fiq(Ureg *ureg)
{
- Vctl *v;
- u32int intid;
-
- m->intr++;
- intid = sysrd(ICC_IAR1_EL1) & 0xFFFFFF;
-// iprint("f<%d>", intid);
- if((intid & ~3) == 1020)
- return; // spurious
- v = vfiq;
- if(v != nil && v->intid == intid && m->machno == 0){
- coherence();
- v->f(ureg, v->a);
- coherence();
+ if (gic_version == 3) {
+ fiq3(ureg);
+ } else {
+ fiq2(ureg);
}
- syswr(ICC_EOIR1_EL1, intid);
}
+void intrenable2(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *c);
+void intrenable3(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *c);
+
void
-intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *)
+intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *c)
{
- Vctl *v;
- u32int intid;
- int cpu, prio;
-
- if(BUSTYPE(tbdf) == BusPCI){
- pciintrenable(tbdf, f, a);
- return;
- }
-
- if(tbdf != BUSUNKNOWN)
- return;
-
- prio = 0x80;
- intid = irq;
- if((v = xalloc(sizeof(Vctl))) == nil)
- panic("intrenable: no mem");
- v->irq = irq;
- v->intid = intid;
- v->f = f;
- v->a = a;
-
- lock(&vctllock);
- if(intid < SPI)
- cpu = m->machno;
- else
- cpu = 0;
- if(irq == IRQfiq){
- vfiq = v;
- prio = 0;
- }else{
- v->next = vctl[cpu][intid%32];
- vctl[cpu][intid%32] = v;
- }
- syswr(ICC_IGRPEN1_EL1, sysrd(ICC_IGRPEN1_EL1)|1);
- coherence();
-
- syswr(ICC_EOIR1_EL1, intid);
- coherence();
-
- /* setup */
- if(intid < 32){
- u32int *rregs = getrregs(cpu);
- rregs[GICR_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
- coherence();
- rregs[GICR_ISENABLER0] = 1 << (intid%32);
- coherence();
- while(rregs[GICR_CTLR]&(1<<3))
- ;
+ if (gic_version == 3) {
+ intrenable3(irq, f, a, tbdf, c);
} else {
- dregs[GICD_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
- dregs[GICD_TARGETSR0 + (intid/4)] |= (1<<cpu) << ((intid%4) << 3);
- coherence();
- dregs[GICD_ISENABLER0 + (intid/32)] = 1 << (intid%32);
- coherence();
- while(dregs[GICD_CTLR]&(1<<31))
- ;
+ intrenable2(irq, f, a, tbdf, c);
}
- unlock(&vctllock);
}
+void intrdisable2(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *c);
+void intrdisable3(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *c);
+
void
-intrdisable(int, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
+intrdisable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *c)
{
- if(BUSTYPE(tbdf) == BusPCI){
- pciintrdisable(tbdf, f, a);
- return;
+ if (gic_version == 3) {
+ intrdisable3(irq, f, a, tbdf, c);
+ } else {
+ intrdisable2(irq, f, a, tbdf, c);
}
}
diff --git a/sys/src/9/arm64/gicv2.c b/sys/src/9/arm64/gicv2.c
new file mode 100644
index 000000000..9466ef042
--- /dev/null
+++ b/sys/src/9/arm64/gicv2.c
@@ -0,0 +1,265 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+#include "ureg.h"
+#include "sysreg.h"
+#include "../port/error.h"
+
+enum {
+ GICD_CTLR = 0x000/4, /* RW, Distributor Control Register */
+ GICD_TYPER = 0x004/4, /* RO, Interrupt Controller Type */
+ GICD_IIDR = 0x008/4, /* RO, Distributor Implementer Identification Register */
+
+ GICD_IGROUPR0 = 0x080/4, /* RW, Interrupt Group Registers (0x80-0xBC) */
+
+ GICD_ISENABLER0 = 0x100/4, /* RW, Interrupt Set-Enable Registers (0x100-0x13C) */
+ GICD_ICENABLER0 = 0x180/4, /* RW, Interrupt Clear-Enable Registers (0x180-0x1BC) */
+
+ GICD_ISPENDR0 = 0x200/4, /* RW, Interrupt Set-Pending Registers (0x200-0x23C) */
+ GICD_ICPENDR0 = 0x280/4, /* RW, Interrupt Clear-Pending Registers (0x280-0x2BC) */
+
+ GICD_ISACTIVER0 = 0x300/4, /* RW, Interrupt Set-Active Registers (0x300-0x33C) */
+ GICD_ICACTIVER0 = 0x380/4, /* RW, Interrupt Clear-Active Registers (0x380-0x3BC) */
+
+ GICD_IPRIORITYR0= 0x400/4, /* RW, Interrupt Priority Registers (0x400-0x5FC) */
+ GICD_TARGETSR0 = 0x800/4, /* RW, Interrupt Target Registers (0x800-0x9FC) */
+ GICD_ICFGR0 = 0xC00/4, /* RW, Interrupt Configuration Registers (0xC00-0xC7C) */
+
+ GICD_ISR0 = 0xD00/4,
+ GICD_PPISR = GICD_ISR0, /* RO, Private Peripheral Interrupt Status Register */
+ GICD_SPISR0 = GICD_ISR0+1, /* RO, Shared Peripheral Interrupt Status Register */
+ GICD_SGIR = 0xF00/4, /* WO, Software Generated Interrupt Register */
+
+ GICD_CPENDSGIR0 = 0xF10/4, /* RW, SGI Clear-Pending Registers (0xF10-0xF1C) */
+ GICD_SPENDSGIR0 = 0xF20/4, /* RW, SGI Set-Pending Registers (0xF20-0xF2C) */
+
+ GICD_PIDR4 = 0xFD0/4, /* RO, Perpheral ID Registers */
+ GICD_PIDR5 = 0xFD4/4,
+ GICD_PIDR6 = 0xFD8/4,
+ GICD_PIDR7 = 0xFDC/4,
+ GICD_PIDR0 = 0xFE0/4,
+ GICD_PIDR1 = 0xFE4/4,
+ GICD_PIDR2 = 0xFE8/4,
+ GICD_PIDR3 = 0xFEC/4,
+
+ GICD_CIDR0 = 0xFF0/4, /* RO, Component ID Registers */
+ GICD_CIDR1 = 0xFF4/4,
+ GICD_CIDR2 = 0xFF8/4,
+ GICD_CIDR3 = 0xFFC/4,
+
+ GICC_CTLR = 0x000/4, /* RW, CPU Interace Control Register */
+ GICC_PMR = 0x004/4, /* RW, Interrupt Priority Mask Register */
+ GICC_BPR = 0x008/4, /* RW, Binary Point Register */
+ GICC_IAR = 0x00C/4, /* RO, Interrupt Acknowledge Register */
+ GICC_EOIR = 0x010/4, /* WO, End of Interrupt Register */
+ GICC_RPR = 0x014/4, /* RO, Running Priority Register */
+ GICC_HPPIR = 0x018/4, /* RO, Highest Priority Pending Interrupt Register */
+ GICC_ABPR = 0x01C/4, /* RW, Aliased Binary Point Register */
+ GICC_AIAR = 0x020/4, /* RO, Aliased Interrupt Acknowledge Register */
+ GICC_AEOIR = 0x024/4, /* WO, Aliased End of Interrupt Register */
+ GICC_AHPPIR = 0x028/4, /* RO, Aliased Highest Priority Pending Interrupt Register */
+ GICC_APR0 = 0x0D0/4, /* RW, Active Priority Register */
+ GICC_NSAPR0 = 0x0E0/4, /* RW, Non-Secure Active Priority Register */
+ GICC_IIDR = 0x0FC/4, /* RO, CPU Interface Identification Register */
+ GICC_DIR = 0x1000/4, /* WO, Deactivate Interrupt Register */
+
+ GICH_HCR = 0x000/4, /* RW, Hypervisor Control Register */
+ GICH_VTR = 0x004/4, /* RO, VGIC Type Register */
+ GICH_VMCR = 0x008/4, /* RW, Virtual Machine Control Register */
+ GICH_MISR = 0x010/4, /* RO, Maintenance Interrupt Status Register */
+ GICH_EISR0 = 0x020/4, /* RO, End of Interrupt Status Register */
+ GICH_ELSR0 = 0x030/4, /* RO, Empty List Register Status Register */
+ GICH_APR0 = 0x0F0/4, /* RW, Active Priority Register */
+ GICH_LR0 = 0x100/4, /* RW, List Registers (0x100-0x10C) */
+
+ GICV_CTLR = 0x000/4, /* RW, Virtual Machine Control Register */
+ GICV_PMR = 0x004/4, /* RW, VM Priority Mask Register */
+ GICV_BPR = 0x008/4, /* RW, VM Binary Point Register */
+ GICV_IAR = 0x00C/4, /* RO, VM Interrupt Acknowledge Register */
+ GICV_EOIR = 0x010/4, /* WO, VM End of Interrupt Register */
+ GICV_RPR = 0x014/4, /* RO, VM Running Priority Register */
+ GICV_HPPIR = 0x018/4, /* RO, VM Highest Piority Pending Interrupt Register */
+ GICV_ABPR = 0x01C/4, /* RW, VM Aliased Binary Point Register */
+ GICV_AIAR = 0x020/4, /* RO, VM Aliased Interrupt Acknowledge Register */
+ GICV_AEOIR = 0x024/4, /* WO, VM Aliased End of Interrupt Register */
+ GICV_AHPPIR = 0x028/4, /* RO, VM Aliaed Highest Piority Pending Interrupt Register */
+ GICV_APR0 = 0x0D0/4, /* RW, VM Active Priority Register */
+ GICV_IIDR = 0x0FC/4, /* RO, VM CPU Interface Identification Register */
+ GICV_DIR = 0x1000/4, /* WO, VM Deactivate Interrupt Register */
+};
+
+typedef struct Vctl Vctl;
+struct Vctl {
+ Vctl *next;
+ void (*f)(Ureg*, void*);
+ void *a;
+ int irq;
+ u32int intid;
+};
+
+static Lock vctllock;
+static Vctl *vctl[MAXMACH][32], *vfiq;
+static u32int *dregs = (u32int*)DREGS;
+static u32int *cregs = (u32int*)CREGS;
+
+void
+intrcpushutdown2(void)
+{
+ /* disable cpu interface */
+ cregs[GICC_CTLR] &= ~1;
+ coherence();
+}
+
+void
+intrinit2(void)
+{
+ int i, n;
+
+ if(m->machno == 0){
+ intrsoff();
+
+ /* clear all interrupts */
+ n = ((dregs[GICD_TYPER] & 0x1F)+1) << 5;
+ for(i = 0; i < n; i += 32){
+ dregs[GICD_ISENABLER0 + (i/32)] = -1;
+ coherence();
+ dregs[GICD_ICENABLER0 + (i/32)] = -1;
+ coherence();
+ }
+ for(i = 0; i < n; i += 4){
+ dregs[GICD_IPRIORITYR0 + (i/4)] = 0;
+ dregs[GICD_TARGETSR0 + (i/4)] = 0;
+ }
+ for(i = 32; i < n; i += 16)
+ dregs[GICD_ICFGR0 + (i/16)] = 0;
+ coherence();
+ }
+}
+
+
+/*
+ * called by trap to handle irq interrupts.
+ * returns true iff a clock interrupt, thus maybe reschedule.
+ */
+int
+irq2(Ureg* ureg)
+{
+ Vctl *v;
+ int clockintr;
+ u32int intid;
+
+ m->intr++;
+ intid = cregs[GICC_IAR] & 0xFFFFFF;
+ if((intid & ~3) == 1020)
+ return 0; // spurious
+ clockintr = 0;
+ for(v = vctl[m->machno][intid%32]; v != nil; v = v->next)
+ if(v->intid == intid){
+ coherence();
+ v->f(ureg, v->a);
+ coherence();
+ if(v->irq == IRQcntvns)
+ clockintr = 1;
+ }
+ coherence();
+ cregs[GICC_EOIR] = intid;
+ return clockintr;
+}
+
+/*
+ * called direct from lexception.s to handle fiq interrupt.
+ */
+void
+fiq2(Ureg *ureg)
+{
+ Vctl *v;
+ u32int intid;
+
+ m->intr++;
+ intid = cregs[GICC_IAR] & 0xFFFFFF;
+ if((intid & ~3) == 1020)
+ return; // spurious
+ v = vfiq;
+ if(v != nil && v->intid == intid && m->machno == 0){
+ coherence();
+ v->f(ureg, v->a);
+ coherence();
+ }
+ cregs[GICC_EOIR] = intid;
+}
+
+void
+intrenable2(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
+{
+ Vctl *v;
+ u32int intid;
+ int cpu, prio;
+
+ if(BUSTYPE(tbdf) == BusPCI){
+ pciintrenable(tbdf, f, a);
+ return;
+ }
+
+ if(tbdf != BUSUNKNOWN)
+ return;
+
+ prio = 0x80;
+ intid = irq;
+
+ if((v = xalloc(sizeof(Vctl))) == nil)
+ panic("intrenable: no mem");
+ v->irq = irq;
+ v->intid = intid;
+ v->f = f;
+ v->a = a;
+
+ lock(&vctllock);
+ if(intid < SPI)
+ cpu = m->machno;
+ else
+ cpu = 0;
+ if(irq == IRQfiq){
+ vfiq = v;
+ prio = 0;
+ }else{
+ v->next = vctl[cpu][intid%32];
+ vctl[cpu][intid%32] = v;
+ }
+
+ /* enable cpu interface */
+ cregs[GICC_PMR] = 0xFF;
+ coherence();
+
+ cregs[GICC_CTLR] |= 1;
+ coherence();
+
+ cregs[GICC_EOIR] = intid;
+
+ /* enable distributor */
+ dregs[GICD_CTLR] |= 1;
+ coherence();
+
+ /* setup */
+ dregs[GICD_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
+ dregs[GICD_TARGETSR0 + (intid/4)] |= (1<<cpu) << ((intid%4) << 3);
+ coherence();
+
+ /* turn on */
+ dregs[GICD_ISENABLER0 + (intid/32)] = 1 << (intid%32);
+ coherence();
+
+ unlock(&vctllock);
+}
+
+void
+intrdisable2(int, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
+{
+ if(BUSTYPE(tbdf) == BusPCI){
+ pciintrdisable(tbdf, f, a);
+ return;
+ }
+}
diff --git a/sys/src/9/arm64/gicv3.c b/sys/src/9/arm64/gicv3.c
new file mode 100644
index 000000000..d26a15b86
--- /dev/null
+++ b/sys/src/9/arm64/gicv3.c
@@ -0,0 +1,310 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+#include "ureg.h"
+#include "sysreg.h"
+#include "../port/error.h"
+
+enum {
+ GICD_CTLR = 0x000/4, /* RW, Distributor Control Register */
+ GICD_TYPER = 0x004/4, /* RO, Interrupt Controller Type */
+ GICD_IIDR = 0x008/4, /* RO, Distributor Implementer Identification Register */
+
+ GICD_IGROUPR0 = 0x080/4, /* RW, Interrupt Group Registers (0x80-0xBC) */
+
+ GICD_ISENABLER0 = 0x100/4, /* RW, Interrupt Set-Enable Registers (0x100-0x13C) */
+ GICD_ICENABLER0 = 0x180/4, /* RW, Interrupt Clear-Enable Registers (0x180-0x1BC) */
+
+ GICD_ISPENDR0 = 0x200/4, /* RW, Interrupt Set-Pending Registers (0x200-0x23C) */
+ GICD_ICPENDR0 = 0x280/4, /* RW, Interrupt Clear-Pending Registers (0x280-0x2BC) */
+
+ GICD_ISACTIVER0 = 0x300/4, /* RW, Interrupt Set-Active Registers (0x300-0x33C) */
+ GICD_ICACTIVER0 = 0x380/4, /* RW, Interrupt Clear-Active Registers (0x380-0x3BC) */
+
+ GICD_IPRIORITYR0= 0x400/4, /* RW, Interrupt Priority Registers (0x400-0x5FC) */
+ GICD_TARGETSR0 = 0x800/4, /* RW, Interrupt Target Registers (0x800-0x9FC) */
+ GICD_ICFGR0 = 0xC00/4, /* RW, Interrupt Configuration Registers (0xC00-0xC7C) */
+
+ GICD_ISR0 = 0xD00/4,
+ GICD_PPISR = GICD_ISR0, /* RO, Private Peripheral Interrupt Status Register */
+ GICD_SPISR0 = GICD_ISR0+1, /* RO, Shared Peripheral Interrupt Status Register */
+ GICD_SGIR = 0xF00/4, /* WO, Software Generated Interrupt Register */
+
+ GICD_CPENDSGIR0 = 0xF10/4, /* RW, SGI Clear-Pending Registers (0xF10-0xF1C) */
+ GICD_SPENDSGIR0 = 0xF20/4, /* RW, SGI Set-Pending Registers (0xF20-0xF2C) */
+
+ GICD_PIDR4 = 0xFD0/4, /* RO, Perpheral ID Registers */
+ GICD_PIDR5 = 0xFD4/4,
+ GICD_PIDR6 = 0xFD8/4,
+ GICD_PIDR7 = 0xFDC/4,
+ GICD_PIDR0 = 0xFE0/4,
+ GICD_PIDR1 = 0xFE4/4,
+ GICD_PIDR2 = 0xFE8/4,
+ GICD_PIDR3 = 0xFEC/4,
+
+ GICD_CIDR0 = 0xFF0/4, /* RO, Component ID Registers */
+ GICD_CIDR1 = 0xFF4/4,
+ GICD_CIDR2 = 0xFF8/4,
+ GICD_CIDR3 = 0xFFC/4,
+
+ RD_base = 0x00000,
+ GICR_CTLR = (RD_base+0x000)/4,
+ GICR_IIDR = (RD_base+0x004)/4,
+ GICR_TYPER = (RD_base+0x008)/4,
+ GICR_STATUSR = (RD_base+0x010)/4,
+ GICR_WAKER = (RD_base+0x014)/4,
+ GICR_SETLPIR = (RD_base+0x040)/4,
+ GICR_CLRLPIR = (RD_base+0x048)/4,
+ GICR_PROPBASER = (RD_base+0x070)/4,
+ GICR_PENDBASER = (RD_base+0x078)/4,
+ GICR_INVLPIR = (RD_base+0x0A0)/4,
+ GICR_INVALLR = (RD_base+0x0B0)/4,
+ GICR_SYNCR = (RD_base+0x0C0)/4,
+
+ SGI_base = 0x10000,
+ GICR_IGROUPR0 = (SGI_base+0x080)/4,
+ GICR_ISENABLER0 = (SGI_base+0x100)/4,
+ GICR_ICENABLER0 = (SGI_base+0x180)/4,
+ GICR_ISPENDR0 = (SGI_base+0x200)/4,
+ GICR_ICPENDR0 = (SGI_base+0x280)/4,
+ GICR_ISACTIVER0 = (SGI_base+0x300)/4,
+ GICR_ICACTIVER0 = (SGI_base+0x380)/4,
+ GICR_IPRIORITYR0= (SGI_base+0x400)/4,
+ GICR_ICFGR0 = (SGI_base+0xC00)/4,
+ GICR_ICFGR1 = (SGI_base+0xC04)/4,
+ GICR_IGRPMODR0 = (SGI_base+0xD00)/4,
+ GICR_NSACR = (SGI_base+0xE00)/4,
+};
+
+typedef struct Vctl Vctl;
+struct Vctl {
+ Vctl *next;
+ void (*f)(Ureg*, void*);
+ void *a;
+ int irq;
+ u32int intid;
+};
+
+static Lock vctllock;
+static Vctl *vctl[MAXMACH][32], *vfiq;
+static u32int *dregs = (u32int*)DREGS;
+
+static u32int*
+getrregs(int machno)
+{
+ u32int *rregs = (u32int*)(VIRTIO + 0xa0000);
+
+ for(;;){
+ if((rregs[GICR_TYPER] & 0xFFFF00) == (machno << 8))
+ return rregs;
+ if(rregs[GICR_TYPER] & (1<<4))
+ break;
+ rregs += (0x20000/4);
+ }
+ panic("getrregs: no re-distributor for cpu %d\n", machno);
+ return nil;
+}
+
+void
+intrcpushutdown3(void)
+{
+ /* disable cpu interface */
+ syswr(ICC_IGRPEN0_EL1, 0);
+ syswr(ICC_IGRPEN1_EL1, 0);
+ coherence();
+}
+
+void
+intrinit3(void)
+{
+ u32int *rregs;
+ int i, n;
+
+ if(m->machno == 0){
+ intrsoff();
+
+ /* clear all interrupts */
+ n = ((dregs[GICD_TYPER] & 0x1F)+1) << 5;
+ for(i = 32; i < n; i += 32){
+ dregs[GICD_IGROUPR0 + (i/32)] = -1;
+
+ dregs[GICD_ISENABLER0 + (i/32)] = -1;
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ dregs[GICD_ICENABLER0 + (i/32)] = -1;
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ dregs[GICD_ICACTIVER0 + (i/32)] = -1;
+ }
+ for(i = 0; i < n; i += 4){
+ dregs[GICD_IPRIORITYR0 + (i/4)] = 0;
+ dregs[GICD_TARGETSR0 + (i/4)] = 0;
+ }
+ for(i = 32; i < n; i += 16){
+ dregs[GICD_ICFGR0 + (i/16)] = 0;
+ }
+ coherence();
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ dregs[GICD_CTLR] = (1<<0) | (1<<1) | (1<<4);
+ }
+
+ rregs = getrregs(m->machno);
+ n = 32;
+ for(i = 0; i < n; i += 32){
+ rregs[GICR_IGROUPR0 + (i/32)] = -1;
+
+ rregs[GICR_ISENABLER0 + (i/32)] = -1;
+ while(rregs[GICR_CTLR]&(1<<3))
+ ;
+ rregs[GICR_ICENABLER0 + (i/32)] = -1;
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ rregs[GICR_ICACTIVER0 + (i/32)] = -1;
+ }
+ for(i = 0; i < n; i += 4){
+ rregs[GICR_IPRIORITYR0 + (i/4)] = 0;
+ }
+ coherence();
+ while(rregs[GICR_CTLR]&(1<<3))
+ ;
+
+ coherence();
+
+ /* enable cpu interface */
+ syswr(ICC_CTLR_EL1, 0);
+ syswr(ICC_BPR1_EL1, 7);
+ syswr(ICC_PMR_EL1, 0xFF);
+
+ coherence();
+}
+
+
+/*
+ * called by trap to handle irq interrupts.
+ * returns true iff a clock interrupt, thus maybe reschedule.
+ */
+int
+irq3(Ureg* ureg)
+{
+ Vctl *v;
+ int clockintr;
+ u32int intid;
+
+ m->intr++;
+ intid = sysrd(ICC_IAR1_EL1) & 0xFFFFFF;
+// iprint("i<%d>", intid);
+ if((intid & ~3) == 1020)
+ return 0; // spurious
+ clockintr = 0;
+ for(v = vctl[m->machno][intid%32]; v != nil; v = v->next)
+ if(v->intid == intid){
+ coherence();
+ v->f(ureg, v->a);
+ coherence();
+ if(v->irq == IRQcntvns)
+ clockintr = 1;
+ }
+ coherence();
+ syswr(ICC_EOIR1_EL1, intid);
+ return clockintr;
+}
+
+/*
+ * called direct from lexception.s to handle fiq interrupt.
+ */
+void
+fiq3(Ureg *ureg)
+{
+ Vctl *v;
+ u32int intid;
+
+ m->intr++;
+ intid = sysrd(ICC_IAR1_EL1) & 0xFFFFFF;
+// iprint("f<%d>", intid);
+ if((intid & ~3) == 1020)
+ return; // spurious
+ v = vfiq;
+ if(v != nil && v->intid == intid && m->machno == 0){
+ coherence();
+ v->f(ureg, v->a);
+ coherence();
+ }
+ syswr(ICC_EOIR1_EL1, intid);
+}
+
+void
+intrenable3(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *)
+{
+ Vctl *v;
+ u32int intid;
+ int cpu, prio;
+
+ if(BUSTYPE(tbdf) == BusPCI){
+ pciintrenable(tbdf, f, a);
+ return;
+ }
+
+ if(tbdf != BUSUNKNOWN)
+ return;
+
+ prio = 0x80;
+ intid = irq;
+ if((v = xalloc(sizeof(Vctl))) == nil)
+ panic("intrenable: no mem");
+ v->irq = irq;
+ v->intid = intid;
+ v->f = f;
+ v->a = a;
+
+ lock(&vctllock);
+ if(intid < SPI)
+ cpu = m->machno;
+ else
+ cpu = 0;
+ if(irq == IRQfiq){
+ vfiq = v;
+ prio = 0;
+ }else{
+ v->next = vctl[cpu][intid%32];
+ vctl[cpu][intid%32] = v;
+ }
+ syswr(ICC_IGRPEN1_EL1, sysrd(ICC_IGRPEN1_EL1)|1);
+ coherence();
+
+ syswr(ICC_EOIR1_EL1, intid);
+ coherence();
+
+ /* setup */
+ if(intid < 32){
+ u32int *rregs = getrregs(cpu);
+ rregs[GICR_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
+ coherence();
+ rregs[GICR_ISENABLER0] = 1 << (intid%32);
+ coherence();
+ while(rregs[GICR_CTLR]&(1<<3))
+ ;
+ } else {
+ dregs[GICD_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
+ dregs[GICD_TARGETSR0 + (intid/4)] |= (1<<cpu) << ((intid%4) << 3);
+ coherence();
+ dregs[GICD_ISENABLER0 + (intid/32)] = 1 << (intid%32);
+ coherence();
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ }
+ unlock(&vctllock);
+}
+
+void
+intrdisable3(int, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
+{
+ if(BUSTYPE(tbdf) == BusPCI){
+ pciintrdisable(tbdf, f, a);
+ return;
+ }
+}
diff --git a/sys/src/9/arm64/io.h b/sys/src/9/arm64/io.h
index 11040915a..0eb5a9ce2 100644
--- a/sys/src/9/arm64/io.h
+++ b/sys/src/9/arm64/io.h
@@ -17,3 +17,6 @@ enum {
#define BUSUNKNOWN (-1)
#define PCIWINDOW 0
#define PCIWADDR(x) (PADDR(x)+PCIWINDOW)
+
+#define DREGS VIRTIO
+#define CREGS (VIRTIO+0x10000)
diff --git a/sys/src/9/arm64/qemu b/sys/src/9/arm64/qemu
index 557a2b288..a8d969dfb 100644
--- a/sys/src/9/arm64/qemu
+++ b/sys/src/9/arm64/qemu
@@ -40,7 +40,7 @@ ip
igmp
ipmux
misc
- gic
+ gic gicv2 gicv3
uartqemu
sdvirtio10 pci sdscsi
port