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