Commit 30f3f68e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux

Pull arm64 fixes from Will Deacon:
 "Here's the weekly batch of fixes for arm64. Not an awful lot here, but
  there are still a few unresolved issues relating to CPU hotplug, RCU
  and IRQ tracing that I hope to queue fixes for next week.

  Summary:

   - Fix early use of kprobes

   - Fix kernel placement in kexec_file_load()

   - Bump maximum number of NUMA nodes"

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  arm64: kexec_file: try more regions if loading segments fails
  arm64: kprobes: Use BRK instead of single-step when executing instructions out-of-line
  arm64: NUMA: Kconfig: Increase NODES_SHIFT to 4
parents 4257087e 108aa503
...@@ -1002,7 +1002,7 @@ config NUMA ...@@ -1002,7 +1002,7 @@ config NUMA
config NODES_SHIFT config NODES_SHIFT
int "Maximum NUMA Nodes (as a power of 2)" int "Maximum NUMA Nodes (as a power of 2)"
range 1 10 range 1 10
default "2" default "4"
depends on NEED_MULTIPLE_NODES depends on NEED_MULTIPLE_NODES
help help
Specify the maximum number of NUMA Nodes available on the target Specify the maximum number of NUMA Nodes available on the target
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* #imm16 values used for BRK instruction generation * #imm16 values used for BRK instruction generation
* 0x004: for installing kprobes * 0x004: for installing kprobes
* 0x005: for installing uprobes * 0x005: for installing uprobes
* 0x006: for kprobe software single-step
* Allowed values for kgdb are 0x400 - 0x7ff * Allowed values for kgdb are 0x400 - 0x7ff
* 0x100: for triggering a fault on purpose (reserved) * 0x100: for triggering a fault on purpose (reserved)
* 0x400: for dynamic BRK instruction * 0x400: for dynamic BRK instruction
...@@ -19,6 +20,7 @@ ...@@ -19,6 +20,7 @@
*/ */
#define KPROBES_BRK_IMM 0x004 #define KPROBES_BRK_IMM 0x004
#define UPROBES_BRK_IMM 0x005 #define UPROBES_BRK_IMM 0x005
#define KPROBES_BRK_SS_IMM 0x006
#define FAULT_BRK_IMM 0x100 #define FAULT_BRK_IMM 0x100
#define KGDB_DYN_DBG_BRK_IMM 0x400 #define KGDB_DYN_DBG_BRK_IMM 0x400
#define KGDB_COMPILED_DBG_BRK_IMM 0x401 #define KGDB_COMPILED_DBG_BRK_IMM 0x401
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
/* kprobes BRK opcodes with ESR encoding */ /* kprobes BRK opcodes with ESR encoding */
#define BRK64_OPCODE_KPROBES (AARCH64_BREAK_MON | (KPROBES_BRK_IMM << 5)) #define BRK64_OPCODE_KPROBES (AARCH64_BREAK_MON | (KPROBES_BRK_IMM << 5))
#define BRK64_OPCODE_KPROBES_SS (AARCH64_BREAK_MON | (KPROBES_BRK_SS_IMM << 5))
/* uprobes BRK opcodes with ESR encoding */ /* uprobes BRK opcodes with ESR encoding */
#define BRK64_OPCODE_UPROBES (AARCH64_BREAK_MON | (UPROBES_BRK_IMM << 5)) #define BRK64_OPCODE_UPROBES (AARCH64_BREAK_MON | (UPROBES_BRK_IMM << 5))
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <linux/percpu.h> #include <linux/percpu.h>
#define __ARCH_WANT_KPROBES_INSN_SLOT #define __ARCH_WANT_KPROBES_INSN_SLOT
#define MAX_INSN_SIZE 1 #define MAX_INSN_SIZE 2
#define flush_insn_slot(p) do { } while (0) #define flush_insn_slot(p) do { } while (0)
#define kretprobe_blacklist_size 0 #define kretprobe_blacklist_size 0
......
...@@ -43,7 +43,7 @@ static void *image_load(struct kimage *image, ...@@ -43,7 +43,7 @@ static void *image_load(struct kimage *image,
u64 flags, value; u64 flags, value;
bool be_image, be_kernel; bool be_image, be_kernel;
struct kexec_buf kbuf; struct kexec_buf kbuf;
unsigned long text_offset; unsigned long text_offset, kernel_segment_number;
struct kexec_segment *kernel_segment; struct kexec_segment *kernel_segment;
int ret; int ret;
...@@ -88,11 +88,37 @@ static void *image_load(struct kimage *image, ...@@ -88,11 +88,37 @@ static void *image_load(struct kimage *image,
/* Adjust kernel segment with TEXT_OFFSET */ /* Adjust kernel segment with TEXT_OFFSET */
kbuf.memsz += text_offset; kbuf.memsz += text_offset;
ret = kexec_add_buffer(&kbuf); kernel_segment_number = image->nr_segments;
if (ret)
/*
* The location of the kernel segment may make it impossible to satisfy
* the other segment requirements, so we try repeatedly to find a
* location that will work.
*/
while ((ret = kexec_add_buffer(&kbuf)) == 0) {
/* Try to load additional data */
kernel_segment = &image->segment[kernel_segment_number];
ret = load_other_segments(image, kernel_segment->mem,
kernel_segment->memsz, initrd,
initrd_len, cmdline);
if (!ret)
break;
/*
* We couldn't find space for the other segments; erase the
* kernel segment and try the next available hole.
*/
image->nr_segments -= 1;
kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
}
if (ret) {
pr_err("Could not find any suitable kernel location!");
return ERR_PTR(ret); return ERR_PTR(ret);
}
kernel_segment = &image->segment[image->nr_segments - 1]; kernel_segment = &image->segment[kernel_segment_number];
kernel_segment->mem += text_offset; kernel_segment->mem += text_offset;
kernel_segment->memsz -= text_offset; kernel_segment->memsz -= text_offset;
image->start = kernel_segment->mem; image->start = kernel_segment->mem;
...@@ -101,12 +127,7 @@ static void *image_load(struct kimage *image, ...@@ -101,12 +127,7 @@ static void *image_load(struct kimage *image,
kernel_segment->mem, kbuf.bufsz, kernel_segment->mem, kbuf.bufsz,
kernel_segment->memsz); kernel_segment->memsz);
/* Load additional data */ return 0;
ret = load_other_segments(image,
kernel_segment->mem, kernel_segment->memsz,
initrd, initrd_len, cmdline);
return ERR_PTR(ret);
} }
#ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG #ifdef CONFIG_KEXEC_IMAGE_VERIFY_SIG
......
...@@ -240,6 +240,11 @@ static int prepare_elf_headers(void **addr, unsigned long *sz) ...@@ -240,6 +240,11 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
return ret; return ret;
} }
/*
* Tries to add the initrd and DTB to the image. If it is not possible to find
* valid locations, this function will undo changes to the image and return non
* zero.
*/
int load_other_segments(struct kimage *image, int load_other_segments(struct kimage *image,
unsigned long kernel_load_addr, unsigned long kernel_load_addr,
unsigned long kernel_size, unsigned long kernel_size,
...@@ -248,7 +253,8 @@ int load_other_segments(struct kimage *image, ...@@ -248,7 +253,8 @@ int load_other_segments(struct kimage *image,
{ {
struct kexec_buf kbuf; struct kexec_buf kbuf;
void *headers, *dtb = NULL; void *headers, *dtb = NULL;
unsigned long headers_sz, initrd_load_addr = 0, dtb_len; unsigned long headers_sz, initrd_load_addr = 0, dtb_len,
orig_segments = image->nr_segments;
int ret = 0; int ret = 0;
kbuf.image = image; kbuf.image = image;
...@@ -334,6 +340,7 @@ int load_other_segments(struct kimage *image, ...@@ -334,6 +340,7 @@ int load_other_segments(struct kimage *image,
return 0; return 0;
out_err: out_err:
image->nr_segments = orig_segments;
vfree(dtb); vfree(dtb);
return ret; return ret;
} }
...@@ -36,25 +36,16 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); ...@@ -36,25 +36,16 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
static void __kprobes static void __kprobes
post_kprobe_handler(struct kprobe_ctlblk *, struct pt_regs *); post_kprobe_handler(struct kprobe_ctlblk *, struct pt_regs *);
static int __kprobes patch_text(kprobe_opcode_t *addr, u32 opcode)
{
void *addrs[1];
u32 insns[1];
addrs[0] = addr;
insns[0] = opcode;
return aarch64_insn_patch_text(addrs, insns, 1);
}
static void __kprobes arch_prepare_ss_slot(struct kprobe *p) static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
{ {
kprobe_opcode_t *addr = p->ainsn.api.insn;
void *addrs[] = {addr, addr + 1};
u32 insns[] = {p->opcode, BRK64_OPCODE_KPROBES_SS};
/* prepare insn slot */ /* prepare insn slot */
patch_text(p->ainsn.api.insn, p->opcode); aarch64_insn_patch_text(addrs, insns, 2);
flush_icache_range((uintptr_t) (p->ainsn.api.insn), flush_icache_range((uintptr_t)addr, (uintptr_t)(addr + MAX_INSN_SIZE));
(uintptr_t) (p->ainsn.api.insn) +
MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
/* /*
* Needs restoring of return address after stepping xol. * Needs restoring of return address after stepping xol.
...@@ -128,13 +119,18 @@ void *alloc_insn_page(void) ...@@ -128,13 +119,18 @@ void *alloc_insn_page(void)
/* arm kprobe: install breakpoint in text */ /* arm kprobe: install breakpoint in text */
void __kprobes arch_arm_kprobe(struct kprobe *p) void __kprobes arch_arm_kprobe(struct kprobe *p)
{ {
patch_text(p->addr, BRK64_OPCODE_KPROBES); void *addr = p->addr;
u32 insn = BRK64_OPCODE_KPROBES;
aarch64_insn_patch_text(&addr, &insn, 1);
} }
/* disarm kprobe: remove breakpoint from text */ /* disarm kprobe: remove breakpoint from text */
void __kprobes arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_disarm_kprobe(struct kprobe *p)
{ {
patch_text(p->addr, p->opcode); void *addr = p->addr;
aarch64_insn_patch_text(&addr, &p->opcode, 1);
} }
void __kprobes arch_remove_kprobe(struct kprobe *p) void __kprobes arch_remove_kprobe(struct kprobe *p)
...@@ -163,20 +159,15 @@ static void __kprobes set_current_kprobe(struct kprobe *p) ...@@ -163,20 +159,15 @@ static void __kprobes set_current_kprobe(struct kprobe *p)
} }
/* /*
* Interrupts need to be disabled before single-step mode is set, and not * Mask all of DAIF while executing the instruction out-of-line, to keep things
* reenabled until after single-step mode ends. * simple and avoid nesting exceptions. Interrupts do have to be disabled since
* Without disabling interrupt on local CPU, there is a chance of * the kprobe state is per-CPU and doesn't get migrated.
* interrupt occurrence in the period of exception return and start of
* out-of-line single-step, that result in wrongly single stepping
* into the interrupt handler.
*/ */
static void __kprobes kprobes_save_local_irqflag(struct kprobe_ctlblk *kcb, static void __kprobes kprobes_save_local_irqflag(struct kprobe_ctlblk *kcb,
struct pt_regs *regs) struct pt_regs *regs)
{ {
kcb->saved_irqflag = regs->pstate & DAIF_MASK; kcb->saved_irqflag = regs->pstate & DAIF_MASK;
regs->pstate |= PSR_I_BIT; regs->pstate |= DAIF_MASK;
/* Unmask PSTATE.D for enabling software step exceptions. */
regs->pstate &= ~PSR_D_BIT;
} }
static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb, static void __kprobes kprobes_restore_local_irqflag(struct kprobe_ctlblk *kcb,
...@@ -219,10 +210,7 @@ static void __kprobes setup_singlestep(struct kprobe *p, ...@@ -219,10 +210,7 @@ static void __kprobes setup_singlestep(struct kprobe *p,
slot = (unsigned long)p->ainsn.api.insn; slot = (unsigned long)p->ainsn.api.insn;
set_ss_context(kcb, slot); /* mark pending ss */ set_ss_context(kcb, slot); /* mark pending ss */
/* IRQs and single stepping do not mix well. */
kprobes_save_local_irqflag(kcb, regs); kprobes_save_local_irqflag(kcb, regs);
kernel_enable_single_step(regs);
instruction_pointer_set(regs, slot); instruction_pointer_set(regs, slot);
} else { } else {
/* insn simulation */ /* insn simulation */
...@@ -273,12 +261,8 @@ post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs) ...@@ -273,12 +261,8 @@ post_kprobe_handler(struct kprobe_ctlblk *kcb, struct pt_regs *regs)
} }
/* call post handler */ /* call post handler */
kcb->kprobe_status = KPROBE_HIT_SSDONE; kcb->kprobe_status = KPROBE_HIT_SSDONE;
if (cur->post_handler) { if (cur->post_handler)
/* post_handler can hit breakpoint and single step
* again, so we enable D-flag for recursive exception.
*/
cur->post_handler(cur, regs, 0); cur->post_handler(cur, regs, 0);
}
reset_current_kprobe(); reset_current_kprobe();
} }
...@@ -302,8 +286,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr) ...@@ -302,8 +286,6 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
if (!instruction_pointer(regs)) if (!instruction_pointer(regs))
BUG(); BUG();
kernel_disable_single_step();
if (kcb->kprobe_status == KPROBE_REENTER) if (kcb->kprobe_status == KPROBE_REENTER)
restore_previous_kprobe(kcb); restore_previous_kprobe(kcb);
else else
...@@ -365,10 +347,6 @@ static void __kprobes kprobe_handler(struct pt_regs *regs) ...@@ -365,10 +347,6 @@ static void __kprobes kprobe_handler(struct pt_regs *regs)
* pre-handler and it returned non-zero, it will * pre-handler and it returned non-zero, it will
* modify the execution path and no need to single * modify the execution path and no need to single
* stepping. Let's just reset current kprobe and exit. * stepping. Let's just reset current kprobe and exit.
*
* pre_handler can hit a breakpoint and can step thru
* before return, keep PSTATE D-flag enabled until
* pre_handler return back.
*/ */
if (!p->pre_handler || !p->pre_handler(p, regs)) { if (!p->pre_handler || !p->pre_handler(p, regs)) {
setup_singlestep(p, regs, kcb, 0); setup_singlestep(p, regs, kcb, 0);
...@@ -399,7 +377,7 @@ kprobe_ss_hit(struct kprobe_ctlblk *kcb, unsigned long addr) ...@@ -399,7 +377,7 @@ kprobe_ss_hit(struct kprobe_ctlblk *kcb, unsigned long addr)
} }
static int __kprobes static int __kprobes
kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr) kprobe_breakpoint_ss_handler(struct pt_regs *regs, unsigned int esr)
{ {
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
int retval; int retval;
...@@ -409,16 +387,15 @@ kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr) ...@@ -409,16 +387,15 @@ kprobe_single_step_handler(struct pt_regs *regs, unsigned int esr)
if (retval == DBG_HOOK_HANDLED) { if (retval == DBG_HOOK_HANDLED) {
kprobes_restore_local_irqflag(kcb, regs); kprobes_restore_local_irqflag(kcb, regs);
kernel_disable_single_step();
post_kprobe_handler(kcb, regs); post_kprobe_handler(kcb, regs);
} }
return retval; return retval;
} }
static struct step_hook kprobes_step_hook = { static struct break_hook kprobes_break_ss_hook = {
.fn = kprobe_single_step_handler, .imm = KPROBES_BRK_SS_IMM,
.fn = kprobe_breakpoint_ss_handler,
}; };
static int __kprobes static int __kprobes
...@@ -486,7 +463,7 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p) ...@@ -486,7 +463,7 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p)
int __init arch_init_kprobes(void) int __init arch_init_kprobes(void)
{ {
register_kernel_break_hook(&kprobes_break_hook); register_kernel_break_hook(&kprobes_break_hook);
register_kernel_step_hook(&kprobes_step_hook); register_kernel_break_hook(&kprobes_break_ss_hook);
return 0; return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment