Merge branch 'devel-stable' into for-next

This commit is contained in:
Russell King 2015-02-10 10:26:38 +00:00
commit df9ab9771c
290 changed files with 3777 additions and 2664 deletions

View File

@ -10,12 +10,13 @@ Optional properties:
Each button (key) is represented as a sub-node of "gpio-keys":
Subnode properties:
- gpios: OF device-tree gpio specification.
- interrupts: the interrupt line for that input.
- label: Descriptive name of the key.
- linux,code: Keycode to emit.
Required mutual exclusive subnode-properties:
- gpios: OF device-tree gpio specification.
- interrupts: the interrupt line for that input
Note that either "interrupts" or "gpios" properties can be omitted, but not
both at the same time. Specifying both properties is allowed.
Optional subnode-properties:
- linux,input-type: Specify event type this button/key generates.
@ -23,6 +24,9 @@ Optional subnode-properties:
- debounce-interval: Debouncing interval time in milliseconds.
If not specified defaults to 5.
- gpio-key,wakeup: Boolean, button can wake-up the system.
- linux,can-disable: Boolean, indicates that button is connected
to dedicated (not shared) interrupt which can be disabled to
suppress events from the button.
Example nodes:

View File

@ -8,6 +8,8 @@ Optional properties:
- debounce-interval : Debouncing interval time in milliseconds
- st,scan-count : Scanning cycles elapsed before key data is updated
- st,no-autorepeat : If specified device will not autorepeat
- keypad,num-rows : See ./matrix-keymap.txt
- keypad,num-columns : See ./matrix-keymap.txt
Example:

View File

@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 19
SUBLEVEL = 0
EXTRAVERSION = -rc1
EXTRAVERSION = -rc3
NAME = Diseased Newt
# *DOCUMENTATION*

View File

@ -61,6 +61,7 @@ config ARM
select HAVE_MEMBLOCK
select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
select HAVE_OPTPROBES if !THUMB2_KERNEL
select HAVE_PERF_EVENTS
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP

View File

@ -266,6 +266,7 @@ core-$(CONFIG_KVM_ARM_HOST) += arch/arm/kvm/
# If we have a machine-specific directory, then include it in the build.
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y += arch/arm/probes/
core-y += arch/arm/net/
core-y += arch/arm/crypto/
core-y += arch/arm/firmware/

View File

@ -203,27 +203,3 @@
compatible = "linux,spdif-dir";
};
};
&pinctrl {
/*
* These pins might be muxed as I2S by
* the bootloader, but it conflicts
* with the real I2S pins that are
* muxed using i2s_pins. We must mux
* those pins to a function other than
* I2S.
*/
pinctrl-0 = <&hog_pins1 &hog_pins2>;
pinctrl-names = "default";
hog_pins1: hog-pins1 {
marvell,pins = "mpp6", "mpp8", "mpp10",
"mpp12", "mpp13";
marvell,function = "gpio";
};
hog_pins2: hog-pins2 {
marvell,pins = "mpp5", "mpp7", "mpp9";
marvell,function = "gpo";
};
};

View File

@ -338,6 +338,7 @@ CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_MVEBU=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_EXYNOS=y
CONFIG_USB_EHCI_TEGRA=y
CONFIG_USB_EHCI_HCD_STI=y
CONFIG_USB_EHCI_HCD_PLATFORM=y

View File

@ -22,7 +22,6 @@
#define __ARCH_WANT_KPROBES_INSN_SLOT
#define MAX_INSN_SIZE 2
#define MAX_STACK_SIZE 64 /* 32 would probably be OK */
#define flush_insn_slot(p) do { } while (0)
#define kretprobe_blacklist_size 0
@ -51,5 +50,37 @@ int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
/* optinsn template addresses */
extern __visible kprobe_opcode_t optprobe_template_entry;
extern __visible kprobe_opcode_t optprobe_template_val;
extern __visible kprobe_opcode_t optprobe_template_call;
extern __visible kprobe_opcode_t optprobe_template_end;
extern __visible kprobe_opcode_t optprobe_template_sub_sp;
extern __visible kprobe_opcode_t optprobe_template_add_sp;
extern __visible kprobe_opcode_t optprobe_template_restore_begin;
extern __visible kprobe_opcode_t optprobe_template_restore_orig_insn;
extern __visible kprobe_opcode_t optprobe_template_restore_end;
#define MAX_OPTIMIZED_LENGTH 4
#define MAX_OPTINSN_SIZE \
((unsigned long)&optprobe_template_end - \
(unsigned long)&optprobe_template_entry)
#define RELATIVEJUMP_SIZE 4
struct arch_optimized_insn {
/*
* copy of the original instructions.
* Different from x86, ARM kprobe_opcode_t is u32.
*/
#define MAX_COPIED_INSN DIV_ROUND_UP(RELATIVEJUMP_SIZE, sizeof(kprobe_opcode_t))
kprobe_opcode_t copied_insn[MAX_COPIED_INSN];
/* detour code buffer */
kprobe_opcode_t *insn;
/*
* We always copy one instruction on ARM,
* so size will always be 4, and unlike x86, there is no
* need for a size field.
*/
};
#endif /* _ARM_KPROBES_H */

View File

@ -19,6 +19,8 @@
#ifndef _ASM_PROBES_H
#define _ASM_PROBES_H
#ifndef __ASSEMBLY__
typedef u32 probes_opcode_t;
struct arch_probes_insn;
@ -38,6 +40,19 @@ struct arch_probes_insn {
probes_check_cc *insn_check_cc;
probes_insn_singlestep_t *insn_singlestep;
probes_insn_fn_t *insn_fn;
int stack_space;
unsigned long register_usage_flags;
bool kprobe_direct_exec;
};
#endif /* __ASSEMBLY__ */
/*
* We assume one instruction can consume at most 64 bytes stack, which is
* 'push {r0-r15}'. Instructions consume more or unknown stack space like
* 'str r0, [sp, #-80]' and 'str r0, [sp, r1]' should be prohibit to probe.
* Both kprobe and jprobe use this macro.
*/
#define MAX_STACK_SIZE 64
#endif

View File

@ -51,20 +51,8 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_UPROBES) += probes.o probes-arm.o uprobes.o uprobes-arm.o
obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o
ifdef CONFIG_THUMB2_KERNEL
obj-$(CONFIG_KPROBES) += kprobes-thumb.o probes-thumb.o
else
obj-$(CONFIG_KPROBES) += kprobes-arm.o probes-arm.o
endif
obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
test-kprobes-objs := kprobes-test.o
ifdef CONFIG_THUMB2_KERNEL
test-kprobes-objs += kprobes-test-thumb.o
else
test-kprobes-objs += kprobes-test-arm.o
endif
# Main staffs in KPROBES are in arch/arm/probes/ .
obj-$(CONFIG_KPROBES) += patch.o insn.o
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
obj-$(CONFIG_KGDB) += kgdb.o patch.o

View File

@ -31,6 +31,7 @@
#include "entry-header.S"
#include <asm/entry-macro-multi.S>
#include <asm/probes.h>
/*
* Interrupt handling.
@ -249,7 +250,7 @@ __und_svc:
@ If a kprobe is about to simulate a "stmdb sp..." instruction,
@ it obviously needs free stack space which then will belong to
@ the saved context.
svc_entry 64
svc_entry MAX_STACK_SIZE
#else
svc_entry
#endif

View File

@ -20,8 +20,7 @@
#include <asm/cacheflush.h>
#include <asm/opcodes.h>
#include <asm/ftrace.h>
#include "insn.h"
#include <asm/insn.h>
#ifdef CONFIG_THUMB2_KERNEL
#define NOP 0xf85deb04 /* pop.w {lr} */

View File

@ -1,8 +1,7 @@
#include <linux/kernel.h>
#include <linux/jump_label.h>
#include "insn.h"
#include "patch.h"
#include <asm/patch.h>
#include <asm/insn.h>
#ifdef HAVE_JUMP_LABEL

View File

@ -14,10 +14,9 @@
#include <linux/kgdb.h>
#include <linux/uaccess.h>
#include <asm/patch.h>
#include <asm/traps.h>
#include "patch.h"
struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
{
{ "r0", 4, offsetof(struct pt_regs, ARM_r0)},

View File

@ -8,8 +8,7 @@
#include <asm/fixmap.h>
#include <asm/smp_plat.h>
#include <asm/opcodes.h>
#include "patch.h"
#include <asm/patch.h>
struct patch {
void *addr;

View File

@ -1049,6 +1049,15 @@ static int c_show(struct seq_file *m, void *v)
seq_printf(m, "model name\t: %s rev %d (%s)\n",
cpu_name, cpuid & 15, elf_platform);
#if defined(CONFIG_SMP)
seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
(per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
#else
seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
loops_per_jiffy / (500000/HZ),
(loops_per_jiffy / (5000/HZ)) % 100);
#endif
/* dump out the processor features */
seq_puts(m, "Features\t: ");

View File

@ -387,6 +387,18 @@ asmlinkage void secondary_start_kernel(void)
void __init smp_cpus_done(unsigned int max_cpus)
{
int cpu;
unsigned long bogosum = 0;
for_each_online_cpu(cpu)
bogosum += per_cpu(cpu_data, cpu).loops_per_jiffy;
printk(KERN_INFO "SMP: Total of %d processors activated "
"(%lu.%02lu BogoMIPS).\n",
num_online_cpus(),
bogosum / (500000/HZ),
(bogosum / (5000/HZ)) % 100);
hyp_mode_check();
}

7
arch/arm/probes/Makefile Normal file
View File

@ -0,0 +1,7 @@
obj-$(CONFIG_UPROBES) += decode.o decode-arm.o uprobes/
obj-$(CONFIG_KPROBES) += decode.o kprobes/
ifdef CONFIG_THUMB2_KERNEL
obj-$(CONFIG_KPROBES) += decode-thumb.o
else
obj-$(CONFIG_KPROBES) += decode-arm.o
endif

View File

@ -1,5 +1,6 @@
/*
* arch/arm/kernel/probes-arm.c
*
* arch/arm/probes/decode-arm.c
*
* Some code moved here from arch/arm/kernel/kprobes-arm.c
*
@ -20,8 +21,8 @@
#include <linux/stddef.h>
#include <linux/ptrace.h>
#include "probes.h"
#include "probes-arm.h"
#include "decode.h"
#include "decode-arm.h"
#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
@ -369,17 +370,17 @@ static const union decode_item arm_cccc_001x_table[] = {
/* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */
/* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */
DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_DATA_PROCESSING_IMM,
DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_MOV_HALFWORD,
REGS(0, NOPC, 0, 0, 0)),
/* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */
DECODE_OR (0x0fff00ff, 0x03200001),
/* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */
DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_EMULATE_NONE),
DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_SEV),
/* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */
/* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */
/* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */
DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_SIMULATE_NOP),
DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_WFE),
/* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */
/* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */
/* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */
@ -725,10 +726,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn,
*/
enum probes_insn __kprobes
arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions)
bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[])
{
asi->insn_singlestep = arm_singlestep;
asi->insn_check_cc = probes_condition_checks[insn>>28];
return probes_decode_insn(insn, asi, probes_decode_arm_table, false,
emulate, actions);
emulate, actions, checkers);
}

View File

@ -1,5 +1,5 @@
/*
* arch/arm/kernel/probes-arm.h
* arch/arm/probes/decode-arm.h
*
* Copyright 2013 Linaro Ltd.
* Written by: David A. Long
@ -15,9 +15,9 @@
#ifndef _ARM_KERNEL_PROBES_ARM_H
#define _ARM_KERNEL_PROBES_ARM_H
#include "decode.h"
enum probes_arm_action {
PROBES_EMULATE_NONE,
PROBES_SIMULATE_NOP,
PROBES_PRELOAD_IMM,
PROBES_PRELOAD_REG,
PROBES_BRANCH_IMM,
@ -68,6 +68,7 @@ extern const union decode_item probes_decode_arm_table[];
enum probes_insn arm_probes_decode_insn(probes_opcode_t,
struct arch_probes_insn *, bool emulate,
const union decode_action *actions);
const union decode_action *actions,
const struct decode_checker *checkers[]);
#endif

View File

@ -1,5 +1,5 @@
/*
* arch/arm/kernel/probes-thumb.c
* arch/arm/probes/decode-thumb.c
*
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
*
@ -12,8 +12,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include "probes.h"
#include "probes-thumb.h"
#include "decode.h"
#include "decode-thumb.h"
static const union decode_item t32_table_1110_100x_x0xx[] = {
@ -863,20 +863,22 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode,
enum probes_insn __kprobes
thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions)
bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[])
{
asi->insn_singlestep = thumb16_singlestep;
asi->insn_check_cc = thumb_check_cc;
return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true,
emulate, actions);
emulate, actions, checkers);
}
enum probes_insn __kprobes
thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions)
bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[])
{
asi->insn_singlestep = thumb32_singlestep;
asi->insn_check_cc = thumb_check_cc;
return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true,
emulate, actions);
emulate, actions, checkers);
}

View File

@ -1,5 +1,5 @@
/*
* arch/arm/kernel/probes-thumb.h
* arch/arm/probes/decode-thumb.h
*
* Copyright 2013 Linaro Ltd.
* Written by: David A. Long
@ -15,6 +15,8 @@
#ifndef _ARM_KERNEL_PROBES_THUMB_H
#define _ARM_KERNEL_PROBES_THUMB_H
#include "decode.h"
/*
* True if current instruction is in an IT block.
*/
@ -89,9 +91,11 @@ extern const union decode_item probes_decode_thumb16_table[];
enum probes_insn __kprobes
thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions);
bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[]);
enum probes_insn __kprobes
thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
bool emulate, const union decode_action *actions);
bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[]);
#endif

View File

@ -1,5 +1,5 @@
/*
* arch/arm/kernel/probes.c
* arch/arm/probes/decode.c
*
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
*
@ -17,7 +17,7 @@
#include <asm/ptrace.h>
#include <linux/bug.h>
#include "probes.h"
#include "decode.h"
#ifndef find_str_pc_offset
@ -342,6 +342,31 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
[DECODE_TYPE_REJECT] = sizeof(struct decode_reject)
};
static int run_checkers(const struct decode_checker *checkers[],
int action, probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
const struct decode_checker **p;
if (!checkers)
return INSN_GOOD;
p = checkers;
while (*p != NULL) {
int retval;
probes_check_t *checker_func = (*p)[action].checker;
retval = INSN_GOOD;
if (checker_func)
retval = checker_func(insn, asi, h);
if (retval == INSN_REJECTED)
return retval;
p++;
}
return INSN_GOOD;
}
/*
* probes_decode_insn operates on data tables in order to decode an ARM
* architecture instruction onto which a kprobe has been placed.
@ -388,11 +413,34 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
int __kprobes
probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
const union decode_item *table, bool thumb,
bool emulate, const union decode_action *actions)
bool emulate, const union decode_action *actions,
const struct decode_checker *checkers[])
{
const struct decode_header *h = (struct decode_header *)table;
const struct decode_header *next;
bool matched = false;
/*
* @insn can be modified by decode_regs. Save its original
* value for checkers.
*/
probes_opcode_t origin_insn = insn;
/*
* stack_space is initialized to 0 here. Checker functions
* should update is value if they find this is a stack store
* instruction: positive value means bytes of stack usage,
* negitive value means unable to determine stack usage
* statically. For instruction doesn't store to stack, checker
* do nothing with it.
*/
asi->stack_space = 0;
/*
* Similarly to stack_space, register_usage_flags is filled by
* checkers. Its default value is set to ~0, which is 'all
* registers are used', to prevent any potential optimization.
*/
asi->register_usage_flags = ~0UL;
if (emulate)
insn = prepare_emulated_insn(insn, asi, thumb);
@ -422,24 +470,41 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
}
case DECODE_TYPE_CUSTOM: {
int err;
struct decode_custom *d = (struct decode_custom *)h;
return actions[d->decoder.action].decoder(insn, asi, h);
int action = d->decoder.action;
err = run_checkers(checkers, action, origin_insn, asi, h);
if (err == INSN_REJECTED)
return INSN_REJECTED;
return actions[action].decoder(insn, asi, h);
}
case DECODE_TYPE_SIMULATE: {
int err;
struct decode_simulate *d = (struct decode_simulate *)h;
asi->insn_handler = actions[d->handler.action].handler;
int action = d->handler.action;
err = run_checkers(checkers, action, origin_insn, asi, h);
if (err == INSN_REJECTED)
return INSN_REJECTED;
asi->insn_handler = actions[action].handler;
return INSN_GOOD_NO_SLOT;
}
case DECODE_TYPE_EMULATE: {
int err;
struct decode_emulate *d = (struct decode_emulate *)h;
int action = d->handler.action;
err = run_checkers(checkers, action, origin_insn, asi, h);
if (err == INSN_REJECTED)
return INSN_REJECTED;
if (!emulate)
return actions[d->handler.action].decoder(insn,
asi, h);
return actions[action].decoder(insn, asi, h);
asi->insn_handler = actions[d->handler.action].handler;
asi->insn_handler = actions[action].handler;
set_emulated_insn(insn, asi, thumb);
return INSN_GOOD;
}

View File

@ -1,5 +1,5 @@
/*
* arch/arm/kernel/probes.h
* arch/arm/probes/decode.h
*
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
*
@ -314,6 +314,14 @@ union decode_action {
probes_custom_decode_t *decoder;
};
typedef enum probes_insn (probes_check_t)(probes_opcode_t,
struct arch_probes_insn *,
const struct decode_header *);
struct decode_checker {
probes_check_t *checker;
};
#define DECODE_END \
{.bits = DECODE_TYPE_END}
@ -402,6 +410,7 @@ probes_insn_handler_t probes_emulate_none;
int __kprobes
probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
const union decode_item *table, bool thumb, bool emulate,
const union decode_action *actions);
const union decode_action *actions,
const struct decode_checker **checkers);
#endif

View File

@ -0,0 +1,12 @@
obj-$(CONFIG_KPROBES) += core.o actions-common.o checkers-common.o
obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
test-kprobes-objs := test-core.o
ifdef CONFIG_THUMB2_KERNEL
obj-$(CONFIG_KPROBES) += actions-thumb.o checkers-thumb.o
test-kprobes-objs += test-thumb.o
else
obj-$(CONFIG_KPROBES) += actions-arm.o checkers-arm.o
obj-$(CONFIG_OPTPROBES) += opt-arm.o
test-kprobes-objs += test-arm.o
endif

View File

@ -1,5 +1,5 @@
/*
* arch/arm/kernel/kprobes-decode.c
* arch/arm/probes/kprobes/actions-arm.c
*
* Copyright (C) 2006, 2007 Motorola Inc.
*
@ -62,8 +62,9 @@
#include <linux/kprobes.h>
#include <linux/ptrace.h>
#include "kprobes.h"
#include "probes-arm.h"
#include "../decode-arm.h"
#include "core.h"
#include "checkers.h"
#if __LINUX_ARM_ARCH__ >= 6
#define BLX(reg) "blx "reg" \n\t"
@ -302,8 +303,6 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
}
const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
[PROBES_EMULATE_NONE] = {.handler = probes_emulate_none},
[PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
[PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
[PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
[PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
@ -341,3 +340,5 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
[PROBES_BRANCH] = {.handler = simulate_bbl},
[PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
};
const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};

View File

@ -1,5 +1,5 @@
/*
* arch/arm/kernel/kprobes-common.c
* arch/arm/probes/kprobes/actions-common.c
*
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
*
@ -15,7 +15,7 @@
#include <linux/kprobes.h>
#include <asm/opcodes.h>
#include "kprobes.h"
#include "core.h"
static void __kprobes simulate_ldm1stm1(probes_opcode_t insn,

View File

@ -1,5 +1,5 @@
/*
* arch/arm/kernel/kprobes-thumb.c
* arch/arm/probes/kprobes/actions-thumb.c
*
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
*
@ -13,8 +13,9 @@
#include <linux/ptrace.h>
#include <linux/kprobes.h>
#include "kprobes.h"
#include "probes-thumb.h"
#include "../decode-thumb.h"
#include "core.h"
#include "checkers.h"
/* These emulation encodings are functionally equivalent... */
#define t32_emulate_rd8rn16rm0ra12_noflags \
@ -664,3 +665,6 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
[PROBES_T32_MUL_ADD_LONG] = {
.handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
};
const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker, NULL};
const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker, NULL};

View File

@ -0,0 +1,192 @@
/*
* arch/arm/probes/kprobes/checkers-arm.c
*
* Copyright (C) 2014 Huawei Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/kernel.h>
#include "../decode.h"
#include "../decode-arm.h"
#include "checkers.h"
static enum probes_insn __kprobes arm_check_stack(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
/*
* PROBES_LDRSTRD, PROBES_LDMSTM, PROBES_STORE,
* PROBES_STORE_EXTRA may get here. Simply mark all normal
* insns as STACK_USE_NONE.
*/
static const union decode_item table[] = {
/*
* 'STR{,D,B,H}, Rt, [Rn, Rm]' should be marked as UNKNOWN
* if Rn or Rm is SP.
* x
* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx
* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx
*/
DECODE_OR (0x0e10000f, 0x0600000d),
DECODE_OR (0x0e1f0000, 0x060d0000),
/*
* x
* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx
* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx
*/
DECODE_OR (0x0e5000bf, 0x000000bd),
DECODE_CUSTOM (0x0e5f00b0, 0x000d00b0, STACK_USE_UNKNOWN),
/*
* For PROBES_LDMSTM, only stmdx sp, [...] need to examine
*
* Bit B/A (bit 24) encodes arithmetic operation order. 1 means
* before, 0 means after.
* Bit I/D (bit 23) encodes arithmetic operation. 1 means
* increment, 0 means decrement.
*
* So:
* B I
* / /
* A D | Rn |
* STMDX SP, [...] cccc 100x 00x0 xxxx xxxx xxxx xxxx xxxx
*/
DECODE_CUSTOM (0x0edf0000, 0x080d0000, STACK_USE_STMDX),
/* P U W | Rn | Rt | imm12 |*/
/* STR (immediate) cccc 010x x0x0 1101 xxxx xxxx xxxx xxxx */
/* STRB (immediate) cccc 010x x1x0 1101 xxxx xxxx xxxx xxxx */
/* P U W | Rn | Rt |imm4| |imm4|*/
/* STRD (immediate) cccc 000x x1x0 1101 xxxx xxxx 1111 xxxx */
/* STRH (immediate) cccc 000x x1x0 1101 xxxx xxxx 1011 xxxx */
/*
* index = (P == '1'); add = (U == '1').
* Above insns with:
* index == 0 (str{,d,h} rx, [sp], #+/-imm) or
* add == 1 (str{,d,h} rx, [sp, #+<imm>])
* should be STACK_USE_NONE.
* Only str{,b,d,h} rx,[sp,#-n] (P == 1 and U == 0) are
* required to be examined.
*/
/* STR{,B} Rt,[SP,#-n] cccc 0101 0xx0 1101 xxxx xxxx xxxx xxxx */
DECODE_CUSTOM (0x0f9f0000, 0x050d0000, STACK_USE_FIXED_XXX),
/* STR{D,H} Rt,[SP,#-n] cccc 0001 01x0 1101 xxxx xxxx 1x11 xxxx */
DECODE_CUSTOM (0x0fdf00b0, 0x014d00b0, STACK_USE_FIXED_X0X),
/* fall through */
DECODE_CUSTOM (0, 0, STACK_USE_NONE),
DECODE_END
};
return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL);
}
const struct decode_checker arm_stack_checker[NUM_PROBES_ARM_ACTIONS] = {
[PROBES_LDRSTRD] = {.checker = arm_check_stack},
[PROBES_STORE_EXTRA] = {.checker = arm_check_stack},
[PROBES_STORE] = {.checker = arm_check_stack},
[PROBES_LDMSTM] = {.checker = arm_check_stack},
};
static enum probes_insn __kprobes arm_check_regs_nouse(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
asi->register_usage_flags = 0;
return INSN_GOOD;
}
static enum probes_insn arm_check_regs_normal(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
int i;
asi->register_usage_flags = 0;
for (i = 0; i < 5; regs >>= 4, insn >>= 4, i++)
if (regs & 0xf)
asi->register_usage_flags |= 1 << (insn & 0xf);
return INSN_GOOD;
}
static enum probes_insn arm_check_regs_ldmstm(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
unsigned int reglist = insn & 0xffff;
unsigned int rn = (insn >> 16) & 0xf;
asi->register_usage_flags = reglist | (1 << rn);
return INSN_GOOD;
}
static enum probes_insn arm_check_regs_mov_ip_sp(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
/* Instruction is 'mov ip, sp' i.e. 'mov r12, r13' */
asi->register_usage_flags = (1 << 12) | (1<< 13);
return INSN_GOOD;
}
/*
* | Rn |Rt/d| | Rm |
* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx
* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx
* | Rn |Rt/d| |imm4L|
* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx
* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx
*
* Such instructions access Rt/d and its next register, so different
* from others, a specific checker is required to handle this extra
* implicit register usage.
*/
static enum probes_insn arm_check_regs_ldrdstrd(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
int rdt = (insn >> 12) & 0xf;
arm_check_regs_normal(insn, asi, h);
asi->register_usage_flags |= 1 << (rdt + 1);
return INSN_GOOD;
}
const struct decode_checker arm_regs_checker[NUM_PROBES_ARM_ACTIONS] = {
[PROBES_MRS] = {.checker = arm_check_regs_normal},
[PROBES_SATURATING_ARITHMETIC] = {.checker = arm_check_regs_normal},
[PROBES_MUL1] = {.checker = arm_check_regs_normal},
[PROBES_MUL2] = {.checker = arm_check_regs_normal},
[PROBES_MUL_ADD_LONG] = {.checker = arm_check_regs_normal},
[PROBES_MUL_ADD] = {.checker = arm_check_regs_normal},
[PROBES_LOAD] = {.checker = arm_check_regs_normal},
[PROBES_LOAD_EXTRA] = {.checker = arm_check_regs_normal},
[PROBES_STORE] = {.checker = arm_check_regs_normal},
[PROBES_STORE_EXTRA] = {.checker = arm_check_regs_normal},
[PROBES_DATA_PROCESSING_REG] = {.checker = arm_check_regs_normal},
[PROBES_DATA_PROCESSING_IMM] = {.checker = arm_check_regs_normal},
[PROBES_SEV] = {.checker = arm_check_regs_nouse},
[PROBES_WFE] = {.checker = arm_check_regs_nouse},
[PROBES_SATURATE] = {.checker = arm_check_regs_normal},
[PROBES_REV] = {.checker = arm_check_regs_normal},
[PROBES_MMI] = {.checker = arm_check_regs_normal},
[PROBES_PACK] = {.checker = arm_check_regs_normal},
[PROBES_EXTEND] = {.checker = arm_check_regs_normal},
[PROBES_EXTEND_ADD] = {.checker = arm_check_regs_normal},
[PROBES_BITFIELD] = {.checker = arm_check_regs_normal},
[PROBES_LDMSTM] = {.checker = arm_check_regs_ldmstm},
[PROBES_MOV_IP_SP] = {.checker = arm_check_regs_mov_ip_sp},
[PROBES_LDRSTRD] = {.checker = arm_check_regs_ldrdstrd},
};

View File

@ -0,0 +1,101 @@
/*
* arch/arm/probes/kprobes/checkers-common.c
*
* Copyright (C) 2014 Huawei Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/kernel.h>
#include "../decode.h"
#include "../decode-arm.h"
#include "checkers.h"
enum probes_insn checker_stack_use_none(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
asi->stack_space = 0;
return INSN_GOOD_NO_SLOT;
}
enum probes_insn checker_stack_use_unknown(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
asi->stack_space = -1;
return INSN_GOOD_NO_SLOT;
}
#ifdef CONFIG_THUMB2_KERNEL
enum probes_insn checker_stack_use_imm_0xx(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
int imm = insn & 0xff;
asi->stack_space = imm;
return INSN_GOOD_NO_SLOT;
}
/*
* Different from other insn uses imm8, the real addressing offset of
* STRD in T32 encoding should be imm8 * 4. See ARMARM description.
*/
enum probes_insn checker_stack_use_t32strd(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
int imm = insn & 0xff;
asi->stack_space = imm << 2;
return INSN_GOOD_NO_SLOT;
}
#else
enum probes_insn checker_stack_use_imm_x0x(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
int imm = ((insn & 0xf00) >> 4) + (insn & 0xf);
asi->stack_space = imm;
return INSN_GOOD_NO_SLOT;
}
#endif
enum probes_insn checker_stack_use_imm_xxx(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
int imm = insn & 0xfff;
asi->stack_space = imm;
return INSN_GOOD_NO_SLOT;
}
enum probes_insn checker_stack_use_stmdx(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
unsigned int reglist = insn & 0xffff;
int pbit = insn & (1 << 24);
asi->stack_space = (hweight32(reglist) - (!pbit ? 1 : 0)) * 4;
return INSN_GOOD_NO_SLOT;
}
const union decode_action stack_check_actions[] = {
[STACK_USE_NONE] = {.decoder = checker_stack_use_none},
[STACK_USE_UNKNOWN] = {.decoder = checker_stack_use_unknown},
#ifdef CONFIG_THUMB2_KERNEL
[STACK_USE_FIXED_0XX] = {.decoder = checker_stack_use_imm_0xx},
[STACK_USE_T32STRD] = {.decoder = checker_stack_use_t32strd},
#else
[STACK_USE_FIXED_X0X] = {.decoder = checker_stack_use_imm_x0x},
#endif
[STACK_USE_FIXED_XXX] = {.decoder = checker_stack_use_imm_xxx},
[STACK_USE_STMDX] = {.decoder = checker_stack_use_stmdx},
};

View File

@ -0,0 +1,110 @@
/*
* arch/arm/probes/kprobes/checkers-thumb.c
*
* Copyright (C) 2014 Huawei Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/kernel.h>
#include "../decode.h"
#include "../decode-thumb.h"
#include "checkers.h"
static enum probes_insn __kprobes t32_check_stack(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
/*
* PROBES_T32_LDMSTM, PROBES_T32_LDRDSTRD and PROBES_T32_LDRSTR
* may get here. Simply mark all normal insns as STACK_USE_NONE.
*/
static const union decode_item table[] = {
/*
* First, filter out all ldr insns to make our life easier.
* Following load insns may come here:
* LDM, LDRD, LDR.
* In T32 encoding, bit 20 is enough for distinguishing
* load and store. All load insns have this bit set, when
* all store insns have this bit clear.
*/
DECODE_CUSTOM (0x00100000, 0x00100000, STACK_USE_NONE),
/*
* Mark all 'STR{,B,H}, Rt, [Rn, Rm]' as STACK_USE_UNKNOWN
* if Rn or Rm is SP. T32 doesn't encode STRD.
*/
/* xx | Rn | Rt | | Rm |*/
/* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */
/* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */
/* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */
/* INVALID INSN 1111 1000 0110 xxxx xxxx 0000 00xx xxxx */
/* By Introducing INVALID INSN, bit 21 and 22 can be ignored. */
DECODE_OR (0xff9f0fc0, 0xf80d0000),
DECODE_CUSTOM (0xff900fcf, 0xf800000d, STACK_USE_UNKNOWN),
/* xx | Rn | Rt | PUW| imm8 |*/
/* STR (imm 8) 1111 1000 0100 1101 xxxx 110x xxxx xxxx */
/* STRB (imm 8) 1111 1000 0000 1101 xxxx 110x xxxx xxxx */
/* STRH (imm 8) 1111 1000 0010 1101 xxxx 110x xxxx xxxx */
/* INVALID INSN 1111 1000 0110 1101 xxxx 110x xxxx xxxx */
/* Only consider U == 0 and P == 1: strx rx, [sp, #-<imm>] */
DECODE_CUSTOM (0xff9f0e00, 0xf80d0c00, STACK_USE_FIXED_0XX),
/* For STR{,B,H} (imm 12), offset is always positive, so ignore them. */
/* P U W | Rn | Rt | Rt2| imm8 |*/
/* STRD (immediate) 1110 1001 01x0 1101 xxxx xxxx xxxx xxxx */
/*
* Only consider U == 0 and P == 1.
* Also note that STRD in T32 encoding is special:
* imm = ZeroExtend(imm8:'00', 32)
*/
DECODE_CUSTOM (0xffdf0000, 0xe94d0000, STACK_USE_T32STRD),
/* | Rn | */
/* STMDB 1110 1001 00x0 1101 xxxx xxxx xxxx xxxx */
DECODE_CUSTOM (0xffdf0000, 0xe90d0000, STACK_USE_STMDX),
/* fall through */
DECODE_CUSTOM (0, 0, STACK_USE_NONE),
DECODE_END
};
return probes_decode_insn(insn, asi, table, false, false, stack_check_actions, NULL);
}
const struct decode_checker t32_stack_checker[NUM_PROBES_T32_ACTIONS] = {
[PROBES_T32_LDMSTM] = {.checker = t32_check_stack},
[PROBES_T32_LDRDSTRD] = {.checker = t32_check_stack},
[PROBES_T32_LDRSTR] = {.checker = t32_check_stack},
};
/*
* See following comments. This insn must be 'push'.
*/
static enum probes_insn __kprobes t16_check_stack(probes_opcode_t insn,
struct arch_probes_insn *asi,
const struct decode_header *h)
{
unsigned int reglist = insn & 0x1ff;
asi->stack_space = hweight32(reglist) * 4;
return INSN_GOOD;
}
/*
* T16 encoding is simple: only the 'push' insn can need extra stack space.
* Other insns, like str, can only use r0-r7 as Rn.
*/
const struct decode_checker t16_stack_checker[NUM_PROBES_T16_ACTIONS] = {
[PROBES_T16_PUSH] = {.checker = t16_check_stack},
};

View File

@ -0,0 +1,55 @@
/*
* arch/arm/probes/kprobes/checkers.h
*
* Copyright (C) 2014 Huawei Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#ifndef _ARM_KERNEL_PROBES_CHECKERS_H
#define _ARM_KERNEL_PROBES_CHECKERS_H
#include <linux/kernel.h>
#include <linux/types.h>
#include "../decode.h"
extern probes_check_t checker_stack_use_none;
extern probes_check_t checker_stack_use_unknown;
#ifdef CONFIG_THUMB2_KERNEL
extern probes_check_t checker_stack_use_imm_0xx;
#else
extern probes_check_t checker_stack_use_imm_x0x;
#endif
extern probes_check_t checker_stack_use_imm_xxx;
extern probes_check_t checker_stack_use_stmdx;
enum {
STACK_USE_NONE,
STACK_USE_UNKNOWN,
#ifdef CONFIG_THUMB2_KERNEL
STACK_USE_FIXED_0XX,
STACK_USE_T32STRD,
#else
STACK_USE_FIXED_X0X,
#endif
STACK_USE_FIXED_XXX,
STACK_USE_STMDX,
NUM_STACK_USE_TYPES
};
extern const union decode_action stack_check_actions[];
#ifndef CONFIG_THUMB2_KERNEL
extern const struct decode_checker arm_stack_checker[];
extern const struct decode_checker arm_regs_checker[];
#else
#endif
extern const struct decode_checker t32_stack_checker[];
extern const struct decode_checker t16_stack_checker[];
#endif

View File

@ -30,11 +30,11 @@
#include <asm/cacheflush.h>
#include <linux/percpu.h>
#include <linux/bug.h>
#include <asm/patch.h>
#include "kprobes.h"
#include "probes-arm.h"
#include "probes-thumb.h"
#include "patch.h"
#include "../decode-arm.h"
#include "../decode-thumb.h"
#include "core.h"
#define MIN_STACK_SIZE(addr) \
min((unsigned long)MAX_STACK_SIZE, \
@ -61,6 +61,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
kprobe_decode_insn_t *decode_insn;
const union decode_action *actions;
int is;
const struct decode_checker **checkers;
if (in_exception_text(addr))
return -EINVAL;
@ -74,9 +75,11 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
insn = __opcode_thumb32_compose(insn, inst2);
decode_insn = thumb32_probes_decode_insn;
actions = kprobes_t32_actions;
checkers = kprobes_t32_checkers;
} else {
decode_insn = thumb16_probes_decode_insn;
actions = kprobes_t16_actions;
checkers = kprobes_t16_checkers;
}
#else /* !CONFIG_THUMB2_KERNEL */
thumb = false;
@ -85,12 +88,13 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
insn = __mem_to_opcode_arm(*p->addr);
decode_insn = arm_probes_decode_insn;
actions = kprobes_arm_actions;
checkers = kprobes_arm_checkers;
#endif
p->opcode = insn;
p->ainsn.insn = tmp_insn;
switch ((*decode_insn)(insn, &p->ainsn, true, actions)) {
switch ((*decode_insn)(insn, &p->ainsn, true, actions, checkers)) {
case INSN_REJECTED: /* not supported */
return -EINVAL;
@ -111,6 +115,15 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
break;
}
/*
* Never instrument insn like 'str r0, [sp, +/-r1]'. Also, insn likes
* 'str r0, [sp, #-68]' should also be prohibited.
* See __und_svc.
*/
if ((p->ainsn.stack_space < 0) ||
(p->ainsn.stack_space > MAX_STACK_SIZE))
return -EINVAL;
return 0;
}
@ -150,19 +163,31 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
* memory. It is also needed to atomically set the two half-words of a 32-bit
* Thumb breakpoint.
*/
int __kprobes __arch_disarm_kprobe(void *p)
struct patch {
void *addr;
unsigned int insn;
};
static int __kprobes_remove_breakpoint(void *data)
{
struct kprobe *kp = p;
void *addr = (void *)((uintptr_t)kp->addr & ~1);
__patch_text(addr, kp->opcode);
struct patch *p = data;
__patch_text(p->addr, p->insn);
return 0;
}
void __kprobes kprobes_remove_breakpoint(void *addr, unsigned int insn)
{
struct patch p = {
.addr = addr,
.insn = insn,
};
stop_machine(__kprobes_remove_breakpoint, &p, cpu_online_mask);
}
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
stop_machine(__arch_disarm_kprobe, p, cpu_online_mask);
kprobes_remove_breakpoint((void *)((uintptr_t)p->addr & ~1),
p->opcode);
}
void __kprobes arch_remove_kprobe(struct kprobe *p)

View File

@ -19,7 +19,8 @@
#ifndef _ARM_KERNEL_KPROBES_H
#define _ARM_KERNEL_KPROBES_H
#include "probes.h"
#include <asm/kprobes.h>
#include "../decode.h"
/*
* These undefined instructions must be unique and
@ -29,6 +30,8 @@
#define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18
#define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018
extern void kprobes_remove_breakpoint(void *addr, unsigned int insn);
enum probes_insn __kprobes
kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi,
const struct decode_header *h);
@ -36,16 +39,19 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi,
typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t,
struct arch_probes_insn *,
bool,
const union decode_action *);
const union decode_action *,
const struct decode_checker *[]);
#ifdef CONFIG_THUMB2_KERNEL
extern const union decode_action kprobes_t32_actions[];
extern const union decode_action kprobes_t16_actions[];
extern const struct decode_checker *kprobes_t32_checkers[];
extern const struct decode_checker *kprobes_t16_checkers[];
#else /* !CONFIG_THUMB2_KERNEL */
extern const union decode_action kprobes_arm_actions[];
extern const struct decode_checker *kprobes_arm_checkers[];
#endif

View File

@ -0,0 +1,370 @@
/*
* Kernel Probes Jump Optimization (Optprobes)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Copyright (C) IBM Corporation, 2002, 2004
* Copyright (C) Hitachi Ltd., 2012
* Copyright (C) Huawei Inc., 2014
*/
#include <linux/kprobes.h>
#include <linux/jump_label.h>
#include <asm/kprobes.h>
#include <asm/cacheflush.h>
/* for arm_gen_branch */
#include <asm/insn.h>
/* for patch_text */
#include <asm/patch.h>
#include "core.h"
/*
* See register_usage_flags. If the probed instruction doesn't use PC,
* we can copy it into template and have it executed directly without
* simulation or emulation.
*/
#define ARM_REG_PC 15
#define can_kprobe_direct_exec(m) (!test_bit(ARM_REG_PC, &(m)))
/*
* NOTE: the first sub and add instruction will be modified according
* to the stack cost of the instruction.
*/
asm (
".global optprobe_template_entry\n"
"optprobe_template_entry:\n"
".global optprobe_template_sub_sp\n"
"optprobe_template_sub_sp:"
" sub sp, sp, #0xff\n"
" stmia sp, {r0 - r14} \n"
".global optprobe_template_add_sp\n"
"optprobe_template_add_sp:"
" add r3, sp, #0xff\n"
" str r3, [sp, #52]\n"
" mrs r4, cpsr\n"
" str r4, [sp, #64]\n"
" mov r1, sp\n"
" ldr r0, 1f\n"
" ldr r2, 2f\n"
/*
* AEABI requires an 8-bytes alignment stack. If
* SP % 8 != 0 (SP % 4 == 0 should be ensured),
* alloc more bytes here.
*/
" and r4, sp, #4\n"
" sub sp, sp, r4\n"
#if __LINUX_ARM_ARCH__ >= 5
" blx r2\n"
#else
" mov lr, pc\n"
" mov pc, r2\n"
#endif
" add sp, sp, r4\n"
" ldr r1, [sp, #64]\n"
" tst r1, #"__stringify(PSR_T_BIT)"\n"
" ldrne r2, [sp, #60]\n"
" orrne r2, #1\n"
" strne r2, [sp, #60] @ set bit0 of PC for thumb\n"
" msr cpsr_cxsf, r1\n"
".global optprobe_template_restore_begin\n"
"optprobe_template_restore_begin:\n"
" ldmia sp, {r0 - r15}\n"
".global optprobe_template_restore_orig_insn\n"
"optprobe_template_restore_orig_insn:\n"
" nop\n"
".global optprobe_template_restore_end\n"
"optprobe_template_restore_end:\n"
" nop\n"
".global optprobe_template_val\n"
"optprobe_template_val:\n"
"1: .long 0\n"
".global optprobe_template_call\n"
"optprobe_template_call:\n"
"2: .long 0\n"
".global optprobe_template_end\n"
"optprobe_template_end:\n");
#define TMPL_VAL_IDX \
((unsigned long *)&optprobe_template_val - (unsigned long *)&optprobe_template_entry)
#define TMPL_CALL_IDX \
((unsigned long *)&optprobe_template_call - (unsigned long *)&optprobe_template_entry)
#define TMPL_END_IDX \
((unsigned long *)&optprobe_template_end - (unsigned long *)&optprobe_template_entry)
#define TMPL_ADD_SP \
((unsigned long *)&optprobe_template_add_sp - (unsigned long *)&optprobe_template_entry)
#define TMPL_SUB_SP \
((unsigned long *)&optprobe_template_sub_sp - (unsigned long *)&optprobe_template_entry)
#define TMPL_RESTORE_BEGIN \
((unsigned long *)&optprobe_template_restore_begin - (unsigned long *)&optprobe_template_entry)
#define TMPL_RESTORE_ORIGN_INSN \
((unsigned long *)&optprobe_template_restore_orig_insn - (unsigned long *)&optprobe_template_entry)
#define TMPL_RESTORE_END \
((unsigned long *)&optprobe_template_restore_end - (unsigned long *)&optprobe_template_entry)
/*
* ARM can always optimize an instruction when using ARM ISA, except
* instructions like 'str r0, [sp, r1]' which store to stack and unable
* to determine stack space consumption statically.
*/
int arch_prepared_optinsn(struct arch_optimized_insn *optinsn)
{
return optinsn->insn != NULL;
}
/*
* In ARM ISA, kprobe opt always replace one instruction (4 bytes
* aligned and 4 bytes long). It is impossible to encounter another
* kprobe in the address range. So always return 0.
*/
int arch_check_optimized_kprobe(struct optimized_kprobe *op)
{
return 0;
}
/* Caller must ensure addr & 3 == 0 */
static int can_optimize(struct kprobe *kp)
{
if (kp->ainsn.stack_space < 0)
return 0;
/*
* 255 is the biggest imm can be used in 'sub r0, r0, #<imm>'.
* Number larger than 255 needs special encoding.
*/
if (kp->ainsn.stack_space > 255 - sizeof(struct pt_regs))
return 0;
return 1;
}
/* Free optimized instruction slot */
static void
__arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty)
{
if (op->optinsn.insn) {
free_optinsn_slot(op->optinsn.insn, dirty);
op->optinsn.insn = NULL;
}
}
extern void kprobe_handler(struct pt_regs *regs);
static void
optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
{
unsigned long flags;
struct kprobe *p = &op->kp;
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
/* Save skipped registers */
regs->ARM_pc = (unsigned long)op->kp.addr;
regs->ARM_ORIG_r0 = ~0UL;
local_irq_save(flags);
if (kprobe_running()) {
kprobes_inc_nmissed_count(&op->kp);
} else {
__this_cpu_write(current_kprobe, &op->kp);
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
opt_pre_handler(&op->kp, regs);
__this_cpu_write(current_kprobe, NULL);
}
/*
* We singlestep the replaced instruction only when it can't be
* executed directly during restore.
*/
if (!p->ainsn.kprobe_direct_exec)
op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
local_irq_restore(flags);
}
int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig)
{
kprobe_opcode_t *code;
unsigned long rel_chk;
unsigned long val;
unsigned long stack_protect = sizeof(struct pt_regs);
if (!can_optimize(orig))
return -EILSEQ;
code = get_optinsn_slot();
if (!code)
return -ENOMEM;
/*
* Verify if the address gap is in 32MiB range, because this uses
* a relative jump.
*
* kprobe opt use a 'b' instruction to branch to optinsn.insn.
* According to ARM manual, branch instruction is:
*
* 31 28 27 24 23 0
* +------+---+---+---+---+----------------+
* | cond | 1 | 0 | 1 | 0 | imm24 |
* +------+---+---+---+---+----------------+
*
* imm24 is a signed 24 bits integer. The real branch offset is computed
* by: imm32 = SignExtend(imm24:'00', 32);
*
* So the maximum forward branch should be:
* (0x007fffff << 2) = 0x01fffffc = 0x1fffffc
* The maximum backword branch should be:
* (0xff800000 << 2) = 0xfe000000 = -0x2000000
*
* We can simply check (rel & 0xfe000003):
* if rel is positive, (rel & 0xfe000000) shoule be 0
* if rel is negitive, (rel & 0xfe000000) should be 0xfe000000
* the last '3' is used for alignment checking.
*/
rel_chk = (unsigned long)((long)code -
(long)orig->addr + 8) & 0xfe000003;
if ((rel_chk != 0) && (rel_chk != 0xfe000000)) {
/*
* Different from x86, we free code buf directly instead of
* calling __arch_remove_optimized_kprobe() because
* we have not fill any field in op.
*/
free_optinsn_slot(code, 0);
return -ERANGE;
}
/* Copy arch-dep-instance from template. */
memcpy(code, &optprobe_template_entry,
TMPL_END_IDX * sizeof(kprobe_opcode_t));
/* Adjust buffer according to instruction. */
BUG_ON(orig->ainsn.stack_space < 0);
stack_protect += orig->ainsn.stack_space;
/* Should have been filtered by can_optimize(). */
BUG_ON(stack_protect > 255);
/* Create a 'sub sp, sp, #<stack_protect>' */
code[TMPL_SUB_SP] = __opcode_to_mem_arm(0xe24dd000 | stack_protect);
/* Create a 'add r3, sp, #<stack_protect>' */
code[TMPL_ADD_SP] = __opcode_to_mem_arm(0xe28d3000 | stack_protect);
/* Set probe information */
val = (unsigned long)op;
code[TMPL_VAL_IDX] = val;
/* Set probe function call */
val = (unsigned long)optimized_callback;
code[TMPL_CALL_IDX] = val;
/* If possible, copy insn and have it executed during restore */
orig->ainsn.kprobe_direct_exec = false;
if (can_kprobe_direct_exec(orig->ainsn.register_usage_flags)) {
kprobe_opcode_t final_branch = arm_gen_branch(
(unsigned long)(&code[TMPL_RESTORE_END]),
(unsigned long)(op->kp.addr) + 4);
if (final_branch != 0) {
/*
* Replace original 'ldmia sp, {r0 - r15}' with
* 'ldmia {r0 - r14}', restore all registers except pc.
*/
code[TMPL_RESTORE_BEGIN] = __opcode_to_mem_arm(0xe89d7fff);
/* The original probed instruction */
code[TMPL_RESTORE_ORIGN_INSN] = __opcode_to_mem_arm(orig->opcode);
/* Jump back to next instruction */
code[TMPL_RESTORE_END] = __opcode_to_mem_arm(final_branch);
orig->ainsn.kprobe_direct_exec = true;
}
}
flush_icache_range((unsigned long)code,
(unsigned long)(&code[TMPL_END_IDX]));
/* Set op->optinsn.insn means prepared. */
op->optinsn.insn = code;
return 0;
}
void __kprobes arch_optimize_kprobes(struct list_head *oplist)
{
struct optimized_kprobe *op, *tmp;
list_for_each_entry_safe(op, tmp, oplist, list) {
unsigned long insn;
WARN_ON(kprobe_disabled(&op->kp));
/*
* Backup instructions which will be replaced
* by jump address
*/
memcpy(op->optinsn.copied_insn, op->kp.addr,
RELATIVEJUMP_SIZE);
insn = arm_gen_branch((unsigned long)op->kp.addr,
(unsigned long)op->optinsn.insn);
BUG_ON(insn == 0);
/*
* Make it a conditional branch if replaced insn
* is consitional
*/
insn = (__mem_to_opcode_arm(
op->optinsn.copied_insn[0]) & 0xf0000000) |
(insn & 0x0fffffff);
/*
* Similar to __arch_disarm_kprobe, operations which
* removing breakpoints must be wrapped by stop_machine
* to avoid racing.
*/
kprobes_remove_breakpoint(op->kp.addr, insn);
list_del_init(&op->list);
}
}
void arch_unoptimize_kprobe(struct optimized_kprobe *op)
{
arch_arm_kprobe(&op->kp);
}
/*
* Recover original instructions and breakpoints from relative jumps.
* Caller must call with locking kprobe_mutex.
*/
void arch_unoptimize_kprobes(struct list_head *oplist,
struct list_head *done_list)
{
struct optimized_kprobe *op, *tmp;
list_for_each_entry_safe(op, tmp, oplist, list) {
arch_unoptimize_kprobe(op);
list_move(&op->list, done_list);
}
}
int arch_within_optimized_kprobe(struct optimized_kprobe *op,
unsigned long addr)
{
return ((unsigned long)op->kp.addr <= addr &&
(unsigned long)op->kp.addr + RELATIVEJUMP_SIZE > addr);
}
void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
{
__arch_remove_optimized_kprobe(op, 1);
}

View File

