patch-2.4.9 linux/arch/sparc64/mm/fault.c
Next file: linux/arch/sparc64/mm/init.c
Previous file: linux/arch/sparc64/kernel/ttable.S
Back to the patch index
Back to the overall index
- Lines: 141
- Date:
Sun Aug 12 11:23:32 2001
- Orig file:
v2.4.8/linux/arch/sparc64/mm/fault.c
- Orig date:
Sun Mar 25 18:14:21 2001
diff -u --recursive --new-file v2.4.8/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.54 2001/03/24 09:36:11 davem Exp $
+/* $Id: fault.c,v 1.55 2001/08/09 20:18:43 davem Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -92,6 +92,13 @@
die_if_kernel("Oops", regs);
}
+/*
+ * We now make sure that mmap_sem is held in all paths that call
+ * this. Additionally, to prevent kswapd from ripping ptes from
+ * under us, raise interrupts around the time that we look at the
+ * pte, kswapd will have to wait to get his smp ipi response from
+ * us. This saves us having to get page_table_lock.
+ */
static unsigned int get_user_insn(unsigned long tpc)
{
pgd_t *pgdp = pgd_offset(current->mm, tpc);
@@ -99,13 +106,17 @@
pte_t *ptep, pte;
unsigned long pa;
u32 insn = 0;
+ unsigned long pstate;
if (pgd_none(*pgdp))
- goto out;
+ goto outret;
pmdp = pmd_offset(pgdp, tpc);
if (pmd_none(*pmdp))
- goto out;
+ goto outret;
ptep = pte_offset(pmdp, tpc);
+ __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
+ __asm__ __volatile__("wrpr %0, %1, %%pstate"
+ : : "r" (pstate), "i" (PSTATE_IE));
pte = *ptep;
if (!pte_present(pte))
goto out;
@@ -119,6 +130,8 @@
: "r" (pa), "i" (ASI_PHYS_USE_EC));
out:
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
+outret:
return insn;
}
@@ -137,21 +150,28 @@
extern int handle_ldf_stq(u32, struct pt_regs *);
extern int handle_ld_nf(u32, struct pt_regs *);
-static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
- unsigned int insn, unsigned long address)
+static inline unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn)
{
- unsigned long g2;
- unsigned char asi = ASI_P;
-
if (!insn) {
+ if (!regs->tpc || (regs->tpc & 0x3))
+ return 0;
if (regs->tstate & TSTATE_PRIV) {
- if (!regs->tpc || (regs->tpc & 0x3))
- goto cannot_handle;
insn = *(unsigned int *)regs->tpc;
} else {
insn = get_user_insn(regs->tpc);
}
}
+ return insn;
+}
+
+static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
+ unsigned int insn, unsigned long address)
+{
+ unsigned long g2;
+ unsigned char asi = ASI_P;
+
+ if (!insn)
+ goto cannot_handle;
/* If user insn could be read (thus insn is zero), that
* is fine. We will just gun down the process with a signal
@@ -232,7 +252,7 @@
* context, we must not take the fault..
*/
if (in_interrupt() || !mm)
- goto handle_kernel_fault;
+ goto intr_or_no_mm;
if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
regs->tpc &= 0xffffffff;
@@ -255,16 +275,9 @@
if (((fault_code &
(FAULT_CODE_DTLB | FAULT_CODE_WRITE | FAULT_CODE_WINFIXUP)) == FAULT_CODE_DTLB) &&
(vma->vm_flags & VM_WRITE) != 0) {
- unsigned long tpc = regs->tpc;
-
- if (tpc & 0x3)
+ insn = get_fault_insn(regs, 0);
+ if (!insn)
goto continue_fault;
-
- if (regs->tstate & TSTATE_PRIV)
- insn = *(unsigned int *)tpc;
- else
- insn = get_user_insn(tpc);
-
if ((insn & 0xc0200000) == 0xc0200000 &&
(insn & 0x1780000) != 0x1680000) {
/* Don't bother updating thread struct value,
@@ -326,6 +339,7 @@
* Fix it, but check if it's kernel or user first..
*/
bad_area:
+ insn = get_fault_insn(regs, insn);
up_read(&mm->mmap_sem);
handle_kernel_fault:
@@ -338,13 +352,19 @@
* us unable to handle the page fault gracefully.
*/
out_of_memory:
+ insn = get_fault_insn(regs, insn);
up_read(&mm->mmap_sem);
printk("VM: killing process %s\n", current->comm);
if (!(regs->tstate & TSTATE_PRIV))
do_exit(SIGKILL);
goto handle_kernel_fault;
+intr_or_no_mm:
+ insn = get_fault_insn(regs, 0);
+ goto handle_kernel_fault;
+
do_sigbus:
+ insn = get_fault_insn(regs, insn);
up_read(&mm->mmap_sem);
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)