summaryrefslogtreecommitdiff
path: root/arch/xtensa/mm/fault.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-05-23 20:54:17 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-05-23 20:54:17 -0700
commit17a05c8f1e18b3ef846d0032a19002568282ac29 (patch)
treefbde58f57f7135eaec99ec89ce8b1e09d18da86d /arch/xtensa/mm/fault.c
parentd61306047533eb6f63a7bd51dfa7f868503bf0ba (diff)
parentdc60001e1a305ad8bba1ddaf09484e0e150aba60 (diff)
downloadlinux-17a05c8f1e18b3ef846d0032a19002568282ac29.tar.gz
linux-17a05c8f1e18b3ef846d0032a19002568282ac29.tar.bz2
linux-17a05c8f1e18b3ef846d0032a19002568282ac29.zip
Merge tag 'xtensa-20220523' of https://github.com/jcmvbkbc/linux-xtensa
Pull xtensa architecture updates from Max Filippov: - support coprocessors on SMP - support KCSAN - support handling protection faults in noMMU configurations - support using coprocessors in the kernel mode - support hibernation - enable context tracking - enable HAVE_VIRT_CPU_ACCOUNTING_GEN - support division by 0 exception on cores without HW division option - clean up locking in the ISS network driver - clean up kernel entry assemly code - various minor fixes * tag 'xtensa-20220523' of https://github.com/jcmvbkbc/linux-xtensa: (36 commits) xtensa: Return true/false (not 1/0) from bool function xtensa: improve call0 ABI probing xtensa: support artificial division by 0 exception xtensa: add trap handler for division by zero xtensa/simdisk: fix proc_read_simdisk() xtensa: no need to initialise statics to 0 xtensa: clean up labels in the kernel entry assembly xtensa: don't leave invalid TLB entry in fast_store_prohibited xtensa: fix declaration of _SecondaryResetVector_text_* irqchip: irq-xtensa-mx: fix initial IRQ affinity xtensa: enable ARCH_HAS_DEBUG_VM_PGTABLE xtensa: add hibernation support xtensa: support coprocessors on SMP xtensa: get rid of stack frame in coprocessor_flush xtensa: merge SAVE_CP_REGS_TAB and LOAD_CP_REGS_TAB xtensa: add xtensa_xsr macro xtensa: handle coprocessor exceptions in kernel mode xtensa: use callx0 opcode in fast_coprocessor xtensa: clean up excsave1 initialization xtensa: clean up declarations in coprocessor.h ...
Diffstat (limited to 'arch/xtensa/mm/fault.c')
-rw-r--r--arch/xtensa/mm/fault.c112
1 files changed, 58 insertions, 54 deletions
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index 06d0973a0d74..16f0a5ff5799 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -21,9 +21,61 @@
#include <asm/cacheflush.h>
#include <asm/hardirq.h>
-DEFINE_PER_CPU(unsigned long, asid_cache) = ASID_USER_FIRST;
void bad_page_fault(struct pt_regs*, unsigned long, int);
+static void vmalloc_fault(struct pt_regs *regs, unsigned int address)
+{
+#ifdef CONFIG_MMU
+ /* Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ */
+ struct mm_struct *act_mm = current->active_mm;
+ int index = pgd_index(address);
+ pgd_t *pgd, *pgd_k;
+ p4d_t *p4d, *p4d_k;
+ pud_t *pud, *pud_k;
+ pmd_t *pmd, *pmd_k;
+ pte_t *pte_k;
+
+ if (act_mm == NULL)
+ goto bad_page_fault;
+
+ pgd = act_mm->pgd + index;
+ pgd_k = init_mm.pgd + index;
+
+ if (!pgd_present(*pgd_k))
+ goto bad_page_fault;
+
+ pgd_val(*pgd) = pgd_val(*pgd_k);
+
+ p4d = p4d_offset(pgd, address);
+ p4d_k = p4d_offset(pgd_k, address);
+ if (!p4d_present(*p4d) || !p4d_present(*p4d_k))
+ goto bad_page_fault;
+
+ pud = pud_offset(p4d, address);
+ pud_k = pud_offset(p4d_k, address);
+ if (!pud_present(*pud) || !pud_present(*pud_k))
+ goto bad_page_fault;
+
+ pmd = pmd_offset(pud, address);
+ pmd_k = pmd_offset(pud_k, address);
+ if (!pmd_present(*pmd) || !pmd_present(*pmd_k))
+ goto bad_page_fault;
+
+ pmd_val(*pmd) = pmd_val(*pmd_k);
+ pte_k = pte_offset_kernel(pmd_k, address);
+
+ if (!pte_present(*pte_k))
+ goto bad_page_fault;
+ return;
+
+bad_page_fault:
+ bad_page_fault(regs, address, SIGKILL);
+#else
+ WARN_ONCE(1, "%s in noMMU configuration\n", __func__);
+#endif
+}
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
@@ -49,8 +101,10 @@ void do_page_fault(struct pt_regs *regs)
/* We fault-in kernel-space virtual memory on-demand. The
* 'reference' page table is init_mm.pgd.
*/
- if (address >= TASK_SIZE && !user_mode(regs))
- goto vmalloc_fault;
+ if (address >= TASK_SIZE && !user_mode(regs)) {
+ vmalloc_fault(regs, address);
+ return;
+ }
/* If we're in an interrupt or have no user
* context, we must not take the fault..
@@ -114,7 +168,7 @@ good_area:
if (fault_signal_pending(fault, regs)) {
if (!user_mode(regs))
- goto bad_page_fault;
+ bad_page_fault(regs, address, SIGKILL);
return;
}
@@ -181,56 +235,6 @@ do_sigbus:
if (!user_mode(regs))
bad_page_fault(regs, address, SIGBUS);
return;
-
-vmalloc_fault:
- {
- /* Synchronize this task's top level page-table
- * with the 'reference' page table.
- */
- struct mm_struct *act_mm = current->active_mm;
- int index = pgd_index(address);
- pgd_t *pgd, *pgd_k;
- p4d_t *p4d, *p4d_k;
- pud_t *pud, *pud_k;
- pmd_t *pmd, *pmd_k;
- pte_t *pte_k;
-
- if (act_mm == NULL)
- goto bad_page_fault;
-
- pgd = act_mm->pgd + index;
- pgd_k = init_mm.pgd + index;
-
- if (!pgd_present(*pgd_k))
- goto bad_page_fault;
-
- pgd_val(*pgd) = pgd_val(*pgd_k);
-
- p4d = p4d_offset(pgd, address);
- p4d_k = p4d_offset(pgd_k, address);
- if (!p4d_present(*p4d) || !p4d_present(*p4d_k))
- goto bad_page_fault;
-
- pud = pud_offset(p4d, address);
- pud_k = pud_offset(p4d_k, address);
- if (!pud_present(*pud) || !pud_present(*pud_k))
- goto bad_page_fault;
-
- pmd = pmd_offset(pud, address);
- pmd_k = pmd_offset(pud_k, address);
- if (!pmd_present(*pmd) || !pmd_present(*pmd_k))
- goto bad_page_fault;
-
- pmd_val(*pmd) = pmd_val(*pmd_k);
- pte_k = pte_offset_kernel(pmd_k, address);
-
- if (!pte_present(*pte_k))
- goto bad_page_fault;
- return;
- }
-bad_page_fault:
- bad_page_fault(regs, address, SIGKILL);
- return;
}