@ -12,8 +12,9 @@
#include <linux/module.h>
#include <asm/system_info.h>
#include <asm/opcodes.h>
#include <asm/probes.h>
#include "kprobes-test.h"
#include "test-core.h"
#define TEST_ISA "32"
@ -203,9 +204,9 @@ void kprobe_arm_test_cases(void)
#endif
TEST_GROUP("Miscellaneous instructions")
TEST("mrs r0, cpsr")
TEST("mrspl r7, cpsr")
TEST("mrs r14, cpsr")
TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr")
TEST_RMASKED("mrspl r",7,~PSR_IGNORE_BITS,", cpsr")
TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr")
TEST_UNSUPPORTED(__inst_arm(0xe10ff000) " @ mrs r15, cpsr")
TEST_UNSUPPORTED("mrs r0, spsr")
TEST_UNSUPPORTED("mrs lr, spsr")
@ -214,9 +215,12 @@ void kprobe_arm_test_cases(void)
TEST_UNSUPPORTED("msr cpsr_f, lr")
TEST_UNSUPPORTED("msr spsr, r0")
#if __LINUX_ARM_ARCH__ >= 5 || \
(__LINUX_ARM_ARCH__ == 4 && !defined(CONFIG_CPU_32v4))
TEST_BF_R("bx r",0,2f,"")
TEST_BB_R("bx r",7,2f,"")
TEST_BF_R("bxeq r",14,2f,"")
#endif
#if __LINUX_ARM_ARCH__ >= 5
TEST_R("clz r0, r",0, 0x0,"")
@ -476,7 +480,9 @@ void kprobe_arm_test_cases(void)
TEST_GROUP("Extra load/store instructions")
TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]")
TEST_RPR( "streqh r",14,VAL2,", [r",13,0, ", r",12, 48,"]")
TEST_RPR( "streqh r",14,VAL2,", [r",11,0, ", r",12, 48,"]")
TEST_UNSUPPORTED( "streqh r14, [r13, r12]")
TEST_UNSUPPORTED( "streqh r14, [r12, r13]")
TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!")
TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
TEST_RPR( "strh r",2, VAL1,", [r",3, 24,"], r",4, 48,"")
@ -501,6 +507,9 @@ void kprobe_arm_test_cases(void)
TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!")
TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48")
TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48")
TEST_RP( "strh r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!")
TEST_UNSUPPORTED("strh r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_RP( "strh r",4, VAL1,", [r",14,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_UNSUPPORTED(__inst_arm(0xe1efc3b0) " @ strh r12, [pc, #48]!")
TEST_UNSUPPORTED(__inst_arm(0xe0c9f3b0) " @ strh pc, [r9], #48")
@ -565,7 +574,9 @@ void kprobe_arm_test_cases(void)
#if __LINUX_ARM_ARCH__ >= 5
TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]")
TEST_RPR( "strccd r",8, VAL2,", [r",13,0, ", r",12,48,"]")
TEST_RPR( "strccd r",8, VAL2,", [r",11,0, ", r",12,48,"]")
TEST_UNSUPPORTED( "strccd r8, [r13, r12]")
TEST_UNSUPPORTED( "strccd r8, [r12, r13]")
TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!")
TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
TEST_RPR( "strd r",2, VAL1,", [r",5, 24,"], r",4,48,"")
@ -589,6 +600,9 @@ void kprobe_arm_test_cases(void)
TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!")
TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48")
TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48")
TEST_RP( "strd r",6, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!")
TEST_UNSUPPORTED("strd r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_RP( "strd r",4, VAL1,", [r",12,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_UNSUPPORTED(__inst_arm(0xe1efc3f0) " @ strd r12, [pc, #48]!")
TEST_P( "ldrd r0, [r",0, 24,", #-8]")
@ -637,14 +651,20 @@ void kprobe_arm_test_cases(void)
TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \
TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \
TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \
TEST_RP( "str"byte" r",3, VAL1,", [r",13,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \
TEST_UNSUPPORTED("str"byte" r3, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \
TEST_RP( "str"byte" r",4, VAL1,", [r",10,TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \
TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \
TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 48,"]") \
TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 48,"]") \
TEST_UNSUPPORTED("str"byte" r14, [r13, r12]") \
TEST_UNSUPPORTED("str"byte" r14, [r12, r13]") \
TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \
TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \
TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \
TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \
TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\
TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 32,", lsr #2]")\
TEST_RPR("str"byte" r",14,VAL2,", [r",11,0, ", r",12, 32,", lsr #2]")\
TEST_UNSUPPORTED("str"byte" r14, [r13, r12, lsr #2]") \
TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\
TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\
TEST_P( "ldr"byte" r0, [r",0, 24,", #-2]") \
@ -668,12 +688,12 @@ void kprobe_arm_test_cases(void)
LOAD_STORE("")
TEST_P( "str pc, [r",0,0,", #15*4]")
TEST_R( "str pc, [sp, r",2,15*4,"]")
TEST_UNSUPPORTED( "str pc, [sp, r2]")
TEST_BF( "ldr pc, [sp, #15*4]")
TEST_BF_R("ldr pc, [sp, r",2,15*4,"]")
TEST_P( "str sp, [r",0,0,", #13*4]")
TEST_R( "str sp, [sp, r",2,13*4,"]")
TEST_UNSUPPORTED( "str sp, [sp, r2]")
TEST_BF( "ldr sp, [sp, #13*4]")
TEST_BF_R("ldr sp, [sp, r",2,13*4,"]")

View File

@ -209,10 +209,10 @@
#include <linux/bug.h>
#include <asm/opcodes.h>
#include "kprobes.h"
#include "probes-arm.h"
#include "probes-thumb.h"
#include "kprobes-test.h"
#include "core.h"
#include "test-core.h"
#include "../decode-arm.h"
#include "../decode-thumb.h"
#define BENCHMARKING 1
@ -236,6 +236,8 @@ static int tests_failed;
#ifndef CONFIG_THUMB2_KERNEL
#define RET(reg) "mov pc, "#reg
long arm_func(long r0, long r1);
static void __used __naked __arm_kprobes_test_func(void)
@ -245,7 +247,7 @@ static void __used __naked __arm_kprobes_test_func(void)
".type arm_func, %%function \n\t"
"arm_func: \n\t"
"adds r0, r0, r1 \n\t"
"bx lr \n\t"
"mov pc, lr \n\t"
".code "NORMAL_ISA /* Back to Thumb if necessary */
: : : "r0", "r1", "cc"
);
@ -253,6 +255,8 @@ static void __used __naked __arm_kprobes_test_func(void)
#else /* CONFIG_THUMB2_KERNEL */
#define RET(reg) "bx "#reg
long thumb16_func(long r0, long r1);
long thumb32even_func(long r0, long r1);
long thumb32odd_func(long r0, long r1);
@ -494,7 +498,7 @@ static void __naked benchmark_nop(void)
{
__asm__ __volatile__ (
"nop \n\t"
"bx lr"
RET(lr)" \n\t"
);
}
@ -977,7 +981,7 @@ void __naked __kprobes_test_case_start(void)
"bic r0, lr, #1 @ r0 = inline data \n\t"
"mov r1, sp \n\t"
"bl kprobes_test_case_start \n\t"
"bx r0 \n\t"
RET(r0)" \n\t"
);
}
@ -1056,15 +1060,6 @@ static int test_case_run_count;
static bool test_case_is_thumb;
static int test_instance;
/*
* We ignore the state of the imprecise abort disable flag (CPSR.A) because this
* can change randomly as the kernel doesn't take care to preserve or initialise
* this across context switches. Also, with Security Extentions, the flag may
* not be under control of the kernel; for this reason we ignore the state of
* the FIQ disable flag CPSR.F as well.
*/
#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT)
static unsigned long test_check_cc(int cc, unsigned long cpsr)
{
int ret = arm_check_condition(cc << 28, cpsr);
@ -1196,6 +1191,13 @@ static void setup_test_context(struct pt_regs *regs)
regs->uregs[arg->reg] =
(unsigned long)current_stack + arg->val;
memory_needs_checking = true;
/*
* Test memory at an address below SP is in danger of
* being altered by an interrupt occurring and pushing
* data onto the stack. Disable interrupts to stop this.
*/
if (arg->reg == 13)
regs->ARM_cpsr |= PSR_I_BIT;
break;
}
case ARG_TYPE_MEM: {
@ -1264,14 +1266,26 @@ test_case_pre_handler(struct kprobe *p, struct pt_regs *regs)
static int __kprobes
test_after_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct test_arg *args;
if (container_of(p, struct test_probe, kprobe)->hit == test_instance)
return 0; /* Already run for this test instance */
result_regs = *regs;
/* Mask out results which are indeterminate */
result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS;
for (args = current_args; args[0].type != ARG_TYPE_END; ++args)
if (args[0].type == ARG_TYPE_REG_MASKED) {
struct test_arg_regptr *arg =
(struct test_arg_regptr *)args;
result_regs.uregs[arg->reg] &= arg->val;
}
/* Undo any changes done to SP by the test case */
regs->ARM_sp = (unsigned long)current_stack;
/* Enable interrupts in case setup_test_context disabled them */
regs->ARM_cpsr &= ~PSR_I_BIT;
container_of(p, struct test_probe, kprobe)->hit = test_instance;
return 0;

View File

@ -1,5 +1,5 @@
/*
* arch/arm/kernel/kprobes-test.h
* arch/arm/probes/kprobes/test-core.h
*
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
*
@ -45,10 +45,11 @@ extern int kprobe_test_cc_position;
*
*/
#define ARG_TYPE_END 0
#define ARG_TYPE_REG 1
#define ARG_TYPE_PTR 2
#define ARG_TYPE_MEM 3
#define ARG_TYPE_END 0
#define ARG_TYPE_REG 1
#define ARG_TYPE_PTR 2
#define ARG_TYPE_MEM 3
#define ARG_TYPE_REG_MASKED 4
#define ARG_FLAG_UNSUPPORTED 0x01
#define ARG_FLAG_SUPPORTED 0x02
@ -61,7 +62,7 @@ struct test_arg {
};
struct test_arg_regptr {
u8 type; /* ARG_TYPE_REG or ARG_TYPE_PTR */
u8 type; /* ARG_TYPE_REG or ARG_TYPE_PTR or ARG_TYPE_REG_MASKED */
u8 reg;
u8 _padding[2];
u32 val;
@ -138,6 +139,12 @@ struct test_arg_end {
".short 0 \n\t" \
".word "#val" \n\t"
#define TEST_ARG_REG_MASKED(reg, val) \
".byte "__stringify(ARG_TYPE_REG_MASKED)" \n\t" \
".byte "#reg" \n\t" \
".short 0 \n\t" \
".word "#val" \n\t"
#define TEST_ARG_END(flags) \
".byte "__stringify(ARG_TYPE_END)" \n\t" \
".byte "TEST_ISA flags" \n\t" \
@ -395,6 +402,22 @@ struct test_arg_end {
" "codex" \n\t" \
TESTCASE_END
#define TEST_RMASKED(code1, reg, mask, code2) \
TESTCASE_START(code1 #reg code2) \
TEST_ARG_REG_MASKED(reg, mask) \
TEST_ARG_END("") \
TEST_INSTRUCTION(code1 #reg code2) \
TESTCASE_END
/*
* We ignore the state of the imprecise abort disable flag (CPSR.A) because this
* can change randomly as the kernel doesn't take care to preserve or initialise
* this across context switches. Also, with Security Extensions, the flag may
* not be under control of the kernel; for this reason we ignore the state of
* the FIQ disable flag CPSR.F as well.
*/
#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT)
/*
* Macros for defining space directives spread over multiple lines.

View File

@ -1,5 +1,5 @@
/*
* arch/arm/kernel/kprobes-test-thumb.c
* arch/arm/probes/kprobes/test-thumb.c
*
* Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
*
@ -11,8 +11,9 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/opcodes.h>
#include <asm/probes.h>
#include "kprobes-test.h"
#include "test-core.h"
#define TEST_ISA "16"
@ -416,6 +417,9 @@ void kprobe_thumb32_test_cases(void)
TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!")
TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16")
TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16")
TEST_RRP("strd r",6, VAL1,", r",7, VAL2,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!")
TEST_UNSUPPORTED("strd r6, r7, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_RRP("strd r",4, VAL1,", r",5, VAL2,", [r",14, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!")
TEST_UNSUPPORTED(__inst_thumb32(0xe9efec04) " @ strd r14, r12, [pc, #16]!")
TEST_UNSUPPORTED(__inst_thumb32(0xe8efec04) " @ strd r14, r12, [pc], #16")
@ -774,8 +778,8 @@ CONDITION_INSTRUCTIONS(22,
TEST_UNSUPPORTED("subs pc, lr, #4")
TEST("mrs r0, cpsr")
TEST("mrs r14, cpsr")
TEST_RMASKED("mrs r",0,~PSR_IGNORE_BITS,", cpsr")
TEST_RMASKED("mrs r",14,~PSR_IGNORE_BITS,", cpsr")
TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8d00) " @ mrs sp, spsr")
TEST_UNSUPPORTED(__inst_thumb32(0xf3ef8f00) " @ mrs pc, spsr")
TEST_UNSUPPORTED("mrs r0, spsr")
@ -821,14 +825,22 @@ CONDITION_INSTRUCTIONS(22,
TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \
TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \
TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \
TEST_UNSUPPORTED("str"size" r0, [r13, r1]") \
TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \
TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \
TEST_RP( "str"size" r",6, VAL1,", [r",13, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"]!") \
TEST_UNSUPPORTED("str"size" r6, [r13, #-"__stringify(MAX_STACK_SIZE)"-8]!") \
TEST_RP( "str"size" r",4, VAL2,", [r",12, TEST_MEMORY_SIZE,", #-"__stringify(MAX_STACK_SIZE)"-8]!") \
TEST_UNSUPPORTED("str"size"t r0, [r1, #4]")
SINGLE_STORE("b")
SINGLE_STORE("h")
SINGLE_STORE("")
TEST_UNSUPPORTED(__inst_thumb32(0xf801000d) " @ strb r0, [r1, r13]")
TEST_UNSUPPORTED(__inst_thumb32(0xf821000d) " @ strh r0, [r1, r13]")
TEST_UNSUPPORTED(__inst_thumb32(0xf841000d) " @ str r0, [r1, r13]")
TEST("str sp, [sp]")
TEST_UNSUPPORTED(__inst_thumb32(0xf8cfe000) " @ str r14, [pc]")
TEST_UNSUPPORTED(__inst_thumb32(0xf8cef000) " @ str pc, [r14]")

View File

@ -0,0 +1 @@
obj-$(CONFIG_UPROBES) += core.o actions-arm.o

View File

@ -13,9 +13,9 @@
#include <linux/uprobes.h>
#include <linux/module.h>
#include "probes.h"
#include "probes-arm.h"
#include "uprobes.h"
#include "../decode.h"
#include "../decode-arm.h"
#include "core.h"
static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs)
{
@ -195,8 +195,6 @@ uprobe_decode_ldmstm(probes_opcode_t insn,
}
const union decode_action uprobes_probes_actions[] = {
[PROBES_EMULATE_NONE] = {.handler = probes_simulate_nop},
[PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
[PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
[PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
[PROBES_BRANCH_IMM] = {.handler = simulate_blx1},

View File

@ -17,9 +17,9 @@
#include <asm/opcodes.h>
#include <asm/traps.h>
#include "probes.h"
#include "probes-arm.h"
#include "uprobes.h"
#include "../decode.h"
#include "../decode-arm.h"
#include "core.h"
#define UPROBE_TRAP_NR UINT_MAX
@ -88,7 +88,7 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN);
ret = arm_probes_decode_insn(insn, &auprobe->asi, false,
uprobes_probes_actions);
uprobes_probes_actions, NULL);
switch (ret) {
case INSN_REJECTED:
return -EINVAL;

View File

@ -1,6 +1,7 @@
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_FHANDLE=y
CONFIG_AUDIT=y
CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
@ -13,14 +14,12 @@ CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_RESOURCE_COUNTERS=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
CONFIG_MEMCG_KMEM=y
CONFIG_CGROUP_HUGETLB=y
# CONFIG_UTS_NS is not set
# CONFIG_IPC_NS is not set
# CONFIG_PID_NS is not set
# CONFIG_NET_NS is not set
CONFIG_SCHED_AUTOGROUP=y
CONFIG_BLK_DEV_INITRD=y
@ -92,7 +91,6 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_VIRTIO_CONSOLE=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HMC_DRV is not set
CONFIG_SPI=y
CONFIG_SPI_PL022=y
CONFIG_GPIO_PL061=y
@ -133,6 +131,8 @@ CONFIG_EXT3_FS=y
CONFIG_EXT4_FS=y
CONFIG_FANOTIFY=y
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
CONFIG_QUOTA=y
CONFIG_AUTOFS4_FS=y
CONFIG_FUSE_FS=y
CONFIG_CUSE=y
CONFIG_VFAT_FS=y
@ -152,14 +152,15 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_KERNEL=y
CONFIG_LOCKUP_DETECTOR=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_PREEMPT is not set
# CONFIG_FTRACE is not set
CONFIG_KEYS=y
CONFIG_SECURITY=y
CONFIG_CRYPTO_ANSI_CPRNG=y
CONFIG_ARM64_CRYPTO=y
CONFIG_CRYPTO_SHA1_ARM64_CE=y
CONFIG_CRYPTO_SHA2_ARM64_CE=y
CONFIG_CRYPTO_GHASH_ARM64_CE=y
CONFIG_CRYPTO_AES_ARM64_CE=y
CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y

View File

@ -52,13 +52,14 @@ static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
dev->archdata.dma_ops = ops;
}
static inline int set_arch_dma_coherent_ops(struct device *dev)
static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
struct iommu_ops *iommu, bool coherent)
{
dev->archdata.dma_coherent = true;
set_dma_ops(dev, &coherent_swiotlb_dma_ops);
return 0;
dev->archdata.dma_coherent = coherent;
if (coherent)
set_dma_ops(dev, &coherent_swiotlb_dma_ops);
}
#define set_arch_dma_coherent_ops set_arch_dma_coherent_ops
#define arch_setup_dma_ops arch_setup_dma_ops
/* do not use this function in a driver */
static inline bool is_device_dma_coherent(struct device *dev)

View File

@ -298,7 +298,6 @@ void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
#define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot)
#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
#define pud_write(pud) pte_write(pud_pte(pud))
#define pud_pfn(pud) (((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
@ -401,7 +400,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr);
}
#define pud_page(pud) pmd_page(pud_pmd(pud))
#define pud_page(pud) pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK))
#endif /* CONFIG_ARM64_PGTABLE_LEVELS > 2 */
@ -437,6 +436,8 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr)
return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(addr);
}
#define pgd_page(pgd) pfn_to_page(__phys_to_pfn(pgd_val(pgd) & PHYS_MASK))
#endif /* CONFIG_ARM64_PGTABLE_LEVELS > 3 */
#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd))

View File

@ -5,6 +5,7 @@
#include <asm/debug-monitors.h>
#include <asm/pgtable.h>
#include <asm/memory.h>
#include <asm/mmu_context.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include <asm/tlbflush.h>
@ -98,7 +99,18 @@ int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
*/
ret = __cpu_suspend_enter(arg, fn);
if (ret == 0) {
cpu_switch_mm(mm->pgd, mm);
/*
* We are resuming from reset with TTBR0_EL1 set to the
* idmap to enable the MMU; restore the active_mm mappings in
* TTBR0_EL1 unless the active_mm == &init_mm, in which case
* the thread entered __cpu_suspend with TTBR0_EL1 set to
* reserved TTBR0 page tables and should be restored as such.
*/
if (mm == &init_mm)
cpu_set_reserved_ttbr0();
else
cpu_switch_mm(mm->pgd, mm);
flush_tlb_all();
/*

View File

@ -11,7 +11,7 @@
#define NR_syscalls 318 /* length of syscall table */
#define NR_syscalls 319 /* length of syscall table */
/*
* The following defines stop scripts/checksyscalls.sh from complaining about

View File

@ -331,5 +331,6 @@
#define __NR_getrandom 1339
#define __NR_memfd_create 1340
#define __NR_bpf 1341
#define __NR_execveat 1342
#endif /* _UAPI_ASM_IA64_UNISTD_H */

View File

@ -1779,6 +1779,7 @@ sys_call_table:
data8 sys_getrandom
data8 sys_memfd_create // 1340
data8 sys_bpf
data8 sys_execveat
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */

View File

@ -72,6 +72,7 @@ void __init setup_cpuinfo(void)
cpuinfo.has_div = fcpu_has(cpu, "altr,has-div");
cpuinfo.has_mul = fcpu_has(cpu, "altr,has-mul");
cpuinfo.has_mulx = fcpu_has(cpu, "altr,has-mulx");
cpuinfo.mmu = fcpu_has(cpu, "altr,has-mmu");
if (IS_ENABLED(CONFIG_NIOS2_HW_DIV_SUPPORT) && !cpuinfo.has_div)
err_cpu("DIV");

View File

@ -365,30 +365,14 @@ ENTRY(ret_from_interrupt)
GET_THREAD_INFO r1
ldw r4, TI_PREEMPT_COUNT(r1)
bne r4, r0, restore_all
need_resched:
ldw r4, TI_FLAGS(r1) /* ? Need resched set */
BTBZ r10, r4, TIF_NEED_RESCHED, restore_all
ldw r4, PT_ESTATUS(sp) /* ? Interrupts off */
andi r10, r4, ESTATUS_EPIE
beq r10, r0, restore_all
movia r4, PREEMPT_ACTIVE
stw r4, TI_PREEMPT_COUNT(r1)
rdctl r10, status /* enable intrs again */
ori r10, r10 ,STATUS_PIE
wrctl status, r10
PUSH r1
call schedule
POP r1
mov r4, r0
stw r4, TI_PREEMPT_COUNT(r1)
rdctl r10, status /* disable intrs */
andi r10, r10, %lo(~STATUS_PIE)
wrctl status, r10
br need_resched
#else
br restore_all
call preempt_schedule_irq
#endif
br restore_all
/***********************************************************************
* A few syscall wrappers

View File

@ -33,11 +33,18 @@
#endif /*!CONFIG_PA20*/
/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*. */
/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.
We don't explicitly expose that "*a" may be written as reload
fails to find a register in class R1_REGS when "a" needs to be
reloaded when generating 64-bit PIC code. Instead, we clobber
memory to indicate to the compiler that the assembly code reads
or writes to items other than those listed in the input and output
operands. This may pessimize the code somewhat but __ldcw is
usually used within code blocks surrounded by memory barriors. */
#define __ldcw(a) ({ \
unsigned __ret; \
__asm__ __volatile__(__LDCW " 0(%2),%0" \
: "=r" (__ret), "+m" (*(a)) : "r" (a)); \
__asm__ __volatile__(__LDCW " 0(%1),%0" \
: "=r" (__ret) : "r" (a) : "memory"); \
__ret; \
})

View File

@ -86,6 +86,11 @@ extern int overlaps_crashkernel(unsigned long start, unsigned long size);
extern void reserve_crashkernel(void);
extern void machine_kexec_mask_interrupts(void);
static inline bool kdump_in_progress(void)
{
return crashing_cpu >= 0;
}
#else /* !CONFIG_KEXEC */
static inline void crash_kexec_secondary(struct pt_regs *regs) { }
@ -106,6 +111,11 @@ static inline int crash_shutdown_unregister(crash_shutdown_t handler)
return 0;
}
static inline bool kdump_in_progress(void)
{
return false;
}
#endif /* CONFIG_KEXEC */
#endif /* ! __ASSEMBLY__ */
#endif /* __KERNEL__ */

View File

@ -366,3 +366,4 @@ SYSCALL_SPU(seccomp)
SYSCALL_SPU(getrandom)
SYSCALL_SPU(memfd_create)
SYSCALL_SPU(bpf)
COMPAT_SYS(execveat)

View File

@ -12,7 +12,7 @@
#include <uapi/asm/unistd.h>
#define __NR_syscalls 362
#define __NR_syscalls 363
#define __NR__exit __NR_exit
#define NR_syscalls __NR_syscalls

View File

@ -384,5 +384,6 @@
#define __NR_getrandom 359
#define __NR_memfd_create 360
#define __NR_bpf 361
#define __NR_execveat 362
#endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */

View File

@ -330,7 +330,7 @@ void default_machine_kexec(struct kimage *image)
* using debugger IPI.
*/
if (crashing_cpu == -1)
if (!kdump_in_progress())
kexec_prepare_cpus();
pr_debug("kexec: Starting switchover sequence.\n");

View File

@ -700,6 +700,7 @@ void start_secondary(void *unused)
smp_store_cpu_info(cpu);
set_dec(tb_ticks_per_jiffy);
preempt_disable();
cpu_callin_map[cpu] = 1;
if (smp_ops->setup_cpu)
smp_ops->setup_cpu(cpu);
@ -738,14 +739,6 @@ void start_secondary(void *unused)
notify_cpu_starting(cpu);
set_cpu_online(cpu, true);
/*
* CPU must be marked active and online before we signal back to the
* master, because the scheduler needs to see the cpu_online and
* cpu_active bits set.
*/
smp_wmb();
cpu_callin_map[cpu] = 1;
local_irq_enable();
cpu_startup_entry(CPUHP_ONLINE);

View File

@ -43,6 +43,7 @@
#include <asm/trace.h>
#include <asm/firmware.h>
#include <asm/plpar_wrappers.h>
#include <asm/kexec.h>
#include <asm/fadump.h>
#include "pseries.h"
@ -267,8 +268,13 @@ static void pSeries_lpar_hptab_clear(void)
* out to the user, but at least this will stop us from
* continuing on further and creating an even more
* difficult to debug situation.
*
* There is a known problem when kdump'ing, if cpus are offline
* the above call will fail. Rather than panicking again, keep
* going and hope the kdump kernel is also little endian, which
* it usually is.
*/
if (rc)
if (rc && !kdump_in_progress())
panic("Could not enable big endian exceptions");
}
#endif

View File

@ -3,6 +3,7 @@ config UML
default y
select HAVE_ARCH_AUDITSYSCALL
select HAVE_UID16
select HAVE_FUTEX_CMPXCHG if FUTEX
select GENERIC_IRQ_SHOW
select GENERIC_CPU_DEVICES
select GENERIC_IO

View File

@ -322,7 +322,8 @@ void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
* Target instructions MUST be relocatable (checked inside)
* This is called when new aggr(opt)probe is allocated or reused.
*/
int arch_prepare_optimized_kprobe(struct optimized_kprobe *op)
int arch_prepare_optimized_kprobe(struct optimized_kprobe *op,
struct kprobe *__unused)
{
u8 *buf;
int ret;

View File

@ -4448,7 +4448,7 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm)
* zap all shadow pages.
*/
if (unlikely(kvm_current_mmio_generation(kvm) == 0)) {
printk_ratelimited(KERN_INFO "kvm: zapping shadow pages for mmio generation wraparound\n");
printk_ratelimited(KERN_DEBUG "kvm: zapping shadow pages for mmio generation wraparound\n");
kvm_mmu_invalidate_zap_all_pages(kvm);
}
}

View File

@ -5840,53 +5840,10 @@ static __init int hardware_setup(void)
memset(vmx_msr_bitmap_legacy, 0xff, PAGE_SIZE);
memset(vmx_msr_bitmap_longmode, 0xff, PAGE_SIZE);
vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true);
memcpy(vmx_msr_bitmap_legacy_x2apic,
vmx_msr_bitmap_legacy, PAGE_SIZE);
memcpy(vmx_msr_bitmap_longmode_x2apic,
vmx_msr_bitmap_longmode, PAGE_SIZE);
if (enable_apicv) {
for (msr = 0x800; msr <= 0x8ff; msr++)
vmx_disable_intercept_msr_read_x2apic(msr);
/* According SDM, in x2apic mode, the whole id reg is used.
* But in KVM, it only use the highest eight bits. Need to
* intercept it */
vmx_enable_intercept_msr_read_x2apic(0x802);
/* TMCCT */
vmx_enable_intercept_msr_read_x2apic(0x839);
/* TPR */
vmx_disable_intercept_msr_write_x2apic(0x808);
/* EOI */
vmx_disable_intercept_msr_write_x2apic(0x80b);
/* SELF-IPI */
vmx_disable_intercept_msr_write_x2apic(0x83f);
}
if (enable_ept) {
kvm_mmu_set_mask_ptes(0ull,
(enable_ept_ad_bits) ? VMX_EPT_ACCESS_BIT : 0ull,
(enable_ept_ad_bits) ? VMX_EPT_DIRTY_BIT : 0ull,
0ull, VMX_EPT_EXECUTABLE_MASK);
ept_set_mmio_spte_mask();
kvm_enable_tdp();
} else
kvm_disable_tdp();
update_ple_window_actual_max();
if (setup_vmcs_config(&vmcs_config) < 0) {
r = -EIO;
goto out7;
}
}
if (boot_cpu_has(X86_FEATURE_NX))
kvm_enable_efer_bits(EFER_NX);
@ -5945,6 +5902,49 @@ static __init int hardware_setup(void)
if (nested)
nested_vmx_setup_ctls_msrs();
vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true);
memcpy(vmx_msr_bitmap_legacy_x2apic,
vmx_msr_bitmap_legacy, PAGE_SIZE);
memcpy(vmx_msr_bitmap_longmode_x2apic,
vmx_msr_bitmap_longmode, PAGE_SIZE);
if (enable_apicv) {
for (msr = 0x800; msr <= 0x8ff; msr++)
vmx_disable_intercept_msr_read_x2apic(msr);
/* According SDM, in x2apic mode, the whole id reg is used.
* But in KVM, it only use the highest eight bits. Need to
* intercept it */
vmx_enable_intercept_msr_read_x2apic(0x802);
/* TMCCT */
vmx_enable_intercept_msr_read_x2apic(0x839);
/* TPR */
vmx_disable_intercept_msr_write_x2apic(0x808);
/* EOI */
vmx_disable_intercept_msr_write_x2apic(0x80b);
/* SELF-IPI */
vmx_disable_intercept_msr_write_x2apic(0x83f);
}
if (enable_ept) {
kvm_mmu_set_mask_ptes(0ull,
(enable_ept_ad_bits) ? VMX_EPT_ACCESS_BIT : 0ull,
(enable_ept_ad_bits) ? VMX_EPT_DIRTY_BIT : 0ull,
0ull, VMX_EPT_EXECUTABLE_MASK);
ept_set_mmio_spte_mask();
kvm_enable_tdp();
} else
kvm_disable_tdp();
update_ple_window_actual_max();
return alloc_kvm_area();
out7:

View File

@ -34,7 +34,7 @@ typedef asmlinkage void (*sys_call_ptr_t)(void);
extern asmlinkage void sys_ni_syscall(void);
const sys_call_ptr_t sys_call_table[] __cacheline_aligned = {
const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = {
/*
* Smells like a compiler bug -- it doesn't work
* when the & below is removed.

View File

@ -47,7 +47,7 @@ typedef void (*sys_call_ptr_t)(void);
extern void sys_ni_syscall(void);
const sys_call_ptr_t sys_call_table[] __cacheline_aligned = {
const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = {
/*
* Smells like a compiler bug -- it doesn't work
* when the & below is removed.

View File

@ -455,6 +455,9 @@ void af_alg_complete(struct crypto_async_request *req, int err)
{
struct af_alg_completion *completion = req->data;
if (err == -EINPROGRESS)
return;
completion->err = err;
complete(&completion->completion);
}

View File

@ -985,8 +985,6 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
state->flags = 0;
switch (cx->type) {
case ACPI_STATE_C1:
if (cx->entry_method != ACPI_CSTATE_FFH)
state->flags |= CPUIDLE_FLAG_TIME_INVALID;
state->enter = acpi_idle_enter_c1;
state->enter_dead = acpi_idle_play_dead;

View File

@ -505,6 +505,23 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
},
},
{
.callback = video_disable_native_backlight,
.ident = "SAMSUNG 870Z5E/880Z5E/680Z5E",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"),
},
},
{
.callback = video_disable_native_backlight,
.ident = "SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "370R4E/370R4V/370R5E/3570RE/370R5V"),
},
},
{}
};

View File

@ -2088,7 +2088,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider);
* Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR()
* on failure.
*/
static struct generic_pm_domain *of_genpd_get_from_provider(
struct generic_pm_domain *of_genpd_get_from_provider(
struct of_phandle_args *genpdspec)
{
struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
@ -2108,6 +2108,7 @@ static struct generic_pm_domain *of_genpd_get_from_provider(
return genpd;
}
EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
/**
* genpd_dev_pm_detach - Detach a device from its PM domain.

View File

@ -108,6 +108,14 @@ static LIST_HEAD(dev_opp_list);
/* Lock to allow exclusive modification to the device and opp lists */
static DEFINE_MUTEX(dev_opp_list_lock);
#define opp_rcu_lockdep_assert() \
do { \
rcu_lockdep_assert(rcu_read_lock_held() || \
lockdep_is_held(&dev_opp_list_lock), \
"Missing rcu_read_lock() or " \
"dev_opp_list_lock protection"); \
} while (0)
/**
* find_device_opp() - find device_opp struct using device pointer
* @dev: device pointer used to lookup device OPPs
@ -208,9 +216,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
* This function returns the number of available opps if there are any,
* else returns 0 if none or the corresponding error value.
*
* Locking: This function must be called under rcu_read_lock(). This function
* internally references two RCU protected structures: device_opp and opp which
* are safe as long as we are under a common RCU locked section.
* Locking: This function takes rcu_read_lock().
*/
int dev_pm_opp_get_opp_count(struct device *dev)
{
@ -218,11 +224,14 @@ int dev_pm_opp_get_opp_count(struct device *dev)
struct dev_pm_opp *temp_opp;
int count = 0;
rcu_read_lock();
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp)) {
int r = PTR_ERR(dev_opp);
dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
return r;
count = PTR_ERR(dev_opp);
dev_err(dev, "%s: device OPP not found (%d)\n",
__func__, count);
goto out_unlock;
}
list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
@ -230,6 +239,8 @@ int dev_pm_opp_get_opp_count(struct device *dev)
count++;
}
out_unlock:
rcu_read_unlock();
return count;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
@ -267,6 +278,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
struct device_opp *dev_opp;
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
opp_rcu_lockdep_assert();
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp)) {
int r = PTR_ERR(dev_opp);
@ -313,6 +326,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
struct device_opp *dev_opp;
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
opp_rcu_lockdep_assert();
if (!dev || !freq) {
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
return ERR_PTR(-EINVAL);
@ -361,6 +376,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
struct device_opp *dev_opp;
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
opp_rcu_lockdep_assert();
if (!dev || !freq) {
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
return ERR_PTR(-EINVAL);
@ -783,9 +800,15 @@ void of_free_opp_table(struct device *dev)
/* Check for existing list for 'dev' */
dev_opp = find_device_opp(dev);
if (WARN(IS_ERR(dev_opp), "%s: dev_opp: %ld\n", dev_name(dev),
PTR_ERR(dev_opp)))
if (IS_ERR(dev_opp)) {
int error = PTR_ERR(dev_opp);
if (error != -ENODEV)
WARN(1, "%s: dev_opp: %d\n",
IS_ERR_OR_NULL(dev) ?
"Invalid device" : dev_name(dev),
error);
return;
}
/* Hold our list modification lock here */
mutex_lock(&dev_opp_list_lock);

View File

@ -417,6 +417,6 @@ static void __exit agp_ali_cleanup(void)
module_init(agp_ali_init);
module_exit(agp_ali_cleanup);
MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_AUTHOR("Dave Jones");
MODULE_LICENSE("GPL and additional rights");

View File

@ -813,6 +813,6 @@ static void __exit agp_amd64_cleanup(void)
module_init(agp_amd64_mod_init);
module_exit(agp_amd64_cleanup);
MODULE_AUTHOR("Dave Jones <davej@redhat.com>, Andi Kleen");
MODULE_AUTHOR("Dave Jones, Andi Kleen");
module_param(agp_try_unsupported, bool, 0);
MODULE_LICENSE("GPL");

View File

@ -579,6 +579,6 @@ static void __exit agp_ati_cleanup(void)
module_init(agp_ati_init);
module_exit(agp_ati_cleanup);
MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_AUTHOR("Dave Jones");
MODULE_LICENSE("GPL and additional rights");

View File

@ -356,7 +356,7 @@ static __init int agp_setup(char *s)
__setup("agp=", agp_setup);
#endif
MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_AUTHOR("Dave Jones, Jeff Hartmann");
MODULE_DESCRIPTION("AGP GART driver");
MODULE_LICENSE("GPL and additional rights");
MODULE_ALIAS_MISCDEV(AGPGART_MINOR);

View File

@ -920,5 +920,5 @@ static void __exit agp_intel_cleanup(void)
module_init(agp_intel_init);
module_exit(agp_intel_cleanup);
MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_AUTHOR("Dave Jones, Various @Intel");
MODULE_LICENSE("GPL and additional rights");

View File

@ -1438,5 +1438,5 @@ void intel_gmch_remove(void)
}
EXPORT_SYMBOL(intel_gmch_remove);
MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_AUTHOR("Dave Jones, Various @Intel");
MODULE_LICENSE("GPL and additional rights");

View File

@ -1,7 +1,7 @@
/*
* Nvidia AGPGART routines.
* Based upon a 2.4 agpgart diff by the folks from NVIDIA, and hacked up
* to work in 2.5 by Dave Jones <davej@redhat.com>
* to work in 2.5 by Dave Jones.
*/
#include <linux/module.h>

View File

@ -595,4 +595,4 @@ module_init(agp_via_init);
module_exit(agp_via_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
MODULE_AUTHOR("Dave Jones");

View File

@ -199,18 +199,6 @@ struct bmc_device {
int guid_set;
char name[16];
struct kref usecount;
/* bmc device attributes */
struct device_attribute device_id_attr;
struct device_attribute provides_dev_sdrs_attr;
struct device_attribute revision_attr;
struct device_attribute firmware_rev_attr;
struct device_attribute version_attr;
struct device_attribute add_dev_support_attr;
struct device_attribute manufacturer_id_attr;
struct device_attribute product_id_attr;
struct device_attribute guid_attr;
struct device_attribute aux_firmware_rev_attr;
};
#define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev)
@ -2252,7 +2240,7 @@ static ssize_t device_id_show(struct device *dev,
return snprintf(buf, 10, "%u\n", bmc->id.device_id);
}
DEVICE_ATTR(device_id, S_IRUGO, device_id_show, NULL);
static DEVICE_ATTR(device_id, S_IRUGO, device_id_show, NULL);
static ssize_t provides_device_sdrs_show(struct device *dev,
struct device_attribute *attr,
@ -2263,7 +2251,8 @@ static ssize_t provides_device_sdrs_show(struct device *dev,
return snprintf(buf, 10, "%u\n",
(bmc->id.device_revision & 0x80) >> 7);
}
DEVICE_ATTR(provides_device_sdrs, S_IRUGO, provides_device_sdrs_show, NULL);
static DEVICE_ATTR(provides_device_sdrs, S_IRUGO, provides_device_sdrs_show,
NULL);
static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
char *buf)
@ -2273,7 +2262,7 @@ static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
return snprintf(buf, 20, "%u\n",
bmc->id.device_revision & 0x0F);
}
DEVICE_ATTR(revision, S_IRUGO, revision_show, NULL);
static DEVICE_ATTR(revision, S_IRUGO, revision_show, NULL);
static ssize_t firmware_revision_show(struct device *dev,
struct device_attribute *attr,
@ -2284,7 +2273,7 @@ static ssize_t firmware_revision_show(struct device *dev,
return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
bmc->id.firmware_revision_2);
}
DEVICE_ATTR(firmware_revision, S_IRUGO, firmware_revision_show, NULL);
static DEVICE_ATTR(firmware_revision, S_IRUGO, firmware_revision_show, NULL);
static ssize_t ipmi_version_show(struct device *dev,
struct device_attribute *attr,
@ -2296,7 +2285,7 @@ static ssize_t ipmi_version_show(struct device *dev,
ipmi_version_major(&bmc->id),
ipmi_version_minor(&bmc->id));
}
DEVICE_ATTR(ipmi_version, S_IRUGO, ipmi_version_show, NULL);
static DEVICE_ATTR(ipmi_version, S_IRUGO, ipmi_version_show, NULL);
static ssize_t add_dev_support_show(struct device *dev,
struct device_attribute *attr,
@ -2307,7 +2296,8 @@ static ssize_t add_dev_support_show(struct device *dev,
return snprintf(buf, 10, "0x%02x\n",
bmc->id.additional_device_support);
}
DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show, NULL);
static DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show,
NULL);
static ssize_t manufacturer_id_show(struct device *dev,
struct device_attribute *attr,
@ -2317,7 +2307,7 @@ static ssize_t manufacturer_id_show(struct device *dev,
return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
}
DEVICE_ATTR(manufacturer_id, S_IRUGO, manufacturer_id_show, NULL);
static DEVICE_ATTR(manufacturer_id, S_IRUGO, manufacturer_id_show, NULL);
static ssize_t product_id_show(struct device *dev,
struct device_attribute *attr,
@ -2327,7 +2317,7 @@ static ssize_t product_id_show(struct device *dev,
return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
}
DEVICE_ATTR(product_id, S_IRUGO, product_id_show, NULL);
static DEVICE_ATTR(product_id, S_IRUGO, product_id_show, NULL);
static ssize_t aux_firmware_rev_show(struct device *dev,
struct device_attribute *attr,
@ -2341,7 +2331,7 @@ static ssize_t aux_firmware_rev_show(struct device *dev,
bmc->id.aux_firmware_revision[1],
bmc->id.aux_firmware_revision[0]);
}
DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL);
static DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL);
static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
char *buf)
@ -2352,7 +2342,7 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
(long long) bmc->guid[0],
(long long) bmc->guid[8]);
}
DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL);
static DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL);
static struct attribute *bmc_dev_attrs[] = {
&dev_attr_device_id.attr,
@ -2392,10 +2382,10 @@ cleanup_bmc_device(struct kref *ref)
if (bmc->id.aux_firmware_revision_set)
device_remove_file(&bmc->pdev.dev,
&bmc->aux_firmware_rev_attr);
&dev_attr_aux_firmware_revision);
if (bmc->guid_set)
device_remove_file(&bmc->pdev.dev,
&bmc->guid_attr);
&dev_attr_guid);
platform_device_unregister(&bmc->pdev);
}
@ -2422,16 +2412,14 @@ static int create_bmc_files(struct bmc_device *bmc)
int err;
if (bmc->id.aux_firmware_revision_set) {
bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
err = device_create_file(&bmc->pdev.dev,
&bmc->aux_firmware_rev_attr);
&dev_attr_aux_firmware_revision);
if (err)
goto out;
}
if (bmc->guid_set) {
bmc->guid_attr.attr.name = "guid";
err = device_create_file(&bmc->pdev.dev,
&bmc->guid_attr);
&dev_attr_guid);
if (err)
goto out_aux_firm;
}
@ -2441,7 +2429,7 @@ static int create_bmc_files(struct bmc_device *bmc)
out_aux_firm:
if (bmc->id.aux_firmware_revision_set)
device_remove_file(&bmc->pdev.dev,
&bmc->aux_firmware_rev_attr);
&dev_attr_aux_firmware_revision);
out:
return err;
}

