Skip to content

Commit dbfbd87

Browse files
mrutland-armwilldeacon
authored andcommitted
arm64: factor insn read out of call_undef_hook()
Subsequent patches will rework EL0 UNDEF handling, removing the need for struct undef_hook and call_undef_hook. In preparation for those changes, this patch factors the logic for reading user instructions out of call_undef_hook() and into a new user_insn_read() helper, matching the style of the existing aarch64_insn_read() helper used for reading kernel instructions. There should be no functional change as a result of this patch. Signed-off-by: Mark Rutland <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: James Morse <[email protected]> Cc: Joey Gouly <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Will Deacon <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent bff8f41 commit dbfbd87

File tree

1 file changed

+22
-9
lines changed

1 file changed

+22
-9
lines changed

arch/arm64/kernel/traps.c

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -394,44 +394,51 @@ void unregister_undef_hook(struct undef_hook *hook)
394394
raw_spin_unlock_irqrestore(&undef_lock, flags);
395395
}
396396

397-
static int call_undef_hook(struct pt_regs *regs)
397+
static int user_insn_read(struct pt_regs *regs, u32 *insnp)
398398
{
399-
struct undef_hook *hook;
400-
unsigned long flags;
401399
u32 instr;
402-
int (*fn)(struct pt_regs *regs, u32 instr) = NULL;
403400
unsigned long pc = instruction_pointer(regs);
404401

405402
if (compat_thumb_mode(regs)) {
406403
/* 16-bit Thumb instruction */
407404
__le16 instr_le;
408405
if (get_user(instr_le, (__le16 __user *)pc))
409-
goto exit;
406+
return -EFAULT;
410407
instr = le16_to_cpu(instr_le);
411408
if (aarch32_insn_is_wide(instr)) {
412409
u32 instr2;
413410

414411
if (get_user(instr_le, (__le16 __user *)(pc + 2)))
415-
goto exit;
412+
return -EFAULT;
416413
instr2 = le16_to_cpu(instr_le);
417414
instr = (instr << 16) | instr2;
418415
}
419416
} else {
420417
/* 32-bit ARM instruction */
421418
__le32 instr_le;
422419
if (get_user(instr_le, (__le32 __user *)pc))
423-
goto exit;
420+
return -EFAULT;
424421
instr = le32_to_cpu(instr_le);
425422
}
426423

424+
*insnp = instr;
425+
return 0;
426+
}
427+
428+
static int call_undef_hook(struct pt_regs *regs, u32 instr)
429+
{
430+
struct undef_hook *hook;
431+
unsigned long flags;
432+
int (*fn)(struct pt_regs *regs, u32 instr) = NULL;
433+
427434
raw_spin_lock_irqsave(&undef_lock, flags);
428435
list_for_each_entry(hook, &undef_hook, node)
429436
if ((instr & hook->instr_mask) == hook->instr_val &&
430437
(regs->pstate & hook->pstate_mask) == hook->pstate_val)
431438
fn = hook->fn;
432439

433440
raw_spin_unlock_irqrestore(&undef_lock, flags);
434-
exit:
441+
435442
return fn ? fn(regs, instr) : 1;
436443
}
437444

@@ -483,13 +490,19 @@ void arm64_notify_segfault(unsigned long addr)
483490

484491
void do_el0_undef(struct pt_regs *regs, unsigned long esr)
485492
{
493+
u32 insn;
494+
486495
/* check for AArch32 breakpoint instructions */
487496
if (!aarch32_break_handler(regs))
488497
return;
489498

490-
if (call_undef_hook(regs) == 0)
499+
if (user_insn_read(regs, &insn))
500+
goto out_err;
501+
502+
if (call_undef_hook(regs, insn) == 0)
491503
return;
492504

505+
out_err:
493506
force_signal_inject(SIGILL, ILL_ILLOPC, regs->pc, 0);
494507
}
495508

0 commit comments

Comments
 (0)