#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <linux/kdebug.h>
#include <linux/extable.h>
#include <linux/memblock.h>
#include <linux/kfence.h>
#include <linux/kprobes.h>
#include <linux/mmiotrace.h>
#include <linux/perf_event.h>
#include <linux/hugetlb.h>
#include <linux/prefetch.h>
#include <linux/context_tracking.h>
#include <linux/uaccess.h>
#include <linux/efi.h>
#include <linux/mm_types.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <asm/cpufeature.h>
#include <asm/traps.h>
#include <asm/fixmap.h>
#include <asm/vsyscall.h>
#include <asm/vm86.h>
#include <asm/mmu_context.h>
#include <asm/efi.h>
#include <asm/desc.h>
#include <asm/cpu_entry_area.h>
#include <asm/pgtable_areas.h>
#include <asm/kvm_para.h>
#include <asm/vdso.h>
#include <asm/irq_stack.h>
#include <asm/fred.h>
#include <asm/sev.h>
#define CREATE_TRACE_POINTS
#include <asm/trace/exceptions.h>
static nokprobe_inline int
kmmio_fault(struct pt_regs *regs, unsigned long addr)
{ … }
static inline int
check_prefetch_opcode(struct pt_regs *regs, unsigned char *instr,
unsigned char opcode, int *prefetch)
{ … }
static bool is_amd_k8_pre_npt(void)
{ … }
static int
is_prefetch(struct pt_regs *regs, unsigned long error_code, unsigned long addr)
{ … }
DEFINE_SPINLOCK(…);
LIST_HEAD(…);
#ifdef CONFIG_X86_32
static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
{
unsigned index = pgd_index(address);
pgd_t *pgd_k;
p4d_t *p4d, *p4d_k;
pud_t *pud, *pud_k;
pmd_t *pmd, *pmd_k;
pgd += index;
pgd_k = init_mm.pgd + index;
if (!pgd_present(*pgd_k))
return NULL;
p4d = p4d_offset(pgd, address);
p4d_k = p4d_offset(pgd_k, address);
if (!p4d_present(*p4d_k))
return NULL;
pud = pud_offset(p4d, address);
pud_k = pud_offset(p4d_k, address);
if (!pud_present(*pud_k))
return NULL;
pmd = pmd_offset(pud, address);
pmd_k = pmd_offset(pud_k, address);
if (pmd_present(*pmd) != pmd_present(*pmd_k))
set_pmd(pmd, *pmd_k);
if (!pmd_present(*pmd_k))
return NULL;
else
BUG_ON(pmd_pfn(*pmd) != pmd_pfn(*pmd_k));
return pmd_k;
}
static noinline int vmalloc_fault(unsigned long address)
{
unsigned long pgd_paddr;
pmd_t *pmd_k;
pte_t *pte_k;
if (!(address >= VMALLOC_START && address < VMALLOC_END))
return -1;
pgd_paddr = read_cr3_pa();
pmd_k = vmalloc_sync_one(__va(pgd_paddr), address);
if (!pmd_k)
return -1;
if (pmd_leaf(*pmd_k))
return 0;
pte_k = pte_offset_kernel(pmd_k, address);
if (!pte_present(*pte_k))
return -1;
return 0;
}
NOKPROBE_SYMBOL(vmalloc_fault);
void arch_sync_kernel_mappings(unsigned long start, unsigned long end)
{
unsigned long addr;
for (addr = start & PMD_MASK;
addr >= TASK_SIZE_MAX && addr < VMALLOC_END;
addr += PMD_SIZE) {
struct page *page;
spin_lock(&pgd_lock);
list_for_each_entry(page, &pgd_list, lru) {
spinlock_t *pgt_lock;
pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
spin_lock(pgt_lock);
vmalloc_sync_one(page_address(page), addr);
spin_unlock(pgt_lock);
}
spin_unlock(&pgd_lock);
}
}
static bool low_pfn(unsigned long pfn)
{
return pfn < max_low_pfn;
}
static void dump_pagetable(unsigned long address)
{
pgd_t *base = __va(read_cr3_pa());
pgd_t *pgd = &base[pgd_index(address)];
p4d_t *p4d;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
#ifdef CONFIG_X86_PAE
pr_info("*pdpt = %016Lx ", pgd_val(*pgd));
if (!low_pfn(pgd_val(*pgd) >> PAGE_SHIFT) || !pgd_present(*pgd))
goto out;
#define pr_pde …
#else
#define pr_pde …
#endif
p4d = p4d_offset(pgd, address);
pud = pud_offset(p4d, address);
pmd = pmd_offset(pud, address);
pr_pde("*pde = %0*Lx ", sizeof(*pmd) * 2, (u64)pmd_val(*pmd));
#undef pr_pde
if (!low_pfn(pmd_pfn(*pmd)) || !pmd_present(*pmd) || pmd_leaf(*pmd))
goto out;
pte = pte_offset_kernel(pmd, address);
pr_cont("*pte = %0*Lx ", sizeof(*pte) * 2, (u64)pte_val(*pte));
out:
pr_cont("\n");
}
#else
#ifdef CONFIG_CPU_SUP_AMD
static const char errata93_warning[] = …;
#endif
static int bad_address(void *p)
{ … }
static void dump_pagetable(unsigned long address)
{ … }
#endif
static int is_errata93(struct pt_regs *regs, unsigned long address)
{ … }
static int is_errata100(struct pt_regs *regs, unsigned long address)
{ … }
static int is_f00f_bug(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{ … }
static void show_ldttss(const struct desc_ptr *gdt, const char *name, u16 index)
{ … }
static void
show_fault_oops(struct pt_regs *regs, unsigned long error_code, unsigned long address)
{ … }
static noinline void
pgtable_bad(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{ … }
static void sanitize_error_code(unsigned long address,
unsigned long *error_code)
{ … }
static void set_signal_archinfo(unsigned long address,
unsigned long error_code)
{ … }
static noinline void
page_fault_oops(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{ … }
static noinline void
kernelmode_fixup_or_oops(struct pt_regs *regs, unsigned long error_code,
unsigned long address, int signal, int si_code,
u32 pkey)
{ … }
static inline void
show_signal_msg(struct pt_regs *regs, unsigned long error_code,
unsigned long address, struct task_struct *tsk)
{ … }
static void
__bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
unsigned long address, u32 pkey, int si_code)
{ … }
static noinline void
bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{ … }
static void
__bad_area(struct pt_regs *regs, unsigned long error_code,
unsigned long address, struct mm_struct *mm,
struct vm_area_struct *vma, u32 pkey, int si_code)
{ … }
static inline bool bad_area_access_from_pkeys(unsigned long error_code,
struct vm_area_struct *vma)
{ … }
static noinline void
bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
unsigned long address, struct mm_struct *mm,
struct vm_area_struct *vma)
{ … }
static void
do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
vm_fault_t fault)
{ … }
static int spurious_kernel_fault_check(unsigned long error_code, pte_t *pte)
{ … }
static noinline int
spurious_kernel_fault(unsigned long error_code, unsigned long address)
{ … }
NOKPROBE_SYMBOL(spurious_kernel_fault);
int show_unhandled_signals = …;
static inline int
access_error(unsigned long error_code, struct vm_area_struct *vma)
{ … }
bool fault_in_kernel_space(unsigned long address)
{ … }
static void
do_kern_addr_fault(struct pt_regs *regs, unsigned long hw_error_code,
unsigned long address)
{ … }
NOKPROBE_SYMBOL(do_kern_addr_fault);
static inline
void do_user_addr_fault(struct pt_regs *regs,
unsigned long error_code,
unsigned long address)
{ … }
NOKPROBE_SYMBOL(do_user_addr_fault);
static __always_inline void
trace_page_fault_entries(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{ … }
static __always_inline void
handle_page_fault(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{ … }
DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
{ … }