View File

@ -52,6 +52,7 @@
#include <linux/dmi.h>
#include <linux/kthread.h>
#include <linux/acpi.h>
#include <linux/ctype.h>
#define PFX "ipmi_ssif: "
#define DEVICE_NAME "ipmi_ssif"

View File

@ -462,7 +462,7 @@ static void __init arch_counter_register(unsigned type)
/* Register the CP15 based counter if we have one */
if (type & ARCH_CP15_TIMER) {
if (arch_timer_use_virtual)
if (IS_ENABLED(CONFIG_ARM64) || arch_timer_use_virtual)
arch_timer_read_counter = arch_counter_get_cntvct;
else
arch_timer_read_counter = arch_counter_get_cntpct;

View File

@ -211,6 +211,17 @@ static int cpufreq_init(struct cpufreq_policy *policy)
/* OPPs might be populated at runtime, don't check for error here */
of_init_opp_table(cpu_dev);
/*
* But we need OPP table to function so if it is not there let's
* give platform code chance to provide it for us.
*/
ret = dev_pm_opp_get_opp_count(cpu_dev);
if (ret <= 0) {
pr_debug("OPP table is not ready, deferring probe\n");
ret = -EPROBE_DEFER;
goto out_free_opp;
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;

View File

@ -2028,6 +2028,12 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
/* Don't start any governor operations if we are entering suspend */
if (cpufreq_suspended)
return 0;
/*
* Governor might not be initiated here if ACPI _PPC changed
* notification happened, so check it.
*/
if (!policy->governor)
return -EINVAL;
if (policy->governor->max_transition_latency &&
policy->cpuinfo.transition_latency >

View File

@ -79,12 +79,7 @@ static int ladder_select_state(struct cpuidle_driver *drv,
last_state = &ldev->states[last_idx];
if (!(drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_INVALID)) {
last_residency = cpuidle_get_last_residency(dev) - \
drv->states[last_idx].exit_latency;
}
else
last_residency = last_state->threshold.promotion_time + 1;
last_residency = cpuidle_get_last_residency(dev) - drv->states[last_idx].exit_latency;
/* consider promotion */
if (last_idx < drv->state_count - 1 &&

View File

@ -396,8 +396,8 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* power state and occurrence of the wakeup event.
*
* If the entered idle state didn't support residency measurements,
* we are basically lost in the dark how much time passed.
* As a compromise, assume we slept for the whole expected time.
* we use them anyway if they are short, and if long,
* truncate to the whole expected time.
*
* Any measured amount of time will include the exit latency.
* Since we are interested in when the wakeup begun, not when it
@ -405,23 +405,18 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* the measured amount of time is less than the exit latency,
* assume the state was never reached and the exit latency is 0.
*/
if (unlikely(target->flags & CPUIDLE_FLAG_TIME_INVALID)) {
/* Use timer value as is */
/* measured value */
measured_us = cpuidle_get_last_residency(dev);
/* Deduct exit latency */
if (measured_us > target->exit_latency)
measured_us -= target->exit_latency;
/* Make sure our coefficients do not exceed unity */
if (measured_us > data->next_timer_us)
measured_us = data->next_timer_us;
} else {
/* Use measured value */
measured_us = cpuidle_get_last_residency(dev);
/* Deduct exit latency */
if (measured_us > target->exit_latency)
measured_us -= target->exit_latency;
/* Make sure our coefficients do not exceed unity */
if (measured_us > data->next_timer_us)
measured_us = data->next_timer_us;
}
/* Update our correction ratio */
new_factor = data->correction_factor[data->bucket];
new_factor -= new_factor / DECAY;

View File

@ -121,13 +121,9 @@ static int kfd_open(struct inode *inode, struct file *filep)
if (IS_ERR(process))
return PTR_ERR(process);
process->is_32bit_user_mode = is_32bit_user_mode;
dev_dbg(kfd_device, "process %d opened, compat mode (32 bit) - %d\n",
process->pasid, process->is_32bit_user_mode);
kfd_init_apertures(process);
return 0;
}

View File

@ -299,13 +299,13 @@ int kfd_init_apertures(struct kfd_process *process)
struct kfd_dev *dev;
struct kfd_process_device *pdd;
mutex_lock(&process->mutex);
/*Iterating over all devices*/
while ((dev = kfd_topology_enum_kfd_devices(id)) != NULL &&
id < NUM_OF_SUPPORTED_GPUS) {
pdd = kfd_get_process_device_data(dev, process, 1);
if (!pdd)
return -1;
/*
* For 64 bit process aperture will be statically reserved in
@ -348,8 +348,6 @@ int kfd_init_apertures(struct kfd_process *process)
id++;
}
mutex_unlock(&process->mutex);
return 0;
}

View File

@ -26,6 +26,8 @@
#include <linux/slab.h>
#include <linux/amd-iommu.h>
#include <linux/notifier.h>
#include <linux/compat.h>
struct mm_struct;
#include "kfd_priv.h"
@ -285,8 +287,15 @@ static struct kfd_process *create_process(const struct task_struct *thread)
if (err != 0)
goto err_process_pqm_init;
/* init process apertures*/
process->is_32bit_user_mode = is_compat_task();
if (kfd_init_apertures(process) != 0)
goto err_init_apretures;
return process;
err_init_apretures:
pqm_uninit(&process->pqm);
err_process_pqm_init:
hash_del_rcu(&process->kfd_processes);
synchronize_rcu();

View File

@ -700,8 +700,6 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
dev->node_props.simd_per_cu);
sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
dev->node_props.max_slots_scratch_cu);
sysfs_show_32bit_prop(buffer, "engine_id",
dev->node_props.engine_id);
sysfs_show_32bit_prop(buffer, "vendor_id",
dev->node_props.vendor_id);
sysfs_show_32bit_prop(buffer, "device_id",
@ -715,6 +713,12 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
dev->gpu->kgd));
sysfs_show_64bit_prop(buffer, "local_mem_size",
kfd2kgd->get_vmem_size(dev->gpu->kgd));
sysfs_show_32bit_prop(buffer, "fw_version",
kfd2kgd->get_fw_version(
dev->gpu->kgd,
KGD_ENGINE_MEC1));
}
ret = sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",

View File

@ -45,6 +45,17 @@ enum kgd_memory_pool {
KGD_POOL_FRAMEBUFFER = 3,
};
enum kgd_engine_type {
KGD_ENGINE_PFP = 1,
KGD_ENGINE_ME,
KGD_ENGINE_CE,
KGD_ENGINE_MEC1,
KGD_ENGINE_MEC2,
KGD_ENGINE_RLC,
KGD_ENGINE_SDMA,
KGD_ENGINE_MAX
};
struct kgd2kfd_shared_resources {
/* Bit n == 1 means VMID n is available for KFD. */
unsigned int compute_vmid_bitmap;
@ -137,6 +148,8 @@ struct kgd2kfd_calls {
*
* @hqd_destroy: Destructs and preempts the queue assigned to that hqd slot.
*
* @get_fw_version: Returns FW versions from the header
*
* This structure contains function pointers to services that the kgd driver
* provides to amdkfd driver.
*
@ -176,6 +189,8 @@ struct kfd2kgd_calls {
int (*hqd_destroy)(struct kgd_dev *kgd, uint32_t reset_type,
unsigned int timeout, uint32_t pipe_id,
uint32_t queue_id);
uint16_t (*get_fw_version)(struct kgd_dev *kgd,
enum kgd_engine_type type);
};
bool kgd2kfd_init(unsigned interface_version,

View File

@ -61,7 +61,7 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
struct drm_crtc_state *crtc_state;
if (plane->state->crtc) {
crtc_state = state->crtc_states[drm_crtc_index(plane->crtc)];
crtc_state = state->crtc_states[drm_crtc_index(plane->state->crtc)];
if (WARN_ON(!crtc_state))
return;

View File

@ -830,6 +830,8 @@ drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
* vblank events since the system was booted, including lost events due to
* modesetting activity.
*
* This is the legacy version of drm_crtc_vblank_count().
*
* Returns:
* The software vblank counter.
*/
@ -843,6 +845,25 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc)
}
EXPORT_SYMBOL(drm_vblank_count);
/**
* drm_crtc_vblank_count - retrieve "cooked" vblank counter value
* @crtc: which counter to retrieve
*
* Fetches the "cooked" vblank count value that represents the number of
* vblank events since the system was booted, including lost events due to
* modesetting activity.
*
* This is the native KMS version of drm_vblank_count().
*
* Returns:
* The software vblank counter.
*/
u32 drm_crtc_vblank_count(struct drm_crtc *crtc)
{
return drm_vblank_count(crtc->dev, drm_crtc_index(crtc));
}
EXPORT_SYMBOL(drm_crtc_vblank_count);
/**
* drm_vblank_count_and_time - retrieve "cooked" vblank counter value
* and the system timestamp corresponding to that vblank counter value.
@ -904,6 +925,8 @@ static void send_vblank_event(struct drm_device *dev,
*
* Updates sequence # and timestamp on event, and sends it to userspace.
* Caller must hold event lock.
*
* This is the legacy version of drm_crtc_send_vblank_event().
*/
void drm_send_vblank_event(struct drm_device *dev, int crtc,
struct drm_pending_vblank_event *e)
@ -922,6 +945,23 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc,
}
EXPORT_SYMBOL(drm_send_vblank_event);
/**
* drm_crtc_send_vblank_event - helper to send vblank event after pageflip
* @crtc: the source CRTC of the vblank event
* @e: the event to send
*
* Updates sequence # and timestamp on event, and sends it to userspace.
* Caller must hold event lock.
*
* This is the native KMS version of drm_send_vblank_event().
*/
void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
struct drm_pending_vblank_event *e)
{
drm_send_vblank_event(crtc->dev, drm_crtc_index(crtc), e);
}
EXPORT_SYMBOL(drm_crtc_send_vblank_event);
/**
* drm_vblank_enable - enable the vblank interrupt on a CRTC
* @dev: DRM device
@ -1594,6 +1634,8 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
*
* Drivers should call this routine in their vblank interrupt handlers to
* update the vblank counter and send any signals that may be pending.
*
* This is the legacy version of drm_crtc_handle_vblank().
*/
bool drm_handle_vblank(struct drm_device *dev, int crtc)
{
@ -1670,3 +1712,21 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
return true;
}
EXPORT_SYMBOL(drm_handle_vblank);
/**
* drm_crtc_handle_vblank - handle a vblank event
* @crtc: where this event occurred
*
* Drivers should call this routine in their vblank interrupt handlers to
* update the vblank counter and send any signals that may be pending.
*
* This is the native KMS version of drm_handle_vblank().
*
* Returns:
* True if the event was successfully handled, false on failure.
*/
bool drm_crtc_handle_vblank(struct drm_crtc *crtc)
{
return drm_handle_vblank(crtc->dev, drm_crtc_index(crtc));
}
EXPORT_SYMBOL(drm_crtc_handle_vblank);

View File

@ -811,6 +811,8 @@ int i915_reset(struct drm_device *dev)
if (!i915.reset)
return 0;
intel_reset_gt_powersave(dev);
mutex_lock(&dev->struct_mutex);
i915_gem_reset(dev);
@ -880,7 +882,7 @@ int i915_reset(struct drm_device *dev)
* of re-init after reset.
*/
if (INTEL_INFO(dev)->gen > 5)
intel_reset_gt_powersave(dev);
intel_enable_gt_powersave(dev);
} else {
mutex_unlock(&dev->struct_mutex);
}
@ -1584,7 +1586,7 @@ static struct drm_driver driver = {
.gem_prime_import = i915_gem_prime_import,
.dumb_create = i915_gem_dumb_create,
.dumb_map_offset = i915_gem_dumb_map_offset,
.dumb_map_offset = i915_gem_mmap_gtt,
.dumb_destroy = drm_gem_dumb_destroy,
.ioctls = i915_ioctls,
.fops = &i915_driver_fops,

View File

@ -2501,9 +2501,8 @@ void i915_vma_move_to_active(struct i915_vma *vma,
int i915_gem_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
int i915_gem_dumb_map_offset(struct drm_file *file_priv,
struct drm_device *dev, uint32_t handle,
uint64_t *offset);
int i915_gem_mmap_gtt(struct drm_file *file_priv, struct drm_device *dev,
uint32_t handle, uint64_t *offset);
/**
* Returns true if seq1 is later than seq2.
*/

View File

@ -401,7 +401,6 @@ static int
i915_gem_create(struct drm_file *file,
struct drm_device *dev,
uint64_t size,
bool dumb,
uint32_t *handle_p)
{
struct drm_i915_gem_object *obj;
@ -417,7 +416,6 @@ i915_gem_create(struct drm_file *file,
if (obj == NULL)
return -ENOMEM;
obj->base.dumb = dumb;
ret = drm_gem_handle_create(file, &obj->base, &handle);
/* drop reference from allocate - handle holds it now */
drm_gem_object_unreference_unlocked(&obj->base);
@ -437,7 +435,7 @@ i915_gem_dumb_create(struct drm_file *file,
args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 64);
args->size = args->pitch * args->height;
return i915_gem_create(file, dev,
args->size, true, &args->handle);
args->size, &args->handle);
}
/**
@ -450,7 +448,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_create *args = data;
return i915_gem_create(file, dev,
args->size, false, &args->handle);
args->size, &args->handle);
}
static inline int
@ -1840,10 +1838,10 @@ static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj)
drm_gem_free_mmap_offset(&obj->base);
}
static int
int
i915_gem_mmap_gtt(struct drm_file *file,
struct drm_device *dev,
uint32_t handle, bool dumb,
uint32_t handle,
uint64_t *offset)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@ -1860,13 +1858,6 @@ i915_gem_mmap_gtt(struct drm_file *file,
goto unlock;
}
/*
* We don't allow dumb mmaps on objects created using another
* interface.
*/
WARN_ONCE(dumb && !(obj->base.dumb || obj->base.import_attach),
"Illegal dumb map of accelerated buffer.\n");
if (obj->base.size > dev_priv->gtt.mappable_end) {
ret = -E2BIG;
goto out;
@ -1891,15 +1882,6 @@ unlock:
return ret;
}
int
i915_gem_dumb_map_offset(struct drm_file *file,
struct drm_device *dev,
uint32_t handle,
uint64_t *offset)
{
return i915_gem_mmap_gtt(file, dev, handle, true, offset);
}
/**
* i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing
* @dev: DRM device
@ -1921,7 +1903,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
{
struct drm_i915_gem_mmap_gtt *args = data;
return i915_gem_mmap_gtt(file, dev, args->handle, false, &args->offset);
return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
}
static inline int

View File

@ -473,7 +473,12 @@ mi_set_context(struct intel_engine_cs *ring,
u32 hw_flags)
{
u32 flags = hw_flags | MI_MM_SPACE_GTT;
int ret;
const int num_rings =
/* Use an extended w/a on ivb+ if signalling from other rings */
i915_semaphore_is_enabled(ring->dev) ?
hweight32(INTEL_INFO(ring->dev)->ring_mask) - 1 :
0;
int len, i, ret;
/* w/a: If Flush TLB Invalidation Mode is enabled, driver must do a TLB
* invalidation prior to MI_SET_CONTEXT. On GEN6 we don't set the value
@ -490,15 +495,31 @@ mi_set_context(struct intel_engine_cs *ring,
if (!IS_HASWELL(ring->dev) && INTEL_INFO(ring->dev)->gen < 8)
flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN);
ret = intel_ring_begin(ring, 6);
len = 4;
if (INTEL_INFO(ring->dev)->gen >= 7)
len += 2 + (num_rings ? 4*num_rings + 2 : 0);
ret = intel_ring_begin(ring, len);
if (ret)
return ret;
/* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */
if (INTEL_INFO(ring->dev)->gen >= 7)
if (INTEL_INFO(ring->dev)->gen >= 7) {
intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE);
else
intel_ring_emit(ring, MI_NOOP);
if (num_rings) {
struct intel_engine_cs *signaller;
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings));
for_each_ring(signaller, to_i915(ring->dev), i) {
if (signaller == ring)
continue;
intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
intel_ring_emit(ring, _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
}
}
}
intel_ring_emit(ring, MI_NOOP);
intel_ring_emit(ring, MI_SET_CONTEXT);
@ -510,10 +531,21 @@ mi_set_context(struct intel_engine_cs *ring,
*/
intel_ring_emit(ring, MI_NOOP);
if (INTEL_INFO(ring->dev)->gen >= 7)
if (INTEL_INFO(ring->dev)->gen >= 7) {
if (num_rings) {
struct intel_engine_cs *signaller;
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings));
for_each_ring(signaller, to_i915(ring->dev), i) {
if (signaller == ring)
continue;
intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
intel_ring_emit(ring, _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
}
}
intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE);
else
intel_ring_emit(ring, MI_NOOP);
}
intel_ring_advance(ring);

View File

@ -121,9 +121,6 @@ eb_lookup_vmas(struct eb_vmas *eb,
goto err;
}
WARN_ONCE(obj->base.dumb,
"GPU use of dumb buffer is illegal.\n");
drm_gem_object_reference(&obj->base);
list_add_tail(&obj->obj_exec_link, &objects);
}

Some files were not shown because too many files have changed in this diff Show More