On Fri, Nov 08, 2013 at 09:40:18AM +0000, Will Deacon wrote:
> Hi Dave,
>
> On Thu, Nov 07, 2013 at 08:51:36PM +0000, Dave Martin wrote:
> > Copying a function with memcpy() and then trying to execute the
> > result isn't trivially portable to Thumb.
> >
> > This patch modifies the kexec soft restart code to copy its
> > assembler trampoline relocate_new_kernel() using fncpy() instead,
> > so that relocate_new_kernel can be in the same ISA as the rest of
> > the kernel without problems.
> >
> > Signed-off-by: Dave Martin <Dave.Martin(a)arm.com>
>
> [...]
>
> > @@ -168,16 +171,16 @@ void machine_kexec(struct kimage *image)
> >
> >
> > /* copy our kernel relocation code to the control code page */
> > - memcpy(reboot_code_buffer,
> > - relocate_new_kernel, relocate_new_kernel_size);
> > + reboot_entry = fncpy(reboot_code_buffer,
> > + reboot_entry,
> > + relocate_new_kernel_size);
>
> My only slight gripe with this is that relocate_new_kernel_size also
> includes a bunch of data following the function (which you have now delimited
> with ENTRY/ENDPROC), so using fncpy for that feels a bit awkward.
ENDPROC() is pretty much a no-op apart from determining the symbol type.
However, putting it after the literaloids will be more consistent with
the GCC behaviour, even if Linux does not make any real use of the ELF
symbol size information.
It would be breathtakingly sensible if there was an ELF relocation to
get the size of a function symbol directly so that we wouldn't need the
silly relocate_new_kernel_size symbol ... but unfortunately, there isn't.
Will make the change and repost.
Cheers
---Dave
Copying a function with memcpy() and then trying to execute the
result isn't trivially portable to Thumb.
This patch modifies the kexec soft restart code to copy its
assembler trampoline relocate_new_kernel() using fncpy() instead,
so that relocate_new_kernel can be in the same ISA as the rest of
the kernel without problems.
Signed-off-by: Dave Martin <Dave.Martin(a)arm.com>
---
Tested on Versatile Express TC2, to boot an ARM kernel from Thumb and
vice-versa.
I believe this brings v7M compatibility closer, but we still need to
avoid the final "bx lr" attempting to switch to ARM in that case --
I think that will undef or fault or something. I don't think we need
to worry about that until someone actually wants it to work. This
patch should not increase the amount of brokenness for v7M.
arch/arm/kernel/machine_kexec.c | 17 ++++++++++-------
arch/arm/kernel/relocate_kernel.S | 8 ++++++--
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index 57221e3..f0d180d 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -14,11 +14,12 @@
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
+#include <asm/fncpy.h>
#include <asm/mach-types.h>
#include <asm/smp_plat.h>
#include <asm/system_misc.h>
-extern const unsigned char relocate_new_kernel[];
+extern void relocate_new_kernel(void);
extern const unsigned int relocate_new_kernel_size;
extern unsigned long kexec_start_address;
@@ -142,6 +143,8 @@ void machine_kexec(struct kimage *image)
{
unsigned long page_list;
unsigned long reboot_code_buffer_phys;
+ unsigned long reboot_entry = (unsigned long)relocate_new_kernel;
+ unsigned long reboot_entry_phys;
void *reboot_code_buffer;
/*
@@ -168,16 +171,16 @@ void machine_kexec(struct kimage *image)
/* copy our kernel relocation code to the control code page */
- memcpy(reboot_code_buffer,
- relocate_new_kernel, relocate_new_kernel_size);
+ reboot_entry = fncpy(reboot_code_buffer,
+ reboot_entry,
+ relocate_new_kernel_size);
+ reboot_entry_phys = (unsigned long)reboot_entry +
+ (reboot_code_buffer_phys - (unsigned long)reboot_code_buffer);
-
- flush_icache_range((unsigned long) reboot_code_buffer,
- (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
printk(KERN_INFO "Bye!\n");
if (kexec_reinit)
kexec_reinit();
- soft_restart(reboot_code_buffer_phys);
+ soft_restart(reboot_entry_phys);
}
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S
index d0cdedf..f2c1691 100644
--- a/arch/arm/kernel/relocate_kernel.S
+++ b/arch/arm/kernel/relocate_kernel.S
@@ -2,10 +2,12 @@
* relocate_kernel.S - put the kernel image in place to boot
*/
+#include <linux/linkage.h>
#include <asm/kexec.h>
- .globl relocate_new_kernel
-relocate_new_kernel:
+ .align 3 /* not needed for this code, but keeps fncpy() happy */
+
+ENTRY(relocate_new_kernel)
ldr r0,kexec_indirection_page
ldr r1,kexec_start_address
@@ -60,6 +62,8 @@ relocate_new_kernel:
ARM( mov pc, lr )
THUMB( bx lr )
+ENDPROC(relocate_new_kernel)
+
.align
.globl kexec_start_address
--
1.7.9.5
Automated DT boot report for various ARM defconfigs.
Tree/Branch: next
Git describe: next-20131107
Failed boot tests (console logs at the end)
===========================================
tegra30-beaver: FAIL: tegra_defconfig
tegra30-beaver: FAIL: multi_v7_defconfig
Full Report
===========
omap2plus_defconfig
-------------------
am335x-boneblack PASS: 0 min 27.8 sec
omap3-beagle-xm PASS: 0 min 50.1 sec
am335x-bone PASS: 0 min 26.6 sec
omap4-panda PASS: 1 min 4.4 sec
omap4-panda-es PASS: 1 min 6.3 sec
omap3-tobi,3730storm PASS: 0 min 23.7 sec
omap3-tobi,3530overo PASS: 0 min 21.5 sec
tegra_defconfig
---------------
tegra30-beaver FAIL: 1 min 36.2 sec
imx_v6_v7_defconfig
-------------------
imx6dl-wandboard,wand-dual PASS: 0 min 16.8 sec
imx6dl-wandboard,wand-solo PASS: 0 min 16.8 sec
imx6q-wandboard PASS: 0 min 15.2 sec
mvebu_defconfig
---------------
armada-xp-openblocks-ax3-4 PASS: 0 min 22.0 sec
armada-370-mirabox PASS: 0 min 20.0 sec
exynos_defconfig
----------------
exynos5250-arndale PASS: 0 min 29.9 sec
multi_v7_defconfig
------------------
ste-snowball PASS: 0 min 28.5 sec
tegra30-beaver FAIL: 1 min 36.2 sec
am335x-boneblack PASS: 0 min 34.7 sec
omap3-beagle-xm PASS: 0 min 49.3 sec
armada-370-mirabox PASS: 0 min 20.6 sec
omap4-panda PASS: 1 min 0.2 sec
omap4-panda-es PASS: 0 min 59.4 sec
armada-xp-openblocks-ax3-4 PASS: 0 min 22.7 sec
imx6dl-wandboard,wand-solo PASS: 0 min 17.4 sec
am335x-bone PASS: 0 min 33.4 sec
imx6q-wandboard PASS: 0 min 15.8 sec
omap3-tobi,3730storm PASS: 0 min 22.2 sec
imx6dl-wandboard,wand-dual PASS: 0 min 16.7 sec
omap3-tobi,3530overo PASS: 0 min 19.9 sec
u8500_defconfig
---------------
ste-snowball PASS: 0 min 28.9 sec
sama5_defconfig
---------------
sama5d35ek PASS: 0 min 17.4 sec
Console logs for failures
=========================
tegra_defconfig
---------------
tegra30-beaver: FAIL: last 24 lines of boot log:
------------------------------------------------
Tegra30 (Beaver) #if test -n ${initenv}; then run initenv; fi
if test -n ${initenv}; then run initenv; fi
Tegra30 (Beaver) #if test -n ${preboot}; then run preboot; fi
if test -n ${preboot}; then run preboot; fi
(Re)start USB...
USB0: USB EHCI 1.00
scanning bus 0 for devices... 1 USB Device(s) found
scanning usb for storage devices... 0 Storage Device(s) found
scanning usb for ethernet devices... 0 Ethernet Device(s) found
Tegra30 (Beaver) # setenv autoload no; setenv autoboot no
setenv autoload no; setenv autoboot no
Tegra30 (Beaver) # dhcp
dhcp
No ethernet found.
Tegra30 (Beaver) # dhcp
dhcp
No ethernet found.
Tegra30 (Beaver) # dhcp
dhcp
No ethernet found.
Tegra30 (Beaver) # ~$off
# PYBOOT: Exception: u-boot: ERROR: timeout getting DHCP address.
# PYBOOT: Time: 96.24 seconds.
# PYBOOT: Result: FAIL
multi_v7_defconfig
------------------
tegra30-beaver: FAIL: last 24 lines of boot log:
------------------------------------------------
Tegra30 (Beaver) # if test -n ${initenv}; then run initenv; fi
if test -n ${initenv}; then run initenv; fi
Tegra30 (Beaver) #if test -n ${preboot}; then run preboot; fi
if test -n ${preboot}; then run preboot; fi
(Re)start USB...
USB0: USB EHCI 1.00
scanning bus 0 for devices... 1 USB Device(s) found
scanning usb for storage devices... 0 Storage Device(s) found
scanning usb for ethernet devices... 0 Ethernet Device(s) found
Tegra30 (Beaver) # setenv autoload no; setenv autoboot no
setenv autoload no; setenv autoboot no
Tegra30 (Beaver) #dhcp
dhcp
No ethernet found.
Tegra30 (Beaver) # dhcp
dhcp
No ethernet found.
Tegra30 (Beaver) # dhcp
dhcp
No ethernet found.
Tegra30 (Beaver) # ~$off
# PYBOOT: Exception: u-boot: ERROR: timeout getting DHCP address.
# PYBOOT: Time: 96.16 seconds.
# PYBOOT: Result: FAIL