patch-2.4.5 linux/arch/i386/mm/fault.c
Next file: linux/arch/m68k/config.in
Previous file: linux/arch/i386/lib/mmx.c
Back to the patch index
Back to the overall index
- Lines: 77
- Date:
Tue May 15 00:16:51 2001
- Orig file:
v2.4.4/linux/arch/i386/mm/fault.c
- Orig date:
Mon Mar 19 12:35:09 2001
diff -u --recursive --new-file v2.4.4/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
@@ -117,6 +117,10 @@
/* get the address */
__asm__("movl %%cr2,%0":"=r" (address));
+ /* It's safe to allow irq's after cr2 has been saved */
+ if (regs->eflags & X86_EFLAGS_IF)
+ local_irq_enable();
+
tsk = current;
/*
@@ -127,8 +131,12 @@
* be in an interrupt or a critical region, and should
* only copy the information from the master page table,
* nothing more.
+ *
+ * This verifies that the fault happens in kernel space
+ * (error_code & 4) == 0, and that the fault was not a
+ * protection error (error_code & 1) == 0.
*/
- if (address >= TASK_SIZE)
+ if (address >= TASK_SIZE && !(error_code & 5))
goto vmalloc_fault;
mm = tsk->mm;
@@ -224,7 +232,6 @@
bad_area:
up_read(&mm->mmap_sem);
-bad_area_nosemaphore:
/* User mode accesses just cause a SIGSEGV */
if (error_code & 4) {
tsk->thread.cr2 = address;
@@ -322,27 +329,32 @@
/*
* Synchronize this task's top level page-table
* with the 'reference' page table.
+ *
+ * Do _not_ use "tsk" here. We might be inside
+ * an interrupt in the middle of a task switch..
*/
int offset = __pgd_offset(address);
pgd_t *pgd, *pgd_k;
pmd_t *pmd, *pmd_k;
+ pte_t *pte_k;
- pgd = tsk->active_mm->pgd + offset;
+ asm("movl %%cr3,%0":"=r" (pgd));
+ pgd = offset + (pgd_t *)__va(pgd);
pgd_k = init_mm.pgd + offset;
- if (!pgd_present(*pgd)) {
- if (!pgd_present(*pgd_k))
- goto bad_area_nosemaphore;
- set_pgd(pgd, *pgd_k);
- return;
- }
-
+ if (!pgd_present(*pgd_k))
+ goto no_context;
+ set_pgd(pgd, *pgd_k);
+
pmd = pmd_offset(pgd, address);
pmd_k = pmd_offset(pgd_k, address);
-
- if (pmd_present(*pmd) || !pmd_present(*pmd_k))
- goto bad_area_nosemaphore;
+ if (!pmd_present(*pmd_k))
+ goto no_context;
set_pmd(pmd, *pmd_k);
+
+ pte_k = pte_offset(pmd_k, address);
+ if (!pte_present(*pte_k))
+ goto no_context;
return;
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)