diff options
author | cosarara <cosa@cosarara.me> | 2024-01-07 23:47:00 +0000 |
---|---|---|
committer | cosarara <cosa@cosarara.me> | 2024-01-08 20:27:39 +0100 |
commit | 99f2ecbf6d3aea356c443ed8169659f0874add46 (patch) | |
tree | 2867012ffa26746e1424aac7ab8442280ff155a9 | |
parent | f70cf0b70eb2b9b6cdf7208bf775189c724eb446 (diff) |
GIC driver in the qemu kernel is now GICv2gicv2
This makes it possible to use KVM on GICv2 hosts.
Eg. on a raspberry pi4 linux host:
qemu-system-aarch64 -M virt-2.12,gic-version=2 \
-cpu host -m 2G -smp 2 \
-bios u-boot.bin \
-drive file=9front-10277.arm64.qcow2,if=none,id=disk \
-device virtio-blk-pci-non-transitional,drive=disk \
-nic bridge,br=br0,model=virtio-net-pci-non-transitional \
-nographic -accel kvm
Trying to use gic-version=3 on the same host would give:
qemu-system-aarch64: KVM does not support GICv3 emulation
-rw-r--r-- | sys/src/9/arm64/gic.c | 191 |
1 files changed, 72 insertions, 119 deletions
diff --git a/sys/src/9/arm64/gic.c b/sys/src/9/arm64/gic.c index 291f7e102..4f1b01ced 100644 --- a/sys/src/9/arm64/gic.c +++ b/sys/src/9/arm64/gic.c @@ -51,33 +51,45 @@ enum { 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, + 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; @@ -91,30 +103,14 @@ struct Vctl { 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; -} +static u32int *dregs = (u32int*)(VIRTIO); +static u32int *cregs = (u32int*)(VIRTIO + 0x10000); void intrcpushutdown(void) { /* disable cpu interface */ - syswr(ICC_IGRPEN0_EL1, 0); - syswr(ICC_IGRPEN1_EL1, 0); + cregs[GICC_CTLR] &= ~1; coherence(); } @@ -122,16 +118,13 @@ void intrsoff(void) { /* disable distributor */ - dregs[GICD_CTLR] = 0; + dregs[GICD_CTLR] &= ~1; coherence(); - while(dregs[GICD_CTLR]&(1<<31)) - ; } void intrinit(void) { - u32int *rregs; int i, n; if(m->machno == 0){ @@ -139,58 +132,20 @@ intrinit(void) /* clear all interrupts */ n = ((dregs[GICD_TYPER] & 0x1F)+1) << 5; - for(i = 32; i < n; i += 32){ - dregs[GICD_IGROUPR0 + (i/32)] = -1; - + for(i = 0; i < n; i += 32){ dregs[GICD_ISENABLER0 + (i/32)] = -1; - while(dregs[GICD_CTLR]&(1<<31)) - ; + coherence(); dregs[GICD_ICENABLER0 + (i/32)] = -1; - while(dregs[GICD_CTLR]&(1<<31)) - ; - dregs[GICD_ICACTIVER0 + (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){ + 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(); } @@ -206,8 +161,7 @@ irq(Ureg* ureg) u32int intid; m->intr++; - intid = sysrd(ICC_IAR1_EL1) & 0xFFFFFF; -// iprint("i<%d>", intid); + intid = cregs[GICC_IAR] & 0xFFFFFF; if((intid & ~3) == 1020) return 0; // spurious clockintr = 0; @@ -220,7 +174,7 @@ irq(Ureg* ureg) clockintr = 1; } coherence(); - syswr(ICC_EOIR1_EL1, intid); + cregs[GICC_EOIR] = intid; return clockintr; } @@ -234,8 +188,7 @@ fiq(Ureg *ureg) u32int intid; m->intr++; - intid = sysrd(ICC_IAR1_EL1) & 0xFFFFFF; -// iprint("f<%d>", intid); + intid = cregs[GICC_IAR] & 0xFFFFFF; if((intid & ~3) == 1020) return; // spurious v = vfiq; @@ -244,11 +197,11 @@ fiq(Ureg *ureg) v->f(ureg, v->a); coherence(); } - syswr(ICC_EOIR1_EL1, intid); + cregs[GICC_EOIR] = intid; } 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*) { Vctl *v; u32int intid; @@ -264,6 +217,7 @@ intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *) prio = 0x80; intid = irq; + if((v = xalloc(sizeof(Vctl))) == nil) panic("intrenable: no mem"); v->irq = irq; @@ -283,35 +237,34 @@ intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *) v->next = vctl[cpu][intid%32]; vctl[cpu][intid%32] = v; } - syswr(ICC_IGRPEN1_EL1, sysrd(ICC_IGRPEN1_EL1)|1); + + /* enable cpu interface */ + cregs[GICC_PMR] = 0xFF; coherence(); - syswr(ICC_EOIR1_EL1, intid); + cregs[GICC_CTLR] |= 1; + coherence(); + + cregs[GICC_EOIR] = intid; + + /* enable distributor */ + dregs[GICD_CTLR] |= 1; 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)) - ; - } + 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 -intrdisable(int tbdf, void (*f)(Ureg*, void*), void *a, int, char*) +intrdisable(int, void (*f)(Ureg*, void*), void *a, int tbdf, char*) { if(BUSTYPE(tbdf) == BusPCI){ pciintrdisable(tbdf, f, a); |