From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=0.2 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.4 Received: (qmail 12195 invoked from network); 8 Jan 2024 00:24:18 -0000 Received: from 9front.inri.net (168.235.81.73) by inbox.vuxu.org with ESMTPUTF8; 8 Jan 2024 00:24:18 -0000 Received: from mail.cosarara.me ([159.69.205.102]) by 9front; Sun Jan 7 19:20:54 -0500 2024 Received: from localhost (unknown [IPv6:2a0c:5a84:e700:a900:77a0:3e36:e2a1:e60]) by mail.cosarara.me (Postfix) with ESMTPSA id 908AE130CC; Mon, 8 Jan 2024 01:20:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cosarara.me; s=20200226; t=1704673250; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=mQdpalR2mxUMRKPc3oesohmZlRET31fMcHdGGmqnz9E=; b=fcDNlDdX6QyM7q00LceePmtpr+trrV0JXFh2uyA+i5sywcK0z166NKacHDStDuhi29S06k wO3l16CE7AnmpT9qH3POqCxAgxRgz8NGSqq+wP7+oIPPHL22rUTE1kQTEmXO6HGtGVUsSr BXuimKooC1KPoo1NrF6Vl9ABqATAXFM= From: cosarara To: 9front@9front.org Cc: cosarara Date: Mon, 8 Jan 2024 01:20:37 +0100 Message-ID: <20240108002037.987173-1-cosa@cosarara.me> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: rails standard software wrapper Subject: [9front] [PATCH] Adds a new configuration to the qemu kernel so that it can run with GIC v2. Reply-To: 9front@9front.org Precedence: bulk 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=3D2 \ -cpu host -m 2G -smp 2 \ -bios u-boot.bin \ -drive file=3D9front-10277.arm64.qcow2,if=3Dnone,id=3Ddisk \ -device virtio-blk-pci-non-transitional,drive=3Ddisk \ -nic bridge,br=3Dbr0,model=3Dvirtio-net-pci-non-transitional,mac=3D52:= 54:28:86:30:47 \ -nographic -accel kvm Build instructions: % cd /sys/src/9/arm64 % mk 'CONF=3Dqemu2' install Then copy /arm64/9qemu2.u over your kernel file: % bind -b '#S' /dev # if needed % 9fs dos % cp /arm64/9qemu2.u /n/dos/9qemu.u (generating a new boot.scr to use the 9qemu2.u filename left as an exercise to the reader) --- sys/src/9/arm64/gicv2.c | 273 ++++++++++++++++++++++++++++++++++++++++ sys/src/9/arm64/mkfile | 2 +- sys/src/9/arm64/qemu2 | 50 ++++++++ 3 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 sys/src/9/arm64/gicv2.c create mode 100644 sys/src/9/arm64/qemu2 diff --git a/sys/src/9/arm64/gicv2.c b/sys/src/9/arm64/gicv2.c new file mode 100644 index 000000000..c84cb4b4d --- /dev/null +++ b/sys/src/9/arm64/gicv2.c @@ -0,0 +1,273 @@ +#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 =3D 0x000/4, /* RW, Distributor Control Register */ + GICD_TYPER =3D 0x004/4, /* RO, Interrupt Controller Type */ + GICD_IIDR =3D 0x008/4, /* RO, Distributor Implementer Identification Re= gister */ + + GICD_IGROUPR0 =3D 0x080/4, /* RW, Interrupt Group Registers (0x80-0xBC)= */ + + GICD_ISENABLER0 =3D 0x100/4, /* RW, Interrupt Set-Enable Registers (0x1= 00-0x13C) */ + GICD_ICENABLER0 =3D 0x180/4, /* RW, Interrupt Clear-Enable Registers (0= x180-0x1BC) */ + + GICD_ISPENDR0 =3D 0x200/4, /* RW, Interrupt Set-Pending Registers (0x20= 0-0x23C) */ + GICD_ICPENDR0 =3D 0x280/4, /* RW, Interrupt Clear-Pending Registers (0x= 280-0x2BC) */ + + GICD_ISACTIVER0 =3D 0x300/4, /* RW, Interrupt Set-Active Registers (0x3= 00-0x33C) */ + GICD_ICACTIVER0 =3D 0x380/4, /* RW, Interrupt Clear-Active Registers (0= x380-0x3BC) */ + + GICD_IPRIORITYR0=3D 0x400/4, /* RW, Interrupt Priority Registers (0x400= -0x5FC) */ + GICD_TARGETSR0 =3D 0x800/4, /* RW, Interrupt Target Registers (0x800-0x= 9FC) */ + GICD_ICFGR0 =3D 0xC00/4, /* RW, Interrupt Configuration Registers (0xC0= 0-0xC7C) */ + + GICD_ISR0 =3D 0xD00/4, + GICD_PPISR =3D GICD_ISR0, /* RO, Private Peripheral Interrupt Status Re= gister */ + GICD_SPISR0 =3D GICD_ISR0+1, /* RO, Shared Peripheral Interrupt Status = Register */ + GICD_SGIR =3D 0xF00/4, /* WO, Software Generated Interrupt Register */ + + GICD_CPENDSGIR0 =3D 0xF10/4, /* RW, SGI Clear-Pending Registers (0xF10-= 0xF1C) */ + GICD_SPENDSGIR0 =3D 0xF20/4, /* RW, SGI Set-Pending Registers (0xF20-0x= F2C) */ + + GICD_PIDR4 =3D 0xFD0/4, /* RO, Perpheral ID Registers */ + GICD_PIDR5 =3D 0xFD4/4, + GICD_PIDR6 =3D 0xFD8/4, + GICD_PIDR7 =3D 0xFDC/4, + GICD_PIDR0 =3D 0xFE0/4, + GICD_PIDR1 =3D 0xFE4/4, + GICD_PIDR2 =3D 0xFE8/4, + GICD_PIDR3 =3D 0xFEC/4, + + GICD_CIDR0 =3D 0xFF0/4, /* RO, Component ID Registers */ + GICD_CIDR1 =3D 0xFF4/4, + GICD_CIDR2 =3D 0xFF8/4, + GICD_CIDR3 =3D 0xFFC/4, + + GICC_CTLR =3D 0x000/4, /* RW, CPU Interace Control Register */ + GICC_PMR =3D 0x004/4, /* RW, Interrupt Priority Mask Register */ + GICC_BPR =3D 0x008/4, /* RW, Binary Point Register */ + GICC_IAR =3D 0x00C/4, /* RO, Interrupt Acknowledge Register */ + GICC_EOIR =3D 0x010/4, /* WO, End of Interrupt Register */ + GICC_RPR =3D 0x014/4, /* RO, Running Priority Register */ + GICC_HPPIR =3D 0x018/4, /* RO, Highest Priority Pending Interrupt Regis= ter */ + GICC_ABPR =3D 0x01C/4, /* RW, Aliased Binary Point Register */ + GICC_AIAR =3D 0x020/4, /* RO, Aliased Interrupt Acknowledge Register */ + GICC_AEOIR =3D 0x024/4, /* WO, Aliased End of Interrupt Register */ + GICC_AHPPIR =3D 0x028/4, /* RO, Aliased Highest Priority Pending Interr= upt Register */ + GICC_APR0 =3D 0x0D0/4, /* RW, Active Priority Register */ + GICC_NSAPR0 =3D 0x0E0/4, /* RW, Non-Secure Active Priority Register */ + GICC_IIDR =3D 0x0FC/4, /* RO, CPU Interface Identification Register */ + GICC_DIR =3D 0x1000/4, /* WO, Deactivate Interrupt Register */ + + GICH_HCR =3D 0x000/4, /* RW, Hypervisor Control Register */ + GICH_VTR =3D 0x004/4, /* RO, VGIC Type Register */ + GICH_VMCR =3D 0x008/4, /* RW, Virtual Machine Control Register */ + GICH_MISR =3D 0x010/4, /* RO, Maintenance Interrupt Status Register */ + GICH_EISR0 =3D 0x020/4, /* RO, End of Interrupt Status Register */ + GICH_ELSR0 =3D 0x030/4, /* RO, Empty List Register Status Register */ + GICH_APR0 =3D 0x0F0/4, /* RW, Active Priority Register */ + GICH_LR0 =3D 0x100/4, /* RW, List Registers (0x100-0x10C) */ + + GICV_CTLR =3D 0x000/4, /* RW, Virtual Machine Control Register */ + GICV_PMR =3D 0x004/4, /* RW, VM Priority Mask Register */ + GICV_BPR =3D 0x008/4, /* RW, VM Binary Point Register */ + GICV_IAR =3D 0x00C/4, /* RO, VM Interrupt Acknowledge Register */ + GICV_EOIR =3D 0x010/4, /* WO, VM End of Interrupt Register */ + GICV_RPR =3D 0x014/4, /* RO, VM Running Priority Register */ + GICV_HPPIR =3D 0x018/4, /* RO, VM Highest Piority Pending Interrupt Reg= ister */ + GICV_ABPR =3D 0x01C/4, /* RW, VM Aliased Binary Point Register */ + GICV_AIAR =3D 0x020/4, /* RO, VM Aliased Interrupt Acknowledge Register= */ + GICV_AEOIR =3D 0x024/4, /* WO, VM Aliased End of Interrupt Register */ + GICV_AHPPIR =3D 0x028/4, /* RO, VM Aliaed Highest Piority Pending Inter= rupt Register */ + GICV_APR0 =3D 0x0D0/4, /* RW, VM Active Priority Register */ + GICV_IIDR =3D 0x0FC/4, /* RO, VM CPU Interface Identification Register = */ + GICV_DIR =3D 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 =3D (u32int*)(VIRTIO + 0x0); +static u32int *cregs =3D (u32int*)(VIRTIO + 0x10000); + +void +intrcpushutdown(void) +{ + /* disable cpu interface */ + cregs[GICC_CTLR] &=3D ~1; + coherence(); +} + +void +intrsoff(void) +{ + /* disable distributor */ + dregs[GICD_CTLR] &=3D ~1; + coherence(); +} + +void +intrinit(void) +{ + int i, n; + + if(m->machno =3D=3D 0){ + intrsoff(); + + /* clear all interrupts */ + n =3D ((dregs[GICD_TYPER] & 0x1F)+1) << 5; + for(i =3D 0; i < n; i +=3D 32){ + dregs[GICD_ISENABLER0 + (i/32)] =3D -1; + coherence(); + dregs[GICD_ICENABLER0 + (i/32)] =3D -1; + coherence(); + } + for(i =3D 0; i < n; i +=3D 4){ + dregs[GICD_IPRIORITYR0 + (i/4)] =3D 0; + dregs[GICD_TARGETSR0 + (i/4)] =3D 0; + } + for(i =3D 32; i < n; i +=3D 16) + dregs[GICD_ICFGR0 + (i/16)] =3D 0; + coherence(); + } +} + + +/* + * 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 =3D cregs[GICC_IAR] & 0xFFFFFF; + if((intid & ~3) =3D=3D 1020) + return 0; // spurious + clockintr =3D 0; + for(v =3D vctl[m->machno][intid%32]; v !=3D nil; v =3D v->next) + if(v->intid =3D=3D intid){ + coherence(); + v->f(ureg, v->a); + coherence(); + if(v->irq =3D=3D IRQcntvns) + clockintr =3D 1; + } + coherence(); + cregs[GICC_EOIR] =3D intid; + return clockintr; +} + +/* + * called direct from lexception.s to handle fiq interrupt. + */ +void +fiq(Ureg *ureg) +{ + Vctl *v; + u32int intid; + + m->intr++; + intid =3D cregs[GICC_IAR] & 0xFFFFFF; + if((intid & ~3) =3D=3D 1020) + return; // spurious + v =3D vfiq; + if(v !=3D nil && v->intid =3D=3D intid && m->machno =3D=3D 0){ + coherence(); + v->f(ureg, v->a); + coherence(); + } + cregs[GICC_EOIR] =3D intid; +} + +void +intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char*) +{ + Vctl *v; + u32int intid; + int cpu, prio; + + if(BUSTYPE(tbdf) =3D=3D BusPCI){ + pciintrenable(tbdf, f, a); + return; + } + + if(tbdf !=3D BUSUNKNOWN) + return; + + prio =3D 0x80; + intid =3D irq; + + if((v =3D xalloc(sizeof(Vctl))) =3D=3D nil) + panic("intrenable: no mem"); + v->irq =3D irq; + v->intid =3D intid; + v->f =3D f; + v->a =3D a; + + lock(&vctllock); + if(intid < SPI) + cpu =3D m->machno; + else + cpu =3D 0; + if(irq =3D=3D IRQfiq){ + vfiq =3D v; + prio =3D 0; + }else{ + v->next =3D vctl[cpu][intid%32]; + vctl[cpu][intid%32] =3D v; + } + + /* enable cpu interface */ + cregs[GICC_PMR] =3D 0xFF; + coherence(); + + cregs[GICC_CTLR] |=3D 1; + coherence(); + + cregs[GICC_EOIR] =3D intid; + + /* enable distributor */ + dregs[GICD_CTLR] |=3D 1; + coherence(); + + /* setup */ + dregs[GICD_IPRIORITYR0 + (intid/4)] |=3D prio << ((intid%4) << 3); + dregs[GICD_TARGETSR0 + (intid/4)] |=3D (1<