fault.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /*
  2. * linux/arch/cris/mm/fault.c
  3. *
  4. * Low level bus fault handler
  5. *
  6. *
  7. * Copyright (C) 2000-2007 Axis Communications AB
  8. *
  9. * Authors: Bjorn Wesen
  10. *
  11. */
  12. #include <linux/mm.h>
  13. #include <asm/uaccess.h>
  14. #include <asm/pgtable.h>
  15. #include <arch/svinto.h>
  16. #include <asm/mmu_context.h>
  17. /* debug of low-level TLB reload */
  18. #undef DEBUG
  19. #ifdef DEBUG
  20. #define D(x) x
  21. #else
  22. #define D(x)
  23. #endif
  24. extern const struct exception_table_entry
  25. *search_exception_tables(unsigned long addr);
  26. asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
  27. int protection, int writeaccess);
  28. /* fast TLB-fill fault handler
  29. * this is called from entry.S with interrupts disabled
  30. */
  31. void
  32. handle_mmu_bus_fault(struct pt_regs *regs)
  33. {
  34. int cause;
  35. int select;
  36. #ifdef DEBUG
  37. int index;
  38. int page_id;
  39. int acc, inv;
  40. #endif
  41. pgd_t* pgd = (pgd_t*)per_cpu(current_pgd, smp_processor_id());
  42. pmd_t *pmd;
  43. pte_t pte;
  44. int miss, we, writeac;
  45. unsigned long address;
  46. unsigned long flags;
  47. cause = *R_MMU_CAUSE;
  48. address = cause & PAGE_MASK; /* get faulting address */
  49. select = *R_TLB_SELECT;
  50. #ifdef DEBUG
  51. page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause);
  52. acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause);
  53. inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause);
  54. index = IO_EXTRACT(R_TLB_SELECT, index, select);
  55. #endif
  56. miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause);
  57. we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause);
  58. writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause);
  59. D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
  60. regs->irp, address, miss, inv, we, acc, index, page_id));
  61. /* leave it to the MM system fault handler */
  62. if (miss)
  63. do_page_fault(address, regs, 0, writeac);
  64. else
  65. do_page_fault(address, regs, 1, we);
  66. /* Reload TLB with new entry to avoid an extra miss exception.
  67. * do_page_fault may have flushed the TLB so we have to restore
  68. * the MMU registers.
  69. */
  70. local_irq_save(flags);
  71. pmd = (pmd_t *)(pgd + pgd_index(address));
  72. if (pmd_none(*pmd))
  73. goto exit;
  74. pte = *pte_offset_kernel(pmd, address);
  75. if (!pte_present(pte))
  76. goto exit;
  77. *R_TLB_SELECT = select;
  78. *R_TLB_HI = cause;
  79. *R_TLB_LO = pte_val(pte);
  80. exit:
  81. local_irq_restore(flags);
  82. }