From 57789d69c5e7cdfdad6c0f1c54ab17240d800ac2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 1 Feb 2014 16:35:42 -0600 Subject: ARM: hisi: fix kconfig warning on HAVE_ARM_TWD Commit "ARM: hisi: don't select SMP" introduced a kconfig warning: warning: (ARCH_HI3xxx) selects HAVE_ARM_TWD which has unmet direct dependencies (SMP) Fix HAVE_ARM_TWD to depend on SMP. Signed-off-by: Rob Herring Signed-off-by: Olof Johansson --- arch/arm/mach-hisi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-hisi/Kconfig b/arch/arm/mach-hisi/Kconfig index 8f4649b301b2..1abae5f6a418 100644 --- a/arch/arm/mach-hisi/Kconfig +++ b/arch/arm/mach-hisi/Kconfig @@ -8,7 +8,7 @@ config ARCH_HI3xxx select CLKSRC_OF select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU - select HAVE_ARM_TWD + select HAVE_ARM_TWD if SMP select HAVE_SMP select PINCTRL select PINCTRL_SINGLE -- cgit v1.2.3 From e803d988662ff365c2ed3c2d10a0aad811c1f492 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 1 Feb 2014 16:35:43 -0600 Subject: ARM: moxart: move DMA_OF selection to driver Move the DMA_OF selection to the DMA driver to fix kconfig warning: warning: (ARCH_MOXART) selects DMA_OF which has unmet direct dependencies (DMADEVICES && OF) Signed-off-by: Rob Herring Signed-off-by: Olof Johansson --- arch/arm/mach-moxart/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-moxart/Kconfig b/arch/arm/mach-moxart/Kconfig index ba470d64493b..3795ae28a613 100644 --- a/arch/arm/mach-moxart/Kconfig +++ b/arch/arm/mach-moxart/Kconfig @@ -2,7 +2,6 @@ config ARCH_MOXART bool "MOXA ART SoC" if ARCH_MULTI_V4T select CPU_FA526 select ARM_DMA_MEM_BUFFERABLE - select DMA_OF select USE_OF select CLKSRC_OF select CLKSRC_MMIO -- cgit v1.2.3 From 8b7dfa7dc701a27ac8ea4c4dfc0dbc8dce4825de Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Sat, 1 Feb 2014 16:35:44 -0600 Subject: ARM: fix HAVE_ARM_TWD selection for OMAP and shmobile The selection of HAVE_ARM_TWD for OMAP and shmobile depend on LOCAL_TIMER which no longer exists. They should depend on SMP instead. Cc: Tony Lindgren Cc: Simon Horman Cc: Magnus Damm Signed-off-by: Rob Herring Signed-off-by: Olof Johansson --- arch/arm/mach-omap2/Kconfig | 2 +- arch/arm/mach-shmobile/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 653b489479e0..e2ce4f8366a7 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -54,7 +54,7 @@ config SOC_OMAP5 select ARM_GIC select CPU_V7 select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_SMP select HAVE_ARM_ARCH_TIMER select ARM_ERRATA_798181 if SMP diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 338640631e08..05fa505df585 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -8,7 +8,7 @@ config ARCH_SHMOBILE_MULTI select CPU_V7 select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if LOCAL_TIMERS + select HAVE_ARM_TWD if SMP select HAVE_SMP select ARM_GIC select MIGHT_HAVE_CACHE_L2X0 -- cgit v1.2.3 From 3f18b1bf599d3d13cd81fdf6bf869c458772adfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 16 Dec 2013 10:24:46 +0100 Subject: ARM: make isa_mode macro more robust and fix for v7-M MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The definition of isa_mode hardcodes the values to shift PSR_J_BIT and PSR_T_BIT to move them to bits 1 and 0 respectively. Instead use __ffs to calculate the shift from the #define already used for masking. This is relevant on v7-M as there PSR_T_BIT is 0x01000000 instead of 0x00000020 for V7-[AR] and earlier. Because of that isa_mode produced values >= 0x80000 which are unsuitable to index into isa_modes[4] there and so made __show_regs read from undefined memory which resulted in hangs and crashes. Moreover isa_mode is wrong for v7-M even after this robustness fix as there is no J-bit in the PSR register. So hardcode isa_mode to "Thumb" for v7-M. Signed-off-by: Uwe Kleine-König --- arch/arm/include/asm/ptrace.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 04c99f36ff7f..627a03ebb987 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -27,9 +27,13 @@ struct pt_regs { #define thumb_mode(regs) (0) #endif +#ifndef CONFIG_CPU_V7M #define isa_mode(regs) \ - ((((regs)->ARM_cpsr & PSR_J_BIT) >> 23) | \ - (((regs)->ARM_cpsr & PSR_T_BIT) >> 5)) + ((((regs)->ARM_cpsr & PSR_J_BIT) >> (__ffs(PSR_J_BIT) - 1)) | \ + (((regs)->ARM_cpsr & PSR_T_BIT) >> (__ffs(PSR_T_BIT)))) +#else +#define isa_mode(regs) 1 /* Thumb */ +#endif #define processor_mode(regs) \ ((regs)->ARM_cpsr & MODE_MASK) -- cgit v1.2.3 From e2e55fde3f2eaeb1d341508108a51a61dd0fb470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 16 Dec 2013 10:38:57 +0100 Subject: ARM: show_regs: on v7-M there are no FIQs, different processor modes, ... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no indication about irqs in PSR and only a single ISA. So skip the whole decoding and just print the xPSR on v7-M. Also mark two static variables as __maybe_unused to prevent the compiler from emitting: arch/arm/kernel/process.c:51:20: warning: 'processor_modes' defined but not used [-Wunused-variable] arch/arm/kernel/process.c:58:20: warning: 'isa_modes' defined but not used [-Wunused-variable] Signed-off-by: Uwe Kleine-König --- arch/arm/kernel/process.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 92f7b15dd221..204f7d273319 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -48,14 +48,14 @@ unsigned long __stack_chk_guard __read_mostly; EXPORT_SYMBOL(__stack_chk_guard); #endif -static const char *processor_modes[] = { +static const char *processor_modes[] __maybe_unused = { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26", "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" , "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32" }; -static const char *isa_modes[] = { +static const char *isa_modes[] __maybe_unused = { "ARM" , "Thumb" , "Jazelle", "ThumbEE" }; @@ -276,12 +276,17 @@ void __show_regs(struct pt_regs *regs) buf[3] = flags & PSR_V_BIT ? 'V' : 'v'; buf[4] = '\0'; +#ifndef CONFIG_CPU_V7M printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n", buf, interrupts_enabled(regs) ? "n" : "ff", fast_interrupts_enabled(regs) ? "n" : "ff", processor_modes[processor_mode(regs)], isa_modes[isa_mode(regs)], get_fs() == get_ds() ? "kernel" : "user"); +#else + printk("xPSR: %08lx\n", regs->ARM_cpsr); +#endif + #ifdef CONFIG_CPU_CP15 { unsigned int ctrl; -- cgit v1.2.3 From f0d7515372ff0ea53fd66099533d3c8e0464cbbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 1 Feb 2012 10:00:00 +0100 Subject: ARM: v7m: add trivial suspend support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König --- arch/arm/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e25419817791..41266af5dfc8 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2270,7 +2270,7 @@ source "kernel/power/Kconfig" config ARCH_SUSPEND_POSSIBLE depends on !ARCH_S5PC100 depends on CPU_ARM920T || CPU_ARM926T || CPU_FEROCEON || CPU_SA1100 || \ - CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK + CPU_V6 || CPU_V6K || CPU_V7 || CPU_V7M || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK def_bool y config ARM_CPU_SUSPEND -- cgit v1.2.3 From 1ff6bbfd13ca2c114a5cb58e1a92d1e5d68ce0b7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 28 Jan 2014 18:10:37 -0500 Subject: arm, pm, vmpressure: add missing slab.h includes arch/arm/mach-tegra/pm.c, kernel/power/console.c and mm/vmpressure.c were somehow getting slab.h indirectly through cgroup.h which in turn was getting it indirectly through xattr.h. A scheduled cgroup change drops xattr.h inclusion from cgroup.h and breaks compilation of these three files. Add explicit slab.h includes to the three files. A pending cgroup patch depends on this change and it'd be great if this can be routed through cgroup/for-3.14-fixes branch. Signed-off-by: Tejun Heo Acked-by: Stephen Warren Cc: Thierry Reding Cc: linux-tegra@vger.kernel.org Cc: "Rafael J. Wysocki" Cc: linux-pm@vger.kernel.org Cc: Johannes Weiner Cc: Michal Hocko Cc: Balbir Singh Cc: KAMEZAWA Hiroyuki Cc: cgroups@vger.kernel.org --- arch/arm/mach-tegra/pm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 4ae0286b468d..f55b05a29b55 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 14cfa4bd74be31e5502dcb5c98de86db63fddb65 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 12 Jan 2014 13:09:24 +0100 Subject: ARM: mvebu: dt: add missing alias 'eth3' on Armada XP mv78260 It was correctly set on mv78460 but not on mv78260, resulting in my OpenBlocks AX3-4 retrieving only 3 of its 4 MAC addresses from the boot loader. Cc: Thomas Petazzoni Cc: Gregory CLEMENT Signed-off-by: Willy Tarreau Acked-by: Gregory CLEMENT Signed-off-by: Jason Cooper --- arch/arm/boot/dts/armada-xp-mv78260.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi index 66609684d41b..9480cf891f8c 100644 --- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi +++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi @@ -23,6 +23,7 @@ gpio0 = &gpio0; gpio1 = &gpio1; gpio2 = &gpio2; + eth3 = ð3; }; cpus { @@ -291,7 +292,7 @@ interrupts = <91>; }; - ethernet@34000 { + eth3: ethernet@34000 { compatible = "marvell,armada-370-neta"; reg = <0x34000 0x4000>; interrupts = <14>; -- cgit v1.2.3 From 1c70e099ac80ee779ffac66a6169ad936425fe41 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sun, 2 Feb 2014 14:49:13 +0100 Subject: ARM: sunxi: dt: Convert to the new net compatibles Switch the device tree to the new compatibles introduced in the ethernet and mdio drivers to have a common pattern accross all Allwinner SoCs. Signed-off-by: Maxime Ripard Signed-off-by: David S. Miller --- arch/arm/boot/dts/sun4i-a10.dtsi | 4 ++-- arch/arm/boot/dts/sun5i-a10s.dtsi | 4 ++-- arch/arm/boot/dts/sun7i-a20.dtsi | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index 040bb0eba152..10666ca8aee1 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -315,7 +315,7 @@ ranges; emac: ethernet@01c0b000 { - compatible = "allwinner,sun4i-emac"; + compatible = "allwinner,sun4i-a10-emac"; reg = <0x01c0b000 0x1000>; interrupts = <55>; clocks = <&ahb_gates 17>; @@ -323,7 +323,7 @@ }; mdio@01c0b080 { - compatible = "allwinner,sun4i-mdio"; + compatible = "allwinner,sun4i-a10-mdio"; reg = <0x01c0b080 0x14>; status = "disabled"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index ea16054857a4..64961595e8d6 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -278,7 +278,7 @@ ranges; emac: ethernet@01c0b000 { - compatible = "allwinner,sun4i-emac"; + compatible = "allwinner,sun4i-a10-emac"; reg = <0x01c0b000 0x1000>; interrupts = <55>; clocks = <&ahb_gates 17>; @@ -286,7 +286,7 @@ }; mdio@01c0b080 { - compatible = "allwinner,sun4i-mdio"; + compatible = "allwinner,sun4i-a10-mdio"; reg = <0x01c0b080 0x14>; status = "disabled"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 119f066f0d98..9ff09484847b 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -340,7 +340,7 @@ ranges; emac: ethernet@01c0b000 { - compatible = "allwinner,sun4i-emac"; + compatible = "allwinner,sun4i-a10-emac"; reg = <0x01c0b000 0x1000>; interrupts = <0 55 4>; clocks = <&ahb_gates 17>; @@ -348,7 +348,7 @@ }; mdio@01c0b080 { - compatible = "allwinner,sun4i-mdio"; + compatible = "allwinner,sun4i-a10-mdio"; reg = <0x01c0b080 0x14>; status = "disabled"; #address-cells = <1>; -- cgit v1.2.3 From 821003ba4b9ffbf020a12177f0ea3d27826463c3 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Wed, 15 Jan 2014 11:24:46 +0100 Subject: ARM: at91/dt: sam9263: fix compatibility string for the I2C Signed-off-by: Jean-Jacques Hiblot Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9263.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index 0042f73068b0..fece8665fb63 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi @@ -523,7 +523,7 @@ }; i2c0: i2c@fff88000 { - compatible = "atmel,at91sam9263-i2c"; + compatible = "atmel,at91sam9260-i2c"; reg = <0xfff88000 0x100>; interrupts = <13 IRQ_TYPE_LEVEL_HIGH 6>; #address-cells = <1>; -- cgit v1.2.3 From 5f877518775a681b516dde700b511641fb3e4f9b Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Thu, 16 Jan 2014 16:25:34 +0100 Subject: ARM: at91/dt: fix sama5d3 ohci hclk clock reference The hclk clock of the ohci node is referencing udphs_clk instead of uhphs_clk. Signed-off-by: Boris BREZILLON Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d3.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 52447c17537a..3d5faf85f51b 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -1228,7 +1228,7 @@ compatible = "atmel,at91rm9200-ohci", "usb-ohci"; reg = <0x00600000 0x100000>; interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>; - clocks = <&usb>, <&uhphs_clk>, <&udphs_clk>, + clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>, <&uhpck>; clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck"; status = "disabled"; -- cgit v1.2.3 From d7e67ee8b2ce27f4481d3cf2ac6ba8febcc3d888 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Tue, 14 Jan 2014 14:34:44 +0800 Subject: ARM: at91: enable USB host on at91sam9n12ek board Enable USB host on at91sam9n12ek board. Signed-off-by: Bo Shen Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9n12ek.dts | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts index e9487f6f0166..924a6a6ffd0f 100644 --- a/arch/arm/boot/dts/at91sam9n12ek.dts +++ b/arch/arm/boot/dts/at91sam9n12ek.dts @@ -124,6 +124,10 @@ nand-on-flash-bbt; status = "okay"; }; + + usb0: ohci@00500000 { + status = "okay"; + }; }; leds { -- cgit v1.2.3 From b7c2b6157079811586180d13c44a1095b57c2d47 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 4 Feb 2014 15:05:55 +0100 Subject: ARM: at91: add Atmel's SAMA5D3 Xplained board Add DT file for new SAMA5D3 Xplained board. This board is based on Atmel's SAMA5D36 Cortex-A5 SoC. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/at91-sama5d3_xplained.dts | 229 ++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 arch/arm/boot/dts/at91-sama5d3_xplained.dts (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b9d6a8b485e0..6d1e43d46187 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -38,6 +38,7 @@ dtb-$(CONFIG_ARCH_AT91) += at91sam9g35ek.dtb dtb-$(CONFIG_ARCH_AT91) += at91sam9x25ek.dtb dtb-$(CONFIG_ARCH_AT91) += at91sam9x35ek.dtb # sama5d3 +dtb-$(CONFIG_ARCH_AT91) += at91-sama5d3_xplained.dtb dtb-$(CONFIG_ARCH_AT91) += sama5d31ek.dtb dtb-$(CONFIG_ARCH_AT91) += sama5d33ek.dtb dtb-$(CONFIG_ARCH_AT91) += sama5d34ek.dtb diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts new file mode 100644 index 000000000000..ce1375595e5f --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts @@ -0,0 +1,229 @@ +/* + * at91-sama5d3_xplained.dts - Device Tree file for the SAMA5D3 Xplained board + * + * Copyright (C) 2014 Atmel, + * 2014 Nicolas Ferre + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d36.dtsi" + +/ { + model = "SAMA5D3 Xplained"; + compatible = "atmel,sama5d3-xplained", "atmel,sama5d3", "atmel,sama5"; + + chosen { + bootargs = "console=ttyS0,115200"; + }; + + memory { + reg = <0x20000000 0x10000000>; + }; + + ahb { + apb { + mmc0: mmc@f0000000 { + pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_dat4_7 &pinctrl_mmc0_cd>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <8>; + cd-gpios = <&pioE 0 GPIO_ACTIVE_LOW>; + }; + }; + + spi0: spi@f0004000 { + cs-gpios = <&pioD 13 0>; + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + phy-mode = "rgmii"; + status = "okay"; + }; + + usart0: serial@f001c000 { + status = "okay"; + }; + + usart1: serial@f0020000 { + pinctrl-0 = <&pinctrl_usart1 &pinctrl_usart1_rts_cts>; + status = "okay"; + }; + + uart0: serial@f0024000 { + status = "okay"; + }; + + mmc1: mmc@f8000000 { + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioE 1 GPIO_ACTIVE_HIGH>; + }; + }; + + spi1: spi@f8008000 { + cs-gpios = <&pioC 25 0>, <0>, <0>, <&pioD 16 0>; + status = "okay"; + }; + + adc0: adc@f8018000 { + pinctrl-0 = < + &pinctrl_adc0_adtrg + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + &pinctrl_adc0_ad5 + &pinctrl_adc0_ad6 + &pinctrl_adc0_ad7 + &pinctrl_adc0_ad8 + &pinctrl_adc0_ad9 + >; + status = "okay"; + }; + + i2c2: i2c@f801c000 { + dmas = <0>, <0>; /* Do not use DMA for i2c2 */ + status = "okay"; + }; + + macb1: ethernet@f802c000 { + phy-mode = "rmii"; + status = "okay"; + }; + + dbgu: serial@ffffee00 { + status = "okay"; + }; + + pinctrl@fffff200 { + board { + pinctrl_mmc0_cd: mmc0_cd { + atmel,pins = + ; + }; + + pinctrl_mmc1_cd: mmc1_cd { + atmel,pins = + ; + }; + + pinctrl_usba_vbus: usba_vbus { + atmel,pins = + ; /* PE9, conflicts with A9 */ + }; + }; + }; + + pmc: pmc@fffffc00 { + main: mainck { + clock-frequency = <12000000>; + }; + }; + }; + + nand0: nand@60000000 { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + atmel,has-pmecc; + atmel,pmecc-cap = <4>; + atmel,pmecc-sector-size = <512>; + nand-on-flash-bbt; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0x80000>; + }; + + bootloaderenv@c0000 { + label = "bootloader env"; + reg = <0xc0000 0xc0000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; + }; + + usb0: gadget@00500000 { + atmel,vbus-gpio = <&pioE 9 GPIO_ACTIVE_HIGH>; /* PE9, conflicts with A9 */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; + status = "okay"; + }; + + usb1: ohci@00600000 { + num-ports = <3>; + atmel,vbus-gpio = <0 + &pioE 3 GPIO_ACTIVE_LOW + &pioE 4 GPIO_ACTIVE_LOW + >; + status = "okay"; + }; + + usb2: ehci@00700000 { + status = "okay"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + bp3 { + label = "PB_USER"; + gpios = <&pioE 29 GPIO_ACTIVE_LOW>; + linux,code = <0x104>; + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + + d2 { + label = "d2"; + gpios = <&pioE 23 GPIO_ACTIVE_LOW>; /* PE23, conflicts with A23, CTS2 */ + linux,default-trigger = "heartbeat"; + }; + + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; +}; -- cgit v1.2.3 From 29ffa48fa64fcdfc71d80593c8ae79248bc27677 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 4 Feb 2014 13:30:05 +0100 Subject: ARM: pxa: fix compilation problem on AM300EPD board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This board fails compilation like this: arch/arm/mach-pxa/am300epd.c: In function ‘am300_cleanup’: arch/arm/mach-pxa/am300epd.c:179:2: error: implicit declaration of function ‘PXA_GPIO_TO_IRQ’ [-Werror=implicit-function-declaration] free_irq(PXA_GPIO_TO_IRQ(RDY_GPIO_PIN), par); This was caused by commit 88f718e3fa4d67f3a8dbe79a2f97d722323e4051 "ARM: pxa: delete the custom GPIO header" This is because it was previously getting the macro PXA_GPIO_TO_IRQ implicitly from which in turn implicitly included which in turn included . Add the missing include so that the board compiles again. Reported-by: Arnd Bergmann Signed-off-by: Linus Walleij Signed-off-by: Kevin Hilman --- arch/arm/mach-pxa/am300epd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-pxa/am300epd.c b/arch/arm/mach-pxa/am300epd.c index c9f309ae88c5..8b90c4f2d430 100644 --- a/arch/arm/mach-pxa/am300epd.c +++ b/arch/arm/mach-pxa/am300epd.c @@ -30,6 +30,7 @@ #include #include +#include #include #include "generic.h" -- cgit v1.2.3 From 9705e74671f0e4f994d86b00cecf441917c64a66 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 4 Feb 2014 13:53:07 +0100 Subject: ARM: pxa: fix various compilation problems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to commit 88f718e3fa4d67f3a8dbe79a2f97d722323e4051 "ARM: pxa: delete the custom GPIO header" some drivers fail compilation, for example like this: In file included from sound/soc/pxa/spitz.c:28:0: sound/soc/pxa/spitz.c: In function ‘spitz_ext_control’: arch/arm/mach-pxa/include/mach/spitz.h:111:30: error: ‘PXA_NR_BUILTIN_GPIO’ undeclared (first use in this function) #define SPITZ_SCP_GPIO_BASE (PXA_NR_BUILTIN_GPIO) (etc.) This is caused by implicit inclusion of from various board-specific headers under in the PXA platform. So we take a sweep over these, and for every such header that uses PXA_NR_BUILTIN_GPIO or PXA_GPIO_TO_IRQ() we explicitly #include "irqs.h" so that we satisfy the dependency in the board include file alone. Reported-by: Arnd Bergmann Signed-off-by: Linus Walleij Cc: stable@vger.kernel.org # v3.13+ Signed-off-by: Kevin Hilman --- arch/arm/mach-pxa/include/mach/balloon3.h | 2 ++ arch/arm/mach-pxa/include/mach/corgi.h | 1 + arch/arm/mach-pxa/include/mach/csb726.h | 2 ++ arch/arm/mach-pxa/include/mach/gumstix.h | 1 + arch/arm/mach-pxa/include/mach/idp.h | 1 + arch/arm/mach-pxa/include/mach/palmld.h | 2 ++ arch/arm/mach-pxa/include/mach/palmt5.h | 2 ++ arch/arm/mach-pxa/include/mach/palmtc.h | 2 ++ arch/arm/mach-pxa/include/mach/palmtx.h | 2 ++ arch/arm/mach-pxa/include/mach/pcm027.h | 2 ++ arch/arm/mach-pxa/include/mach/pcm990_baseboard.h | 1 + arch/arm/mach-pxa/include/mach/poodle.h | 2 ++ arch/arm/mach-pxa/include/mach/spitz.h | 2 +- arch/arm/mach-pxa/include/mach/tosa.h | 2 ++ arch/arm/mach-pxa/include/mach/trizeps4.h | 2 ++ 15 files changed, 25 insertions(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-pxa/include/mach/balloon3.h b/arch/arm/mach-pxa/include/mach/balloon3.h index 954641e6c8b1..1b0825911e62 100644 --- a/arch/arm/mach-pxa/include/mach/balloon3.h +++ b/arch/arm/mach-pxa/include/mach/balloon3.h @@ -14,6 +14,8 @@ #ifndef ASM_ARCH_BALLOON3_H #define ASM_ARCH_BALLOON3_H +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */ + enum balloon3_features { BALLOON3_FEATURE_OHCI, BALLOON3_FEATURE_MMC, diff --git a/arch/arm/mach-pxa/include/mach/corgi.h b/arch/arm/mach-pxa/include/mach/corgi.h index f3c3493b468d..c030d955bbd7 100644 --- a/arch/arm/mach-pxa/include/mach/corgi.h +++ b/arch/arm/mach-pxa/include/mach/corgi.h @@ -13,6 +13,7 @@ #ifndef __ASM_ARCH_CORGI_H #define __ASM_ARCH_CORGI_H 1 +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */ /* * Corgi (Non Standard) GPIO Definitions diff --git a/arch/arm/mach-pxa/include/mach/csb726.h b/arch/arm/mach-pxa/include/mach/csb726.h index 2628e7b72116..00cfbbbf73f7 100644 --- a/arch/arm/mach-pxa/include/mach/csb726.h +++ b/arch/arm/mach-pxa/include/mach/csb726.h @@ -11,6 +11,8 @@ #ifndef CSB726_H #define CSB726_H +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + #define CSB726_GPIO_IRQ_LAN 52 #define CSB726_GPIO_IRQ_SM501 53 #define CSB726_GPIO_MMC_DETECT 100 diff --git a/arch/arm/mach-pxa/include/mach/gumstix.h b/arch/arm/mach-pxa/include/mach/gumstix.h index dba14b6503ad..f7df27bbb42e 100644 --- a/arch/arm/mach-pxa/include/mach/gumstix.h +++ b/arch/arm/mach-pxa/include/mach/gumstix.h @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ /* BTRESET - Reset line to Bluetooth module, active low signal. */ #define GPIO_GUMSTIX_BTRESET 7 diff --git a/arch/arm/mach-pxa/include/mach/idp.h b/arch/arm/mach-pxa/include/mach/idp.h index 22a96f87232b..7e63f4680271 100644 --- a/arch/arm/mach-pxa/include/mach/idp.h +++ b/arch/arm/mach-pxa/include/mach/idp.h @@ -23,6 +23,7 @@ * IDP hardware. */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ #define IDP_FLASH_PHYS (PXA_CS0_PHYS) #define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS) diff --git a/arch/arm/mach-pxa/include/mach/palmld.h b/arch/arm/mach-pxa/include/mach/palmld.h index 2c4471336570..b184f296023b 100644 --- a/arch/arm/mach-pxa/include/mach/palmld.h +++ b/arch/arm/mach-pxa/include/mach/palmld.h @@ -13,6 +13,8 @@ #ifndef _INCLUDE_PALMLD_H_ #define _INCLUDE_PALMLD_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/palmt5.h b/arch/arm/mach-pxa/include/mach/palmt5.h index 0bd4f036c72f..e342c5921405 100644 --- a/arch/arm/mach-pxa/include/mach/palmt5.h +++ b/arch/arm/mach-pxa/include/mach/palmt5.h @@ -15,6 +15,8 @@ #ifndef _INCLUDE_PALMT5_H_ #define _INCLUDE_PALMT5_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/palmtc.h b/arch/arm/mach-pxa/include/mach/palmtc.h index c383a21680b6..81c727b3cfd2 100644 --- a/arch/arm/mach-pxa/include/mach/palmtc.h +++ b/arch/arm/mach-pxa/include/mach/palmtc.h @@ -16,6 +16,8 @@ #ifndef _INCLUDE_PALMTC_H_ #define _INCLUDE_PALMTC_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/palmtx.h b/arch/arm/mach-pxa/include/mach/palmtx.h index f2e530380253..92bc1f05300d 100644 --- a/arch/arm/mach-pxa/include/mach/palmtx.h +++ b/arch/arm/mach-pxa/include/mach/palmtx.h @@ -16,6 +16,8 @@ #ifndef _INCLUDE_PALMTX_H_ #define _INCLUDE_PALMTX_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /** HERE ARE GPIOs **/ /* GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/pcm027.h b/arch/arm/mach-pxa/include/mach/pcm027.h index 6bf28de228bd..86ebd7b6c960 100644 --- a/arch/arm/mach-pxa/include/mach/pcm027.h +++ b/arch/arm/mach-pxa/include/mach/pcm027.h @@ -23,6 +23,8 @@ * Definitions of CPU card resources only */ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /* phyCORE-PXA270 (PCM027) Interrupts */ #define PCM027_IRQ(x) (IRQ_BOARD_START + (x)) #define PCM027_BTDET_IRQ PCM027_IRQ(0) diff --git a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h b/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h index 0260aaa2fc17..7e544c14967e 100644 --- a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h +++ b/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h @@ -20,6 +20,7 @@ */ #include +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ /* * definitions relevant only when the PCM-990 diff --git a/arch/arm/mach-pxa/include/mach/poodle.h b/arch/arm/mach-pxa/include/mach/poodle.h index f32ff75dcca8..b56b19351a03 100644 --- a/arch/arm/mach-pxa/include/mach/poodle.h +++ b/arch/arm/mach-pxa/include/mach/poodle.h @@ -15,6 +15,8 @@ #ifndef __ASM_ARCH_POODLE_H #define __ASM_ARCH_POODLE_H 1 +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /* * GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/spitz.h b/arch/arm/mach-pxa/include/mach/spitz.h index 0bfe6507c95d..25c9f62e46aa 100644 --- a/arch/arm/mach-pxa/include/mach/spitz.h +++ b/arch/arm/mach-pxa/include/mach/spitz.h @@ -15,8 +15,8 @@ #define __ASM_ARCH_SPITZ_H 1 #endif +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO, PXA_GPIO_TO_IRQ */ #include -#include /* Spitz/Akita GPIOs */ diff --git a/arch/arm/mach-pxa/include/mach/tosa.h b/arch/arm/mach-pxa/include/mach/tosa.h index 2bb0e862598c..0497d95cef25 100644 --- a/arch/arm/mach-pxa/include/mach/tosa.h +++ b/arch/arm/mach-pxa/include/mach/tosa.h @@ -13,6 +13,8 @@ #ifndef _ASM_ARCH_TOSA_H_ #define _ASM_ARCH_TOSA_H_ 1 +#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */ + /* TOSA Chip selects */ #define TOSA_LCDC_PHYS PXA_CS4_PHYS /* Internel Scoop */ diff --git a/arch/arm/mach-pxa/include/mach/trizeps4.h b/arch/arm/mach-pxa/include/mach/trizeps4.h index d2ca01053f69..ae3ca013afab 100644 --- a/arch/arm/mach-pxa/include/mach/trizeps4.h +++ b/arch/arm/mach-pxa/include/mach/trizeps4.h @@ -10,6 +10,8 @@ #ifndef _TRIPEPS4_H_ #define _TRIPEPS4_H_ +#include "irqs.h" /* PXA_GPIO_TO_IRQ */ + /* physical memory regions */ #define TRIZEPS4_FLASH_PHYS (PXA_CS0_PHYS) /* Flash region */ #define TRIZEPS4_DISK_PHYS (PXA_CS1_PHYS) /* Disk On Chip region */ -- cgit v1.2.3 From e7c57ecd6019cc6392223605aed18cce257c3eff Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 29 Jan 2014 17:10:04 +0100 Subject: ARM: imx6: Initialize low-power mode early again Since commit 9e8147bb5ec5d1dda2141da70f96b98985a306cb "ARM: imx6q: move low-power code out of clock driver" the kernel fails to boot on i.MX6Q/D if preemption is enabled (CONFIG_PREEMPT=y). The kernel just hangs before the console comes up. The above commit moved the initalization of the low-power mode setting (enabling clocked WAIT states), which was introduced in commit 83ae20981ae924c37d02a42c829155fc3851260c "ARM: imx: correct low-power mode setting", from imx6q_clks_init to imx6q_pm_init. Now it is called much later, after all cores are enabled. This patch moves the low-power mode initialization back to imx6q_clks_init again (and to imx6sl_clks_init). Signed-off-by: Philipp Zabel Signed-off-by: Shawn Guo Signed-off-by: Kevin Hilman --- arch/arm/mach-imx/clk-imx6q.c | 3 +++ arch/arm/mach-imx/clk-imx6sl.c | 3 +++ arch/arm/mach-imx/pm-imx6q.c | 2 -- 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c index af2e582d2b74..4d677f442539 100644 --- a/arch/arm/mach-imx/clk-imx6q.c +++ b/arch/arm/mach-imx/clk-imx6q.c @@ -482,6 +482,9 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) if (IS_ENABLED(CONFIG_PCI_IMX6)) clk_set_parent(clk[lvds1_sel], clk[sata_ref]); + /* Set initial power mode */ + imx6q_set_lpm(WAIT_CLOCKED); + np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt"); base = of_iomap(np, 0); WARN_ON(!base); diff --git a/arch/arm/mach-imx/clk-imx6sl.c b/arch/arm/mach-imx/clk-imx6sl.c index 3781a1853998..4c86f3035205 100644 --- a/arch/arm/mach-imx/clk-imx6sl.c +++ b/arch/arm/mach-imx/clk-imx6sl.c @@ -266,6 +266,9 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node) /* Audio-related clocks configuration */ clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]); + /* Set initial power mode */ + imx6q_set_lpm(WAIT_CLOCKED); + np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpt"); base = of_iomap(np, 0); WARN_ON(!base); diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c index 9d47adc078aa..7a9b98589db7 100644 --- a/arch/arm/mach-imx/pm-imx6q.c +++ b/arch/arm/mach-imx/pm-imx6q.c @@ -236,8 +236,6 @@ void __init imx6q_pm_init(void) regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT, IMX6Q_GPR1_GINT); - /* Set initial power mode */ - imx6q_set_lpm(WAIT_CLOCKED); suspend_set_ops(&imx6q_pm_ops); } -- cgit v1.2.3 From 5db1dabc562b27c356376fbb527a746dcf7c9572 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 6 Feb 2014 09:29:31 -0600 Subject: ARM: multi_v7_defconfig: Select CONFIG_SOC_DRA7XX Select CONFIG_SOC_DRA7XX so that we can boot dra7-evm. DRA7 family are A15 based processors that supports LPAE and an evolutionary update to the OMAP5 generation of processors. Signed-off-by: Nishanth Menon Signed-off-by: Kevin Hilman --- arch/arm/configs/multi_v7_defconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm') diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 845bc745706b..ee6982976d66 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -29,6 +29,7 @@ CONFIG_ARCH_OMAP3=y CONFIG_ARCH_OMAP4=y CONFIG_SOC_OMAP5=y CONFIG_SOC_AM33XX=y +CONFIG_SOC_DRA7XX=y CONFIG_SOC_AM43XX=y CONFIG_ARCH_ROCKCHIP=y CONFIG_ARCH_SOCFPGA=y -- cgit v1.2.3 From 46f5b96085b03f9e71a0134de77efc6a1f9d84c3 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 31 Jan 2014 12:55:06 +0100 Subject: ARM: zynq: Reserve not DMAable space in front of the kernel Reserve space from 0x0 - __pa(swapper_pg_dir), if kernel is loaded from 0, which is not DMAable. It is causing problem with MMC driver and others which want to add dma buffers to this space. Signed-off-by: Michal Simek Signed-off-by: Kevin Hilman --- arch/arm/mach-zynq/common.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 1db2a5ca9ab8..8c09a8393fb6 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -41,6 +42,18 @@ void __iomem *zynq_scu_base; +/** + * zynq_memory_init - Initialize special memory + * + * We need to stop things allocating the low memory as DMA can't work in + * the 1st 512K of memory. + */ +static void __init zynq_memory_init(void) +{ + if (!__pa(PAGE_OFFSET)) + memblock_reserve(__pa(PAGE_OFFSET), __pa(swapper_pg_dir)); +} + static struct platform_device zynq_cpuidle_device = { .name = "cpuidle-zynq", }; @@ -117,5 +130,6 @@ DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform") .init_machine = zynq_init_machine, .init_time = zynq_timer_init, .dt_compat = zynq_dt_match, + .reserve = zynq_memory_init, .restart = zynq_system_reset, MACHINE_END -- cgit v1.2.3 From 902e6a0c7eba08ec978cea8304c6cb2ddce7b9dc Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 20 Dec 2013 10:46:52 +0100 Subject: ARM: pxa: Add dummy backlight power supply on Mitac Mio A701 Recent changes to the pwm-backlight driver have made the power supply mandatory. There is code in the regulator core to deal with situations where no regulator is specified and provide a dummy, but that works on DT-based boards only. The situation can be remedied by adding a dummy regulator during board initialization. Tested-by: Robert Jarzmik Signed-off-by: Thierry Reding Signed-off-by: Haojian Zhuang --- arch/arm/mach-pxa/mioa701.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index f70583fee59f..29997bde277d 100644 --- a/arch/arm/mach-pxa/mioa701.c +++ b/arch/arm/mach-pxa/mioa701.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -714,6 +715,10 @@ static struct gpio global_gpios[] = { { GPIO56_MT9M111_nOE, GPIOF_OUT_INIT_LOW, "Camera nOE" }, }; +static struct regulator_consumer_supply fixed_5v0_consumers[] = { + REGULATOR_SUPPLY("power", "pwm-backlight"), +}; + static void __init mioa701_machine_init(void) { int rc; @@ -753,6 +758,10 @@ static void __init mioa701_machine_init(void) pxa_set_i2c_info(&i2c_pdata); pxa27x_set_i2c_power_info(NULL); pxa_set_camera_info(&mioa701_pxacamera_platform_data); + + regulator_register_always_on(0, "fixed-5.0V", fixed_5v0_consumers, + ARRAY_SIZE(fixed_5v0_consumers), + 5000000); } static void mioa701_machine_exit(void) -- cgit v1.2.3 From 10c8562f932d89c030083e15f9279971ed637136 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 16 Jan 2014 15:39:17 +0100 Subject: ARM: dma-mapping: fix GFP_ATOMIC macro usage GFP_ATOMIC is not a single gfp flag, but a macro which expands to the other flags and LACK of __GFP_WAIT flag. To check if caller wanted to perform an atomic allocation, the code must test __GFP_WAIT flag presence. This patch fixes the issue introduced in v3.6-rc5 Signed-off-by: Marek Szyprowski CC: stable@vger.kernel.org --- arch/arm/mm/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 1a77450e728a..11b3914660d2 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1358,7 +1358,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size, *handle = DMA_ERROR_CODE; size = PAGE_ALIGN(size); - if (gfp & GFP_ATOMIC) + if (!(gfp & __GFP_WAIT)) return __iommu_alloc_atomic(dev, size, handle); /* -- cgit v1.2.3 From 8858d88a25142544843869f0cd3e6654aa7b4aec Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 11 Feb 2014 14:02:37 +0100 Subject: ARM: ux500: disable msp2 device tree node Commit 70b41abc151f9 "ARM: ux500: move MSP pin control to the device tree" accidentally activated MSP2, giving rise to a boot scroll scream as the kernel attempts to probe a driver for it and fails to obtain DMA channel 14. Fix this up by marking the node disabled again. Acked-by: Lee Jones Signed-off-by: Linus Walleij Signed-off-by: Kevin Hilman --- arch/arm/boot/dts/ste-href.dtsi | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/ste-href.dtsi b/arch/arm/boot/dts/ste-href.dtsi index 0c1e8d871ed1..6cb9b68e2188 100644 --- a/arch/arm/boot/dts/ste-href.dtsi +++ b/arch/arm/boot/dts/ste-href.dtsi @@ -188,7 +188,6 @@ msp2: msp@80117000 { pinctrl-names = "default"; pinctrl-0 = <&msp2_default_mode>; - status = "okay"; }; msp3: msp@80125000 { -- cgit v1.2.3 From d26794c04553901d00c4ca1542e1cbf4ec9580fb Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Sat, 21 Dec 2013 16:12:23 +0100 Subject: ARM: dts: omap3-gta04: Add EOC irq gpio line handling. BMP085 EOC (End Of Conversion) irq line is connected to gpio113 on gta04. Set irq properties to have driver using irq instead polling for EOC. Signed-off-by: Marek Belisko Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-gta04.dts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/omap3-gta04.dts b/arch/arm/boot/dts/omap3-gta04.dts index b9b55c95a566..7a8e37de51b8 100644 --- a/arch/arm/boot/dts/omap3-gta04.dts +++ b/arch/arm/boot/dts/omap3-gta04.dts @@ -92,6 +92,8 @@ bmp085@77 { compatible = "bosch,bmp085"; reg = <0x77>; + interrupt-parent = <&gpio4>; + interrupts = <17 IRQ_TYPE_EDGE_RISING>; }; /* leds */ -- cgit v1.2.3 From 967d6a0bbfddcc25a7d1debbe8e2e4e7161d0566 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 23 Dec 2013 11:28:34 +0200 Subject: ARM: DTS: am335x-evmsk: Correct audio clock frequency The clock for audio is sourced from virt_24000000_ck, so the correct frequency is 24000000. Signed-off-by: Peter Ujfalusi Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/am335x-evmsk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index 4718ec4a4dbf..50abe53f6887 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -121,7 +121,7 @@ ti,model = "AM335x-EVMSK"; ti,audio-codec = <&tlv320aic3106>; ti,mcasp-controller = <&mcasp1>; - ti,codec-clock-rate = <24576000>; + ti,codec-clock-rate = <24000000>; ti,audio-routing = "Headphone Jack", "HPLOUT", "Headphone Jack", "HPROUT"; -- cgit v1.2.3 From 29ea5efb0bb612d352aa360de26e2095cb230e4a Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 23 Dec 2013 11:28:35 +0200 Subject: ARM: dts: am335x-evmsk: Fix mmc1 support Add pinctrl section and cd-gpio to mmc1. Without these the SD card is not working on EVM-SK board. Signed-off-by: Peter Ujfalusi Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/am335x-evmsk.dts | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index 50abe53f6887..486880b74831 100644 --- a/arch/arm/boot/dts/am335x-evmsk.dts +++ b/arch/arm/boot/dts/am335x-evmsk.dts @@ -256,6 +256,12 @@ >; }; + mmc1_pins: pinmux_mmc1_pins { + pinctrl-single,pins = < + 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */ + >; + }; + mcasp1_pins: mcasp1_pins { pinctrl-single,pins = < 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */ @@ -456,6 +462,9 @@ status = "okay"; vmmc-supply = <&vmmc_reg>; bus-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; }; &sham { -- cgit v1.2.3 From 22106c11252833419a29c9294411101cb2199a5f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 15 Jan 2014 14:00:38 -0600 Subject: ARM: OMAP2+: add missing ARCH_HAS_OPP OMAP5, DRA7, AM43xx all have OPPs. So select the same to allow SoC only configuration boot to work with OPP. Reported-by: Nikhil Devshatwar Signed-off-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 653b489479e0..8165a4a3ce20 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -50,6 +50,7 @@ config SOC_OMAP5 bool "TI OMAP5" depends on ARCH_MULTI_V7 select ARCH_OMAP2PLUS + select ARCH_HAS_OPP select ARM_CPU_SUSPEND if PM select ARM_GIC select CPU_V7 @@ -63,6 +64,7 @@ config SOC_AM33XX bool "TI AM33XX" depends on ARCH_MULTI_V7 select ARCH_OMAP2PLUS + select ARCH_HAS_OPP select ARM_CPU_SUSPEND if PM select CPU_V7 select MULTI_IRQ_HANDLER @@ -72,6 +74,7 @@ config SOC_AM43XX depends on ARCH_MULTI_V7 select CPU_V7 select ARCH_OMAP2PLUS + select ARCH_HAS_OPP select MULTI_IRQ_HANDLER select ARM_GIC select MACH_OMAP_GENERIC @@ -80,6 +83,7 @@ config SOC_DRA7XX bool "TI DRA7XX" depends on ARCH_MULTI_V7 select ARCH_OMAP2PLUS + select ARCH_HAS_OPP select ARM_CPU_SUSPEND if PM select ARM_GIC select CPU_V7 -- cgit v1.2.3 From d8bd67317455744039e10fe33d6c76b82262c647 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 25 Jan 2014 22:28:55 +0100 Subject: ARM: dts: omap3-gta04: Fix 'aux' gpio key flags. It should be ACTIVE_HIGH. Signed-off-by: NeilBrown Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-gta04.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/omap3-gta04.dts b/arch/arm/boot/dts/omap3-gta04.dts index 7a8e37de51b8..81e0bb477bcd 100644 --- a/arch/arm/boot/dts/omap3-gta04.dts +++ b/arch/arm/boot/dts/omap3-gta04.dts @@ -32,7 +32,7 @@ aux-button { label = "aux"; linux,code = <169>; - gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; gpio-key,wakeup; }; }; -- cgit v1.2.3 From 2d6ac29e6a043c3adc3e82f5200ae1e07617e3ea Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Sat, 25 Jan 2014 22:28:57 +0100 Subject: ARM: dts: omap3-gta04: Fix mmc1 properties. Does not have an aux supply, and must be non-removable. Otherwise it is removed during suspend and filesystem gets confused. Signed-off-by: NeilBrown Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-gta04.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/omap3-gta04.dts b/arch/arm/boot/dts/omap3-gta04.dts index 81e0bb477bcd..c551e4af4d83 100644 --- a/arch/arm/boot/dts/omap3-gta04.dts +++ b/arch/arm/boot/dts/omap3-gta04.dts @@ -143,8 +143,8 @@ pinctrl-names = "default"; pinctrl-0 = <&mmc1_pins>; vmmc-supply = <&vmmc1>; - vmmc_aux-supply = <&vsim>; bus-width = <4>; + ti,non-removable; }; &mmc2 { -- cgit v1.2.3 From 6b187b21c92b6e2c7e8ef0b450181c37a3f31681 Mon Sep 17 00:00:00 2001 From: Pekon Gupta Date: Tue, 28 Jan 2014 11:42:40 +0530 Subject: ARM: OMAP2+: gpmc: fix: DT NAND child nodes not probed when MTD_NAND is built as module Fixes: commit bc6b1e7b86f5d8e4a6fc1c0189e64bba4077efe0 ARM: OMAP: gpmc: add DT bindings for GPMC timings and NAND OMAP SoC(s) depend on GPMC controller driver to parse GPMC DT child nodes and register them platform_device for NAND driver to probe later. However this does not happen if generic MTD_NAND framework is built as module (CONFIG_MTD_NAND=m). Therefore, when MTD/NAND and MTD/NAND/OMAP2 modules are loaded, they are unable to find any matching platform_device and remain un-binded. This causes on board NAND flash to remain un-detected. This patch causes GPMC controller to parse DT nodes when CONFIG_MTD_NAND=y || CONFIG_MTD_NAND=m CC: # 3.9.x+ Signed-off-by: Pekon Gupta Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index d24926e6340f..c77a84b63a59 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1339,7 +1339,7 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np, of_property_read_bool(np, "gpmc,time-para-granularity"); } -#ifdef CONFIG_MTD_NAND +#if IS_ENABLED(CONFIG_MTD_NAND) static const char * const nand_xfer_types[] = { [NAND_OMAP_PREFETCH_POLLED] = "prefetch-polled", -- cgit v1.2.3 From 980386d2d6d49e0b42f48550853ef1ad6aa5d79a Mon Sep 17 00:00:00 2001 From: Pekon Gupta Date: Tue, 28 Jan 2014 11:42:41 +0530 Subject: ARM: OMAP2+: gpmc: fix: DT ONENAND child nodes not probed when MTD_ONENAND is built as module Fixes: commit 75d3625e0e86b2d8d77b4e9c6f685fd7ea0d5a96 ARM: OMAP2+: gpmc: add DT bindings for OneNAND OMAP SoC(s) depend on GPMC controller driver to parse GPMC DT child nodes and register them platform_device for ONENAND driver to probe later. However this does not happen if generic MTD_ONENAND framework is built as module (CONFIG_MTD_ONENAND=m). Therefore, when MTD/ONENAND and MTD/ONENAND/OMAP2 modules are loaded, they are unable to find any matching platform_device and remain un-binded. This causes on board ONENAND flash to remain un-detected. This patch causes GPMC controller to parse DT nodes when CONFIG_MTD_ONENAND=y || CONFIG_MTD_ONENAND=m CC: # 3.9.x+ Signed-off-by: Pekon Gupta Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/gpmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index c77a84b63a59..ab43755364f5 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -1429,7 +1429,7 @@ static int gpmc_probe_nand_child(struct platform_device *pdev, } #endif -#ifdef CONFIG_MTD_ONENAND +#if IS_ENABLED(CONFIG_MTD_ONENAND) static int gpmc_probe_onenand_child(struct platform_device *pdev, struct device_node *child) { -- cgit v1.2.3 From 8c5cb1a8f81370f60c62450fa5a5cf20aa081050 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sat, 8 Feb 2014 15:48:55 +0200 Subject: ARM: OMAP1: nokia770: enable tahvo-usb Add platform data for tahvo-usb. This is the last missing piece to get Tahvo USB working with 3.14. Signed-off-by: Aaro Koskinen Signed-off-by: Tony Lindgren --- arch/arm/mach-omap1/board-nokia770.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index 91449c5cb70f..85089d821982 100644 --- a/arch/arm/mach-omap1/board-nokia770.c +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -156,6 +156,7 @@ static struct omap_usb_config nokia770_usb_config __initdata = { .register_dev = 1, .hmc_mode = 16, .pins[0] = 6, + .extcon = "tahvo-usb", }; #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) -- cgit v1.2.3 From 2a074deffd66d5e1893e859dc0737887fea9d46d Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 9 Feb 2014 14:12:35 +0200 Subject: ARM: dts: N9/N950: fix boot hang with 3.14-rc1 N9/N950 does not boot anymore with 3.14-rc1, because SoC compatible property is missing. Fix that. Signed-off-by: Aaro Koskinen Reviewed-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-n9.dts | 2 +- arch/arm/boot/dts/omap3-n950.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/omap3-n9.dts b/arch/arm/boot/dts/omap3-n9.dts index 39828ce464ee..9938b5dc1909 100644 --- a/arch/arm/boot/dts/omap3-n9.dts +++ b/arch/arm/boot/dts/omap3-n9.dts @@ -14,5 +14,5 @@ / { model = "Nokia N9"; - compatible = "nokia,omap3-n9", "ti,omap3"; + compatible = "nokia,omap3-n9", "ti,omap36xx", "ti,omap3"; }; diff --git a/arch/arm/boot/dts/omap3-n950.dts b/arch/arm/boot/dts/omap3-n950.dts index b076a526b999..261c5589bfa3 100644 --- a/arch/arm/boot/dts/omap3-n950.dts +++ b/arch/arm/boot/dts/omap3-n950.dts @@ -14,5 +14,5 @@ / { model = "Nokia N950"; - compatible = "nokia,omap3-n950", "ti,omap3"; + compatible = "nokia,omap3-n950", "ti,omap36xx", "ti,omap3"; }; -- cgit v1.2.3 From c3580bc12569b4c02ab5505b853825d863e6f86e Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 9 Feb 2014 14:12:36 +0200 Subject: ARM: dts: N900: add missing compatible property Add missing compatible property to avoid problems in the future. Signed-off-by: Aaro Koskinen Reviewed-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-n900.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index 6fc85f963530..0bf40c90faba 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -1,6 +1,6 @@ /* * Copyright (C) 2013 Pavel Machek - * Copyright 2013 Aaro Koskinen + * Copyright (C) 2013-2014 Aaro Koskinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 (or later) as @@ -13,7 +13,7 @@ / { model = "Nokia N900"; - compatible = "nokia,omap3-n900", "ti,omap3"; + compatible = "nokia,omap3-n900", "ti,omap3430", "ti,omap3"; cpus { cpu@0 { -- cgit v1.2.3 From 84b57c84b10de62d832b04da02af9cba60199d0c Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sun, 9 Feb 2014 16:01:28 +0100 Subject: ARM: OMAP2+: Remove MACH_NOKIA_N800 The last caller of machine_is_nokia_n800() was removed in commit 5a87cde490e1 ("ARM: OMAP2+: Remove legacy booting support for n8x0"). That means that the Kconfig symbol MACH_NOKIA_N800 is now unused. It can safely be removed. Signed-off-by: Paul Bolle Acked-by: Aaro Koskinen Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Kconfig | 4 ---- 1 file changed, 4 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 8165a4a3ce20..9320252ca43a 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -272,9 +272,6 @@ config MACH_OMAP_3430SDP default y select OMAP_PACKAGE_CBB -config MACH_NOKIA_N800 - bool - config MACH_NOKIA_N810 bool @@ -285,7 +282,6 @@ config MACH_NOKIA_N8X0 bool "Nokia N800/N810" depends on SOC_OMAP2420 default y - select MACH_NOKIA_N800 select MACH_NOKIA_N810 select MACH_NOKIA_N810_WIMAX select OMAP_PACKAGE_ZAC -- cgit v1.2.3 From 43e21ef061598024dcb4821b97b9eaebfed0b50d Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Wed, 12 Feb 2014 10:45:52 +0100 Subject: ARM: OMAP2+: Remove legacy macros for zoom platforms Commit 97411608fd5f ("ARM: OMAP2+: Remove legacy support for zoom platforms") removed the Kconfig symbols MACH_OMAP_ZOOM2 and MACH_OMAP_ZOOM3. Remove the last usage of the related macros too. Signed-off-by: Paul Bolle Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/io.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index d408b15b4fbf..af432b191255 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -179,15 +179,6 @@ static struct map_desc omap34xx_io_desc[] __initdata = { .length = L4_EMU_34XX_SIZE, .type = MT_DEVICE }, -#if defined(CONFIG_DEBUG_LL) && \ - (defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)) - { - .virtual = ZOOM_UART_VIRT, - .pfn = __phys_to_pfn(ZOOM_UART_BASE), - .length = SZ_1M, - .type = MT_DEVICE - }, -#endif }; #endif -- cgit v1.2.3 From df1a29f4768a3de4ea793ff0b4c6e79ffa15849d Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Thu, 13 Feb 2014 11:25:13 +0100 Subject: ARM: dts: omap3-tobi: Fix boot with OMAP36xx-based Overo Tobi expansion board can be used with both OMAP35xx-based Overo, and OMAP36xx-based Overo. Currently the boot is broken with newer OMAP36xx-based Overo (Storm and alike). Fix include file and compatible string to be able to boot newer models. This will break older models. This will be addressed later. Signed-off-by: Florian Vaussard Tested-by: Kevin Hilman Acked-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-overo.dtsi | 3 --- arch/arm/boot/dts/omap3-tobi.dts | 5 ++++- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/omap3-overo.dtsi b/arch/arm/boot/dts/omap3-overo.dtsi index a461d2fd1fb0..597099907f8e 100644 --- a/arch/arm/boot/dts/omap3-overo.dtsi +++ b/arch/arm/boot/dts/omap3-overo.dtsi @@ -9,9 +9,6 @@ /* * The Gumstix Overo must be combined with an expansion board. */ -/dts-v1/; - -#include "omap34xx.dtsi" / { pwmleds { diff --git a/arch/arm/boot/dts/omap3-tobi.dts b/arch/arm/boot/dts/omap3-tobi.dts index 7e4ad2aec37a..0e3b8bf49761 100644 --- a/arch/arm/boot/dts/omap3-tobi.dts +++ b/arch/arm/boot/dts/omap3-tobi.dts @@ -10,11 +10,14 @@ * Tobi expansion board is manufactured by Gumstix Inc. */ +/dts-v1/; + +#include "omap36xx.dtsi" #include "omap3-overo.dtsi" / { model = "TI OMAP3 Gumstix Overo on Tobi"; - compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3"; + compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap36xx", "ti,omap3"; leds { compatible = "gpio-leds"; -- cgit v1.2.3 From 1ce64826b02032827abb166fc2d8909171d4b296 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Thu, 13 Feb 2014 11:25:14 +0100 Subject: ARM: dts: omap3-tobi: Use the correct vendor prefix Gumstix is the correct vendor for all Overo related products. Reported-by: Javier Martinez Canillas Signed-off-by: Florian Vaussard Acked-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/omap3-tobi.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/omap3-tobi.dts b/arch/arm/boot/dts/omap3-tobi.dts index 0e3b8bf49761..c742afaa2c26 100644 --- a/arch/arm/boot/dts/omap3-tobi.dts +++ b/arch/arm/boot/dts/omap3-tobi.dts @@ -17,7 +17,7 @@ / { model = "TI OMAP3 Gumstix Overo on Tobi"; - compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap36xx", "ti,omap3"; + compatible = "gumstix,omap3-tobi", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3"; leds { compatible = "gpio-leds"; -- cgit v1.2.3 From f03ef09b6f59c0807d6aeba10f18238be1ea6390 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Thu, 13 Feb 2014 11:25:15 +0100 Subject: ARM: dts: Add support for both OMAP35xx and OMAP36xx Overo/Tobi Unfortunatly the device tree for older OMAP35xx Overo cannot be used with newer OMAP36xx and vice-versa. To address this issue, move most of the Tobi DTS to a common include file, and create model-specific Tobi DTS. Signed-off-by: Florian Vaussard Tested-by: Kevin Hilman Acked-by: Nishanth Menon Signed-off-by: Tony Lindgren --- arch/arm/boot/dts/Makefile | 3 +- arch/arm/boot/dts/omap3-overo-storm-tobi.dts | 22 +++++++ arch/arm/boot/dts/omap3-overo-tobi-common.dtsi | 80 ++++++++++++++++++++++++ arch/arm/boot/dts/omap3-overo-tobi.dts | 22 +++++++ arch/arm/boot/dts/omap3-tobi.dts | 86 -------------------------- 5 files changed, 126 insertions(+), 87 deletions(-) create mode 100644 arch/arm/boot/dts/omap3-overo-storm-tobi.dts create mode 100644 arch/arm/boot/dts/omap3-overo-tobi-common.dtsi create mode 100644 arch/arm/boot/dts/omap3-overo-tobi.dts delete mode 100644 arch/arm/boot/dts/omap3-tobi.dts (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index b9d6a8b485e0..e8355f4d8b0c 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -208,7 +208,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \ omap3-n900.dtb \ omap3-n9.dtb \ omap3-n950.dtb \ - omap3-tobi.dtb \ + omap3-overo-tobi.dtb \ + omap3-overo-storm-tobi.dtb \ omap3-gta04.dtb \ omap3-igep0020.dtb \ omap3-igep0030.dtb \ diff --git a/arch/arm/boot/dts/omap3-overo-storm-tobi.dts b/arch/arm/boot/dts/omap3-overo-storm-tobi.dts new file mode 100644 index 000000000000..966b5c9cd96a --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-storm-tobi.dts @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group + * + * 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. + */ + +/* + * Tobi expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap36xx.dtsi" +#include "omap3-overo-tobi-common.dtsi" + +/ { + model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Tobi"; + compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3"; +}; + diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi new file mode 100644 index 000000000000..4edc013a91c1 --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group + * + * 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. + */ + +/* + * Tobi expansion board is manufactured by Gumstix Inc. + */ + +#include "omap3-overo.dtsi" + +/ { + leds { + compatible = "gpio-leds"; + heartbeat { + label = "overo:red:gpio21"; + gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; + + vddvario: regulator-vddvario { + compatible = "regulator-fixed"; + regulator-name = "vddvario"; + regulator-always-on; + }; + + vdd33a: regulator-vdd33a { + compatible = "regulator-fixed"; + regulator-name = "vdd33a"; + regulator-always-on; + }; +}; + +&gpmc { + ranges = <5 0 0x2c000000 0x1000000>; /* CS5 */ + + ethernet@5,0 { + compatible = "smsc,lan9221", "smsc,lan9115"; + reg = <5 0 0xff>; + bank-width = <2>; + + gpmc,mux-add-data; + gpmc,cs-on-ns = <0>; + gpmc,cs-rd-off-ns = <42>; + gpmc,cs-wr-off-ns = <36>; + gpmc,adv-on-ns = <6>; + gpmc,adv-rd-off-ns = <12>; + gpmc,adv-wr-off-ns = <12>; + gpmc,oe-on-ns = <0>; + gpmc,oe-off-ns = <42>; + gpmc,we-on-ns = <0>; + gpmc,we-off-ns = <36>; + gpmc,rd-cycle-ns = <60>; + gpmc,wr-cycle-ns = <54>; + gpmc,access-ns = <36>; + gpmc,page-burst-access-ns = <0>; + gpmc,bus-turnaround-ns = <0>; + gpmc,cycle2cycle-delay-ns = <0>; + gpmc,wr-data-mux-bus-ns = <18>; + gpmc,wr-access-ns = <42>; + gpmc,cycle2cycle-samecsen; + gpmc,cycle2cycle-diffcsen; + + interrupt-parent = <&gpio6>; + interrupts = <16 IRQ_TYPE_LEVEL_LOW>; /* GPIO 176 */ + reg-io-width = <4>; + }; +}; + +&i2c3 { + clock-frequency = <100000>; +}; + +&mmc3 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/omap3-overo-tobi.dts b/arch/arm/boot/dts/omap3-overo-tobi.dts new file mode 100644 index 000000000000..de5653e1b5ca --- /dev/null +++ b/arch/arm/boot/dts/omap3-overo-tobi.dts @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group + * + * 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. + */ + +/* + * Tobi expansion board is manufactured by Gumstix Inc. + */ + +/dts-v1/; + +#include "omap34xx.dtsi" +#include "omap3-overo-tobi-common.dtsi" + +/ { + model = "OMAP35xx Gumstix Overo on Tobi"; + compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3"; +}; + diff --git a/arch/arm/boot/dts/omap3-tobi.dts b/arch/arm/boot/dts/omap3-tobi.dts deleted file mode 100644 index c742afaa2c26..000000000000 --- a/arch/arm/boot/dts/omap3-tobi.dts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group - * - * 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. - */ - -/* - * Tobi expansion board is manufactured by Gumstix Inc. - */ - -/dts-v1/; - -#include "omap36xx.dtsi" -#include "omap3-overo.dtsi" - -/ { - model = "TI OMAP3 Gumstix Overo on Tobi"; - compatible = "gumstix,omap3-tobi", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3"; - - leds { - compatible = "gpio-leds"; - heartbeat { - label = "overo:red:gpio21"; - gpios = <&gpio1 21 GPIO_ACTIVE_LOW>; - linux,default-trigger = "heartbeat"; - }; - }; - - vddvario: regulator-vddvario { - compatible = "regulator-fixed"; - regulator-name = "vddvario"; - regulator-always-on; - }; - - vdd33a: regulator-vdd33a { - compatible = "regulator-fixed"; - regulator-name = "vdd33a"; - regulator-always-on; - }; -}; - -&gpmc { - ranges = <5 0 0x2c000000 0x1000000>; /* CS5 */ - - ethernet@5,0 { - compatible = "smsc,lan9221", "smsc,lan9115"; - reg = <5 0 0xff>; - bank-width = <2>; - - gpmc,mux-add-data; - gpmc,cs-on-ns = <0>; - gpmc,cs-rd-off-ns = <42>; - gpmc,cs-wr-off-ns = <36>; - gpmc,adv-on-ns = <6>; - gpmc,adv-rd-off-ns = <12>; - gpmc,adv-wr-off-ns = <12>; - gpmc,oe-on-ns = <0>; - gpmc,oe-off-ns = <42>; - gpmc,we-on-ns = <0>; - gpmc,we-off-ns = <36>; - gpmc,rd-cycle-ns = <60>; - gpmc,wr-cycle-ns = <54>; - gpmc,access-ns = <36>; - gpmc,page-burst-access-ns = <0>; - gpmc,bus-turnaround-ns = <0>; - gpmc,cycle2cycle-delay-ns = <0>; - gpmc,wr-data-mux-bus-ns = <18>; - gpmc,wr-access-ns = <42>; - gpmc,cycle2cycle-samecsen; - gpmc,cycle2cycle-diffcsen; - - interrupt-parent = <&gpio6>; - interrupts = <16 IRQ_TYPE_LEVEL_LOW>; /* GPIO 176 */ - reg-io-width = <4>; - }; -}; - -&i2c3 { - clock-frequency = <100000>; -}; - -&mmc3 { - status = "disabled"; -}; -- cgit v1.2.3 From ae10f8329f9b22d650aa12307b260eba2bc0c571 Mon Sep 17 00:00:00 2001 From: Jason Cooper Date: Mon, 17 Feb 2014 19:09:58 +0000 Subject: ARM: dove: dt: revert PMU interrupt controller node The corresponding driver didn't make it into v3.14, so we need to remove the node. Dove systems fail to boot with the node present and no driver. This node will be re-added when the driver makes it to mainline. Reported-by: Jean-Francois Moine Tested-by: Jean-Francois Moine Signed-off-by: Jason Cooper --- arch/arm/boot/dts/dove.dtsi | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi index 2b76524f4aa7..187fd46b7b5e 100644 --- a/arch/arm/boot/dts/dove.dtsi +++ b/arch/arm/boot/dts/dove.dtsi @@ -379,15 +379,6 @@ #clock-cells = <1>; }; - pmu_intc: pmu-interrupt-ctrl@d0050 { - compatible = "marvell,dove-pmu-intc"; - interrupt-controller; - #interrupt-cells = <1>; - reg = <0xd0050 0x8>; - interrupts = <33>; - marvell,#interrupts = <7>; - }; - pinctrl: pin-ctrl@d0200 { compatible = "marvell,dove-pinctrl"; reg = <0xd0200 0x10>; @@ -610,8 +601,6 @@ rtc: real-time-clock@d8500 { compatible = "marvell,orion-rtc"; reg = <0xd8500 0x20>; - interrupt-parent = <&pmu_intc>; - interrupts = <5>; }; gpio2: gpio-ctrl@e8400 { -- cgit v1.2.3 From 763fbff2bef5d5db5a993b54c29c841432e056ec Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 13 Feb 2014 17:18:26 -0700 Subject: ARM: tegra: fix RTC0 alias for Cardhu This alias entry was evidently cut/paste from a different board, and not correctly updated to match Cardhu. Fix this. Fixes: 553c0a200e20 ("ARM: tegra: set up /aliases entries for RTCs") Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson --- arch/arm/boot/dts/tegra30-cardhu.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index 9104224124ee..1e156d9d0506 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -28,7 +28,7 @@ compatible = "nvidia,cardhu", "nvidia,tegra30"; aliases { - rtc0 = "/i2c@7000d000/tps6586x@34"; + rtc0 = "/i2c@7000d000/tps65911@2d"; rtc1 = "/rtc@7000e000"; }; -- cgit v1.2.3 From 28a9f3b078c545064dcf4b46d2c6917554d1642e Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 18 Feb 2014 10:35:05 +0800 Subject: ARM: imx6: build pm-imx6q.c independently of CONFIG_PM When building a kernel image with only CONFIG_CPU_IDLE but no CONFIG_PM, we will get the following link error. LD init/built-in.o arch/arm/mach-imx/built-in.o: In function `imx6q_enter_wait': platform-spi_imx.c:(.text+0x25c0): undefined reference to `imx6q_set_lpm' platform-spi_imx.c:(.text+0x25d4): undefined reference to `imx6q_set_lpm' arch/arm/mach-imx/built-in.o: In function `imx6q_cpuidle_init': platform-spi_imx.c:(.init.text+0x75d4): undefined reference to `imx6q_set_chicken_bit' make[1]: *** [vmlinux] Error 1 Since pm-imx6q.c has been a collection of library functions that access CCM low-power registers used by not only suspend but also cpuidle and other drivers, let's build pm-imx6q.c independently of CONFIG_PM to fix above error. Reported-by: Lucas Stach Signed-off-by: Shawn Guo Cc: stable@vger.kernel.org Acked-by: Christian Gmeiner Signed-off-by: Olof Johansson --- arch/arm/mach-imx/Makefile | 2 -- arch/arm/mach-imx/common.h | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index befcaf5d0574..ec419649320f 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -101,11 +101,9 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o -ifeq ($(CONFIG_PM),y) obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o # i.MX6SL reuses i.MX6Q code obj-$(CONFIG_SOC_IMX6SL) += pm-imx6q.o headsmp.o -endif # i.MX5 based machines obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index 59c3b9b26bb4..baf439dc22d8 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -144,13 +144,11 @@ void imx6q_set_chicken_bit(void); void imx_cpu_die(unsigned int cpu); int imx_cpu_kill(unsigned int cpu); -#ifdef CONFIG_PM void imx6q_pm_init(void); void imx6q_pm_set_ccm_base(void __iomem *base); +#ifdef CONFIG_PM void imx5_pm_init(void); #else -static inline void imx6q_pm_init(void) {} -static inline void imx6q_pm_set_ccm_base(void __iomem *base) {} static inline void imx5_pm_init(void) {} #endif -- cgit v1.2.3 From 688b56b485578465f6619b9529d08c2b95641915 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 18 Feb 2014 23:03:31 +0100 Subject: ARM: tegra: Add head numbers to display controllers The number of the head specifies the index of the display controller unit and is required to properly configure outputs so that they receive video data from the correct source. Signed-off-by: Thierry Reding Acked-by: Stephen Warren Signed-off-by: Olof Johansson --- arch/arm/boot/dts/tegra114.dtsi | 4 ++++ arch/arm/boot/dts/tegra20.dtsi | 4 ++++ arch/arm/boot/dts/tegra30.dtsi | 4 ++++ 3 files changed, 12 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 389e987ec281..44ec401ec366 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -57,6 +57,8 @@ resets = <&tegra_car 27>; reset-names = "dc"; + nvidia,head = <0>; + rgb { status = "disabled"; }; @@ -72,6 +74,8 @@ resets = <&tegra_car 26>; reset-names = "dc"; + nvidia,head = <1>; + rgb { status = "disabled"; }; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 480ecda3416b..48d2a7f4d0c0 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -94,6 +94,8 @@ resets = <&tegra_car 27>; reset-names = "dc"; + nvidia,head = <0>; + rgb { status = "disabled"; }; @@ -109,6 +111,8 @@ resets = <&tegra_car 26>; reset-names = "dc"; + nvidia,head = <1>; + rgb { status = "disabled"; }; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index ed8e7700b46d..19a84e933f4e 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -170,6 +170,8 @@ resets = <&tegra_car 27>; reset-names = "dc"; + nvidia,head = <0>; + rgb { status = "disabled"; }; @@ -185,6 +187,8 @@ resets = <&tegra_car 26>; reset-names = "dc"; + nvidia,head = <1>; + rgb { status = "disabled"; }; -- cgit v1.2.3 From 8859685785bfafadf9bc922dd3a2278e59886947 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 18 Feb 2014 16:51:58 -0700 Subject: ARM: tegra: only run PL310 init on systems with one Fix tegra_init_cache() to check whether the system has a PL310 cache before touching the PL310 registers. This prevents access to non-existent registers on Tegra114 and later. Note for stable kernels: In <= v3.12, the file to patch is arch/arm/mach-tegra/common.c. Cc: # v3.9+ Signed-off-by: Stephen Warren Signed-off-by: Olof Johansson --- arch/arm/mach-tegra/tegra.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 303a285d80fd..6191603379e1 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -73,10 +73,20 @@ u32 tegra_uart_config[3] = { static void __init tegra_init_cache(void) { #ifdef CONFIG_CACHE_L2X0 + static const struct of_device_id pl310_ids[] __initconst = { + { .compatible = "arm,pl310-cache", }, + {} + }; + + struct device_node *np; int ret; void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000; u32 aux_ctrl, cache_type; + np = of_find_matching_node(NULL, pl310_ids); + if (!np) + return; + cache_type = readl(p + L2X0_CACHE_TYPE); aux_ctrl = (cache_type & 0x700) << (17-8); aux_ctrl |= 0x7C400001; -- cgit v1.2.3 From b5190516b282bee6f10569c3387d16f83447d280 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 18 Feb 2014 21:46:16 +0000 Subject: of: Move testcase FDT data into drivers/of The testcase data is usable by any platform. This patch moves it into the drivers/of directory so it can be included by any architecture. Using the test cases requires manually adding #include to the end of the boards .dtsi file and enabling CONFIG_OF_SELFTEST. Not pretty though. A useful project would be to make the testcase code easier to execute. Signed-off-by: Grant Likely --- arch/arm/boot/dts/testcases/tests-interrupts.dtsi | 58 ----------------------- arch/arm/boot/dts/testcases/tests-phandle.dtsi | 39 --------------- arch/arm/boot/dts/testcases/tests.dtsi | 2 - arch/arm/boot/dts/versatile-pb.dts | 4 +- 4 files changed, 2 insertions(+), 101 deletions(-) delete mode 100644 arch/arm/boot/dts/testcases/tests-interrupts.dtsi delete mode 100644 arch/arm/boot/dts/testcases/tests-phandle.dtsi delete mode 100644 arch/arm/boot/dts/testcases/tests.dtsi (limited to 'arch/arm') diff --git a/arch/arm/boot/dts/testcases/tests-interrupts.dtsi b/arch/arm/boot/dts/testcases/tests-interrupts.dtsi deleted file mode 100644 index c843720bd3e5..000000000000 --- a/arch/arm/boot/dts/testcases/tests-interrupts.dtsi +++ /dev/null @@ -1,58 +0,0 @@ - -/ { - testcase-data { - interrupts { - #address-cells = <1>; - #size-cells = <1>; - test_intc0: intc0 { - interrupt-controller; - #interrupt-cells = <1>; - }; - - test_intc1: intc1 { - interrupt-controller; - #interrupt-cells = <3>; - }; - - test_intc2: intc2 { - interrupt-controller; - #interrupt-cells = <2>; - }; - - test_intmap0: intmap0 { - #interrupt-cells = <1>; - #address-cells = <0>; - interrupt-map = <1 &test_intc0 9>, - <2 &test_intc1 10 11 12>, - <3 &test_intc2 13 14>, - <4 &test_intc2 15 16>; - }; - - test_intmap1: intmap1 { - #interrupt-cells = <2>; - interrupt-map = <0x5000 1 2 &test_intc0 15>; - }; - - interrupts0 { - interrupt-parent = <&test_intc0>; - interrupts = <1>, <2>, <3>, <4>; - }; - - interrupts1 { - interrupt-parent = <&test_intmap0>; - interrupts = <1>, <2>, <3>, <4>; - }; - - interrupts-extended0 { - reg = <0x5000 0x100>; - interrupts-extended = <&test_intc0 1>, - <&test_intc1 2 3 4>, - <&test_intc2 5 6>, - <&test_intmap0 1>, - <&test_intmap0 2>, - <&test_intmap0 3>, - <&test_intmap1 1 2>; - }; - }; - }; -}; diff --git a/arch/arm/boot/dts/testcases/tests-phandle.dtsi b/arch/arm/boot/dts/testcases/tests-phandle.dtsi deleted file mode 100644 index 0007d3cd7dc2..000000000000 --- a/arch/arm/boot/dts/testcases/tests-phandle.dtsi +++ /dev/null @@ -1,39 +0,0 @@ - -/ { - testcase-data { - phandle-tests { - provider0: provider0 { - #phandle-cells = <0>; - }; - - provider1: provider1 { - #phandle-cells = <1>; - }; - - provider2: provider2 { - #phandle-cells = <2>; - }; - - provider3: provider3 { - #phandle-cells = <3>; - }; - - consumer-a { - phandle-list = <&provider1 1>, - <&provider2 2 0>, - <0>, - <&provider3 4 4 3>, - <&provider2 5 100>, - <&provider0>, - <&provider1 7>; - phandle-list-names = "first", "second", "third"; - - phandle-list-bad-phandle = <12345678 0 0>; - phandle-list-bad-args = <&provider2 1 0>, - <&provider3 0>; - empty-property; - unterminated-string = [40 41 42 43]; - }; - }; - }; -}; diff --git a/arch/arm/boot/dts/testcases/tests.dtsi b/arch/arm/boot/dts/testcases/tests.dtsi deleted file mode 100644 index 3f123ecc9dd7..000000000000 --- a/arch/arm/boot/dts/testcases/tests.dtsi +++ /dev/null @@ -1,2 +0,0 @@ -/include/ "tests-phandle.dtsi" -/include/ "tests-interrupts.dtsi" diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts index f43907c40c93..65f657711323 100644 --- a/arch/arm/boot/dts/versatile-pb.dts +++ b/arch/arm/boot/dts/versatile-pb.dts @@ -1,4 +1,4 @@ -/include/ "versatile-ab.dts" +#include / { model = "ARM Versatile PB"; @@ -47,4 +47,4 @@ }; }; -/include/ "testcases/tests.dtsi" +#include -- cgit v1.2.3 From bbd64559376fa25732994c4181c8ec493fa57871 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 7 Feb 2014 21:01:19 +0000 Subject: ARM: perf: support percpu irqs for the CPU PMU Some CPU PMUs are wired up with one PPI for all the CPUs instead of with a different SPI for each CPU. Add support for these devices. Signed-off-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event.c | 14 ++++-- arch/arm/kernel/perf_event_cpu.c | 97 ++++++++++++++++++++++++++++------------ 2 files changed, 80 insertions(+), 31 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 789d846a9184..b0c8489018d3 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -295,9 +297,15 @@ validate_group(struct perf_event *event) static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) { - struct arm_pmu *armpmu = (struct arm_pmu *) dev; - struct platform_device *plat_device = armpmu->plat_device; - struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev); + struct arm_pmu *armpmu; + struct platform_device *plat_device; + struct arm_pmu_platdata *plat; + + if (irq_is_percpu(irq)) + dev = *(void **)dev; + armpmu = dev; + plat_device = armpmu->plat_device; + plat = dev_get_platdata(&plat_device->dev); if (plat && plat->handle_irq) return plat->handle_irq(irq, dev, armpmu->handle_irq); diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 20d553c9f5e2..6efd8aab15df 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include @@ -33,6 +35,7 @@ /* Set at runtime when we know what CPU type we are. */ static struct arm_pmu *cpu_pmu; +static DEFINE_PER_CPU(struct arm_pmu *, percpu_pmu); static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events); static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask); static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); @@ -71,6 +74,26 @@ static struct pmu_hw_events *cpu_pmu_get_cpu_events(void) return this_cpu_ptr(&cpu_hw_events); } +static void cpu_pmu_enable_percpu_irq(void *data) +{ + struct arm_pmu *cpu_pmu = data; + struct platform_device *pmu_device = cpu_pmu->plat_device; + int irq = platform_get_irq(pmu_device, 0); + + enable_percpu_irq(irq, IRQ_TYPE_NONE); + cpumask_set_cpu(smp_processor_id(), &cpu_pmu->active_irqs); +} + +static void cpu_pmu_disable_percpu_irq(void *data) +{ + struct arm_pmu *cpu_pmu = data; + struct platform_device *pmu_device = cpu_pmu->plat_device; + int irq = platform_get_irq(pmu_device, 0); + + cpumask_clear_cpu(smp_processor_id(), &cpu_pmu->active_irqs); + disable_percpu_irq(irq); +} + static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu) { int i, irq, irqs; @@ -78,12 +101,18 @@ static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu) irqs = min(pmu_device->num_resources, num_possible_cpus()); - for (i = 0; i < irqs; ++i) { - if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs)) - continue; - irq = platform_get_irq(pmu_device, i); - if (irq >= 0) - free_irq(irq, cpu_pmu); + irq = platform_get_irq(pmu_device, 0); + if (irq >= 0 && irq_is_percpu(irq)) { + on_each_cpu(cpu_pmu_disable_percpu_irq, cpu_pmu, 1); + free_percpu_irq(irq, &percpu_pmu); + } else { + for (i = 0; i < irqs; ++i) { + if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs)) + continue; + irq = platform_get_irq(pmu_device, i); + if (irq >= 0) + free_irq(irq, cpu_pmu); + } } } @@ -101,33 +130,44 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) return -ENODEV; } - for (i = 0; i < irqs; ++i) { - err = 0; - irq = platform_get_irq(pmu_device, i); - if (irq < 0) - continue; - - /* - * If we have a single PMU interrupt that we can't shift, - * assume that we're running on a uniprocessor machine and - * continue. Otherwise, continue without this interrupt. - */ - if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { - pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", - irq, i); - continue; - } - - err = request_irq(irq, handler, - IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu", - cpu_pmu); + irq = platform_get_irq(pmu_device, 0); + if (irq >= 0 && irq_is_percpu(irq)) { + err = request_percpu_irq(irq, handler, "arm-pmu", &percpu_pmu); if (err) { pr_err("unable to request IRQ%d for ARM PMU counters\n", irq); return err; } - - cpumask_set_cpu(i, &cpu_pmu->active_irqs); + on_each_cpu(cpu_pmu_enable_percpu_irq, cpu_pmu, 1); + } else { + for (i = 0; i < irqs; ++i) { + err = 0; + irq = platform_get_irq(pmu_device, i); + if (irq < 0) + continue; + + /* + * If we have a single PMU interrupt that we can't shift, + * assume that we're running on a uniprocessor machine and + * continue. Otherwise, continue without this interrupt. + */ + if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { + pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", + irq, i); + continue; + } + + err = request_irq(irq, handler, + IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu", + cpu_pmu); + if (err) { + pr_err("unable to request IRQ%d for ARM PMU counters\n", + irq); + return err; + } + + cpumask_set_cpu(i, &cpu_pmu->active_irqs); + } } return 0; @@ -141,6 +181,7 @@ static void cpu_pmu_init(struct arm_pmu *cpu_pmu) events->events = per_cpu(hw_events, cpu); events->used_mask = per_cpu(used_mask, cpu); raw_spin_lock_init(&events->pmu_lock); + per_cpu(percpu_pmu, cpu) = cpu_pmu; } cpu_pmu->get_hw_events = cpu_pmu_get_cpu_events; -- cgit v1.2.3 From 3a3967ed9135f931f3848b0c946dcf3c10ca9f9a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 7 Feb 2014 21:01:20 +0000 Subject: ARM: perf: assign pdev pointer earlier for CPU PMUs We want to inspect the of_node that the pdev is pointing to in the Krait CPU specific PMU initialization function. Assign it earlier so that we don't crash with a NULL pointer dereference. Signed-off-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event_cpu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 6efd8aab15df..68d02ca0ca1b 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -311,6 +311,9 @@ static int cpu_pmu_device_probe(struct platform_device *pdev) return -ENOMEM; } + cpu_pmu = pmu; + cpu_pmu->plat_device = pdev; + if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) { init_fn = of_id->data; ret = init_fn(pmu); @@ -323,8 +326,6 @@ static int cpu_pmu_device_probe(struct platform_device *pdev) goto out_free; } - cpu_pmu = pmu; - cpu_pmu->plat_device = pdev; cpu_pmu_init(cpu_pmu); ret = armpmu_register(cpu_pmu, PERF_TYPE_RAW); -- cgit v1.2.3 From 2a3391cdb3c7bbea3be5cb39279764843a15ef25 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 7 Feb 2014 21:01:21 +0000 Subject: ARM: perf: add basic support for Krait CPU PMUs Add basic support for the Krait CPU PMU. This allows us to use the architected functionality of the PMU. This is based on code originally written by Ashwin Chaugule and Neil Leeder [1]. [1] https://www.codeaurora.org/cgit/quic/la/kernel/msm/tree/arch/arm/kernel/perf_event_msm_krait.c?h=msm-3.4 Cc: Neil Leeder Cc: Ashwin Chaugule Signed-off-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event_cpu.c | 1 + arch/arm/kernel/perf_event_v7.c | 164 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 68d02ca0ca1b..ed571d386c0b 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -229,6 +229,7 @@ static struct of_device_id cpu_pmu_of_device_ids[] = { {.compatible = "arm,arm11mpcore-pmu", .data = armv6mpcore_pmu_init}, {.compatible = "arm,arm1176-pmu", .data = armv6pmu_init}, {.compatible = "arm,arm1136-pmu", .data = armv6pmu_init}, + {.compatible = "qcom,krait-pmu", .data = krait_pmu_init}, {}, }; diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 039cffb053a7..16386b1d27a8 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -731,6 +731,138 @@ static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, }; +/* + * Krait HW events mapping + */ +static const unsigned krait_perf_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, + [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES, +}; + +static const unsigned krait_perf_map_no_branch[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, + [PERF_COUNT_HW_CACHE_REFERENCES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_CACHE_MISSES] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES, +}; + +static const unsigned krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + [C(L1D)] = { + /* + * The performance counters don't differentiate between read + * and write accesses/misses so this isn't strictly correct, + * but it's the best we can do. Writes and reads get + * combined. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(L1I)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(DTLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, +}; + /* * Perf Events' indices */ @@ -1212,6 +1344,18 @@ static int armv7_a7_map_event(struct perf_event *event) &armv7_a7_perf_cache_map, 0xFF); } +static int krait_map_event(struct perf_event *event) +{ + return armpmu_map_event(event, &krait_perf_map, + &krait_perf_cache_map, 0xFFFFF); +} + +static int krait_map_event_no_branch(struct perf_event *event) +{ + return armpmu_map_event(event, &krait_perf_map_no_branch, + &krait_perf_cache_map, 0xFFFFF); +} + static void armv7pmu_init(struct arm_pmu *cpu_pmu) { cpu_pmu->handle_irq = armv7pmu_handle_irq; @@ -1283,6 +1427,21 @@ static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) cpu_pmu->set_event_filter = armv7pmu_set_event_filter; return 0; } + +static int krait_pmu_init(struct arm_pmu *cpu_pmu) +{ + armv7pmu_init(cpu_pmu); + cpu_pmu->name = "ARMv7 Krait"; + /* Some early versions of Krait don't support PC write events */ + if (of_property_read_bool(cpu_pmu->plat_device->dev.of_node, + "qcom,no-pc-write")) + cpu_pmu->map_event = krait_map_event_no_branch; + else + cpu_pmu->map_event = krait_map_event; + cpu_pmu->num_events = armv7_read_num_pmnc_events(); + cpu_pmu->set_event_filter = armv7pmu_set_event_filter; + return 0; +} #else static inline int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu) { @@ -1308,4 +1467,9 @@ static inline int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) { return -ENODEV; } + +static inline int krait_pmu_init(struct arm_pmu *cpu_pmu) +{ + return -ENODEV; +} #endif /* CONFIG_CPU_V7 */ -- cgit v1.2.3 From eab443ef391d18772710dc2c156f7ee05e51f754 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 7 Feb 2014 21:01:22 +0000 Subject: ARM: perf: add hook for event index clearing On Krait processors we have a many-to-one relationship between raw CPU events and the event programmed into the PMNx counter. Two raw CPU events could map to the same value programmed in the PMNx counter. To avoid this problem, we check for collisions during the get_event_idx() callback by setting a bit in a bitmap whenever a certain event is used in a PMNx counter (see the next patch). Unfortunately, we don't have a hook to clear this bit in the bitmap when the event is deleted so let's add an optional clear_event_idx() callback for this purpose. Signed-off-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/include/asm/pmu.h | 2 ++ arch/arm/kernel/perf_event.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index f24edad26c70..ae1919be8f98 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -71,6 +71,8 @@ struct arm_pmu { void (*disable)(struct perf_event *event); int (*get_event_idx)(struct pmu_hw_events *hw_events, struct perf_event *event); + void (*clear_event_idx)(struct pmu_hw_events *hw_events, + struct perf_event *event); int (*set_event_filter)(struct hw_perf_event *evt, struct perf_event_attr *attr); u32 (*read_counter)(struct perf_event *event); diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index b0c8489018d3..361a1aaee7c8 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -207,6 +207,8 @@ armpmu_del(struct perf_event *event, int flags) armpmu_stop(event, PERF_EF_UPDATE); hw_events->events[idx] = NULL; clear_bit(idx, hw_events->used_mask); + if (armpmu->clear_event_idx) + armpmu->clear_event_idx(hw_events, event); perf_event_update_userpage(event); } -- cgit v1.2.3 From b7aafe9928beda2ed2c1a3035a1bed878f0cb2ab Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 7 Feb 2014 13:01:23 -0800 Subject: ARM: perf: fully support Krait CPU PMU events Krait supports a set of performance monitor region event selection registers (PMRESR) sitting behind a cp15 based interface that extend the architected PMU events to include Krait CPU and Venum VFP specific events. To use these events the user is expected to program the region register (PMRESRn) with the event code shifted into the group they care about and then point the PMNx event at that region+group combo by writing a PMRESRn_GROUPx event. Add support for this hardware. Note: the raw event number is a pure software construct that allows us to map the multi-dimensional number space of regions, groups, and event codes into a flat event number space suitable for use by the perf framework. This is based on code originally written by Ashwin Chaugule and Neil Leeder [1]. [1] https://www.codeaurora.org/cgit/quic/la/kernel/msm/tree/arch/arm/kernel/perf_event_msm_krait.c?h=msm-3.4 Cc: Neil Leeder Cc: Ashwin Chaugule Signed-off-by: Stephen Boyd Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event_v7.c | 407 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 401 insertions(+), 6 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 16386b1d27a8..2fce4751f4c0 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -18,6 +18,10 @@ #ifdef CONFIG_CPU_V7 +#include +#include +#include "../vfp/vfpinstr.h" + /* * Common ARMv7 event types * @@ -109,6 +113,20 @@ enum armv7_a15_perf_types { ARMV7_A15_PERFCTR_PC_WRITE_SPEC = 0x76, }; +/* ARMv7 Krait specific event types */ +enum krait_perf_types { + KRAIT_PMRESR0_GROUP0 = 0xcc, + KRAIT_PMRESR1_GROUP0 = 0xd0, + KRAIT_PMRESR2_GROUP0 = 0xd4, + KRAIT_VPMRESR0_GROUP0 = 0xd8, + + KRAIT_PERFCTR_L1_ICACHE_ACCESS = 0x10011, + KRAIT_PERFCTR_L1_ICACHE_MISS = 0x10010, + + KRAIT_PERFCTR_L1_ITLB_ACCESS = 0x12222, + KRAIT_PERFCTR_L1_DTLB_ACCESS = 0x12210, +}; + /* * Cortex-A8 HW events mapping * @@ -779,8 +797,8 @@ static const unsigned krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, [C(L1I)] = { [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_ICACHE_ACCESS, + [C(RESULT_MISS)] = KRAIT_PERFCTR_L1_ICACHE_MISS, }, [C(OP_WRITE)] = { [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, @@ -807,11 +825,11 @@ static const unsigned krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, [C(DTLB)] = { [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_DTLB_ACCESS, [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_DTLB_ACCESS, [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, [C(OP_PREFETCH)] = { @@ -821,11 +839,11 @@ static const unsigned krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, [C(ITLB)] = { [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_ITLB_ACCESS, [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_ITLB_ACCESS, [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, }, [C(OP_PREFETCH)] = { @@ -1428,6 +1446,378 @@ static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) return 0; } +/* + * Krait Performance Monitor Region Event Selection Register (PMRESRn) + * + * 31 30 24 16 8 0 + * +--------------------------------+ + * PMRESR0 | EN | CC | CC | CC | CC | N = 1, R = 0 + * +--------------------------------+ + * PMRESR1 | EN | CC | CC | CC | CC | N = 1, R = 1 + * +--------------------------------+ + * PMRESR2 | EN | CC | CC | CC | CC | N = 1, R = 2 + * +--------------------------------+ + * VPMRESR0 | EN | CC | CC | CC | CC | N = 2, R = ? + * +--------------------------------+ + * EN | G=3 | G=2 | G=1 | G=0 + * + * Event Encoding: + * + * hwc->config_base = 0xNRCCG + * + * N = prefix, 1 for Krait CPU (PMRESRn), 2 for Venum VFP (VPMRESR) + * R = region register + * CC = class of events the group G is choosing from + * G = group or particular event + * + * Example: 0x12021 is a Krait CPU event in PMRESR2's group 1 with code 2 + * + * A region (R) corresponds to a piece of the CPU (execution unit, instruction + * unit, etc.) while the event code (CC) corresponds to a particular class of + * events (interrupts for example). An event code is broken down into + * groups (G) that can be mapped into the PMU (irq, fiqs, and irq+fiqs for + * example). + */ + +#define KRAIT_EVENT (1 << 16) +#define VENUM_EVENT (2 << 16) +#define KRAIT_EVENT_MASK (KRAIT_EVENT | VENUM_EVENT) +#define PMRESRn_EN BIT(31) + +static u32 krait_read_pmresrn(int n) +{ + u32 val; + + switch (n) { + case 0: + asm volatile("mrc p15, 1, %0, c9, c15, 0" : "=r" (val)); + break; + case 1: + asm volatile("mrc p15, 1, %0, c9, c15, 1" : "=r" (val)); + break; + case 2: + asm volatile("mrc p15, 1, %0, c9, c15, 2" : "=r" (val)); + break; + default: + BUG(); /* Should be validated in krait_pmu_get_event_idx() */ + } + + return val; +} + +static void krait_write_pmresrn(int n, u32 val) +{ + switch (n) { + case 0: + asm volatile("mcr p15, 1, %0, c9, c15, 0" : : "r" (val)); + break; + case 1: + asm volatile("mcr p15, 1, %0, c9, c15, 1" : : "r" (val)); + break; + case 2: + asm volatile("mcr p15, 1, %0, c9, c15, 2" : : "r" (val)); + break; + default: + BUG(); /* Should be validated in krait_pmu_get_event_idx() */ + } +} + +static u32 krait_read_vpmresr0(void) +{ + u32 val; + asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val)); + return val; +} + +static void krait_write_vpmresr0(u32 val) +{ + asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val)); +} + +static void krait_pre_vpmresr0(u32 *venum_orig_val, u32 *fp_orig_val) +{ + u32 venum_new_val; + u32 fp_new_val; + + BUG_ON(preemptible()); + /* CPACR Enable CP10 and CP11 access */ + *venum_orig_val = get_copro_access(); + venum_new_val = *venum_orig_val | CPACC_SVC(10) | CPACC_SVC(11); + set_copro_access(venum_new_val); + + /* Enable FPEXC */ + *fp_orig_val = fmrx(FPEXC); + fp_new_val = *fp_orig_val | FPEXC_EN; + fmxr(FPEXC, fp_new_val); +} + +static void krait_post_vpmresr0(u32 venum_orig_val, u32 fp_orig_val) +{ + BUG_ON(preemptible()); + /* Restore FPEXC */ + fmxr(FPEXC, fp_orig_val); + isb(); + /* Restore CPACR */ + set_copro_access(venum_orig_val); +} + +static u32 krait_get_pmresrn_event(unsigned int region) +{ + static const u32 pmresrn_table[] = { KRAIT_PMRESR0_GROUP0, + KRAIT_PMRESR1_GROUP0, + KRAIT_PMRESR2_GROUP0 }; + return pmresrn_table[region]; +} + +static void krait_evt_setup(int idx, u32 config_base) +{ + u32 val; + u32 mask; + u32 vval, fval; + unsigned int region; + unsigned int group; + unsigned int code; + unsigned int group_shift; + bool venum_event; + + venum_event = !!(config_base & VENUM_EVENT); + region = (config_base >> 12) & 0xf; + code = (config_base >> 4) & 0xff; + group = (config_base >> 0) & 0xf; + + group_shift = group * 8; + mask = 0xff << group_shift; + + /* Configure evtsel for the region and group */ + if (venum_event) + val = KRAIT_VPMRESR0_GROUP0; + else + val = krait_get_pmresrn_event(region); + val += group; + /* Mix in mode-exclusion bits */ + val |= config_base & (ARMV7_EXCLUDE_USER | ARMV7_EXCLUDE_PL1); + armv7_pmnc_write_evtsel(idx, val); + + asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (0)); + + if (venum_event) { + krait_pre_vpmresr0(&vval, &fval); + val = krait_read_vpmresr0(); + val &= ~mask; + val |= code << group_shift; + val |= PMRESRn_EN; + krait_write_vpmresr0(val); + krait_post_vpmresr0(vval, fval); + } else { + val = krait_read_pmresrn(region); + val &= ~mask; + val |= code << group_shift; + val |= PMRESRn_EN; + krait_write_pmresrn(region, val); + } +} + +static u32 krait_clear_pmresrn_group(u32 val, int group) +{ + u32 mask; + int group_shift; + + group_shift = group * 8; + mask = 0xff << group_shift; + val &= ~mask; + + /* Don't clear enable bit if entire region isn't disabled */ + if (val & ~PMRESRn_EN) + return val |= PMRESRn_EN; + + return 0; +} + +static void krait_clearpmu(u32 config_base) +{ + u32 val; + u32 vval, fval; + unsigned int region; + unsigned int group; + bool venum_event; + + venum_event = !!(config_base & VENUM_EVENT); + region = (config_base >> 12) & 0xf; + group = (config_base >> 0) & 0xf; + + if (venum_event) { + krait_pre_vpmresr0(&vval, &fval); + val = krait_read_vpmresr0(); + val = krait_clear_pmresrn_group(val, group); + krait_write_vpmresr0(val); + krait_post_vpmresr0(vval, fval); + } else { + val = krait_read_pmresrn(region); + val = krait_clear_pmresrn_group(val, group); + krait_write_pmresrn(region, val); + } +} + +static void krait_pmu_disable_event(struct perf_event *event) +{ + unsigned long flags; + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + + /* Disable counter and interrupt */ + raw_spin_lock_irqsave(&events->pmu_lock, flags); + + /* Disable counter */ + armv7_pmnc_disable_counter(idx); + + /* + * Clear pmresr code (if destined for PMNx counters) + */ + if (hwc->config_base & KRAIT_EVENT_MASK) + krait_clearpmu(hwc->config_base); + + /* Disable interrupt for this counter */ + armv7_pmnc_disable_intens(idx); + + raw_spin_unlock_irqrestore(&events->pmu_lock, flags); +} + +static void krait_pmu_enable_event(struct perf_event *event) +{ + unsigned long flags; + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + struct pmu_hw_events *events = cpu_pmu->get_hw_events(); + + /* + * Enable counter and interrupt, and set the counter to count + * the event that we're interested in. + */ + raw_spin_lock_irqsave(&events->pmu_lock, flags); + + /* Disable counter */ + armv7_pmnc_disable_counter(idx); + + /* + * Set event (if destined for PMNx counters) + * We set the event for the cycle counter because we + * have the ability to perform event filtering. + */ + if (hwc->config_base & KRAIT_EVENT_MASK) + krait_evt_setup(idx, hwc->config_base); + else + armv7_pmnc_write_evtsel(idx, hwc->config_base); + + /* Enable interrupt for this counter */ + armv7_pmnc_enable_intens(idx); + + /* Enable counter */ + armv7_pmnc_enable_counter(idx); + + raw_spin_unlock_irqrestore(&events->pmu_lock, flags); +} + +static void krait_pmu_reset(void *info) +{ + u32 vval, fval; + + armv7pmu_reset(info); + + /* Clear all pmresrs */ + krait_write_pmresrn(0, 0); + krait_write_pmresrn(1, 0); + krait_write_pmresrn(2, 0); + + krait_pre_vpmresr0(&vval, &fval); + krait_write_vpmresr0(0); + krait_post_vpmresr0(vval, fval); +} + +static int krait_event_to_bit(struct perf_event *event, unsigned int region, + unsigned int group) +{ + int bit; + struct hw_perf_event *hwc = &event->hw; + struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + + if (hwc->config_base & VENUM_EVENT) + bit = KRAIT_VPMRESR0_GROUP0; + else + bit = krait_get_pmresrn_event(region); + bit -= krait_get_pmresrn_event(0); + bit += group; + /* + * Lower bits are reserved for use by the counters (see + * armv7pmu_get_event_idx() for more info) + */ + bit += ARMV7_IDX_COUNTER_LAST(cpu_pmu) + 1; + + return bit; +} + +/* + * We check for column exclusion constraints here. + * Two events cant use the same group within a pmresr register. + */ +static int krait_pmu_get_event_idx(struct pmu_hw_events *cpuc, + struct perf_event *event) +{ + int idx; + int bit; + unsigned int prefix; + unsigned int region; + unsigned int code; + unsigned int group; + bool krait_event; + struct hw_perf_event *hwc = &event->hw; + + region = (hwc->config_base >> 12) & 0xf; + code = (hwc->config_base >> 4) & 0xff; + group = (hwc->config_base >> 0) & 0xf; + krait_event = !!(hwc->config_base & KRAIT_EVENT_MASK); + + if (krait_event) { + /* Ignore invalid events */ + if (group > 3 || region > 2) + return -EINVAL; + prefix = hwc->config_base & KRAIT_EVENT_MASK; + if (prefix != KRAIT_EVENT && prefix != VENUM_EVENT) + return -EINVAL; + if (prefix == VENUM_EVENT && (code & 0xe0)) + return -EINVAL; + + bit = krait_event_to_bit(event, region, group); + if (test_and_set_bit(bit, cpuc->used_mask)) + return -EAGAIN; + } + + idx = armv7pmu_get_event_idx(cpuc, event); + if (idx < 0 && krait_event) + clear_bit(bit, cpuc->used_mask); + + return idx; +} + +static void krait_pmu_clear_event_idx(struct pmu_hw_events *cpuc, + struct perf_event *event) +{ + int bit; + struct hw_perf_event *hwc = &event->hw; + unsigned int region; + unsigned int group; + bool krait_event; + + region = (hwc->config_base >> 12) & 0xf; + group = (hwc->config_base >> 0) & 0xf; + krait_event = !!(hwc->config_base & KRAIT_EVENT_MASK); + + if (krait_event) { + bit = krait_event_to_bit(event, region, group); + clear_bit(bit, cpuc->used_mask); + } +} + static int krait_pmu_init(struct arm_pmu *cpu_pmu) { armv7pmu_init(cpu_pmu); @@ -1440,6 +1830,11 @@ static int krait_pmu_init(struct arm_pmu *cpu_pmu) cpu_pmu->map_event = krait_map_event; cpu_pmu->num_events = armv7_read_num_pmnc_events(); cpu_pmu->set_event_filter = armv7pmu_set_event_filter; + cpu_pmu->reset = krait_pmu_reset; + cpu_pmu->enable = krait_pmu_enable_event; + cpu_pmu->disable = krait_pmu_disable_event; + cpu_pmu->get_event_idx = krait_pmu_get_event_idx; + cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx; return 0; } #else -- cgit v1.2.3 From 5f5092e72cc25a6a5785308270e0085b2b2772cc Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 11 Feb 2014 18:08:41 +0000 Subject: ARM: perf: hook up perf_sample_event_took around pmu irq handling Since we indirect all of our PMU IRQ handling through a dispatcher, it's trivial to hook up perf_sample_event_took to prevent applications such as oprofile from generating interrupt storms due to an unrealisticly low sample period. Reported-by: Robert Richter Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 361a1aaee7c8..a6bc431cde70 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -302,6 +302,8 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) struct arm_pmu *armpmu; struct platform_device *plat_device; struct arm_pmu_platdata *plat; + int ret; + u64 start_clock, finish_clock; if (irq_is_percpu(irq)) dev = *(void **)dev; @@ -309,10 +311,15 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) plat_device = armpmu->plat_device; plat = dev_get_platdata(&plat_device->dev); + start_clock = sched_clock(); if (plat && plat->handle_irq) - return plat->handle_irq(irq, dev, armpmu->handle_irq); + ret = plat->handle_irq(irq, dev, armpmu->handle_irq); else - return armpmu->handle_irq(irq, dev); + ret = armpmu->handle_irq(irq, dev); + finish_clock = sched_clock(); + + perf_sample_event_took(finish_clock - start_clock); + return ret; } static void -- cgit v1.2.3 From 51e5fef62059e4074054ee731385e0dc7ca561ff Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 18 Feb 2014 10:31:10 +0000 Subject: ARM: perf: remove unused PMU probing code The ARM perf backend can discover the type of PMU it needs to drive either from DT or by probing a CPU it is running on. For Cortex-A{5,7,15} there are no platforms in mainline not using dt, and this probing won't work well for big.LITTLE systems with heterogeneous PMUs. This patch drops the probing for those CPUs, relying on information from dt instead. Future platforms should describe their PMU(s) with dt. Suggested-by: Will Deacon Signed-off-by: Mark Rutland Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event_cpu.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index ed571d386c0b..326cb58de2f8 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -267,15 +267,6 @@ static int probe_current_pmu(struct arm_pmu *pmu) case ARM_CPU_PART_CORTEX_A9: ret = armv7_a9_pmu_init(pmu); break; - case ARM_CPU_PART_CORTEX_A5: - ret = armv7_a5_pmu_init(pmu); - break; - case ARM_CPU_PART_CORTEX_A15: - ret = armv7_a15_pmu_init(pmu); - break; - case ARM_CPU_PART_CORTEX_A7: - ret = armv7_a7_pmu_init(pmu); - break; } /* Intel CPUs [xscale]. */ } else if (implementor == ARM_CPU_IMP_INTEL) { -- cgit v1.2.3 From 8e781f65423c2e8e65a56972ba996b6c01a5ef3e Mon Sep 17 00:00:00 2001 From: Albin Tonnerre Date: Wed, 29 Jan 2014 14:28:57 +0000 Subject: ARM: perf: add support for the Cortex-A12 PMU Cortex-A12 implements Performance Monitors compliant with the PMUv2 architecture. This patch adds support for the Cortex-A12 PMU to the ARM perf backend. Signed-off-by: Albin Tonnerre Signed-off-by: Will Deacon --- arch/arm/kernel/perf_event_cpu.c | 1 + arch/arm/kernel/perf_event_v7.c | 158 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) (limited to 'arch/arm') diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c index 326cb58de2f8..51798d7854ac 100644 --- a/arch/arm/kernel/perf_event_cpu.c +++ b/arch/arm/kernel/perf_event_cpu.c @@ -222,6 +222,7 @@ static struct notifier_block cpu_pmu_hotplug_notifier = { */ static struct of_device_id cpu_pmu_of_device_ids[] = { {.compatible = "arm,cortex-a15-pmu", .data = armv7_a15_pmu_init}, + {.compatible = "arm,cortex-a12-pmu", .data = armv7_a12_pmu_init}, {.compatible = "arm,cortex-a9-pmu", .data = armv7_a9_pmu_init}, {.compatible = "arm,cortex-a8-pmu", .data = armv7_a8_pmu_init}, {.compatible = "arm,cortex-a7-pmu", .data = armv7_a7_pmu_init}, diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 2fce4751f4c0..f4ef3981ed02 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -113,6 +113,19 @@ enum armv7_a15_perf_types { ARMV7_A15_PERFCTR_PC_WRITE_SPEC = 0x76, }; +/* ARMv7 Cortex-A12 specific event types */ +enum armv7_a12_perf_types { + ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_READ = 0x40, + ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_WRITE = 0x41, + + ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_READ = 0x50, + ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_WRITE = 0x51, + + ARMV7_A12_PERFCTR_PC_WRITE_SPEC = 0x76, + + ARMV7_A12_PERFCTR_PF_TLB_REFILL = 0xe7, +}; + /* ARMv7 Krait specific event types */ enum krait_perf_types { KRAIT_PMRESR0_GROUP0 = 0xcc, @@ -749,6 +762,130 @@ static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, }; +/* + * Cortex-A12 HW events mapping + */ +static const unsigned armv7_a12_perf_map[PERF_COUNT_HW_MAX] = { + [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, + [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, + [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, + [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_L1_DCACHE_REFILL, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_A12_PERFCTR_PC_WRITE_SPEC, + [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_BUS_CYCLES, + [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = HW_OP_UNSUPPORTED, + [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = HW_OP_UNSUPPORTED, +}; + +static const unsigned armv7_a12_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = { + [C(L1D)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_READ, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_WRITE, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(L1I)] = { + /* + * Not all performance counters differentiate between read + * and write accesses/misses so we're not always strictly + * correct, but it's the best we can do. Writes and reads get + * combined in these cases. + */ + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(LL)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_READ, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACHE_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_WRITE, + [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACHE_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(DTLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_A12_PERFCTR_PF_TLB_REFILL, + }, + }, + [C(ITLB)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_REFILL, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_REFILL, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(BPU)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, + [C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, + [C(NODE)] = { + [C(OP_READ)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_WRITE)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + [C(OP_PREFETCH)] = { + [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, + [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, + }, + }, +}; + /* * Krait HW events mapping */ @@ -1362,6 +1499,12 @@ static int armv7_a7_map_event(struct perf_event *event) &armv7_a7_perf_cache_map, 0xFF); } +static int armv7_a12_map_event(struct perf_event *event) +{ + return armpmu_map_event(event, &armv7_a12_perf_map, + &armv7_a12_perf_cache_map, 0xFF); +} + static int krait_map_event(struct perf_event *event) { return armpmu_map_event(event, &krait_perf_map, @@ -1446,6 +1589,16 @@ static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) return 0; } +static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu) +{ + armv7pmu_init(cpu_pmu); + cpu_pmu->name = "ARMv7 Cortex-A12"; + cpu_pmu->map_event = armv7_a12_map_event; + cpu_pmu->num_events = armv7_read_num_pmnc_events(); + cpu_pmu->set_event_filter = armv7pmu_set_event_filter; + return 0; +} + /* * Krait Performance Monitor Region Event Selection Register (PMRESRn) * @@ -1863,6 +2016,11 @@ static inline int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) return -ENODEV; } +static inline int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu) +{ + return -ENODEV; +} + static inline int krait_pmu_init(struct arm_pmu *cpu_pmu) { return -ENODEV; -- cgit v1.2.3 From b20c9f29c5c25921c6ad18b50d4b61e6d181c3cc Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 26 Feb 2014 18:47:36 +0000 Subject: arm/arm64: KVM: detect CPU reset on CPU_PM_EXIT Commit 1fcf7ce0c602 (arm: kvm: implement CPU PM notifier) added support for CPU power-management, using a cpu_notifier to re-init KVM on a CPU that entered CPU idle. The code assumed that a CPU entering idle would actually be powered off, loosing its state entierely, and would then need to be reinitialized. It turns out that this is not always the case, and some HW performs CPU PM without actually killing the core. In this case, we try to reinitialize KVM while it is still live. It ends up badly, as reported by Andre Przywara (using a Calxeda Midway): [ 3.663897] Kernel panic - not syncing: unexpected prefetch abort in Hyp mode at: 0x685760 [ 3.663897] unexpected data abort in Hyp mode at: 0xc067d150 [ 3.663897] unexpected HVC/SVC trap in Hyp mode at: 0xc0901dd0 The trick here is to detect if we've been through a full re-init or not by looking at HVBAR (VBAR_EL2 on arm64). This involves implementing the backend for __hyp_get_vectors in the main KVM HYP code (rather small), and checking the return value against the default one when the CPU notifier is called on CPU_PM_EXIT. Reported-by: Andre Przywara Tested-by: Andre Przywara Cc: Lorenzo Pieralisi Cc: Rob Herring Acked-by: Christoffer Dall Signed-off-by: Marc Zyngier Signed-off-by: Paolo Bonzini --- arch/arm/kvm/arm.c | 3 ++- arch/arm/kvm/interrupts.S | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 1d8248ea5669..bd18bb8b2770 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -878,7 +878,8 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd, void *v) { - if (cmd == CPU_PM_EXIT) { + if (cmd == CPU_PM_EXIT && + __hyp_get_vectors() == hyp_default_vectors) { cpu_init_hyp_mode(NULL); return NOTIFY_OK; } diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S index ddc15539bad2..0d68d4073068 100644 --- a/arch/arm/kvm/interrupts.S +++ b/arch/arm/kvm/interrupts.S @@ -220,6 +220,10 @@ after_vfp_restore: * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are * passed in r0 and r1. * + * A function pointer with a value of 0xffffffff has a special meaning, + * and is used to implement __hyp_get_vectors in the same way as in + * arch/arm/kernel/hyp_stub.S. + * * The calling convention follows the standard AAPCS: * r0 - r3: caller save * r12: caller save @@ -363,6 +367,11 @@ hyp_hvc: host_switch_to_hyp: pop {r0, r1, r2} + /* Check for __hyp_get_vectors */ + cmp r0, #-1 + mrceq p15, 4, r0, c12, c0, 0 @ get HVBAR + beq 1f + push {lr} mrs lr, SPSR push {lr} @@ -378,7 +387,7 @@ THUMB( orr lr, #1) pop {lr} msr SPSR_csxf, lr pop {lr} - eret +1: eret guest_trap: load_vcpu @ Load VCPU pointer to r0 -- cgit v1.2.3 From 21254ebc9e509967317ad8c6922797e21137ad53 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Thu, 6 Mar 2014 18:17:52 -0500 Subject: ARM: Fix missing includes in kprobes sources Make sure includes in ARM kprobes sources are done explicitly. Do not rely on includes from other includes. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/kprobes.h | 2 +- arch/arm/kernel/kprobes-common.c | 3 +++ arch/arm/kernel/kprobes-test-arm.c | 1 + arch/arm/kernel/kprobes-test.c | 4 +++- arch/arm/kernel/kprobes.c | 2 ++ 5 files changed, 10 insertions(+), 2 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index f82ec22eeb11..fd2e5caec6ed 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -18,7 +18,7 @@ #include #include -#include +#include #define __ARCH_WANT_KPROBES_INSN_SLOT #define MAX_INSN_SIZE 2 diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 18a76282970e..455c8003bffb 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include #include "kprobes.h" diff --git a/arch/arm/kernel/kprobes-test-arm.c b/arch/arm/kernel/kprobes-test-arm.c index 839312905067..87839de77e5f 100644 --- a/arch/arm/kernel/kprobes-test-arm.c +++ b/arch/arm/kernel/kprobes-test-arm.c @@ -10,6 +10,7 @@ #include #include +#include #include "kprobes-test.h" diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c index 0cd63d080c7b..4a774d40c946 100644 --- a/arch/arm/kernel/kprobes-test.c +++ b/arch/arm/kernel/kprobes-test.c @@ -201,7 +201,9 @@ #include #include #include - +#include +#include +#include #include #include "kprobes.h" diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index a7b621ece23d..54e7b46a3295 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "kprobes.h" #include "patch.h" -- cgit v1.2.3 From b2531dd5e5f19ea01d67aed82d81c5f778ec0fb7 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Thu, 6 Mar 2014 17:53:34 -0500 Subject: ARM: move shared uprobe/kprobe definitions into new include file Separate the kprobe-only definitions from the definitions needed by both kprobes and uprobes. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/kprobes.h | 15 +-------------- arch/arm/include/asm/probes.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 arch/arm/include/asm/probes.h (limited to 'arch/arm') diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index fd2e5caec6ed..6e1046661f07 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -28,21 +28,8 @@ #define kretprobe_blacklist_size 0 typedef u32 kprobe_opcode_t; - struct kprobe; -typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); -typedef unsigned long (kprobe_check_cc)(unsigned long); -typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); -typedef void (kprobe_insn_fn_t)(void); - -/* Architecture specific copy of original instruction. */ -struct arch_specific_insn { - kprobe_opcode_t *insn; - kprobe_insn_handler_t *insn_handler; - kprobe_check_cc *insn_check_cc; - kprobe_insn_singlestep_t *insn_singlestep; - kprobe_insn_fn_t *insn_fn; -}; +#include struct prev_kprobe { struct kprobe *kp; diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h new file mode 100644 index 000000000000..90c5f5485202 --- /dev/null +++ b/arch/arm/include/asm/probes.h @@ -0,0 +1,36 @@ +/* + * arch/arm/include/asm/probes.h + * + * Original contents copied from arch/arm/include/asm/kprobes.h + * which contains the following notice... + * + * Copyright (C) 2006, 2007 Motorola 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 _ASM_PROBES_H +#define _ASM_PROBES_H + +typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); +typedef unsigned long (kprobe_check_cc)(unsigned long); +typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); +typedef void (kprobe_insn_fn_t)(void); + +/* Architecture specific copy of original instruction. */ +struct arch_specific_insn { + kprobe_opcode_t *insn; + kprobe_insn_handler_t *insn_handler; + kprobe_check_cc *insn_check_cc; + kprobe_insn_singlestep_t *insn_singlestep; + kprobe_insn_fn_t *insn_fn; +}; + +#endif -- cgit v1.2.3 From c18377c303787ded44b7decd7dee694db0f205e9 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Fri, 7 Mar 2014 11:16:10 -0500 Subject: ARM: Move generic arm instruction parsing code to new files for sharing between features Move the arm version of the kprobes instruction parsing code into more generic files from where it can be used by uprobes and possibly other subsystems. The symbol names will be made more generic in a subsequent part of this patchset. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/probes.h | 2 + arch/arm/kernel/Makefile | 4 +- arch/arm/kernel/kprobes-arm.c | 724 +------------------------------------- arch/arm/kernel/kprobes-common.c | 425 ----------------------- arch/arm/kernel/kprobes.h | 373 +------------------- arch/arm/kernel/probes-arm.c | 731 +++++++++++++++++++++++++++++++++++++++ arch/arm/kernel/probes-arm.h | 38 ++ arch/arm/kernel/probes.c | 443 ++++++++++++++++++++++++ arch/arm/kernel/probes.h | 397 +++++++++++++++++++++ 9 files changed, 1624 insertions(+), 1513 deletions(-) create mode 100644 arch/arm/kernel/probes-arm.c create mode 100644 arch/arm/kernel/probes-arm.h create mode 100644 arch/arm/kernel/probes.c create mode 100644 arch/arm/kernel/probes.h (limited to 'arch/arm') diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index 90c5f5485202..737a9b310efc 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -19,6 +19,8 @@ #ifndef _ASM_PROBES_H #define _ASM_PROBES_H +struct kprobe; + typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); typedef unsigned long (kprobe_check_cc)(unsigned long); typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index a30fc9be9e9e..4c8b13e64280 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -50,11 +50,11 @@ 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_KPROBES) += kprobes.o kprobes-common.o patch.o +obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o ifdef CONFIG_THUMB2_KERNEL obj-$(CONFIG_KPROBES) += kprobes-thumb.o else -obj-$(CONFIG_KPROBES) += kprobes-arm.o +obj-$(CONFIG_KPROBES) += kprobes-arm.o probes-arm.o endif obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o test-kprobes-objs := kprobes-test.o diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index 8a30c89da70e..a1d0a8f00f9e 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -60,13 +60,10 @@ #include #include -#include +#include #include "kprobes.h" - -#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) - -#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) +#include "probes-arm.h" #if __LINUX_ARM_ARCH__ >= 6 #define BLX(reg) "blx "reg" \n\t" @@ -75,88 +72,8 @@ "mov pc, "reg" \n\t" #endif -/* - * To avoid the complications of mimicing single-stepping on a - * processor without a Next-PC or a single-step mode, and to - * avoid having to deal with the side-effects of boosting, we - * simulate or emulate (almost) all ARM instructions. - * - * "Simulation" is where the instruction's behavior is duplicated in - * C code. "Emulation" is where the original instruction is rewritten - * and executed, often by altering its registers. - * - * By having all behavior of the kprobe'd instruction completed before - * returning from the kprobe_handler(), all locks (scheduler and - * interrupt) can safely be released. There is no need for secondary - * breakpoints, no race with MP or preemptable kernels, nor having to - * clean up resources counts at a later time impacting overall system - * performance. By rewriting the instruction, only the minimum registers - * need to be loaded and saved back optimizing performance. - * - * Calling the insnslot_*_rwflags version of a function doesn't hurt - * anything even when the CPSR flags aren't updated by the - * instruction. It's just a little slower in return for saving - * a little space by not having a duplicate function that doesn't - * update the flags. (The same optimization can be said for - * instructions that do or don't perform register writeback) - * Also, instructions can either read the flags, only write the - * flags, or read and write the flags. To save combinations - * rather than for sheer performance, flag functions just assume - * read and write of flags. - */ - -static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; - int disp = branch_displacement(insn); - - if (insn & (1 << 24)) - regs->ARM_lr = iaddr + 4; - - regs->ARM_pc = iaddr + 8 + disp; -} - -static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; - int disp = branch_displacement(insn); - - regs->ARM_lr = iaddr + 4; - regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); - regs->ARM_cpsr |= PSR_T_BIT; -} -static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rm = insn & 0xf; - long rmv = regs->uregs[rm]; - - if (insn & (1 << 5)) - regs->ARM_lr = (long)p->addr + 4; - - regs->ARM_pc = rmv & ~0x1; - regs->ARM_cpsr &= ~PSR_T_BIT; - if (rmv & 0x1) - regs->ARM_cpsr |= PSR_T_BIT; -} - -static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) -{ - kprobe_opcode_t insn = p->opcode; - int rd = (insn >> 12) & 0xf; - unsigned long mask = 0xf8ff03df; /* Mask out execution state */ - regs->uregs[rd] = regs->ARM_cpsr & mask; -} - -static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) -{ - regs->uregs[12] = regs->uregs[13]; -} - -static void __kprobes +void __kprobes emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -185,7 +102,7 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -static void __kprobes +void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -215,7 +132,7 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -static void __kprobes +void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -242,7 +159,7 @@ emulate_str(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -static void __kprobes +void __kprobes emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -277,7 +194,7 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static void __kprobes +void __kprobes emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -304,7 +221,7 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static void __kprobes +void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -333,7 +250,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static void __kprobes +void __kprobes emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -353,7 +270,7 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -static void __kprobes +void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -382,624 +299,3 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->uregs[rdhi] = rdhiv; regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } - -/* - * For the instruction masking and comparisons in all the "space_*" - * functions below, Do _not_ rearrange the order of tests unless - * you're very, very sure of what you are doing. For the sake of - * efficiency, the masks for some tests sometimes assume other test - * have been done prior to them so the number of patterns to test - * for an instruction set can be as broad as possible to reduce the - * number of tests needed. - */ - -static const union decode_item arm_1111_table[] = { - /* Unconditional instructions */ - - /* memory hint 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */ - /* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */ - /* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */ - /* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop), - - /* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */ - /* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */ - /* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */ - /* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */ - DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop), - - /* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1), - - /* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ - /* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ - /* SRS 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ - /* RFE 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ - - /* Coprocessor instructions... */ - /* MCRR2 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */ - /* MRRC2 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */ - /* LDC2 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ - /* STC2 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - /* CDP2 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - /* MCR2 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ - /* MRC2 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = { - /* Miscellaneous instructions */ - - /* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ - DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs, - REGS(0, NOPC, 0, 0, 0)), - - /* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ - DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx), - - /* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ - DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx, - REGS(0, 0, 0, 0, NOPC)), - - /* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */ - /* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */ - /* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */ - /* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */ - DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ - /* MSR cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ - /* MRS spsr cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ - /* BKPT 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ - /* SMC cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = { - /* Halfword multiply and multiply-accumulate */ - - /* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ - DECODE_OR (0x0ff000b0, 0x012000a0), - /* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, 0, NOPC, 0, NOPC)), - - /* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_OR (0x0ff00090, 0x01000080), - /* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */ - DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0000_____1001_table[] = { - /* Multiply and multiply-accumulate */ - - /* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */ - /* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, 0, NOPC, 0, NOPC)), - - /* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */ - /* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */ - DECODE_OR (0x0fe000f0, 0x00200090), - /* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */ - DECODE_OR (0x0ff000f0, 0x00400090), - /* UMULL cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */ - /* UMULLS cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */ - /* UMLAL cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */ - /* UMLALS cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */ - /* SMULL cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */ - /* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */ - /* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */ - /* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0001_____1001_table[] = { - /* Synchronization primitives */ - -#if __LINUX_ARM_ARCH__ < 6 - /* Deprecated on ARMv6 and may be UNDEFINED on v7 */ - /* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), -#endif - /* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -static const union decode_item arm_cccc_000x_____1xx1_table[] = { - /* Extra load/store instructions */ - - /* STRHT cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */ - /* ??? cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */ - /* LDRHT cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */ - /* LDRSBT cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */ - /* LDRSHT cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */ - DECODE_REJECT (0x0f200090, 0x00200090), - - /* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */ - DECODE_REJECT (0x0e10e0d0, 0x0000e0d0), - - /* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */ - /* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd, - REGS(NOPCWB, NOPCX, 0, 0, NOPC)), - - /* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */ - /* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd, - REGS(NOPCWB, NOPCX, 0, 0, 0)), - - /* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str, - REGS(NOPCWB, NOPC, 0, 0, NOPC)), - - /* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */ - /* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */ - /* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr, - REGS(NOPCWB, NOPC, 0, 0, NOPC)), - - /* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str, - REGS(NOPCWB, NOPC, 0, 0, 0)), - - /* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */ - /* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */ - /* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr, - REGS(NOPCWB, NOPC, 0, 0, 0)), - - DECODE_END -}; - -static const union decode_item arm_cccc_000x_table[] = { - /* Data-processing (register) */ - - /* S PC, ... cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */ - DECODE_REJECT (0x0e10f000, 0x0010f000), - - /* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */ - DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp), - - /* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */ - /* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */ - /* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */ - /* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, 0, 0, 0, ANY)), - - /* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */ - /* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags, - REGS(0, ANY, 0, 0, ANY)), - - /* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */ - /* EOR (register) cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */ - /* SUB (register) cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */ - /* RSB (register) cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */ - /* ADD (register) cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */ - /* ADC (register) cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */ - /* SBC (register) cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */ - /* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */ - /* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */ - /* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, ANY, 0, 0, ANY)), - - /* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */ - /* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */ - /* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */ - /* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, 0, NOPC, 0, ANY)), - - /* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */ - /* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags, - REGS(0, ANY, NOPC, 0, ANY)), - - /* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */ - /* EOR (reg-shift reg) cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */ - /* SUB (reg-shift reg) cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */ - /* RSB (reg-shift reg) cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */ - /* ADD (reg-shift reg) cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */ - /* ADC (reg-shift reg) cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */ - /* SBC (reg-shift reg) cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */ - /* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */ - /* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */ - /* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, ANY, NOPC, 0, ANY)), - - DECODE_END -}; - -static const union decode_item arm_cccc_001x_table[] = { - /* Data-processing (immediate) */ - - /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ - /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0fb00000, 0x03000000, emulate_rd12rm0_noflags_nopc, - 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, kprobe_emulate_none), - /* 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, kprobe_simulate_nop), - /* 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 */ - DECODE_REJECT (0x0fb00000, 0x03200000), - - /* S PC, ... cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */ - DECODE_REJECT (0x0e10f000, 0x0210f000), - - /* TST (immediate) cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */ - /* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */ - /* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */ - /* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, 0, 0, 0, 0)), - - /* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */ - /* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags, - REGS(0, ANY, 0, 0, 0)), - - /* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */ - /* EOR (immediate) cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */ - /* SUB (immediate) cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */ - /* RSB (immediate) cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */ - /* ADD (immediate) cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */ - /* ADC (immediate) cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */ - /* SBC (immediate) cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */ - /* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */ - /* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */ - /* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags, - REGS(ANY, ANY, 0, 0, 0)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0110_____xxx1_table[] = { - /* Media instructions */ - - /* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */ - /* USAT cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */ - DECODE_OR(0x0fa00030, 0x06a00010), - /* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */ - /* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */ - DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ - /* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ - /* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ - /* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */ - DECODE_REJECT (0x0fb00010, 0x06000010), - /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */ - DECODE_REJECT (0x0f8000f0, 0x060000b0), - /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */ - DECODE_REJECT (0x0f8000f0, 0x060000d0), - /* SADD16 cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */ - /* SADDSUBX cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */ - /* SSUBADDX cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */ - /* SSUB16 cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */ - /* SADD8 cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */ - /* SSUB8 cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */ - /* QADD16 cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */ - /* QADDSUBX cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */ - /* QSUBADDX cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */ - /* QSUB16 cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */ - /* QADD8 cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */ - /* QSUB8 cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */ - /* SHADD16 cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */ - /* SHADDSUBX cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */ - /* SHSUBADDX cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */ - /* SHSUB16 cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */ - /* SHADD8 cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */ - /* SHSUB8 cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */ - /* UADD16 cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */ - /* UADDSUBX cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */ - /* USUBADDX cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */ - /* USUB16 cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */ - /* UADD8 cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */ - /* USUB8 cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */ - /* UQADD16 cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */ - /* UQADDSUBX cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */ - /* UQSUBADDX cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */ - /* UQSUB16 cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */ - /* UQADD8 cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */ - /* UQSUB8 cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */ - /* UHADD16 cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */ - /* UHADDSUBX cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */ - /* UHSUBADDX cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */ - /* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */ - /* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */ - /* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */ - /* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */ - DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPC, NOPC, 0, 0, NOPC)), - - /* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */ - /* ??? cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */ - DECODE_REJECT (0x0fb000f0, 0x06900070), - - /* SXTB16 cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */ - /* SXTB cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */ - /* SXTH cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */ - /* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */ - /* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */ - /* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */ - DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */ - /* SXTAB cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */ - /* SXTAH cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */ - /* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */ - /* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */ - /* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */ - DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc, - REGS(NOPCX, NOPC, 0, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_0111_____xxx1_table[] = { - /* Media instructions */ - - /* UNDEFINED cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ - DECODE_REJECT (0x0ff000f0, 0x07f000f0), - - /* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ - /* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */ - /* SMUSD cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */ - DECODE_OR (0x0ff0f090, 0x0700f010), - /* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */ - DECODE_OR (0x0ff0f0d0, 0x0750f010), - /* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, 0, NOPC, 0, NOPC)), - - /* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */ - /* SMLSD cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */ - DECODE_OR (0x0ff00090, 0x07000010), - /* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */ - DECODE_OR (0x0ff000d0, 0x07500010), - /* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPCX, NOPC, 0, NOPC)), - - /* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */ - DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc, - REGS(NOPC, NOPC, NOPC, 0, NOPC)), - - /* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */ - /* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */ - DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPC)), - - /* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */ - DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, 0)), - - /* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */ - DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc, - REGS(0, NOPC, 0, 0, NOPCX)), - - DECODE_END -}; - -static const union decode_item arm_cccc_01xx_table[] = { - /* Load/store word and unsigned byte */ - - /* LDRB/STRB pc,[...] cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0c40f000, 0x0440f000), - - /* STRT cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ - /* LDRT cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ - /* STRBT cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ - /* LDRBT cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0d200000, 0x04200000), - - /* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */ - /* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str, - REGS(NOPCWB, ANY, 0, 0, 0)), - - /* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr, - REGS(NOPCWB, ANY, 0, 0, 0)), - - /* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */ - /* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str, - REGS(NOPCWB, ANY, 0, 0, NOPC)), - - /* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr, - REGS(NOPCWB, ANY, 0, 0, NOPC)), - - DECODE_END -}; - -static const union decode_item arm_cccc_100x_table[] = { - /* Block data transfer instructions */ - - /* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ - /* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm), - - /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */ - /* LDM (exception ret) cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ - DECODE_END -}; - -const union decode_item kprobe_decode_arm_table[] = { - /* - * Unconditional instructions - * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xf0000000, 0xf0000000, arm_1111_table), - - /* - * Miscellaneous instructions - * cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx - */ - DECODE_TABLE (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table), - - /* - * Halfword multiply and multiply-accumulate - * cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx - */ - DECODE_TABLE (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table), - - /* - * Multiply and multiply-accumulate - * cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx - */ - DECODE_TABLE (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table), - - /* - * Synchronization primitives - * cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx - */ - DECODE_TABLE (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table), - - /* - * Extra load/store instructions - * cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx - */ - DECODE_TABLE (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table), - - /* - * Data-processing (register) - * cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx - * Data-processing (register-shifted register) - * cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx - */ - DECODE_TABLE (0x0e000000, 0x00000000, arm_cccc_000x_table), - - /* - * Data-processing (immediate) - * cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0x0e000000, 0x02000000, arm_cccc_001x_table), - - /* - * Media instructions - * cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx - */ - DECODE_TABLE (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table), - DECODE_TABLE (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table), - - /* - * Load/store word and unsigned byte - * cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0x0c000000, 0x04000000, arm_cccc_01xx_table), - - /* - * Block data transfer instructions - * cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0x0e000000, 0x08000000, arm_cccc_100x_table), - - /* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ - /* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl), - - /* - * Supervisor Call, and coprocessor instructions - */ - - /* MCRR cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */ - /* MRRC cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */ - /* LDC cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ - /* STC cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ - /* CDP cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ - /* MCR cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ - /* MRC cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ - /* SVC cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0x0c000000, 0x0c000000), - - DECODE_END -}; -#ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_arm_table); -#endif - -static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); -} - -/* Return: - * INSN_REJECTED If instruction is one not allowed to kprobe, - * INSN_GOOD If instruction is supported and uses instruction slot, - * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. - * - * For instructions we don't want to kprobe (INSN_REJECTED return result): - * These are generally ones that modify the processor state making - * them "hard" to simulate such as switches processor modes or - * make accesses in alternate modes. Any of these could be simulated - * if the work was put into it, but low return considering they - * should also be very rare. - */ -enum kprobe_insn __kprobes -arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - asi->insn_singlestep = arm_singlestep; - asi->insn_check_cc = kprobe_condition_checks[insn>>28]; - return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false); -} diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 455c8003bffb..f02c038059c3 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -13,178 +13,10 @@ #include #include -#include -#include -#include -#include #include "kprobes.h" -#ifndef find_str_pc_offset - -/* - * For STR and STM instructions, an ARM core may choose to use either - * a +8 or a +12 displacement from the current instruction's address. - * Whichever value is chosen for a given core, it must be the same for - * both instructions and may not change. This function measures it. - */ - -int str_pc_offset; - -void __init find_str_pc_offset(void) -{ - int addr, scratch, ret; - - __asm__ ( - "sub %[ret], pc, #4 \n\t" - "str pc, %[addr] \n\t" - "ldr %[scr], %[addr] \n\t" - "sub %[ret], %[scr], %[ret] \n\t" - : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); - - str_pc_offset = ret; -} - -#endif /* !find_str_pc_offset */ - - -#ifndef test_load_write_pc_interworking - -bool load_write_pc_interworks; - -void __init test_load_write_pc_interworking(void) -{ - int arch = cpu_architecture(); - BUG_ON(arch == CPU_ARCH_UNKNOWN); - load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T; -} - -#endif /* !test_load_write_pc_interworking */ - - -#ifndef test_alu_write_pc_interworking - -bool alu_write_pc_interworks; - -void __init test_alu_write_pc_interworking(void) -{ - int arch = cpu_architecture(); - BUG_ON(arch == CPU_ARCH_UNKNOWN); - alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7; -} - -#endif /* !test_alu_write_pc_interworking */ - - -void __init arm_kprobe_decode_init(void) -{ - find_str_pc_offset(); - test_load_write_pc_interworking(); - test_alu_write_pc_interworking(); -} - - -static unsigned long __kprobes __check_eq(unsigned long cpsr) -{ - return cpsr & PSR_Z_BIT; -} - -static unsigned long __kprobes __check_ne(unsigned long cpsr) -{ - return (~cpsr) & PSR_Z_BIT; -} - -static unsigned long __kprobes __check_cs(unsigned long cpsr) -{ - return cpsr & PSR_C_BIT; -} - -static unsigned long __kprobes __check_cc(unsigned long cpsr) -{ - return (~cpsr) & PSR_C_BIT; -} - -static unsigned long __kprobes __check_mi(unsigned long cpsr) -{ - return cpsr & PSR_N_BIT; -} - -static unsigned long __kprobes __check_pl(unsigned long cpsr) -{ - return (~cpsr) & PSR_N_BIT; -} - -static unsigned long __kprobes __check_vs(unsigned long cpsr) -{ - return cpsr & PSR_V_BIT; -} - -static unsigned long __kprobes __check_vc(unsigned long cpsr) -{ - return (~cpsr) & PSR_V_BIT; -} - -static unsigned long __kprobes __check_hi(unsigned long cpsr) -{ - cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ - return cpsr & PSR_C_BIT; -} - -static unsigned long __kprobes __check_ls(unsigned long cpsr) -{ - cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ - return (~cpsr) & PSR_C_BIT; -} - -static unsigned long __kprobes __check_ge(unsigned long cpsr) -{ - cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - return (~cpsr) & PSR_N_BIT; -} - -static unsigned long __kprobes __check_lt(unsigned long cpsr) -{ - cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - return cpsr & PSR_N_BIT; -} - -static unsigned long __kprobes __check_gt(unsigned long cpsr) -{ - unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ - return (~temp) & PSR_N_BIT; -} - -static unsigned long __kprobes __check_le(unsigned long cpsr) -{ - unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ - temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ - return temp & PSR_N_BIT; -} - -static unsigned long __kprobes __check_al(unsigned long cpsr) -{ - return true; -} - -kprobe_check_cc * const kprobe_condition_checks[16] = { - &__check_eq, &__check_ne, &__check_cs, &__check_cc, - &__check_mi, &__check_pl, &__check_vs, &__check_vc, - &__check_hi, &__check_ls, &__check_ge, &__check_lt, - &__check_gt, &__check_le, &__check_al, &__check_al -}; - - -void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs) -{ -} - -void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs) -{ - p->ainsn.insn_fn(); -} - static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -322,260 +154,3 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } - -/* - * Prepare an instruction slot to receive an instruction for emulating. - * This is done by placing a subroutine return after the location where the - * instruction will be placed. We also modify ARM instructions to be - * unconditional as the condition code will already be checked before any - * emulation handler is called. - */ -static kprobe_opcode_t __kprobes -prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - bool thumb) -{ -#ifdef CONFIG_THUMB2_KERNEL - if (thumb) { - u16 *thumb_insn = (u16 *)asi->insn; - thumb_insn[1] = 0x4770; /* Thumb bx lr */ - thumb_insn[2] = 0x4770; /* Thumb bx lr */ - return insn; - } - asi->insn[1] = 0xe12fff1e; /* ARM bx lr */ -#else - asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */ -#endif - /* Make an ARM instruction unconditional */ - if (insn < 0xe0000000) - insn = (insn | 0xe0000000) & ~0x10000000; - return insn; -} - -/* - * Write a (probably modified) instruction into the slot previously prepared by - * prepare_emulated_insn - */ -static void __kprobes -set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - bool thumb) -{ -#ifdef CONFIG_THUMB2_KERNEL - if (thumb) { - u16 *ip = (u16 *)asi->insn; - if (is_wide_instruction(insn)) - *ip++ = insn >> 16; - *ip++ = insn; - return; - } -#endif - asi->insn[0] = insn; -} - -/* - * When we modify the register numbers encoded in an instruction to be emulated, - * the new values come from this define. For ARM and 32-bit Thumb instructions - * this gives... - * - * bit position 16 12 8 4 0 - * ---------------+---+---+---+---+---+ - * register r2 r0 r1 -- r3 - */ -#define INSN_NEW_BITS 0x00020103 - -/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */ -#define INSN_SAMEAS16_BITS 0x22222222 - -/* - * Validate and modify each of the registers encoded in an instruction. - * - * Each nibble in regs contains a value from enum decode_reg_type. For each - * non-zero value, the corresponding nibble in pinsn is validated and modified - * according to the type. - */ -static bool __kprobes decode_regs(kprobe_opcode_t* pinsn, u32 regs) -{ - kprobe_opcode_t insn = *pinsn; - kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */ - - for (; regs != 0; regs >>= 4, mask <<= 4) { - - kprobe_opcode_t new_bits = INSN_NEW_BITS; - - switch (regs & 0xf) { - - case REG_TYPE_NONE: - /* Nibble not a register, skip to next */ - continue; - - case REG_TYPE_ANY: - /* Any register is allowed */ - break; - - case REG_TYPE_SAMEAS16: - /* Replace register with same as at bit position 16 */ - new_bits = INSN_SAMEAS16_BITS; - break; - - case REG_TYPE_SP: - /* Only allow SP (R13) */ - if ((insn ^ 0xdddddddd) & mask) - goto reject; - break; - - case REG_TYPE_PC: - /* Only allow PC (R15) */ - if ((insn ^ 0xffffffff) & mask) - goto reject; - break; - - case REG_TYPE_NOSP: - /* Reject SP (R13) */ - if (((insn ^ 0xdddddddd) & mask) == 0) - goto reject; - break; - - case REG_TYPE_NOSPPC: - case REG_TYPE_NOSPPCX: - /* Reject SP and PC (R13 and R15) */ - if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0) - goto reject; - break; - - case REG_TYPE_NOPCWB: - if (!is_writeback(insn)) - break; /* No writeback, so any register is OK */ - /* fall through... */ - case REG_TYPE_NOPC: - case REG_TYPE_NOPCX: - /* Reject PC (R15) */ - if (((insn ^ 0xffffffff) & mask) == 0) - goto reject; - break; - } - - /* Replace value of nibble with new register number... */ - insn &= ~mask; - insn |= new_bits & mask; - } - - *pinsn = insn; - return true; - -reject: - return false; -} - -static const int decode_struct_sizes[NUM_DECODE_TYPES] = { - [DECODE_TYPE_TABLE] = sizeof(struct decode_table), - [DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom), - [DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate), - [DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate), - [DECODE_TYPE_OR] = sizeof(struct decode_or), - [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) -}; - -/* - * kprobe_decode_insn operates on data tables in order to decode an ARM - * architecture instruction onto which a kprobe has been placed. - * - * These instruction decoding tables are a concatenation of entries each - * of which consist of one of the following structs: - * - * decode_table - * decode_custom - * decode_simulate - * decode_emulate - * decode_or - * decode_reject - * - * Each of these starts with a struct decode_header which has the following - * fields: - * - * type_regs - * mask - * value - * - * The least significant DECODE_TYPE_BITS of type_regs contains a value - * from enum decode_type, this indicates which of the decode_* structs - * the entry contains. The value DECODE_TYPE_END indicates the end of the - * table. - * - * When the table is parsed, each entry is checked in turn to see if it - * matches the instruction to be decoded using the test: - * - * (insn & mask) == value - * - * If no match is found before the end of the table is reached then decoding - * fails with INSN_REJECTED. - * - * When a match is found, decode_regs() is called to validate and modify each - * of the registers encoded in the instruction; the data it uses to do this - * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding - * to fail with INSN_REJECTED. - * - * Once the instruction has passed the above tests, further processing - * depends on the type of the table entry's decode struct. - * - */ -int __kprobes -kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb) -{ - const struct decode_header *h = (struct decode_header *)table; - const struct decode_header *next; - bool matched = false; - - insn = prepare_emulated_insn(insn, asi, thumb); - - for (;; h = next) { - enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; - u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; - - if (type == DECODE_TYPE_END) - return INSN_REJECTED; - - next = (struct decode_header *) - ((uintptr_t)h + decode_struct_sizes[type]); - - if (!matched && (insn & h->mask.bits) != h->value.bits) - continue; - - if (!decode_regs(&insn, regs)) - return INSN_REJECTED; - - switch (type) { - - case DECODE_TYPE_TABLE: { - struct decode_table *d = (struct decode_table *)h; - next = (struct decode_header *)d->table.table; - break; - } - - case DECODE_TYPE_CUSTOM: { - struct decode_custom *d = (struct decode_custom *)h; - return (*d->decoder.decoder)(insn, asi); - } - - case DECODE_TYPE_SIMULATE: { - struct decode_simulate *d = (struct decode_simulate *)h; - asi->insn_handler = d->handler.handler; - return INSN_GOOD_NO_SLOT; - } - - case DECODE_TYPE_EMULATE: { - struct decode_emulate *d = (struct decode_emulate *)h; - asi->insn_handler = d->handler.handler; - set_emulated_insn(insn, asi, thumb); - return INSN_GOOD; - } - - case DECODE_TYPE_OR: - matched = true; - break; - - case DECODE_TYPE_REJECT: - default: - return INSN_REJECTED; - } - } - } diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index 38945f78f9f1..aa68c0ea1a0b 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -52,377 +52,6 @@ enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, void __init arm_kprobe_decode_init(void); -extern kprobe_check_cc * const kprobe_condition_checks[16]; - - -#if __LINUX_ARM_ARCH__ >= 7 - -/* str_pc_offset is architecturally defined from ARMv7 onwards */ -#define str_pc_offset 8 -#define find_str_pc_offset() - -#else /* __LINUX_ARM_ARCH__ < 7 */ - -/* We need a run-time check to determine str_pc_offset */ -extern int str_pc_offset; -void __init find_str_pc_offset(void); - -#endif - - -/* - * Update ITSTATE after normal execution of an IT block instruction. - * - * The 8 IT state bits are split into two parts in CPSR: - * ITSTATE<1:0> are in CPSR<26:25> - * ITSTATE<7:2> are in CPSR<15:10> - */ -static inline unsigned long it_advance(unsigned long cpsr) - { - if ((cpsr & 0x06000400) == 0) { - /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */ - cpsr &= ~PSR_IT_MASK; - } else { - /* We need to shift left ITSTATE<4:0> */ - const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */ - unsigned long it = cpsr & mask; - it <<= 1; - it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */ - it &= mask; - cpsr &= ~mask; - cpsr |= it; - } - return cpsr; -} - -static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs) -{ - long cpsr = regs->ARM_cpsr; - if (pcv & 0x1) { - cpsr |= PSR_T_BIT; - pcv &= ~0x1; - } else { - cpsr &= ~PSR_T_BIT; - pcv &= ~0x2; /* Avoid UNPREDICTABLE address allignment */ - } - regs->ARM_cpsr = cpsr; - regs->ARM_pc = pcv; -} - - -#if __LINUX_ARM_ARCH__ >= 6 - -/* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */ -#define load_write_pc_interworks true -#define test_load_write_pc_interworking() - -#else /* __LINUX_ARM_ARCH__ < 6 */ - -/* We need run-time testing to determine if load_write_pc() should interwork. */ -extern bool load_write_pc_interworks; -void __init test_load_write_pc_interworking(void); - -#endif - -static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs) -{ - if (load_write_pc_interworks) - bx_write_pc(pcv, regs); - else - regs->ARM_pc = pcv; -} - - -#if __LINUX_ARM_ARCH__ >= 7 - -#define alu_write_pc_interworks true -#define test_alu_write_pc_interworking() - -#elif __LINUX_ARM_ARCH__ <= 5 - -/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */ -#define alu_write_pc_interworks false -#define test_alu_write_pc_interworking() - -#else /* __LINUX_ARM_ARCH__ == 6 */ - -/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */ -extern bool alu_write_pc_interworks; -void __init test_alu_write_pc_interworking(void); - -#endif /* __LINUX_ARM_ARCH__ == 6 */ - -static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) -{ - if (alu_write_pc_interworks) - bx_write_pc(pcv, regs); - else - regs->ARM_pc = pcv; -} - - -void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); -void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); - -enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); - -/* - * Test if load/store instructions writeback the address register. - * if P (bit 24) == 0 or W (bit 21) == 1 - */ -#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) - -/* - * The following definitions and macros are used to build instruction - * decoding tables for use by kprobe_decode_insn. - * - * These tables are a concatenation of entries each of which consist of one of - * the decode_* structs. All of the fields in every type of decode structure - * are of the union type decode_item, therefore the entire decode table can be - * viewed as an array of these and declared like: - * - * static const union decode_item table_name[] = {}; - * - * In order to construct each entry in the table, macros are used to - * initialise a number of sequential decode_item values in a layout which - * matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct - * decode_simulate by initialising four decode_item objects like this... - * - * {.bits = _type}, - * {.bits = _mask}, - * {.bits = _value}, - * {.handler = _handler}, - * - * Initialising a specified member of the union means that the compiler - * will produce a warning if the argument is of an incorrect type. - * - * Below is a list of each of the macros used to initialise entries and a - * description of the action performed when that entry is matched to an - * instruction. A match is found when (instruction & mask) == value. - * - * DECODE_TABLE(mask, value, table) - * Instruction decoding jumps to parsing the new sub-table 'table'. - * - * DECODE_CUSTOM(mask, value, decoder) - * The custom function 'decoder' is called to the complete decoding - * of an instruction. - * - * DECODE_SIMULATE(mask, value, handler) - * Set the probes instruction handler to 'handler', this will be used - * to simulate the instruction when the probe is hit. Decoding returns - * with INSN_GOOD_NO_SLOT. - * - * DECODE_EMULATE(mask, value, handler) - * Set the probes instruction handler to 'handler', this will be used - * to emulate the instruction when the probe is hit. The modified - * instruction (see below) is placed in the probes instruction slot so it - * may be called by the emulation code. Decoding returns with INSN_GOOD. - * - * DECODE_REJECT(mask, value) - * Instruction decoding fails with INSN_REJECTED - * - * DECODE_OR(mask, value) - * This allows the mask/value test of multiple table entries to be - * logically ORed. Once an 'or' entry is matched the decoding action to - * be performed is that of the next entry which isn't an 'or'. E.g. - * - * DECODE_OR (mask1, value1) - * DECODE_OR (mask2, value2) - * DECODE_SIMULATE (mask3, value3, simulation_handler) - * - * This means that if any of the three mask/value pairs match the - * instruction being decoded, then 'simulation_handler' will be used - * for it. - * - * Both the SIMULATE and EMULATE macros have a second form which take an - * additional 'regs' argument. - * - * DECODE_SIMULATEX(mask, value, handler, regs) - * DECODE_EMULATEX (mask, value, handler, regs) - * - * These are used to specify what kind of CPU register is encoded in each of the - * least significant 5 nibbles of the instruction being decoded. The regs value - * is specified using the REGS macro, this takes any of the REG_TYPE_* values - * from enum decode_reg_type as arguments; only the '*' part of the name is - * given. E.g. - * - * REGS(0, ANY, NOPC, 0, ANY) - * - * This indicates an instruction is encoded like: - * - * bits 19..16 ignore - * bits 15..12 any register allowed here - * bits 11.. 8 any register except PC allowed here - * bits 7.. 4 ignore - * bits 3.. 0 any register allowed here - * - * This register specification is checked after a decode table entry is found to - * match an instruction (through the mask/value test). Any invalid register then - * found in the instruction will cause decoding to fail with INSN_REJECTED. In - * the above example this would happen if bits 11..8 of the instruction were - * 1111, indicating R15 or PC. - * - * As well as checking for legal combinations of registers, this data is also - * used to modify the registers encoded in the instructions so that an - * emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.) - * - * Here is a real example which matches ARM instructions of the form - * "AND ,,, " - * - * DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, - * REGS(ANY, ANY, NOPC, 0, ANY)), - * ^ ^ ^ ^ - * Rn Rd Rs Rm - * - * Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because - * Rs == R15 - * - * Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the - * instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into - * the kprobes instruction slot. This can then be called later by the handler - * function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction. - */ - -enum decode_type { - DECODE_TYPE_END, - DECODE_TYPE_TABLE, - DECODE_TYPE_CUSTOM, - DECODE_TYPE_SIMULATE, - DECODE_TYPE_EMULATE, - DECODE_TYPE_OR, - DECODE_TYPE_REJECT, - NUM_DECODE_TYPES /* Must be last enum */ -}; - -#define DECODE_TYPE_BITS 4 -#define DECODE_TYPE_MASK ((1 << DECODE_TYPE_BITS) - 1) - -enum decode_reg_type { - REG_TYPE_NONE = 0, /* Not a register, ignore */ - REG_TYPE_ANY, /* Any register allowed */ - REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */ - REG_TYPE_SP, /* Register must be SP */ - REG_TYPE_PC, /* Register must be PC */ - REG_TYPE_NOSP, /* Register must not be SP */ - REG_TYPE_NOSPPC, /* Register must not be SP or PC */ - REG_TYPE_NOPC, /* Register must not be PC */ - REG_TYPE_NOPCWB, /* No PC if load/store write-back flag also set */ - - /* The following types are used when the encoding for PC indicates - * another instruction form. This distiction only matters for test - * case coverage checks. - */ - REG_TYPE_NOPCX, /* Register must not be PC */ - REG_TYPE_NOSPPCX, /* Register must not be SP or PC */ - - /* Alias to allow '0' arg to be used in REGS macro. */ - REG_TYPE_0 = REG_TYPE_NONE -}; - -#define REGS(r16, r12, r8, r4, r0) \ - ((REG_TYPE_##r16) << 16) + \ - ((REG_TYPE_##r12) << 12) + \ - ((REG_TYPE_##r8) << 8) + \ - ((REG_TYPE_##r4) << 4) + \ - (REG_TYPE_##r0) - -union decode_item { - u32 bits; - const union decode_item *table; - kprobe_insn_handler_t *handler; - kprobe_decode_insn_t *decoder; -}; - - -#define DECODE_END \ - {.bits = DECODE_TYPE_END} - - -struct decode_header { - union decode_item type_regs; - union decode_item mask; - union decode_item value; -}; - -#define DECODE_HEADER(_type, _mask, _value, _regs) \ - {.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)}, \ - {.bits = (_mask)}, \ - {.bits = (_value)} - - -struct decode_table { - struct decode_header header; - union decode_item table; -}; - -#define DECODE_TABLE(_mask, _value, _table) \ - DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0), \ - {.table = (_table)} - - -struct decode_custom { - struct decode_header header; - union decode_item decoder; -}; - -#define DECODE_CUSTOM(_mask, _value, _decoder) \ - DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \ - {.decoder = (_decoder)} - - -struct decode_simulate { - struct decode_header header; - union decode_item handler; -}; - -#define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \ - DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \ - {.handler = (_handler)} - -#define DECODE_SIMULATE(_mask, _value, _handler) \ - DECODE_SIMULATEX(_mask, _value, _handler, 0) - - -struct decode_emulate { - struct decode_header header; - union decode_item handler; -}; - -#define DECODE_EMULATEX(_mask, _value, _handler, _regs) \ - DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \ - {.handler = (_handler)} - -#define DECODE_EMULATE(_mask, _value, _handler) \ - DECODE_EMULATEX(_mask, _value, _handler, 0) - - -struct decode_or { - struct decode_header header; -}; - -#define DECODE_OR(_mask, _value) \ - DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0) - - -struct decode_reject { - struct decode_header header; -}; - -#define DECODE_REJECT(_mask, _value) \ - DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0) - - -#ifdef CONFIG_THUMB2_KERNEL -extern const union decode_item kprobe_decode_thumb16_table[]; -extern const union decode_item kprobe_decode_thumb32_table[]; -#else -extern const union decode_item kprobe_decode_arm_table[]; -#endif - - -int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb16); - +#include "probes.h" #endif /* _ARM_KERNEL_KPROBES_H */ diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c new file mode 100644 index 000000000000..57e08b28e87f --- /dev/null +++ b/arch/arm/kernel/probes-arm.c @@ -0,0 +1,731 @@ +/* + * arch/arm/kernel/probes-arm.c + * + * Some code moved here from arch/arm/kernel/kprobes-arm.c + * + * Copyright (C) 2006, 2007 Motorola 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 +#include +#include +#include +#include + +#include "kprobes.h" +#include "probes-arm.h" + +#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) + +#define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) + +/* + * To avoid the complications of mimicing single-stepping on a + * processor without a Next-PC or a single-step mode, and to + * avoid having to deal with the side-effects of boosting, we + * simulate or emulate (almost) all ARM instructions. + * + * "Simulation" is where the instruction's behavior is duplicated in + * C code. "Emulation" is where the original instruction is rewritten + * and executed, often by altering its registers. + * + * By having all behavior of the kprobe'd instruction completed before + * returning from the kprobe_handler(), all locks (scheduler and + * interrupt) can safely be released. There is no need for secondary + * breakpoints, no race with MP or preemptable kernels, nor having to + * clean up resources counts at a later time impacting overall system + * performance. By rewriting the instruction, only the minimum registers + * need to be loaded and saved back optimizing performance. + * + * Calling the insnslot_*_rwflags version of a function doesn't hurt + * anything even when the CPSR flags aren't updated by the + * instruction. It's just a little slower in return for saving + * a little space by not having a duplicate function that doesn't + * update the flags. (The same optimization can be said for + * instructions that do or don't perform register writeback) + * Also, instructions can either read the flags, only write the + * flags, or read and write the flags. To save combinations + * rather than for sheer performance, flag functions just assume + * read and write of flags. + */ + +void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int disp = branch_displacement(insn); + + if (insn & (1 << 24)) + regs->ARM_lr = iaddr + 4; + + regs->ARM_pc = iaddr + 8 + disp; +} + +void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + long iaddr = (long)p->addr; + int disp = branch_displacement(insn); + + regs->ARM_lr = iaddr + 4; + regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); + regs->ARM_cpsr |= PSR_T_BIT; +} + +void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rm = insn & 0xf; + long rmv = regs->uregs[rm]; + + if (insn & (1 << 5)) + regs->ARM_lr = (long)p->addr + 4; + + regs->ARM_pc = rmv & ~0x1; + regs->ARM_cpsr &= ~PSR_T_BIT; + if (rmv & 0x1) + regs->ARM_cpsr |= PSR_T_BIT; +} + +void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) +{ + kprobe_opcode_t insn = p->opcode; + int rd = (insn >> 12) & 0xf; + unsigned long mask = 0xf8ff03df; /* Mask out execution state */ + regs->uregs[rd] = regs->ARM_cpsr & mask; +} + +void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) +{ + regs->uregs[12] = regs->uregs[13]; +} + +/* + * For the instruction masking and comparisons in all the "space_*" + * functions below, Do _not_ rearrange the order of tests unless + * you're very, very sure of what you are doing. For the sake of + * efficiency, the masks for some tests sometimes assume other test + * have been done prior to them so the number of patterns to test + * for an instruction set can be as broad as possible to reduce the + * number of tests needed. + */ + +static const union decode_item arm_1111_table[] = { + /* Unconditional instructions */ + + /* memory hint 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */ + /* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */ + /* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */ + /* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */ + DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop), + + /* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */ + /* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */ + /* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */ + /* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */ + DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop), + + /* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */ + DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1), + + /* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ + /* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ + /* SRS 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ + + /* Coprocessor instructions... */ + /* MCRR2 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */ + /* MRRC2 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */ + /* LDC2 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ + /* STC2 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ + /* CDP2 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ + /* MCR2 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ + /* MRC2 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = { + /* Miscellaneous instructions */ + + /* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ + DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs, + REGS(0, NOPC, 0, 0, 0)), + + /* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ + DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx), + + /* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ + DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx, + REGS(0, 0, 0, 0, NOPC)), + + /* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ + DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, NOPC)), + + /* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */ + /* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */ + /* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */ + /* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */ + DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPC, NOPC, 0, 0, NOPC)), + + /* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ + /* MSR cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ + /* MRS spsr cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ + /* BKPT 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ + /* SMC cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ + /* And unallocated instructions... */ + DECODE_END +}; + +static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = { + /* Halfword multiply and multiply-accumulate */ + + /* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ + DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + /* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ + DECODE_OR (0x0ff000b0, 0x012000a0), + /* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ + DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, 0, NOPC, 0, NOPC)), + + /* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */ + DECODE_OR (0x0ff00090, 0x01000080), + /* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */ + DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + DECODE_END +}; + +static const union decode_item arm_cccc_0000_____1001_table[] = { + /* Multiply and multiply-accumulate */ + + /* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */ + /* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */ + DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, 0, NOPC, 0, NOPC)), + + /* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */ + /* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */ + DECODE_OR (0x0fe000f0, 0x00200090), + /* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */ + DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + /* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */ + DECODE_OR (0x0ff000f0, 0x00400090), + /* UMULL cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */ + /* UMULLS cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */ + /* UMLAL cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */ + /* UMLALS cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */ + /* SMULL cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */ + /* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */ + /* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */ + /* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */ + DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + DECODE_END +}; + +static const union decode_item arm_cccc_0001_____1001_table[] = { + /* Synchronization primitives */ + +#if __LINUX_ARM_ARCH__ < 6 + /* Deprecated on ARMv6 and may be UNDEFINED on v7 */ + /* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */ + DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPC, NOPC, 0, 0, NOPC)), +#endif + /* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */ + /* And unallocated instructions... */ + DECODE_END +}; + +static const union decode_item arm_cccc_000x_____1xx1_table[] = { + /* Extra load/store instructions */ + + /* STRHT cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */ + /* ??? cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */ + /* LDRHT cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */ + /* LDRSBT cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */ + /* LDRSHT cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */ + DECODE_REJECT (0x0f200090, 0x00200090), + + /* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */ + DECODE_REJECT (0x0e10e0d0, 0x0000e0d0), + + /* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */ + /* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */ + DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd, + REGS(NOPCWB, NOPCX, 0, 0, NOPC)), + + /* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */ + /* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */ + DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd, + REGS(NOPCWB, NOPCX, 0, 0, 0)), + + /* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */ + DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str, + REGS(NOPCWB, NOPC, 0, 0, NOPC)), + + /* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */ + /* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */ + /* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */ + DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr, + REGS(NOPCWB, NOPC, 0, 0, NOPC)), + + /* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */ + DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str, + REGS(NOPCWB, NOPC, 0, 0, 0)), + + /* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */ + /* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */ + /* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */ + DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr, + REGS(NOPCWB, NOPC, 0, 0, 0)), + + DECODE_END +}; + +static const union decode_item arm_cccc_000x_table[] = { + /* Data-processing (register) */ + + /* S PC, ... cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */ + DECODE_REJECT (0x0e10f000, 0x0010f000), + + /* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */ + DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp), + + /* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */ + /* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */ + /* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */ + /* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */ + DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, 0, 0, 0, ANY)), + + /* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */ + /* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */ + DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags, + REGS(0, ANY, 0, 0, ANY)), + + /* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */ + /* EOR (register) cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */ + /* SUB (register) cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */ + /* RSB (register) cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */ + /* ADD (register) cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */ + /* ADC (register) cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */ + /* SBC (register) cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */ + /* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */ + /* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */ + /* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */ + DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, ANY, 0, 0, ANY)), + + /* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */ + /* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */ + /* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */ + /* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */ + DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, 0, NOPC, 0, ANY)), + + /* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */ + /* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */ + DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags, + REGS(0, ANY, NOPC, 0, ANY)), + + /* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */ + /* EOR (reg-shift reg) cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */ + /* SUB (reg-shift reg) cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */ + /* RSB (reg-shift reg) cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */ + /* ADD (reg-shift reg) cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */ + /* ADC (reg-shift reg) cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */ + /* SBC (reg-shift reg) cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */ + /* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */ + /* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */ + /* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */ + DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, ANY, NOPC, 0, ANY)), + + DECODE_END +}; + +static const union decode_item arm_cccc_001x_table[] = { + /* Data-processing (immediate) */ + + /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ + /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0fb00000, 0x03000000, emulate_rd12rm0_noflags_nopc, + 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, kprobe_emulate_none), + /* 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, kprobe_simulate_nop), + /* 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 */ + DECODE_REJECT (0x0fb00000, 0x03200000), + + /* S PC, ... cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */ + DECODE_REJECT (0x0e10f000, 0x0210f000), + + /* TST (immediate) cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */ + /* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */ + /* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */ + /* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, 0, 0, 0, 0)), + + /* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */ + /* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags, + REGS(0, ANY, 0, 0, 0)), + + /* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */ + /* EOR (immediate) cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */ + /* SUB (immediate) cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */ + /* RSB (immediate) cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */ + /* ADD (immediate) cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */ + /* ADC (immediate) cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */ + /* SBC (immediate) cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */ + /* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */ + /* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */ + /* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags, + REGS(ANY, ANY, 0, 0, 0)), + + DECODE_END +}; + +static const union decode_item arm_cccc_0110_____xxx1_table[] = { + /* Media instructions */ + + /* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */ + DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPC, NOPC, 0, 0, NOPC)), + + /* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */ + /* USAT cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */ + DECODE_OR(0x0fa00030, 0x06a00010), + /* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */ + /* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */ + DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc, + REGS(0, NOPC, 0, 0, NOPC)), + + /* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ + /* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ + /* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ + /* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ + DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, NOPC)), + + /* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */ + DECODE_REJECT (0x0fb00010, 0x06000010), + /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */ + DECODE_REJECT (0x0f8000f0, 0x060000b0), + /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */ + DECODE_REJECT (0x0f8000f0, 0x060000d0), + /* SADD16 cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */ + /* SADDSUBX cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */ + /* SSUBADDX cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */ + /* SSUB16 cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */ + /* SADD8 cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */ + /* SSUB8 cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */ + /* QADD16 cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */ + /* QADDSUBX cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */ + /* QSUBADDX cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */ + /* QSUB16 cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */ + /* QADD8 cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */ + /* QSUB8 cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */ + /* SHADD16 cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */ + /* SHADDSUBX cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */ + /* SHSUBADDX cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */ + /* SHSUB16 cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */ + /* SHADD8 cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */ + /* SHSUB8 cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */ + /* UADD16 cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */ + /* UADDSUBX cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */ + /* USUBADDX cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */ + /* USUB16 cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */ + /* UADD8 cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */ + /* USUB8 cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */ + /* UQADD16 cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */ + /* UQADDSUBX cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */ + /* UQSUBADDX cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */ + /* UQSUB16 cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */ + /* UQADD8 cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */ + /* UQSUB8 cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */ + /* UHADD16 cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */ + /* UHADDSUBX cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */ + /* UHSUBADDX cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */ + /* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */ + /* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */ + /* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */ + DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPC, NOPC, 0, 0, NOPC)), + + /* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */ + /* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */ + DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPC, NOPC, 0, 0, NOPC)), + + /* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */ + /* ??? cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */ + DECODE_REJECT (0x0fb000f0, 0x06900070), + + /* SXTB16 cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */ + /* SXTB cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */ + /* SXTH cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */ + /* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */ + /* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */ + /* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */ + DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, NOPC)), + + /* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */ + /* SXTAB cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */ + /* SXTAH cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */ + /* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */ + /* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */ + /* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */ + DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc, + REGS(NOPCX, NOPC, 0, 0, NOPC)), + + DECODE_END +}; + +static const union decode_item arm_cccc_0111_____xxx1_table[] = { + /* Media instructions */ + + /* UNDEFINED cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ + DECODE_REJECT (0x0ff000f0, 0x07f000f0), + + /* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ + /* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ + DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + /* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */ + /* SMUSD cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */ + DECODE_OR (0x0ff0f090, 0x0700f010), + /* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */ + DECODE_OR (0x0ff0f0d0, 0x0750f010), + /* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ + DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, 0, NOPC, 0, NOPC)), + + /* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */ + /* SMLSD cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */ + DECODE_OR (0x0ff00090, 0x07000010), + /* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */ + DECODE_OR (0x0ff000d0, 0x07500010), + /* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ + DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, NOPCX, NOPC, 0, NOPC)), + + /* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */ + DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc, + REGS(NOPC, NOPC, NOPC, 0, NOPC)), + + /* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */ + /* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */ + DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, NOPC)), + + /* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */ + DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, 0)), + + /* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */ + DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc, + REGS(0, NOPC, 0, 0, NOPCX)), + + DECODE_END +}; + +static const union decode_item arm_cccc_01xx_table[] = { + /* Load/store word and unsigned byte */ + + /* LDRB/STRB pc,[...] cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0x0c40f000, 0x0440f000), + + /* STRT cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ + /* LDRT cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ + /* STRBT cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ + /* LDRBT cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0x0d200000, 0x04200000), + + /* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */ + /* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str, + REGS(NOPCWB, ANY, 0, 0, 0)), + + /* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */ + /* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr, + REGS(NOPCWB, ANY, 0, 0, 0)), + + /* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */ + /* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str, + REGS(NOPCWB, ANY, 0, 0, NOPC)), + + /* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */ + /* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr, + REGS(NOPCWB, ANY, 0, 0, NOPC)), + + DECODE_END +}; + +static const union decode_item arm_cccc_100x_table[] = { + /* Block data transfer instructions */ + + /* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ + /* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ + DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm), + + /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */ + /* LDM (exception ret) cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ + DECODE_END +}; + +const union decode_item kprobe_decode_arm_table[] = { + /* + * Unconditional instructions + * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xf0000000, 0xf0000000, arm_1111_table), + + /* + * Miscellaneous instructions + * cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx + */ + DECODE_TABLE (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table), + + /* + * Halfword multiply and multiply-accumulate + * cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx + */ + DECODE_TABLE (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table), + + /* + * Multiply and multiply-accumulate + * cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx + */ + DECODE_TABLE (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table), + + /* + * Synchronization primitives + * cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx + */ + DECODE_TABLE (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table), + + /* + * Extra load/store instructions + * cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx + */ + DECODE_TABLE (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table), + + /* + * Data-processing (register) + * cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx + * Data-processing (register-shifted register) + * cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx + */ + DECODE_TABLE (0x0e000000, 0x00000000, arm_cccc_000x_table), + + /* + * Data-processing (immediate) + * cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0x0e000000, 0x02000000, arm_cccc_001x_table), + + /* + * Media instructions + * cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx + */ + DECODE_TABLE (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table), + DECODE_TABLE (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table), + + /* + * Load/store word and unsigned byte + * cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0x0c000000, 0x04000000, arm_cccc_01xx_table), + + /* + * Block data transfer instructions + * cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0x0e000000, 0x08000000, arm_cccc_100x_table), + + /* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ + /* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ + DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl), + + /* + * Supervisor Call, and coprocessor instructions + */ + + /* MCRR cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */ + /* MRRC cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */ + /* LDC cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ + /* STC cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ + /* CDP cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ + /* MCR cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ + /* MRC cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ + /* SVC cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0x0c000000, 0x0c000000), + + DECODE_END +}; +#ifdef CONFIG_ARM_KPROBES_TEST_MODULE +EXPORT_SYMBOL_GPL(kprobe_decode_arm_table); +#endif + +static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_pc += 4; + p->ainsn.insn_handler(p, regs); +} + +/* Return: + * INSN_REJECTED If instruction is one not allowed to kprobe, + * INSN_GOOD If instruction is supported and uses instruction slot, + * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. + * + * For instructions we don't want to kprobe (INSN_REJECTED return result): + * These are generally ones that modify the processor state making + * them "hard" to simulate such as switches processor modes or + * make accesses in alternate modes. Any of these could be simulated + * if the work was put into it, but low return considering they + * should also be very rare. + */ +enum kprobe_insn __kprobes +arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + asi->insn_singlestep = arm_singlestep; + asi->insn_check_cc = kprobe_condition_checks[insn>>28]; + return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false); +} diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h new file mode 100644 index 000000000000..86084727d36d --- /dev/null +++ b/arch/arm/kernel/probes-arm.h @@ -0,0 +1,38 @@ +/* + * arch/arm/kernel/probes-arm.h + * + * Copyright 2013 Linaro Ltd. + * Written by: David A. Long + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _ARM_KERNEL_PROBES_ARM_H +#define _ARM_KERNEL_PROBES_ARM_H + +void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs); + +void __kprobes emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs); +void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs); +void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs); +void __kprobes emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, + struct pt_regs *regs); +void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, + struct pt_regs *regs); +void __kprobes emulate_rd12rm0_noflags_nopc(struct kprobe *p, + struct pt_regs *regs); +void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, + struct pt_regs *regs); + +#endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c new file mode 100644 index 000000000000..3a63f8f83cf8 --- /dev/null +++ b/arch/arm/kernel/probes.c @@ -0,0 +1,443 @@ +/* + * arch/arm/kernel/probes.c + * + * Copyright (C) 2011 Jon Medhurst . + * + * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is + * Copyright (C) 2006, 2007 Motorola 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "kprobes.h" + + +#ifndef find_str_pc_offset + +/* + * For STR and STM instructions, an ARM core may choose to use either + * a +8 or a +12 displacement from the current instruction's address. + * Whichever value is chosen for a given core, it must be the same for + * both instructions and may not change. This function measures it. + */ + +int str_pc_offset; + +void __init find_str_pc_offset(void) +{ + int addr, scratch, ret; + + __asm__ ( + "sub %[ret], pc, #4 \n\t" + "str pc, %[addr] \n\t" + "ldr %[scr], %[addr] \n\t" + "sub %[ret], %[scr], %[ret] \n\t" + : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); + + str_pc_offset = ret; +} + +#endif /* !find_str_pc_offset */ + + +#ifndef test_load_write_pc_interworking + +bool load_write_pc_interworks; + +void __init test_load_write_pc_interworking(void) +{ + int arch = cpu_architecture(); + BUG_ON(arch == CPU_ARCH_UNKNOWN); + load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T; +} + +#endif /* !test_load_write_pc_interworking */ + + +#ifndef test_alu_write_pc_interworking + +bool alu_write_pc_interworks; + +void __init test_alu_write_pc_interworking(void) +{ + int arch = cpu_architecture(); + BUG_ON(arch == CPU_ARCH_UNKNOWN); + alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7; +} + +#endif /* !test_alu_write_pc_interworking */ + + +void __init arm_kprobe_decode_init(void) +{ + find_str_pc_offset(); + test_load_write_pc_interworking(); + test_alu_write_pc_interworking(); +} + + +static unsigned long __kprobes __check_eq(unsigned long cpsr) +{ + return cpsr & PSR_Z_BIT; +} + +static unsigned long __kprobes __check_ne(unsigned long cpsr) +{ + return (~cpsr) & PSR_Z_BIT; +} + +static unsigned long __kprobes __check_cs(unsigned long cpsr) +{ + return cpsr & PSR_C_BIT; +} + +static unsigned long __kprobes __check_cc(unsigned long cpsr) +{ + return (~cpsr) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_mi(unsigned long cpsr) +{ + return cpsr & PSR_N_BIT; +} + +static unsigned long __kprobes __check_pl(unsigned long cpsr) +{ + return (~cpsr) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_vs(unsigned long cpsr) +{ + return cpsr & PSR_V_BIT; +} + +static unsigned long __kprobes __check_vc(unsigned long cpsr) +{ + return (~cpsr) & PSR_V_BIT; +} + +static unsigned long __kprobes __check_hi(unsigned long cpsr) +{ + cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return cpsr & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ls(unsigned long cpsr) +{ + cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ + return (~cpsr) & PSR_C_BIT; +} + +static unsigned long __kprobes __check_ge(unsigned long cpsr) +{ + cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return (~cpsr) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_lt(unsigned long cpsr) +{ + cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + return cpsr & PSR_N_BIT; +} + +static unsigned long __kprobes __check_gt(unsigned long cpsr) +{ + unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ + return (~temp) & PSR_N_BIT; +} + +static unsigned long __kprobes __check_le(unsigned long cpsr) +{ + unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ + temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ + return temp & PSR_N_BIT; +} + +static unsigned long __kprobes __check_al(unsigned long cpsr) +{ + return true; +} + +kprobe_check_cc * const kprobe_condition_checks[16] = { + &__check_eq, &__check_ne, &__check_cs, &__check_cc, + &__check_mi, &__check_pl, &__check_vs, &__check_vc, + &__check_hi, &__check_ls, &__check_ge, &__check_lt, + &__check_gt, &__check_le, &__check_al, &__check_al +}; + + +void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs) +{ +} + +void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs) +{ + p->ainsn.insn_fn(); +} + +/* + * Prepare an instruction slot to receive an instruction for emulating. + * This is done by placing a subroutine return after the location where the + * instruction will be placed. We also modify ARM instructions to be + * unconditional as the condition code will already be checked before any + * emulation handler is called. + */ +static kprobe_opcode_t __kprobes +prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + bool thumb) +{ +#ifdef CONFIG_THUMB2_KERNEL + if (thumb) { + u16 *thumb_insn = (u16 *)asi->insn; + thumb_insn[1] = 0x4770; /* Thumb bx lr */ + thumb_insn[2] = 0x4770; /* Thumb bx lr */ + return insn; + } + asi->insn[1] = 0xe12fff1e; /* ARM bx lr */ +#else + asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */ +#endif + /* Make an ARM instruction unconditional */ + if (insn < 0xe0000000) + insn = (insn | 0xe0000000) & ~0x10000000; + return insn; +} + +/* + * Write a (probably modified) instruction into the slot previously prepared by + * prepare_emulated_insn + */ +static void __kprobes +set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + bool thumb) +{ +#ifdef CONFIG_THUMB2_KERNEL + if (thumb) { + u16 *ip = (u16 *)asi->insn; + if (is_wide_instruction(insn)) + *ip++ = insn >> 16; + *ip++ = insn; + return; + } +#endif + asi->insn[0] = insn; +} + +/* + * When we modify the register numbers encoded in an instruction to be emulated, + * the new values come from this define. For ARM and 32-bit Thumb instructions + * this gives... + * + * bit position 16 12 8 4 0 + * ---------------+---+---+---+---+---+ + * register r2 r0 r1 -- r3 + */ +#define INSN_NEW_BITS 0x00020103 + +/* Each nibble has same value as that at INSN_NEW_BITS bit 16 */ +#define INSN_SAMEAS16_BITS 0x22222222 + +/* + * Validate and modify each of the registers encoded in an instruction. + * + * Each nibble in regs contains a value from enum decode_reg_type. For each + * non-zero value, the corresponding nibble in pinsn is validated and modified + * according to the type. + */ +static bool __kprobes decode_regs(kprobe_opcode_t *pinsn, u32 regs) +{ + kprobe_opcode_t insn = *pinsn; + kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */ + + for (; regs != 0; regs >>= 4, mask <<= 4) { + + kprobe_opcode_t new_bits = INSN_NEW_BITS; + + switch (regs & 0xf) { + + case REG_TYPE_NONE: + /* Nibble not a register, skip to next */ + continue; + + case REG_TYPE_ANY: + /* Any register is allowed */ + break; + + case REG_TYPE_SAMEAS16: + /* Replace register with same as at bit position 16 */ + new_bits = INSN_SAMEAS16_BITS; + break; + + case REG_TYPE_SP: + /* Only allow SP (R13) */ + if ((insn ^ 0xdddddddd) & mask) + goto reject; + break; + + case REG_TYPE_PC: + /* Only allow PC (R15) */ + if ((insn ^ 0xffffffff) & mask) + goto reject; + break; + + case REG_TYPE_NOSP: + /* Reject SP (R13) */ + if (((insn ^ 0xdddddddd) & mask) == 0) + goto reject; + break; + + case REG_TYPE_NOSPPC: + case REG_TYPE_NOSPPCX: + /* Reject SP and PC (R13 and R15) */ + if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0) + goto reject; + break; + + case REG_TYPE_NOPCWB: + if (!is_writeback(insn)) + break; /* No writeback, so any register is OK */ + /* fall through... */ + case REG_TYPE_NOPC: + case REG_TYPE_NOPCX: + /* Reject PC (R15) */ + if (((insn ^ 0xffffffff) & mask) == 0) + goto reject; + break; + } + + /* Replace value of nibble with new register number... */ + insn &= ~mask; + insn |= new_bits & mask; + } + + *pinsn = insn; + return true; + +reject: + return false; +} + +static const int decode_struct_sizes[NUM_DECODE_TYPES] = { + [DECODE_TYPE_TABLE] = sizeof(struct decode_table), + [DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom), + [DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate), + [DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate), + [DECODE_TYPE_OR] = sizeof(struct decode_or), + [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) +}; + +/* + * kprobe_decode_insn operates on data tables in order to decode an ARM + * architecture instruction onto which a kprobe has been placed. + * + * These instruction decoding tables are a concatenation of entries each + * of which consist of one of the following structs: + * + * decode_table + * decode_custom + * decode_simulate + * decode_emulate + * decode_or + * decode_reject + * + * Each of these starts with a struct decode_header which has the following + * fields: + * + * type_regs + * mask + * value + * + * The least significant DECODE_TYPE_BITS of type_regs contains a value + * from enum decode_type, this indicates which of the decode_* structs + * the entry contains. The value DECODE_TYPE_END indicates the end of the + * table. + * + * When the table is parsed, each entry is checked in turn to see if it + * matches the instruction to be decoded using the test: + * + * (insn & mask) == value + * + * If no match is found before the end of the table is reached then decoding + * fails with INSN_REJECTED. + * + * When a match is found, decode_regs() is called to validate and modify each + * of the registers encoded in the instruction; the data it uses to do this + * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding + * to fail with INSN_REJECTED. + * + * Once the instruction has passed the above tests, further processing + * depends on the type of the table entry's decode struct. + * + */ +int __kprobes +kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const union decode_item *table, bool thumb) +{ + const struct decode_header *h = (struct decode_header *)table; + const struct decode_header *next; + bool matched = false; + + insn = prepare_emulated_insn(insn, asi, thumb); + + for (;; h = next) { + enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; + u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; + + if (type == DECODE_TYPE_END) + return INSN_REJECTED; + + next = (struct decode_header *) + ((uintptr_t)h + decode_struct_sizes[type]); + + if (!matched && (insn & h->mask.bits) != h->value.bits) + continue; + + if (!decode_regs(&insn, regs)) + return INSN_REJECTED; + + switch (type) { + + case DECODE_TYPE_TABLE: { + struct decode_table *d = (struct decode_table *)h; + next = (struct decode_header *)d->table.table; + break; + } + + case DECODE_TYPE_CUSTOM: { + struct decode_custom *d = (struct decode_custom *)h; + return (*d->decoder.decoder)(insn, asi); + } + + case DECODE_TYPE_SIMULATE: { + struct decode_simulate *d = (struct decode_simulate *)h; + asi->insn_handler = d->handler.handler; + return INSN_GOOD_NO_SLOT; + } + + case DECODE_TYPE_EMULATE: { + struct decode_emulate *d = (struct decode_emulate *)h; + asi->insn_handler = d->handler.handler; + set_emulated_insn(insn, asi, thumb); + return INSN_GOOD; + } + + case DECODE_TYPE_OR: + matched = true; + break; + + case DECODE_TYPE_REJECT: + default: + return INSN_REJECTED; + } + } +} diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h new file mode 100644 index 000000000000..17f656011aa3 --- /dev/null +++ b/arch/arm/kernel/probes.h @@ -0,0 +1,397 @@ +/* + * arch/arm/kernel/probes.h + * + * Copyright (C) 2011 Jon Medhurst . + * + * Some contents moved here from arch/arm/include/asm/kprobes.h which is + * Copyright (C) 2006, 2007 Motorola 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_H +#define _ARM_KERNEL_PROBES_H + +#include +#include +#include + +#if __LINUX_ARM_ARCH__ >= 7 + +/* str_pc_offset is architecturally defined from ARMv7 onwards */ +#define str_pc_offset 8 +#define find_str_pc_offset() + +#else /* __LINUX_ARM_ARCH__ < 7 */ + +/* We need a run-time check to determine str_pc_offset */ +extern int str_pc_offset; +void __init find_str_pc_offset(void); + +#endif + + +/* + * Update ITSTATE after normal execution of an IT block instruction. + * + * The 8 IT state bits are split into two parts in CPSR: + * ITSTATE<1:0> are in CPSR<26:25> + * ITSTATE<7:2> are in CPSR<15:10> + */ +static inline unsigned long it_advance(unsigned long cpsr) + { + if ((cpsr & 0x06000400) == 0) { + /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */ + cpsr &= ~PSR_IT_MASK; + } else { + /* We need to shift left ITSTATE<4:0> */ + const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */ + unsigned long it = cpsr & mask; + it <<= 1; + it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */ + it &= mask; + cpsr &= ~mask; + cpsr |= it; + } + return cpsr; +} + +static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs) +{ + long cpsr = regs->ARM_cpsr; + if (pcv & 0x1) { + cpsr |= PSR_T_BIT; + pcv &= ~0x1; + } else { + cpsr &= ~PSR_T_BIT; + pcv &= ~0x2; /* Avoid UNPREDICTABLE address allignment */ + } + regs->ARM_cpsr = cpsr; + regs->ARM_pc = pcv; +} + + +#if __LINUX_ARM_ARCH__ >= 6 + +/* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */ +#define load_write_pc_interworks true +#define test_load_write_pc_interworking() + +#else /* __LINUX_ARM_ARCH__ < 6 */ + +/* We need run-time testing to determine if load_write_pc() should interwork. */ +extern bool load_write_pc_interworks; +void __init test_load_write_pc_interworking(void); + +#endif + +static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs) +{ + if (load_write_pc_interworks) + bx_write_pc(pcv, regs); + else + regs->ARM_pc = pcv; +} + + +#if __LINUX_ARM_ARCH__ >= 7 + +#define alu_write_pc_interworks true +#define test_alu_write_pc_interworking() + +#elif __LINUX_ARM_ARCH__ <= 5 + +/* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */ +#define alu_write_pc_interworks false +#define test_alu_write_pc_interworking() + +#else /* __LINUX_ARM_ARCH__ == 6 */ + +/* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */ +extern bool alu_write_pc_interworks; +void __init test_alu_write_pc_interworking(void); + +#endif /* __LINUX_ARM_ARCH__ == 6 */ + +static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) +{ + if (alu_write_pc_interworks) + bx_write_pc(pcv, regs); + else + regs->ARM_pc = pcv; +} + + +void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); +void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); + +enum kprobe_insn __kprobes +kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); + +/* + * Test if load/store instructions writeback the address register. + * if P (bit 24) == 0 or W (bit 21) == 1 + */ +#define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) + +/* + * The following definitions and macros are used to build instruction + * decoding tables for use by kprobe_decode_insn. + * + * These tables are a concatenation of entries each of which consist of one of + * the decode_* structs. All of the fields in every type of decode structure + * are of the union type decode_item, therefore the entire decode table can be + * viewed as an array of these and declared like: + * + * static const union decode_item table_name[] = {}; + * + * In order to construct each entry in the table, macros are used to + * initialise a number of sequential decode_item values in a layout which + * matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct + * decode_simulate by initialising four decode_item objects like this... + * + * {.bits = _type}, + * {.bits = _mask}, + * {.bits = _value}, + * {.handler = _handler}, + * + * Initialising a specified member of the union means that the compiler + * will produce a warning if the argument is of an incorrect type. + * + * Below is a list of each of the macros used to initialise entries and a + * description of the action performed when that entry is matched to an + * instruction. A match is found when (instruction & mask) == value. + * + * DECODE_TABLE(mask, value, table) + * Instruction decoding jumps to parsing the new sub-table 'table'. + * + * DECODE_CUSTOM(mask, value, decoder) + * The custom function 'decoder' is called to the complete decoding + * of an instruction. + * + * DECODE_SIMULATE(mask, value, handler) + * Set the probes instruction handler to 'handler', this will be used + * to simulate the instruction when the probe is hit. Decoding returns + * with INSN_GOOD_NO_SLOT. + * + * DECODE_EMULATE(mask, value, handler) + * Set the probes instruction handler to 'handler', this will be used + * to emulate the instruction when the probe is hit. The modified + * instruction (see below) is placed in the probes instruction slot so it + * may be called by the emulation code. Decoding returns with INSN_GOOD. + * + * DECODE_REJECT(mask, value) + * Instruction decoding fails with INSN_REJECTED + * + * DECODE_OR(mask, value) + * This allows the mask/value test of multiple table entries to be + * logically ORed. Once an 'or' entry is matched the decoding action to + * be performed is that of the next entry which isn't an 'or'. E.g. + * + * DECODE_OR (mask1, value1) + * DECODE_OR (mask2, value2) + * DECODE_SIMULATE (mask3, value3, simulation_handler) + * + * This means that if any of the three mask/value pairs match the + * instruction being decoded, then 'simulation_handler' will be used + * for it. + * + * Both the SIMULATE and EMULATE macros have a second form which take an + * additional 'regs' argument. + * + * DECODE_SIMULATEX(mask, value, handler, regs) + * DECODE_EMULATEX (mask, value, handler, regs) + * + * These are used to specify what kind of CPU register is encoded in each of the + * least significant 5 nibbles of the instruction being decoded. The regs value + * is specified using the REGS macro, this takes any of the REG_TYPE_* values + * from enum decode_reg_type as arguments; only the '*' part of the name is + * given. E.g. + * + * REGS(0, ANY, NOPC, 0, ANY) + * + * This indicates an instruction is encoded like: + * + * bits 19..16 ignore + * bits 15..12 any register allowed here + * bits 11.. 8 any register except PC allowed here + * bits 7.. 4 ignore + * bits 3.. 0 any register allowed here + * + * This register specification is checked after a decode table entry is found to + * match an instruction (through the mask/value test). Any invalid register then + * found in the instruction will cause decoding to fail with INSN_REJECTED. In + * the above example this would happen if bits 11..8 of the instruction were + * 1111, indicating R15 or PC. + * + * As well as checking for legal combinations of registers, this data is also + * used to modify the registers encoded in the instructions so that an + * emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.) + * + * Here is a real example which matches ARM instructions of the form + * "AND ,,, " + * + * DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, + * REGS(ANY, ANY, NOPC, 0, ANY)), + * ^ ^ ^ ^ + * Rn Rd Rs Rm + * + * Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because + * Rs == R15 + * + * Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the + * instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into + * the kprobes instruction slot. This can then be called later by the handler + * function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction. + */ + +enum decode_type { + DECODE_TYPE_END, + DECODE_TYPE_TABLE, + DECODE_TYPE_CUSTOM, + DECODE_TYPE_SIMULATE, + DECODE_TYPE_EMULATE, + DECODE_TYPE_OR, + DECODE_TYPE_REJECT, + NUM_DECODE_TYPES /* Must be last enum */ +}; + +#define DECODE_TYPE_BITS 4 +#define DECODE_TYPE_MASK ((1 << DECODE_TYPE_BITS) - 1) + +enum decode_reg_type { + REG_TYPE_NONE = 0, /* Not a register, ignore */ + REG_TYPE_ANY, /* Any register allowed */ + REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */ + REG_TYPE_SP, /* Register must be SP */ + REG_TYPE_PC, /* Register must be PC */ + REG_TYPE_NOSP, /* Register must not be SP */ + REG_TYPE_NOSPPC, /* Register must not be SP or PC */ + REG_TYPE_NOPC, /* Register must not be PC */ + REG_TYPE_NOPCWB, /* No PC if load/store write-back flag also set */ + + /* The following types are used when the encoding for PC indicates + * another instruction form. This distiction only matters for test + * case coverage checks. + */ + REG_TYPE_NOPCX, /* Register must not be PC */ + REG_TYPE_NOSPPCX, /* Register must not be SP or PC */ + + /* Alias to allow '0' arg to be used in REGS macro. */ + REG_TYPE_0 = REG_TYPE_NONE +}; + +#define REGS(r16, r12, r8, r4, r0) \ + (((REG_TYPE_##r16) << 16) + \ + ((REG_TYPE_##r12) << 12) + \ + ((REG_TYPE_##r8) << 8) + \ + ((REG_TYPE_##r4) << 4) + \ + (REG_TYPE_##r0)) + +union decode_item { + u32 bits; + const union decode_item *table; + kprobe_insn_handler_t *handler; + kprobe_decode_insn_t *decoder; +}; + + +#define DECODE_END \ + {.bits = DECODE_TYPE_END} + + +struct decode_header { + union decode_item type_regs; + union decode_item mask; + union decode_item value; +}; + +#define DECODE_HEADER(_type, _mask, _value, _regs) \ + {.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)}, \ + {.bits = (_mask)}, \ + {.bits = (_value)} + + +struct decode_table { + struct decode_header header; + union decode_item table; +}; + +#define DECODE_TABLE(_mask, _value, _table) \ + DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0), \ + {.table = (_table)} + + +struct decode_custom { + struct decode_header header; + union decode_item decoder; +}; + +#define DECODE_CUSTOM(_mask, _value, _decoder) \ + DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \ + {.decoder = (_decoder)} + + +struct decode_simulate { + struct decode_header header; + union decode_item handler; +}; + +#define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \ + DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \ + {.handler = (_handler)} + +#define DECODE_SIMULATE(_mask, _value, _handler) \ + DECODE_SIMULATEX(_mask, _value, _handler, 0) + + +struct decode_emulate { + struct decode_header header; + union decode_item handler; +}; + +#define DECODE_EMULATEX(_mask, _value, _handler, _regs) \ + DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \ + {.handler = (_handler)} + +#define DECODE_EMULATE(_mask, _value, _handler) \ + DECODE_EMULATEX(_mask, _value, _handler, 0) + + +struct decode_or { + struct decode_header header; +}; + +#define DECODE_OR(_mask, _value) \ + DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0) + + +struct decode_reject { + struct decode_header header; +}; + +#define DECODE_REJECT(_mask, _value) \ + DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0) + + +#ifdef CONFIG_THUMB2_KERNEL +extern const union decode_item kprobe_decode_thumb16_table[]; +extern const union decode_item kprobe_decode_thumb32_table[]; +#else +extern const union decode_item kprobe_decode_arm_table[]; +#endif + +extern kprobe_check_cc * const kprobe_condition_checks[16]; + + +int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const union decode_item *table, bool thumb16); + +#endif -- cgit v1.2.3 From 87abef63ead5ac9e2c67f0c07c461eda6be16aeb Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:06:29 -0500 Subject: ARM: move generic thumb instruction parsing code to new files for use by other feature Move the thumb version of the kprobes instruction parsing code into more generic files from where it can be used by uprobes and possibly other subsystems. The symbol names will be made more generic in a subsequent part of this patchset. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/kprobes-thumb.c | 949 ++-------------------------------------- arch/arm/kernel/probes-thumb.c | 878 +++++++++++++++++++++++++++++++++++++ arch/arm/kernel/probes-thumb.h | 81 ++++ 4 files changed, 1000 insertions(+), 910 deletions(-) create mode 100644 arch/arm/kernel/probes-thumb.c create mode 100644 arch/arm/kernel/probes-thumb.h (limited to 'arch/arm') diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 4c8b13e64280..bb739f28dd80 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -52,7 +52,7 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o obj-$(CONFIG_KPROBES) += probes.o kprobes.o kprobes-common.o patch.o ifdef CONFIG_THUMB2_KERNEL -obj-$(CONFIG_KPROBES) += kprobes-thumb.o +obj-$(CONFIG_KPROBES) += kprobes-thumb.o probes-thumb.o else obj-$(CONFIG_KPROBES) += kprobes-arm.o probes-arm.o endif diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 6123daf397a7..977f21723a9c 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -8,24 +8,13 @@ * published by the Free Software Foundation. */ +#include #include +#include #include -#include #include "kprobes.h" - - -/* - * True if current instruction is in an IT block. - */ -#define in_it_block(cpsr) ((cpsr & 0x06000c00) != 0x00000000) - -/* - * Return the condition code to check for the currently executing instruction. - * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if - * in_it_block returns true. - */ -#define current_cond(cpsr) ((cpsr >> 12) & 0xf) +#include "probes-thumb.h" /* * Return the PC value for a probe in thumb code. @@ -38,7 +27,9 @@ static inline unsigned long __kprobes thumb_probe_pc(struct kprobe *p) return (unsigned long)p->addr - 1 + 4; } -static void __kprobes +/* t32 thumb actions */ + +void __kprobes t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -58,7 +49,7 @@ t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + 2 * halfwords; } -static void __kprobes +void __kprobes t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -67,7 +58,7 @@ t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = regs->ARM_cpsr & mask; } -static void __kprobes +void __kprobes t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -82,7 +73,7 @@ t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) { int cc = (insn >> 22) & 0xf; @@ -91,7 +82,7 @@ t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } -static void __kprobes +void __kprobes t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -119,7 +110,7 @@ t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -static void __kprobes +void __kprobes t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -157,7 +148,7 @@ t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = rtv; } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) { enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi); @@ -170,7 +161,7 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) return ret; } -static void __kprobes +void __kprobes t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -197,7 +188,7 @@ t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt2] = rt2v; } -static void __kprobes +void __kprobes t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -223,7 +214,7 @@ t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = rtv; } -static void __kprobes +void __kprobes t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -250,7 +241,7 @@ t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static void __kprobes +void __kprobes t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -270,7 +261,7 @@ t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -static void __kprobes +void __kprobes t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -290,7 +281,7 @@ t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -static void __kprobes +void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -315,640 +306,9 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rdlo] = rdlov; regs->uregs[rdhi] = rdhiv; } +/* t16 thumb actions */ -/* These emulation encodings are functionally equivalent... */ -#define t32_emulate_rd8rn16rm0ra12_noflags \ - t32_emulate_rdlo12rdhi8rn16rm0_noflags - -static const union decode_item t32_table_1110_100x_x0xx[] = { - /* Load/store multiple instructions */ - - /* Rn is PC 1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe4f0000, 0xe80f0000), - - /* SRS 1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */ - /* RFE 1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffc00000, 0xe8000000), - /* SRS 1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */ - /* RFE 1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffc00000, 0xe9800000), - - /* STM Rn, {...pc} 1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe508000, 0xe8008000), - /* LDM Rn, {...lr,pc} 1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe50c000, 0xe810c000), - /* LDM/STM Rn, {...sp} 1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */ - DECODE_REJECT (0xfe402000, 0xe8002000), - - /* STMIA 1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ - /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), - - DECODE_END -}; - -static const union decode_item t32_table_1110_100x_x1xx[] = { - /* Load/store dual, load/store exclusive, table branch */ - - /* STRD (immediate) 1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */ - /* LDRD (immediate) 1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_OR (0xff600000, 0xe8600000), - /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ - /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, - REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), - - /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ - /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ - DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, - REGS(NOSP, 0, 0, 0, NOSPPC)), - - /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ - /* LDREX 1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */ - /* STREXB 1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */ - /* STREXH 1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */ - /* STREXD 1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */ - /* LDREXB 1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */ - /* LDREXH 1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */ - /* LDREXD 1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1110_101x[] = { - /* Data-processing (shifted register) */ - - /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ - /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, 0, 0, NOSPPC)), - - /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ - DECODE_OR (0xfff00f00, 0xeb100f00), - /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOPC, 0, 0, 0, NOSPPC)), - - /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ - /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(0, 0, NOSPPC, 0, NOSPPC)), - - /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ - /* ??? 1110 1010 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffa00000, 0xeaa00000), - /* ??? 1110 1011 001x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffe00000, 0xeb200000), - /* ??? 1110 1011 100x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffe00000, 0xeb800000), - /* ??? 1110 1011 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xffe00000, 0xebe00000), - - /* ADD/SUB SP, SP, Rm, LSL #0..3 */ - /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ - DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, - REGS(SP, 0, SP, 0, NOSPPC)), - - /* ADD/SUB SP, SP, Rm, shift */ - /* 1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */ - DECODE_REJECT (0xff4f0f00, 0xeb0d0d00), - - /* ADD/SUB Rd, SP, Rm, shift */ - /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(SP, 0, NOPC, 0, NOSPPC)), - - /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ - /* BIC 1110 1010 001x xxxx xxxx xxxx xxxx xxxx */ - /* ORR 1110 1010 010x xxxx xxxx xxxx xxxx xxxx */ - /* ORN 1110 1010 011x xxxx xxxx xxxx xxxx xxxx */ - /* EOR 1110 1010 100x xxxx xxxx xxxx xxxx xxxx */ - /* PKH 1110 1010 110x xxxx xxxx xxxx xxxx xxxx */ - /* ADD 1110 1011 000x xxxx xxxx xxxx xxxx xxxx */ - /* ADC 1110 1011 010x xxxx xxxx xxxx xxxx xxxx */ - /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ - /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ - /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), - - DECODE_END -}; - -static const union decode_item t32_table_1111_0x0x___0[] = { - /* Data-processing (modified immediate) */ - - /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ - /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, 0, 0, 0)), - - /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_OR (0xfbf08f00, 0xf1100f00), - /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOPC, 0, 0, 0, 0)), - - /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ - /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(0, 0, NOSPPC, 0, 0)), - - /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf0a00000), - /* ??? 1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */ - /* ??? 1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbc08000, 0xf0c00000), - /* ??? 1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf1200000), - /* ??? 1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf1800000), - /* ??? 1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfbe08000, 0xf1e00000), - - /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ - /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, - REGS(SP, 0, NOPC, 0, 0)), - - /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ - /* BIC 1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */ - /* ORR 1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */ - /* ORN 1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */ - /* EOR 1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */ - /* ADD 1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */ - /* ADC 1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */ - /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ - /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ - /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, 0)), - - DECODE_END -}; - -static const union decode_item t32_table_1111_0x1x___0[] = { - /* Data-processing (plain binary immediate) */ - - /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ - DECODE_OR (0xfbff8000, 0xf20f0000), - /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, - REGS(PC, 0, NOSPPC, 0, 0)), - - /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ - DECODE_OR (0xfbff8f00, 0xf20d0d00), - /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ - DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, - REGS(SP, 0, SP, 0, 0)), - - /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_OR (0xfbf08000, 0xf2000000), - /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, - REGS(NOPCX, 0, NOSPPC, 0, 0)), - - /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ - /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, - REGS(0, 0, NOSPPC, 0, 0)), - - /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ - /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ - /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ - /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, 0)), - - /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ - /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, - REGS(NOSPPC, 0, NOSPPC, 0, 0)), - - /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, - REGS(0, 0, NOSPPC, 0, 0)), - - /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, - REGS(NOSPPCX, 0, NOSPPC, 0, 0)), - - DECODE_END -}; - -static const union decode_item t32_table_1111_0xxx___1[] = { - /* Branches and miscellaneous control */ - - /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ - DECODE_OR (0xfff0d7ff, 0xf3a08001), - /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ - DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), - /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ - /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ - /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ - DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), - - /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, - REGS(0, 0, NOSPPC, 0, 0)), - - /* - * Unsupported instructions - * 1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx - * - * MSR 1111 0011 100x xxxx 10x0 xxxx xxxx xxxx - * DBG hint 1111 0011 1010 xxxx 10x0 x000 1111 xxxx - * Unallocated hints 1111 0011 1010 xxxx 10x0 x000 xxxx xxxx - * CPS 1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx - * CLREX/DSB/DMB/ISB 1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx - * BXJ 1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx - * SUBS PC,LR,# 1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx - * MRS Rd, SPSR 1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx - * SMC 1111 0111 1111 xxxx 1000 xxxx xxxx xxxx - * UNDEFINED 1111 0111 1111 xxxx 1010 xxxx xxxx xxxx - * ??? 1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx - */ - DECODE_REJECT (0xfb80d000, 0xf3808000), - - /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ - DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), - - /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ - DECODE_OR (0xf800d001, 0xf000c000), - /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ - /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ - DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), - - DECODE_END -}; - -static const union decode_item t32_table_1111_100x_x0x1__1111[] = { - /* Memory hints */ - - /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ - /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), - - /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ - DECODE_OR (0xffd0f000, 0xf890f000), - /* PLD{W} (immediate) 1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */ - DECODE_OR (0xffd0ff00, 0xf810fc00), - /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ - DECODE_OR (0xfff0f000, 0xf990f000), - /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ - DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, - REGS(NOPCX, 0, 0, 0, 0)), - - /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ - DECODE_OR (0xffd0ffc0, 0xf810f000), - /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ - DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, - REGS(NOPCX, 0, 0, 0, NOSPPC)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_100x[] = { - /* Store/Load single data item */ - - /* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfe600000, 0xf8600000), - - /* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xfff00000, 0xf9500000), - - /* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */ - DECODE_REJECT (0xfe800d00, 0xf8000800), - - /* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */ - /* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */ - /* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */ - /* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */ - /* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */ - /* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */ - /* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */ - /* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */ - DECODE_REJECT (0xfe800f00, 0xf8000e00), - - /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */ - DECODE_REJECT (0xff1f0000, 0xf80f0000), - - /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */ - DECODE_REJECT (0xff10f000, 0xf800f000), - - /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, - REGS(PC, ANY, 0, 0, 0)), - - /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ - /* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */ - DECODE_OR (0xffe00800, 0xf8400800), - /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ - /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, - REGS(NOPCX, ANY, 0, 0, 0)), - - /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ - /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ - DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, - REGS(NOPCX, ANY, 0, 0, NOSPPC)), - - /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ - /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ - /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ - /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, - REGS(PC, NOSPPCX, 0, 0, 0)), - - /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ - /* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */ - /* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */ - DECODE_OR (0xfec00800, 0xf8000800), - /* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */ - /* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */ - /* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */ - /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ - /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ - /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, - REGS(NOPCX, NOSPPCX, 0, 0, 0)), - - /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ - /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ - /* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */ - /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ - /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ - /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ - DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, - REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_1010___1111[] = { - /* Data-processing (register) */ - - /* ??? 1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */ - DECODE_REJECT (0xffe0f080, 0xfa60f080), - - /* SXTH 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */ - /* UXTH 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */ - /* SXTB16 1111 1010 0010 1111 1111 xxxx 1xxx xxxx */ - /* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */ - /* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */ - /* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */ - DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, t32_emulate_rd8rn16rm0_rwflags, - REGS(0, 0, NOSPPC, 0, NOSPPC)), - - - /* ??? 1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */ - DECODE_REJECT (0xff80f0b0, 0xfa80f030), - /* ??? 1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */ - DECODE_REJECT (0xffb0f080, 0xfab0f000), - - /* SADD16 1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */ - /* SASX 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */ - /* SSAX 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */ - /* SSUB16 1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */ - /* SADD8 1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */ - /* SSUB8 1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */ - - /* QADD16 1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */ - /* QASX 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */ - /* QSAX 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */ - /* QSUB16 1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */ - /* QADD8 1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */ - /* QSUB8 1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */ - - /* SHADD16 1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */ - /* SHASX 1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */ - /* SHSAX 1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */ - /* SHSUB16 1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */ - /* SHADD8 1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */ - /* SHSUB8 1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */ - - /* UADD16 1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */ - /* UASX 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */ - /* USAX 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */ - /* USUB16 1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */ - /* UADD8 1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */ - /* USUB8 1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */ - - /* UQADD16 1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */ - /* UQASX 1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */ - /* UQSAX 1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */ - /* UQSUB16 1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */ - /* UQADD8 1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */ - /* UQSUB8 1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */ - - /* UHADD16 1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */ - /* UHASX 1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */ - /* UHSAX 1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */ - /* UHSUB16 1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */ - /* UHADD8 1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */ - /* UHSUB8 1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */ - DECODE_OR (0xff80f080, 0xfa80f000), - - /* SXTAH 1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */ - /* UXTAH 1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */ - /* SXTAB16 1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */ - /* UXTAB16 1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */ - /* SXTAB 1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */ - /* UXTAB 1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */ - DECODE_OR (0xff80f080, 0xfa00f080), - - /* QADD 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */ - /* QDADD 1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */ - /* QSUB 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */ - /* QDSUB 1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */ - DECODE_OR (0xfff0f0c0, 0xfa80f080), - - /* SEL 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ - DECODE_OR (0xfff0f0f0, 0xfaa0f080), - - /* LSL 1111 1010 000x xxxx 1111 xxxx 0000 xxxx */ - /* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */ - /* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */ - /* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), - - /* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ - DECODE_OR (0xfff0f0f0, 0xfab0f080), - - /* REV 1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */ - /* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */ - /* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */ - /* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */ - DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, t32_emulate_rd8rn16_noflags, - REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_1011_0[] = { - /* Multiply, multiply accumulate, and absolute difference */ - - /* ??? 1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */ - DECODE_REJECT (0xfff0f0f0, 0xfb00f010), - /* ??? 1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */ - DECODE_REJECT (0xfff0f0f0, 0xfb70f010), - - /* SMULxy 1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */ - DECODE_OR (0xfff0f0c0, 0xfb10f000), - /* MUL 1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */ - /* SMUAD{X} 1111 1011 0010 xxxx 1111 xxxx 000x xxxx */ - /* SMULWy 1111 1011 0011 xxxx 1111 xxxx 000x xxxx */ - /* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */ - /* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */ - /* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, t32_emulate_rd8rn16rm0_rwflags, - REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), - - /* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */ - DECODE_REJECT (0xfff000f0, 0xfb700010), - - /* SMLAxy 1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */ - DECODE_OR (0xfff000c0, 0xfb100000), - /* MLA 1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */ - /* MLS 1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */ - /* SMLAD{X} 1111 1011 0010 xxxx xxxx xxxx 000x xxxx */ - /* SMLAWy 1111 1011 0011 xxxx xxxx xxxx 000x xxxx */ - /* SMLSD{X} 1111 1011 0100 xxxx xxxx xxxx 000x xxxx */ - /* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */ - /* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */ - /* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff8000c0, 0xfb000000, t32_emulate_rd8rn16rm0ra12_noflags, - REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)), - - /* Other unallocated instructions... */ - DECODE_END -}; - -static const union decode_item t32_table_1111_1011_1[] = { - /* Long multiply, long multiply accumulate, and divide */ - - /* UMAAL 1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */ - DECODE_OR (0xfff000f0, 0xfbe00060), - /* SMLALxy 1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */ - DECODE_OR (0xfff000c0, 0xfbc00080), - /* SMLALD{X} 1111 1011 1100 xxxx xxxx xxxx 110x xxxx */ - /* SMLSLD{X} 1111 1011 1101 xxxx xxxx xxxx 110x xxxx */ - DECODE_OR (0xffe000e0, 0xfbc000c0), - /* SMULL 1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */ - /* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */ - /* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */ - /* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff9000f0, 0xfb800000, t32_emulate_rdlo12rdhi8rn16rm0_noflags, - REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)), - - /* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */ - /* UDIV 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */ - /* Other unallocated instructions... */ - DECODE_END -}; - -const union decode_item kprobe_decode_thumb32_table[] = { - - /* - * Load/store multiple instructions - * 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx), - - /* - * Load/store dual, load/store exclusive, table branch - * 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx), - - /* - * Data-processing (shifted register) - * 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe000000, 0xea000000, t32_table_1110_101x), - - /* - * Coprocessor instructions - * 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_REJECT (0xfc000000, 0xec000000), - - /* - * Data-processing (modified immediate) - * 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0), - - /* - * Data-processing (plain binary immediate) - * 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0), - - /* - * Branches and miscellaneous control - * 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1), - - /* - * Advanced SIMD element or structure load/store instructions - * 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx - */ - DECODE_REJECT (0xff100000, 0xf9000000), - - /* - * Memory hints - * 1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), - - /* - * Store single data item - * 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx - * Load single data items - * 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x), - - /* - * Data-processing (register) - * 1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx - */ - DECODE_TABLE (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111), - - /* - * Multiply, multiply accumulate, and absolute difference - * 1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xff800000, 0xfb000000, t32_table_1111_1011_0), - - /* - * Long multiply, long multiply accumulate, and divide - * 1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_TABLE (0xff800000, 0xfb800000, t32_table_1111_1011_1), - - /* - * Coprocessor instructions - * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx - */ - DECODE_END -}; -#ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_thumb32_table); -#endif - -static void __kprobes +void __kprobes t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -962,7 +322,7 @@ t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) bx_write_pc(rmv, regs); } -static void __kprobes +void __kprobes t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -972,7 +332,7 @@ t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = base[index]; } -static void __kprobes +void __kprobes t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -985,7 +345,7 @@ t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) base[index] = regs->uregs[rt]; } -static void __kprobes +void __kprobes t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -996,7 +356,7 @@ t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = base + offset * 4; } -static void __kprobes +void __kprobes t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -1007,7 +367,7 @@ t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) regs->ARM_sp += imm * 4; } -static void __kprobes +void __kprobes t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -1021,7 +381,7 @@ t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) } } -static void __kprobes +void __kprobes t16_simulate_it(struct kprobe *p, struct pt_regs *regs) { /* @@ -1038,21 +398,21 @@ t16_simulate_it(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = cpsr; } -static void __kprobes +void __kprobes t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) { regs->ARM_pc += 2; t16_simulate_it(p, regs); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi) { asi->insn_singlestep = t16_singlestep_it; return INSN_GOOD_NO_SLOT; } -static void __kprobes +void __kprobes t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -1062,7 +422,7 @@ t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) { int cc = (insn >> 8) & 0xf; @@ -1071,7 +431,7 @@ t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } -static void __kprobes +void __kprobes t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -1103,13 +463,13 @@ t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK); } -static void __kprobes +void __kprobes t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) { regs->ARM_cpsr = t16_emulate_loregs(p, regs); } -static void __kprobes +void __kprobes t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) { unsigned long cpsr = t16_emulate_loregs(p, regs); @@ -1117,7 +477,7 @@ t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = cpsr; } -static void __kprobes +void __kprobes t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -1148,7 +508,7 @@ t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) { insn &= ~0x00ff; @@ -1158,7 +518,7 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } -static void __kprobes +void __kprobes t16_emulate_push(struct kprobe *p, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -1174,7 +534,7 @@ t16_emulate_push(struct kprobe *p, struct pt_regs *regs) ); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* @@ -1188,7 +548,7 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } -static void __kprobes +void __kprobes t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -1204,7 +564,7 @@ t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) ); } -static void __kprobes +void __kprobes t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) { register unsigned long pc asm("r8"); @@ -1224,7 +584,7 @@ t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) bx_write_pc(pc, regs); } -static enum kprobe_insn __kprobes +enum kprobe_insn __kprobes t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) { /* @@ -1238,232 +598,3 @@ t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) : t16_emulate_pop_nopc; return INSN_GOOD; } - -static const union decode_item t16_table_1011[] = { - /* Miscellaneous 16-bit instructions */ - - /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ - /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ - DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), - - /* CBZ 1011 00x1 xxxx xxxx */ - /* CBNZ 1011 10x1 xxxx xxxx */ - DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), - - /* SXTH 1011 0010 00xx xxxx */ - /* SXTB 1011 0010 01xx xxxx */ - /* UXTH 1011 0010 10xx xxxx */ - /* UXTB 1011 0010 11xx xxxx */ - /* REV 1011 1010 00xx xxxx */ - /* REV16 1011 1010 01xx xxxx */ - /* ??? 1011 1010 10xx xxxx */ - /* REVSH 1011 1010 11xx xxxx */ - DECODE_REJECT (0xffc0, 0xba80), - DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), - - /* PUSH 1011 010x xxxx xxxx */ - DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), - /* POP 1011 110x xxxx xxxx */ - DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), - - /* - * If-Then, and hints - * 1011 1111 xxxx xxxx - */ - - /* YIELD 1011 1111 0001 0000 */ - DECODE_OR (0xffff, 0xbf10), - /* SEV 1011 1111 0100 0000 */ - DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), - /* NOP 1011 1111 0000 0000 */ - /* WFE 1011 1111 0010 0000 */ - /* WFI 1011 1111 0011 0000 */ - DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), - /* Unassigned hints 1011 1111 xxxx 0000 */ - DECODE_REJECT (0xff0f, 0xbf00), - /* IT 1011 1111 xxxx xxxx */ - DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), - - /* SETEND 1011 0110 010x xxxx */ - /* CPS 1011 0110 011x xxxx */ - /* BKPT 1011 1110 xxxx xxxx */ - /* And unallocated instructions... */ - DECODE_END -}; - -const union decode_item kprobe_decode_thumb16_table[] = { - - /* - * Shift (immediate), add, subtract, move, and compare - * 00xx xxxx xxxx xxxx - */ - - /* CMP (immediate) 0010 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), - - /* ADD (register) 0001 100x xxxx xxxx */ - /* SUB (register) 0001 101x xxxx xxxx */ - /* LSL (immediate) 0000 0xxx xxxx xxxx */ - /* LSR (immediate) 0000 1xxx xxxx xxxx */ - /* ASR (immediate) 0001 0xxx xxxx xxxx */ - /* ADD (immediate, Thumb) 0001 110x xxxx xxxx */ - /* SUB (immediate, Thumb) 0001 111x xxxx xxxx */ - /* MOV (immediate) 0010 0xxx xxxx xxxx */ - /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ - /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ - DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), - - /* - * 16-bit Thumb data-processing instructions - * 0100 00xx xxxx xxxx - */ - - /* TST (register) 0100 0010 00xx xxxx */ - DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), - /* CMP (register) 0100 0010 10xx xxxx */ - /* CMN (register) 0100 0010 11xx xxxx */ - DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), - /* AND (register) 0100 0000 00xx xxxx */ - /* EOR (register) 0100 0000 01xx xxxx */ - /* LSL (register) 0100 0000 10xx xxxx */ - /* LSR (register) 0100 0000 11xx xxxx */ - /* ASR (register) 0100 0001 00xx xxxx */ - /* ADC (register) 0100 0001 01xx xxxx */ - /* SBC (register) 0100 0001 10xx xxxx */ - /* ROR (register) 0100 0001 11xx xxxx */ - /* RSB (immediate) 0100 0010 01xx xxxx */ - /* ORR (register) 0100 0011 00xx xxxx */ - /* MUL 0100 0011 00xx xxxx */ - /* BIC (register) 0100 0011 10xx xxxx */ - /* MVN (register) 0100 0011 10xx xxxx */ - DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), - - /* - * Special data instructions and branch and exchange - * 0100 01xx xxxx xxxx - */ - - /* BLX pc 0100 0111 1111 1xxx */ - DECODE_REJECT (0xfff8, 0x47f8), - - /* BX (register) 0100 0111 0xxx xxxx */ - /* BLX (register) 0100 0111 1xxx xxxx */ - DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), - - /* ADD pc, pc 0100 0100 1111 1111 */ - DECODE_REJECT (0xffff, 0x44ff), - - /* ADD (register) 0100 0100 xxxx xxxx */ - /* CMP (register) 0100 0101 xxxx xxxx */ - /* MOV (register) 0100 0110 xxxx xxxx */ - DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), - - /* - * Load from Literal Pool - * LDR (literal) 0100 1xxx xxxx xxxx - */ - DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), - - /* - * 16-bit Thumb Load/store instructions - * 0101 xxxx xxxx xxxx - * 011x xxxx xxxx xxxx - * 100x xxxx xxxx xxxx - */ - - /* STR (register) 0101 000x xxxx xxxx */ - /* STRH (register) 0101 001x xxxx xxxx */ - /* STRB (register) 0101 010x xxxx xxxx */ - /* LDRSB (register) 0101 011x xxxx xxxx */ - /* LDR (register) 0101 100x xxxx xxxx */ - /* LDRH (register) 0101 101x xxxx xxxx */ - /* LDRB (register) 0101 110x xxxx xxxx */ - /* LDRSH (register) 0101 111x xxxx xxxx */ - /* STR (immediate, Thumb) 0110 0xxx xxxx xxxx */ - /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ - /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ - /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ - DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), - /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ - /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), - /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ - /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ - DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), - - /* - * Generate PC-/SP-relative address - * ADR (literal) 1010 0xxx xxxx xxxx - * ADD (SP plus immediate) 1010 1xxx xxxx xxxx - */ - DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), - - /* - * Miscellaneous 16-bit instructions - * 1011 xxxx xxxx xxxx - */ - DECODE_TABLE (0xf000, 0xb000, t16_table_1011), - - /* STM 1100 0xxx xxxx xxxx */ - /* LDM 1100 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), - - /* - * Conditional branch, and Supervisor Call - */ - - /* Permanently UNDEFINED 1101 1110 xxxx xxxx */ - /* SVC 1101 1111 xxxx xxxx */ - DECODE_REJECT (0xfe00, 0xde00), - - /* Conditional branch 1101 xxxx xxxx xxxx */ - DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), - - /* - * Unconditional branch - * B 1110 0xxx xxxx xxxx - */ - DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), - - DECODE_END -}; -#ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_thumb16_table); -#endif - -static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) -{ - if (unlikely(in_it_block(cpsr))) - return kprobe_condition_checks[current_cond(cpsr)](cpsr); - return true; -} - -static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc += 2; - p->ainsn.insn_handler(p, regs); - regs->ARM_cpsr = it_advance(regs->ARM_cpsr); -} - -static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); - regs->ARM_cpsr = it_advance(regs->ARM_cpsr); -} - -enum kprobe_insn __kprobes -thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - asi->insn_singlestep = thumb16_singlestep; - asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); -} - -enum kprobe_insn __kprobes -thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) -{ - asi->insn_singlestep = thumb32_singlestep; - asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); -} diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c new file mode 100644 index 000000000000..a1f24777a41a --- /dev/null +++ b/arch/arm/kernel/probes-thumb.c @@ -0,0 +1,878 @@ +/* + * arch/arm/kernel/kprobes-thumb.c + * + * Copyright (C) 2011 Jon Medhurst . + * + * 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. + */ + +#include +#include +#include +#include + +#include "kprobes.h" +#include "probes-thumb.h" + +/* These emulation encodings are functionally equivalent... */ +#define t32_emulate_rd8rn16rm0ra12_noflags \ + t32_emulate_rdlo12rdhi8rn16rm0_noflags + +static const union decode_item t32_table_1110_100x_x0xx[] = { + /* Load/store multiple instructions */ + + /* Rn is PC 1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe4f0000, 0xe80f0000), + + /* SRS 1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE 1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffc00000, 0xe8000000), + /* SRS 1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */ + /* RFE 1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffc00000, 0xe9800000), + + /* STM Rn, {...pc} 1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe508000, 0xe8008000), + /* LDM Rn, {...lr,pc} 1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe50c000, 0xe810c000), + /* LDM/STM Rn, {...sp} 1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */ + DECODE_REJECT (0xfe402000, 0xe8002000), + + /* STMIA 1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ + /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), + + DECODE_END +}; + +static const union decode_item t32_table_1110_100x_x1xx[] = { + /* Load/store dual, load/store exclusive, table branch */ + + /* STRD (immediate) 1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */ + /* LDRD (immediate) 1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */ + DECODE_OR (0xff600000, 0xe8600000), + /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ + /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, + REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), + + /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ + /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ + DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, + REGS(NOSP, 0, 0, 0, NOSPPC)), + + /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ + /* LDREX 1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */ + /* STREXB 1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */ + /* STREXH 1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */ + /* STREXD 1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */ + /* LDREXB 1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */ + /* LDREXH 1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */ + /* LDREXD 1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */ + /* And unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1110_101x[] = { + /* Data-processing (shifted register) */ + + /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ + /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, 0, 0, NOSPPC)), + + /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ + DECODE_OR (0xfff00f00, 0xeb100f00), + /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOPC, 0, 0, 0, NOSPPC)), + + /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ + /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(0, 0, NOSPPC, 0, NOSPPC)), + + /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ + /* ??? 1110 1010 111x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffa00000, 0xeaa00000), + /* ??? 1110 1011 001x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffe00000, 0xeb200000), + /* ??? 1110 1011 100x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffe00000, 0xeb800000), + /* ??? 1110 1011 111x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xffe00000, 0xebe00000), + + /* ADD/SUB SP, SP, Rm, LSL #0..3 */ + /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ + DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, + REGS(SP, 0, SP, 0, NOSPPC)), + + /* ADD/SUB SP, SP, Rm, shift */ + /* 1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */ + DECODE_REJECT (0xff4f0f00, 0xeb0d0d00), + + /* ADD/SUB Rd, SP, Rm, shift */ + /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(SP, 0, NOPC, 0, NOSPPC)), + + /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ + /* BIC 1110 1010 001x xxxx xxxx xxxx xxxx xxxx */ + /* ORR 1110 1010 010x xxxx xxxx xxxx xxxx xxxx */ + /* ORN 1110 1010 011x xxxx xxxx xxxx xxxx xxxx */ + /* EOR 1110 1010 100x xxxx xxxx xxxx xxxx xxxx */ + /* PKH 1110 1010 110x xxxx xxxx xxxx xxxx xxxx */ + /* ADD 1110 1011 000x xxxx xxxx xxxx xxxx xxxx */ + /* ADC 1110 1011 010x xxxx xxxx xxxx xxxx xxxx */ + /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ + /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ + /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), + + DECODE_END +}; + +static const union decode_item t32_table_1111_0x0x___0[] = { + /* Data-processing (modified immediate) */ + + /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ + /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, 0, 0, 0)), + + /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ + DECODE_OR (0xfbf08f00, 0xf1100f00), + /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ + DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOPC, 0, 0, 0, 0)), + + /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ + /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(0, 0, NOSPPC, 0, 0)), + + /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf0a00000), + /* ??? 1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */ + /* ??? 1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbc08000, 0xf0c00000), + /* ??? 1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf1200000), + /* ??? 1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf1800000), + /* ??? 1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfbe08000, 0xf1e00000), + + /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ + /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, + REGS(SP, 0, NOPC, 0, 0)), + + /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ + /* BIC 1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */ + /* ORR 1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */ + /* ORN 1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */ + /* EOR 1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */ + /* ADD 1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */ + /* ADC 1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */ + /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ + /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ + /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, 0)), + + DECODE_END +}; + +static const union decode_item t32_table_1111_0x1x___0[] = { + /* Data-processing (plain binary immediate) */ + + /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ + DECODE_OR (0xfbff8000, 0xf20f0000), + /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, + REGS(PC, 0, NOSPPC, 0, 0)), + + /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ + DECODE_OR (0xfbff8f00, 0xf20d0d00), + /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ + DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, + REGS(SP, 0, SP, 0, 0)), + + /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_OR (0xfbf08000, 0xf2000000), + /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, + REGS(NOPCX, 0, NOSPPC, 0, 0)), + + /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ + /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, + REGS(0, 0, NOSPPC, 0, 0)), + + /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ + /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ + /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ + /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, 0)), + + /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ + /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, + REGS(NOSPPC, 0, NOSPPC, 0, 0)), + + /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, + REGS(0, 0, NOSPPC, 0, 0)), + + /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, + REGS(NOSPPCX, 0, NOSPPC, 0, 0)), + + DECODE_END +}; + +static const union decode_item t32_table_1111_0xxx___1[] = { + /* Branches and miscellaneous control */ + + /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ + DECODE_OR (0xfff0d7ff, 0xf3a08001), + /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ + DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), + /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ + /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ + /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ + DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), + + /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ + DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, + REGS(0, 0, NOSPPC, 0, 0)), + + /* + * Unsupported instructions + * 1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx + * + * MSR 1111 0011 100x xxxx 10x0 xxxx xxxx xxxx + * DBG hint 1111 0011 1010 xxxx 10x0 x000 1111 xxxx + * Unallocated hints 1111 0011 1010 xxxx 10x0 x000 xxxx xxxx + * CPS 1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx + * CLREX/DSB/DMB/ISB 1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx + * BXJ 1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx + * SUBS PC,LR,# 1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx + * MRS Rd, SPSR 1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx + * SMC 1111 0111 1111 xxxx 1000 xxxx xxxx xxxx + * UNDEFINED 1111 0111 1111 xxxx 1010 xxxx xxxx xxxx + * ??? 1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx + */ + DECODE_REJECT (0xfb80d000, 0xf3808000), + + /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ + DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), + + /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ + DECODE_OR (0xf800d001, 0xf000c000), + /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ + /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ + DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), + + DECODE_END +}; + +static const union decode_item t32_table_1111_100x_x0x1__1111[] = { + /* Memory hints */ + + /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ + /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ + DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), + + /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ + DECODE_OR (0xffd0f000, 0xf890f000), + /* PLD{W} (immediate) 1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */ + DECODE_OR (0xffd0ff00, 0xf810fc00), + /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ + DECODE_OR (0xfff0f000, 0xf990f000), + /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ + DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, + REGS(NOPCX, 0, 0, 0, 0)), + + /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ + DECODE_OR (0xffd0ffc0, 0xf810f000), + /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ + DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, + REGS(NOPCX, 0, 0, 0, NOSPPC)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_100x[] = { + /* Store/Load single data item */ + + /* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfe600000, 0xf8600000), + + /* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xfff00000, 0xf9500000), + + /* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */ + DECODE_REJECT (0xfe800d00, 0xf8000800), + + /* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */ + /* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */ + /* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */ + /* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */ + /* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */ + /* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */ + /* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */ + /* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */ + DECODE_REJECT (0xfe800f00, 0xf8000e00), + + /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */ + DECODE_REJECT (0xff1f0000, 0xf80f0000), + + /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */ + DECODE_REJECT (0xff10f000, 0xf800f000), + + /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ + DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, + REGS(PC, ANY, 0, 0, 0)), + + /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ + /* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */ + DECODE_OR (0xffe00800, 0xf8400800), + /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ + /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, + REGS(NOPCX, ANY, 0, 0, 0)), + + /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ + /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ + DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, + REGS(NOPCX, ANY, 0, 0, NOSPPC)), + + /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ + /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ + /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ + /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ + DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, + REGS(PC, NOSPPCX, 0, 0, 0)), + + /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ + /* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */ + /* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */ + DECODE_OR (0xfec00800, 0xf8000800), + /* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */ + /* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */ + /* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */ + /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ + /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ + /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ + DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, + REGS(NOPCX, NOSPPCX, 0, 0, 0)), + + /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ + /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ + /* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */ + /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ + /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ + /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ + DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, + REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_1010___1111[] = { + /* Data-processing (register) */ + + /* ??? 1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */ + DECODE_REJECT (0xffe0f080, 0xfa60f080), + + /* SXTH 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */ + /* UXTH 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */ + /* SXTB16 1111 1010 0010 1111 1111 xxxx 1xxx xxxx */ + /* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */ + /* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */ + /* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */ + DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, t32_emulate_rd8rn16rm0_rwflags, + REGS(0, 0, NOSPPC, 0, NOSPPC)), + + + /* ??? 1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */ + DECODE_REJECT (0xff80f0b0, 0xfa80f030), + /* ??? 1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */ + DECODE_REJECT (0xffb0f080, 0xfab0f000), + + /* SADD16 1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */ + /* SASX 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */ + /* SSAX 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */ + /* SSUB16 1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */ + /* SADD8 1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */ + /* SSUB8 1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */ + + /* QADD16 1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */ + /* QASX 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */ + /* QSAX 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */ + /* QSUB16 1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */ + /* QADD8 1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */ + /* QSUB8 1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */ + + /* SHADD16 1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */ + /* SHASX 1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */ + /* SHSAX 1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */ + /* SHSUB16 1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */ + /* SHADD8 1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */ + /* SHSUB8 1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */ + + /* UADD16 1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */ + /* UASX 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */ + /* USAX 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */ + /* USUB16 1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */ + /* UADD8 1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */ + /* USUB8 1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */ + + /* UQADD16 1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */ + /* UQASX 1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */ + /* UQSAX 1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */ + /* UQSUB16 1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */ + /* UQADD8 1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */ + /* UQSUB8 1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */ + + /* UHADD16 1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */ + /* UHASX 1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */ + /* UHSAX 1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */ + /* UHSUB16 1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */ + /* UHADD8 1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */ + /* UHSUB8 1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */ + DECODE_OR (0xff80f080, 0xfa80f000), + + /* SXTAH 1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */ + /* UXTAH 1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */ + /* SXTAB16 1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */ + /* UXTAB16 1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */ + /* SXTAB 1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */ + /* UXTAB 1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */ + DECODE_OR (0xff80f080, 0xfa00f080), + + /* QADD 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */ + /* QDADD 1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */ + /* QSUB 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */ + /* QDSUB 1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */ + DECODE_OR (0xfff0f0c0, 0xfa80f080), + + /* SEL 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ + DECODE_OR (0xfff0f0f0, 0xfaa0f080), + + /* LSL 1111 1010 000x xxxx 1111 xxxx 0000 xxxx */ + /* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */ + /* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */ + /* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), + + /* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ + DECODE_OR (0xfff0f0f0, 0xfab0f080), + + /* REV 1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */ + /* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */ + /* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */ + /* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */ + DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, t32_emulate_rd8rn16_noflags, + REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_1011_0[] = { + /* Multiply, multiply accumulate, and absolute difference */ + + /* ??? 1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */ + DECODE_REJECT (0xfff0f0f0, 0xfb00f010), + /* ??? 1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */ + DECODE_REJECT (0xfff0f0f0, 0xfb70f010), + + /* SMULxy 1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */ + DECODE_OR (0xfff0f0c0, 0xfb10f000), + /* MUL 1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */ + /* SMUAD{X} 1111 1011 0010 xxxx 1111 xxxx 000x xxxx */ + /* SMULWy 1111 1011 0011 xxxx 1111 xxxx 000x xxxx */ + /* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */ + /* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */ + /* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, t32_emulate_rd8rn16rm0_rwflags, + REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), + + /* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */ + DECODE_REJECT (0xfff000f0, 0xfb700010), + + /* SMLAxy 1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */ + DECODE_OR (0xfff000c0, 0xfb100000), + /* MLA 1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */ + /* MLS 1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */ + /* SMLAD{X} 1111 1011 0010 xxxx xxxx xxxx 000x xxxx */ + /* SMLAWy 1111 1011 0011 xxxx xxxx xxxx 000x xxxx */ + /* SMLSD{X} 1111 1011 0100 xxxx xxxx xxxx 000x xxxx */ + /* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */ + /* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */ + /* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff8000c0, 0xfb000000, t32_emulate_rd8rn16rm0ra12_noflags, + REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)), + + /* Other unallocated instructions... */ + DECODE_END +}; + +static const union decode_item t32_table_1111_1011_1[] = { + /* Long multiply, long multiply accumulate, and divide */ + + /* UMAAL 1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */ + DECODE_OR (0xfff000f0, 0xfbe00060), + /* SMLALxy 1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */ + DECODE_OR (0xfff000c0, 0xfbc00080), + /* SMLALD{X} 1111 1011 1100 xxxx xxxx xxxx 110x xxxx */ + /* SMLSLD{X} 1111 1011 1101 xxxx xxxx xxxx 110x xxxx */ + DECODE_OR (0xffe000e0, 0xfbc000c0), + /* SMULL 1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */ + /* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */ + /* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */ + /* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */ + DECODE_EMULATEX (0xff9000f0, 0xfb800000, t32_emulate_rdlo12rdhi8rn16rm0_noflags, + REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)), + + /* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */ + /* UDIV 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */ + /* Other unallocated instructions... */ + DECODE_END +}; + +const union decode_item kprobe_decode_thumb32_table[] = { + + /* + * Load/store multiple instructions + * 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx), + + /* + * Load/store dual, load/store exclusive, table branch + * 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx), + + /* + * Data-processing (shifted register) + * 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe000000, 0xea000000, t32_table_1110_101x), + + /* + * Coprocessor instructions + * 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_REJECT (0xfc000000, 0xec000000), + + /* + * Data-processing (modified immediate) + * 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0), + + /* + * Data-processing (plain binary immediate) + * 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0), + + /* + * Branches and miscellaneous control + * 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1), + + /* + * Advanced SIMD element or structure load/store instructions + * 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx + */ + DECODE_REJECT (0xff100000, 0xf9000000), + + /* + * Memory hints + * 1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), + + /* + * Store single data item + * 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx + * Load single data items + * 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x), + + /* + * Data-processing (register) + * 1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx + */ + DECODE_TABLE (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111), + + /* + * Multiply, multiply accumulate, and absolute difference + * 1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xff800000, 0xfb000000, t32_table_1111_1011_0), + + /* + * Long multiply, long multiply accumulate, and divide + * 1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_TABLE (0xff800000, 0xfb800000, t32_table_1111_1011_1), + + /* + * Coprocessor instructions + * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx + */ + DECODE_END +}; +#ifdef CONFIG_ARM_KPROBES_TEST_MODULE +EXPORT_SYMBOL_GPL(kprobe_decode_thumb32_table); +#endif + +static const union decode_item t16_table_1011[] = { + /* Miscellaneous 16-bit instructions */ + + /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ + /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ + DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), + + /* CBZ 1011 00x1 xxxx xxxx */ + /* CBNZ 1011 10x1 xxxx xxxx */ + DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), + + /* SXTH 1011 0010 00xx xxxx */ + /* SXTB 1011 0010 01xx xxxx */ + /* UXTH 1011 0010 10xx xxxx */ + /* UXTB 1011 0010 11xx xxxx */ + /* REV 1011 1010 00xx xxxx */ + /* REV16 1011 1010 01xx xxxx */ + /* ??? 1011 1010 10xx xxxx */ + /* REVSH 1011 1010 11xx xxxx */ + DECODE_REJECT (0xffc0, 0xba80), + DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), + + /* PUSH 1011 010x xxxx xxxx */ + DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), + /* POP 1011 110x xxxx xxxx */ + DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), + + /* + * If-Then, and hints + * 1011 1111 xxxx xxxx + */ + + /* YIELD 1011 1111 0001 0000 */ + DECODE_OR (0xffff, 0xbf10), + /* SEV 1011 1111 0100 0000 */ + DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), + /* NOP 1011 1111 0000 0000 */ + /* WFE 1011 1111 0010 0000 */ + /* WFI 1011 1111 0011 0000 */ + DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), + /* Unassigned hints 1011 1111 xxxx 0000 */ + DECODE_REJECT (0xff0f, 0xbf00), + /* IT 1011 1111 xxxx xxxx */ + DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), + + /* SETEND 1011 0110 010x xxxx */ + /* CPS 1011 0110 011x xxxx */ + /* BKPT 1011 1110 xxxx xxxx */ + /* And unallocated instructions... */ + DECODE_END +}; + +const union decode_item kprobe_decode_thumb16_table[] = { + + /* + * Shift (immediate), add, subtract, move, and compare + * 00xx xxxx xxxx xxxx + */ + + /* CMP (immediate) 0010 1xxx xxxx xxxx */ + DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), + + /* ADD (register) 0001 100x xxxx xxxx */ + /* SUB (register) 0001 101x xxxx xxxx */ + /* LSL (immediate) 0000 0xxx xxxx xxxx */ + /* LSR (immediate) 0000 1xxx xxxx xxxx */ + /* ASR (immediate) 0001 0xxx xxxx xxxx */ + /* ADD (immediate, Thumb) 0001 110x xxxx xxxx */ + /* SUB (immediate, Thumb) 0001 111x xxxx xxxx */ + /* MOV (immediate) 0010 0xxx xxxx xxxx */ + /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ + /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ + DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), + + /* + * 16-bit Thumb data-processing instructions + * 0100 00xx xxxx xxxx + */ + + /* TST (register) 0100 0010 00xx xxxx */ + DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), + /* CMP (register) 0100 0010 10xx xxxx */ + /* CMN (register) 0100 0010 11xx xxxx */ + DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), + /* AND (register) 0100 0000 00xx xxxx */ + /* EOR (register) 0100 0000 01xx xxxx */ + /* LSL (register) 0100 0000 10xx xxxx */ + /* LSR (register) 0100 0000 11xx xxxx */ + /* ASR (register) 0100 0001 00xx xxxx */ + /* ADC (register) 0100 0001 01xx xxxx */ + /* SBC (register) 0100 0001 10xx xxxx */ + /* ROR (register) 0100 0001 11xx xxxx */ + /* RSB (immediate) 0100 0010 01xx xxxx */ + /* ORR (register) 0100 0011 00xx xxxx */ + /* MUL 0100 0011 00xx xxxx */ + /* BIC (register) 0100 0011 10xx xxxx */ + /* MVN (register) 0100 0011 10xx xxxx */ + DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), + + /* + * Special data instructions and branch and exchange + * 0100 01xx xxxx xxxx + */ + + /* BLX pc 0100 0111 1111 1xxx */ + DECODE_REJECT (0xfff8, 0x47f8), + + /* BX (register) 0100 0111 0xxx xxxx */ + /* BLX (register) 0100 0111 1xxx xxxx */ + DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), + + /* ADD pc, pc 0100 0100 1111 1111 */ + DECODE_REJECT (0xffff, 0x44ff), + + /* ADD (register) 0100 0100 xxxx xxxx */ + /* CMP (register) 0100 0101 xxxx xxxx */ + /* MOV (register) 0100 0110 xxxx xxxx */ + DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), + + /* + * Load from Literal Pool + * LDR (literal) 0100 1xxx xxxx xxxx + */ + DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), + + /* + * 16-bit Thumb Load/store instructions + * 0101 xxxx xxxx xxxx + * 011x xxxx xxxx xxxx + * 100x xxxx xxxx xxxx + */ + + /* STR (register) 0101 000x xxxx xxxx */ + /* STRH (register) 0101 001x xxxx xxxx */ + /* STRB (register) 0101 010x xxxx xxxx */ + /* LDRSB (register) 0101 011x xxxx xxxx */ + /* LDR (register) 0101 100x xxxx xxxx */ + /* LDRH (register) 0101 101x xxxx xxxx */ + /* LDRB (register) 0101 110x xxxx xxxx */ + /* LDRSH (register) 0101 111x xxxx xxxx */ + /* STR (immediate, Thumb) 0110 0xxx xxxx xxxx */ + /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ + /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ + /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ + DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), + /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ + /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ + DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), + /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ + /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ + DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), + + /* + * Generate PC-/SP-relative address + * ADR (literal) 1010 0xxx xxxx xxxx + * ADD (SP plus immediate) 1010 1xxx xxxx xxxx + */ + DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), + + /* + * Miscellaneous 16-bit instructions + * 1011 xxxx xxxx xxxx + */ + DECODE_TABLE (0xf000, 0xb000, t16_table_1011), + + /* STM 1100 0xxx xxxx xxxx */ + /* LDM 1100 1xxx xxxx xxxx */ + DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), + + /* + * Conditional branch, and Supervisor Call + */ + + /* Permanently UNDEFINED 1101 1110 xxxx xxxx */ + /* SVC 1101 1111 xxxx xxxx */ + DECODE_REJECT (0xfe00, 0xde00), + + /* Conditional branch 1101 xxxx xxxx xxxx */ + DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), + + /* + * Unconditional branch + * B 1110 0xxx xxxx xxxx + */ + DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), + + DECODE_END +}; +#ifdef CONFIG_ARM_KPROBES_TEST_MODULE +EXPORT_SYMBOL_GPL(kprobe_decode_thumb16_table); +#endif + +static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) +{ + if (unlikely(in_it_block(cpsr))) + return kprobe_condition_checks[current_cond(cpsr)](cpsr); + return true; +} + +static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_pc += 2; + p->ainsn.insn_handler(p, regs); + regs->ARM_cpsr = it_advance(regs->ARM_cpsr); +} + +static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + regs->ARM_pc += 4; + p->ainsn.insn_handler(p, regs); + regs->ARM_cpsr = it_advance(regs->ARM_cpsr); +} + +enum kprobe_insn __kprobes +thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + asi->insn_singlestep = thumb16_singlestep; + asi->insn_check_cc = thumb_check_cc; + return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); +} + +enum kprobe_insn __kprobes +thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +{ + asi->insn_singlestep = thumb32_singlestep; + asi->insn_check_cc = thumb_check_cc; + return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); +} diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h new file mode 100644 index 000000000000..98709c40b659 --- /dev/null +++ b/arch/arm/kernel/probes-thumb.h @@ -0,0 +1,81 @@ +/* + * arch/arm/kernel/probes-thumb.h + * + * Copyright 2013 Linaro Ltd. + * Written by: David A. Long + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _ARM_KERNEL_PROBES_THUMB_H +#define _ARM_KERNEL_PROBES_THUMB_H + +/* + * True if current instruction is in an IT block. + */ +#define in_it_block(cpsr) ((cpsr & 0x06000c00) != 0x00000000) + +/* + * Return the condition code to check for the currently executing instruction. + * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if + * in_it_block returns true. + */ +#define current_cond(cpsr) ((cpsr >> 12) & 0xf) + +void __kprobes t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_simulate_ldrstr_sp_relative(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_simulate_it(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_singlestep_it(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t16_decode_it(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t16_decode_cond_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t16_simulate_branch(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_emulate_loregs_rwflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t16_emulate_loregs_noitrwflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t16_decode_hiregs(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t16_emulate_push(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t16_decode_push(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs); +void __kprobes t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t16_decode_pop(kprobe_opcode_t insn, + struct arch_specific_insn *asi); + +void __kprobes t32_simulate_table_branch(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs); +void __kprobes t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t32_decode_cond_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t32_simulate_branch(struct kprobe *p, struct pt_regs *regs); +void __kprobes t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); +enum kprobe_insn __kprobes t32_decode_ldmstm(kprobe_opcode_t insn, + struct arch_specific_insn *asi); +void __kprobes t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs); +void __kprobes t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs); +void __kprobes t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t32_emulate_rd8pc16_noflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t32_emulate_rd8rn16_noflags(struct kprobe *p, + struct pt_regs *regs); +void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, + struct pt_regs *regs); + +#endif -- cgit v1.2.3 From 3e6cd394bb10c2d65322e5f5d2ff0a9074d903a1 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Thu, 6 Mar 2014 18:06:43 -0500 Subject: ARM: use a function table for determining instruction interpreter action Make the instruction interpreter call back to semantic action functions through a function pointer array provided by the invoker. The interpreter decodes the instructions into groups and uses the group number to index into the supplied array. kprobes and uprobes code will each supply their own array of functions. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/kernel/kprobes-arm.c | 57 ++++++++++++--- arch/arm/kernel/kprobes-common.c | 3 +- arch/arm/kernel/kprobes-thumb.c | 149 ++++++++++++++++++++++++++++----------- arch/arm/kernel/kprobes.c | 9 ++- arch/arm/kernel/kprobes.h | 15 ++-- arch/arm/kernel/probes-arm.c | 114 +++++++++++++++--------------- arch/arm/kernel/probes-arm.h | 52 ++++++++++---- arch/arm/kernel/probes-thumb.c | 145 ++++++++++++++++++------------------- arch/arm/kernel/probes-thumb.h | 104 ++++++++++++++------------- arch/arm/kernel/probes.c | 9 +-- arch/arm/kernel/probes.h | 55 ++++++++++----- 11 files changed, 441 insertions(+), 271 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index a1d0a8f00f9e..8ebd84c48867 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -73,7 +73,7 @@ #endif -void __kprobes +static void __kprobes emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -102,7 +102,7 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -void __kprobes +static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -132,7 +132,7 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -void __kprobes +static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -159,7 +159,7 @@ emulate_str(struct kprobe *p, struct pt_regs *regs) regs->uregs[rn] = rnv; } -void __kprobes +static void __kprobes emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -194,7 +194,7 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -void __kprobes +static void __kprobes emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -221,7 +221,7 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -void __kprobes +static void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -250,7 +250,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -void __kprobes +static void __kprobes emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -270,7 +270,7 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -void __kprobes +static void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -299,3 +299,44 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) regs->uregs[rdhi] = rdhiv; regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } + +const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { + [PROBES_EMULATE_NONE] = {.handler = kprobe_emulate_none}, + [PROBES_SIMULATE_NOP] = {.handler = kprobe_simulate_nop}, + [PROBES_PRELOAD_IMM] = {.handler = kprobe_simulate_nop}, + [PROBES_PRELOAD_REG] = {.handler = kprobe_simulate_nop}, + [PROBES_BRANCH_IMM] = {.handler = simulate_blx1}, + [PROBES_MRS] = {.handler = simulate_mrs}, + [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, + [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc}, + [PROBES_SATURATING_ARITHMETIC] = { + .handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc}, + [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc}, + [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd}, + [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr}, + [PROBES_LOAD] = {.handler = emulate_ldr}, + [PROBES_STORE_EXTRA] = {.handler = emulate_str}, + [PROBES_STORE] = {.handler = emulate_str}, + [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp}, + [PROBES_DATA_PROCESSING_REG] = { + .handler = emulate_rd12rn16rm0rs8_rwflags}, + [PROBES_DATA_PROCESSING_IMM] = { + .handler = emulate_rd12rn16rm0rs8_rwflags}, + [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc}, + [PROBES_SEV] = {.handler = kprobe_emulate_none}, + [PROBES_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc}, + [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc}, + [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, + [PROBES_MUL_ADD_LONG] = { + .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc}, + [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc}, + [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc}, + [PROBES_BRANCH] = {.handler = simulate_bbl}, + [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm} +}; diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index f02c038059c3..029b79c6face 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -112,7 +112,8 @@ emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs) } enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) +kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *h) { kprobe_insn_handler_t *handler = 0; unsigned reglist = insn & 0xffff; diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 977f21723a9c..d83f6092920a 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -16,6 +16,10 @@ #include "kprobes.h" #include "probes-thumb.h" +/* These emulation encodings are functionally equivalent... */ +#define t32_emulate_rd8rn16rm0ra12_noflags \ + t32_emulate_rdlo12rdhi8rn16rm0_noflags + /* * Return the PC value for a probe in thumb code. * This is the address of the probed instruction plus 4. @@ -29,7 +33,7 @@ static inline unsigned long __kprobes thumb_probe_pc(struct kprobe *p) /* t32 thumb actions */ -void __kprobes +static void __kprobes t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -49,7 +53,7 @@ t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + 2 * halfwords; } -void __kprobes +static void __kprobes t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -58,7 +62,7 @@ t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = regs->ARM_cpsr & mask; } -void __kprobes +static void __kprobes t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -73,8 +77,9 @@ t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -enum kprobe_insn __kprobes -t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { int cc = (insn >> 22) & 0xf; asi->insn_check_cc = kprobe_condition_checks[cc]; @@ -82,7 +87,7 @@ t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } -void __kprobes +static void __kprobes t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -110,7 +115,7 @@ t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -void __kprobes +static void __kprobes t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -148,10 +153,11 @@ t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = rtv; } -enum kprobe_insn __kprobes -t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { - enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi); + enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi, d); /* Fixup modified instruction to have halfwords in correct order...*/ insn = asi->insn[0]; @@ -161,7 +167,7 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) return ret; } -void __kprobes +static void __kprobes t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -188,7 +194,7 @@ t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt2] = rt2v; } -void __kprobes +static void __kprobes t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -214,7 +220,7 @@ t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = rtv; } -void __kprobes +static void __kprobes t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -241,7 +247,7 @@ t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -void __kprobes +static void __kprobes t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -261,7 +267,7 @@ t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -void __kprobes +static void __kprobes t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -281,7 +287,7 @@ t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) regs->uregs[rd] = rdv; } -void __kprobes +static void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -308,7 +314,7 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) } /* t16 thumb actions */ -void __kprobes +static void __kprobes t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -322,7 +328,7 @@ t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) bx_write_pc(rmv, regs); } -void __kprobes +static void __kprobes t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -332,7 +338,7 @@ t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = base[index]; } -void __kprobes +static void __kprobes t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -345,7 +351,7 @@ t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) base[index] = regs->uregs[rt]; } -void __kprobes +static void __kprobes t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -356,7 +362,7 @@ t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) regs->uregs[rt] = base + offset * 4; } -void __kprobes +static void __kprobes t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -367,7 +373,7 @@ t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) regs->ARM_sp += imm * 4; } -void __kprobes +static void __kprobes t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -381,7 +387,7 @@ t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) } } -void __kprobes +static void __kprobes t16_simulate_it(struct kprobe *p, struct pt_regs *regs) { /* @@ -398,21 +404,22 @@ t16_simulate_it(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = cpsr; } -void __kprobes +static void __kprobes t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) { regs->ARM_pc += 2; t16_simulate_it(p, regs); } -enum kprobe_insn __kprobes -t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { asi->insn_singlestep = t16_singlestep_it; return INSN_GOOD_NO_SLOT; } -void __kprobes +static void __kprobes t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -422,8 +429,9 @@ t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = pc + (offset * 2); } -enum kprobe_insn __kprobes -t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { int cc = (insn >> 8) & 0xf; asi->insn_check_cc = kprobe_condition_checks[cc]; @@ -431,7 +439,7 @@ t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD_NO_SLOT; } -void __kprobes +static void __kprobes t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -463,13 +471,13 @@ t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK); } -void __kprobes +static void __kprobes t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) { regs->ARM_cpsr = t16_emulate_loregs(p, regs); } -void __kprobes +static void __kprobes t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) { unsigned long cpsr = t16_emulate_loregs(p, regs); @@ -477,7 +485,7 @@ t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = cpsr; } -void __kprobes +static void __kprobes t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) { kprobe_opcode_t insn = p->opcode; @@ -508,8 +516,9 @@ t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -enum kprobe_insn __kprobes -t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { insn &= ~0x00ff; insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */ @@ -518,7 +527,7 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } -void __kprobes +static void __kprobes t16_emulate_push(struct kprobe *p, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -534,8 +543,9 @@ t16_emulate_push(struct kprobe *p, struct pt_regs *regs) ); } -enum kprobe_insn __kprobes -t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { /* * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}" @@ -548,7 +558,7 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) return INSN_GOOD; } -void __kprobes +static void __kprobes t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -564,7 +574,7 @@ t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) ); } -void __kprobes +static void __kprobes t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) { register unsigned long pc asm("r8"); @@ -584,8 +594,9 @@ t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) bx_write_pc(pc, regs); } -enum kprobe_insn __kprobes -t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) +static enum kprobe_insn __kprobes +t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *d) { /* * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}" @@ -598,3 +609,57 @@ t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) : t16_emulate_pop_nopc; return INSN_GOOD; } + +const union decode_action kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = { + [PROBES_T16_ADD_SP] = {.handler = t16_simulate_add_sp_imm}, + [PROBES_T16_CBZ] = {.handler = t16_simulate_cbz}, + [PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags}, + [PROBES_T16_PUSH] = {.decoder = t16_decode_push}, + [PROBES_T16_POP] = {.decoder = t16_decode_pop}, + [PROBES_T16_SEV] = {.handler = kprobe_emulate_none}, + [PROBES_T16_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_T16_IT] = {.decoder = t16_decode_it}, + [PROBES_T16_CMP] = {.handler = t16_emulate_loregs_rwflags}, + [PROBES_T16_ADDSUB] = {.handler = t16_emulate_loregs_noitrwflags}, + [PROBES_T16_LOGICAL] = {.handler = t16_emulate_loregs_noitrwflags}, + [PROBES_T16_LDR_LIT] = {.handler = t16_simulate_ldr_literal}, + [PROBES_T16_BLX] = {.handler = t16_simulate_bxblx}, + [PROBES_T16_HIREGOPS] = {.decoder = t16_decode_hiregs}, + [PROBES_T16_LDRHSTRH] = {.handler = t16_emulate_loregs_rwflags}, + [PROBES_T16_LDRSTR] = {.handler = t16_simulate_ldrstr_sp_relative}, + [PROBES_T16_ADR] = {.handler = t16_simulate_reladr}, + [PROBES_T16_LDMSTM] = {.handler = t16_emulate_loregs_rwflags}, + [PROBES_T16_BRANCH_COND] = {.decoder = t16_decode_cond_branch}, + [PROBES_T16_BRANCH] = {.handler = t16_simulate_branch}, +}; + +const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { + [PROBES_T32_LDMSTM] = {.decoder = t32_decode_ldmstm}, + [PROBES_T32_LDRDSTRD] = {.handler = t32_emulate_ldrdstrd}, + [PROBES_T32_TABLE_BRANCH] = {.handler = t32_simulate_table_branch}, + [PROBES_T32_TST] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_MOV] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_ADDSUB] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_LOGICAL] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_CMP] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_ADDWSUBW_PC] = {.handler = t32_emulate_rd8pc16_noflags,}, + [PROBES_T32_ADDWSUBW] = {.handler = t32_emulate_rd8rn16_noflags}, + [PROBES_T32_MOVW] = {.handler = t32_emulate_rd8rn16_noflags}, + [PROBES_T32_SAT] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_BITFIELD] = {.handler = t32_emulate_rd8rn16_noflags}, + [PROBES_T32_SEV] = {.handler = kprobe_emulate_none}, + [PROBES_T32_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_T32_MRS] = {.handler = t32_simulate_mrs}, + [PROBES_T32_BRANCH_COND] = {.decoder = t32_decode_cond_branch}, + [PROBES_T32_BRANCH] = {.handler = t32_simulate_branch}, + [PROBES_T32_PLDI] = {.handler = kprobe_simulate_nop}, + [PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal}, + [PROBES_T32_LDRSTR] = {.handler = t32_emulate_ldrstr}, + [PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_MEDIA] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_REVERSE] = {.handler = t32_emulate_rd8rn16_noflags}, + [PROBES_T32_MUL_ADD] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, + [PROBES_T32_MUL_ADD2] = {.handler = t32_emulate_rd8rn16rm0ra12_noflags}, + [PROBES_T32_MUL_ADD_LONG] = { + .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags}, +}; diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 54e7b46a3295..a757c3c22381 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -56,6 +56,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) unsigned long addr = (unsigned long)p->addr; bool thumb; kprobe_decode_insn_t *decode_insn; + const union decode_action *actions; int is; if (in_exception_text(addr)) @@ -69,20 +70,24 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) insn <<= 16; insn |= ((u16 *)addr)[1]; decode_insn = thumb32_kprobe_decode_insn; - } else + actions = kprobes_t32_actions; + } else { decode_insn = thumb16_kprobe_decode_insn; + actions = kprobes_t16_actions; + } #else /* !CONFIG_THUMB2_KERNEL */ thumb = false; if (addr & 0x3) return -EINVAL; insn = *p->addr; decode_insn = arm_kprobe_decode_insn; + actions = kprobes_arm_actions; #endif p->opcode = insn; p->ainsn.insn = tmp_insn; - switch ((*decode_insn)(insn, &p->ainsn)) { + switch ((*decode_insn)(insn, &p->ainsn, actions)) { case INSN_REJECTED: /* not supported */ return -EINVAL; diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index aa68c0ea1a0b..7798035d6003 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -27,6 +27,8 @@ #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 +struct decode_header; +union decode_action; enum kprobe_insn { INSN_REJECTED, @@ -35,19 +37,24 @@ enum kprobe_insn { }; typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t, - struct arch_specific_insn *); + struct arch_specific_insn *, + const union decode_action *); #ifdef CONFIG_THUMB2_KERNEL enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t, - struct arch_specific_insn *); + struct arch_specific_insn *, + const union decode_action *); enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t, - struct arch_specific_insn *); + struct arch_specific_insn *, + const union decode_action *); #else /* !CONFIG_THUMB2_KERNEL */ enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, - struct arch_specific_insn *); + struct arch_specific_insn *, + const union decode_action *); + #endif void __init arm_kprobe_decode_init(void); diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 57e08b28e87f..496e0e913fa6 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -126,16 +126,16 @@ static const union decode_item arm_1111_table[] = { /* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */ /* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */ /* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop), + DECODE_SIMULATE (0xfe300000, 0xf4100000, PROBES_PRELOAD_IMM), /* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */ /* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */ /* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */ /* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */ - DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop), + DECODE_SIMULATE (0xfe300010, 0xf6100000, PROBES_PRELOAD_REG), /* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1), + DECODE_SIMULATE (0xfe000000, 0xfa000000, PROBES_BRANCH_IMM), /* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ /* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ @@ -159,25 +159,25 @@ static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = { /* Miscellaneous instructions */ /* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ - DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs, + DECODE_SIMULATEX(0x0ff000f0, 0x01000000, PROBES_MRS, REGS(0, NOPC, 0, 0, 0)), /* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ - DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx), + DECODE_SIMULATE (0x0ff000f0, 0x01200010, PROBES_BRANCH_REG), /* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ - DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx, + DECODE_SIMULATEX(0x0ff000f0, 0x01200030, PROBES_BRANCH_REG, REGS(0, 0, 0, 0, NOPC)), /* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0ff000f0, 0x01600010, PROBES_CLZ, REGS(0, NOPC, 0, 0, NOPC)), /* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */ /* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */ /* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */ /* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */ - DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0f9000f0, 0x01000050, PROBES_SATURATING_ARITHMETIC, REGS(NOPC, NOPC, 0, 0, NOPC)), /* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ @@ -193,19 +193,19 @@ static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = { /* Halfword multiply and multiply-accumulate */ /* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + DECODE_EMULATEX (0x0ff00090, 0x01400080, PROBES_MUL1, REGS(NOPC, NOPC, NOPC, 0, NOPC)), /* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ DECODE_OR (0x0ff000b0, 0x012000a0), /* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff00090, 0x01600080, PROBES_MUL2, REGS(NOPC, 0, NOPC, 0, NOPC)), /* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */ DECODE_OR (0x0ff00090, 0x01000080), /* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */ - DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff000b0, 0x01200080, PROBES_MUL2, REGS(NOPC, NOPC, NOPC, 0, NOPC)), DECODE_END @@ -216,14 +216,14 @@ static const union decode_item arm_cccc_0000_____1001_table[] = { /* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */ /* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0fe000f0, 0x00000090, PROBES_MUL2, REGS(NOPC, 0, NOPC, 0, NOPC)), /* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */ /* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */ DECODE_OR (0x0fe000f0, 0x00200090), /* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff000f0, 0x00600090, PROBES_MUL2, REGS(NOPC, NOPC, NOPC, 0, NOPC)), /* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */ @@ -236,7 +236,7 @@ static const union decode_item arm_cccc_0000_____1001_table[] = { /* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */ /* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */ /* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + DECODE_EMULATEX (0x0f8000f0, 0x00800090, PROBES_MUL1, REGS(NOPC, NOPC, NOPC, 0, NOPC)), DECODE_END @@ -248,7 +248,7 @@ static const union decode_item arm_cccc_0001_____1001_table[] = { #if __LINUX_ARM_ARCH__ < 6 /* Deprecated on ARMv6 and may be UNDEFINED on v7 */ /* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */ - DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0fb000f0, 0x01000090, PROBES_SWP, REGS(NOPC, NOPC, 0, 0, NOPC)), #endif /* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */ @@ -271,32 +271,32 @@ static const union decode_item arm_cccc_000x_____1xx1_table[] = { /* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */ /* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd, + DECODE_EMULATEX (0x0e5000d0, 0x000000d0, PROBES_LDRSTRD, REGS(NOPCWB, NOPCX, 0, 0, NOPC)), /* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */ /* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd, + DECODE_EMULATEX (0x0e5000d0, 0x004000d0, PROBES_LDRSTRD, REGS(NOPCWB, NOPCX, 0, 0, 0)), /* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str, + DECODE_EMULATEX (0x0e5000f0, 0x000000b0, PROBES_STORE_EXTRA, REGS(NOPCWB, NOPC, 0, 0, NOPC)), /* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */ /* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */ /* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr, + DECODE_EMULATEX (0x0e500090, 0x00100090, PROBES_LOAD_EXTRA, REGS(NOPCWB, NOPC, 0, 0, NOPC)), /* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str, + DECODE_EMULATEX (0x0e5000f0, 0x004000b0, PROBES_STORE_EXTRA, REGS(NOPCWB, NOPC, 0, 0, 0)), /* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */ /* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */ /* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr, + DECODE_EMULATEX (0x0e500090, 0x00500090, PROBES_LOAD_EXTRA, REGS(NOPCWB, NOPC, 0, 0, 0)), DECODE_END @@ -309,18 +309,18 @@ static const union decode_item arm_cccc_000x_table[] = { DECODE_REJECT (0x0e10f000, 0x0010f000), /* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */ - DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp), + DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, PROBES_MOV_IP_SP), /* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */ /* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */ /* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */ /* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0f900010, 0x01100000, PROBES_DATA_PROCESSING_REG, REGS(ANY, 0, 0, 0, ANY)), /* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */ /* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0fa00010, 0x01a00000, PROBES_DATA_PROCESSING_REG, REGS(0, ANY, 0, 0, ANY)), /* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */ @@ -333,19 +333,19 @@ static const union decode_item arm_cccc_000x_table[] = { /* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */ /* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */ /* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */ - DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0e000010, 0x00000000, PROBES_DATA_PROCESSING_REG, REGS(ANY, ANY, 0, 0, ANY)), /* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */ /* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */ /* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */ /* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0f900090, 0x01100010, PROBES_DATA_PROCESSING_REG, REGS(ANY, 0, NOPC, 0, ANY)), /* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */ /* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0fa00090, 0x01a00010, PROBES_DATA_PROCESSING_REG, REGS(0, ANY, NOPC, 0, ANY)), /* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */ @@ -358,7 +358,7 @@ static const union decode_item arm_cccc_000x_table[] = { /* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */ /* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */ /* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */ - DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG, REGS(ANY, ANY, NOPC, 0, ANY)), DECODE_END @@ -369,17 +369,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, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0fb00000, 0x03000000, PROBES_DATA_PROCESSING_IMM, 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, kprobe_emulate_none), + DECODE_EMULATE (0x0fff00ff, 0x03200004, PROBES_EMULATE_NONE), /* 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, kprobe_simulate_nop), + DECODE_SIMULATE (0x0fff00fc, 0x03200000, PROBES_SIMULATE_NOP), /* 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 */ @@ -392,12 +392,12 @@ static const union decode_item arm_cccc_001x_table[] = { /* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */ /* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */ /* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0f900000, 0x03100000, PROBES_DATA_PROCESSING_IMM, REGS(ANY, 0, 0, 0, 0)), /* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */ /* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0fa00000, 0x03a00000, PROBES_DATA_PROCESSING_IMM, REGS(0, ANY, 0, 0, 0)), /* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */ @@ -410,7 +410,7 @@ static const union decode_item arm_cccc_001x_table[] = { /* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */ /* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */ /* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags, + DECODE_EMULATEX (0x0e000000, 0x02000000, PROBES_DATA_PROCESSING_IMM, REGS(ANY, ANY, 0, 0, 0)), DECODE_END @@ -420,7 +420,7 @@ static const union decode_item arm_cccc_0110_____xxx1_table[] = { /* Media instructions */ /* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0ff000f0, 0x068000b0, PROBES_SATURATE, REGS(NOPC, NOPC, 0, 0, NOPC)), /* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */ @@ -428,14 +428,14 @@ static const union decode_item arm_cccc_0110_____xxx1_table[] = { DECODE_OR(0x0fa00030, 0x06a00010), /* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */ /* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */ - DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0fb000f0, 0x06a00030, PROBES_SATURATE, REGS(0, NOPC, 0, 0, NOPC)), /* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ /* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ /* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ /* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ - DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0fb00070, 0x06b00030, PROBES_REV, REGS(0, NOPC, 0, 0, NOPC)), /* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */ @@ -480,12 +480,12 @@ static const union decode_item arm_cccc_0110_____xxx1_table[] = { /* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */ /* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */ /* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */ - DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0f800010, 0x06000010, PROBES_MMI, REGS(NOPC, NOPC, 0, 0, NOPC)), /* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */ /* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */ - DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0ff00030, 0x06800010, PROBES_PACK, REGS(NOPC, NOPC, 0, 0, NOPC)), /* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */ @@ -498,7 +498,7 @@ static const union decode_item arm_cccc_0110_____xxx1_table[] = { /* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */ /* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */ /* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */ - DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, PROBES_EXTEND, REGS(0, NOPC, 0, 0, NOPC)), /* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */ @@ -507,7 +507,7 @@ static const union decode_item arm_cccc_0110_____xxx1_table[] = { /* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */ /* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */ /* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */ - DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc, + DECODE_EMULATEX (0x0f8000f0, 0x06800070, PROBES_EXTEND_ADD, REGS(NOPCX, NOPC, 0, 0, NOPC)), DECODE_END @@ -521,7 +521,7 @@ static const union decode_item arm_cccc_0111_____xxx1_table[] = { /* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ /* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ - DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, + DECODE_EMULATEX (0x0ff00090, 0x07400010, PROBES_MUL_ADD_LONG, REGS(NOPC, NOPC, NOPC, 0, NOPC)), /* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */ @@ -530,7 +530,7 @@ static const union decode_item arm_cccc_0111_____xxx1_table[] = { /* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */ DECODE_OR (0x0ff0f0d0, 0x0750f010), /* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, PROBES_MUL_ADD, REGS(NOPC, 0, NOPC, 0, NOPC)), /* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */ @@ -539,24 +539,24 @@ static const union decode_item arm_cccc_0111_____xxx1_table[] = { /* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */ DECODE_OR (0x0ff000d0, 0x07500010), /* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ - DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff000f0, 0x07800010, PROBES_MUL_ADD, REGS(NOPC, NOPCX, NOPC, 0, NOPC)), /* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */ - DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc, + DECODE_EMULATEX (0x0ff000d0, 0x075000d0, PROBES_MUL_ADD, REGS(NOPC, NOPC, NOPC, 0, NOPC)), /* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */ /* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */ - DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0fa00070, 0x07a00050, PROBES_BITFIELD, REGS(0, NOPC, 0, 0, NOPC)), /* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */ - DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, PROBES_BITFIELD, REGS(0, NOPC, 0, 0, 0)), /* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */ - DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc, + DECODE_EMULATEX (0x0fe00070, 0x07c00010, PROBES_BITFIELD, REGS(0, NOPC, 0, 0, NOPCX)), DECODE_END @@ -576,22 +576,22 @@ static const union decode_item arm_cccc_01xx_table[] = { /* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */ /* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str, + DECODE_EMULATEX (0x0e100000, 0x04000000, PROBES_STORE, REGS(NOPCWB, ANY, 0, 0, 0)), /* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */ /* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr, + DECODE_EMULATEX (0x0e100000, 0x04100000, PROBES_LOAD, REGS(NOPCWB, ANY, 0, 0, 0)), /* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */ /* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str, + DECODE_EMULATEX (0x0e100000, 0x06000000, PROBES_STORE, REGS(NOPCWB, ANY, 0, 0, NOPC)), /* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */ /* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr, + DECODE_EMULATEX (0x0e100000, 0x06100000, PROBES_LOAD, REGS(NOPCWB, ANY, 0, 0, NOPC)), DECODE_END @@ -602,7 +602,7 @@ static const union decode_item arm_cccc_100x_table[] = { /* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ /* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ - DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm), + DECODE_CUSTOM (0x0e400000, 0x08000000, PROBES_LDMSTM), /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */ @@ -682,7 +682,7 @@ const union decode_item kprobe_decode_arm_table[] = { /* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ /* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ - DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl), + DECODE_SIMULATE (0x0e000000, 0x0a000000, PROBES_BRANCH), /* * Supervisor Call, and coprocessor instructions @@ -723,9 +723,11 @@ static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) * should also be very rare. */ enum kprobe_insn __kprobes -arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const union decode_action *actions) { asi->insn_singlestep = arm_singlestep; asi->insn_check_cc = kprobe_condition_checks[insn>>28]; - return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false); + return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false, + actions); } diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index 86084727d36d..ef3089419a0b 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -15,24 +15,48 @@ #ifndef _ARM_KERNEL_PROBES_ARM_H #define _ARM_KERNEL_PROBES_ARM_H +enum probes_arm_action { + PROBES_EMULATE_NONE, + PROBES_SIMULATE_NOP, + PROBES_PRELOAD_IMM, + PROBES_PRELOAD_REG, + PROBES_BRANCH_IMM, + PROBES_BRANCH_REG, + PROBES_MRS, + PROBES_CLZ, + PROBES_SATURATING_ARITHMETIC, + PROBES_MUL1, + PROBES_MUL2, + PROBES_SWP, + PROBES_LDRSTRD, + PROBES_LOAD, + PROBES_STORE, + PROBES_LOAD_EXTRA, + PROBES_STORE_EXTRA, + PROBES_MOV_IP_SP, + PROBES_DATA_PROCESSING_REG, + PROBES_DATA_PROCESSING_IMM, + PROBES_MOV_HALFWORD, + PROBES_SEV, + PROBES_WFE, + PROBES_SATURATE, + PROBES_REV, + PROBES_MMI, + PROBES_PACK, + PROBES_EXTEND, + PROBES_EXTEND_ADD, + PROBES_MUL_ADD_LONG, + PROBES_MUL_ADD, + PROBES_BITFIELD, + PROBES_BRANCH, + PROBES_LDMSTM, + NUM_PROBES_ARM_ACTIONS +}; + void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs); void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs); void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs); void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs); void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs); -void __kprobes emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs); -void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs); -void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs); -void __kprobes emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, - struct pt_regs *regs); -void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, - struct pt_regs *regs); -void __kprobes emulate_rd12rm0_noflags_nopc(struct kprobe *p, - struct pt_regs *regs); -void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, - struct pt_regs *regs); - #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index a1f24777a41a..2abe8ceeb670 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -16,9 +16,6 @@ #include "kprobes.h" #include "probes-thumb.h" -/* These emulation encodings are functionally equivalent... */ -#define t32_emulate_rd8rn16rm0ra12_noflags \ - t32_emulate_rdlo12rdhi8rn16rm0_noflags static const union decode_item t32_table_1110_100x_x0xx[] = { /* Load/store multiple instructions */ @@ -44,7 +41,7 @@ static const union decode_item t32_table_1110_100x_x0xx[] = { /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), + DECODE_CUSTOM (0xfe400000, 0xe8000000, PROBES_T32_LDMSTM), DECODE_END }; @@ -57,12 +54,12 @@ static const union decode_item t32_table_1110_100x_x1xx[] = { DECODE_OR (0xff600000, 0xe8600000), /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, + DECODE_EMULATEX (0xff400000, 0xe9400000, PROBES_T32_LDRDSTRD, REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ - DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, + DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, PROBES_T32_TABLE_BRANCH, REGS(NOSP, 0, 0, 0, NOSPPC)), /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ @@ -82,18 +79,18 @@ static const union decode_item t32_table_1110_101x[] = { /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff700f00, 0xea100f00, PROBES_T32_TST, REGS(NOSPPC, 0, 0, 0, NOSPPC)), /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ DECODE_OR (0xfff00f00, 0xeb100f00), /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfff00f00, 0xebb00f00, PROBES_T32_TST, REGS(NOPC, 0, 0, 0, NOSPPC)), /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xffcf0000, 0xea4f0000, PROBES_T32_MOV, REGS(0, 0, NOSPPC, 0, NOSPPC)), /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ @@ -108,7 +105,7 @@ static const union decode_item t32_table_1110_101x[] = { /* ADD/SUB SP, SP, Rm, LSL #0..3 */ /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ - DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, PROBES_T32_ADDSUB, REGS(SP, 0, SP, 0, NOSPPC)), /* ADD/SUB SP, SP, Rm, shift */ @@ -117,7 +114,7 @@ static const union decode_item t32_table_1110_101x[] = { /* ADD/SUB Rd, SP, Rm, shift */ /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, PROBES_T32_ADDSUB, REGS(SP, 0, NOPC, 0, NOSPPC)), /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ @@ -131,7 +128,7 @@ static const union decode_item t32_table_1110_101x[] = { /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfe000000, 0xea000000, PROBES_T32_LOGICAL, REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), DECODE_END @@ -142,18 +139,18 @@ static const union decode_item t32_table_1111_0x0x___0[] = { /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfb708f00, 0xf0100f00, PROBES_T32_TST, REGS(NOSPPC, 0, 0, 0, 0)), /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ DECODE_OR (0xfbf08f00, 0xf1100f00), /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ - DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, PROBES_T32_CMP, REGS(NOPC, 0, 0, 0, 0)), /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, PROBES_T32_MOV, REGS(0, 0, NOSPPC, 0, 0)), /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ @@ -170,7 +167,7 @@ static const union decode_item t32_table_1111_0x0x___0[] = { /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, PROBES_T32_ADDSUB, REGS(SP, 0, NOPC, 0, 0)), /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ @@ -183,7 +180,7 @@ static const union decode_item t32_table_1111_0x0x___0[] = { /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfa008000, 0xf0000000, PROBES_T32_LOGICAL, REGS(NOSPPC, 0, NOSPPC, 0, 0)), DECODE_END @@ -195,44 +192,44 @@ static const union decode_item t32_table_1111_0x1x___0[] = { /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ DECODE_OR (0xfbff8000, 0xf20f0000), /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, + DECODE_EMULATEX (0xfbff8000, 0xf2af0000, PROBES_T32_ADDWSUBW_PC, REGS(PC, 0, NOSPPC, 0, 0)), /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ DECODE_OR (0xfbff8f00, 0xf20d0d00), /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ - DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, PROBES_T32_ADDWSUBW, REGS(SP, 0, SP, 0, 0)), /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ DECODE_OR (0xfbf08000, 0xf2000000), /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfbf08000, 0xf2a00000, PROBES_T32_ADDWSUBW, REGS(NOPCX, 0, NOSPPC, 0, 0)), /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfb708000, 0xf2400000, PROBES_T32_MOVW, REGS(0, 0, NOSPPC, 0, 0)), /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xfb508000, 0xf3000000, PROBES_T32_SAT, REGS(NOSPPC, 0, NOSPPC, 0, 0)), /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfb708000, 0xf3400000, PROBES_T32_BITFIELD, REGS(NOSPPC, 0, NOSPPC, 0, 0)), /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfbff8000, 0xf36f0000, PROBES_T32_BITFIELD, REGS(0, 0, NOSPPC, 0, 0)), /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfbf08000, 0xf3600000, PROBES_T32_BITFIELD, REGS(NOSPPCX, 0, NOSPPC, 0, 0)), DECODE_END @@ -244,14 +241,14 @@ static const union decode_item t32_table_1111_0xxx___1[] = { /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ DECODE_OR (0xfff0d7ff, 0xf3a08001), /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ - DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), + DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, PROBES_T32_SEV), /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ - DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), + DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, PROBES_T32_WFE), /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, + DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, PROBES_T32_MRS, REGS(0, 0, NOSPPC, 0, 0)), /* @@ -273,13 +270,13 @@ static const union decode_item t32_table_1111_0xxx___1[] = { DECODE_REJECT (0xfb80d000, 0xf3808000), /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ - DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), + DECODE_CUSTOM (0xf800d000, 0xf0008000, PROBES_T32_BRANCH_COND), /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ DECODE_OR (0xf800d001, 0xf000c000), /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ - DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), + DECODE_SIMULATE (0xf8009000, 0xf0009000, PROBES_T32_BRANCH), DECODE_END }; @@ -289,7 +286,7 @@ static const union decode_item t32_table_1111_100x_x0x1__1111[] = { /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ - DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), + DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, PROBES_T32_PLDI), /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ DECODE_OR (0xffd0f000, 0xf890f000), @@ -298,13 +295,13 @@ static const union decode_item t32_table_1111_100x_x0x1__1111[] = { /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ DECODE_OR (0xfff0f000, 0xf990f000), /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ - DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, + DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, PROBES_T32_PLDI, REGS(NOPCX, 0, 0, 0, 0)), /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ DECODE_OR (0xffd0ffc0, 0xf810f000), /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ - DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, + DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, PROBES_T32_PLDI, REGS(NOPCX, 0, 0, 0, NOSPPC)), /* Other unallocated instructions... */ @@ -340,7 +337,7 @@ static const union decode_item t32_table_1111_100x[] = { DECODE_REJECT (0xff10f000, 0xf800f000), /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, + DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, PROBES_T32_LDR_LIT, REGS(PC, ANY, 0, 0, 0)), /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ @@ -348,19 +345,19 @@ static const union decode_item t32_table_1111_100x[] = { DECODE_OR (0xffe00800, 0xf8400800), /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, + DECODE_EMULATEX (0xffe00000, 0xf8c00000, PROBES_T32_LDRSTR, REGS(NOPCX, ANY, 0, 0, 0)), /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ - DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, + DECODE_EMULATEX (0xffe00fc0, 0xf8400000, PROBES_T32_LDRSTR, REGS(NOPCX, ANY, 0, 0, NOSPPC)), /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ - DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, + DECODE_SIMULATEX(0xfe5f0000, 0xf81f0000, PROBES_T32_LDR_LIT, REGS(PC, NOSPPCX, 0, 0, 0)), /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ @@ -376,7 +373,7 @@ static const union decode_item t32_table_1111_100x[] = { /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ - DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, + DECODE_EMULATEX (0xfec00000, 0xf8800000, PROBES_T32_LDRSTR, REGS(NOPCX, NOSPPCX, 0, 0, 0)), /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ @@ -385,7 +382,7 @@ static const union decode_item t32_table_1111_100x[] = { /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ - DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, + DECODE_EMULATEX (0xfe800fc0, 0xf8000000, PROBES_T32_LDRSTR, REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), /* Other unallocated instructions... */ @@ -404,7 +401,7 @@ static const union decode_item t32_table_1111_1010___1111[] = { /* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */ /* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */ /* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */ - DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, PROBES_T32_SIGN_EXTEND, REGS(0, 0, NOSPPC, 0, NOSPPC)), @@ -477,7 +474,7 @@ static const union decode_item t32_table_1111_1010___1111[] = { /* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */ /* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */ /* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, PROBES_T32_MEDIA, REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), /* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ @@ -487,7 +484,7 @@ static const union decode_item t32_table_1111_1010___1111[] = { /* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */ /* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */ /* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */ - DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, t32_emulate_rd8rn16_noflags, + DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, PROBES_T32_REVERSE, REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)), /* Other unallocated instructions... */ @@ -510,7 +507,7 @@ static const union decode_item t32_table_1111_1011_0[] = { /* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */ /* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */ /* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, t32_emulate_rd8rn16rm0_rwflags, + DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, PROBES_T32_MUL_ADD, REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), /* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */ @@ -526,7 +523,7 @@ static const union decode_item t32_table_1111_1011_0[] = { /* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */ /* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */ /* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff8000c0, 0xfb000000, t32_emulate_rd8rn16rm0ra12_noflags, + DECODE_EMULATEX (0xff8000c0, 0xfb000000, PROBES_T32_MUL_ADD2, REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)), /* Other unallocated instructions... */ @@ -547,7 +544,7 @@ static const union decode_item t32_table_1111_1011_1[] = { /* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */ /* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */ /* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */ - DECODE_EMULATEX (0xff9000f0, 0xfb800000, t32_emulate_rdlo12rdhi8rn16rm0_noflags, + DECODE_EMULATEX (0xff9000f0, 0xfb800000, PROBES_T32_MUL_ADD_LONG, REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)), /* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */ @@ -653,11 +650,11 @@ static const union decode_item t16_table_1011[] = { /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ - DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), + DECODE_SIMULATE (0xff00, 0xb000, PROBES_T16_ADD_SP), /* CBZ 1011 00x1 xxxx xxxx */ /* CBNZ 1011 10x1 xxxx xxxx */ - DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), + DECODE_SIMULATE (0xf500, 0xb100, PROBES_T16_CBZ), /* SXTH 1011 0010 00xx xxxx */ /* SXTB 1011 0010 01xx xxxx */ @@ -668,12 +665,12 @@ static const union decode_item t16_table_1011[] = { /* ??? 1011 1010 10xx xxxx */ /* REVSH 1011 1010 11xx xxxx */ DECODE_REJECT (0xffc0, 0xba80), - DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xf500, 0xb000, PROBES_T16_SIGN_EXTEND), /* PUSH 1011 010x xxxx xxxx */ - DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), + DECODE_CUSTOM (0xfe00, 0xb400, PROBES_T16_PUSH), /* POP 1011 110x xxxx xxxx */ - DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), + DECODE_CUSTOM (0xfe00, 0xbc00, PROBES_T16_POP), /* * If-Then, and hints @@ -683,15 +680,15 @@ static const union decode_item t16_table_1011[] = { /* YIELD 1011 1111 0001 0000 */ DECODE_OR (0xffff, 0xbf10), /* SEV 1011 1111 0100 0000 */ - DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), + DECODE_EMULATE (0xffff, 0xbf40, PROBES_T16_SEV), /* NOP 1011 1111 0000 0000 */ /* WFE 1011 1111 0010 0000 */ /* WFI 1011 1111 0011 0000 */ - DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), + DECODE_SIMULATE (0xffcf, 0xbf00, PROBES_T16_WFE), /* Unassigned hints 1011 1111 xxxx 0000 */ DECODE_REJECT (0xff0f, 0xbf00), /* IT 1011 1111 xxxx xxxx */ - DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), + DECODE_CUSTOM (0xff00, 0xbf00, PROBES_T16_IT), /* SETEND 1011 0110 010x xxxx */ /* CPS 1011 0110 011x xxxx */ @@ -708,7 +705,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { */ /* CMP (immediate) 0010 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xf800, 0x2800, PROBES_T16_CMP), /* ADD (register) 0001 100x xxxx xxxx */ /* SUB (register) 0001 101x xxxx xxxx */ @@ -720,7 +717,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* MOV (immediate) 0010 0xxx xxxx xxxx */ /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ - DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), + DECODE_EMULATE (0xc000, 0x0000, PROBES_T16_ADDSUB), /* * 16-bit Thumb data-processing instructions @@ -728,10 +725,10 @@ const union decode_item kprobe_decode_thumb16_table[] = { */ /* TST (register) 0100 0010 00xx xxxx */ - DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xffc0, 0x4200, PROBES_T16_CMP), /* CMP (register) 0100 0010 10xx xxxx */ /* CMN (register) 0100 0010 11xx xxxx */ - DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xff80, 0x4280, PROBES_T16_CMP), /* AND (register) 0100 0000 00xx xxxx */ /* EOR (register) 0100 0000 01xx xxxx */ /* LSL (register) 0100 0000 10xx xxxx */ @@ -745,7 +742,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* MUL 0100 0011 00xx xxxx */ /* BIC (register) 0100 0011 10xx xxxx */ /* MVN (register) 0100 0011 10xx xxxx */ - DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), + DECODE_EMULATE (0xfc00, 0x4000, PROBES_T16_LOGICAL), /* * Special data instructions and branch and exchange @@ -757,7 +754,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* BX (register) 0100 0111 0xxx xxxx */ /* BLX (register) 0100 0111 1xxx xxxx */ - DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), + DECODE_SIMULATE (0xff00, 0x4700, PROBES_T16_BLX), /* ADD pc, pc 0100 0100 1111 1111 */ DECODE_REJECT (0xffff, 0x44ff), @@ -765,13 +762,13 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* ADD (register) 0100 0100 xxxx xxxx */ /* CMP (register) 0100 0101 xxxx xxxx */ /* MOV (register) 0100 0110 xxxx xxxx */ - DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), + DECODE_CUSTOM (0xfc00, 0x4400, PROBES_T16_HIREGOPS), /* * Load from Literal Pool * LDR (literal) 0100 1xxx xxxx xxxx */ - DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), + DECODE_SIMULATE (0xf800, 0x4800, PROBES_T16_LDR_LIT), /* * 16-bit Thumb Load/store instructions @@ -792,20 +789,20 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ - DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xc000, 0x4000, PROBES_T16_LDRHSTRH), /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xf000, 0x8000, PROBES_T16_LDRHSTRH), /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ - DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), + DECODE_SIMULATE (0xf000, 0x9000, PROBES_T16_LDRSTR), /* * Generate PC-/SP-relative address * ADR (literal) 1010 0xxx xxxx xxxx * ADD (SP plus immediate) 1010 1xxx xxxx xxxx */ - DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), + DECODE_SIMULATE (0xf000, 0xa000, PROBES_T16_ADR), /* * Miscellaneous 16-bit instructions @@ -815,7 +812,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { /* STM 1100 0xxx xxxx xxxx */ /* LDM 1100 1xxx xxxx xxxx */ - DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), + DECODE_EMULATE (0xf000, 0xc000, PROBES_T16_LDMSTM), /* * Conditional branch, and Supervisor Call @@ -826,13 +823,13 @@ const union decode_item kprobe_decode_thumb16_table[] = { DECODE_REJECT (0xfe00, 0xde00), /* Conditional branch 1101 xxxx xxxx xxxx */ - DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), + DECODE_CUSTOM (0xf000, 0xd000, PROBES_T16_BRANCH_COND), /* * Unconditional branch * B 1110 0xxx xxxx xxxx */ - DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), + DECODE_SIMULATE (0xf800, 0xe000, PROBES_T16_BRANCH), DECODE_END }; @@ -862,17 +859,21 @@ static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) } enum kprobe_insn __kprobes -thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const union decode_action *actions) { asi->insn_singlestep = thumb16_singlestep; asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); + return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true, + actions); } enum kprobe_insn __kprobes -thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) +thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const union decode_action *actions) { asi->insn_singlestep = thumb32_singlestep; asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); + return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true, + actions); } diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h index 98709c40b659..8d6b4eefa706 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/kernel/probes-thumb.h @@ -27,55 +27,61 @@ */ #define current_cond(cpsr) ((cpsr >> 12) & 0xf) -void __kprobes t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_simulate_ldrstr_sp_relative(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_simulate_it(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_singlestep_it(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t16_decode_it(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t16_decode_cond_branch(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t16_simulate_branch(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_emulate_loregs_rwflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t16_emulate_loregs_noitrwflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t16_decode_hiregs(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t16_emulate_push(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t16_decode_push(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs); -void __kprobes t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t16_decode_pop(kprobe_opcode_t insn, - struct arch_specific_insn *asi); +enum probes_t32_action { + PROBES_T32_EMULATE_NONE, + PROBES_T32_SIMULATE_NOP, + PROBES_T32_LDMSTM, + PROBES_T32_LDRDSTRD, + PROBES_T32_TABLE_BRANCH, + PROBES_T32_TST, + PROBES_T32_CMP, + PROBES_T32_MOV, + PROBES_T32_ADDSUB, + PROBES_T32_LOGICAL, + PROBES_T32_ADDWSUBW_PC, + PROBES_T32_ADDWSUBW, + PROBES_T32_MOVW, + PROBES_T32_SAT, + PROBES_T32_BITFIELD, + PROBES_T32_SEV, + PROBES_T32_WFE, + PROBES_T32_MRS, + PROBES_T32_BRANCH_COND, + PROBES_T32_BRANCH, + PROBES_T32_PLDI, + PROBES_T32_LDR_LIT, + PROBES_T32_LDRSTR, + PROBES_T32_SIGN_EXTEND, + PROBES_T32_MEDIA, + PROBES_T32_REVERSE, + PROBES_T32_MUL_ADD, + PROBES_T32_MUL_ADD2, + PROBES_T32_MUL_ADD_LONG, + NUM_PROBES_T32_ACTIONS +}; -void __kprobes t32_simulate_table_branch(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs); -void __kprobes t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t32_decode_cond_branch(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t32_simulate_branch(struct kprobe *p, struct pt_regs *regs); -void __kprobes t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs); -enum kprobe_insn __kprobes t32_decode_ldmstm(kprobe_opcode_t insn, - struct arch_specific_insn *asi); -void __kprobes t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs); -void __kprobes t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs); -void __kprobes t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t32_emulate_rd8pc16_noflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t32_emulate_rd8rn16_noflags(struct kprobe *p, - struct pt_regs *regs); -void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, - struct pt_regs *regs); +enum probes_t16_action { + PROBES_T16_ADD_SP, + PROBES_T16_CBZ, + PROBES_T16_SIGN_EXTEND, + PROBES_T16_PUSH, + PROBES_T16_POP, + PROBES_T16_SEV, + PROBES_T16_WFE, + PROBES_T16_IT, + PROBES_T16_CMP, + PROBES_T16_ADDSUB, + PROBES_T16_LOGICAL, + PROBES_T16_BLX, + PROBES_T16_HIREGOPS, + PROBES_T16_LDR_LIT, + PROBES_T16_LDRHSTRH, + PROBES_T16_LDRSTR, + PROBES_T16_ADR, + PROBES_T16_LDMSTM, + PROBES_T16_BRANCH_COND, + PROBES_T16_BRANCH, + NUM_PROBES_T16_ACTIONS +}; #endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index 3a63f8f83cf8..efd92c5b4a52 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -381,7 +381,8 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { */ int __kprobes kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb) + const union decode_item *table, bool thumb, + const union decode_action *actions) { const struct decode_header *h = (struct decode_header *)table; const struct decode_header *next; @@ -415,18 +416,18 @@ kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, case DECODE_TYPE_CUSTOM: { struct decode_custom *d = (struct decode_custom *)h; - return (*d->decoder.decoder)(insn, asi); + return actions[d->decoder.action].decoder(insn, asi, h); } case DECODE_TYPE_SIMULATE: { struct decode_simulate *d = (struct decode_simulate *)h; - asi->insn_handler = d->handler.handler; + asi->insn_handler = actions[d->handler.action].handler; return INSN_GOOD_NO_SLOT; } case DECODE_TYPE_EMULATE: { struct decode_emulate *d = (struct decode_emulate *)h; - asi->insn_handler = d->handler.handler; + asi->insn_handler = actions[d->handler.action].handler; set_emulated_insn(insn, asi, thumb); return INSN_GOOD; } diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 17f656011aa3..5554f161bdac 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -133,7 +133,8 @@ void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); +kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *h); /* * Test if load/store instructions writeback the address register. @@ -160,7 +161,7 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); * {.bits = _type}, * {.bits = _mask}, * {.bits = _value}, - * {.handler = _handler}, + * {.action = _handler}, * * Initialising a specified member of the union means that the compiler * will produce a warning if the argument is of an incorrect type. @@ -173,19 +174,23 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); * Instruction decoding jumps to parsing the new sub-table 'table'. * * DECODE_CUSTOM(mask, value, decoder) - * The custom function 'decoder' is called to the complete decoding - * of an instruction. + * The value of 'decoder' is used as an index into the array of + * action functions, and the retrieved decoder function is invoked + * to complete decoding of the instruction. * * DECODE_SIMULATE(mask, value, handler) - * Set the probes instruction handler to 'handler', this will be used - * to simulate the instruction when the probe is hit. Decoding returns - * with INSN_GOOD_NO_SLOT. + * The probes instruction handler is set to the value found by + * indexing into the action array using the value of 'handler'. This + * will be used to simulate the instruction when the probe is hit. + * Decoding returns with INSN_GOOD_NO_SLOT. * * DECODE_EMULATE(mask, value, handler) - * Set the probes instruction handler to 'handler', this will be used - * to emulate the instruction when the probe is hit. The modified - * instruction (see below) is placed in the probes instruction slot so it - * may be called by the emulation code. Decoding returns with INSN_GOOD. + * The probes instruction handler is set to the value found by + * indexing into the action array using the value of 'handler'. This + * will be used to emulate the instruction when the probe is hit. The + * modified instruction (see below) is placed in the probes instruction + * slot so it may be called by the emulation code. Decoding returns + * with INSN_GOOD. * * DECODE_REJECT(mask, value) * Instruction decoding fails with INSN_REJECTED @@ -238,7 +243,7 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); * Here is a real example which matches ARM instructions of the form * "AND ,,, " * - * DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, + * DECODE_EMULATEX (0x0e000090, 0x00000010, PROBES_DATA_PROCESSING_REG, * REGS(ANY, ANY, NOPC, 0, ANY)), * ^ ^ ^ ^ * Rn Rd Rs Rm @@ -249,7 +254,8 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); * Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the * instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into * the kprobes instruction slot. This can then be called later by the handler - * function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction. + * function emulate_rd12rn16rm0rs8_rwflags (a pointer to which is retrieved from + * the indicated slot in the action array), in order to simulate the instruction. */ enum decode_type { @@ -298,10 +304,17 @@ enum decode_reg_type { union decode_item { u32 bits; const union decode_item *table; - kprobe_insn_handler_t *handler; - kprobe_decode_insn_t *decoder; + int action; }; +typedef enum kprobe_insn (probes_custom_decode_t)(kprobe_opcode_t, + struct arch_specific_insn *, + const struct decode_header *); + +union decode_action { + kprobe_insn_handler_t *handler; + probes_custom_decode_t *decoder; +}; #define DECODE_END \ {.bits = DECODE_TYPE_END} @@ -336,7 +349,7 @@ struct decode_custom { #define DECODE_CUSTOM(_mask, _value, _decoder) \ DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \ - {.decoder = (_decoder)} + {.action = (_decoder)} struct decode_simulate { @@ -346,7 +359,7 @@ struct decode_simulate { #define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \ DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \ - {.handler = (_handler)} + {.action = (_handler)} #define DECODE_SIMULATE(_mask, _value, _handler) \ DECODE_SIMULATEX(_mask, _value, _handler, 0) @@ -359,7 +372,7 @@ struct decode_emulate { #define DECODE_EMULATEX(_mask, _value, _handler, _regs) \ DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \ - {.handler = (_handler)} + {.action = (_handler)} #define DECODE_EMULATE(_mask, _value, _handler) \ DECODE_EMULATEX(_mask, _value, _handler, 0) @@ -384,14 +397,18 @@ struct decode_reject { #ifdef CONFIG_THUMB2_KERNEL extern const union decode_item kprobe_decode_thumb16_table[]; extern const union decode_item kprobe_decode_thumb32_table[]; +extern const union decode_action kprobes_t32_actions[]; +extern const union decode_action kprobes_t16_actions[]; #else extern const union decode_item kprobe_decode_arm_table[]; +extern const union decode_action kprobes_arm_actions[]; #endif extern kprobe_check_cc * const kprobe_condition_checks[16]; int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb16); + const union decode_item *table, bool thumb16, + const union decode_action *actions); #endif -- cgit v1.2.3 From 7579f4b3764337b39087d10496af0e741cbfe570 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Fri, 7 Mar 2014 11:19:32 -0500 Subject: ARM: Remove use of struct kprobe from generic probes code Change the generic ARM probes code to pass in the opcode and architecture-specific structure separately instead of using struct kprobe, so we do not pollute code being used only for uprobes or other non-kprobes instruction interpretation. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/probes.h | 9 +- arch/arm/kernel/kprobes-arm.c | 61 +++++++------- arch/arm/kernel/kprobes-common.c | 40 +++++---- arch/arm/kernel/kprobes-thumb.c | 175 +++++++++++++++++++-------------------- arch/arm/kernel/kprobes.c | 2 +- arch/arm/kernel/probes-arm.c | 33 ++++---- arch/arm/kernel/probes-arm.h | 15 ++-- arch/arm/kernel/probes-thumb.c | 15 ++-- arch/arm/kernel/probes.c | 13 +-- arch/arm/kernel/probes.h | 8 +- 10 files changed, 201 insertions(+), 170 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index 737a9b310efc..4d014c4aa1e7 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -21,9 +21,14 @@ struct kprobe; -typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); +struct arch_specific_insn; +typedef void (kprobe_insn_handler_t)(kprobe_opcode_t, + struct arch_specific_insn *, + struct pt_regs *); typedef unsigned long (kprobe_check_cc)(unsigned long); -typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); +typedef void (kprobe_insn_singlestep_t)(kprobe_opcode_t, + struct arch_specific_insn *, + struct pt_regs *); typedef void (kprobe_insn_fn_t)(void); /* Architecture specific copy of original instruction. */ diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index 8ebd84c48867..4a232e682e5a 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -72,12 +72,11 @@ "mov pc, "reg" \n\t" #endif - static void __kprobes -emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) +emulate_ldrdstrd(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = (unsigned long)p->addr + 8; + unsigned long pc = regs->ARM_pc + 4; int rt = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -92,7 +91,7 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) BLX("%[fn]") : "=r" (rtv), "=r" (rt2v), "=r" (rnv) : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv), - [fn] "r" (p->ainsn.insn_fn) + [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -103,10 +102,10 @@ emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_ldr(struct kprobe *p, struct pt_regs *regs) +emulate_ldr(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = (unsigned long)p->addr + 8; + unsigned long pc = regs->ARM_pc + 4; int rt = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -119,7 +118,7 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( BLX("%[fn]") : "=r" (rtv), "=r" (rnv) - : "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) + : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -133,11 +132,11 @@ emulate_ldr(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_str(struct kprobe *p, struct pt_regs *regs) +emulate_str(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long rtpc = (unsigned long)p->addr + str_pc_offset; - unsigned long rnpc = (unsigned long)p->addr + 8; + unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset; + unsigned long rnpc = regs->ARM_pc + 4; int rt = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -151,7 +150,7 @@ emulate_str(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( BLX("%[fn]") : "=r" (rnv) - : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) + : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -160,10 +159,10 @@ emulate_str(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) +emulate_rd12rn16rm0rs8_rwflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = (unsigned long)p->addr + 8; + unsigned long pc = regs->ARM_pc + 4; int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -183,7 +182,7 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) "mrs %[cpsr], cpsr \n\t" : "=r" (rdv), [cpsr] "=r" (cpsr) : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + "1" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -195,9 +194,9 @@ emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) +emulate_rd12rn16rm0_rwflags_nopc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -213,7 +212,7 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) "mrs %[cpsr], cpsr \n\t" : "=r" (rdv), [cpsr] "=r" (cpsr) : "0" (rdv), "r" (rnv), "r" (rmv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + "1" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -222,9 +221,10 @@ emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) +emulate_rd16rn12rm0rs8_rwflags_nopc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 16) & 0xf; int rn = (insn >> 12) & 0xf; int rm = insn & 0xf; @@ -242,7 +242,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) "mrs %[cpsr], cpsr \n\t" : "=r" (rdv), [cpsr] "=r" (cpsr) : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + "1" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -251,9 +251,9 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) +emulate_rd12rm0_noflags_nopc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 12) & 0xf; int rm = insn & 0xf; @@ -263,7 +263,7 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( BLX("%[fn]") : "=r" (rdv) - : "0" (rdv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) + : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -271,9 +271,10 @@ emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) +emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rdlo = (insn >> 12) & 0xf; int rdhi = (insn >> 16) & 0xf; int rn = insn & 0xf; @@ -291,7 +292,7 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) "mrs %[cpsr], cpsr \n\t" : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr) : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), - "2" (cpsr), [fn] "r" (p->ainsn.insn_fn) + "2" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 029b79c6face..abe03890f84d 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -17,9 +17,10 @@ #include "kprobes.h" -static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) +static void __kprobes simulate_ldm1stm1(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rn = (insn >> 16) & 0xf; int lbit = insn & (1 << 20); int wbit = insn & (1 << 21); @@ -58,24 +59,31 @@ static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) } } -static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) +static void __kprobes simulate_stm1_pc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - regs->ARM_pc = (long)p->addr + str_pc_offset; - simulate_ldm1stm1(p, regs); - regs->ARM_pc = (long)p->addr + 4; + unsigned long addr = regs->ARM_pc - 4; + + regs->ARM_pc = (long)addr + str_pc_offset; + simulate_ldm1stm1(insn, asi, regs); + regs->ARM_pc = (long)addr + 4; } -static void __kprobes simulate_ldm1_pc(struct kprobe *p, struct pt_regs *regs) +static void __kprobes simulate_ldm1_pc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - simulate_ldm1stm1(p, regs); + simulate_ldm1stm1(insn, asi, regs); load_write_pc(regs->ARM_pc, regs); } static void __kprobes -emulate_generic_r0_12_noflags(struct kprobe *p, struct pt_regs *regs) +emulate_generic_r0_12_noflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { register void *rregs asm("r1") = regs; - register void *rfn asm("lr") = p->ainsn.insn_fn; + register void *rfn asm("lr") = asi->insn_fn; __asm__ __volatile__ ( "stmdb sp!, {%[regs], r11} \n\t" @@ -99,15 +107,19 @@ emulate_generic_r0_12_noflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -emulate_generic_r2_14_noflags(struct kprobe *p, struct pt_regs *regs) +emulate_generic_r2_14_noflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+2)); + emulate_generic_r0_12_noflags(insn, asi, + (struct pt_regs *)(regs->uregs+2)); } static void __kprobes -emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs) +emulate_ldm_r3_15(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+3)); + emulate_generic_r0_12_noflags(insn, asi, + (struct pt_regs *)(regs->uregs+3)); load_write_pc(regs->ARM_pc, regs); } diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index d83f6092920a..adc08f8d4a1c 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -20,24 +20,13 @@ #define t32_emulate_rd8rn16rm0ra12_noflags \ t32_emulate_rdlo12rdhi8rn16rm0_noflags -/* - * Return the PC value for a probe in thumb code. - * This is the address of the probed instruction plus 4. - * We subtract one because the address will have bit zero set to indicate - * a pointer to thumb code. - */ -static inline unsigned long __kprobes thumb_probe_pc(struct kprobe *p) -{ - return (unsigned long)p->addr - 1 + 4; -} - /* t32 thumb actions */ static void __kprobes -t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) +t32_simulate_table_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -54,19 +43,19 @@ t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) +t32_simulate_mrs(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 8) & 0xf; unsigned long mask = 0xf8ff03df; /* Mask out execution state */ regs->uregs[rd] = regs->ARM_cpsr & mask; } static void __kprobes -t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) +t32_simulate_cond_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc; long offset = insn & 0x7ff; /* imm11 */ offset += (insn & 0x003f0000) >> 5; /* imm6 */ @@ -88,10 +77,10 @@ t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) +t32_simulate_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc; long offset = insn & 0x7ff; /* imm11 */ offset += (insn & 0x03ff0000) >> 5; /* imm10 */ @@ -104,7 +93,7 @@ t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) if (insn & (1 << 14)) { /* BL or BLX */ - regs->ARM_lr = (unsigned long)p->addr + 4; + regs->ARM_lr = regs->ARM_pc | 1; if (!(insn & (1 << 12))) { /* BLX so switch to ARM mode */ regs->ARM_cpsr &= ~PSR_T_BIT; @@ -116,10 +105,10 @@ t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) +t32_simulate_ldr_literal(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long addr = thumb_probe_pc(p) & ~3; + unsigned long addr = regs->ARM_pc & ~3; int rt = (insn >> 12) & 0xf; unsigned long rtv; @@ -168,10 +157,10 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) +t32_emulate_ldrdstrd(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p) & ~3; + unsigned long pc = regs->ARM_pc & ~3; int rt1 = (insn >> 12) & 0xf; int rt2 = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; @@ -184,7 +173,7 @@ t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( "blx %[fn]" : "=r" (rt1v), "=r" (rt2v), "=r" (rnv) - : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (p->ainsn.insn_fn) + : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -195,9 +184,9 @@ t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) +t32_emulate_ldrstr(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rt = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -209,7 +198,7 @@ t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( "blx %[fn]" : "=r" (rtv), "=r" (rnv) - : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) + : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -221,9 +210,9 @@ t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) +t32_emulate_rd8rn16rm0_rwflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; int rm = insn & 0xf; @@ -239,7 +228,7 @@ t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) "mrs %[cpsr], cpsr \n\t" : "=r" (rdv), [cpsr] "=r" (cpsr) : "0" (rdv), "r" (rnv), "r" (rmv), - "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + "1" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -248,10 +237,10 @@ t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) +t32_emulate_rd8pc16_noflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc; int rd = (insn >> 8) & 0xf; register unsigned long rdv asm("r1") = regs->uregs[rd]; @@ -260,7 +249,7 @@ t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( "blx %[fn]" : "=r" (rdv) - : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) + : "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -268,9 +257,9 @@ t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) +t32_emulate_rd8rn16_noflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; @@ -280,7 +269,7 @@ t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) __asm__ __volatile__ ( "blx %[fn]" : "=r" (rdv) - : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) + : "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -288,9 +277,10 @@ t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) +t32_emulate_rdlo12rdhi8rn16rm0_noflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rdlo = (insn >> 12) & 0xf; int rdhi = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; @@ -305,7 +295,7 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) "blx %[fn]" : "=r" (rdlov), "=r" (rdhiv) : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), - [fn] "r" (p->ainsn.insn_fn) + [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -315,33 +305,33 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) /* t16 thumb actions */ static void __kprobes -t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) +t16_simulate_bxblx(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc + 2; int rm = (insn >> 3) & 0xf; unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm]; if (insn & (1 << 7)) /* BLX ? */ - regs->ARM_lr = (unsigned long)p->addr + 2; + regs->ARM_lr = regs->ARM_pc | 1; bx_write_pc(rmv, regs); } static void __kprobes -t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) +t16_simulate_ldr_literal(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long* base = (unsigned long *)(thumb_probe_pc(p) & ~3); + unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3); long index = insn & 0xff; int rt = (insn >> 8) & 0x7; regs->uregs[rt] = base[index]; } static void __kprobes -t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) +t16_simulate_ldrstr_sp_relative(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; unsigned long* base = (unsigned long *)regs->ARM_sp; long index = insn & 0xff; int rt = (insn >> 8) & 0x7; @@ -352,20 +342,20 @@ t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) +t16_simulate_reladr(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; unsigned long base = (insn & 0x800) ? regs->ARM_sp - : (thumb_probe_pc(p) & ~3); + : ((regs->ARM_pc + 2) & ~3); long offset = insn & 0xff; int rt = (insn >> 8) & 0x7; regs->uregs[rt] = base + offset * 4; } static void __kprobes -t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) +t16_simulate_add_sp_imm(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; long imm = insn & 0x7f; if (insn & 0x80) /* SUB */ regs->ARM_sp -= imm * 4; @@ -374,21 +364,22 @@ t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) +t16_simulate_cbz(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rn = insn & 0x7; kprobe_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; if (nonzero & 0x800) { long i = insn & 0x200; long imm5 = insn & 0xf8; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc + 2; regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2); } } static void __kprobes -t16_simulate_it(struct kprobe *p, struct pt_regs *regs) +t16_simulate_it(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { /* * The 8 IT state bits are split into two parts in CPSR: @@ -396,7 +387,6 @@ t16_simulate_it(struct kprobe *p, struct pt_regs *regs) * ITSTATE<7:2> are in CPSR<15:10> * The new IT state is in the lower byte of insn. */ - kprobe_opcode_t insn = p->opcode; unsigned long cpsr = regs->ARM_cpsr; cpsr &= ~PSR_IT_MASK; cpsr |= (insn & 0xfc) << 8; @@ -405,10 +395,11 @@ t16_simulate_it(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) +t16_singlestep_it(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 2; - t16_simulate_it(p, regs); + t16_simulate_it(insn, asi, regs); } static enum kprobe_insn __kprobes @@ -420,10 +411,10 @@ t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) +t16_simulate_cond_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc + 2; long offset = insn & 0x7f; offset -= insn & 0x80; /* Apply sign bit */ regs->ARM_pc = pc + (offset * 2); @@ -440,17 +431,18 @@ t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) +t16_simulate_branch(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc + 2; long offset = insn & 0x3ff; offset -= insn & 0x400; /* Apply sign bit */ regs->ARM_pc = pc + (offset * 2); } static unsigned long __kprobes -t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) +t16_emulate_loregs(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long oldcpsr = regs->ARM_cpsr; unsigned long newcpsr; @@ -463,7 +455,7 @@ t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) "mrs %[newcpsr], cpsr \n\t" : [newcpsr] "=r" (newcpsr) : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs), - [fn] "r" (p->ainsn.insn_fn) + [fn] "r" (asi->insn_fn) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "lr", "memory", "cc" ); @@ -472,24 +464,26 @@ t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) } static void __kprobes -t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) +t16_emulate_loregs_rwflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - regs->ARM_cpsr = t16_emulate_loregs(p, regs); + regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs); } static void __kprobes -t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) +t16_emulate_loregs_noitrwflags(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - unsigned long cpsr = t16_emulate_loregs(p, regs); + unsigned long cpsr = t16_emulate_loregs(insn, asi, regs); if (!in_it_block(cpsr)) regs->ARM_cpsr = cpsr; } static void __kprobes -t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) +t16_emulate_hiregs(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - unsigned long pc = thumb_probe_pc(p); + unsigned long pc = regs->ARM_pc + 2; int rdn = (insn & 0x7) | ((insn & 0x80) >> 4); int rm = (insn >> 3) & 0xf; @@ -505,7 +499,7 @@ t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) "blx %[fn] \n\t" "mrs %[cpsr], cpsr \n\t" : "=r" (rdnv), [cpsr] "=r" (cpsr) - : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) + : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (asi->insn_fn) : "lr", "memory", "cc" ); @@ -528,7 +522,8 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_emulate_push(struct kprobe *p, struct pt_regs *regs) +t16_emulate_push(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( "ldr r9, [%[regs], #13*4] \n\t" @@ -537,7 +532,7 @@ t16_emulate_push(struct kprobe *p, struct pt_regs *regs) "blx %[fn] \n\t" "str r9, [%[regs], #13*4] \n\t" : - : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) + : [regs] "r" (regs), [fn] "r" (asi->insn_fn) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "lr", "memory", "cc" ); @@ -559,7 +554,8 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) +t16_emulate_pop_nopc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( "ldr r9, [%[regs], #13*4] \n\t" @@ -568,14 +564,15 @@ t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) "stmia %[regs], {r0-r7} \n\t" "str r9, [%[regs], #13*4] \n\t" : - : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) + : [regs] "r" (regs), [fn] "r" (asi->insn_fn) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", "lr", "memory", "cc" ); } static void __kprobes -t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) +t16_emulate_pop_pc(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { register unsigned long pc asm("r8"); @@ -586,7 +583,7 @@ t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) "stmia %[regs], {r0-r7} \n\t" "str r9, [%[regs], #13*4] \n\t" : "=r" (pc) - : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) + : [regs] "r" (regs), [fn] "r" (asi->insn_fn) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", "lr", "memory", "cc" ); diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index a757c3c22381..b4a3028edffe 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -204,7 +204,7 @@ singlestep_skip(struct kprobe *p, struct pt_regs *regs) static inline void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) { - p->ainsn.insn_singlestep(p, regs); + p->ainsn.insn_singlestep(p->opcode, &p->ainsn, regs); } /* diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 496e0e913fa6..36002e5d0f0e 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -19,9 +19,8 @@ #include #include #include -#include -#include "kprobes.h" +#include "probes.h" #include "probes-arm.h" #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) @@ -58,10 +57,10 @@ * read and write of flags. */ -void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) +void __kprobes simulate_bbl(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; + long iaddr = (long) regs->ARM_pc - 4; int disp = branch_displacement(insn); if (insn & (1 << 24)) @@ -70,10 +69,10 @@ void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) regs->ARM_pc = iaddr + 8 + disp; } -void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) +void __kprobes simulate_blx1(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; - long iaddr = (long)p->addr; + long iaddr = (long) regs->ARM_pc - 4; int disp = branch_displacement(insn); regs->ARM_lr = iaddr + 4; @@ -81,14 +80,14 @@ void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr |= PSR_T_BIT; } -void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) +void __kprobes simulate_blx2bx(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rm = insn & 0xf; long rmv = regs->uregs[rm]; if (insn & (1 << 5)) - regs->ARM_lr = (long)p->addr + 4; + regs->ARM_lr = (long) regs->ARM_pc; regs->ARM_pc = rmv & ~0x1; regs->ARM_cpsr &= ~PSR_T_BIT; @@ -96,15 +95,16 @@ void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) regs->ARM_cpsr |= PSR_T_BIT; } -void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) +void __kprobes simulate_mrs(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { - kprobe_opcode_t insn = p->opcode; int rd = (insn >> 12) & 0xf; unsigned long mask = 0xf8ff03df; /* Mask out execution state */ regs->uregs[rd] = regs->ARM_cpsr & mask; } -void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) +void __kprobes simulate_mov_ipsp(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { regs->uregs[12] = regs->uregs[13]; } @@ -704,10 +704,11 @@ const union decode_item kprobe_decode_arm_table[] = { EXPORT_SYMBOL_GPL(kprobe_decode_arm_table); #endif -static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) +static void __kprobes arm_singlestep(kprobe_opcode_t insn, + struct arch_specific_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); + asi->insn_handler(insn, asi, regs); } /* Return: diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index ef3089419a0b..d0ac8a42caa0 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -53,10 +53,15 @@ enum probes_arm_action { NUM_PROBES_ARM_ACTIONS }; -void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs); -void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs); -void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs); -void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs); -void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs); +void __kprobes simulate_bbl(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, struct pt_regs *regs); +void __kprobes simulate_blx1(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, struct pt_regs *regs); +void __kprobes simulate_blx2bx(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, struct pt_regs *regs); +void __kprobes simulate_mrs(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, struct pt_regs *regs); +void __kprobes simulate_mov_ipsp(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, struct pt_regs *regs); #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index 2abe8ceeb670..aa3176da1b29 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -10,10 +10,9 @@ #include #include -#include #include -#include "kprobes.h" +#include "probes.h" #include "probes-thumb.h" @@ -844,17 +843,21 @@ static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) return true; } -static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) +static void __kprobes thumb16_singlestep(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, + struct pt_regs *regs) { regs->ARM_pc += 2; - p->ainsn.insn_handler(p, regs); + asi->insn_handler(opcode, asi, regs); regs->ARM_cpsr = it_advance(regs->ARM_cpsr); } -static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) +static void __kprobes thumb32_singlestep(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, + struct pt_regs *regs) { regs->ARM_pc += 4; - p->ainsn.insn_handler(p, regs); + asi->insn_handler(opcode, asi, regs); regs->ARM_cpsr = it_advance(regs->ARM_cpsr); } diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index efd92c5b4a52..f2ab8856ba2b 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -13,12 +13,11 @@ #include #include -#include #include #include #include -#include "kprobes.h" +#include "probes.h" #ifndef find_str_pc_offset @@ -176,13 +175,17 @@ kprobe_check_cc * const kprobe_condition_checks[16] = { }; -void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs) +void __kprobes kprobe_simulate_nop(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, + struct pt_regs *regs) { } -void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs) +void __kprobes kprobe_emulate_none(kprobe_opcode_t opcode, + struct arch_specific_insn *asi, + struct pt_regs *regs) { - p->ainsn.insn_fn(); + asi->insn_fn(); } /* diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 5554f161bdac..efea63c02742 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -22,6 +22,7 @@ #include #include #include +#include "kprobes.h" #if __LINUX_ARM_ARCH__ >= 7 @@ -37,6 +38,7 @@ void __init find_str_pc_offset(void); #endif +struct decode_header; /* * Update ITSTATE after normal execution of an IT block instruction. @@ -129,8 +131,10 @@ static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) } -void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); -void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); +void __kprobes kprobe_simulate_nop(kprobe_opcode_t, struct arch_specific_insn *, + struct pt_regs *regs); +void __kprobes kprobe_emulate_none(kprobe_opcode_t, struct arch_specific_insn *, + struct pt_regs *regs); enum kprobe_insn __kprobes kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, -- cgit v1.2.3 From f145d664df502585618b12ed68c681f82153e02a Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:17:23 -0500 Subject: ARM: Make the kprobes condition_check symbol names more generic In preparation for sharing the ARM kprobes instruction interpreting code with uprobes, make the symbols names less kprobes-specific. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/probes.h | 11 +++--- arch/arm/kernel/kprobes-arm.c | 16 ++++----- arch/arm/kernel/kprobes-common.c | 14 ++++---- arch/arm/kernel/kprobes-thumb.c | 76 ++++++++++++++++++++-------------------- arch/arm/kernel/kprobes.h | 8 ++--- arch/arm/kernel/probes-arm.c | 16 ++++----- arch/arm/kernel/probes-arm.h | 10 +++--- arch/arm/kernel/probes-thumb.c | 10 +++--- arch/arm/kernel/probes.c | 22 ++++++------ arch/arm/kernel/probes.h | 12 +++---- 10 files changed, 98 insertions(+), 97 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index 4d014c4aa1e7..c4acf6c8a2d4 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -20,22 +20,23 @@ #define _ASM_PROBES_H struct kprobe; +typedef u32 probes_opcode_t; struct arch_specific_insn; -typedef void (kprobe_insn_handler_t)(kprobe_opcode_t, +typedef void (kprobe_insn_handler_t)(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *); -typedef unsigned long (kprobe_check_cc)(unsigned long); -typedef void (kprobe_insn_singlestep_t)(kprobe_opcode_t, +typedef unsigned long (probes_check_cc)(unsigned long); +typedef void (kprobe_insn_singlestep_t)(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *); typedef void (kprobe_insn_fn_t)(void); /* Architecture specific copy of original instruction. */ struct arch_specific_insn { - kprobe_opcode_t *insn; + probes_opcode_t *insn; kprobe_insn_handler_t *insn_handler; - kprobe_check_cc *insn_check_cc; + probes_check_cc *insn_check_cc; kprobe_insn_singlestep_t *insn_singlestep; kprobe_insn_fn_t *insn_fn; }; diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index 4a232e682e5a..09a7b1e19c14 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -73,7 +73,7 @@ #endif static void __kprobes -emulate_ldrdstrd(kprobe_opcode_t insn, +emulate_ldrdstrd(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; @@ -102,7 +102,7 @@ emulate_ldrdstrd(kprobe_opcode_t insn, } static void __kprobes -emulate_ldr(kprobe_opcode_t insn, +emulate_ldr(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; @@ -132,7 +132,7 @@ emulate_ldr(kprobe_opcode_t insn, } static void __kprobes -emulate_str(kprobe_opcode_t insn, +emulate_str(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset; @@ -159,7 +159,7 @@ emulate_str(kprobe_opcode_t insn, } static void __kprobes -emulate_rd12rn16rm0rs8_rwflags(kprobe_opcode_t insn, +emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; @@ -194,7 +194,7 @@ emulate_rd12rn16rm0rs8_rwflags(kprobe_opcode_t insn, } static void __kprobes -emulate_rd12rn16rm0_rwflags_nopc(kprobe_opcode_t insn, +emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; @@ -221,7 +221,7 @@ emulate_rd12rn16rm0_rwflags_nopc(kprobe_opcode_t insn, } static void __kprobes -emulate_rd16rn12rm0rs8_rwflags_nopc(kprobe_opcode_t insn, +emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -251,7 +251,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(kprobe_opcode_t insn, } static void __kprobes -emulate_rd12rm0_noflags_nopc(kprobe_opcode_t insn, +emulate_rd12rm0_noflags_nopc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; @@ -271,7 +271,7 @@ emulate_rd12rm0_noflags_nopc(kprobe_opcode_t insn, } static void __kprobes -emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(kprobe_opcode_t insn, +emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index abe03890f84d..08b55605c1ec 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -17,7 +17,7 @@ #include "kprobes.h" -static void __kprobes simulate_ldm1stm1(kprobe_opcode_t insn, +static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -59,7 +59,7 @@ static void __kprobes simulate_ldm1stm1(kprobe_opcode_t insn, } } -static void __kprobes simulate_stm1_pc(kprobe_opcode_t insn, +static void __kprobes simulate_stm1_pc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -70,7 +70,7 @@ static void __kprobes simulate_stm1_pc(kprobe_opcode_t insn, regs->ARM_pc = (long)addr + 4; } -static void __kprobes simulate_ldm1_pc(kprobe_opcode_t insn, +static void __kprobes simulate_ldm1_pc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -79,7 +79,7 @@ static void __kprobes simulate_ldm1_pc(kprobe_opcode_t insn, } static void __kprobes -emulate_generic_r0_12_noflags(kprobe_opcode_t insn, +emulate_generic_r0_12_noflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { register void *rregs asm("r1") = regs; @@ -107,7 +107,7 @@ emulate_generic_r0_12_noflags(kprobe_opcode_t insn, } static void __kprobes -emulate_generic_r2_14_noflags(kprobe_opcode_t insn, +emulate_generic_r2_14_noflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { emulate_generic_r0_12_noflags(insn, asi, @@ -115,7 +115,7 @@ emulate_generic_r2_14_noflags(kprobe_opcode_t insn, } static void __kprobes -emulate_ldm_r3_15(kprobe_opcode_t insn, +emulate_ldm_r3_15(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { emulate_generic_r0_12_noflags(insn, asi, @@ -124,7 +124,7 @@ emulate_ldm_r3_15(kprobe_opcode_t insn, } enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, +kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *h) { kprobe_insn_handler_t *handler = 0; diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index adc08f8d4a1c..610d6932e9bf 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -23,7 +23,7 @@ /* t32 thumb actions */ static void __kprobes -t32_simulate_table_branch(kprobe_opcode_t insn, +t32_simulate_table_branch(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -43,7 +43,7 @@ t32_simulate_table_branch(kprobe_opcode_t insn, } static void __kprobes -t32_simulate_mrs(kprobe_opcode_t insn, +t32_simulate_mrs(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; @@ -52,7 +52,7 @@ t32_simulate_mrs(kprobe_opcode_t insn, } static void __kprobes -t32_simulate_cond_branch(kprobe_opcode_t insn, +t32_simulate_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -67,17 +67,17 @@ t32_simulate_cond_branch(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t32_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { int cc = (insn >> 22) & 0xf; - asi->insn_check_cc = kprobe_condition_checks[cc]; + asi->insn_check_cc = probes_condition_checks[cc]; asi->insn_handler = t32_simulate_cond_branch; return INSN_GOOD_NO_SLOT; } static void __kprobes -t32_simulate_branch(kprobe_opcode_t insn, +t32_simulate_branch(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -105,7 +105,7 @@ t32_simulate_branch(kprobe_opcode_t insn, } static void __kprobes -t32_simulate_ldr_literal(kprobe_opcode_t insn, +t32_simulate_ldr_literal(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long addr = regs->ARM_pc & ~3; @@ -143,7 +143,7 @@ t32_simulate_ldr_literal(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t32_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi, d); @@ -157,7 +157,7 @@ t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t32_emulate_ldrdstrd(kprobe_opcode_t insn, +t32_emulate_ldrdstrd(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc & ~3; @@ -184,7 +184,7 @@ t32_emulate_ldrdstrd(kprobe_opcode_t insn, } static void __kprobes -t32_emulate_ldrstr(kprobe_opcode_t insn, +t32_emulate_ldrstr(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rt = (insn >> 12) & 0xf; @@ -210,7 +210,7 @@ t32_emulate_ldrstr(kprobe_opcode_t insn, } static void __kprobes -t32_emulate_rd8rn16rm0_rwflags(kprobe_opcode_t insn, +t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; @@ -237,7 +237,7 @@ t32_emulate_rd8rn16rm0_rwflags(kprobe_opcode_t insn, } static void __kprobes -t32_emulate_rd8pc16_noflags(kprobe_opcode_t insn, +t32_emulate_rd8pc16_noflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -257,7 +257,7 @@ t32_emulate_rd8pc16_noflags(kprobe_opcode_t insn, } static void __kprobes -t32_emulate_rd8rn16_noflags(kprobe_opcode_t insn, +t32_emulate_rd8rn16_noflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; @@ -277,7 +277,7 @@ t32_emulate_rd8rn16_noflags(kprobe_opcode_t insn, } static void __kprobes -t32_emulate_rdlo12rdhi8rn16rm0_noflags(kprobe_opcode_t insn, +t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -305,7 +305,7 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(kprobe_opcode_t insn, /* t16 thumb actions */ static void __kprobes -t16_simulate_bxblx(kprobe_opcode_t insn, +t16_simulate_bxblx(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; @@ -319,7 +319,7 @@ t16_simulate_bxblx(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_ldr_literal(kprobe_opcode_t insn, +t16_simulate_ldr_literal(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3); @@ -329,7 +329,7 @@ t16_simulate_ldr_literal(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_ldrstr_sp_relative(kprobe_opcode_t insn, +t16_simulate_ldrstr_sp_relative(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long* base = (unsigned long *)regs->ARM_sp; @@ -342,7 +342,7 @@ t16_simulate_ldrstr_sp_relative(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_reladr(kprobe_opcode_t insn, +t16_simulate_reladr(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long base = (insn & 0x800) ? regs->ARM_sp @@ -353,7 +353,7 @@ t16_simulate_reladr(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_add_sp_imm(kprobe_opcode_t insn, +t16_simulate_add_sp_imm(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { long imm = insn & 0x7f; @@ -364,11 +364,11 @@ t16_simulate_add_sp_imm(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_cbz(kprobe_opcode_t insn, +t16_simulate_cbz(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rn = insn & 0x7; - kprobe_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; + probes_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; if (nonzero & 0x800) { long i = insn & 0x200; long imm5 = insn & 0xf8; @@ -378,7 +378,7 @@ t16_simulate_cbz(kprobe_opcode_t insn, } static void __kprobes -t16_simulate_it(kprobe_opcode_t insn, +t16_simulate_it(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { /* @@ -395,7 +395,7 @@ t16_simulate_it(kprobe_opcode_t insn, } static void __kprobes -t16_singlestep_it(kprobe_opcode_t insn, +t16_singlestep_it(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 2; @@ -403,7 +403,7 @@ t16_singlestep_it(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_it(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { asi->insn_singlestep = t16_singlestep_it; @@ -411,7 +411,7 @@ t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_simulate_cond_branch(kprobe_opcode_t insn, +t16_simulate_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; @@ -421,17 +421,17 @@ t16_simulate_cond_branch(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { int cc = (insn >> 8) & 0xf; - asi->insn_check_cc = kprobe_condition_checks[cc]; + asi->insn_check_cc = probes_condition_checks[cc]; asi->insn_handler = t16_simulate_cond_branch; return INSN_GOOD_NO_SLOT; } static void __kprobes -t16_simulate_branch(kprobe_opcode_t insn, +t16_simulate_branch(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; @@ -441,7 +441,7 @@ t16_simulate_branch(kprobe_opcode_t insn, } static unsigned long __kprobes -t16_emulate_loregs(kprobe_opcode_t insn, +t16_emulate_loregs(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long oldcpsr = regs->ARM_cpsr; @@ -464,14 +464,14 @@ t16_emulate_loregs(kprobe_opcode_t insn, } static void __kprobes -t16_emulate_loregs_rwflags(kprobe_opcode_t insn, +t16_emulate_loregs_rwflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs); } static void __kprobes -t16_emulate_loregs_noitrwflags(kprobe_opcode_t insn, +t16_emulate_loregs_noitrwflags(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long cpsr = t16_emulate_loregs(insn, asi, regs); @@ -480,7 +480,7 @@ t16_emulate_loregs_noitrwflags(kprobe_opcode_t insn, } static void __kprobes -t16_emulate_hiregs(kprobe_opcode_t insn, +t16_emulate_hiregs(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; @@ -511,7 +511,7 @@ t16_emulate_hiregs(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_hiregs(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { insn &= ~0x00ff; @@ -522,7 +522,7 @@ t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_emulate_push(kprobe_opcode_t insn, +t16_emulate_push(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -539,7 +539,7 @@ t16_emulate_push(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_push(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { /* @@ -554,7 +554,7 @@ t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi, } static void __kprobes -t16_emulate_pop_nopc(kprobe_opcode_t insn, +t16_emulate_pop_nopc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( @@ -571,7 +571,7 @@ t16_emulate_pop_nopc(kprobe_opcode_t insn, } static void __kprobes -t16_emulate_pop_pc(kprobe_opcode_t insn, +t16_emulate_pop_pc(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { register unsigned long pc asm("r8"); @@ -592,7 +592,7 @@ t16_emulate_pop_pc(kprobe_opcode_t insn, } static enum kprobe_insn __kprobes -t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_pop(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { /* diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index 7798035d6003..d0530b15e473 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -36,22 +36,22 @@ enum kprobe_insn { INSN_GOOD_NO_SLOT }; -typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t, +typedef enum kprobe_insn (kprobe_decode_insn_t)(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); #ifdef CONFIG_THUMB2_KERNEL -enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t, +enum kprobe_insn thumb16_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); -enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t, +enum kprobe_insn thumb32_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); #else /* !CONFIG_THUMB2_KERNEL */ -enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, +enum kprobe_insn arm_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 36002e5d0f0e..3357a074597d 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -57,7 +57,7 @@ * read and write of flags. */ -void __kprobes simulate_bbl(kprobe_opcode_t insn, +void __kprobes simulate_bbl(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { long iaddr = (long) regs->ARM_pc - 4; @@ -69,7 +69,7 @@ void __kprobes simulate_bbl(kprobe_opcode_t insn, regs->ARM_pc = iaddr + 8 + disp; } -void __kprobes simulate_blx1(kprobe_opcode_t insn, +void __kprobes simulate_blx1(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { long iaddr = (long) regs->ARM_pc - 4; @@ -80,7 +80,7 @@ void __kprobes simulate_blx1(kprobe_opcode_t insn, regs->ARM_cpsr |= PSR_T_BIT; } -void __kprobes simulate_blx2bx(kprobe_opcode_t insn, +void __kprobes simulate_blx2bx(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rm = insn & 0xf; @@ -95,7 +95,7 @@ void __kprobes simulate_blx2bx(kprobe_opcode_t insn, regs->ARM_cpsr |= PSR_T_BIT; } -void __kprobes simulate_mrs(kprobe_opcode_t insn, +void __kprobes simulate_mrs(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; @@ -103,7 +103,7 @@ void __kprobes simulate_mrs(kprobe_opcode_t insn, regs->uregs[rd] = regs->ARM_cpsr & mask; } -void __kprobes simulate_mov_ipsp(kprobe_opcode_t insn, +void __kprobes simulate_mov_ipsp(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { regs->uregs[12] = regs->uregs[13]; @@ -704,7 +704,7 @@ const union decode_item kprobe_decode_arm_table[] = { EXPORT_SYMBOL_GPL(kprobe_decode_arm_table); #endif -static void __kprobes arm_singlestep(kprobe_opcode_t insn, +static void __kprobes arm_singlestep(probes_opcode_t insn, struct arch_specific_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 4; @@ -724,11 +724,11 @@ static void __kprobes arm_singlestep(kprobe_opcode_t insn, * should also be very rare. */ enum kprobe_insn __kprobes -arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +arm_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = arm_singlestep; - asi->insn_check_cc = kprobe_condition_checks[insn>>28]; + asi->insn_check_cc = probes_condition_checks[insn>>28]; return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false, actions); } diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index d0ac8a42caa0..9a9d379dbf33 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -53,15 +53,15 @@ enum probes_arm_action { NUM_PROBES_ARM_ACTIONS }; -void __kprobes simulate_bbl(kprobe_opcode_t opcode, +void __kprobes simulate_bbl(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); -void __kprobes simulate_blx1(kprobe_opcode_t opcode, +void __kprobes simulate_blx1(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); -void __kprobes simulate_blx2bx(kprobe_opcode_t opcode, +void __kprobes simulate_blx2bx(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); -void __kprobes simulate_mrs(kprobe_opcode_t opcode, +void __kprobes simulate_mrs(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); -void __kprobes simulate_mov_ipsp(kprobe_opcode_t opcode, +void __kprobes simulate_mov_ipsp(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index aa3176da1b29..a15a79b7c9c5 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -839,11 +839,11 @@ EXPORT_SYMBOL_GPL(kprobe_decode_thumb16_table); static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) { if (unlikely(in_it_block(cpsr))) - return kprobe_condition_checks[current_cond(cpsr)](cpsr); + return probes_condition_checks[current_cond(cpsr)](cpsr); return true; } -static void __kprobes thumb16_singlestep(kprobe_opcode_t opcode, +static void __kprobes thumb16_singlestep(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -852,7 +852,7 @@ static void __kprobes thumb16_singlestep(kprobe_opcode_t opcode, regs->ARM_cpsr = it_advance(regs->ARM_cpsr); } -static void __kprobes thumb32_singlestep(kprobe_opcode_t opcode, +static void __kprobes thumb32_singlestep(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -862,7 +862,7 @@ static void __kprobes thumb32_singlestep(kprobe_opcode_t opcode, } enum kprobe_insn __kprobes -thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +thumb16_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = thumb16_singlestep; @@ -872,7 +872,7 @@ thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, } enum kprobe_insn __kprobes -thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +thumb32_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = thumb32_singlestep; diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index f2ab8856ba2b..c1cdc0d27e05 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -167,7 +167,7 @@ static unsigned long __kprobes __check_al(unsigned long cpsr) return true; } -kprobe_check_cc * const kprobe_condition_checks[16] = { +probes_check_cc * const probes_condition_checks[16] = { &__check_eq, &__check_ne, &__check_cs, &__check_cc, &__check_mi, &__check_pl, &__check_vs, &__check_vc, &__check_hi, &__check_ls, &__check_ge, &__check_lt, @@ -175,13 +175,13 @@ kprobe_check_cc * const kprobe_condition_checks[16] = { }; -void __kprobes kprobe_simulate_nop(kprobe_opcode_t opcode, +void __kprobes kprobe_simulate_nop(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { } -void __kprobes kprobe_emulate_none(kprobe_opcode_t opcode, +void __kprobes kprobe_emulate_none(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { @@ -195,8 +195,8 @@ void __kprobes kprobe_emulate_none(kprobe_opcode_t opcode, * unconditional as the condition code will already be checked before any * emulation handler is called. */ -static kprobe_opcode_t __kprobes -prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +static probes_opcode_t __kprobes +prepare_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, bool thumb) { #ifdef CONFIG_THUMB2_KERNEL @@ -221,7 +221,7 @@ prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, * prepare_emulated_insn */ static void __kprobes -set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +set_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, bool thumb) { #ifdef CONFIG_THUMB2_KERNEL @@ -257,14 +257,14 @@ set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, * non-zero value, the corresponding nibble in pinsn is validated and modified * according to the type. */ -static bool __kprobes decode_regs(kprobe_opcode_t *pinsn, u32 regs) +static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs) { - kprobe_opcode_t insn = *pinsn; - kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */ + probes_opcode_t insn = *pinsn; + probes_opcode_t mask = 0xf; /* Start at least significant nibble */ for (; regs != 0; regs >>= 4, mask <<= 4) { - kprobe_opcode_t new_bits = INSN_NEW_BITS; + probes_opcode_t new_bits = INSN_NEW_BITS; switch (regs & 0xf) { @@ -383,7 +383,7 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { * */ int __kprobes -kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_item *table, bool thumb, const union decode_action *actions) { diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index efea63c02742..5a0497f5a8f7 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -131,13 +131,13 @@ static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) } -void __kprobes kprobe_simulate_nop(kprobe_opcode_t, struct arch_specific_insn *, +void __kprobes kprobe_simulate_nop(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *regs); -void __kprobes kprobe_emulate_none(kprobe_opcode_t, struct arch_specific_insn *, +void __kprobes kprobe_emulate_none(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *regs); enum kprobe_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, +kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *h); /* @@ -311,7 +311,7 @@ union decode_item { int action; }; -typedef enum kprobe_insn (probes_custom_decode_t)(kprobe_opcode_t, +typedef enum kprobe_insn (probes_custom_decode_t)(probes_opcode_t, struct arch_specific_insn *, const struct decode_header *); @@ -408,10 +408,10 @@ extern const union decode_item kprobe_decode_arm_table[]; extern const union decode_action kprobes_arm_actions[]; #endif -extern kprobe_check_cc * const kprobe_condition_checks[16]; +extern probes_check_cc * const probes_condition_checks[16]; -int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, +int kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_item *table, bool thumb16, const union decode_action *actions); -- cgit v1.2.3 From eb73ea97e63bb06bf98ff052615ce181bc7f69ec Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:20:25 -0500 Subject: ARM: Change more ARM kprobes symbol names to something more generic Change kprobe_emulate_none, kprobe_simulate_nop, and arm_kprobe_decode_init function names to something more appropriate for code being shared outside of the kprobes subsystem. Also, move the new arm_probes_decode_init declaration out of the kprobes.h include file and into the probes.h include file. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/kernel/kprobes-arm.c | 12 ++++++------ arch/arm/kernel/kprobes-thumb.c | 10 +++++----- arch/arm/kernel/kprobes.c | 2 +- arch/arm/kernel/kprobes.h | 2 -- arch/arm/kernel/probes.c | 6 +++--- arch/arm/kernel/probes.h | 6 ++++-- 6 files changed, 19 insertions(+), 19 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index 09a7b1e19c14..d01d9f56f583 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -302,10 +302,10 @@ emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, } const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { - [PROBES_EMULATE_NONE] = {.handler = kprobe_emulate_none}, - [PROBES_SIMULATE_NOP] = {.handler = kprobe_simulate_nop}, - [PROBES_PRELOAD_IMM] = {.handler = kprobe_simulate_nop}, - [PROBES_PRELOAD_REG] = {.handler = kprobe_simulate_nop}, + [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}, [PROBES_MRS] = {.handler = simulate_mrs}, [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, @@ -326,8 +326,8 @@ const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = { [PROBES_DATA_PROCESSING_IMM] = { .handler = emulate_rd12rn16rm0rs8_rwflags}, [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc}, - [PROBES_SEV] = {.handler = kprobe_emulate_none}, - [PROBES_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_SEV] = {.handler = probes_emulate_none}, + [PROBES_WFE] = {.handler = probes_simulate_nop}, [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc}, [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc}, diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 610d6932e9bf..2a73330fb19f 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -613,8 +613,8 @@ const union decode_action kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = { [PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags}, [PROBES_T16_PUSH] = {.decoder = t16_decode_push}, [PROBES_T16_POP] = {.decoder = t16_decode_pop}, - [PROBES_T16_SEV] = {.handler = kprobe_emulate_none}, - [PROBES_T16_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_T16_SEV] = {.handler = probes_emulate_none}, + [PROBES_T16_WFE] = {.handler = probes_simulate_nop}, [PROBES_T16_IT] = {.decoder = t16_decode_it}, [PROBES_T16_CMP] = {.handler = t16_emulate_loregs_rwflags}, [PROBES_T16_ADDSUB] = {.handler = t16_emulate_loregs_noitrwflags}, @@ -644,12 +644,12 @@ const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = { [PROBES_T32_MOVW] = {.handler = t32_emulate_rd8rn16_noflags}, [PROBES_T32_SAT] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, [PROBES_T32_BITFIELD] = {.handler = t32_emulate_rd8rn16_noflags}, - [PROBES_T32_SEV] = {.handler = kprobe_emulate_none}, - [PROBES_T32_WFE] = {.handler = kprobe_simulate_nop}, + [PROBES_T32_SEV] = {.handler = probes_emulate_none}, + [PROBES_T32_WFE] = {.handler = probes_simulate_nop}, [PROBES_T32_MRS] = {.handler = t32_simulate_mrs}, [PROBES_T32_BRANCH_COND] = {.decoder = t32_decode_cond_branch}, [PROBES_T32_BRANCH] = {.handler = t32_simulate_branch}, - [PROBES_T32_PLDI] = {.handler = kprobe_simulate_nop}, + [PROBES_T32_PLDI] = {.handler = probes_simulate_nop}, [PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal}, [PROBES_T32_LDRSTR] = {.handler = t32_emulate_ldrstr}, [PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags}, diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index b4a3028edffe..bfd7b8161c58 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -614,7 +614,7 @@ static struct undef_hook kprobes_arm_break_hook = { int __init arch_init_kprobes() { - arm_kprobe_decode_init(); + arm_probes_decode_init(); #ifdef CONFIG_THUMB2_KERNEL register_undef_hook(&kprobes_thumb16_break_hook); register_undef_hook(&kprobes_thumb32_break_hook); diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index d0530b15e473..e2ae4ed168cd 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -57,8 +57,6 @@ enum kprobe_insn arm_kprobe_decode_insn(probes_opcode_t, #endif -void __init arm_kprobe_decode_init(void); - #include "probes.h" #endif /* _ARM_KERNEL_KPROBES_H */ diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index c1cdc0d27e05..92d359a22843 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -76,7 +76,7 @@ void __init test_alu_write_pc_interworking(void) #endif /* !test_alu_write_pc_interworking */ -void __init arm_kprobe_decode_init(void) +void __init arm_probes_decode_init(void) { find_str_pc_offset(); test_load_write_pc_interworking(); @@ -175,13 +175,13 @@ probes_check_cc * const probes_condition_checks[16] = { }; -void __kprobes kprobe_simulate_nop(probes_opcode_t opcode, +void __kprobes probes_simulate_nop(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { } -void __kprobes kprobe_emulate_none(probes_opcode_t opcode, +void __kprobes probes_emulate_none(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs) { diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 5a0497f5a8f7..dedff8a5a924 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -24,6 +24,8 @@ #include #include "kprobes.h" +void __init arm_probes_decode_init(void); + #if __LINUX_ARM_ARCH__ >= 7 /* str_pc_offset is architecturally defined from ARMv7 onwards */ @@ -131,9 +133,9 @@ static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) } -void __kprobes kprobe_simulate_nop(probes_opcode_t, struct arch_specific_insn *, +void __kprobes probes_simulate_nop(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *regs); -void __kprobes kprobe_emulate_none(probes_opcode_t, struct arch_specific_insn *, +void __kprobes probes_emulate_none(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *regs); enum kprobe_insn __kprobes -- cgit v1.2.3 From 44a0a59c535004eac9f18210cb2ce10b23861630 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:23:42 -0500 Subject: ARM: Rename the shared kprobes/uprobe return value enum Change the name of kprobes_insn to probes_insn so it can be shared between kprobes and uprobes without confusion. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/kernel/kprobes-common.c | 2 +- arch/arm/kernel/kprobes-thumb.c | 16 ++++++++-------- arch/arm/kernel/kprobes.h | 14 ++++---------- arch/arm/kernel/probes-arm.c | 2 +- arch/arm/kernel/probes-thumb.c | 4 ++-- arch/arm/kernel/probes.h | 9 +++++++-- 6 files changed, 23 insertions(+), 24 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 08b55605c1ec..f151e15f566a 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -123,7 +123,7 @@ emulate_ldm_r3_15(probes_opcode_t insn, load_write_pc(regs->ARM_pc, regs); } -enum kprobe_insn __kprobes +enum probes_insn __kprobes kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *h) { diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index 2a73330fb19f..c271d5d2810c 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -66,7 +66,7 @@ t32_simulate_cond_branch(probes_opcode_t insn, regs->ARM_pc = pc + (offset * 2); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t32_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { @@ -142,11 +142,11 @@ t32_simulate_ldr_literal(probes_opcode_t insn, regs->uregs[rt] = rtv; } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t32_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { - enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi, d); + enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d); /* Fixup modified instruction to have halfwords in correct order...*/ insn = asi->insn[0]; @@ -402,7 +402,7 @@ t16_singlestep_it(probes_opcode_t insn, t16_simulate_it(insn, asi, regs); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t16_decode_it(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { @@ -420,7 +420,7 @@ t16_simulate_cond_branch(probes_opcode_t insn, regs->ARM_pc = pc + (offset * 2); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t16_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { @@ -510,7 +510,7 @@ t16_emulate_hiregs(probes_opcode_t insn, regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t16_decode_hiregs(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { @@ -538,7 +538,7 @@ t16_emulate_push(probes_opcode_t insn, ); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t16_decode_push(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { @@ -591,7 +591,7 @@ t16_emulate_pop_pc(probes_opcode_t insn, bx_write_pc(pc, regs); } -static enum kprobe_insn __kprobes +static enum probes_insn __kprobes t16_decode_pop(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *d) { diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index e2ae4ed168cd..3684fc9e27cc 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -30,28 +30,22 @@ struct decode_header; union decode_action; -enum kprobe_insn { - INSN_REJECTED, - INSN_GOOD, - INSN_GOOD_NO_SLOT -}; - -typedef enum kprobe_insn (kprobe_decode_insn_t)(probes_opcode_t, +typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); #ifdef CONFIG_THUMB2_KERNEL -enum kprobe_insn thumb16_kprobe_decode_insn(probes_opcode_t, +enum probes_insn thumb16_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); -enum kprobe_insn thumb32_kprobe_decode_insn(probes_opcode_t, +enum probes_insn thumb32_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); #else /* !CONFIG_THUMB2_KERNEL */ -enum kprobe_insn arm_kprobe_decode_insn(probes_opcode_t, +enum probes_insn arm_kprobe_decode_insn(probes_opcode_t, struct arch_specific_insn *, const union decode_action *); diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 3357a074597d..a9439e607ac0 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -723,7 +723,7 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, * if the work was put into it, but low return considering they * should also be very rare. */ -enum kprobe_insn __kprobes +enum probes_insn __kprobes arm_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index a15a79b7c9c5..d23ef009fe63 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -861,7 +861,7 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, regs->ARM_cpsr = it_advance(regs->ARM_cpsr); } -enum kprobe_insn __kprobes +enum probes_insn __kprobes thumb16_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { @@ -871,7 +871,7 @@ thumb16_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, actions); } -enum kprobe_insn __kprobes +enum probes_insn __kprobes thumb32_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index dedff8a5a924..870282a39261 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -138,7 +138,7 @@ void __kprobes probes_simulate_nop(probes_opcode_t, struct arch_specific_insn *, void __kprobes probes_emulate_none(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *regs); -enum kprobe_insn __kprobes +enum probes_insn __kprobes kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *h); @@ -313,7 +313,7 @@ union decode_item { int action; }; -typedef enum kprobe_insn (probes_custom_decode_t)(probes_opcode_t, +typedef enum probes_insn (probes_custom_decode_t)(probes_opcode_t, struct arch_specific_insn *, const struct decode_header *); @@ -391,6 +391,11 @@ struct decode_or { #define DECODE_OR(_mask, _value) \ DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0) +enum probes_insn { + INSN_REJECTED, + INSN_GOOD, + INSN_GOOD_NO_SLOT +}; struct decode_reject { struct decode_header header; -- cgit v1.2.3 From 47e190fafde49ff8ca732fa137e39cb2b8baba8c Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Thu, 6 Mar 2014 18:12:07 -0500 Subject: ARM: Change the remaining shared kprobes/uprobes symbols to something generic Any more ARM kprobes/uprobes symbols which have "kprobe" in the name must be changed to the more generic "probes" or other non-kprobes specific symbol. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/probes.h | 13 ++++++------- arch/arm/kernel/kprobes-common.c | 2 +- arch/arm/kernel/kprobes-test.c | 8 +++++--- arch/arm/kernel/kprobes.c | 10 ++++++---- arch/arm/kernel/kprobes.h | 21 ++++++++------------ arch/arm/kernel/probes-arm.c | 8 ++++---- arch/arm/kernel/probes-arm.h | 6 ++++++ arch/arm/kernel/probes-thumb.c | 18 ++++++++--------- arch/arm/kernel/probes-thumb.h | 10 ++++++++++ arch/arm/kernel/probes.c | 4 ++-- arch/arm/kernel/probes.h | 42 ++++++++++++---------------------------- 11 files changed, 69 insertions(+), 73 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index c4acf6c8a2d4..c37252c73ee5 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -19,26 +19,25 @@ #ifndef _ASM_PROBES_H #define _ASM_PROBES_H -struct kprobe; typedef u32 probes_opcode_t; struct arch_specific_insn; -typedef void (kprobe_insn_handler_t)(probes_opcode_t, +typedef void (probes_insn_handler_t)(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *); typedef unsigned long (probes_check_cc)(unsigned long); -typedef void (kprobe_insn_singlestep_t)(probes_opcode_t, +typedef void (probes_insn_singlestep_t)(probes_opcode_t, struct arch_specific_insn *, struct pt_regs *); -typedef void (kprobe_insn_fn_t)(void); +typedef void (probes_insn_fn_t)(void); /* Architecture specific copy of original instruction. */ struct arch_specific_insn { probes_opcode_t *insn; - kprobe_insn_handler_t *insn_handler; + probes_insn_handler_t *insn_handler; probes_check_cc *insn_check_cc; - kprobe_insn_singlestep_t *insn_singlestep; - kprobe_insn_fn_t *insn_fn; + probes_insn_singlestep_t *insn_singlestep; + probes_insn_fn_t *insn_fn; }; #endif diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index f151e15f566a..6159725597a1 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -127,7 +127,7 @@ enum probes_insn __kprobes kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, const struct decode_header *h) { - kprobe_insn_handler_t *handler = 0; + probes_insn_handler_t *handler = 0; unsigned reglist = insn & 0xffff; int is_ldm = insn & 0x100000; int rn = (insn >> 16) & 0xf; diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c index 4a774d40c946..c2fd06b4c389 100644 --- a/arch/arm/kernel/kprobes-test.c +++ b/arch/arm/kernel/kprobes-test.c @@ -207,6 +207,8 @@ #include #include "kprobes.h" +#include "probes-arm.h" +#include "probes-thumb.h" #include "kprobes-test.h" @@ -1610,7 +1612,7 @@ static int __init run_all_tests(void) goto out; pr_info("ARM instruction simulation\n"); - ret = run_test_cases(kprobe_arm_test_cases, kprobe_decode_arm_table); + ret = run_test_cases(kprobe_arm_test_cases, probes_decode_arm_table); if (ret) goto out; @@ -1633,13 +1635,13 @@ static int __init run_all_tests(void) pr_info("16-bit Thumb instruction simulation\n"); ret = run_test_cases(kprobe_thumb16_test_cases, - kprobe_decode_thumb16_table); + probes_decode_thumb16_table); if (ret) goto out; pr_info("32-bit Thumb instruction simulation\n"); ret = run_test_cases(kprobe_thumb32_test_cases, - kprobe_decode_thumb32_table); + probes_decode_thumb32_table); if (ret) goto out; #endif diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index bfd7b8161c58..468d4a980c6c 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -31,6 +31,8 @@ #include #include "kprobes.h" +#include "probes-arm.h" +#include "probes-thumb.h" #include "patch.h" #define MIN_STACK_SIZE(addr) \ @@ -69,10 +71,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) if (is_wide_instruction(insn)) { insn <<= 16; insn |= ((u16 *)addr)[1]; - decode_insn = thumb32_kprobe_decode_insn; + decode_insn = thumb32_probes_decode_insn; actions = kprobes_t32_actions; } else { - decode_insn = thumb16_kprobe_decode_insn; + decode_insn = thumb16_probes_decode_insn; actions = kprobes_t16_actions; } #else /* !CONFIG_THUMB2_KERNEL */ @@ -80,7 +82,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) if (addr & 0x3) return -EINVAL; insn = *p->addr; - decode_insn = arm_kprobe_decode_insn; + decode_insn = arm_probes_decode_insn; actions = kprobes_arm_actions; #endif @@ -99,7 +101,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) p->ainsn.insn[is] = tmp_insn[is]; flush_insns(p->ainsn.insn, sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE); - p->ainsn.insn_fn = (kprobe_insn_fn_t *) + p->ainsn.insn_fn = (probes_insn_fn_t *) ((uintptr_t)p->ainsn.insn | thumb); break; diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index 3684fc9e27cc..eee8089b1b93 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -19,6 +19,8 @@ #ifndef _ARM_KERNEL_KPROBES_H #define _ARM_KERNEL_KPROBES_H +#include "probes.h" + /* * These undefined instructions must be unique and * reserved solely for kprobes' use. @@ -27,8 +29,9 @@ #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 -struct decode_header; -union decode_action; +enum probes_insn __kprobes +kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, + const struct decode_header *h); typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, struct arch_specific_insn *, @@ -36,21 +39,13 @@ typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, #ifdef CONFIG_THUMB2_KERNEL -enum probes_insn thumb16_kprobe_decode_insn(probes_opcode_t, - struct arch_specific_insn *, - const union decode_action *); -enum probes_insn thumb32_kprobe_decode_insn(probes_opcode_t, - struct arch_specific_insn *, - const union decode_action *); +extern const union decode_action kprobes_t32_actions[]; +extern const union decode_action kprobes_t16_actions[]; #else /* !CONFIG_THUMB2_KERNEL */ -enum probes_insn arm_kprobe_decode_insn(probes_opcode_t, - struct arch_specific_insn *, - const union decode_action *); +extern const union decode_action kprobes_arm_actions[]; #endif -#include "probes.h" - #endif /* _ARM_KERNEL_KPROBES_H */ diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index a9439e607ac0..738e5fc58928 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -610,7 +610,7 @@ static const union decode_item arm_cccc_100x_table[] = { DECODE_END }; -const union decode_item kprobe_decode_arm_table[] = { +const union decode_item probes_decode_arm_table[] = { /* * Unconditional instructions * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx @@ -701,7 +701,7 @@ const union decode_item kprobe_decode_arm_table[] = { DECODE_END }; #ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_arm_table); +EXPORT_SYMBOL_GPL(probes_decode_arm_table); #endif static void __kprobes arm_singlestep(probes_opcode_t insn, @@ -724,11 +724,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, * should also be very rare. */ enum probes_insn __kprobes -arm_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +arm_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = arm_singlestep; asi->insn_check_cc = probes_condition_checks[insn>>28]; - return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false, + return probes_decode_insn(insn, asi, probes_decode_arm_table, false, actions); } diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index 9a9d379dbf33..7a5cce497a9b 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -64,4 +64,10 @@ void __kprobes simulate_mrs(probes_opcode_t opcode, void __kprobes simulate_mov_ipsp(probes_opcode_t opcode, struct arch_specific_insn *asi, struct pt_regs *regs); +extern const union decode_item probes_decode_arm_table[]; + +enum probes_insn arm_probes_decode_insn(probes_opcode_t, + struct arch_specific_insn *, + const union decode_action *actions); + #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index d23ef009fe63..eab440f6b2d4 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -1,5 +1,5 @@ /* - * arch/arm/kernel/kprobes-thumb.c + * arch/arm/kernel/probes-thumb.c * * Copyright (C) 2011 Jon Medhurst . * @@ -552,7 +552,7 @@ static const union decode_item t32_table_1111_1011_1[] = { DECODE_END }; -const union decode_item kprobe_decode_thumb32_table[] = { +const union decode_item probes_decode_thumb32_table[] = { /* * Load/store multiple instructions @@ -641,7 +641,7 @@ const union decode_item kprobe_decode_thumb32_table[] = { DECODE_END }; #ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_thumb32_table); +EXPORT_SYMBOL_GPL(probes_decode_thumb32_table); #endif static const union decode_item t16_table_1011[] = { @@ -696,7 +696,7 @@ static const union decode_item t16_table_1011[] = { DECODE_END }; -const union decode_item kprobe_decode_thumb16_table[] = { +const union decode_item probes_decode_thumb16_table[] = { /* * Shift (immediate), add, subtract, move, and compare @@ -833,7 +833,7 @@ const union decode_item kprobe_decode_thumb16_table[] = { DECODE_END }; #ifdef CONFIG_ARM_KPROBES_TEST_MODULE -EXPORT_SYMBOL_GPL(kprobe_decode_thumb16_table); +EXPORT_SYMBOL_GPL(probes_decode_thumb16_table); #endif static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) @@ -862,21 +862,21 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, } enum probes_insn __kprobes -thumb16_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = thumb16_singlestep; asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true, + return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true, actions); } enum probes_insn __kprobes -thumb32_kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_action *actions) { asi->insn_singlestep = thumb32_singlestep; asi->insn_check_cc = thumb_check_cc; - return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true, + return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true, actions); } diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h index 8d6b4eefa706..d6f67c1df7af 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/kernel/probes-thumb.h @@ -84,4 +84,14 @@ enum probes_t16_action { NUM_PROBES_T16_ACTIONS }; +extern const union decode_item probes_decode_thumb32_table[]; +extern const union decode_item probes_decode_thumb16_table[]; + +enum probes_insn __kprobes +thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, + const union decode_action *actions); +enum probes_insn __kprobes +thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, + const union decode_action *actions); + #endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index 92d359a22843..b6d9b855273c 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -340,7 +340,7 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { }; /* - * kprobe_decode_insn operates on data tables in order to decode an ARM + * probes_decode_insn operates on data tables in order to decode an ARM * architecture instruction onto which a kprobe has been placed. * * These instruction decoding tables are a concatenation of entries each @@ -383,7 +383,7 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { * */ int __kprobes -kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_item *table, bool thumb, const union decode_action *actions) { diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 870282a39261..0c72e544175d 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -21,11 +21,12 @@ #include #include -#include -#include "kprobes.h" +#include void __init arm_probes_decode_init(void); +extern probes_check_cc * const probes_condition_checks[16]; + #if __LINUX_ARM_ARCH__ >= 7 /* str_pc_offset is architecturally defined from ARMv7 onwards */ @@ -40,7 +41,6 @@ void __init find_str_pc_offset(void); #endif -struct decode_header; /* * Update ITSTATE after normal execution of an IT block instruction. @@ -133,15 +133,6 @@ static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) } -void __kprobes probes_simulate_nop(probes_opcode_t, struct arch_specific_insn *, - struct pt_regs *regs); -void __kprobes probes_emulate_none(probes_opcode_t, struct arch_specific_insn *, - struct pt_regs *regs); - -enum probes_insn __kprobes -kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, - const struct decode_header *h); - /* * Test if load/store instructions writeback the address register. * if P (bit 24) == 0 or W (bit 21) == 1 @@ -150,7 +141,7 @@ kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, /* * The following definitions and macros are used to build instruction - * decoding tables for use by kprobe_decode_insn. + * decoding tables for use by probes_decode_insn. * * These tables are a concatenation of entries each of which consist of one of * the decode_* structs. All of the fields in every type of decode structure @@ -313,12 +304,13 @@ union decode_item { int action; }; +struct decode_header; typedef enum probes_insn (probes_custom_decode_t)(probes_opcode_t, struct arch_specific_insn *, const struct decode_header *); union decode_action { - kprobe_insn_handler_t *handler; + probes_insn_handler_t *handler; probes_custom_decode_t *decoder; }; @@ -404,22 +396,12 @@ struct decode_reject { #define DECODE_REJECT(_mask, _value) \ DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0) +probes_insn_handler_t probes_simulate_nop; +probes_insn_handler_t probes_emulate_none; -#ifdef CONFIG_THUMB2_KERNEL -extern const union decode_item kprobe_decode_thumb16_table[]; -extern const union decode_item kprobe_decode_thumb32_table[]; -extern const union decode_action kprobes_t32_actions[]; -extern const union decode_action kprobes_t16_actions[]; -#else -extern const union decode_item kprobe_decode_arm_table[]; -extern const union decode_action kprobes_arm_actions[]; -#endif - -extern probes_check_cc * const probes_condition_checks[16]; - - -int kprobe_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb16, - const union decode_action *actions); +int __kprobes +probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, + const union decode_item *table, bool thumb, + const union decode_action *actions); #endif -- cgit v1.2.3 From 602cd2609eee92d338a83e400774e97c60535ba2 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:40:12 -0500 Subject: ARM: Add an emulate flag to the kprobes/uprobes instruction decode functions Add an emulate flag into the instruction interpreter, primarily for uprobes support. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/kernel/kprobes.c | 2 +- arch/arm/kernel/kprobes.h | 1 + arch/arm/kernel/probes-arm.c | 4 ++-- arch/arm/kernel/probes-arm.h | 2 +- arch/arm/kernel/probes-thumb.c | 8 ++++---- arch/arm/kernel/probes-thumb.h | 4 ++-- arch/arm/kernel/probes.c | 18 +++++++++++++----- arch/arm/kernel/probes.h | 2 +- 8 files changed, 25 insertions(+), 16 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 468d4a980c6c..8795f9f819d5 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c @@ -89,7 +89,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) p->opcode = insn; p->ainsn.insn = tmp_insn; - switch ((*decode_insn)(insn, &p->ainsn, actions)) { + switch ((*decode_insn)(insn, &p->ainsn, true, actions)) { case INSN_REJECTED: /* not supported */ return -EINVAL; diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index eee8089b1b93..d0a24b73bcfa 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -35,6 +35,7 @@ kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, struct arch_specific_insn *, + bool, const union decode_action *); #ifdef CONFIG_THUMB2_KERNEL diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 738e5fc58928..8e7fde876521 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -725,10 +725,10 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, */ enum probes_insn __kprobes arm_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_action *actions) + bool emulate, const union decode_action *actions) { 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, - actions); + emulate, actions); } diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index 7a5cce497a9b..ea614dc5aaa3 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -67,7 +67,7 @@ void __kprobes simulate_mov_ipsp(probes_opcode_t opcode, extern const union decode_item probes_decode_arm_table[]; enum probes_insn arm_probes_decode_insn(probes_opcode_t, - struct arch_specific_insn *, + struct arch_specific_insn *, bool emulate, const union decode_action *actions); #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index eab440f6b2d4..23e2cbdb37cb 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -863,20 +863,20 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, enum probes_insn __kprobes thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_action *actions) + bool emulate, const union decode_action *actions) { asi->insn_singlestep = thumb16_singlestep; asi->insn_check_cc = thumb_check_cc; return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true, - actions); + emulate, actions); } enum probes_insn __kprobes thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_action *actions) + bool emulate, const union decode_action *actions) { asi->insn_singlestep = thumb32_singlestep; asi->insn_check_cc = thumb_check_cc; return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true, - actions); + emulate, actions); } diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h index d6f67c1df7af..65e4250e9b78 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/kernel/probes-thumb.h @@ -89,9 +89,9 @@ extern const union decode_item probes_decode_thumb16_table[]; enum probes_insn __kprobes thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_action *actions); + bool emulate, const union decode_action *actions); enum probes_insn __kprobes thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_action *actions); + bool emulate, const union decode_action *actions); #endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index b6d9b855273c..f9dff12cf85c 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -257,7 +257,7 @@ set_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, * non-zero value, the corresponding nibble in pinsn is validated and modified * according to the type. */ -static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs) +static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs, bool modify) { probes_opcode_t insn = *pinsn; probes_opcode_t mask = 0xf; /* Start at least significant nibble */ @@ -323,7 +323,9 @@ static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs) insn |= new_bits & mask; } - *pinsn = insn; + if (modify) + *pinsn = insn; + return true; reject: @@ -385,13 +387,14 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { int __kprobes probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, const union decode_item *table, bool thumb, - const union decode_action *actions) + bool emulate, const union decode_action *actions) { const struct decode_header *h = (struct decode_header *)table; const struct decode_header *next; bool matched = false; - insn = prepare_emulated_insn(insn, asi, thumb); + if (emulate) + insn = prepare_emulated_insn(insn, asi, thumb); for (;; h = next) { enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; @@ -406,7 +409,7 @@ probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, if (!matched && (insn & h->mask.bits) != h->value.bits) continue; - if (!decode_regs(&insn, regs)) + if (!decode_regs(&insn, regs, emulate)) return INSN_REJECTED; switch (type) { @@ -430,6 +433,11 @@ probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, case DECODE_TYPE_EMULATE: { struct decode_emulate *d = (struct decode_emulate *)h; + + if (!emulate) + return actions[d->handler.action].decoder(insn, + asi, h); + asi->insn_handler = actions[d->handler.action].handler; set_emulated_insn(insn, asi, thumb); return INSN_GOOD; diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 0c72e544175d..33cc30c50cf5 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -401,7 +401,7 @@ probes_insn_handler_t probes_emulate_none; int __kprobes probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, - const union decode_item *table, bool thumb, + const union decode_item *table, bool thumb, bool emulate, const union decode_action *actions); #endif -- cgit v1.2.3 From b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97 Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Wed, 5 Mar 2014 21:41:29 -0500 Subject: ARM: Make arch_specific_insn a define for new arch_probes_insn structure Because the common underlying code for ARM kprobes and uprobes needs to share a common architecrure-specific context structure, and because the generic kprobes include file insists on defining this to a dummy structure when kprobes is not configured, a new common structure is required which can exist when uprobes is configured without kprobes. In this case kprobes will define a dummy structure, but without the define aliasing the two structure tags it will not affect uprobes and the shared probes code. Signed-off-by: David A. Long Acked-by: Jon Medhurst --- arch/arm/include/asm/kprobes.h | 2 ++ arch/arm/include/asm/probes.h | 8 ++--- arch/arm/kernel/kprobes-arm.c | 16 ++++----- arch/arm/kernel/kprobes-common.c | 14 ++++---- arch/arm/kernel/kprobes-thumb.c | 70 ++++++++++++++++++++-------------------- arch/arm/kernel/kprobes.h | 4 +-- arch/arm/kernel/probes-arm.c | 14 ++++---- arch/arm/kernel/probes-arm.h | 12 +++---- arch/arm/kernel/probes-thumb.c | 8 ++--- arch/arm/kernel/probes-thumb.h | 4 +-- arch/arm/kernel/probes.c | 10 +++--- arch/arm/kernel/probes.h | 4 +-- 12 files changed, 84 insertions(+), 82 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index 6e1046661f07..49fa0dfaad33 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h @@ -31,6 +31,8 @@ typedef u32 kprobe_opcode_t; struct kprobe; #include +#define arch_specific_insn arch_probes_insn + struct prev_kprobe { struct kprobe *kp; unsigned int status; diff --git a/arch/arm/include/asm/probes.h b/arch/arm/include/asm/probes.h index c37252c73ee5..806cfe622a9e 100644 --- a/arch/arm/include/asm/probes.h +++ b/arch/arm/include/asm/probes.h @@ -21,18 +21,18 @@ typedef u32 probes_opcode_t; -struct arch_specific_insn; +struct arch_probes_insn; typedef void (probes_insn_handler_t)(probes_opcode_t, - struct arch_specific_insn *, + struct arch_probes_insn *, struct pt_regs *); typedef unsigned long (probes_check_cc)(unsigned long); typedef void (probes_insn_singlestep_t)(probes_opcode_t, - struct arch_specific_insn *, + struct arch_probes_insn *, struct pt_regs *); typedef void (probes_insn_fn_t)(void); /* Architecture specific copy of original instruction. */ -struct arch_specific_insn { +struct arch_probes_insn { probes_opcode_t *insn; probes_insn_handler_t *insn_handler; probes_check_cc *insn_check_cc; diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c index d01d9f56f583..ac300c60d656 100644 --- a/arch/arm/kernel/kprobes-arm.c +++ b/arch/arm/kernel/kprobes-arm.c @@ -74,7 +74,7 @@ static void __kprobes emulate_ldrdstrd(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; int rt = (insn >> 12) & 0xf; @@ -103,7 +103,7 @@ emulate_ldrdstrd(probes_opcode_t insn, static void __kprobes emulate_ldr(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; int rt = (insn >> 12) & 0xf; @@ -133,7 +133,7 @@ emulate_ldr(probes_opcode_t insn, static void __kprobes emulate_str(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset; unsigned long rnpc = regs->ARM_pc + 4; @@ -160,7 +160,7 @@ emulate_str(probes_opcode_t insn, static void __kprobes emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 4; int rd = (insn >> 12) & 0xf; @@ -195,7 +195,7 @@ emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, static void __kprobes emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; @@ -222,7 +222,7 @@ emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn, static void __kprobes emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 16) & 0xf; @@ -252,7 +252,7 @@ emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn, static void __kprobes emulate_rd12rm0_noflags_nopc(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; int rm = insn & 0xf; @@ -272,7 +272,7 @@ emulate_rd12rm0_noflags_nopc(probes_opcode_t insn, static void __kprobes emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { int rdlo = (insn >> 12) & 0xf; diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c index 6159725597a1..c311ed94ff1c 100644 --- a/arch/arm/kernel/kprobes-common.c +++ b/arch/arm/kernel/kprobes-common.c @@ -18,7 +18,7 @@ static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { int rn = (insn >> 16) & 0xf; @@ -60,7 +60,7 @@ static void __kprobes simulate_ldm1stm1(probes_opcode_t insn, } static void __kprobes simulate_stm1_pc(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long addr = regs->ARM_pc - 4; @@ -71,7 +71,7 @@ static void __kprobes simulate_stm1_pc(probes_opcode_t insn, } static void __kprobes simulate_ldm1_pc(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { simulate_ldm1stm1(insn, asi, regs); @@ -80,7 +80,7 @@ static void __kprobes simulate_ldm1_pc(probes_opcode_t insn, static void __kprobes emulate_generic_r0_12_noflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { register void *rregs asm("r1") = regs; register void *rfn asm("lr") = asi->insn_fn; @@ -108,7 +108,7 @@ emulate_generic_r0_12_noflags(probes_opcode_t insn, static void __kprobes emulate_generic_r2_14_noflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { emulate_generic_r0_12_noflags(insn, asi, (struct pt_regs *)(regs->uregs+2)); @@ -116,7 +116,7 @@ emulate_generic_r2_14_noflags(probes_opcode_t insn, static void __kprobes emulate_ldm_r3_15(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { emulate_generic_r0_12_noflags(insn, asi, (struct pt_regs *)(regs->uregs+3)); @@ -124,7 +124,7 @@ emulate_ldm_r3_15(probes_opcode_t insn, } enum probes_insn __kprobes -kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, +kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *h) { probes_insn_handler_t *handler = 0; diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c index c271d5d2810c..6619188619ae 100644 --- a/arch/arm/kernel/kprobes-thumb.c +++ b/arch/arm/kernel/kprobes-thumb.c @@ -24,7 +24,7 @@ static void __kprobes t32_simulate_table_branch(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; int rn = (insn >> 16) & 0xf; @@ -44,7 +44,7 @@ t32_simulate_table_branch(probes_opcode_t insn, static void __kprobes t32_simulate_mrs(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; unsigned long mask = 0xf8ff03df; /* Mask out execution state */ @@ -53,7 +53,7 @@ t32_simulate_mrs(probes_opcode_t insn, static void __kprobes t32_simulate_cond_branch(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -67,7 +67,7 @@ t32_simulate_cond_branch(probes_opcode_t insn, } static enum probes_insn __kprobes -t32_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, +t32_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { int cc = (insn >> 22) & 0xf; @@ -78,7 +78,7 @@ t32_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t32_simulate_branch(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; @@ -106,7 +106,7 @@ t32_simulate_branch(probes_opcode_t insn, static void __kprobes t32_simulate_ldr_literal(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long addr = regs->ARM_pc & ~3; int rt = (insn >> 12) & 0xf; @@ -143,7 +143,7 @@ t32_simulate_ldr_literal(probes_opcode_t insn, } static enum probes_insn __kprobes -t32_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, +t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d); @@ -158,7 +158,7 @@ t32_decode_ldmstm(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t32_emulate_ldrdstrd(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc & ~3; int rt1 = (insn >> 12) & 0xf; @@ -185,7 +185,7 @@ t32_emulate_ldrdstrd(probes_opcode_t insn, static void __kprobes t32_emulate_ldrstr(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rt = (insn >> 12) & 0xf; int rn = (insn >> 16) & 0xf; @@ -211,7 +211,7 @@ t32_emulate_ldrstr(probes_opcode_t insn, static void __kprobes t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; @@ -238,7 +238,7 @@ t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn, static void __kprobes t32_emulate_rd8pc16_noflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc; int rd = (insn >> 8) & 0xf; @@ -258,7 +258,7 @@ t32_emulate_rd8pc16_noflags(probes_opcode_t insn, static void __kprobes t32_emulate_rd8rn16_noflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 8) & 0xf; int rn = (insn >> 16) & 0xf; @@ -278,7 +278,7 @@ t32_emulate_rd8rn16_noflags(probes_opcode_t insn, static void __kprobes t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { int rdlo = (insn >> 12) & 0xf; @@ -306,7 +306,7 @@ t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn, static void __kprobes t16_simulate_bxblx(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; int rm = (insn >> 3) & 0xf; @@ -320,7 +320,7 @@ t16_simulate_bxblx(probes_opcode_t insn, static void __kprobes t16_simulate_ldr_literal(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3); long index = insn & 0xff; @@ -330,7 +330,7 @@ t16_simulate_ldr_literal(probes_opcode_t insn, static void __kprobes t16_simulate_ldrstr_sp_relative(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long* base = (unsigned long *)regs->ARM_sp; long index = insn & 0xff; @@ -343,7 +343,7 @@ t16_simulate_ldrstr_sp_relative(probes_opcode_t insn, static void __kprobes t16_simulate_reladr(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long base = (insn & 0x800) ? regs->ARM_sp : ((regs->ARM_pc + 2) & ~3); @@ -354,7 +354,7 @@ t16_simulate_reladr(probes_opcode_t insn, static void __kprobes t16_simulate_add_sp_imm(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { long imm = insn & 0x7f; if (insn & 0x80) /* SUB */ @@ -365,7 +365,7 @@ t16_simulate_add_sp_imm(probes_opcode_t insn, static void __kprobes t16_simulate_cbz(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rn = insn & 0x7; probes_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; @@ -379,7 +379,7 @@ t16_simulate_cbz(probes_opcode_t insn, static void __kprobes t16_simulate_it(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { /* * The 8 IT state bits are split into two parts in CPSR: @@ -396,14 +396,14 @@ t16_simulate_it(probes_opcode_t insn, static void __kprobes t16_singlestep_it(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 2; t16_simulate_it(insn, asi, regs); } static enum probes_insn __kprobes -t16_decode_it(probes_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_it(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { asi->insn_singlestep = t16_singlestep_it; @@ -412,7 +412,7 @@ t16_decode_it(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t16_simulate_cond_branch(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; long offset = insn & 0x7f; @@ -421,7 +421,7 @@ t16_simulate_cond_branch(probes_opcode_t insn, } static enum probes_insn __kprobes -t16_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { int cc = (insn >> 8) & 0xf; @@ -432,7 +432,7 @@ t16_decode_cond_branch(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t16_simulate_branch(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; long offset = insn & 0x3ff; @@ -442,7 +442,7 @@ t16_simulate_branch(probes_opcode_t insn, static unsigned long __kprobes t16_emulate_loregs(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long oldcpsr = regs->ARM_cpsr; unsigned long newcpsr; @@ -465,14 +465,14 @@ t16_emulate_loregs(probes_opcode_t insn, static void __kprobes t16_emulate_loregs_rwflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs); } static void __kprobes t16_emulate_loregs_noitrwflags(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long cpsr = t16_emulate_loregs(insn, asi, regs); if (!in_it_block(cpsr)) @@ -481,7 +481,7 @@ t16_emulate_loregs_noitrwflags(probes_opcode_t insn, static void __kprobes t16_emulate_hiregs(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { unsigned long pc = regs->ARM_pc + 2; int rdn = (insn & 0x7) | ((insn & 0x80) >> 4); @@ -511,7 +511,7 @@ t16_emulate_hiregs(probes_opcode_t insn, } static enum probes_insn __kprobes -t16_decode_hiregs(probes_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { insn &= ~0x00ff; @@ -523,7 +523,7 @@ t16_decode_hiregs(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t16_emulate_push(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( "ldr r9, [%[regs], #13*4] \n\t" @@ -539,7 +539,7 @@ t16_emulate_push(probes_opcode_t insn, } static enum probes_insn __kprobes -t16_decode_push(probes_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { /* @@ -555,7 +555,7 @@ t16_decode_push(probes_opcode_t insn, struct arch_specific_insn *asi, static void __kprobes t16_emulate_pop_nopc(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { __asm__ __volatile__ ( "ldr r9, [%[regs], #13*4] \n\t" @@ -572,7 +572,7 @@ t16_emulate_pop_nopc(probes_opcode_t insn, static void __kprobes t16_emulate_pop_pc(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { register unsigned long pc asm("r8"); @@ -592,7 +592,7 @@ t16_emulate_pop_pc(probes_opcode_t insn, } static enum probes_insn __kprobes -t16_decode_pop(probes_opcode_t insn, struct arch_specific_insn *asi, +t16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *d) { /* diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h index d0a24b73bcfa..9a2712ecefc3 100644 --- a/arch/arm/kernel/kprobes.h +++ b/arch/arm/kernel/kprobes.h @@ -30,11 +30,11 @@ #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 enum probes_insn __kprobes -kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi, +kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_probes_insn *asi, const struct decode_header *h); typedef enum probes_insn (kprobe_decode_insn_t)(probes_opcode_t, - struct arch_specific_insn *, + struct arch_probes_insn *, bool, const union decode_action *); diff --git a/arch/arm/kernel/probes-arm.c b/arch/arm/kernel/probes-arm.c index 8e7fde876521..51a13a027989 100644 --- a/arch/arm/kernel/probes-arm.c +++ b/arch/arm/kernel/probes-arm.c @@ -58,7 +58,7 @@ */ void __kprobes simulate_bbl(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { long iaddr = (long) regs->ARM_pc - 4; int disp = branch_displacement(insn); @@ -70,7 +70,7 @@ void __kprobes simulate_bbl(probes_opcode_t insn, } void __kprobes simulate_blx1(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { long iaddr = (long) regs->ARM_pc - 4; int disp = branch_displacement(insn); @@ -81,7 +81,7 @@ void __kprobes simulate_blx1(probes_opcode_t insn, } void __kprobes simulate_blx2bx(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rm = insn & 0xf; long rmv = regs->uregs[rm]; @@ -96,7 +96,7 @@ void __kprobes simulate_blx2bx(probes_opcode_t insn, } void __kprobes simulate_mrs(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { int rd = (insn >> 12) & 0xf; unsigned long mask = 0xf8ff03df; /* Mask out execution state */ @@ -104,7 +104,7 @@ void __kprobes simulate_mrs(probes_opcode_t insn, } void __kprobes simulate_mov_ipsp(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->uregs[12] = regs->uregs[13]; } @@ -705,7 +705,7 @@ EXPORT_SYMBOL_GPL(probes_decode_arm_table); #endif static void __kprobes arm_singlestep(probes_opcode_t insn, - struct arch_specific_insn *asi, struct pt_regs *regs) + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 4; asi->insn_handler(insn, asi, regs); @@ -724,7 +724,7 @@ static void __kprobes arm_singlestep(probes_opcode_t insn, * should also be very rare. */ enum probes_insn __kprobes -arm_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool emulate, const union decode_action *actions) { asi->insn_singlestep = arm_singlestep; diff --git a/arch/arm/kernel/probes-arm.h b/arch/arm/kernel/probes-arm.h index ea614dc5aaa3..ace6572f6e26 100644 --- a/arch/arm/kernel/probes-arm.h +++ b/arch/arm/kernel/probes-arm.h @@ -54,20 +54,20 @@ enum probes_arm_action { }; void __kprobes simulate_bbl(probes_opcode_t opcode, - struct arch_specific_insn *asi, struct pt_regs *regs); + struct arch_probes_insn *asi, struct pt_regs *regs); void __kprobes simulate_blx1(probes_opcode_t opcode, - struct arch_specific_insn *asi, struct pt_regs *regs); + struct arch_probes_insn *asi, struct pt_regs *regs); void __kprobes simulate_blx2bx(probes_opcode_t opcode, - struct arch_specific_insn *asi, struct pt_regs *regs); + struct arch_probes_insn *asi, struct pt_regs *regs); void __kprobes simulate_mrs(probes_opcode_t opcode, - struct arch_specific_insn *asi, struct pt_regs *regs); + struct arch_probes_insn *asi, struct pt_regs *regs); void __kprobes simulate_mov_ipsp(probes_opcode_t opcode, - struct arch_specific_insn *asi, struct pt_regs *regs); + struct arch_probes_insn *asi, struct pt_regs *regs); extern const union decode_item probes_decode_arm_table[]; enum probes_insn arm_probes_decode_insn(probes_opcode_t, - struct arch_specific_insn *, bool emulate, + struct arch_probes_insn *, bool emulate, const union decode_action *actions); #endif diff --git a/arch/arm/kernel/probes-thumb.c b/arch/arm/kernel/probes-thumb.c index 23e2cbdb37cb..4131351e812f 100644 --- a/arch/arm/kernel/probes-thumb.c +++ b/arch/arm/kernel/probes-thumb.c @@ -844,7 +844,7 @@ static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) } static void __kprobes thumb16_singlestep(probes_opcode_t opcode, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 2; @@ -853,7 +853,7 @@ static void __kprobes thumb16_singlestep(probes_opcode_t opcode, } static void __kprobes thumb32_singlestep(probes_opcode_t opcode, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { regs->ARM_pc += 4; @@ -862,7 +862,7 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode, } enum probes_insn __kprobes -thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool emulate, const union decode_action *actions) { asi->insn_singlestep = thumb16_singlestep; @@ -872,7 +872,7 @@ thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, } enum probes_insn __kprobes -thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool emulate, const union decode_action *actions) { asi->insn_singlestep = thumb32_singlestep; diff --git a/arch/arm/kernel/probes-thumb.h b/arch/arm/kernel/probes-thumb.h index 65e4250e9b78..7c6f6ebe514f 100644 --- a/arch/arm/kernel/probes-thumb.h +++ b/arch/arm/kernel/probes-thumb.h @@ -88,10 +88,10 @@ extern const union decode_item probes_decode_thumb32_table[]; extern const union decode_item probes_decode_thumb16_table[]; enum probes_insn __kprobes -thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool emulate, const union decode_action *actions); enum probes_insn __kprobes -thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool emulate, const union decode_action *actions); #endif diff --git a/arch/arm/kernel/probes.c b/arch/arm/kernel/probes.c index f9dff12cf85c..b41873f33e69 100644 --- a/arch/arm/kernel/probes.c +++ b/arch/arm/kernel/probes.c @@ -176,13 +176,13 @@ probes_check_cc * const probes_condition_checks[16] = { void __kprobes probes_simulate_nop(probes_opcode_t opcode, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { } void __kprobes probes_emulate_none(probes_opcode_t opcode, - struct arch_specific_insn *asi, + struct arch_probes_insn *asi, struct pt_regs *regs) { asi->insn_fn(); @@ -196,7 +196,7 @@ void __kprobes probes_emulate_none(probes_opcode_t opcode, * emulation handler is called. */ static probes_opcode_t __kprobes -prepare_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +prepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool thumb) { #ifdef CONFIG_THUMB2_KERNEL @@ -221,7 +221,7 @@ prepare_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, * prepare_emulated_insn */ static void __kprobes -set_emulated_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +set_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi, bool thumb) { #ifdef CONFIG_THUMB2_KERNEL @@ -385,7 +385,7 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = { * */ int __kprobes -probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +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) { diff --git a/arch/arm/kernel/probes.h b/arch/arm/kernel/probes.h index 33cc30c50cf5..dba9f2466a93 100644 --- a/arch/arm/kernel/probes.h +++ b/arch/arm/kernel/probes.h @@ -306,7 +306,7 @@ union decode_item { struct decode_header; typedef enum probes_insn (probes_custom_decode_t)(probes_opcode_t, - struct arch_specific_insn *, + struct arch_probes_insn *, const struct decode_header *); union decode_action { @@ -400,7 +400,7 @@ probes_insn_handler_t probes_simulate_nop; probes_insn_handler_t probes_emulate_none; int __kprobes -probes_decode_insn(probes_opcode_t insn, struct arch_specific_insn *asi, +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); -- cgit v1.2.3 From c7edc9e326d53ca5ef9bed82de0740c6b107d55b Mon Sep 17 00:00:00 2001 From: "David A. Long" Date: Fri, 7 Mar 2014 11:23:04 -0500 Subject: ARM: add uprobes support Using Rabin Vincent's ARM uprobes patches as a base, enable uprobes support on ARM. Caveats: - Thumb is not supported Signed-off-by: Rabin Vincent Signed-off-by: David A. Long --- arch/arm/Kconfig | 3 + arch/arm/include/asm/ptrace.h | 6 + arch/arm/include/asm/thread_info.h | 5 +- arch/arm/include/asm/uprobes.h | 45 +++++++ arch/arm/kernel/Makefile | 1 + arch/arm/kernel/signal.c | 4 + arch/arm/kernel/uprobes-arm.c | 234 +++++++++++++++++++++++++++++++++++++ arch/arm/kernel/uprobes.c | 210 +++++++++++++++++++++++++++++++++ arch/arm/kernel/uprobes.h | 35 ++++++ 9 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/uprobes.h create mode 100644 arch/arm/kernel/uprobes-arm.c create mode 100644 arch/arm/kernel/uprobes.c create mode 100644 arch/arm/kernel/uprobes.h (limited to 'arch/arm') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index e25419817791..4d05bb93714a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -207,6 +207,9 @@ config ZONE_DMA config NEED_DMA_MAP_STATE def_bool y +config ARCH_SUPPORTS_UPROBES + def_bool y + config ARCH_HAS_DMA_SET_COHERENT_MASK bool diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 04c99f36ff7f..ee688b0a13c3 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -80,6 +80,12 @@ static inline long regs_return_value(struct pt_regs *regs) #define instruction_pointer(regs) (regs)->ARM_pc +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + instruction_pointer(regs) = val; +} + #ifdef CONFIG_SMP extern unsigned long profile_pc(struct pt_regs *regs); #else diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 71a06b293489..f989d7c22dc5 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -153,6 +153,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define TIF_SIGPENDING 0 #define TIF_NEED_RESCHED 1 #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ +#define TIF_UPROBE 7 #define TIF_SYSCALL_TRACE 8 #define TIF_SYSCALL_AUDIT 9 #define TIF_SYSCALL_TRACEPOINT 10 @@ -165,6 +166,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) +#define _TIF_UPROBE (1 << TIF_UPROBE) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) @@ -178,7 +180,8 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, /* * Change these and you break ASM code in entry-common.S */ -#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_RESUME) +#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ + _TIF_NOTIFY_RESUME | _TIF_UPROBE) #endif /* __KERNEL__ */ #endif /* __ASM_ARM_THREAD_INFO_H */ diff --git a/arch/arm/include/asm/uprobes.h b/arch/arm/include/asm/uprobes.h new file mode 100644 index 000000000000..9472c20b7d49 --- /dev/null +++ b/arch/arm/include/asm/uprobes.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 Rabin Vincent + * + * 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. + */ + +#ifndef _ASM_UPROBES_H +#define _ASM_UPROBES_H + +#include +#include + +typedef u32 uprobe_opcode_t; + +#define MAX_UINSN_BYTES 4 +#define UPROBE_XOL_SLOT_BYTES 64 + +#define UPROBE_SWBP_ARM_INSN 0xe7f001f9 +#define UPROBE_SS_ARM_INSN 0xe7f001fa +#define UPROBE_SWBP_INSN __opcode_to_mem_arm(UPROBE_SWBP_ARM_INSN) +#define UPROBE_SWBP_INSN_SIZE 4 + +struct arch_uprobe_task { + u32 backup; + unsigned long saved_trap_no; +}; + +struct arch_uprobe { + u8 insn[MAX_UINSN_BYTES]; + unsigned long ixol[2]; + uprobe_opcode_t bpinsn; + bool simulate; + u32 pcreg; + void (*prehandler)(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs); + void (*posthandler)(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs); + struct arch_probes_insn asi; +}; + +#endif diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index bb739f28dd80..a766bcbaf8ad 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -50,6 +50,7 @@ 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 diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 04d63880037f..bd1983437205 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -590,6 +591,9 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) return restart; } syscall = 0; + } else if (thread_flags & _TIF_UPROBE) { + clear_thread_flag(TIF_UPROBE); + uprobe_notify_resume(regs); } else { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/kernel/uprobes-arm.c new file mode 100644 index 000000000000..d3b655ff17da --- /dev/null +++ b/arch/arm/kernel/uprobes-arm.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2012 Rabin Vincent + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "probes.h" +#include "probes-arm.h" +#include "uprobes.h" + +static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs) +{ + probes_opcode_t insn = __mem_to_opcode_arm(*pinsn); + probes_opcode_t temp; + probes_opcode_t mask; + int freereg; + u32 free = 0xffff; + u32 regs; + + for (regs = oregs; regs; regs >>= 4, insn >>= 4) { + if ((regs & 0xf) == REG_TYPE_NONE) + continue; + + free &= ~(1 << (insn & 0xf)); + } + + /* No PC, no problem */ + if (free & (1 << 15)) + return 15; + + if (!free) + return -1; + + /* + * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would + * pick LR instead of R1. + */ + freereg = free = fls(free) - 1; + + temp = __mem_to_opcode_arm(*pinsn); + insn = temp; + regs = oregs; + mask = 0xf; + + for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) { + if ((regs & 0xf) == REG_TYPE_NONE) + continue; + + if ((temp & 0xf) != 15) + continue; + + insn &= ~mask; + insn |= free & mask; + } + + *pinsn = __opcode_to_mem_arm(insn); + return freereg; +} + +static void uprobe_set_pc(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs) +{ + u32 pcreg = auprobe->pcreg; + + autask->backup = regs->uregs[pcreg]; + regs->uregs[pcreg] = regs->ARM_pc + 8; +} + +static void uprobe_unset_pc(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs) +{ + /* PC will be taken care of by common code */ + regs->uregs[auprobe->pcreg] = autask->backup; +} + +static void uprobe_aluwrite_pc(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs) +{ + u32 pcreg = auprobe->pcreg; + + alu_write_pc(regs->uregs[pcreg], regs); + regs->uregs[pcreg] = autask->backup; +} + +static void uprobe_write_pc(struct arch_uprobe *auprobe, + struct arch_uprobe_task *autask, + struct pt_regs *regs) +{ + u32 pcreg = auprobe->pcreg; + + load_write_pc(regs->uregs[pcreg], regs); + regs->uregs[pcreg] = autask->backup; +} + +enum probes_insn +decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *d) +{ + struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, + asi); + struct decode_emulate *decode = (struct decode_emulate *) d; + u32 regs = decode->header.type_regs.bits >> DECODE_TYPE_BITS; + int reg; + + reg = uprobes_substitute_pc(&auprobe->ixol[0], regs); + if (reg == 15) + return INSN_GOOD; + + if (reg == -1) + return INSN_REJECTED; + + auprobe->pcreg = reg; + auprobe->prehandler = uprobe_set_pc; + auprobe->posthandler = uprobe_unset_pc; + + return INSN_GOOD; +} + +enum probes_insn +decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *d, bool alu) +{ + struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, + asi); + enum probes_insn ret = decode_pc_ro(insn, asi, d); + + if (((insn >> 12) & 0xf) == 15) + auprobe->posthandler = alu ? uprobe_aluwrite_pc + : uprobe_write_pc; + + return ret; +} + +enum probes_insn +decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *d) +{ + return decode_wb_pc(insn, asi, d, true); +} + +enum probes_insn +decode_ldr(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *d) +{ + return decode_wb_pc(insn, asi, d, false); +} + +enum probes_insn +uprobe_decode_ldmstm(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *d) +{ + struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, + asi); + unsigned reglist = insn & 0xffff; + int rn = (insn >> 16) & 0xf; + int lbit = insn & (1 << 20); + unsigned used = reglist | (1 << rn); + + if (rn == 15) + return INSN_REJECTED; + + if (!(used & (1 << 15))) + return INSN_GOOD; + + if (used & (1 << 14)) + return INSN_REJECTED; + + /* Use LR instead of PC */ + insn ^= 0xc000; + + auprobe->pcreg = 14; + auprobe->ixol[0] = __opcode_to_mem_arm(insn); + + auprobe->prehandler = uprobe_set_pc; + if (lbit) + auprobe->posthandler = uprobe_write_pc; + else + auprobe->posthandler = uprobe_unset_pc; + + return INSN_GOOD; +} + +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}, + [PROBES_MRS] = {.handler = simulate_mrs}, + [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx}, + [PROBES_CLZ] = {.handler = probes_simulate_nop}, + [PROBES_SATURATING_ARITHMETIC] = {.handler = probes_simulate_nop}, + [PROBES_MUL1] = {.handler = probes_simulate_nop}, + [PROBES_MUL2] = {.handler = probes_simulate_nop}, + [PROBES_SWP] = {.handler = probes_simulate_nop}, + [PROBES_LDRSTRD] = {.decoder = decode_pc_ro}, + [PROBES_LOAD_EXTRA] = {.decoder = decode_pc_ro}, + [PROBES_LOAD] = {.decoder = decode_ldr}, + [PROBES_STORE_EXTRA] = {.decoder = decode_pc_ro}, + [PROBES_STORE] = {.decoder = decode_pc_ro}, + [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp}, + [PROBES_DATA_PROCESSING_REG] = { + .decoder = decode_rd12rn16rm0rs8_rwflags}, + [PROBES_DATA_PROCESSING_IMM] = { + .decoder = decode_rd12rn16rm0rs8_rwflags}, + [PROBES_MOV_HALFWORD] = {.handler = probes_simulate_nop}, + [PROBES_SEV] = {.handler = probes_simulate_nop}, + [PROBES_WFE] = {.handler = probes_simulate_nop}, + [PROBES_SATURATE] = {.handler = probes_simulate_nop}, + [PROBES_REV] = {.handler = probes_simulate_nop}, + [PROBES_MMI] = {.handler = probes_simulate_nop}, + [PROBES_PACK] = {.handler = probes_simulate_nop}, + [PROBES_EXTEND] = {.handler = probes_simulate_nop}, + [PROBES_EXTEND_ADD] = {.handler = probes_simulate_nop}, + [PROBES_MUL_ADD_LONG] = {.handler = probes_simulate_nop}, + [PROBES_MUL_ADD] = {.handler = probes_simulate_nop}, + [PROBES_BITFIELD] = {.handler = probes_simulate_nop}, + [PROBES_BRANCH] = {.handler = simulate_bbl}, + [PROBES_LDMSTM] = {.decoder = uprobe_decode_ldmstm} +}; diff --git a/arch/arm/kernel/uprobes.c b/arch/arm/kernel/uprobes.c new file mode 100644 index 000000000000..f9bacee973bf --- /dev/null +++ b/arch/arm/kernel/uprobes.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2012 Rabin Vincent + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "probes.h" +#include "probes-arm.h" +#include "uprobes.h" + +#define UPROBE_TRAP_NR UINT_MAX + +bool is_swbp_insn(uprobe_opcode_t *insn) +{ + return (__mem_to_opcode_arm(*insn) & 0x0fffffff) == + (UPROBE_SWBP_ARM_INSN & 0x0fffffff); +} + +int set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, + unsigned long vaddr) +{ + return uprobe_write_opcode(mm, vaddr, + __opcode_to_mem_arm(auprobe->bpinsn)); +} + +bool arch_uprobe_ignore(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + if (!auprobe->asi.insn_check_cc(regs->ARM_cpsr)) { + regs->ARM_pc += 4; + return true; + } + + return false; +} + +bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + probes_opcode_t opcode; + + if (!auprobe->simulate) + return false; + + opcode = __mem_to_opcode_arm(*(unsigned int *) auprobe->insn); + + auprobe->asi.insn_singlestep(opcode, &auprobe->asi, regs); + + return true; +} + +unsigned long +arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, + struct pt_regs *regs) +{ + unsigned long orig_ret_vaddr; + + orig_ret_vaddr = regs->ARM_lr; + /* Replace the return addr with trampoline addr */ + regs->ARM_lr = trampoline_vaddr; + return orig_ret_vaddr; +} + +int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, + unsigned long addr) +{ + unsigned int insn; + unsigned int bpinsn; + enum probes_insn ret; + + /* Thumb not yet support */ + if (addr & 0x3) + return -EINVAL; + + insn = __mem_to_opcode_arm(*(unsigned int *)auprobe->insn); + auprobe->ixol[0] = __opcode_to_mem_arm(insn); + auprobe->ixol[1] = __opcode_to_mem_arm(UPROBE_SS_ARM_INSN); + + ret = arm_probes_decode_insn(insn, &auprobe->asi, false, + uprobes_probes_actions); + switch (ret) { + case INSN_REJECTED: + return -EINVAL; + + case INSN_GOOD_NO_SLOT: + auprobe->simulate = true; + break; + + case INSN_GOOD: + default: + break; + } + + bpinsn = UPROBE_SWBP_ARM_INSN & 0x0fffffff; + if (insn >= 0xe0000000) + bpinsn |= 0xe0000000; /* Unconditional instruction */ + else + bpinsn |= insn & 0xf0000000; /* Copy condition from insn */ + + auprobe->bpinsn = bpinsn; + + return 0; +} + +int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + if (auprobe->prehandler) + auprobe->prehandler(auprobe, &utask->autask, regs); + + utask->autask.saved_trap_no = current->thread.trap_no; + current->thread.trap_no = UPROBE_TRAP_NR; + regs->ARM_pc = utask->xol_vaddr; + + return 0; +} + +int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + WARN_ON_ONCE(current->thread.trap_no != UPROBE_TRAP_NR); + + current->thread.trap_no = utask->autask.saved_trap_no; + regs->ARM_pc = utask->vaddr + 4; + + if (auprobe->posthandler) + auprobe->posthandler(auprobe, &utask->autask, regs); + + return 0; +} + +bool arch_uprobe_xol_was_trapped(struct task_struct *t) +{ + if (t->thread.trap_no != UPROBE_TRAP_NR) + return true; + + return false; +} + +void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + current->thread.trap_no = utask->autask.saved_trap_no; + instruction_pointer_set(regs, utask->vaddr); +} + +int arch_uprobe_exception_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + return NOTIFY_DONE; +} + +static int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr) +{ + unsigned long flags; + + local_irq_save(flags); + instr &= 0x0fffffff; + if (instr == (UPROBE_SWBP_ARM_INSN & 0x0fffffff)) + uprobe_pre_sstep_notifier(regs); + else if (instr == (UPROBE_SS_ARM_INSN & 0x0fffffff)) + uprobe_post_sstep_notifier(regs); + local_irq_restore(flags); + + return 0; +} + +unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) +{ + return instruction_pointer(regs); +} + +static struct undef_hook uprobes_arm_break_hook = { + .instr_mask = 0x0fffffff, + .instr_val = (UPROBE_SWBP_ARM_INSN & 0x0fffffff), + .cpsr_mask = MODE_MASK, + .cpsr_val = USR_MODE, + .fn = uprobe_trap_handler, +}; + +static struct undef_hook uprobes_arm_ss_hook = { + .instr_mask = 0x0fffffff, + .instr_val = (UPROBE_SS_ARM_INSN & 0x0fffffff), + .cpsr_mask = MODE_MASK, + .cpsr_val = USR_MODE, + .fn = uprobe_trap_handler, +}; + +static int arch_uprobes_init(void) +{ + register_undef_hook(&uprobes_arm_break_hook); + register_undef_hook(&uprobes_arm_ss_hook); + + return 0; +} +device_initcall(arch_uprobes_init); diff --git a/arch/arm/kernel/uprobes.h b/arch/arm/kernel/uprobes.h new file mode 100644 index 000000000000..1d0c12dfbd03 --- /dev/null +++ b/arch/arm/kernel/uprobes.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 Rabin Vincent + * + * 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. + */ + +#ifndef __ARM_KERNEL_UPROBES_H +#define __ARM_KERNEL_UPROBES_H + +enum probes_insn uprobe_decode_ldmstm(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *d); + +enum probes_insn decode_ldr(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *d); + +enum probes_insn +decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn, + struct arch_probes_insn *asi, + const struct decode_header *d); + +enum probes_insn +decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *d, bool alu); + +enum probes_insn +decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi, + const struct decode_header *d); + +extern const union decode_action uprobes_probes_actions[]; + +#endif -- cgit v1.2.3