11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * linux/arch/cris/mm/fault.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Low level bus fault handler 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 740316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson * Copyright (C) 2000-2007 Axis Communications AB 840316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson * 940316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson * Authors: Bjorn Wesen 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h> 16556dcee7b829e5c350c3ffdbdb87a8b15aa3c5d3Jesper Nilsson#include <arch/svinto.h> 178d20a541b089ecb67a88a673548161b686ed7b85Mikael Starvik#include <asm/mmu_context.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* debug of low-level TLB reload */ 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define D(x) x 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define D(x) 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern const struct exception_table_entry 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *search_exception_tables(unsigned long addr); 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsasmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs, 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int protection, int writeaccess); 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* fast TLB-fill fault handler 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this is called from entry.S with interrupts disabled 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshandle_mmu_bus_fault(struct pt_regs *regs) 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cause; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int select; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int index; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int page_id; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int acc, inv; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 488d20a541b089ecb67a88a673548161b686ed7b85Mikael Starvik pgd_t* pgd = (pgd_t*)per_cpu(current_pgd, smp_processor_id()); 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pmd_t *pmd; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pte_t pte; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int miss, we, writeac; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long address; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cause = *R_MMU_CAUSE; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address = cause & PAGE_MASK; /* get faulting address */ 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds select = *R_TLB_SELECT; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); 6340316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = IO_EXTRACT(R_TLB_SELECT, index, select); 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n", 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regs->irp, address, miss, inv, we, acc, index, page_id)); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* leave it to the MM system fault handler */ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (miss) 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_page_fault(address, regs, 0, writeac); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_page_fault(address, regs, 1, we); 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reload TLB with new entry to avoid an extra miss exception. 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do_page_fault may have flushed the TLB so we have to restore 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the MMU registers. 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8384a3098f1ff8b42f2fdcfda25d1a83ea4a53b021Jiri Kosina local_irq_save(flags); 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pmd = (pmd_t *)(pgd + pgd_index(address)); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pmd_none(*pmd)) 8640316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson goto exit; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pte = *pte_offset_kernel(pmd, address); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pte_present(pte)) 8940316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilsson goto exit; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *R_TLB_SELECT = select; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *R_TLB_HI = cause; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *R_TLB_LO = pte_val(pte); 9340316c1fadfcd7856e43029fdbac5df6a1d57063Jesper Nilssonexit: 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 96