[PATCH 08/10] arm64/kexec: Add core kexec support

Arun Chandran achandran at mvista.com
Fri Nov 7 03:01:51 PST 2014


Hi Geoff,

> diff --git a/arch/arm64/kernel/relocate_kernel.S b/arch/arm64/kernel/relocate_kernel.S
> new file mode 100644
> index 0000000..49cf9a0
> --- /dev/null
> +++ b/arch/arm64/kernel/relocate_kernel.S
> @@ -0,0 +1,184 @@
> +/*
> + * kexec for arm64
> + *
> + * Copyright (C) Linaro.
> + *
> + * 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 <asm/assembler.h>
> +#include <asm/kexec.h>
> +#include <asm/memory.h>
> +#include <asm/page.h>
> +#include <asm/proc-macros.S>
> +
> +/* The list entry flags. */
> +
> +#define IND_DESTINATION_BIT 0
> +#define IND_INDIRECTION_BIT 1
> +#define IND_DONE_BIT        2
> +#define IND_SOURCE_BIT      3
> +
> +/*
> + * relocate_new_kernel - Put a 2nd stage kernel image in place and boot it.
> + *
> + * The memory that the old kernel occupies may be overwritten when coping the
> + * new image to its final location.  To assure that the relocate_new_kernel
> + * routine which does that copy is not overwritten all code and data needed
> + * by relocate_new_kernel must be between the symbols relocate_new_kernel and
> + * relocate_new_kernel_end.  The machine_kexec() routine will copy
> + * relocate_new_kernel to the kexec control_code_page, a special page which
> + * has been set up to be preserved during the copy operation.
> + */
> +
> +.globl relocate_new_kernel
> +relocate_new_kernel:
> +
> +       /* Setup the list loop variables. */
> +
> +       ldr     x18, arm64_kexec_kimage_head    /* x18 = list entry */
> +       dcache_line_size x17, x0                /* x17 = dcache line size */
> +       mov     x16, xzr                        /* x16 = segment start */
> +       mov     x15, xzr                        /* x15 = entry ptr */
> +       mov     x14, xzr                        /* x14 = copy dest */
> +
> +       /* Check if the new image needs relocation. */
> +
> +       cbz     x18, .Ldone
> +       tbnz    x18, IND_DONE_BIT, .Ldone
> +
> +.Lloop:
> +       and     x13, x18, PAGE_MASK             /* x13 = addr */
> +
> +       /* Test the entry flags. */
> +
> +.Ltest_source:
> +       tbz     x18, IND_SOURCE_BIT, .Ltest_indirection
> +
> +       /* copy_page(x20 = dest, x21 = src) */
> +
> +       mov x20, x14
> +       mov x21, x13
> +
> +1:     ldp     x22, x23, [x21]
> +       ldp     x24, x25, [x21, #16]
> +       ldp     x26, x27, [x21, #32]
> +       ldp     x28, x29, [x21, #48]
> +       add     x21, x21, #64
> +       stnp    x22, x23, [x20]
> +       stnp    x24, x25, [x20, #16]
> +       stnp    x26, x27, [x20, #32]
> +       stnp    x28, x29, [x20, #48]
> +       add     x20, x20, #64
> +       tst     x21, #(PAGE_SIZE - 1)
> +       b.ne    1b
> +
> +       /* dest += PAGE_SIZE */
> +
> +       add     x14, x14, PAGE_SIZE
> +       b       .Lnext
> +
> +.Ltest_indirection:
> +       tbz     x18, IND_INDIRECTION_BIT, .Ltest_destination
> +
> +       /* ptr = addr */
> +
> +       mov     x15, x13
> +       b       .Lnext
> +
> +.Ltest_destination:
> +       tbz     x18, IND_DESTINATION_BIT, .Lnext
> +
> +       /* flush segment */
> +
> +       bl      .Lflush
> +       mov     x16, x13
> +
> +       /* dest = addr */
> +
> +       mov     x14, x13
> +
> +.Lnext:
> +       /* entry = *ptr++ */
> +
> +       ldr     x18, [x15], #8
> +
> +       /* while (!(entry & DONE)) */
> +
> +       tbz     x18, IND_DONE_BIT, .Lloop
> +
> +.Ldone:
> +       /* flush last segment */
> +
> +       bl      .Lflush
> +
> +       dsb     sy
> +       isb
> +       ic      ialluis
> +       dsb     sy
> +       isb
> +
> +       /* start_new_image */
> +
> +       ldr     x4, arm64_kexec_kimage_start
> +       ldr     x0, arm64_kexec_dtb_addr
> +       mov     x1, xzr
> +       mov     x2, xzr
> +       mov     x3, xzr
> +       br      x4
> +
> +/* flush - x17 = line size, x16 = start addr, x14 = end addr. */
> +
> +.Lflush:
> +       cbz     x16, 2f
> +       mov     x0, x16
> +       sub     x1, x17, #1
> +       bic     x0, x0, x1
> +1:     dc      civac, x0
> +       add     x0, x0, x17
> +       cmp     x0, x14
> +       b.lo    1b
> +2:     ret
> +

I have issue in flushing with L3 cache on . kexec does not reboot with L3.
Is the above logic of flushing (clean + invalidate) after copying the
image data is correct? Is there exist the danger of image data being
overwritten by invalid cache lines?

I tried with only invalidate(dc ivac); but that also not seems to be
working.

Finally I moved the entire flushing logic before copying then
things started working. Please see the code change below.

############
diff --git a/arch/arm64/kernel/relocate_kernel.S
b/arch/arm64/kernel/relocate_kernel.S
index 49cf9a0..f06c082 100644
--- a/arch/arm64/kernel/relocate_kernel.S
+++ b/arch/arm64/kernel/relocate_kernel.S
@@ -62,6 +62,17 @@ relocate_new_kernel:
        mov x20, x14
        mov x21, x13

+.Lflush:
+       mov     x0, x14
+       add     x19, x0, #PAGE_SIZE
+       sub     x1, x17, #1
+       bic     x0, x0, x1
+1:     dc      ivac, x0
+       add     x0, x0, x17
+       cmp     x0, x19
+       b.lo    1b
+       dsb     sy
+
 1:     ldp     x22, x23, [x21]
        ldp     x24, x25, [x21, #16]
        ldp     x26, x27, [x21, #32]
@@ -91,11 +102,6 @@ relocate_new_kernel:
 .Ltest_destination:
        tbz     x18, IND_DESTINATION_BIT, .Lnext

-       /* flush segment */
-
-       bl      .Lflush
-       mov     x16, x13
-
        /* dest = addr */

        mov     x14, x13
@@ -110,12 +116,7 @@ relocate_new_kernel:
        tbz     x18, IND_DONE_BIT, .Lloop

 .Ldone:
-       /* flush last segment */
-
-       bl      .Lflush

-       dsb     sy
-       isb
        ic      ialluis
        dsb     sy
        isb
@@ -129,19 +130,6 @@ relocate_new_kernel:
        mov     x3, xzr
        br      x4

-/* flush - x17 = line size, x16 = start addr, x14 = end addr. */
-
-.Lflush:
-       cbz     x16, 2f
-       mov     x0, x16
-       sub     x1, x17, #1
-       bic     x0, x0, x1
-1:     dc      civac, x0
-       add     x0, x0, x17
-       cmp     x0, x14
-       b.lo    1b
-2:     ret
-
 .align 3       /* To keep the 64-bit values below naturally aligned. */

 /* The machine_kexec routines set these variables. */
################

--Arun




> +.align 3       /* To keep the 64-bit values below naturally aligned. */
> +
> +/* The machine_kexec routines set these variables. */
> +
> +/*
> + * arm64_kexec_kimage_start - Copy of image->start, the entry point of the new
> + * image.
> + */
> +
> +.globl arm64_kexec_kimage_start
> +arm64_kexec_kimage_start:
> +       .quad   0x0
> +
> +/*
> + * arm64_kexec_dtb_addr - Physical address of a device tree.
> + */
> +
> +.globl arm64_kexec_dtb_addr
> +arm64_kexec_dtb_addr:
> +       .quad   0x0
> +
> +/*
> + * arm64_kexec_kimage_head - Copy of image->head, the list of kimage entries.
> + */
> +
> +.globl arm64_kexec_kimage_head
> +arm64_kexec_kimage_head:
> +       .quad   0x0
> +
> +.Lrelocate_new_kernel_end:
> +
> +/*
> + * relocate_new_kernel_size - Number of bytes to copy to the control_code_page.
> + */
> +
> +.globl relocate_new_kernel_size
> +relocate_new_kernel_size:
> +       .quad .Lrelocate_new_kernel_end - relocate_new_kernel
> +
> +.org   KEXEC_CONTROL_PAGE_SIZE
> diff --git a/include/uapi/linux/kexec.h b/include/uapi/linux/kexec.h
> index 6925f5b..04626b9 100644
> --- a/include/uapi/linux/kexec.h
> +++ b/include/uapi/linux/kexec.h
> @@ -39,6 +39,7 @@
>  #define KEXEC_ARCH_SH      (42 << 16)
>  #define KEXEC_ARCH_MIPS_LE (10 << 16)
>  #define KEXEC_ARCH_MIPS    ( 8 << 16)
> +#define KEXEC_ARCH_ARM64   (183 << 16)
>
>  /* The artificial cap on the number of segments passed to kexec_load. */
>  #define KEXEC_SEGMENT_MAX 16
> --
> 1.9.1
>



More information about the linux-arm-kernel mailing list