x86/entry: Switch page fault exception to IDTENTRY_RAW
Convert page fault exceptions to IDTENTRY_RAW: - Implement the C entry point with DEFINE_IDTENTRY_RAW - Add the CR2 read into the exception handler - Add the idtentry_enter/exit_cond_rcu() invocations in in the regular page fault handler and in the async PF part. - Emit the ASM stub with DECLARE_IDTENTRY_RAW - Remove the ASM idtentry in 64-bit - Remove the CR2 read from 64-bit - Remove the open coded ASM entry code in 32-bit - Fix up the XEN/PV code - Remove the old prototypes No functional change. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@kernel.org> Acked-by: Andy Lutomirski <luto@kernel.org> Link: https://lore.kernel.org/r/20200521202118.238455120@linutronix.de
This commit is contained in:
@@ -1357,11 +1357,38 @@ trace_page_fault_entries(struct pt_regs *regs, unsigned long error_code,
|
||||
trace_page_fault_kernel(address, regs, error_code);
|
||||
}
|
||||
|
||||
dotraplinkage void
|
||||
do_page_fault(struct pt_regs *regs, unsigned long hw_error_code,
|
||||
unsigned long address)
|
||||
static __always_inline void
|
||||
handle_page_fault(struct pt_regs *regs, unsigned long error_code,
|
||||
unsigned long address)
|
||||
{
|
||||
trace_page_fault_entries(regs, error_code, address);
|
||||
|
||||
if (unlikely(kmmio_fault(regs, address)))
|
||||
return;
|
||||
|
||||
/* Was the fault on kernel-controlled part of the address space? */
|
||||
if (unlikely(fault_in_kernel_space(address))) {
|
||||
do_kern_addr_fault(regs, error_code, address);
|
||||
} else {
|
||||
do_user_addr_fault(regs, error_code, address);
|
||||
/*
|
||||
* User address page fault handling might have reenabled
|
||||
* interrupts. Fixing up all potential exit points of
|
||||
* do_user_addr_fault() and its leaf functions is just not
|
||||
* doable w/o creating an unholy mess or turning the code
|
||||
* upside down.
|
||||
*/
|
||||
local_irq_disable();
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
|
||||
{
|
||||
unsigned long address = read_cr2();
|
||||
bool rcu_exit;
|
||||
|
||||
prefetchw(¤t->mm->mmap_lock);
|
||||
|
||||
/*
|
||||
* KVM has two types of events that are, logically, interrupts, but
|
||||
* are unfortunately delivered using the #PF vector. These events are
|
||||
@@ -1376,28 +1403,28 @@ do_page_fault(struct pt_regs *regs, unsigned long hw_error_code,
|
||||
* getting values from real and async page faults mixed up.
|
||||
*
|
||||
* Fingers crossed.
|
||||
*
|
||||
* The async #PF handling code takes care of idtentry handling
|
||||
* itself.
|
||||
*/
|
||||
if (kvm_handle_async_pf(regs, (u32)address))
|
||||
return;
|
||||
|
||||
trace_page_fault_entries(regs, hw_error_code, address);
|
||||
/*
|
||||
* Entry handling for valid #PF from kernel mode is slightly
|
||||
* different: RCU is already watching and rcu_irq_enter() must not
|
||||
* be invoked because a kernel fault on a user space address might
|
||||
* sleep.
|
||||
*
|
||||
* In case the fault hit a RCU idle region the conditional entry
|
||||
* code reenabled RCU to avoid subsequent wreckage which helps
|
||||
* debugability.
|
||||
*/
|
||||
rcu_exit = idtentry_enter_cond_rcu(regs);
|
||||
|
||||
if (unlikely(kmmio_fault(regs, address)))
|
||||
return;
|
||||
instrumentation_begin();
|
||||
handle_page_fault(regs, error_code, address);
|
||||
instrumentation_end();
|
||||
|
||||
/* Was the fault on kernel-controlled part of the address space? */
|
||||
if (unlikely(fault_in_kernel_space(address))) {
|
||||
do_kern_addr_fault(regs, hw_error_code, address);
|
||||
} else {
|
||||
do_user_addr_fault(regs, hw_error_code, address);
|
||||
/*
|
||||
* User address page fault handling might have reenabled
|
||||
* interrupts. Fixing up all potential exit points of
|
||||
* do_user_addr_fault() and its leaf functions is just not
|
||||
* doable w/o creating an unholy mess or turning the code
|
||||
* upside down.
|
||||
*/
|
||||
local_irq_disable();
|
||||
}
|
||||
idtentry_exit_cond_rcu(regs, rcu_exit);
|
||||
}
|
||||
NOKPROBE_SYMBOL(do_page_fault);
|
||||
|
Fai riferimento in un nuovo problema
Block a user