1// SPDX-License-Identifier: GPL-2.0 2#include <linux/err.h> 3#include <linux/mm.h> 4#include <asm/current.h> 5#include <asm/traps.h> 6#include <asm/vdso.h> 7 8struct vdso_exception_table_entry { 9 int insn, fixup; 10}; 11 12bool fixup_vdso_exception(struct pt_regs *regs, int trapnr, 13 unsigned long error_code, unsigned long fault_addr) 14{ 15 const struct vdso_image *image = current->mm->context.vdso_image; 16 const struct vdso_exception_table_entry *extable; 17 unsigned int nr_entries, i; 18 unsigned long base; 19 20 /* 21 * Do not attempt to fixup #DB or #BP. It's impossible to identify 22 * whether or not a #DB/#BP originated from within an SGX enclave and 23 * SGX enclaves are currently the only use case for vDSO fixup. 24 */ 25 if (trapnr == X86_TRAP_DB || trapnr == X86_TRAP_BP) 26 return false; 27 28 if (!current->mm->context.vdso) 29 return false; 30 31 base = (unsigned long)current->mm->context.vdso + image->extable_base; 32 nr_entries = image->extable_len / (sizeof(*extable)); 33 extable = image->extable; 34 35 for (i = 0; i < nr_entries; i++) { 36 if (regs->ip == base + extable[i].insn) { 37 regs->ip = base + extable[i].fixup; 38 regs->di = trapnr; 39 regs->si = error_code; 40 regs->dx = fault_addr; 41 return true; 42 } 43 } 44 45 return false; 46} 47