Thread (72 messages) 72 messages, 9 authors, 2014-11-17
STALE4228d

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

From: Arun Chandran <hidden>
Date: 2014-11-07 11:01:51
Also in: kexec

Hi Geoff,
quoted hunk ↗ jump to hunk
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



quoted hunk ↗ jump to hunk
+.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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help