9front - general discussion about 9front
 help / color / mirror / Atom feed
* [9front] [PATCH] GIC driver in the qemu kernel is now GICv2
@ 2024-01-08 20:24 cosarara
  0 siblings, 0 replies; only message in thread
From: cosarara @ 2024-01-08 20:24 UTC (permalink / raw)
  To: 9front; +Cc: cosarara

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
---
 sys/src/9/arm64/gic.c | 191 ++++++++++++++++--------------------------
 1 file 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);
-- 
2.43.0


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-01-08 20:26 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-08 20:24 [9front] [PATCH] GIC driver in the qemu kernel is now GICv2 cosarara

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).