/* Invalidate a single page. */ void __flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { int i; int mmu; unsigned long page_id; unsigned long flags; unsigned long tlb_hi; unsigned long mmu_tlb_hi; page_id = vma->vm_mm->context.page_id; if (page_id == NO_CONTEXT) return; addr &= PAGE_MASK; /* * Invalidate those TLB entries that match both the mm context and the * requested virtual address. */ local_irq_save(flags); for (mmu = 1; mmu <= 2; mmu++) { SUPP_BANK_SEL(mmu); for (i = 0; i < NUM_TLB_ENTRIES; i++) { UPDATE_TLB_SEL_IDX(i); SUPP_REG_RD(RW_MM_TLB_HI, tlb_hi); /* Check if page_id and address matches */ if (((tlb_hi & 0xff) == page_id) && ((tlb_hi & PAGE_MASK) == addr)) { mmu_tlb_hi = REG_FIELD(mmu, rw_mm_tlb_hi, pid, INVALID_PAGEID) | addr; UPDATE_TLB_HILO(mmu_tlb_hi, 0); } } } local_irq_restore(flags); }
/* Flush an entire user address space. */ void __flush_tlb_mm(struct mm_struct *mm) { int i; int mmu; unsigned long flags; unsigned long page_id; unsigned long tlb_hi; unsigned long mmu_tlb_hi; page_id = mm->context.page_id; if (page_id == NO_CONTEXT) return; /* Mark the TLB entries that match the page_id as invalid. */ local_irq_save(flags); for (mmu = 1; mmu <= 2; mmu++) { SUPP_BANK_SEL(mmu); for (i = 0; i < NUM_TLB_ENTRIES; i++) { UPDATE_TLB_SEL_IDX(i); /* Get the page_id */ SUPP_REG_RD(RW_MM_TLB_HI, tlb_hi); /* Check if the page_id match. */ if ((tlb_hi & 0xff) == page_id) { mmu_tlb_hi = (REG_FIELD(mmu, rw_mm_tlb_hi, pid, INVALID_PAGEID) | REG_FIELD(mmu, rw_mm_tlb_hi, vpn, i & 0xf)); UPDATE_TLB_HILO(mmu_tlb_hi, 0); } } } local_irq_restore(flags); }
static long get_debugreg(long pid, unsigned int regno) { register int old_srs; register long data; if (pid != bp_owner) { return 0; } /* Remember old SRS. */ SPEC_REG_RD(SPEC_REG_SRS, old_srs); /* Switch to BP bank. */ SUPP_BANK_SEL(BANK_BP); switch (regno - PT_BP) { case 0: SUPP_REG_RD(0, data); break; case 1: case 2: /* error return value? */ data = 0; break; case 3: SUPP_REG_RD(3, data); break; case 4: SUPP_REG_RD(4, data); break; case 5: SUPP_REG_RD(5, data); break; case 6: SUPP_REG_RD(6, data); break; case 7: SUPP_REG_RD(7, data); break; case 8: SUPP_REG_RD(8, data); break; case 9: SUPP_REG_RD(9, data); break; case 10: SUPP_REG_RD(10, data); break; case 11: SUPP_REG_RD(11, data); break; case 12: SUPP_REG_RD(12, data); break; case 13: SUPP_REG_RD(13, data); break; case 14: SUPP_REG_RD(14, data); break; default: /* error return value? */ data = 0; } /* Restore SRS. */ SPEC_REG_WR(SPEC_REG_SRS, old_srs); /* Just for show. */ NOP(); NOP(); NOP(); return data; }
void show_registers(struct pt_regs *regs) { /* * It's possible to use either the USP register or current->thread.usp. * USP might not correspond to the current process for all cases this * function is called, and current->thread.usp isn't up to date for the * current process. Experience shows that using USP is the way to go. */ unsigned long usp = rdusp(); unsigned long d_mmu_cause; unsigned long i_mmu_cause; printk("CPU: %d\n", smp_processor_id()); printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n", regs->erp, regs->srp, regs->ccs, usp, regs->mof); printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", regs->r0, regs->r1, regs->r2, regs->r3); printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", regs->r4, regs->r5, regs->r6, regs->r7); printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", regs->r8, regs->r9, regs->r10, regs->r11); printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n", regs->r12, regs->r13, regs->orig_r10, regs->acr); printk(" sp: %08lx\n", (unsigned long)regs); SUPP_BANK_SEL(BANK_IM); SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause); SUPP_BANK_SEL(BANK_DM); SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause); printk(" Data MMU Cause: %08lx\n", d_mmu_cause); printk("Instruction MMU Cause: %08lx\n", i_mmu_cause); printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current); /* * When in-kernel, we also print out the stack and code at the * time of the fault.. */ if (!user_mode(regs)) { int i; show_stack(NULL, (unsigned long *)usp); /* * If the previous stack-dump wasn't a kernel one, dump the * kernel stack now. */ if (usp != 0) show_stack(NULL, NULL); printk("\nCode: "); if (regs->erp < PAGE_OFFSET) goto bad_value; /* * Quite often the value at regs->erp doesn't point to the * interesting instruction, which often is the previous * instruction. So dump at an offset large enough that the * instruction decoding should be in sync at the interesting * point, but small enough to fit on a row. The regs->erp * location is pointed out in a ksymoops-friendly way by * wrapping the byte for that address in parenthesises. */ for (i = -12; i < 12; i++) { unsigned char c; if (__get_user(c, &((unsigned char *)regs->erp)[i])) { bad_value: printk(" Bad IP value."); break; } if (i == 0) printk("(%02x) ", c); else printk("%02x ", c); } printk("\n"); } }