powerpc/111296: Support IMISS, DLMISS an DSMISS interrupts
Andrew Turner
andrew at fubar.geek.nz
Fri Apr 6 00:50:05 UTC 2007
>Number: 111296
>Category: powerpc
>Synopsis: Support IMISS, DLMISS an DSMISS interrupts
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: freebsd-ppc
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Fri Apr 06 00:50:04 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator: Andrew Turner
>Release: FreeBSD 6.2-STABLE i386
>Organization:
>Environment:
System: FreeBSD hermies.int.fubar.geek.nz 6.2-STABLE FreeBSD 6.2-STABLE #0: Sat Feb 3 15:23:37 NZDT 2007 root at hermies.int.fubar.geek.nz:/usr/obj/srctrees/RELENG_6/sys/GENERIC i386
>Description:
The attached patch adds support for the IMISS, DLMISS an DSMISS interrupts required to run FreeBSD on a G2 core.
>How-To-Repeat:
>Fix:
Patch attached with submission follows:
Index: sys/powerpc/powerpc/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/powerpc/powerpc/machdep.c,v
retrieving revision 1.100
diff -u -r1.100 machdep.c
--- sys/powerpc/powerpc/machdep.c 12 Feb 2007 08:59:33 -0000 1.100
+++ sys/powerpc/powerpc/machdep.c 5 Apr 2007 21:26:45 -0000
@@ -253,6 +253,9 @@
extern void *extint, *extsize;
extern void *dblow, *dbsize;
extern void *vectrap, *vectrapsize;
+extern void *imisstrap, *imisssize;
+extern void *dlmisstrap, *dlmisssize;
+extern void *dsmisstrap, *dsmisssize;
void
powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp)
@@ -343,6 +346,9 @@
bcopy(&trapcode, (void *)EXC_SC, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_TRC, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_FPA, (size_t)&trapsize);
+ bcopy(&imisstrap, (void *)EXC_IMISS, (size_t)&imisssize);
+ bcopy(&dlmisstrap, (void *)EXC_DLMISS, (size_t)&dlmisssize);
+ bcopy(&dsmisstrap, (void *)EXC_DSMISS, (size_t)&dsmisssize);
bcopy(&vectrap, (void *)EXC_VEC, (size_t)&vectrapsize);
bcopy(&trapcode, (void *)EXC_VECAST, (size_t)&trapsize);
bcopy(&trapcode, (void *)EXC_THRM, (size_t)&trapsize);
Index: sys/powerpc/powerpc/trap_subr.S
===================================================================
RCS file: /cvsroot/src/sys/powerpc/powerpc/trap_subr.S,v
retrieving revision 1.16
diff -u -r1.16 trap_subr.S
--- sys/powerpc/powerpc/trap_subr.S 23 Dec 2005 13:05:27 -0000 1.16
+++ sys/powerpc/powerpc/trap_subr.S 5 Apr 2007 21:21:15 -0000
@@ -284,6 +284,207 @@
CNAME(alisize) = .-CNAME(alitrap)
/*
+ * It's G2 specific. Instuction TLB miss.
+ */
+ .globl CNAME(imisstrap),CNAME(imisssize)
+CNAME(imisstrap):
+ mfspr %r2, SPR_HASH1 /* get first pointer */
+ addi %r1, 0, 8 /* load 8 for counter */
+ mfctr %r0 /* save counter */
+ mfspr %r3, SPR_ICMP /* get first compare value */
+ addi %r2, %r2, -8 /* pre dec the pointer */
+im0:
+ mtctr %r1 /* load counter */
+im1:
+ lwzu %r1, 8(%r2) /* get next pte */
+ cmp 0, %r1, %r3 /* see if found pte */
+ bdnzf 2, im1 /* dec count br if cmp ne and if
+ * count not zero */
+ bne instr_sec_hash /* if not found set up second hash
+ * or exit */
+ lwz %r1, +4(%r2) /* load tlb entry lower-word */
+ andi. %r3, %r1, 8 /* check G bit */
+ bne do_isi_prot /* if guarded, take an ISI */
+ mtctr %r0 /* restore counter */
+ mfspr %r0, SPR_IMISS /* get the miss address for the tlbli */
+ mfspr %r3, SPR_SRR1 /* get the saved cr0 bits */
+ mtcrf 0x80, %r3 /* restore CR0 */
+ mtspr SPR_RPA, %r1 /* set the pte */
+ ori %r1, %r1, 0x100 /* set reference bit */
+ srwi %r1, %r1, 8 /* get byte 7 of pte */
+ tlbli %r0 /* load the itlb */
+ stb %r1, +6(%r2) /* update page table */
+ rfi /* return to executing program */
+
+instr_sec_hash:
+ andi. %r1, %r3, 0x0040 /* see if we have done second hash */
+ bne do_isi /* if so, go to ISI interrupt */
+ mfspr %r2, SPR_HASH2 /* get the second pointer */
+ ori %r3, %r3, 0x0040 /* change the compare value */
+ addi %r1, %r0, 8 /* load 8 for counter */
+ addi %r2, %r2, -8 /* pre dec for update on load */
+ b im0 /* try second hash */
+
+/* Create a faked ISI interrupt as the address was not found */
+do_isi_prot:
+ mfspr %r3, SPR_SRR1 /* get srr1 */
+ andi. %r2, %r3, 0xffff /* clean upper srr1 */
+ addis %r2, %r2, 0x0800 /* or in srr<4> = 1 to flag prot
+ * violation */
+ b isi1
+do_isi:
+ mfspr %r3, SPR_SRR1 /* get srr1 */
+ andi. %r2, %r3, 0xffff /* clean srr1 */
+ addis %r2, %r2, 0x4000 /* or in srr1<1> = 1 to flag pte
+ * not found */
+isi1:
+ mtctr %r0 /* restore counter */
+ mtspr SPR_SRR1, %r2 /* set srr1 */
+ mfmsr %r0 /* get msr */
+ xoris %r0, %r0, 0x2 /* flip the msr<tgpr> bit */
+ mtcrf 0x80, %r3 /* restore CR0 */
+ mtmsr %r0 /* flip back to the native gprs */
+ ba EXC_ISI /* go to instr. access interrupt */
+
+CNAME(imisssize) = .-CNAME(imisstrap)
+
+/*
+ * It's G2 specific. Data load TLB miss.
+ */
+ .globl CNAME(dlmisstrap),CNAME(dlmisssize)
+CNAME(dlmisstrap):
+ mfspr %r2, SPR_HASH1 /* get first pointer */
+ addi %r1, 0, 8 /* load 8 for counter */
+ mfctr %r0 /* save counter */
+ mfspr %r3, SPR_DCMP /* get first compare value */
+ addi %r2, %r2, -8 /* pre dec the pointer */
+dm0:
+ mtctr %r1 /* load counter */
+dm1:
+ lwzu %r1, 8(%r2) /* get next pte */
+ cmp 0, 0, %r1, %r3 /* see if found pte */
+ bdnzf 2, dm1 /* dec count br if cmp ne and if
+ * count not zero */
+ bne data_sec_hash /* if not found set up second hash
+ * or exit */
+ lwz %r1, +4(%r2) /* load tlb entry lower-word */
+ mtctr %r0 /* restore counter */
+ mfspr %r0, SPR_DMISS /* get the miss address for the tlbld */
+ mfspr %r3, SPR_SRR1 /* get the saved cr0 bits */
+ mtcrf 0x80, %r3 /* restore CR0 */
+ mtspr SPR_RPA, %r1 /* set the pte */
+ ori %r1, %r1, 0x100 /* set reference bit */
+ srwi %r1, %r1, 8 /* get byte 7 of pte */
+ tlbld %r0 /* load the dtlb */
+ stb %r1, +6(%r2) /* update page table */
+ rfi /* return to executing program */
+
+data_sec_hash:
+ andi. %r1, %r3, 0x0040 /* see if we have done second hash */
+ bne do_dsi /* if so, go to DSI interrupt */
+ mfspr %r2, SPR_HASH2 /* get the second pointer */
+ ori %r3, %r3, 0x0040 /* change the compare value */
+ addi %r1, 0, 8 /* load 8 for counter */
+ addi %r2, %r2, -8 /* pre dec for update on load */
+ b dm0 /* try second hash */
+
+CNAME(dlmisssize) = .-CNAME(dlmisstrap)
+
+/*
+ * It's G2 specific. Data store TLB miss.
+ */
+ .globl CNAME(dsmisstrap),CNAME(dsmisssize)
+CNAME(dsmisstrap):
+ mfspr %r2, SPR_HASH1 /* get first pointer */
+ addi %r1, 0, 8 /* load 8 for counter */
+ mfctr %r0 /* save counter */
+ mfspr %r3, SPR_DCMP /* get first compare value */
+ addi %r2, %r2, -8 /* pre dec the pointer */
+ds0:
+ mtctr %r1 /* load counter */
+ds1:
+ lwzu %r1, 8(%r2) /* get next pte */
+ cmp 0, 0, %r1, %r3 /* see if found pte */
+ bdnzf 2, ds1 /* dec count br if cmp ne and if
+ * count not zero */
+ bne data_store_sec_hash /* if not found set up second hash
+ * or exit */
+ lwz %r1, +4(%r2) /* load tlb entry lower-word */
+ andi. %r3, %r1, 0x80 /* check the C-bit */
+ beq data_store_chk_prot /* if (C==0)
+ * go check protection modes */
+ds2:
+ mtctr %r0 /* restore counter */
+ mfspr %r0, SPR_DMISS /* get the miss address for the tlbld */
+ mfspr %r3, SPR_SRR1 /* get the saved cr0 bits */
+ mtcrf 0x80, %r3 /* restore CR0 */
+ mtspr SPR_RPA, %r1 /* set the pte */
+ tlbld %r0 /* load the dtlb */
+ rfi /* return to executing program */
+
+data_store_sec_hash:
+ andi. %r1, %r3, 0x0040 /* see if we have done second hash */
+ bne do_dsi /* if so, go to DSI interrupt */
+ mfspr %r2, SPR_HASH2 /* get the second pointer */
+ ori %r3, %r3, 0x0040 /* change the compare value */
+ addi %r1, 0, 8 /* load 8 for counter */
+ addi %r2, %r2, -8 /* pre dec for update on load */
+ b ds0 /* try second hash */
+
+/* Check the protection before setting PTE(c-bit) */
+data_store_chk_prot:
+ rlwinm. %r3,%r1,30,0,1 /* test PP */
+ bge- chk0 /* if (PP == 00 or PP == 01)
+ * goto chk0: */
+ andi. %r3, %r1, 1 /* test PP[0] */
+ beq+ chk2 /* return if PP[0] == 0 */
+ b do_dsi_prot /* else DSIp */
+chk0:
+ mfspr %r3,SPR_SRR1 /* get old msr */
+ andis. %r3,%r3,0x0008 /* test the KEY bit (SRR1-bit 12) */
+ beq chk2 /* if (KEY==0) goto chk2: */
+ b do_dsi_prot /* else do_dsi_prot */
+chk2:
+ ori %r1, %r1, 0x180 /* set reference and change bit */
+ sth %r1, 6(%r2) /* update page table */
+ b ds2 /* and back we go */
+
+/* Create a faked DSI interrupt as the address was not found */
+do_dsi:
+ mfspr %r3, SPR_SRR1 /* get srr1 */
+ rlwinm %r1,%r3,9,6,6 /* get srr1<flag> to bit 6 for
+ * load/store, zero rest */
+ addis %r1, %r1, 0x4000 /* or in dsisr<1> = 1 to flag pte
+ * not found */
+ b dsi1
+
+do_dsi_prot:
+ mfspr %r3, SPR_SRR1 /* get srr1 */
+ rlwinm %r1,%r3,9,6,6 /* get srr1<flag> to bit 6 for
+ *load/store, zero rest */
+ addis %r1, %r1, 0x0800 /* or in dsisr<4> = 1 to flag prot
+ * violation */
+
+dsi1:
+ mtctr %r0 /* restore counter */
+ andi. %r2, %r3, 0xffff /* clear upper bits of srr1 */
+ mtspr SPR_SRR1, %r2 /* set srr1 */
+ mtspr SPR_DSISR, %r1 /* load the dsisr */
+ mfspr %r1, SPR_DMISS /* get miss address */
+ rlwinm. %r2,%r2,0,31,31 /* test LE bit */
+ beq dsi2 /* if little endian then: */
+ xor %r1, %r1, 0x07 /* de-mung the data address */
+dsi2:
+ mtspr SPR_DAR, %r1 /* put in dar */
+ mfmsr %r0 /* get msr */
+ xoris %r0, %r0, 0x2 /* flip the msr<tgpr> bit */
+ mtcrf 0x80, %r3 /* restore CR0 */
+ mtmsr %r0 /* flip back to the native gprs */
+ ba EXC_DSI /* branch to DSI interrupt */
+
+CNAME(dsmisssize) = .-CNAME(dsmisstrap)
+
+/*
* Similar to the above for DSI
* Has to handle BAT spills
* and standard pagetable spills
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-ppc
mailing list