* [git pull] signals pile 3
From: Daniel Mack @ 2012-10-14 22:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121014222449.GN21164@n2100.arm.linux.org.uk>
On 15.10.2012 00:24, Russell King - ARM Linux wrote:
> Okay, here's the post-mortem diagnosis.
>
> What's happening is as follows (I'm very certain of this.)
>
> We come through the usual init, and issue (see init/main.c):
>
> kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
>
> This creates a new thread, which falls through to the ret_from_fork
> assembly, with r4 set NULL and r5 set to kernel_init. You can see
> this in your oops dump register set - r5 is 0xc0344555, which is the
> address of kernel_init plus 1 which marks the function as Thumb code.
>
> Now, let's look at this code a little closer - this is what the
> disassembly looks like:
>
> c000d180 <ret_from_fork>:
> c000d180: f03a fe08 bl c0047d94 <schedule_tail>
> c000d184: 2d00 cmp r5, #0
> c000d186: bf1e ittt ne
> c000d188: 4620 movne r0, r4
> c000d18a: 46fe movne lr, pc <-- XXXXXXX
> c000d18c: 46af movne pc, r5
> c000d18e: 46e9 mov r9, sp
> c000d190: ea4f 3959 mov.w r9, r9, lsr #13
> c000d194: ea4f 3949 mov.w r9, r9, lsl #13
> c000d198: e7c8 b.n c000d12c <ret_to_user>
> c000d19a: bf00 nop
> c000d19c: f3af 8000 nop.w
>
> I have marked one instruction, and it's the significant one.
>
> Eventually, having had a successful call to kernel_execve(), kernel_init()
> returns zero.
>
> In returning, it uses the value in 'lr' which was set by the instruction
> I marked above. Unfortunately, this causes lr to contain 0xc000d18e -
> an even address. This switches the ISA to ARM on return but with a non
> word aligned PC value.
>
> So, what do we end up executing? Well, not the instructions above - yes
> the opcodes, but they don't mean the same thing in ARM mode. In ARM mode,
> it looks like this instead:
>
> c000d18c: 46e946af strbtmi r4, [r9], pc, lsr #13
> c000d190: 3959ea4f ldmdbcc r9, {r0, r1, r2, r3, r6, r9, fp, sp, lr, pc}^
> c000d194: 3949ea4f stmdbcc r9, {r0, r1, r2, r3, r6, r9, fp, sp, lr, pc}^
> c000d198: bf00e7c8 svclt 0x0000e7c8
> c000d19c: 8000f3af andhi pc, r0, pc, lsr #7
> c000d1a0: e88db092 stm sp, {r1, r4, r7, ip, sp, pc}
> c000d1a4: 46e81fff ; <UNDEFINED> instruction: 0x46e81fff
> c000d1a8: 8a00f3ef bhi 0xc004a16c
> c000d1ac: 0a0cf08a beq 0xc03493dc
>
> I have included more above, because it's relevant. The PSR flags which we
> can see in the oops dump are nZCv, so Z and C are set.
>
> All the above ARM instructions are not executed, except for two. c000d1a0,
> which has no writeback, and writes below the current stack pointer (and
> that data is lost when we take the next exception.) The other instruction
> which is executed is c000d1ac, which takes us to... 0xc03493dc. However,
> remember that bit 1 of the PC got set. So that makes it 0xc03493de.
>
> And that value is the value we find in the oops dump for PC. What is the
> instruction here when interpreted in ARM mode?
>
> 0: f71e150c ; <UNDEFINED> instruction: 0xf71e150c
>
> and there we have our undefined instruction (remember that the 'never'
> condition code, 0xf, has been deprecated and is now always executed.)
>
> So, what we have above is a consistent and sane story for how we ended up
> at such a strange place in the kernel with such an odd register dump - with
> no unanswered questions about what happened to get us there.
>
> In light of this, I'm 100% certain that the patch below will fix the issue
> you're seeing - please test this and get back to me ASAP, thanks.
Quite impressive analysis :) And it seems you really spotted the reason
here, as your patch fixes the problem.
> arch/arm/kernel/entry-common.S | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index 417bac1..3471175 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -88,9 +88,9 @@ ENTRY(ret_from_fork)
> bl schedule_tail
> cmp r5, #0
> movne r0, r4
> - movne lr, pc
> + adrne lr, BSYM(1f)
> movne pc, r5
> - get_thread_info tsk
> +1: get_thread_info tsk
> b ret_slow_syscall
> ENDPROC(ret_from_fork)
Tested-by: Daniel Mack <zonque@gmail.com>
Many thanks for the very prompt response!
Daniel
^ permalink raw reply
* dma_alloc_coherent fails in framebuffer
From: Tony Prisk @ 2012-10-14 22:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350246895.11504.6.camel@gitbox>
On Mon, 2012-10-15 at 09:34 +1300, Tony Prisk wrote:
> On Sun, 2012-10-14 at 18:28 +1300, Tony Prisk wrote:
> > Up until 07 Oct, drivers/video/wm8505-fb.c was working fine, but on the
> > 11 Oct when I did another pull from linus all of a sudden
> > dma_alloc_coherent is failing to allocate the framebuffer any longer.
> >
> > I did a quick look back and found this:
> >
> > ARM: add coherent dma ops
> >
> > arch_is_coherent is problematic as it is a global symbol. This
> > doesn't work for multi-platform kernels or platforms which can support
> > per device coherent DMA.
> >
> > This adds arm_coherent_dma_ops to be used for devices which connected
> > coherently (i.e. to the ACP port on Cortex-A9 or A15). The arm_dma_ops
> > are modified at boot when arch_is_coherent is true.
> >
> > Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> > Cc: Russell King <linux@arm.linux.org.uk>
> > Cc: Marek Szyprowski <m.szyprowski@samsung.com>
> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> >
> >
> > This is the only patch lately that I could find (not that I would claim
> > to be any good at finding things) that is related to the problem. Could
> > it have caused the allocations to fail?
> >
> > Regards
> > Tony P
>
> Have done a bit more digging and found the cause - not Rob's patch so
> apologies.
>
> The cause of the regression is this patch:
>
> From f40d1e42bb988d2a26e8e111ea4c4c7bac819b7e Mon Sep 17 00:00:00 2001
> From: Mel Gorman <mgorman@suse.de>
> Date: Mon, 8 Oct 2012 16:32:36 -0700
> Subject: [PATCH 2/3] mm: compaction: acquire the zone->lock as late as
> possible
>
> Up until then, the framebuffer allocation with dma_alloc_coherent(...)
> was fine. From this patch onwards, allocations fail.
>
> I don't know how this patch would effect CMA allocations, but it seems
> to be causing the issue (or at least, it's caused an error in
> arch-vt8500 to become visible).
>
> Perhaps someone who understand -mm could explain the best way to
> troubleshoot the cause of this problem?
>
>
> Regards
> Tony P
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Have done a bit more testing..
Disabling Memory Compaction makes no difference.
Disabling CMA fixes/hides the problem. ?!?!?!
Regards
Tony P
^ permalink raw reply
* [git pull] signals pile 3
From: Russell King - ARM Linux @ 2012-10-14 22:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121014202431.GL21164@n2100.arm.linux.org.uk>
Okay, here's the post-mortem diagnosis.
What's happening is as follows (I'm very certain of this.)
We come through the usual init, and issue (see init/main.c):
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
This creates a new thread, which falls through to the ret_from_fork
assembly, with r4 set NULL and r5 set to kernel_init. You can see
this in your oops dump register set - r5 is 0xc0344555, which is the
address of kernel_init plus 1 which marks the function as Thumb code.
Now, let's look at this code a little closer - this is what the
disassembly looks like:
c000d180 <ret_from_fork>:
c000d180: f03a fe08 bl c0047d94 <schedule_tail>
c000d184: 2d00 cmp r5, #0
c000d186: bf1e ittt ne
c000d188: 4620 movne r0, r4
c000d18a: 46fe movne lr, pc <-- XXXXXXX
c000d18c: 46af movne pc, r5
c000d18e: 46e9 mov r9, sp
c000d190: ea4f 3959 mov.w r9, r9, lsr #13
c000d194: ea4f 3949 mov.w r9, r9, lsl #13
c000d198: e7c8 b.n c000d12c <ret_to_user>
c000d19a: bf00 nop
c000d19c: f3af 8000 nop.w
I have marked one instruction, and it's the significant one.
Eventually, having had a successful call to kernel_execve(), kernel_init()
returns zero.
In returning, it uses the value in 'lr' which was set by the instruction
I marked above. Unfortunately, this causes lr to contain 0xc000d18e -
an even address. This switches the ISA to ARM on return but with a non
word aligned PC value.
So, what do we end up executing? Well, not the instructions above - yes
the opcodes, but they don't mean the same thing in ARM mode. In ARM mode,
it looks like this instead:
c000d18c: 46e946af strbtmi r4, [r9], pc, lsr #13
c000d190: 3959ea4f ldmdbcc r9, {r0, r1, r2, r3, r6, r9, fp, sp, lr, pc}^
c000d194: 3949ea4f stmdbcc r9, {r0, r1, r2, r3, r6, r9, fp, sp, lr, pc}^
c000d198: bf00e7c8 svclt 0x0000e7c8
c000d19c: 8000f3af andhi pc, r0, pc, lsr #7
c000d1a0: e88db092 stm sp, {r1, r4, r7, ip, sp, pc}
c000d1a4: 46e81fff ; <UNDEFINED> instruction: 0x46e81fff
c000d1a8: 8a00f3ef bhi 0xc004a16c
c000d1ac: 0a0cf08a beq 0xc03493dc
I have included more above, because it's relevant. The PSR flags which we
can see in the oops dump are nZCv, so Z and C are set.
All the above ARM instructions are not executed, except for two. c000d1a0,
which has no writeback, and writes below the current stack pointer (and
that data is lost when we take the next exception.) The other instruction
which is executed is c000d1ac, which takes us to... 0xc03493dc. However,
remember that bit 1 of the PC got set. So that makes it 0xc03493de.
And that value is the value we find in the oops dump for PC. What is the
instruction here when interpreted in ARM mode?
0: f71e150c ; <UNDEFINED> instruction: 0xf71e150c
and there we have our undefined instruction (remember that the 'never'
condition code, 0xf, has been deprecated and is now always executed.)
So, what we have above is a consistent and sane story for how we ended up
at such a strange place in the kernel with such an odd register dump - with
no unanswered questions about what happened to get us there.
In light of this, I'm 100% certain that the patch below will fix the issue
you're seeing - please test this and get back to me ASAP, thanks.
arch/arm/kernel/entry-common.S | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 417bac1..3471175 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -88,9 +88,9 @@ ENTRY(ret_from_fork)
bl schedule_tail
cmp r5, #0
movne r0, r4
- movne lr, pc
+ adrne lr, BSYM(1f)
movne pc, r5
- get_thread_info tsk
+1: get_thread_info tsk
b ret_slow_syscall
ENDPROC(ret_from_fork)
^ permalink raw reply related
* [PATCH v2 5/5] ARM: bcm476x: Add restart hook
From: Domenico Andreoli @ 2012-10-14 22:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121014221450.866288977@gmail.com>
An embedded and charset-unspecified text was scrubbed...
Name: arm-bcm476x-add-restart-hook.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121015/42c7c931/attachment.ksh>
^ permalink raw reply
* [PATCH v2 4/5] ARM: bcm476x: Add stub clock driver
From: Domenico Andreoli @ 2012-10-14 22:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121014221450.866288977@gmail.com>
An embedded and charset-unspecified text was scrubbed...
Name: arm-bcm476x-add-stub-clock-driver.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121015/4c2fb98c/attachment.ksh>
^ permalink raw reply
* [PATCH v2 3/5] ARM: bcm476x: Add ripple counter
From: Domenico Andreoli @ 2012-10-14 22:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121014221450.866288977@gmail.com>
An embedded and charset-unspecified text was scrubbed...
Name: arm-bcm476x-add-ripple-counter.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121015/594e107b/attachment.ksh>
^ permalink raw reply
* [PATCH v2 2/5] ARM: bcm476x: Add system timer
From: Domenico Andreoli @ 2012-10-14 22:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121014221450.866288977@gmail.com>
An embedded and charset-unspecified text was scrubbed...
Name: arm-bcm476x-add-system-timer.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121015/99f89d0e/attachment.ksh>
^ permalink raw reply
* [PATCH v2 1/5] ARM: bcm476x: Add platform infrastructure
From: Domenico Andreoli @ 2012-10-14 22:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121014221450.866288977@gmail.com>
An embedded and charset-unspecified text was scrubbed...
Name: arm-bcm476x-add-infrastructure.patch
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121015/9f64b4e9/attachment.ksh>
^ permalink raw reply
* [PATCH v2 0/5] ARM: Add support for Broadcom BCM476x SoCs
From: Domenico Andreoli @ 2012-10-14 22:14 UTC (permalink / raw)
To: linux-arm-kernel
Hallo,
first of all thank you for the feedback you've sent on the first
round of this patchset. I think I've addressed all the points plus some
extra I've found on the way. The details are in the description of the
single patches.
Tested on v3.7-rc1 (ddffeb8). Any feedback is welcome.
Thanks,
Domenico
^ permalink raw reply
* [PATCH 5/5] ARM: AT91: Add AT91RM9200 device tree
From: Joachim Eastwood @ 2012-10-14 21:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350251199-28065-1-git-send-email-manabian@gmail.com>
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
arch/arm/boot/dts/at91rm9200.dtsi | 333 ++++++++++++++++++++++++++++++++++++++
1 file changed, 333 insertions(+)
create mode 100644 arch/arm/boot/dts/at91rm9200.dtsi
diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi
new file mode 100644
index 0000000..5c4f91d
--- /dev/null
+++ b/arch/arm/boot/dts/at91rm9200.dtsi
@@ -0,0 +1,333 @@
+/*
+ * at91rm9200.dtsi - Device Tree Include file for AT91RM9200 family SoC
+ *
+ * Copyright (C) 2011 Atmel,
+ * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>,
+ * 2012 Joachim Eastwood <manabian@gmail.com>
+ *
+ * Based on at91sam9260.dtsi
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Atmel AT91RM9200 family SoC";
+ compatible = "atmel,at91rm9200";
+ interrupt-parent = <&aic>;
+
+ aliases {
+ serial0 = &dbgu;
+ serial1 = &usart0;
+ serial2 = &usart1;
+ serial3 = &usart2;
+ serial4 = &usart3;
+ gpio0 = &pioA;
+ gpio1 = &pioB;
+ gpio2 = &pioC;
+ gpio3 = &pioD;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
+ };
+ cpus {
+ cpu at 0 {
+ compatible = "arm,arm920t";
+ };
+ };
+
+ memory {
+ reg = <0x20000000 0x04000000>;
+ };
+
+ ahb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ apb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ aic: interrupt-controller at fffff000 {
+ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+ atmel,external-irqs = <25 26 27 28 29 30 31>;
+ };
+
+ ramc0: ramc at ffffff00 {
+ compatible = "atmel,at91rm9200-sdramc";
+ reg = <0xffffff00 0x100>;
+ };
+
+ pmc: pmc at fffffc00 {
+ compatible = "atmel,at91rm9200-pmc";
+ reg = <0xfffffc00 0x100>;
+ };
+
+ st: timer at fffffd00 {
+ compatible = "atmel,at91rm9200-st";
+ reg = <0xfffffd00 0x100>;
+ interrupts = <1 4 7>;
+ };
+
+ tcb0: timer at fffa0000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffa0000 0x100>;
+ interrupts = <17 4 0 18 4 0 19 4 0>;
+ };
+
+ tcb1: timer at fffa4000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffa4000 0x100>;
+ interrupts = <20 4 0 21 4 0 22 4 0>;
+ };
+
+ pinctrl at fffff400 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x800>;
+
+ atmel,mux-mask = <
+ /* A B */
+ 0xffffffff 0xffffffff /* pioA */
+ 0xffffffff 0x083fffff /* pioB */
+ 0xffff3fff 0x00000000 /* pioC */
+ 0x03ff87ff 0x0fffff80 /* pioD */
+ >;
+
+ /* shared pinctrl settings */
+ dbgu {
+ pinctrl_dbgu: dbgu-0 {
+ atmel,pins =
+ <0 30 0x1 0x0 /* PA30 periph A */
+ 0 31 0x1 0x1>; /* PA31 periph with pullup */
+ };
+ };
+
+ uart0 {
+ pinctrl_uart0: uart0-0 {
+ atmel,pins =
+ <0 17 0x1 0x0 /* PA17 periph A */
+ 0 18 0x1 0x0>; /* PA18 periph A */
+ };
+
+ pinctrl_uart0_rts_cts: uart0_rts_cts-0 {
+ atmel,pins =
+ <0 20 0x1 0x0 /* PA20 periph A */
+ 0 21 0x1 0x0>; /* PA21 periph A */
+ };
+ };
+
+ uart1 {
+ pinctrl_uart1: uart1-0 {
+ atmel,pins =
+ <1 20 0x1 0x1 /* PB20 periph A with pullup */
+ 1 21 0x1 0x0>; /* PB21 periph A */
+ };
+
+ pinctrl_uart1_rts_cts: uart1_rts_cts-0 {
+ atmel,pins =
+ <1 24 0x1 0x0 /* PB24 periph A */
+ 1 26 0x1 0x0>; /* PB26 periph A */
+ };
+
+ pinctrl_uart1_dtr_dsr: uart1_dtr_dsr-0 {
+ atmel,pins =
+ <1 19 0x1 0x0 /* PB19 periph A */
+ 1 25 0x1 0x0>; /* PB25 periph A */
+ };
+
+ pinctrl_uart1_dcd: uart1_dcd-0 {
+ atmel,pins =
+ <1 23 0x1 0x0>; /* PB23 periph A */
+ };
+
+ pinctrl_uart1_ri: uart1_ri-0 {
+ atmel,pins =
+ <1 18 0x1 0x0>; /* PB18 periph A */
+ };
+ };
+
+ uart2 {
+ pinctrl_uart2: uart2-0 {
+ atmel,pins =
+ <0 22 0x1 0x0 /* PA22 periph A */
+ 0 23 0x1 0x1>; /* PA23 periph A with pullup */
+ };
+
+ pinctrl_uart2_rts_cts: uart2_rts_cts-0 {
+ atmel,pins =
+ <0 30 0x2 0x0 /* PA30 periph B */
+ 0 31 0x2 0x0>; /* PA31 periph B */
+ };
+ };
+
+ uart3 {
+ pinctrl_uart3: uart3-0 {
+ atmel,pins =
+ <0 5 0x2 0x1 /* PA5 periph B with pullup */
+ 0 6 0x2 0x0>; /* PA6 periph B */
+ };
+
+ pinctrl_uart3_rts_cts: uart3_rts_cts-0 {
+ atmel,pins =
+ <1 0 0x2 0x0 /* PB0 periph B */
+ 1 1 0x2 0x0>; /* PB1 periph B */
+ };
+ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+ atmel,pins =
+ <2 2 0x0 0x1 /* PC2 gpio RDY pin pull_up */
+ 1 1 0x0 0x1>; /* PB1 gpio CD pin pull_up */
+ };
+ };
+
+ pioA: gpio at fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio at fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x200>;
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio at fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x200>;
+ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio at fffffa00 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x200>;
+ interrupts = <5 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ dbgu: serial at fffff200 {
+ compatible = "atmel,at91rm9200-usart";
+ reg = <0xfffff200 0x200>;
+ interrupts = <1 4 7>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dbgu>;
+ status = "disabled";
+ };
+
+ usart0: serial at fffc0000 {
+ compatible = "atmel,at91rm9200-usart";
+ reg = <0xfffc0000 0x200>;
+ interrupts = <6 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart0>;
+ status = "disabled";
+ };
+
+ usart1: serial at fffc4000 {
+ compatible = "atmel,at91rm9200-usart";
+ reg = <0xfffc4000 0x200>;
+ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "disabled";
+ };
+
+ usart2: serial at fffc8000 {
+ compatible = "atmel,at91rm9200-usart";
+ reg = <0xfffc8000 0x200>;
+ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "disabled";
+ };
+
+ usart3: serial at fffcc000 {
+ compatible = "atmel,at91rm9200-usart";
+ reg = <0xfffcc000 0x200>;
+ interrupts = <23 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ status = "disabled";
+ };
+
+ usb1: gadget at fffb0000 {
+ compatible = "atmel,at91rm9200-udc";
+ reg = <0xfffb0000 0x4000>;
+ interrupts = <11 4 2>;
+ status = "disabled";
+ };
+ };
+
+ nand0: nand at 40000000 {
+ compatible = "atmel,at91rm9200-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x40000000 0x10000000>;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nand>;
+ nand-ecc-mode = "soft";
+ gpios = <&pioC 2 0
+ 0
+ &pioB 1 0
+ >;
+ status = "disabled";
+ };
+
+ usb0: ohci at 00300000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00300000 0x100000>;
+ interrupts = <23 4 2>;
+ status = "disabled";
+ };
+ };
+
+ i2c at 0 {
+ compatible = "i2c-gpio";
+ gpios = <&pioA 23 0 /* sda */
+ &pioA 24 0 /* scl */
+ >;
+ i2c-gpio,sda-open-drain;
+ i2c-gpio,scl-open-drain;
+ i2c-gpio,delay-us = <2>; /* ~100 kHz */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+};
--
1.7.12.3
^ permalink raw reply related
* [PATCH 4/5] ARM: AT91: Add AT91RM9200 DT board
From: Joachim Eastwood @ 2012-10-14 21:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350251199-28065-1-git-send-email-manabian@gmail.com>
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
arch/arm/mach-at91/Kconfig | 8 +++++
arch/arm/mach-at91/Makefile | 1 +
arch/arm/mach-at91/board-rm9200-dt.c | 59 ++++++++++++++++++++++++++++++++++++
arch/arm/mach-at91/generic.h | 1 +
arch/arm/mach-at91/setup.c | 14 +++++++++
5 files changed, 83 insertions(+)
create mode 100644 arch/arm/mach-at91/board-rm9200-dt.c
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index d9b0546..3f45906 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -505,6 +505,14 @@ endif
comment "Generic Board Type"
+config MACH_AT91RM9200_DT
+ bool "Atmel AT91RM9200 Evaluation Kits with device-tree support"
+ select SOC_AT91RM9200
+ select USE_OF
+ help
+ Select this if you want to experiment device-tree with
+ an Atmel RM9200 Evaluation Kit.
+
config MACH_AT91SAM_DT
bool "Atmel AT91SAM Evaluation Kits with device-tree support"
select SOC_AT91SAM9
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index d6e0d21..75dee683 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_MACH_SNAPPER_9260) += board-snapper9260.o
obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o
# AT91SAM board with device-tree
+obj-$(CONFIG_MACH_AT91RM9200_DT) += board-rm9200-dt.o
obj-$(CONFIG_MACH_AT91SAM_DT) += board-dt.o
# AT91X40 board-specific support
diff --git a/arch/arm/mach-at91/board-rm9200-dt.c b/arch/arm/mach-at91/board-rm9200-dt.c
new file mode 100644
index 0000000..47e91d9
--- /dev/null
+++ b/arch/arm/mach-at91/board-rm9200-dt.c
@@ -0,0 +1,59 @@
+/*
+ * Setup code for AT91RM9200 Evaluation Kits with Device Tree support
+ *
+ * Copyright (C) 2011 Atmel,
+ * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>
+ * 2012 Joachim Eastwood <manabian@gmail.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include <mach/board.h>
+#include <mach/at91_aic.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include "generic.h"
+
+
+static const struct of_device_id irq_of_match[] __initconst = {
+ { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
+ { /*sentinel*/ }
+};
+
+static void __init at91rm9200_dt_init_irq(void)
+{
+ of_irq_init(irq_of_match);
+}
+
+static void __init at91rm9200_dt_device_init(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *at91rm9200_dt_board_compat[] __initdata = {
+ "atmel,at91rm9200",
+ NULL
+};
+
+DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200 (Device Tree)")
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
+ .handle_irq = at91_aic_handle_irq,
+ .init_early = at91rm9200_dt_initialize,
+ .init_irq = at91rm9200_dt_init_irq,
+ .init_machine = at91rm9200_dt_device_init,
+ .dt_compat = at91rm9200_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index f496506..9bb5ce5 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -20,6 +20,7 @@ extern void __init at91_init_sram(int bank, unsigned long base,
extern void __init at91rm9200_set_type(int type);
extern void __init at91_initialize(unsigned long main_clock);
extern void __init at91x40_initialize(unsigned long main_clock);
+extern void __init at91rm9200_dt_initialize(void);
extern void __init at91_dt_initialize(void);
/* Interrupts */
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index 523daa9..e3f1ea4 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -339,6 +339,7 @@ static void at91_dt_rstc(void)
}
static struct of_device_id ramc_ids[] = {
+ { .compatible = "atmel,at91rm9200-sdramc" },
{ .compatible = "atmel,at91sam9260-sdramc" },
{ .compatible = "atmel,at91sam9g45-ddramc" },
{ /*sentinel*/ }
@@ -437,6 +438,19 @@ end:
of_node_put(np);
}
+void __init at91rm9200_dt_initialize(void)
+{
+ at91_dt_ramc();
+
+ /* Init clock subsystem */
+ at91_dt_clock_init();
+
+ /* Register the processor-specific clocks */
+ at91_boot_soc.register_clocks();
+
+ at91_boot_soc.init();
+}
+
void __init at91_dt_initialize(void)
{
at91_dt_rstc();
--
1.7.12.3
^ permalink raw reply related
* [PATCH 3/5] ARM: AT91: Add usart/tc/pio DT clock lookup to AT91RM9200
From: Joachim Eastwood @ 2012-10-14 21:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350251199-28065-1-git-send-email-manabian@gmail.com>
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
arch/arm/mach-at91/at91rm9200.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index a454734..f68533b 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -188,12 +188,29 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
+ /* usart lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+ CLKDEV_CON_DEV_ID("usart", "fffc0000.serial", &usart0_clk),
+ CLKDEV_CON_DEV_ID("usart", "fffc4000.serial", &usart1_clk),
+ CLKDEV_CON_DEV_ID("usart", "fffc8000.serial", &usart2_clk),
+ CLKDEV_CON_DEV_ID("usart", "fffcc000.serial", &usart3_clk),
+ /* tc lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
+ CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "fffa4000.timer", &tc3_clk),
+ CLKDEV_CON_DEV_ID("t1_clk", "fffa4000.timer", &tc4_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "fffa4000.timer", &tc5_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
CLKDEV_CON_ID("pioB", &pioB_clk),
CLKDEV_CON_ID("pioC", &pioC_clk),
CLKDEV_CON_ID("pioD", &pioD_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioD_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {
--
1.7.12.3
^ permalink raw reply related
* [PATCH 2/5] ARM: AT91: Add DT support to AT91RM9200 System Timer
From: Joachim Eastwood @ 2012-10-14 21:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350251199-28065-1-git-send-email-manabian@gmail.com>
Based on AT91 PIT DT patch from Jean-Christophe PLAGNIOL-VILLARD.
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
.../devicetree/bindings/arm/atmel-at91.txt | 6 +++
arch/arm/mach-at91/at91rm9200_time.c | 63 +++++++++++++++++++++-
2 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
index ecc81e3..8adc9a8 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt
@@ -7,6 +7,12 @@ PIT Timer required properties:
- interrupts: Should contain interrupt for the PIT which is the IRQ line
shared across all System Controller members.
+System Timer (ST) required properties:
+- compatible: Should be "atmel,at91rm9200-st"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt for the ST which is the IRQ line
+ shared across all System Controller members.
+
TC/TCLIB Timer required properties:
- compatible: Should be "atmel,<chip>-pit".
<chip> can be "at91rm9200" or "at91sam9x5"
diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c
index aaa443b..cafe988 100644
--- a/arch/arm/mach-at91/at91rm9200_time.c
+++ b/arch/arm/mach-at91/at91rm9200_time.c
@@ -24,6 +24,9 @@
#include <linux/irq.h>
#include <linux/clockchips.h>
#include <linux/export.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <asm/mach/time.h>
@@ -91,7 +94,8 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
static struct irqaction at91rm9200_timer_irq = {
.name = "at91_tick",
.flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = at91rm9200_timer_interrupt
+ .handler = at91rm9200_timer_interrupt,
+ .irq = NR_IRQS_LEGACY + AT91_ID_SYS,
};
static cycle_t read_clk32k(struct clocksource *cs)
@@ -179,8 +183,60 @@ static struct clock_event_device clkevt = {
void __iomem *at91_st_base;
EXPORT_SYMBOL_GPL(at91_st_base);
+#ifdef CONFIG_OF
+static struct of_device_id at91rm9200_st_timer_ids[] = {
+ { .compatible = "atmel,at91rm9200-st" },
+ { /* sentinel */ }
+};
+
+static int __init of_at91rm9200_st_init(void)
+{
+ struct device_node *np;
+ int ret;
+
+ np = of_find_matching_node(NULL, at91rm9200_st_timer_ids);
+ if (!np)
+ goto err;
+
+ at91_st_base = of_iomap(np, 0);
+ if (!at91_st_base)
+ goto node_err;
+
+ /* Get the interrupts property */
+ ret = irq_of_parse_and_map(np, 0);
+ if (!ret)
+ goto ioremap_err;
+ at91rm9200_timer_irq.irq = ret;
+
+ of_node_put(np);
+
+ return 0;
+
+ioremap_err:
+ iounmap(at91_st_base);
+node_err:
+ of_node_put(np);
+err:
+ return -EINVAL;
+}
+#else
+static int __init of_at91rm9200_st_init(void)
+{
+ return -EINVAL;
+}
+#endif
+
void __init at91rm9200_ioremap_st(u32 addr)
{
+#ifdef CONFIG_OF
+ struct device_node *np;
+
+ np = of_find_matching_node(NULL, at91rm9200_st_timer_ids);
+ if (np) {
+ of_node_put(np);
+ return;
+ }
+#endif
at91_st_base = ioremap(addr, 256);
if (!at91_st_base)
panic("Impossible to ioremap ST\n");
@@ -191,13 +247,16 @@ void __init at91rm9200_ioremap_st(u32 addr)
*/
void __init at91rm9200_timer_init(void)
{
+ /* For device tree enabled device: initialize here */
+ of_at91rm9200_st_init();
+
/* Disable all timer interrupts, and clear any pending ones */
at91_st_write(AT91_ST_IDR,
AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
at91_st_read(AT91_ST_SR);
/* Make IRQs happen for the system timer */
- setup_irq(NR_IRQS_LEGACY + AT91_ID_SYS, &at91rm9200_timer_irq);
+ setup_irq(at91rm9200_timer_irq.irq, &at91rm9200_timer_irq);
/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
* directly for the clocksource and all clockevents, after adjusting
--
1.7.12.3
^ permalink raw reply related
* [PATCH 1/5] ARM: AT91: Fix build failure on board-dt
From: Joachim Eastwood @ 2012-10-14 21:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350251199-28065-1-git-send-email-manabian@gmail.com>
We need CONFIG_SOC_AT91SAM9 to get the at91sam926x_timer
symbol used in board-dt.
Signed-off-by: Joachim Eastwood <manabian@gmail.com>
---
arch/arm/mach-at91/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 0fafb6a..d9b0546 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -507,6 +507,7 @@ comment "Generic Board Type"
config MACH_AT91SAM_DT
bool "Atmel AT91SAM Evaluation Kits with device-tree support"
+ select SOC_AT91SAM9
select USE_OF
help
Select this if you want to experiment device-tree with
--
1.7.12.3
^ permalink raw reply related
* [PATCH 0/5] Add DT support for AT91RM9200
From: Joachim Eastwood @ 2012-10-14 21:46 UTC (permalink / raw)
To: linux-arm-kernel
Hi
This patch series add support for devicetree on AT91RM9200. Series is dependent upon at91-pinctrl.
There isn't support for any boards yet, but I am working on one now. I will submit it once I have a couple of more bindings in place.
Patch 1 is a fix for a build failure which can happen if board-dt is enabled when no AT91SAM machines are enabled.
regards
Joachim Eastwood
Joachim Eastwood (5):
ARM: AT91: Fix build failure on board-dt
ARM: AT91: Add DT support to AT91RM9200 System Timer
ARM: AT91: Add usart/tc/pio DT clock lookup to AT91RM9200
ARM: AT91: Add AT91RM9200 DT board
ARM: AT91: Add AT91RM9200 device tree
.../devicetree/bindings/arm/atmel-at91.txt | 6 +
arch/arm/boot/dts/at91rm9200.dtsi | 333 +++++++++++++++++++++
arch/arm/mach-at91/Kconfig | 9 +
arch/arm/mach-at91/Makefile | 1 +
arch/arm/mach-at91/at91rm9200.c | 17 ++
arch/arm/mach-at91/at91rm9200_time.c | 63 +++-
arch/arm/mach-at91/board-rm9200-dt.c | 59 ++++
arch/arm/mach-at91/generic.h | 1 +
arch/arm/mach-at91/setup.c | 14 +
9 files changed, 501 insertions(+), 2 deletions(-)
create mode 100644 arch/arm/boot/dts/at91rm9200.dtsi
create mode 100644 arch/arm/mach-at91/board-rm9200-dt.c
--
1.7.12.3
^ permalink raw reply
* [PATCH 3/4] ARM: AT91: Add AT91RM9200 support to DT board
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-10-14 21:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGhQ9VyNqsU8pnMaxOEu7bkzv_LizG+d9Vw-ODW72muTPQ9Qtg@mail.gmail.com>
On 18:39 Sun 14 Oct , Joachim Eastwood wrote:
> On Sun, Oct 14, 2012 at 4:54 PM, Jean-Christophe PLAGNIOL-VILLARD
> <plagnioj@jcrosoft.com> wrote:
> > On 19:08 Fri 12 Oct , Joachim Eastwood wrote:
> >> On Fri, Oct 12, 2012 at 6:27 PM, Jean-Christophe PLAGNIOL-VILLARD
> >> <plagnioj@jcrosoft.com> wrote:
> >> > On 17:28 Fri 12 Oct , ludovic.desroches wrote:
> >> >> Le 10/12/2012 04:22 PM, Jean-Christophe PLAGNIOL-VILLARD a ?crit :
> >> >> >On 00:05 Fri 12 Oct , Joachim Eastwood wrote:
> >> >> >>Signed-off-by: Joachim Eastwood <manabian@gmail.com>
> >> >> >>---
> >> >> >>
> >> >> >>Hi,
> >> >> >>
> >> >> >>This patch has some potential issues.
> >> >> >>Before this patch board-dt would fail building when only AT91RM9200 was enabled because at91sam926x_timer symbol would be missing. This patch uses the at91rm9200_timer which
> >> >> >>will fail if AT91RM9200 is not enabled.
> >> >> >this need work with ot wtihout rm9200
> >>
> >> btw, to solve the build issue with board-dt in mainline now we need to
> >> add a select CONFIG_SOC_AT91SAM9 to config MACH_AT91SAM_DT.
> >>
> >> >> >>
> >> >> >>Any thoughts on solving this? As mention above this bug exists in mainline now.
> >> >> >duplicate the board-dt with one for rm9200 only
> >> >> >as rm9200 ans sam9 are 2 distict familly
> >> >>
> >> >> Why not adding a new machine descriptor for rm9200 in order to
> >> >> prevent file duplication?
> >> > because the soc are different and can only be compile if the timer is enable
> >> > and I do not want to enable the rm9200 timer on sam9 so instead of a ifdef i
> >> > the board-dt create a new board is better as we have a 50 lines file
> >> >
> >> > with different board_compat and different machine descriptor
> >>
> >> I am okey with either approach, but I would like to hear what Nicolas
> >> Ferre has to say since he is the on the one that added board-dt. It
> >> would be nice to have everything in one board DT file, but I
> >> understand your concern with the RM9200 timer.
> >>
> >> We will also bump into this again on AT91X40 I guess.
> > simple on x40 forget about it the x40 is no MMU only SoC
> >
> > so you can not enable it by default as the all other at91 are use with MMU
> >
> > I did the necessary to make the board-dt nearly empty and the same for all the
> > sam9 but the board-dt is sam9 only and need to be keeped this way
> >
> > Nico will tell you the same
>
> okay. I'll make the necessary changes to the patch set.
>
> I'll also include a fix for board-dt (select CONFIG_SOC_AT91SAM9) to
> stop the build failure when it's enabled on a RM9200 only config.
if rm9200 only the board-dt does not have to be enabled
as you do not have the clock for any of the soc
Best Regards,
J.
^ permalink raw reply
* dma_alloc_coherent fails in framebuffer
From: Tony Prisk @ 2012-10-14 20:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350192523.10946.4.camel@gitbox>
On Sun, 2012-10-14 at 18:28 +1300, Tony Prisk wrote:
> Up until 07 Oct, drivers/video/wm8505-fb.c was working fine, but on the
> 11 Oct when I did another pull from linus all of a sudden
> dma_alloc_coherent is failing to allocate the framebuffer any longer.
>
> I did a quick look back and found this:
>
> ARM: add coherent dma ops
>
> arch_is_coherent is problematic as it is a global symbol. This
> doesn't work for multi-platform kernels or platforms which can support
> per device coherent DMA.
>
> This adds arm_coherent_dma_ops to be used for devices which connected
> coherently (i.e. to the ACP port on Cortex-A9 or A15). The arm_dma_ops
> are modified at boot when arch_is_coherent is true.
>
> Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Marek Szyprowski <m.szyprowski@samsung.com>
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>
>
> This is the only patch lately that I could find (not that I would claim
> to be any good at finding things) that is related to the problem. Could
> it have caused the allocations to fail?
>
> Regards
> Tony P
Have done a bit more digging and found the cause - not Rob's patch so
apologies.
The cause of the regression is this patch:
>From f40d1e42bb988d2a26e8e111ea4c4c7bac819b7e Mon Sep 17 00:00:00 2001
From: Mel Gorman <mgorman@suse.de>
Date: Mon, 8 Oct 2012 16:32:36 -0700
Subject: [PATCH 2/3] mm: compaction: acquire the zone->lock as late as
possible
Up until then, the framebuffer allocation with dma_alloc_coherent(...)
was fine. From this patch onwards, allocations fail.
I don't know how this patch would effect CMA allocations, but it seems
to be causing the issue (or at least, it's caused an error in
arch-vt8500 to become visible).
Perhaps someone who understand -mm could explain the best way to
troubleshoot the cause of this problem?
Regards
Tony P
^ permalink raw reply
* [git pull] signals pile 3
From: Russell King - ARM Linux @ 2012-10-14 20:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <507ADBBB.9090209@gmail.com>
On Sun, Oct 14, 2012 at 05:35:23PM +0200, Daniel Mack wrote:
> I rebased my ARM development branch and figured that your patch 9fff2fa
> ("arm: switch to saner kernel_execve() semantics") breaks the boot on my
> board right after init is invoked via NFS:
Ok, I'm not going to assign blame to Al's commits (I never reviewed his
stuff before they hit mainline - patches never posted to the ARM mailing
list, and the development actually happened within the merge window,
all things we tell people not to do...) I _still_ haven't reviewed that
stuff yet.
But... nevertheless...
> [ 4.682072] VFS: Mounted root (nfs filesystem) on device 0:12.
> [ 4.690744] devtmpfs: mounted
> [ 4.694395] Freeing init memory: 172K
> [ 5.291417] Internal error: Oops - undefined instruction: 0 [#1] SMP
> THUMB2
Ok, so this tells us the kernel was built using Thumb2 ISA.
> [ 5.298734] Modules linked in:
> [ 5.301952] CPU: 0 Not tainted (3.6.0-11053-g56c8535 #128)
> [ 5.308071] PC is at cpsw_probe+0x422/0x9ac
PC is not word aligned, so it can't be running in the ARM ISA.
> [ 5.312459] LR is at trace_hardirqs_on_caller+0x8f/0xfc
> [ 5.317934] pc : [<c03493de>] lr : [<c005e81f>] psr: 60000113
Note that this reconfirms the above (well, it should do, it's the same
value.)
> [ 5.317934] sp : cf055fb0 ip : 00000000 fp : 00000000
> [ 5.329944] r10: 00000000 r9 : 00000000 r8 : 00000000
> [ 5.335413] r7 : 00000000 r6 : 00000000 r5 : c034458d r4 : 00000000
> [ 5.342244] r3 : cf057a40 r2 : 00000000 r1 : 00000001 r0 : 00000000
> [ 5.349078] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM
> Segment user
And this tells us that we're running in ARM mode, not Thumb mode.
> [ 5.356546] Control: 50c5387d Table: 8f434019 DAC: 00000015
> [ 5.362562] Process init (pid: 1, stack limit = 0xcf054240)
> [ 5.368395] Stack: (0xcf055fb0 to 0xcf056000)
> [ 5.372961] 5fa0: 00000001
> 00000000 00000000 00000000
> [ 5.381525] 5fc0: cf055fb0 c000d1a8 00000000 00000000 00000000
> 00000000 00000000 00000000
> [ 5.390091] 5fe0: 00000000 bee83f10 00000000 b6fdedd0 00000010
> 00000000 aaaabfaf a8babbaa
No stack backtrace (and it's silent about why that is).
The other strange thing here is that the stack dump above is showing that
the stack is completely empty - which shouldn't be the case if we're in a
driver probe function - driver probe functions are called via the driver
model layers...
> [ 5.398664] Code: 2206a010 718ef508 0184f8da f8b1f65d (3070f8d8)
And now we come to the Code: line, which makes no sense as an ARM ISA:
0: 2206a010 andcs sl, r6, #16
4: 718ef508 orrvc pc, lr, r8, lsl #10
8: 0184f8da ldrdeq pc, [r4, sl]
c: f8b1f65d ; <UNDEFINED> instruction: 0xf8b1f65d
10: 3070f8d8 ldrsbtcc pc, [r0], #-136 ; 0xffffff78 ; <UNPREDICTABLE>
But as Thumb, it looks more reasonable:
0: a010 add r0, pc, #64 ; (adr r0, 44 <foo+0x44>)
2: 2206 movs r2, #6
4: f508 718e add.w r1, r8, #284 ; 0x11c
8: f8da 0184 ldr.w r0, [sl, #388] ; 0x184
c: f65d f8b1 bl ffe5d172 <foo+0xffe5d172>
10: f8d8 3070 ldr.w r3, [r8, #112] ; 0x70
I don't have any further comments to make on this yet, as I've no idea
what state stuff is in, but the above oops dump to me suggests that
we've randomly jumped into some part of the kernel which just happens
to be cpsw_probe().
Please send me (in private mail) your vmlinux file and a corresponding
oops dump from that same kernel, and I'll dig and try and work out
what's going on...
This kind of investigation reminds me of those I did back in the 1990s
when stuff was rather unstable and ARM was a young architecture. Now
all we need is for an ARM platform to dump its entire memory out the
ethernet port, bringing an university department network to a halt (I
did that once - back in the 1990s - sorry Tim!)
^ permalink raw reply
* [PULL REQ] IXP4xx changes for Linux 3.7
From: Arnd Bergmann @ 2012-10-14 20:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <m3bog6m5iz.fsf@intrepid.localdomain>
On Saturday 13 October 2012, Krzysztof Halasa wrote:
> Linus,
>
> please pull my ARM IXP4xx changes for 3.7:
>
> The following changes since commit 4d7127dace8cf4b05eb7c8c8531fc204fbb195f4:
>
> "Merge branch 'for-linus' of git://git.kernel.org/.../jmorris/linux-security"
> (2012-10-13 11:29:00 +0900)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/chris/linux.git next
>
> for you to fetch changes up to b94740b3b38fd8e37fcd3bb06a18ec2796061c7d:
> IXP4xx: use __iomem for MMIO (2012-10-13 20:37:30 +0200)
>
> Build-tested for now. This is based on your current tree tip because it
> depends on commits following 3.6 release.
Hi Krzysztof,
as mentioned before, all arch/arm/mach-* patches should go through the
arm-soc tree or get an Ack from the arm-soc maintainers. The same thing
is true for the char-misc and the crypto trees.
Also, never rebase your tree immediately before sending a pull request.
The preferred way is to have everything based on the -rc release that
is the latest one at the time when you do your testing. If you rebase
later, you essentially have to test everything again.
Finally when sending bug fixes, please annotate any patches with
'Cc: stable at vger.kernel.org' if they address bugs that are already
present in older kernels, so that the stable and longterm maintainers
can easily backport the fixes.
Almost all of the platform patches in your tree seem to be bug fixes,
so they are still good for inclusion in v3.7 if you submit them to
arm-soc soon, but please make sure you separate bug fixes from other
changes so we can group them appropriately when forwarding them to
Linus.
Thanks,
Arnd
^ permalink raw reply
* [revert request for commit 9fff2fa] Re: [git pull] signals pile 3
From: Al Viro @ 2012-10-14 19:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121014192402.GZ2616@ZenIV.linux.org.uk>
On Sun, Oct 14, 2012 at 08:24:03PM +0100, Al Viro wrote:
> Russell, could you recall what those had been about? I'm not sure if that
> had been oopsable that far back (again, oops scenario is userland stack
> page getting swapped out before we get to start_thread(), leading to
> direct read from an absent page in start_thread() by plain ldr, without
> anything in exception table about that insn), but it looks very odd
> regardless of that problem.
BTW, arm64 has copied that logics, so it also seems to be unsafe and very
odd - there we definitely have only ELF to cope with. arm64 folks Cc'd...
^ permalink raw reply
* [revert request for commit 9fff2fa] Re: [git pull] signals pile 3
From: Al Viro @ 2012-10-14 19:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121014172640.GW2616@ZenIV.linux.org.uk>
On Sun, Oct 14, 2012 at 06:26:40PM +0100, Al Viro wrote:
> and the last 3 make no sense whatsoever. Note that on normal execve() we'll
> be going through the syscall return, so the userland will see 0 in there,
> no matter what do we do here. Theoretically, it might've been done for
> ptrace sake (it will be able to observe the values in those registers before
> the tracee reaches userland),
Except that it won't be able to see what start_thread() puts in r0 either;
on successful exceve(2) we will store return value of sys_execve() (i.e. 0)
in regs->ARM_r0 before we get to any of the places where it could have
examine the sucker. So what was that assignment for? And as far as I can
see, ARM ELF ABI says that general register values on process startup are
undefined, so r1 and r2 assignments also seem to be pointless. OTOH, they
predate the ELF conversion by quite a but - that code had been there since
1.x times, when we used to use a.out... In any case, they were *not* going
to be usable as main() arguments - zero argc would make userland rather
unhappy. I don't have arm libc sources from those times, but I'd expect
it to have all those suckers read from userland stack...
Russell, could you recall what those had been about? I'm not sure if that
had been oopsable that far back (again, oops scenario is userland stack
page getting swapped out before we get to start_thread(), leading to
direct read from an absent page in start_thread() by plain ldr, without
anything in exception table about that insn), but it looks very odd
regardless of that problem.
^ permalink raw reply
* [PATCH 9/9] ARM: add uprobes support
From: Rabin Vincent @ 2012-10-14 19:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350242593-17761-1-git-send-email-rabin@rab.in>
Add basic uprobes support for ARM.
perf probe --exec and SystemTap's userspace probing work. The ARM
kprobes test code has also been run in a userspace harness to test the
uprobe instruction decoding.
Caveats:
- Thumb is not supported
- XOL abort/trap handling is not implemented
Signed-off-by: Rabin Vincent <rabin@rab.in>
---
arch/arm/Kconfig | 4 +
arch/arm/include/asm/ptrace.h | 6 ++
arch/arm/include/asm/thread_info.h | 5 +-
arch/arm/include/asm/uprobes.h | 34 +++++++
arch/arm/kernel/Makefile | 1 +
arch/arm/kernel/signal.c | 4 +
arch/arm/kernel/uprobes.c | 191 ++++++++++++++++++++++++++++++++++++
7 files changed, 244 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/include/asm/uprobes.h
create mode 100644 arch/arm/kernel/uprobes.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 272c3a1..2191b61d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -168,6 +168,10 @@ config ZONE_DMA
config NEED_DMA_MAP_STATE
def_bool y
+config ARCH_SUPPORTS_UPROBES
+ depends on KPROBES
+ 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 142d6ae..297936a 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -197,6 +197,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 8477b4c..7bedaee 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -148,6 +148,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
@@ -160,6 +161,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)
@@ -172,7 +174,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 0000000..fa4b81e
--- /dev/null
+++ b/arch/arm/include/asm/uprobes.h
@@ -0,0 +1,34 @@
+#ifndef _ASM_UPROBES_H
+#define _ASM_UPROBES_H
+
+#include <asm/probes.h>
+
+typedef u32 uprobe_opcode_t;
+
+#define MAX_UINSN_BYTES 4
+#define UPROBE_XOL_SLOT_BYTES 64
+
+#define UPROBE_SWBP_INSN 0x07f001f9
+#define UPROBE_SS_INSN 0x07f001fa
+#define UPROBE_SWBP_INSN_SIZE 4
+
+struct arch_uprobe_task {
+ u32 backup;
+};
+
+struct arch_uprobe {
+ u8 insn[MAX_UINSN_BYTES];
+ uprobe_opcode_t modinsn;
+ 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_specific_insn asi;
+};
+
+#endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 5bbec7b..a39f634 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -40,6 +40,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) += uprobes.o uprobes-arm.o kprobes-arm.o
obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o patch.o
ifdef CONFIG_THUMB2_KERNEL
obj-$(CONFIG_KPROBES) += kprobes-thumb.o
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 56f72d2..3b1e88e 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -12,6 +12,7 @@
#include <linux/personality.h>
#include <linux/uaccess.h>
#include <linux/tracehook.h>
+#include <linux/uprobes.h>
#include <asm/elf.h>
#include <asm/cacheflush.h>
@@ -655,6 +656,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.c b/arch/arm/kernel/uprobes.c
new file mode 100644
index 0000000..f25a4af
--- /dev/null
+++ b/arch/arm/kernel/uprobes.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2012 Rabin Vincent <rabin@rab.in>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/uprobes.h>
+#include <linux/notifier.h>
+#include <linux/kprobes.h>
+
+#include <asm/opcodes.h>
+#include <asm/traps.h>
+
+#include "kprobes.h"
+
+bool is_swbp_insn(uprobe_opcode_t *insn)
+{
+ return (__mem_to_opcode_arm(*insn) & 0x0fffffff) == UPROBE_SWBP_INSN;
+}
+
+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)
+{
+ struct kprobe kp;
+
+ if (!auprobe->simulate)
+ return false;
+
+ kp.addr = (void *) regs->ARM_pc;
+ kp.opcode = __mem_to_opcode_arm(*(unsigned int *) auprobe->insn);
+ kp.ainsn.insn_handler = auprobe->asi.insn_handler;
+
+ auprobe->asi.insn_singlestep(&kp, regs);
+
+ return true;
+}
+
+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
+ unsigned long addr)
+{
+ unsigned int insn;
+ unsigned int bpinsn;
+ enum kprobe_insn ret;
+
+ /* Thumb not yet support */
+ if (addr & 0x3)
+ return -EINVAL;
+
+ insn = __mem_to_opcode_arm(*(unsigned int *)auprobe->insn);
+ auprobe->modinsn = insn;
+
+ ret = arm_kprobe_decode_insn(insn, &auprobe->asi, true);
+ switch (ret) {
+ case INSN_REJECTED:
+ return -EINVAL;
+
+ case INSN_GOOD_NO_SLOT:
+ auprobe->simulate = true;
+ break;
+
+ case INSN_GOOD:
+ default:
+ break;
+ }
+
+ bpinsn = UPROBE_SWBP_INSN;
+ if (insn >= 0xe0000000)
+ bpinsn |= 0xe0000000; /* Unconditional instruction */
+ else
+ bpinsn |= insn & 0xf0000000; /* Copy condition from insn */
+
+ auprobe->bpinsn = bpinsn;
+
+ return 0;
+}
+
+void arch_uprobe_write_opcode(struct arch_uprobe *auprobe, void *vaddr,
+ uprobe_opcode_t opcode)
+{
+ unsigned long *addr = vaddr;
+
+ if (opcode == UPROBE_SWBP_INSN)
+ opcode = __opcode_to_mem_arm(auprobe->bpinsn);
+
+ *addr = opcode;
+}
+
+void arch_uprobe_xol_copy(struct arch_uprobe *auprobe, void *vaddr)
+{
+ unsigned long *addr = vaddr;
+
+ addr[0] = __opcode_to_mem_arm(auprobe->modinsn);
+ addr[1] = __opcode_to_mem_arm(0xe0000000 | UPROBE_SS_INSN);
+}
+
+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);
+
+ 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;
+
+ 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)
+{
+ /* TODO: implement */
+ return false;
+}
+
+void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+ /* TODO: implement */
+}
+
+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);
+ if ((instr & 0x0fffffff) == UPROBE_SWBP_INSN)
+ uprobe_pre_sstep_notifier(regs);
+ else
+ 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_INSN,
+ .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_INSN,
+ .cpsr_mask = MODE_MASK,
+ .cpsr_val = USR_MODE,
+ .fn = uprobe_trap_handler,
+};
+
+int arch_uprobes_init(void)
+{
+ register_undef_hook(&uprobes_arm_break_hook);
+ register_undef_hook(&uprobes_arm_ss_hook);
+
+ return 0;
+}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 8/9] ARM: support uprobe handling
From: Rabin Vincent @ 2012-10-14 19:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350242593-17761-1-git-send-email-rabin@rab.in>
Extend the kprobes code to handle user-space probes. Much of the code
can be reused so currently the ARM uprobes code reuses the kprobes
structures. The decode tables are reused, with the modification that
for those instruction that require custom decoding for uprobes, a new
element is added in the table to specify a custom decoder function.
Thumb is not handled.
Cc: Jon Medhurst <tixy@yxit.co.uk>
Signed-off-by: Rabin Vincent <rabin@rab.in>
---
arch/arm/include/asm/kprobes.h | 17 +---
arch/arm/include/asm/probes.h | 23 +++++
arch/arm/kernel/kprobes-arm.c | 27 +++++-
arch/arm/kernel/kprobes-common.c | 63 ++++++++++----
arch/arm/kernel/kprobes-test.c | 12 ++-
arch/arm/kernel/kprobes-thumb.c | 31 ++++---
arch/arm/kernel/kprobes.c | 2 +-
arch/arm/kernel/kprobes.h | 36 +++++---
arch/arm/kernel/uprobes-arm.c | 178 ++++++++++++++++++++++++++++++++++++++
arch/arm/kernel/uprobes.h | 23 +++++
10 files changed, 349 insertions(+), 63 deletions(-)
create mode 100644 arch/arm/include/asm/probes.h
create mode 100644 arch/arm/kernel/uprobes-arm.c
create mode 100644 arch/arm/kernel/uprobes.h
diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h
index f82ec22..53b1a80 100644
--- a/arch/arm/include/asm/kprobes.h
+++ b/arch/arm/include/asm/kprobes.h
@@ -27,22 +27,7 @@
#define flush_insn_slot(p) do { } while (0)
#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 <asm/probes.h>
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 0000000..df46994
--- /dev/null
+++ b/arch/arm/include/asm/probes.h
@@ -0,0 +1,23 @@
+#ifndef _ASM_PROBES_H
+#define _ASM_PROBES_H
+
+#ifdef CONFIG_KPROBES
+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;
+};
+#endif
+
+#endif
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c
index 8a30c89..d9cf0e2 100644
--- a/arch/arm/kernel/kprobes-arm.c
+++ b/arch/arm/kernel/kprobes-arm.c
@@ -62,6 +62,7 @@
#include <linux/kprobes.h>
#include <linux/module.h>
+#include "uprobes.h"
#include "kprobes.h"
#define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit)))))
@@ -545,31 +546,37 @@ 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 */
+ UDECODE_NEXT (decode_pc_ro)
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 */
+ UDECODE_NEXT (decode_pc_ro)
DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd,
REGS(NOPCWB, NOPCX, 0, 0, 0)),
/* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */
+ UDECODE_NEXT (decode_pc_ro)
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 */
+ UDECODE_NEXT (decode_pc_ro)
DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr,
REGS(NOPCWB, NOPC, 0, 0, NOPC)),
/* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */
+ UDECODE_NEXT (decode_pc_ro)
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 */
+ UDECODE_NEXT (decode_pc_ro)
DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr,
REGS(NOPCWB, NOPC, 0, 0, 0)),
@@ -589,11 +596,13 @@ static const union decode_item arm_cccc_000x_table[] = {
/* 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 */
+ UDECODE_NEXT (decode_rd12rn16rm0rs8_rwflags)
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 */
+ UDECODE_NEXT (decode_rd12rn16rm0rs8_rwflags)
DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags,
REGS(0, ANY, 0, 0, ANY)),
@@ -607,6 +616,7 @@ 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 */
+ UDECODE_NEXT (decode_rd12rn16rm0rs8_rwflags)
DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags,
REGS(ANY, ANY, 0, 0, ANY)),
@@ -614,11 +624,13 @@ static const union decode_item arm_cccc_000x_table[] = {
/* 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 */
+ UDECODE_NEXT (decode_rd12rn16rm0rs8_rwflags)
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 */
+ UDECODE_NEXT (decode_rd12rn16rm0rs8_rwflags)
DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags,
REGS(0, ANY, NOPC, 0, ANY)),
@@ -632,6 +644,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 */
+ UDECODE_NEXT (decode_rd12rn16rm0rs8_rwflags)
DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags,
REGS(ANY, ANY, NOPC, 0, ANY)),
@@ -666,11 +679,13 @@ 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 */
+ UDECODE_NEXT (decode_rd12rn16rm0rs8_rwflags)
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 */
+ UDECODE_NEXT (decode_rd12rn16rm0rs8_rwflags)
DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags,
REGS(0, ANY, 0, 0, 0)),
@@ -684,6 +699,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 */
+ UDECODE_NEXT (decode_rd12rn16rm0rs8_rwflags)
DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags,
REGS(ANY, ANY, 0, 0, 0)),
@@ -850,21 +866,25 @@ 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 */
+ UDECODE_NEXT (decode_pc_ro)
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 */
+ UDECODE_NEXT (decode_ldr)
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 */
+ UDECODE_NEXT (decode_pc_ro)
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 */
+ UDECODE_NEXT (decode_ldr)
DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr,
REGS(NOPCWB, ANY, 0, 0, NOPC)),
@@ -876,6 +896,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 */
+ UDECODE_NEXT (uprobe_decode_ldmstm)
DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm),
/* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */
@@ -997,9 +1018,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,
+ bool uprobe)
{
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,
+ uprobe);
}
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c
index 18a7628..f811bfb 100644
--- a/arch/arm/kernel/kprobes-common.c
+++ b/arch/arm/kernel/kprobes-common.c
@@ -277,7 +277,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,
+ void *d)
{
kprobe_insn_handler_t *handler = 0;
unsigned reglist = insn & 0xffff;
@@ -389,7 +390,7 @@ 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(kprobe_opcode_t *pinsn, u32 regs, bool modify)
{
kprobe_opcode_t insn = *pinsn;
kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */
@@ -450,12 +451,16 @@ static bool __kprobes decode_regs(kprobe_opcode_t* pinsn, u32 regs)
break;
}
- /* Replace value of nibble with new register number... */
- insn &= ~mask;
- insn |= new_bits & mask;
+ if (modify) {
+ /* Replace value of nibble with new register number */
+ insn &= ~mask;
+ insn |= new_bits & mask;
+ }
}
- *pinsn = insn;
+ if (modify)
+ *pinsn = insn;
+
return true;
reject:
@@ -468,7 +473,8 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
[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)
+ [DECODE_TYPE_REJECT] = sizeof(struct decode_reject),
+ [UDECODE_TYPE_NEXT] = sizeof(struct decode_header)
};
/*
@@ -516,13 +522,17 @@ 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,
+ bool uprobe)
{
+ enum kprobe_insn (*decoder)(kprobe_opcode_t,
+ struct arch_specific_insn *, void *d) = NULL;
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 (!uprobe)
+ insn = prepare_emulated_insn(insn, asi, thumb);
for (;; h = next) {
enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
@@ -534,13 +544,24 @@ kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
next = (struct decode_header *)
((uintptr_t)h + decode_struct_sizes[type]);
- if (!matched && (insn & h->mask.bits) != h->value.bits)
+ if (!uprobe && type == UDECODE_TYPE_NEXT)
continue;
- if (!decode_regs(&insn, regs))
- return INSN_REJECTED;
+ if (type != UDECODE_TYPE_NEXT) {
+ if (!matched &&
+ (insn & h->mask.bits) != h->value.bits) {
+ decoder = NULL;
+ continue;
+ }
+
+ if (!decode_regs(&insn, regs, !uprobe))
+ return INSN_REJECTED;
+ }
switch (type) {
+ case UDECODE_TYPE_NEXT:
+ decoder = h->mask.decoder;
+ break;
case DECODE_TYPE_TABLE: {
struct decode_table *d = (struct decode_table *)h;
@@ -550,7 +571,11 @@ 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);
+
+ if (decoder)
+ return decoder(insn, asi, d);
+
+ return (*d->decoder.decoder)(insn, asi, d);
}
case DECODE_TYPE_SIMULATE: {
@@ -561,8 +586,14 @@ kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
case DECODE_TYPE_EMULATE: {
struct decode_emulate *d = (struct decode_emulate *)h;
- asi->insn_handler = d->handler.handler;
- set_emulated_insn(insn, asi, thumb);
+
+ if (decoder)
+ return decoder(insn, asi, d);
+
+ if (!uprobe) {
+ asi->insn_handler = d->handler.handler;
+ set_emulated_insn(insn, asi, thumb);
+ }
return INSN_GOOD;
}
@@ -574,5 +605,5 @@ kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
default:
return INSN_REJECTED;
}
- }
}
+}
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c
index 1862d8f..a2d4213 100644
--- a/arch/arm/kernel/kprobes-test.c
+++ b/arch/arm/kernel/kprobes-test.c
@@ -630,7 +630,8 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
[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)
+ [DECODE_TYPE_REJECT] = sizeof(struct decode_reject),
+ [UDECODE_TYPE_NEXT] = sizeof(struct decode_header)
};
static int table_iter(const union decode_item *table,
@@ -646,9 +647,11 @@ static int table_iter(const union decode_item *table,
if (type == DECODE_TYPE_END)
return 0;
- result = fn(h, args);
- if (result)
- return result;
+ if (type != UDECODE_TYPE_NEXT) {
+ result = fn(h, args);
+ if (result)
+ return result;
+ }
h = (struct decode_header *)
((uintptr_t)h + decode_struct_sizes[type]);
@@ -918,6 +921,7 @@ static void coverage_add(kprobe_opcode_t insn)
break;
case DECODE_TYPE_REJECT:
+ case UDECODE_TYPE_NEXT:
default:
return;
}
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c
index 6123daf..761aa55 100644
--- a/arch/arm/kernel/kprobes-thumb.c
+++ b/arch/arm/kernel/kprobes-thumb.c
@@ -83,7 +83,8 @@ t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs)
}
static enum kprobe_insn __kprobes
-t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi,
+ void *d)
{
int cc = (insn >> 22) & 0xf;
asi->insn_check_cc = kprobe_condition_checks[cc];
@@ -158,9 +159,10 @@ t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs)
}
static enum kprobe_insn __kprobes
-t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi,
+ void *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];
@@ -1046,7 +1048,7 @@ t16_singlestep_it(struct kprobe *p, struct pt_regs *regs)
}
static enum kprobe_insn __kprobes
-t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi, void *d)
{
asi->insn_singlestep = t16_singlestep_it;
return INSN_GOOD_NO_SLOT;
@@ -1063,7 +1065,8 @@ t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs)
}
static enum kprobe_insn __kprobes
-t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi,
+ void *d)
{
int cc = (insn >> 8) & 0xf;
asi->insn_check_cc = kprobe_condition_checks[cc];
@@ -1149,7 +1152,7 @@ t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs)
}
static enum kprobe_insn __kprobes
-t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi, void *d)
{
insn &= ~0x00ff;
insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
@@ -1175,7 +1178,7 @@ t16_emulate_push(struct kprobe *p, struct pt_regs *regs)
}
static enum kprobe_insn __kprobes
-t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi, void *d)
{
/*
* To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}"
@@ -1225,7 +1228,7 @@ t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs)
}
static enum kprobe_insn __kprobes
-t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi)
+t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi, void *d)
{
/*
* To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}"
@@ -1453,17 +1456,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,
+ bool uprobes)
{
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,
+ uprobes);
}
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,
+ bool uprobes)
{
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,
+ uprobes);
}
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
index 4dd41fc..1b2a324 100644
--- a/arch/arm/kernel/kprobes.c
+++ b/arch/arm/kernel/kprobes.c
@@ -80,7 +80,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
p->opcode = insn;
p->ainsn.insn = tmp_insn;
- switch ((*decode_insn)(insn, &p->ainsn)) {
+ switch ((*decode_insn)(insn, &p->ainsn, false)) {
case INSN_REJECTED: /* not supported */
return -EINVAL;
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h
index 38945f7..442a161 100644
--- a/arch/arm/kernel/kprobes.h
+++ b/arch/arm/kernel/kprobes.h
@@ -35,20 +35,19 @@ enum kprobe_insn {
};
typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t,
- struct arch_specific_insn *);
-
-#ifdef CONFIG_THUMB2_KERNEL
+ struct arch_specific_insn *,
+ bool uprobes);
enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t,
- struct arch_specific_insn *);
+ struct arch_specific_insn *,
+ bool uprobes);
enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t,
- struct arch_specific_insn *);
-
-#else /* !CONFIG_THUMB2_KERNEL */
+ struct arch_specific_insn *,
+ bool uprobes);
enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t,
- struct arch_specific_insn *);
-#endif
+ struct arch_specific_insn *,
+ bool uprobes);
void __init arm_kprobe_decode_init(void);
@@ -165,7 +164,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,
+ void *d);
/*
* Test if load/store instructions writeback the address register.
@@ -292,6 +292,7 @@ enum decode_type {
DECODE_TYPE_EMULATE,
DECODE_TYPE_OR,
DECODE_TYPE_REJECT,
+ UDECODE_TYPE_NEXT,
NUM_DECODE_TYPES /* Must be last enum */
};
@@ -331,7 +332,9 @@ union decode_item {
u32 bits;
const union decode_item *table;
kprobe_insn_handler_t *handler;
- kprobe_decode_insn_t *decoder;
+ enum kprobe_insn (*decoder)(kprobe_opcode_t,
+ struct arch_specific_insn *,
+ void *d);
};
@@ -396,6 +399,14 @@ struct decode_emulate {
#define DECODE_EMULATE(_mask, _value, _handler) \
DECODE_EMULATEX(_mask, _value, _handler, 0)
+#ifdef CONFIG_UPROBES
+#define UDECODE_NEXT(_decoder) \
+ {.bits = UDECODE_TYPE_NEXT }, \
+ {.decoder = _decoder}, \
+ {.bits = 0 },
+#else
+#define UDECODE_NEXT(_decoder)
+#endif
struct decode_or {
struct decode_header header;
@@ -422,7 +433,8 @@ extern const union decode_item kprobe_decode_arm_table[];
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,
+ bool uprobe);
#endif /* _ARM_KERNEL_KPROBES_H */
diff --git a/arch/arm/kernel/uprobes-arm.c b/arch/arm/kernel/uprobes-arm.c
new file mode 100644
index 0000000..8d7de10
--- /dev/null
+++ b/arch/arm/kernel/uprobes-arm.c
@@ -0,0 +1,178 @@
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/uprobes.h>
+#include <linux/module.h>
+
+#include "uprobes.h"
+#include "kprobes.h"
+
+static int uprobes_substitute_pc(kprobe_opcode_t *pinsn, u32 oregs)
+{
+ kprobe_opcode_t insn = *pinsn;
+ kprobe_opcode_t temp;
+ kprobe_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 = *pinsn;
+ insn = *pinsn;
+ 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 = 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 kprobe_insn
+decode_pc_ro(kprobe_opcode_t insn, struct arch_specific_insn *asi, void *d)
+{
+ struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, asi);
+ struct decode_emulate *decode = d;
+ u32 regs = decode->header.type_regs.bits >> DECODE_TYPE_BITS;
+ int reg;
+
+ reg = uprobes_substitute_pc(&auprobe->modinsn, 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 kprobe_insn
+decode_wb_pc(kprobe_opcode_t insn, struct arch_specific_insn *asi,
+ void *d, bool alu)
+{
+ struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe, asi);
+ enum kprobe_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 kprobe_insn
+decode_rd12rn16rm0rs8_rwflags(kprobe_opcode_t insn,
+ struct arch_specific_insn *asi, void *d)
+{
+ return decode_wb_pc(insn, asi, d, true);
+}
+
+enum kprobe_insn
+decode_ldr(kprobe_opcode_t insn, struct arch_specific_insn *asi, void *d)
+{
+ return decode_wb_pc(insn, asi, d, false);
+}
+
+enum kprobe_insn
+uprobe_decode_ldmstm(kprobe_opcode_t insn,
+ struct arch_specific_insn *asi, void *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->modinsn = insn;
+
+ auprobe->prehandler = uprobe_set_pc;
+ if (lbit)
+ auprobe->posthandler = uprobe_write_pc;
+ else
+ auprobe->posthandler = uprobe_unset_pc;
+
+ return INSN_GOOD;
+}
diff --git a/arch/arm/kernel/uprobes.h b/arch/arm/kernel/uprobes.h
new file mode 100644
index 0000000..a1a4897
--- /dev/null
+++ b/arch/arm/kernel/uprobes.h
@@ -0,0 +1,23 @@
+#ifndef __ARM_KERNEL_UPROBES_H
+#define __ARM_KERNEL_UPROBES_H
+
+enum kprobe_insn uprobe_decode_ldmstm(kprobe_opcode_t insn,
+ struct arch_specific_insn *asi,
+ void *d);
+
+enum kprobe_insn decode_ldr(kprobe_opcode_t insn,
+ struct arch_specific_insn *asi,
+ void *d);
+
+enum kprobe_insn
+decode_rd12rn16rm0rs8_rwflags(kprobe_opcode_t insn,
+ struct arch_specific_insn *asi, void *d);
+
+enum kprobe_insn
+decode_wb_pc(kprobe_opcode_t insn, struct arch_specific_insn *asi,
+ void *d, bool alu);
+
+enum kprobe_insn
+decode_pc_ro(kprobe_opcode_t insn, struct arch_specific_insn *asi, void *d);
+
+#endif
--
1.7.9.5
^ permalink raw reply related
* [PATCH 7/9] uprobes: add arch write opcode hook
From: Rabin Vincent @ 2012-10-14 19:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350242593-17761-1-git-send-email-rabin@rab.in>
Allow arches to write the opcode with a custom function. ARM needs to
customize the swbp instruction depending on the condition code of the
instruction it replaces.
Signed-off-by: Rabin Vincent <rabin@rab.in>
---
include/linux/uprobes.h | 3 +++
kernel/events/uprobes.c | 8 +++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index c3dc5de..35b9490 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -131,6 +131,9 @@ extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs)
extern bool __weak arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs);
extern void __weak arch_uprobe_xol_copy(struct arch_uprobe *auprobe, void *vaddr);
extern int __weak arch_uprobes_init(void);
+extern void __weak arch_uprobe_write_opcode(struct arch_uprobe *auprobe,
+ void *vaddr,
+ uprobe_opcode_t opcode);
#else /* !CONFIG_UPROBES */
struct uprobes_state {
};
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 8c52f93..95ea618 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -203,6 +203,12 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn)
* have fixed length instructions.
*/
+void __weak arch_uprobe_write_opcode(struct arch_uprobe *auprobe, void *vaddr,
+ uprobe_opcode_t opcode)
+{
+ memcpy(vaddr, &opcode, UPROBE_SWBP_INSN_SIZE);
+}
+
/*
* write_opcode - write the opcode at a given virtual address.
* @auprobe: arch breakpointing information.
@@ -242,7 +248,7 @@ retry:
vaddr_new = kmap_atomic(new_page);
memcpy(vaddr_new, vaddr_old, PAGE_SIZE);
- memcpy(vaddr_new + (vaddr & ~PAGE_MASK), &opcode, UPROBE_SWBP_INSN_SIZE);
+ arch_uprobe_write_opcode(auprobe, vaddr_new + (vaddr & ~PAGE_MASK), opcode);
kunmap_atomic(vaddr_new);
kunmap_atomic(vaddr_old);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 6/9] uprobes: flush cache after xol write
From: Rabin Vincent @ 2012-10-14 19:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350242593-17761-1-git-send-email-rabin@rab.in>
Flush the cache so that the instructions written to the XOL area are
visible.
Signed-off-by: Rabin Vincent <rabin@rab.in>
---
kernel/events/uprobes.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index ca000a9..8c52f93 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1246,6 +1246,7 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot
offset = current->utask->xol_vaddr & ~PAGE_MASK;
vaddr = kmap_atomic(area->page);
arch_uprobe_xol_copy(&uprobe->arch, vaddr + offset);
+ flush_dcache_page(area->page);
kunmap_atomic(vaddr);
return current->utask->xol_vaddr;
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox