+#ifdef LUNA2
+#ifdef DEBUG
+struct writebackstats {
+ int calls;
+ int cpushes;
+ int move16s;
+ int wb1s, wb2s, wb3s;
+ int wbsize[4];
+} wbstats;
+
+char *f7sz[] = { "longword", "byte", "word", "line" };
+char *f7tt[] = { "normal", "MOVE16", "AFC", "ACK" };
+char *f7tm[] = { "d-push", "u-data", "u-code", "M-data",
+ "M-code", "k-data", "k-code", "RES" };
+char wberrstr[] =
+ "WARNING: pid %d(%s) writeback [%s] failed, pc=%x fa=%x wba=%x wbd=%x\n";
+#endif
+
+writeback(fp, docachepush)
+ struct frame *fp;
+ int docachepush;
+{
+ register struct fmt7 *f = &fp->f_fmt7;
+ register struct proc *p = curproc;
+ int err = 0;
+ u_int fa;
+ caddr_t oonfault = p->p_addr->u_pcb.pcb_onfault;
+
+#ifdef DEBUG
+ if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) {
+ printf(" pid=%d, fa=%x,", p->p_pid, f->f_fa);
+ dumpssw(f->f_ssw);
+ }
+ wbstats.calls++;
+#endif
+ /*
+ * Deal with special cases first.
+ */
+ if ((f->f_ssw & SSW4_TMMASK) == SSW4_TMDCP) {
+ /*
+ * Dcache push fault.
+ * Line-align the address and write out the push data to
+ * the indicated physical address.
+ */
+#ifdef DEBUG
+ if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) {
+ printf(" pushing %s to PA %x, data %x",
+ f7sz[(f->f_ssw & SSW4_SZMASK) >> 5],
+ f->f_fa, f->f_pd0);
+ if ((f->f_ssw & SSW4_SZMASK) == SSW4_SZLN)
+ printf("/%x/%x/%x",
+ f->f_pd1, f->f_pd2, f->f_pd3);
+ printf("\n");
+ }
+ if (f->f_wb1s & SSW4_WBSV)
+ panic("writeback: cache push with WB1S valid");
+ wbstats.cpushes++;
+#endif
+ /*
+ * XXX there are security problems if we attempt to do a
+ * cache push after a signal handler has been called.
+ */
+ if (docachepush) {
+ pmap_enter(kernel_pmap, (vm_offset_t)vmmap,
+ trunc_page(f->f_fa), VM_PROT_WRITE, TRUE);
+ fa = (u_int)&vmmap[(f->f_fa & PGOFSET) & ~0xF];
+ bcopy((caddr_t)&f->f_pd0, (caddr_t)fa, 16);
+ DCFL(pmap_extract(kernel_pmap, (vm_offset_t)fa));
+ pmap_remove(kernel_pmap, (vm_offset_t)vmmap,
+ (vm_offset_t)&vmmap[NBPG]);
+ } else
+ printf("WARNING: pid %d(%s) uid %d: CPUSH not done\n",
+ p->p_pid, p->p_comm, p->p_ucred->cr_uid);
+ } else if ((f->f_ssw & (SSW4_RW|SSW4_TTMASK)) == SSW4_TTM16) {
+ /*
+ * MOVE16 fault.
+ * Line-align the address and write out the push data to
+ * the indicated virtual address.
+ */
+#ifdef DEBUG
+ if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
+ printf(" MOVE16 to VA %x(%x), data %x/%x/%x/%x\n",
+ f->f_fa, f->f_fa & ~0xF, f->f_pd0, f->f_pd1,
+ f->f_pd2, f->f_pd3);
+ if (f->f_wb1s & SSW4_WBSV)
+ panic("writeback: MOVE16 with WB1S valid");
+ wbstats.move16s++;
+#endif
+ if (KDFAULT(f->f_wb1s))
+ bcopy((caddr_t)&f->f_pd0, (caddr_t)(f->f_fa & ~0xF), 16);
+ else
+ err = suline((caddr_t)(f->f_fa & ~0xF), (caddr_t)&f->f_pd0);
+ if (err) {
+ fa = f->f_fa & ~0xF;
+#ifdef DEBUG
+ if (mmudebug & MDB_WBFAILED)
+ printf(wberrstr, p->p_pid, p->p_comm,
+ "MOVE16", fp->f_pc, f->f_fa,
+ f->f_fa & ~0xF, f->f_pd0);
+#endif
+ }
+ } else if (f->f_wb1s & SSW4_WBSV) {
+ /*
+ * Writeback #1.
+ * Position the "memory-aligned" data and write it out.
+ */
+ register u_int wb1d = f->f_wb1d;
+ register int off;
+
+#ifdef DEBUG
+ if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
+ dumpwb(1, f->f_wb1s, f->f_wb1a, f->f_wb1d);
+ wbstats.wb1s++;
+ wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++;
+#endif
+ off = (f->f_wb1a & 3) * 8;
+ switch (f->f_wb1s & SSW4_SZMASK) {
+ case SSW4_SZLW:
+ if (off)
+ wb1d = (wb1d >> (32 - off)) | (wb1d << off);
+ if (KDFAULT(f->f_wb1s))
+ *(long *)f->f_wb1a = wb1d;
+ else
+ err = suword((caddr_t)f->f_wb1a, wb1d);
+ break;
+ case SSW4_SZB:
+ off = 24 - off;
+ if (off)
+ wb1d >>= off;
+ if (KDFAULT(f->f_wb1s))
+ *(char *)f->f_wb1a = wb1d;
+ else
+ err = subyte((caddr_t)f->f_wb1a, wb1d);
+ break;
+ case SSW4_SZW:
+ off = (off + 16) % 32;
+ if (off)
+ wb1d = (wb1d >> (32 - off)) | (wb1d << off);
+ if (KDFAULT(f->f_wb1s))
+ *(short *)f->f_wb1a = wb1d;
+ else
+ err = susword((caddr_t)f->f_wb1a, wb1d);
+ break;
+ }
+ if (err) {
+ fa = f->f_wb1a;
+#ifdef DEBUG
+ if (mmudebug & MDB_WBFAILED)
+ printf(wberrstr, p->p_pid, p->p_comm,
+ "#1", fp->f_pc, f->f_fa,
+ f->f_wb1a, f->f_wb1d);
+#endif
+ }
+ }
+ /*
+ * Deal with the "normal" writebacks.
+ *
+ * XXX writeback2 is known to reflect a LINE size writeback after
+ * a MOVE16 was already dealt with above. Ignore it.
+ */
+ if (err == 0 && (f->f_wb2s & SSW4_WBSV) &&
+ (f->f_wb2s & SSW4_SZMASK) != SSW4_SZLN) {
+#ifdef DEBUG
+ if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
+ dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d);
+ wbstats.wb2s++;
+ wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++;
+#endif
+ switch (f->f_wb2s & SSW4_SZMASK) {
+ case SSW4_SZLW:
+ if (KDFAULT(f->f_wb2s))
+ *(long *)f->f_wb2a = f->f_wb2d;
+ else
+ err = suword((caddr_t)f->f_wb2a, f->f_wb2d);
+ break;
+ case SSW4_SZB:
+ if (KDFAULT(f->f_wb2s))
+ *(char *)f->f_wb2a = f->f_wb2d;
+ else
+ err = subyte((caddr_t)f->f_wb2a, f->f_wb2d);
+ break;
+ case SSW4_SZW:
+ if (KDFAULT(f->f_wb2s))
+ *(short *)f->f_wb2a = f->f_wb2d;
+ else
+ err = susword((caddr_t)f->f_wb2a, f->f_wb2d);
+ break;
+ }
+ if (err) {
+ fa = f->f_wb2a;
+#ifdef DEBUG
+ if (mmudebug & MDB_WBFAILED) {
+ printf(wberrstr, p->p_pid, p->p_comm,
+ "#2", fp->f_pc, f->f_fa,
+ f->f_wb2a, f->f_wb2d);
+ dumpssw(f->f_ssw);
+ dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d);
+ }
+#endif
+ }
+ }
+ if (err == 0 && (f->f_wb3s & SSW4_WBSV)) {
+#ifdef DEBUG
+ if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
+ dumpwb(3, f->f_wb3s, f->f_wb3a, f->f_wb3d);
+ wbstats.wb3s++;
+ wbstats.wbsize[(f->f_wb3s&SSW4_SZMASK)>>5]++;
+#endif
+ switch (f->f_wb3s & SSW4_SZMASK) {
+ case SSW4_SZLW:
+ if (KDFAULT(f->f_wb3s))
+ *(long *)f->f_wb3a = f->f_wb3d;
+ else
+ err = suword((caddr_t)f->f_wb3a, f->f_wb3d);
+ break;
+ case SSW4_SZB:
+ if (KDFAULT(f->f_wb3s))
+ *(char *)f->f_wb3a = f->f_wb3d;
+ else
+ err = subyte((caddr_t)f->f_wb3a, f->f_wb3d);
+ break;
+ case SSW4_SZW:
+ if (KDFAULT(f->f_wb3s))
+ *(short *)f->f_wb3a = f->f_wb3d;
+ else
+ err = susword((caddr_t)f->f_wb3a, f->f_wb3d);
+ break;
+#ifdef DEBUG
+ case SSW4_SZLN:
+ panic("writeback: wb3s indicates LINE write");
+#endif
+ }
+ if (err) {
+ fa = f->f_wb3a;
+#ifdef DEBUG
+ if (mmudebug & MDB_WBFAILED)
+ printf(wberrstr, p->p_pid, p->p_comm,
+ "#3", fp->f_pc, f->f_fa,
+ f->f_wb3a, f->f_wb3d);
+#endif
+ }
+ }
+ p->p_addr->u_pcb.pcb_onfault = oonfault;
+ /*
+ * Determine the cause of the failure if any translating to
+ * a signal. If the corresponding VA is valid and RO it is
+ * a protection fault (SIGBUS) otherwise consider it an
+ * illegal reference (SIGSEGV).
+ */
+ if (err) {
+ if (vm_map_check_protection(&p->p_vmspace->vm_map,
+ trunc_page(fa), round_page(fa),
+ VM_PROT_READ) &&
+ !vm_map_check_protection(&p->p_vmspace->vm_map,
+ trunc_page(fa), round_page(fa),
+ VM_PROT_WRITE))
+ err = SIGBUS;
+ else
+ err = SIGSEGV;
+ }
+ return(err);
+}
+
+#ifdef DEBUG
+dumpssw(ssw)
+ register u_short ssw;
+{
+ printf(" SSW: %x: ", ssw);
+ if (ssw & SSW4_CP)
+ printf("CP,");
+ if (ssw & SSW4_CU)
+ printf("CU,");
+ if (ssw & SSW4_CT)
+ printf("CT,");
+ if (ssw & SSW4_CM)
+ printf("CM,");
+ if (ssw & SSW4_MA)
+ printf("MA,");
+ if (ssw & SSW4_ATC)
+ printf("ATC,");
+ if (ssw & SSW4_LK)
+ printf("LK,");
+ if (ssw & SSW4_RW)
+ printf("RW,");
+ printf(" SZ=%s, TT=%s, TM=%s\n",
+ f7sz[(ssw & SSW4_SZMASK) >> 5],
+ f7tt[(ssw & SSW4_TTMASK) >> 3],
+ f7tm[ssw & SSW4_TMMASK]);
+}
+
+dumpwb(num, s, a, d)
+ int num;
+ u_short s;
+ u_int a, d;
+{
+ register struct proc *p = curproc;
+ vm_offset_t pa;
+
+ printf(" writeback #%d: VA %x, data %x, SZ=%s, TT=%s, TM=%s\n",
+ num, a, d, f7sz[(s & SSW4_SZMASK) >> 5],
+ f7tt[(s & SSW4_TTMASK) >> 3], f7tm[s & SSW4_TMMASK]);
+ printf(" PA ");
+ pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)a);
+ if (pa == 0)
+ printf("<invalid address>");
+ else
+ printf("%x, current value %x", pa, fuword((caddr_t)a));
+ printf("\n");
+}
+#endif
+#endif
+