diff options
author | cosarara <cosa@cosarara.me> | 2024-01-09 00:11:43 +0000 |
---|---|---|
committer | cosarara <cosa@cosarara.me> | 2024-01-09 00:11:43 +0000 |
commit | c0ca24e0792cbdabbf725a5bbca8c3a40b7acd29 (patch) | |
tree | 7d1d6e87e714b6b45cad7a6d8e62c94ba749041f | |
parent | e2978c785ad240e254849ff944294e62651414e3 (diff) |
detection worksgicvn
-rw-r--r-- | sys/src/9/arm64/gic.c | 324 | ||||
-rw-r--r-- | sys/src/9/arm64/gicv2.c | 265 | ||||
-rw-r--r-- | sys/src/9/arm64/gicv3.c | 310 | ||||
-rw-r--r-- | sys/src/9/arm64/io.h | 3 | ||||
-rw-r--r-- | sys/src/9/arm64/qemu | 2 |
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 |