arm64 kexec-tools patches
Subsystems (2)
v3 cover arm64 kexec-tools patches
This series adds the core support for kexec re-boot on ARM64.
Linux kernel support for ARM64 kexec reboot has been merged in v4.8-rc1 with the expectation that it will be included in the v4.8 stable kernel release.
For ARM64 kdump support see Takahiro's patches [1].
[1] http://lists.infradead.org/pipermail/kexec/2016-July/016642.html
Changes for v3 (Aug 9, 2016, 1m):
o Rebase to v2.0.13.
o Add bits 1-3 support to arm64 image-header.h.
o Fix OPT_ARCH_MAX value.
o Use fdt_pack() in dtb_set_property().
o Remove patch ("kexec: (bugfix) calc correct end address of memory ranges in device tree").
Changes for v2 (July 26, 2016, 0m):
o Inline some small routines.
o Reformat some dbgprintf messages.
o Remove debug_brk from entry.S
o Change arm64_image_header.flags to uint64_t.
o Look in iomem then dt for mem info.
o Remove check_cpu_nodes.
o Remove purgatory printing.
First submission v1 (July 20, 2016).
-Geoff
The following changes since commit 67488beb0a6ee8ad2c0b05f721a9e00041fab93a:
kexec-tools 2.0.13 (2016-08-08 12:26:44 +0200)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/geoff/kexec-tools.git for-merge-arm64-v3
for you to fetch changes up to 726816b353ad67c222d135117145dd03663bb863:
arm64: Add support for binary image files (2016-08-08 14:54:18 -0700)
----------------------------------------------------------------
Geoff Levand (2):
kexec: Add common device tree routines
arm64: Add arm64 kexec support
Pratyush Anand (1):
arm64: Add support for binary image files
configure.ac | 3 + kexec/Makefile | 5 + kexec/arch/arm64/Makefile | 40 ++ kexec/arch/arm64/crashdump-arm64.c | 21 + kexec/arch/arm64/crashdump-arm64.h | 12 + kexec/arch/arm64/image-header.h | 126 ++++++ kexec/arch/arm64/include/arch/options.h | 39 ++ kexec/arch/arm64/kexec-arm64.c | 704 ++++++++++++++++++++++++++++++++ kexec/arch/arm64/kexec-arm64.h | 70 ++++ kexec/arch/arm64/kexec-elf-arm64.c | 130 ++++++ kexec/arch/arm64/kexec-image-arm64.c | 63 +++ kexec/dt-ops.c | 145 +++++++ kexec/dt-ops.h | 13 + kexec/kexec-syscall.h | 8 +- purgatory/Makefile | 1 + purgatory/arch/arm64/Makefile | 18 + purgatory/arch/arm64/entry.S | 51 +++ purgatory/arch/arm64/purgatory-arm64.c | 19 + 18 files changed, 1466 insertions(+), 2 deletions(-) create mode 100644 kexec/arch/arm64/Makefile create mode 100644 kexec/arch/arm64/crashdump-arm64.c create mode 100644 kexec/arch/arm64/crashdump-arm64.h create mode 100644 kexec/arch/arm64/image-header.h create mode 100644 kexec/arch/arm64/include/arch/options.h create mode 100644 kexec/arch/arm64/kexec-arm64.c create mode 100644 kexec/arch/arm64/kexec-arm64.h create mode 100644 kexec/arch/arm64/kexec-elf-arm64.c create mode 100644 kexec/arch/arm64/kexec-image-arm64.c create mode 100644 kexec/dt-ops.c create mode 100644 kexec/dt-ops.h create mode 100644 purgatory/arch/arm64/Makefile create mode 100644 purgatory/arch/arm64/entry.S create mode 100644 purgatory/arch/arm64/purgatory-arm64.c
Signature · 7 lines
2.5.0 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec
PATCH v3 1/3 kexec: Add common device tree routines
Common device tree routines that can be shared between all arches that have device tree support.
--- kexec/Makefile | 4 ++ kexec/dt-ops.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kexec/dt-ops.h | 13 ++++++ 3 files changed, 162 insertions(+) create mode 100644 kexec/dt-ops.c create mode 100644 kexec/dt-ops.h
kexec/Makefile +4 -0
@@ -73,6 +73,10 @@ dist += kexec/mem_regions.c kexec/mem_regions.h $(ARCH)_MEM_REGIONS = KEXEC_SRCS += $($(ARCH)_MEM_REGIONS) +dist += kexec/dt-ops.c kexec/dt-ops.h +$(ARCH)_DT_OPS = +KEXEC_SRCS += $($(ARCH)_DT_OPS) + include $(srcdir)/kexec/arch/alpha/Makefile include $(srcdir)/kexec/arch/arm/Makefile include $(srcdir)/kexec/arch/i386/Makefile
kexec/dt-ops.c new file +145 -0
145 lines not on this page · raw message
kexec/dt-ops.h new file +13 -0
@@ -0,0 +1,13 @@ +#if !defined(KEXEC_DT_OPS_H ) +#define KEXEC_DT_OPS_H + +#include <sys/types.h> + +int dtb_set_initrd (char **dtb,off_t *dtb_size,off_t start,off_t end); +int dtb_set_bootargs (char **dtb,off_t *dtb_size,const char *command_line); +int dtb_set_property (char **dtb,off_t *dtb_size,const char *node, +const char *prop,const void *value,int value_len); + +int dtb_delete_property (char *dtb,const char *node,const char *prop); + +#endif
Signature · 8 lines
2.5.0 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec
PATCH v3 2/3 arm64: Add arm64 kexec support
In reply to Geoff LevandAdd kexec reboot support for ARM64 platforms.
--- configure.ac | 3 + kexec/Makefile | 1 + kexec/arch/arm64/Makefile | 40 ++ kexec/arch/arm64/crashdump-arm64.c | 21 + kexec/arch/arm64/crashdump-arm64.h | 12 + kexec/arch/arm64/image-header.h | 126 ++++++ kexec/arch/arm64/include/arch/options.h | 39 ++ kexec/arch/arm64/kexec-arm64.c | 704 ++++++++++++++++++++++++++++++++ kexec/arch/arm64/kexec-arm64.h | 70 ++++ kexec/arch/arm64/kexec-elf-arm64.c | 130 ++++++ kexec/arch/arm64/kexec-image-arm64.c | 44 ++ kexec/kexec-syscall.h | 8 +- purgatory/Makefile | 1 + purgatory/arch/arm64/Makefile | 18 + purgatory/arch/arm64/entry.S | 51 +++ purgatory/arch/arm64/purgatory-arm64.c | 19 + 16 files changed, 1285 insertions(+), 2 deletions(-) create mode 100644 kexec/arch/arm64/Makefile create mode 100644 kexec/arch/arm64/crashdump-arm64.c create mode 100644 kexec/arch/arm64/crashdump-arm64.h create mode 100644 kexec/arch/arm64/image-header.h create mode 100644 kexec/arch/arm64/include/arch/options.h create mode 100644 kexec/arch/arm64/kexec-arm64.c create mode 100644 kexec/arch/arm64/kexec-arm64.h create mode 100644 kexec/arch/arm64/kexec-elf-arm64.c create mode 100644 kexec/arch/arm64/kexec-image-arm64.c create mode 100644 purgatory/arch/arm64/Makefile create mode 100644 purgatory/arch/arm64/entry.S create mode 100644 purgatory/arch/arm64/purgatory-arm64.c
configure.ac +3 -0
@@ -34,6 +34,9 @@ case $target_cpu in ARCH="ppc64" SUBARCH="LE" ;; + aarch64* ) + ARCH="arm64" + ;; arm* ) ARCH="arm" ;;
kexec/Makefile +1 -0
@@ -79,6 +79,7 @@ KEXEC_SRCS += $($(ARCH)_DT_OPS) include $(srcdir)/kexec/arch/alpha/Makefile include $(srcdir)/kexec/arch/arm/Makefile +include $(srcdir)/kexec/arch/arm64/Makefile include $(srcdir)/kexec/arch/i386/Makefile include $(srcdir)/kexec/arch/ia64/Makefile include $(srcdir)/kexec/arch/m68k/Makefile
kexec/arch/arm64/Makefile new file +40 -0
@@ -0,0 +1,40 @@ + +arm64_FS2DT += kexec/fs2dt.c +arm64_FS2DT_INCLUDE += -include $(srcdir)/kexec/arch/arm64/kexec-arm64.h \ + -include $(srcdir)/kexec/arch/arm64/crashdump-arm64.h + +arm64_DT_OPS += kexec/dt-ops.c + +arm64_CPPFLAGS += -I $(srcdir)/kexec/ + +arm64_KEXEC_SRCS += \ + kexec/arch/arm64/kexec-arm64.c \ + kexec/arch/arm64/kexec-image-arm64.c \ + kexec/arch/arm64/kexec-elf-arm64.c \ + kexec/arch/arm64/crashdump-arm64.c + +arm64_ARCH_REUSE_INITRD = +arm64_ADD_SEGMENT = +arm64_VIRT_TO_PHYS = +arm64_PHYS_TO_VIRT = + +dist += $(arm64_KEXEC_SRCS) \ + kexec/arch/arm64/Makefile \ + kexec/arch/arm64/kexec-arm64.h \ + kexec/arch/arm64/crashdump-arm64.h + +ifdef HAVE_LIBFDT + +LIBS += -lfdt + +else + +include $(srcdir)/kexec/libfdt/Makefile.libfdt + +libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%) + +arm64_CPPFLAGS += -I$(srcdir)/kexec/libfdt + +arm64_KEXEC_SRCS += $(libfdt_SRCS) + +endif
kexec/arch/arm64/crashdump-arm64.c new file +21 -0
@@ -0,0 +1,21 @@ +/* +* ARM64 crashdump. +*/ + +#define _GNU_SOURCE + +#include <errno.h> +#include <linux/elf.h> + +#include "kexec.h" +#include "crashdump.h" +#include "crashdump-arm64.h" +#include "kexec-arm64.h" +#include "kexec-elf.h" + +struct memory_ranges usablemem_rgns = {}; + +int is_crashkernel_mem_reserved (void ) +{ +return 0 ; +}
kexec/arch/arm64/crashdump-arm64.h new file +12 -0
@@ -0,0 +1,12 @@ +/* +* ARM64 crashdump. +*/ + +#if !defined(CRASHDUMP_ARM64_H ) +#define CRASHDUMP_ARM64_H + +#include "kexec.h" + +extern struct memory_ranges usablemem_rgns; + +#endif
kexec/arch/arm64/image-header.h new file +126 -0
126 lines not on this page · raw message
kexec/arch/arm64/include/arch/options.h new file +39 -0
@@ -0,0 +1,39 @@ +#if !defined(KEXEC_ARCH_ARM64_OPTIONS_H ) +#define KEXEC_ARCH_ARM64_OPTIONS_H + +#define OPT_APPEND ((OPT_MAX)+0) +#define OPT_DTB ((OPT_MAX)+1) +#define OPT_INITRD ((OPT_MAX)+2) +#define OPT_REUSE_CMDLINE ((OPT_MAX)+3) +#define OPT_ARCH_MAX ((OPT_MAX)+4) + +#define KEXEC_ARCH_OPTIONS \ + KEXEC_OPTIONS \ + { "append", 1, NULL, OPT_APPEND }, \ + { "command-line", 1, NULL, OPT_APPEND }, \ + { "dtb", 1, NULL, OPT_DTB }, \ + { "initrd", 1, NULL, OPT_INITRD }, \ + { "ramdisk", 1, NULL, OPT_INITRD }, \ + { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \ + +#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR/* Only accept long arch options. */ +#define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS +#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR + +static const char arm64_opts_usage[] __attribute__ ((unused)) = +" --append=STRING Set the kernel command line to STRING.\n" +" --command-line=STRING Set the kernel command line to STRING.\n" +" --dtb=FILE Use FILE as the device tree blob.\n" +" --initrd=FILE Use FILE as the kernel initial ramdisk.\n" +" --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n" +" --reuse-cmdline Use kernel command line from running system.\n" ; + +struct arm64_opts { +const char *command_line; +const char *dtb; +const char *initrd; +}; + +extern struct arm64_opts arm64_opts; + +#endif
kexec/arch/arm64/kexec-arm64.c new file +704 -0
704 lines not on this page · raw message
kexec/arch/arm64/kexec-arm64.h new file +70 -0
70 lines not on this page · raw message
kexec/arch/arm64/kexec-elf-arm64.c new file +130 -0
130 lines not on this page · raw message
kexec/arch/arm64/kexec-image-arm64.c new file +44 -0
44 lines not on this page · raw message
kexec/kexec-syscall.h +6 -2
@@ -39,8 +39,8 @@#ifdef __s390__#define __NR_kexec_load 277#endif -#ifdef __arm__ -#define __NR_kexec_load __NR_SYSCALL_BASE + 347 +#if defined(__arm__) || defined(__arm64__) +#define __NR_kexec_load __NR_SYSCALL_BASE + 347#endif #if defined(__mips__)#define __NR_kexec_load 4311
@@ -108,6 +108,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,#define KEXEC_ARCH_PPC64 (21 << 16)#define KEXEC_ARCH_IA_64 (50 << 16)#define KEXEC_ARCH_ARM (40 << 16) +#define KEXEC_ARCH_ARM64 (183 << 16)#define KEXEC_ARCH_S390 (22 << 16)#define KEXEC_ARCH_SH (42 << 16)#define KEXEC_ARCH_MIPS_LE (10 << 16)
@@ -153,5 +154,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,#ifdef __m68k__#define KEXEC_ARCH_NATIVE KEXEC_ARCH_68K#endif +#if defined(__arm64__) +#define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM64 +#endif #endif /* KEXEC_SYSCALL_H */
purgatory/Makefile +1 -0
@@ -19,6 +19,7 @@ dist += purgatory/Makefile $(PURGATORY_SRCS) \ include $(srcdir)/purgatory/arch/alpha/Makefile include $(srcdir)/purgatory/arch/arm/Makefile +include $(srcdir)/purgatory/arch/arm64/Makefile include $(srcdir)/purgatory/arch/i386/Makefile include $(srcdir)/purgatory/arch/ia64/Makefile include $(srcdir)/purgatory/arch/mips/Makefile
purgatory/arch/arm64/Makefile new file +18 -0
@@ -0,0 +1,18 @@ + +arm64_PURGATORY_EXTRA_CFLAGS = \ + -mcmodel=large \ + -fno-stack-protector \ + -fno-asynchronous-unwind-tables \ + -Wundef \ + -Werror-implicit-function-declaration \ + -Wdeclaration-after-statement \ + -Werror=implicit-int \ + -Werror=strict-prototypes + +arm64_PURGATORY_SRCS += \ + purgatory/arch/arm64/entry.S \ + purgatory/arch/arm64/purgatory-arm64.c + +dist += \ + $(arm64_PURGATORY_SRCS) \ + purgatory/arch/arm64/Makefile
purgatory/arch/arm64/entry.S new file +51 -0
52 lines not on this page · raw message
purgatory/arch/arm64/purgatory-arm64.c new file +19 -0
@@ -0,0 +1,19 @@ +/* +* ARM64 purgatory. +*/ + +#include <stdint.h> +#include <purgatory.h> + +void putchar (int ch) +{ +/* Nothing for now */ +} + +void post_verification_setup_arch (void ) +{ +} + +void setup_arch (void ) +{ +}
Signature · 8 lines
2.5.0 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec
Re: [PATCH v3 2/3] arm64: Add arm64 kexec support
Quoted 189 lines · Geoff Levand
Add kexec reboot support for ARM64 platforms.
Signed-off-by Geoff Levand <[email protected]>--- configure.ac | 3 + kexec/Makefile | 1 + kexec/arch/arm64/Makefile | 40 ++ kexec/arch/arm64/crashdump-arm64.c | 21 + kexec/arch/arm64/crashdump-arm64.h | 12 + kexec/arch/arm64/image-header.h | 126 ++++++ kexec/arch/arm64/include/arch/options.h | 39 ++ kexec/arch/arm64/kexec-arm64.c | 704 ++++++++++++++++++++++++++++++++ kexec/arch/arm64/kexec-arm64.h | 70 ++++ kexec/arch/arm64/kexec-elf-arm64.c | 130 ++++++ kexec/arch/arm64/kexec-image-arm64.c | 44 ++ kexec/kexec-syscall.h | 8 +- purgatory/Makefile | 1 + purgatory/arch/arm64/Makefile | 18 + purgatory/arch/arm64/entry.S | 51 +++ purgatory/arch/arm64/purgatory-arm64.c | 19 + 16 files changed, 1285 insertions(+), 2 deletions(-) create mode 100644 kexec/arch/arm64/Makefile create mode 100644 kexec/arch/arm64/crashdump-arm64.c create mode 100644 kexec/arch/arm64/crashdump-arm64.h create mode 100644 kexec/arch/arm64/image-header.h create mode 100644 kexec/arch/arm64/include/arch/options.h create mode 100644 kexec/arch/arm64/kexec-arm64.c create mode 100644 kexec/arch/arm64/kexec-arm64.h create mode 100644 kexec/arch/arm64/kexec-elf-arm64.c create mode 100644 kexec/arch/arm64/kexec-image-arm64.c create mode 100644 purgatory/arch/arm64/Makefile create mode 100644 purgatory/arch/arm64/entry.S create mode 100644 purgatory/arch/arm64/purgatory-arm64.cconfigure.ac +3
-0@@ -34,6 +34,9 @@ case $target_cpu in ARCH="ppc64" SUBARCH="LE" ;; + aarch64* ) + ARCH="arm64" + ;; arm* ) ARCH="arm" ;;kexec/Makefile +1
-0@@ -79,6 +79,7 @@ KEXEC_SRCS += $($(ARCH)_DT_OPS) include $(srcdir)/kexec/arch/alpha/Makefile include $(srcdir)/kexec/arch/arm/Makefile +include $(srcdir)/kexec/arch/arm64/Makefile include $(srcdir)/kexec/arch/i386/Makefile include $(srcdir)/kexec/arch/ia64/Makefile include $(srcdir)/kexec/arch/m68k/Makefilekexec/arch/arm64/Makefile new file +40
-0@@ -0,0 +1,40 @@ + +arm64_FS2DT += kexec/fs2dt.c +arm64_FS2DT_INCLUDE += -include $(srcdir)/kexec/arch/arm64/kexec-arm64.h \ + -include $(srcdir)/kexec/arch/arm64/crashdump-arm64.h + +arm64_DT_OPS += kexec/dt-ops.c + +arm64_CPPFLAGS += -I $(srcdir)/kexec/ + +arm64_KEXEC_SRCS += \ + kexec/arch/arm64/kexec-arm64.c \ + kexec/arch/arm64/kexec-image-arm64.c \ + kexec/arch/arm64/kexec-elf-arm64.c \ + kexec/arch/arm64/crashdump-arm64.c + +arm64_ARCH_REUSE_INITRD = +arm64_ADD_SEGMENT = +arm64_VIRT_TO_PHYS = +arm64_PHYS_TO_VIRT = + +dist += $(arm64_KEXEC_SRCS) \ + kexec/arch/arm64/Makefile \ + kexec/arch/arm64/kexec-arm64.h \ + kexec/arch/arm64/crashdump-arm64.h + +ifdef HAVE_LIBFDT + +LIBS += -lfdt + +else + +include $(srcdir)/kexec/libfdt/Makefile.libfdt + +libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%) + +arm64_CPPFLAGS += -I$(srcdir)/kexec/libfdt + +arm64_KEXEC_SRCS += $(libfdt_SRCS) + +endifkexec/arch/arm64/crashdump-arm64.c new file +21
-0@@ -0,0 +1,21 @@ +/* +* ARM64 crashdump. +*/ + +#define _GNU_SOURCE + +#include <errno.h> +#include <linux/elf.h> + +#include "kexec.h" +#include "crashdump.h" +#include "crashdump-arm64.h" +#include "kexec-arm64.h" +#include "kexec-elf.h" + +struct memory_ranges usablemem_rgns = {}; + +int is_crashkernel_mem_reserved (void ) +{ +return 0 ; +}kexec/arch/arm64/crashdump-arm64.h new file +12
-0@@ -0,0 +1,12 @@ +/* +* ARM64 crashdump. +*/ + +#if !defined(CRASHDUMP_ARM64_H ) +#define CRASHDUMP_ARM64_H + +#include "kexec.h" + +extern struct memory_ranges usablemem_rgns; + +#endif kexec/arch/arm64/image-header.h new file +32
-0@@ -0,0 +1,126 @@ +/* +* ARM64 binary image header. +*/ + +#if !defined(__ARM64_IMAGE_HEADER_H) +#define __ARM64_IMAGE_HEADER_H + +#include <endian.h> +#include <stdint.h> + +/** + * struct arm64_image_header - arm64 kernel image header. + * + * @pe_sig: Optional PE format 'MZ' signature. + * @branch_code: Reserved for instructions to branch to stext. + * @text_offset: The image load offset in LSB byte order. + * @image_size: An estimated size of the memory image size in LSB byte order. + * @flags: Bit flags in LSB byte order: + * Bit 0: Image byte order: 1=MSB. + * Bit 1-2: Kernel page size: 1=4K, 2=16K, 3=64K. + * Bit 3: Image placement: 0=low. + * @reserved_1: Reserved. + * @magic: Magic number, "ARM\x64". + * @pe_header: Optional offset to a PE format header. + **/ + +struct arm64_image_header { + uint8_t pe_sig[2]; + uint16_t branch_code[3]; + uint64_t text_offset; + uint64_t image_size; + uint64_t flags;
kexec/arch/arm64/image-header.h line 42
Quoted 10 lines
kexec/arch/arm64/image-header.h new file +10
-0+uint64_t reserved_1[3 ]; +uint8_t magic[4 ]; +uint32_t pe_header; +}; + +static const uint8_t arm64_image_magic[4 ] = {'A' ,'R' ,'M' ,0x64U }; +static const uint8_t arm64_image_pe_sig[2 ] = {'M' ,'Z' }; +static const uint64_t arm64_image_flag_be = (1UL <<0 ); +static const uint64_t arm64_image_flag_page_size = (3UL <<1 ); +static const uint64_t arm64_image_flag_placement = (1UL <<3 );
Why not define like:
#define ARM64_FLAG_PAGE_SIZE_4K 1
#define ARM64_FLAG_PAGE_SIZE_16K 2
#define ARM64_FLAG_PAGE_SIZE_64K 3
if you have arm64_header_page_size()?
Quoted 18 lines
kexec/arch/arm64/image-header.h new file +18
-0+ +/** +* arm64_header_check_magic - Helper to check the arm64 image header. +* +* Returns non-zero if header is OK. +*/ + +static inline int arm64_header_check_magic (const struct arm64_image_header *h) +{ +if (!h) +return 0 ; + +return (h->magic[0 ] == arm64_image_magic[0 ] + && h->magic[1 ] == arm64_image_magic[1 ] + && h->magic[2 ] == arm64_image_magic[2 ] + && h->magic[3 ] == arm64_image_magic[3 ]); +} +
kexec/arch/arm64/image-header.h line 70
Quoted 10 lines
kexec/arch/arm64/image-header.h new file +10
-0+/** +* arm64_header_check_pe_sig - Helper to check the arm64 image header. +* +* Returns non-zero if 'MZ' signature is found. +*/ + +static inline int arm64_header_check_pe_sig (const struct arm64_image_header *h) +{ +if (!h) +return 0 ;
Why not add assert() here like get_phys_offset()?
Quoted 5 lines
kexec/arch/arm64/image-header.h new file +5
-0+ +return (h->pe_sig[0 ] == arm64_image_pe_sig[0 ] + && h->pe_sig[1 ] == arm64_image_pe_sig[1 ]); +} +
kexec/arch/arm64/image-header.h line 85
Quoted 10 lines
kexec/arch/arm64/image-header.h new file +10
-0+/** +* arm64_header_check_msb - Helper to check the arm64 image header. +* +* Returns non-zero if the image was built as big endian. +*/ + +static inline int arm64_header_check_msb (const struct arm64_image_header *h) +{ +if (!h) +return 0 ;
ditto
kexec/arch/arm64/image-header.h line 97
Quoted 12 lines
kexec/arch/arm64/image-header.h new file +12
-0+ +return (le64toh (h->flags) & arm64_image_flag_be) >>0 ; +} + +/** +* arm64_header_page_size +*/ + +static inline int arm64_header_page_size (const struct arm64_image_header *h) +{ +if (!h) +return 0 ;
ditto
kexec/arch/arm64/image-header.h line 109
Quoted 12 lines
kexec/arch/arm64/image-header.h new file +12
-0+ +return (le64toh (h->flags) & arm64_image_flag_page_size) >>1 ; +} + +/** +* arm64_header_placement +*/ + +static inline int arm64_header_placement (const struct arm64_image_header *h) +{ +if (!h) +return 0 ;
ditto
kexec/arch/arm64/image-header.h line 116
Quoted 7 lines
kexec/arch/arm64/image-header.h new file +7
-0+ +return (le64toh (h->flags) & arm64_image_flag_placement) >>3 ; +} + +static inline uint64_t arm64_header_text_offset ( +const struct arm64_image_header *h) +{
Why not check for !h?
kexec/arch/arm64/image-header.h line 122
Quoted 6 lines
kexec/arch/arm64/image-header.h new file +6
-0+return le64toh (h->text_offset); +} + +static inline uint64_t arm64_header_image_size ( +const struct arm64_image_header *h) +{
ditto
Quoted 632 lines
kexec/arch/arm64/image-header.h new file +4
-0+ return le64toh(h->image_size); +} + +#endif kexec/arch/arm64/include/arch/options.h new file +39
-0@@ -0,0 +1,39 @@ +#if !defined(KEXEC_ARCH_ARM64_OPTIONS_H ) +#define KEXEC_ARCH_ARM64_OPTIONS_H + +#define OPT_APPEND ((OPT_MAX)+0) +#define OPT_DTB ((OPT_MAX)+1) +#define OPT_INITRD ((OPT_MAX)+2) +#define OPT_REUSE_CMDLINE ((OPT_MAX)+3) +#define OPT_ARCH_MAX ((OPT_MAX)+4) + +#define KEXEC_ARCH_OPTIONS \ + KEXEC_OPTIONS \ + { "append", 1, NULL, OPT_APPEND }, \ + { "command-line", 1, NULL, OPT_APPEND }, \ + { "dtb", 1, NULL, OPT_DTB }, \ + { "initrd", 1, NULL, OPT_INITRD }, \ + { "ramdisk", 1, NULL, OPT_INITRD }, \ + { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \ + +#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR/* Only accept long arch options. */ +#define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS +#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR + +static const char arm64_opts_usage[] __attribute__ ((unused)) = +" --append=STRING Set the kernel command line to STRING.\n" +" --command-line=STRING Set the kernel command line to STRING.\n" +" --dtb=FILE Use FILE as the device tree blob.\n" +" --initrd=FILE Use FILE as the kernel initial ramdisk.\n" +" --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n" +" --reuse-cmdline Use kernel command line from running system.\n" ; + +struct arm64_opts { +const char *command_line; +const char *dtb; +const char *initrd; +}; + +extern struct arm64_opts arm64_opts; + +#endif kexec/arch/arm64/kexec-arm64.c new file +577
-0@@ -0,0 +1,704 @@ +/* +* ARM64 kexec. +*/ + +#define _GNU_SOURCE + +#include <assert.h> +#include <errno.h> +#include <getopt.h> +#include <inttypes.h> +#include <libfdt.h> +#include <limits.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <linux/elf.h> + +#include "kexec.h" +#include "kexec-arm64.h" +#include "crashdump.h" +#include "crashdump-arm64.h" +#include "dt-ops.h" +#include "fs2dt.h" +#include "kexec-syscall.h" +#include "arch/options.h" + +/* Global varables the core kexec routines expect. */ + +unsigned char reuse_initrd; + +off_t initrd_base; +off_t initrd_size; + +const struct arch_map_entry arches[] = { + {"aarch64" ,KEXEC_ARCH_ARM64 }, + {"aarch64_be" ,KEXEC_ARCH_ARM64 }, + {NULL ,0 }, +}; + +struct file_type file_type[] = { + {"vmlinux" , elf_arm64_probe, elf_arm64_load, elf_arm64_usage}, + {"Image" , image_arm64_probe, image_arm64_load, image_arm64_usage}, +}; + +int file_types =sizeof (file_type) /sizeof (file_type[0 ]); + +/* arm64 global varables. */ + +struct arm64_opts arm64_opts; +struct arm64_mem arm64_mem = { + .phys_offset = arm64_mem_ngv, + .page_offset = arm64_mem_ngv, +}; + +uint64_t get_phys_offset (void ) +{ +assert (arm64_mem.phys_offset != arm64_mem_ngv); +return arm64_mem.phys_offset; +} + +uint64_t get_page_offset (void ) +{ +assert (arm64_mem.page_offset != arm64_mem_ngv); +return arm64_mem.page_offset; +} + +/** +* arm64_process_image_header - Process the arm64 image header. +* +* Make a guess that KERNEL_IMAGE_SIZE will be enough for older kernels. +*/ + +int arm64_process_image_header (const struct arm64_image_header *h) +{ +#if !defined(KERNEL_IMAGE_SIZE ) +# define KERNEL_IMAGE_SIZE MiB(16) +#endif + +if (!arm64_header_check_magic (h)) +return -EFAILED ; + +if (h->image_size) { + arm64_mem.text_offset =arm64_header_text_offset (h); + arm64_mem.image_size =arm64_header_image_size (h); + }else { +/* For 3.16 and older kernels. */ + arm64_mem.text_offset =0x80000 ; + arm64_mem.image_size =KERNEL_IMAGE_SIZE ; +fprintf (stderr, +"kexec: %s: Warning: Kernel image size set to %lu MiB.\n" +" Please verify compatability with lodaed kernel.\n" , + __func__,KERNEL_IMAGE_SIZE /1024UL /1024UL ); + } + +return 0 ; +} + +void arch_usage (void ) +{ +printf (arm64_opts_usage); +} + +int arch_process_options (int argc,char **argv) +{ +static const char short_options[] =KEXEC_OPT_STR "" ; +static const struct option options[] = { + KEXEC_ARCH_OPTIONS + {0 } + }; +int opt; +char *cmdline =NULL ; +const char *append =NULL ; + +for (opt =0 ; opt !=-1 ; ) { + opt =getopt_long (argc, argv, short_options, options,0 ); + +switch (opt) { +case OPT_APPEND : + append = optarg; +break ; +case OPT_REUSE_CMDLINE : + cmdline =get_command_line (); +break ; +case OPT_DTB : + arm64_opts.dtb = optarg; +break ; +case OPT_INITRD : + arm64_opts.initrd = optarg; +break ; +case OPT_PANIC : +die ("load-panic (-p) not supported" ); +break ; +default : +break ;/* Ignore core and unknown options. */ + } + } + + arm64_opts.command_line =concat_cmdline (cmdline, append); + +dbgprintf ("%s:%d: command_line: %s\n" , __func__, __LINE__, + arm64_opts.command_line); +dbgprintf ("%s:%d: initrd: %s\n" , __func__, __LINE__, + arm64_opts.initrd); +dbgprintf ("%s:%d: dtb: %s\n" , __func__, __LINE__, arm64_opts.dtb); + +return 0 ; +} + +/** +* struct dtb - Info about a binary device tree. +* +* @buf: Device tree data. +* @size: Device tree data size. +* @name: Shorthand name of this dtb for messages. +* @path: Filesystem path. +*/ + +struct dtb { +char *buf; +off_t size; +const char *name; +const char *path; +}; + +/** +* dump_reservemap - Dump the dtb's reservemap. +*/ + +static void dump_reservemap (const struct dtb *dtb) +{ +int i; + +for (i =0 ; ; i++) { +uint64_t address; +uint64_t size; + +fdt_get_mem_rsv (dtb->buf, i, &address, &size); + +if (!size) +break ; + +dbgprintf ("%s: %s {%" PRIx64", %" PRIx64"}\n" , __func__, + dtb->name, address, size); + } +} + +/** +* set_bootargs - Set the dtb's bootargs. +*/ + +static int set_bootargs (struct dtb *dtb,const char *command_line) +{ +int result; + +if (!command_line || !command_line[0 ]) +return 0 ; + + result =dtb_set_bootargs (&dtb->buf, &dtb->size, command_line); + +if (result) { +fprintf (stderr, +"kexec: Set device tree bootargs failed.\n" ); +return -EFAILED ; + } + +return 0 ; +} + +/** +* read_proc_dtb - Read /proc/device-tree. +*/ + +static int read_proc_dtb (struct dtb *dtb) +{ +int result; +struct stat s; +static const char path[] ="/proc/device-tree" ; + + result =stat (path, &s); + +if (result) { +dbgprintf ("%s: %s\n" , __func__,strerror (errno)); +return -EFAILED ; + } + + dtb->path = path; +create_flatten_tree ((char **)&dtb->buf, &dtb->size,NULL ); + +return 0 ; +} + +/** +* read_sys_dtb - Read /sys/firmware/fdt. +*/ + +static int read_sys_dtb (struct dtb *dtb) +{ +int result; +struct stat s; +static const char path[] ="/sys/firmware/fdt" ; + + result =stat (path, &s); + +if (result) { +dbgprintf ("%s: %s\n" , __func__,strerror (errno)); +return -EFAILED ; + } + + dtb->path = path; + dtb->buf =slurp_file (path, &dtb->size); + +return 0 ; +} + +/** +* read_1st_dtb - Read the 1st stage kernel's dtb. +*/ + +static int read_1st_dtb (struct dtb *dtb) +{ +int result; + + result =read_sys_dtb (dtb); + +if (!result) + goto on_success; + + result =read_proc_dtb (dtb); + +if (!result) + goto on_success; + +dbgprintf ("%s: not found\n" , __func__); +return -EFAILED ; + +on_success: +dbgprintf ("%s: found %s\n" , __func__, dtb->path); +return 0 ; +} + +/** +* setup_2nd_dtb - Setup the 2nd stage kernel's dtb. +*/ + +static int setup_2nd_dtb (struct dtb *dtb,char *command_line) +{ +int result; + + result =fdt_check_header (dtb->buf); + +if (result) { +fprintf (stderr,"kexec: Invalid 2nd device tree.\n" ); +return -EFAILED ; + } + + result =set_bootargs (dtb, command_line); + +dump_reservemap (dtb); + +return result; +} + +/** +* arm64_load_other_segments - Prepare the dtb, initrd and purgatory segments. +*/ + +int arm64_load_other_segments (struct kexec_info *info, +uint64_t kernel_entry) +{ +int result; +uint64_t dtb_base; +uint64_t image_base; +unsigned long hole_min; +unsigned long hole_max; +char *initrd_buf =NULL ; +struct dtb dtb; +char command_line[COMMAND_LINE_SIZE ] ="" ; + +if (arm64_opts.command_line) { +strncpy (command_line, arm64_opts.command_line, +sizeof (command_line)); + command_line[sizeof (command_line) -1 ] =0 ; + } + +if (arm64_opts.dtb) { + dtb.name ="dtb_2" ; + dtb.buf =slurp_file (arm64_opts.dtb, &dtb.size); + }else { + dtb.name ="dtb_1" ; + result =read_1st_dtb (&dtb); + +if (result) { +fprintf (stderr, +"kexec: Error: No device tree available.\n" ); +return -EFAILED ; + } + } + + result =setup_2nd_dtb (&dtb, command_line); + +if (result) +return -EFAILED ; + +/* Put the other segments after the image. */ + + image_base = arm64_mem.phys_offset + arm64_mem.text_offset; + hole_min = image_base + arm64_mem.image_size; + hole_max =ULONG_MAX ; + +if (arm64_opts.initrd) { + initrd_buf =slurp_file (arm64_opts.initrd, &initrd_size); + +if (!initrd_buf) +fprintf (stderr,"kexec: Empty ramdisk file.\n" ); +else { +/* +* Put the initrd after the kernel. As specified in +* booting.txt, align to 1 GiB. +*/ + + initrd_base =add_buffer_phys_virt (info, initrd_buf, + initrd_size, initrd_size,GiB (1 ), + hole_min, hole_max,1 ,0 ); + +/* initrd_base is valid if we got here. */ + +dbgprintf ("initrd: base %lx, size %lxh (%ld)\n" , + initrd_base, initrd_size, initrd_size); + +/* Check size limit as specified in booting.txt. */ + +if (initrd_base - image_base + initrd_size >GiB (32 )) { +fprintf (stderr,"kexec: Error: image + initrd too big.\n" ); +return -EFAILED ; + } + + result =dtb_set_initrd ((char **)&dtb.buf, + &dtb.size, initrd_base, + initrd_base + initrd_size); + +if (result) +return -EFAILED ; + } + } + +/* Check size limit as specified in booting.txt. */ + +if (dtb.size >MiB (2 )) { +fprintf (stderr,"kexec: Error: dtb too big.\n" ); +return -EFAILED ; + } + + dtb_base =add_buffer_phys_virt (info, dtb.buf, dtb.size, dtb.size, +0 , hole_min, hole_max,1 ,0 ); + +/* dtb_base is valid if we got here. */ + +dbgprintf ("dtb: base %lx, size %lxh (%ld)\n" , dtb_base, dtb.size, + dtb.size); + +elf_rel_build_load (info, &info->rhdr, purgatory, purgatory_size, + hole_min, hole_max,1 ,0 ); + + info->entry = (void *)elf_rel_get_addr (&info->rhdr,"purgatory_start" ); + +elf_rel_set_symbol (&info->rhdr,"arm64_kernel_entry" , &kernel_entry, +sizeof (kernel_entry)); + +elf_rel_set_symbol (&info->rhdr,"arm64_dtb_addr" , &dtb_base, +sizeof (dtb_base)); + +return 0 ; +} + +/** +* virt_to_phys - For processing elf file values. +*/ + +unsigned long virt_to_phys (unsigned long v) +{ +unsigned long p; + + p = v -get_page_offset () +get_phys_offset (); + +return p; +} + +/** +* phys_to_virt - For crashdump setup. +*/ + +unsigned long phys_to_virt (struct crash_elf_info *elf_info, +unsigned long long p) +{ +unsigned long v; + + v = p -get_phys_offset () + elf_info->page_offset; + +return v; +} + +/** +* add_segment - Use virt_to_phys when loading elf files. +*/ + +void add_segment (struct kexec_info *info,const void *buf,size_t bufsz, +unsigned long base,size_t memsz) +{ +add_segment_phys_virt (info, buf, bufsz, base, memsz,1 ); +} + +/** +* get_memory_ranges_iomem_cb - Helper for get_memory_ranges_iomem. +*/ + +static int get_memory_ranges_iomem_cb (void *data,int nr,char *str, +unsigned long long base,unsigned long long length) +{ +struct memory_range *r; + +if (nr >=KEXEC_SEGMENT_MAX ) +return -1 ; + + r = (struct memory_range *)data + nr; + r->type =RANGE_RAM ; + r->start = base; + r->end = base + length -1 ; + +set_phys_offset (r->start); + +dbgprintf ("%s: %016llx - %016llx : %s" , __func__, r->start, + r->end, str); + +return 0 ; +} + +/** +* get_memory_ranges_iomem - Try to get the memory ranges from /proc/iomem. +*/ + +static int get_memory_ranges_iomem (struct memory_range *array, +unsigned int *count) +{ + *count =kexec_iomem_for_each_line ("System RAM\n" , + get_memory_ranges_iomem_cb, array); + +if (!*count) { +dbgprintf ("%s: failed: No RAM found.\n" , __func__); +return -EFAILED ; + } + +return 0 ; +} + +/** +* get_memory_ranges_dt - Try to get the memory ranges from the 1st stage dtb. +*/ + +static int get_memory_ranges_dt (struct memory_range *array,unsigned int *count) +{ +struct region {uint64_t base;uint64_t size;}; +struct dtb dtb = {.name ="range_dtb" }; +int offset; +int result; + + *count =0 ; + + result =read_1st_dtb (&dtb); + +if (result) { + goto on_error; + } + + result =fdt_check_header (dtb.buf); + +if (result) { +dbgprintf ("%s:%d: %s: fdt_check_header failed:%s\n" , __func__, + __LINE__, dtb.path,fdt_strerror (result)); + goto on_error; + } + +for (offset =0 ; ; ) { +const struct region *region; +const struct region *end; +int len; + + offset =fdt_subnode_offset (dtb.buf, offset,"memory" ); + +if (offset == -FDT_ERR_NOTFOUND ) +break ; + +if (offset <=0 ) { +dbgprintf ("%s:%d: fdt_subnode_offset failed: %d %s\n" , + __func__, __LINE__, offset, +fdt_strerror (offset)); + goto on_error; + } + +dbgprintf ("%s:%d: node_%d %s\n" , __func__, __LINE__, offset, +fdt_get_name (dtb.buf, offset,NULL )); + + region =fdt_getprop (dtb.buf, offset,"reg" , &len); + +if (region <=0 ) { +dbgprintf ("%s:%d: fdt_getprop failed: %d %s\n" , + __func__, __LINE__, offset, +fdt_strerror (offset)); + goto on_error; + } + +for (end = region + len /sizeof (*region); + region < end && *count <KEXEC_SEGMENT_MAX ; + region++) { +struct memory_range r; + + r.type =RANGE_RAM ; + r.start =fdt64_to_cpu (region->base); + r.end = r.start +fdt64_to_cpu (region->size) -1 ; + +if (!region->size) { +dbgprintf ("%s:%d: SKIP: %016llx - %016llx\n" , + __func__, __LINE__, r.start, r.end); +continue ; + } + +dbgprintf ("%s:%d: RAM: %016llx - %016llx\n" , __func__, + __LINE__, r.start, r.end); + + array[(*count)++] = r; + +set_phys_offset (r.start); + } + } + +if (!*count) { +dbgprintf ("%s:%d: %s: No RAM found.\n" , __func__, __LINE__, + dtb.path); + goto on_error;
kexec/arch/arm64/kexec-arm64.c line 587
Quoted 10 lines
kexec/arch/arm64/kexec-arm64.c new file +10
-0+ } + +dbgprintf ("%s:%d: %s: Success\n" , __func__, __LINE__, dtb.path); + result =0 ; + goto on_exit; + +on_error: +fprintf (stderr,"%s:%d: %s: Unusable device-tree file\n" , __func__, + __LINE__, dtb.path); + result =-1 ;
EFAILED?
kexec/arch/arm64/kexec-arm64.c line 591
Quoted 4 lines
kexec/arch/arm64/kexec-arm64.c new file +4
-0+ +on_exit: +free (dtb.buf); +return -EFAILED ;
return result?
Quoted 12 lines
kexec/arch/arm64/kexec-arm64.c new file +12
-0+} + +/** +* get_memory_ranges - Try to get the memory ranges some how. +*/ + +int get_memory_ranges (struct memory_range **range,int *ranges, +unsigned long kexec_flags) +{ +static struct memory_range array[KEXEC_SEGMENT_MAX ]; +unsigned int count; +int result;
kexec/arch/arm64/kexec-arm64.c line 613
Quoted 10 lines
kexec/arch/arm64/kexec-arm64.c new file +10
-0+ + result =get_memory_ranges_iomem (array, &count); + +if (result) + result =get_memory_ranges_dt (array, &count); + + *range = result ?NULL : array; + *ranges = result ?0 : count; + +return -EFAILED ;
return result?
Quoted 25 lines
kexec/arch/arm64/kexec-arm64.c new file +25
-0+} + +int arch_compat_trampoline (struct kexec_info *info) +{ +return 0 ; +} + +int machine_verify_elf_rel (struct mem_ehdr *ehdr) +{ +return (ehdr->e_machine ==EM_AARCH64 ); +} + +void machine_apply_elf_rel (struct mem_ehdr *ehdr,struct mem_sym *UNUSED (sym ), +unsigned long r_type,void *ptr,unsigned long address, +unsigned long value) +{ +#if !defined(R_AARCH64_ABS64 ) +# define R_AARCH64_ABS64 257 +#endif + +#if !defined(R_AARCH64_LD_PREL_LO19 ) +# define R_AARCH64_LD_PREL_LO19 273 +#endif + +#if !defined(R_AARCH64_ADR_PREL_LO21 )
kexec/arch/arm64/kexec-arm64.c line 648
Quoted 10 lines
kexec/arch/arm64/kexec-arm64.c new file +10
-0+# define R_AARCH64_ADR_PREL_LO21 274 +#endif + +#if !defined(R_AARCH64_JUMP26 ) +# define R_AARCH64_JUMP26 282 +#endif + +#if !defined(R_AARCH64_CALL26 ) +# define R_AARCH64_CALL26 283 +#endif
I still believe those definitons should go into elf.h.
Quoted 100 lines
kexec/arch/arm64/kexec-arm64.c new file +56
-0+ +uint64_t *loc64; +uint32_t *loc32; +uint64_t *location = (uint64_t *)ptr; +uint64_t data = *location; +const char *type =NULL ; + +switch (r_type) { +case R_AARCH64_ABS64 : + type ="ABS64" ; + loc64 = ptr; + *loc64 =cpu_to_elf64 (ehdr,elf64_to_cpu (ehdr, *loc64) + value); +break ; +case R_AARCH64_LD_PREL_LO19 : + type ="LD_PREL_LO19" ; + loc32 = ptr; + *loc32 =cpu_to_le32 (le32_to_cpu (*loc32) + + (((value - address) <<3 ) &0xffffe0 )); +break ; +case R_AARCH64_ADR_PREL_LO21 : +if (value &3 ) +die ("%s: ERROR Unaligned value: %lx\n" , __func__, + value); + type ="ADR_PREL_LO21" ; + loc32 = ptr; + *loc32 =cpu_to_le32 (le32_to_cpu (*loc32) + + (((value - address) <<3 ) &0xffffe0 )); +break ; +case R_AARCH64_JUMP26 : + type ="JUMP26" ; + loc32 = ptr; + *loc32 =cpu_to_le32 (le32_to_cpu (*loc32) + + (((value - address) >>2 ) &0x3ffffff )); +break ; +case R_AARCH64_CALL26 : + type ="CALL26" ; + loc32 = ptr; + *loc32 =cpu_to_le32 (le32_to_cpu (*loc32) + + (((value - address) >>2 ) &0x3ffffff )); +break ; +default : +die ("%s: ERROR Unknown type: %lu\n" , __func__, r_type); +break ; + } + +dbgprintf ("%s: %s %016lx->%016lx\n" , __func__, type, data, *location); +} + +void arch_reuse_initrd (void ) +{ + reuse_initrd =1 ; +} + +void arch_update_purgatory (struct kexec_info *UNUSED (info )) +{ +}kexec/arch/arm64/kexec-arm64.h new file +38
-0@@ -0,0 +1,70 @@ +/* +* ARM64 kexec. +*/ + +#if !defined(KEXEC_ARM64_H ) +#define KEXEC_ARM64_H + +#include <stdbool.h> +#include <sys/types.h> + +#include "image-header.h" +#include "kexec.h" + +#define KEXEC_SEGMENT_MAX 16 + +#define BOOT_BLOCK_VERSION 17 +#define BOOT_BLOCK_LAST_COMP_VERSION 16 +#define COMMAND_LINE_SIZE 512 + +#define KiB (x) ((x) * 1024UL) +#define MiB (x) (KiB(x) * 1024UL) +#define GiB (x) (MiB(x) * 1024UL) + +int elf_arm64_probe (const char *kernel_buf,off_t kernel_size); +int elf_arm64_load (int argc,char **argv,const char *kernel_buf, +off_t kernel_size,struct kexec_info *info); +void elf_arm64_usage (void ); + +int image_arm64_probe (const char *kernel_buf,off_t kernel_size); +int image_arm64_load (int argc,char **argv,const char *kernel_buf, +off_t kernel_size,struct kexec_info *info); +void image_arm64_usage (void ); + +off_t initrd_base; +off_t initrd_size; + +/** +* struct arm64_mem - Memory layout info.
kexec/arch/arm64/kexec-arm64.h line 48
Quoted 10 lines
kexec/arch/arm64/kexec-arm64.h new file +10
-0+*/ + +struct arm64_mem { +uint64_t phys_offset; +uint64_t text_offset; +uint64_t image_size; +uint64_t page_offset; +}; + +#define arm64_mem_ngv UINT64_MAX
In image_header.h, you define "const" variables,
here you define a macro.
Quoted 124 lines
kexec/arch/arm64/kexec-arm64.h new file +22
-0+struct arm64_mem arm64_mem; + +uint64_t get_phys_offset (void ); +uint64_t get_page_offset (void ); + +static inline void reset_page_offset (void ) +{ + arm64_mem.page_offset = arm64_mem_ngv; +} + +static inline void set_phys_offset (uint64_t v) +{ +if (arm64_mem.phys_offset == arm64_mem_ngv + || v < arm64_mem.phys_offset) + arm64_mem.phys_offset = v; +} + +int arm64_process_image_header (const struct arm64_image_header *h); +int arm64_load_other_segments (struct kexec_info *info, +uint64_t kernel_entry); + +#endif kexec/arch/arm64/kexec-elf-arm64.c new file +96
-0@@ -0,0 +1,130 @@ +/* +* ARM64 kexec elf support. +*/ + +#define _GNU_SOURCE + +#include <errno.h> +#include <stdlib.h> +#include <linux/elf.h> + +#include "kexec-arm64.h" +#include "kexec-elf.h" +#include "kexec-syscall.h" + +int elf_arm64_probe (const char *kernel_buf,off_t kernel_size) +{ +struct mem_ehdr ehdr; +int result; + + result =build_elf_exec_info (kernel_buf, kernel_size, &ehdr,0 ); + +if (result <0 ) { +dbgprintf ("%s: Not an ELF executable.\n" , __func__); + goto on_exit; + } + +if (ehdr.e_machine !=EM_AARCH64 ) { +dbgprintf ("%s: Not an AARCH64 ELF executable.\n" , __func__); + result =-1 ; + goto on_exit; + } + + result =0 ; +on_exit: +free_elf_info (&ehdr); +return result; +} + +int elf_arm64_load (int argc,char **argv,const char *kernel_buf, +off_t kernel_size,struct kexec_info *info) +{ +struct mem_ehdr ehdr; +int result; +int i; + +if (info->kexec_flags &KEXEC_ON_CRASH ) { +fprintf (stderr,"kexec: kdump not yet supported on arm64\n" ); +return -EFAILED ; + } + + result =build_elf_exec_info (kernel_buf, kernel_size, &ehdr,0 ); + +if (result <0 ) { +dbgprintf ("%s: build_elf_exec_info failed\n" , __func__); + goto exit; + } + +/* Find and process the arm64 image header. */ + +for (i =0 ; i < ehdr.e_phnum; i++) { +struct mem_phdr *phdr = &ehdr.e_phdr[i]; +const struct arm64_image_header *h; +unsigned long header_offset; + +if (phdr->p_type !=PT_LOAD ) +continue ; + +/* +* When CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET=y the image header +* could be offset in the elf segment. The linker script sets +* ehdr.e_entry to the start of text. +*/ + + header_offset = ehdr.e_entry - phdr->p_vaddr; + + h = (const struct arm64_image_header *)( + kernel_buf + phdr->p_offset + header_offset); + +if (arm64_process_image_header (h)) +continue ; + + arm64_mem.page_offset = ehdr.e_entry - arm64_mem.text_offset; + +dbgprintf ("%s: e_entry: %016llx -> %016lx\n" , __func__, + ehdr.e_entry, +virt_to_phys (ehdr.e_entry)); +dbgprintf ("%s: p_vaddr: %016llx -> %016lx\n" , __func__, + phdr->p_vaddr, +virt_to_phys (phdr->p_vaddr)); +dbgprintf ("%s: header_offset: %016lx\n" , __func__, + header_offset); +dbgprintf ("%s: text_offset: %016lx\n" , __func__, + arm64_mem.text_offset); +dbgprintf ("%s: image_size: %016lx\n" , __func__, + arm64_mem.image_size); + dbgprintf("%s: phys_offset: %016lx\n", __func__,
kexec/arch/arm64/kexec-elf-arm64.c line 106
Quoted 10 lines
kexec/arch/arm64/kexec-elf-arm64.c new file +10
-0+ arm64_mem.phys_offset); +dbgprintf ("%s: page_offset: %016lx\n" , __func__, + arm64_mem.page_offset); +dbgprintf ("%s: PE format: %s\n" , __func__, + (arm64_header_check_pe_sig (h) ?"yes" :"no" )); + + result =elf_exec_load (&ehdr, info); + +if (result) { +fprintf (stderr,"kexec: Elf load failed.\n" );
dbgprintf?
You use this for build_elf_exec_info() above.
kexec/arch/arm64/kexec-elf-arm64.c line 115
Quoted 9 lines
kexec/arch/arm64/kexec-elf-arm64.c new file +9
-0+ goto exit; + } + + result =arm64_load_other_segments (info, +virt_to_phys (ehdr.e_entry)); + goto exit; + } + +fprintf (stderr,"kexec: Bad arm64 image header.\n" );
Is this an appropriate message?
Quoted 21 lines
kexec/arch/arm64/kexec-elf-arm64.c new file +15
-0+ result = -EFAILED ; + goto exit; + +exit: +reset_page_offset (); +free_elf_info (&ehdr); +return result; +} + +void elf_arm64_usage (void ) +{ +printf ( +" An ARM64 ELF image, big or little endian.\n" +" Typically vmlinux or a stripped version of vmlinux.\n\n" ); +}kexec/arch/arm64/kexec-image-arm64.c new file +0
-0
kexec/arch/arm64/kexec-image-arm64.c line 7
Quoted 7 lines
kexec/arch/arm64/kexec-image-arm64.c new file +7
-0@@ -0,0 +1,44 @@ +/* +* ARM64 kexec binary image support. +*/ + +#define _GNU_SOURCE + +#include <errno.h>
Not used.
Thanks,
-Takahiro AKASHI
Quoted 192 lines
kexec/arch/arm64/kexec-image-arm64.c new file +37
-0+ +#include "kexec-arm64.h" + +int image_arm64_probe (const char *kernel_buf,off_t kernel_size) +{ +const struct arm64_image_header *h; + +if (kernel_size <sizeof (struct arm64_image_header )) { +dbgprintf ("%s: No arm64 image header.\n" , __func__); +return -1 ; + } + + h = (const struct arm64_image_header *)(kernel_buf); + +if (!arm64_header_check_magic (h)) { +dbgprintf ("%s: Bad arm64 image header.\n" , __func__); +return -1 ; + } + +fprintf (stderr,"kexec: ARM64 binary image files are currently NOT SUPPORTED.\n" ); + +return -1 ; +} + +int image_arm64_load (int argc,char **argv,const char *kernel_buf, +off_t kernel_size,struct kexec_info *info) +{ +return -EFAILED ; +} + +void image_arm64_usage (void ) +{ +printf ( +" An ARM64 binary image, compressed or not, big or little endian.\n" +" Typically an Image, Image.gz or Image.lzma file.\n" +" This file type is currently NOT SUPPORTED.\n\n" ); +}kexec/kexec-syscall.h +6
-2@@ -39,8 +39,8 @@#ifdef __s390__#define __NR_kexec_load 277#endif -#ifdef __arm__ -#define __NR_kexec_load __NR_SYSCALL_BASE + 347 +#if defined(__arm__) || defined(__arm64__) +#define __NR_kexec_load __NR_SYSCALL_BASE + 347#endif #if defined(__mips__)#define __NR_kexec_load 4311@@ -108,6 +108,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,#define KEXEC_ARCH_PPC64 (21 << 16)#define KEXEC_ARCH_IA_64 (50 << 16)#define KEXEC_ARCH_ARM (40 << 16) +#define KEXEC_ARCH_ARM64 (183 << 16)#define KEXEC_ARCH_S390 (22 << 16)#define KEXEC_ARCH_SH (42 << 16)#define KEXEC_ARCH_MIPS_LE (10 << 16)@@ -153,5 +154,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,#ifdef __m68k__#define KEXEC_ARCH_NATIVE KEXEC_ARCH_68K#endif +#if defined(__arm64__) +#define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM64 +#endif #endif /* KEXEC_SYSCALL_H */ purgatory/Makefile +1
-0@@ -19,6 +19,7 @@ dist += purgatory/Makefile $(PURGATORY_SRCS) \ include $(srcdir)/purgatory/arch/alpha/Makefile include $(srcdir)/purgatory/arch/arm/Makefile +include $(srcdir)/purgatory/arch/arm64/Makefile include $(srcdir)/purgatory/arch/i386/Makefile include $(srcdir)/purgatory/arch/ia64/Makefile include $(srcdir)/purgatory/arch/mips/Makefilepurgatory/arch/arm64/Makefile new file +18
-0@@ -0,0 +1,18 @@ + +arm64_PURGATORY_EXTRA_CFLAGS = \ + -mcmodel=large \ + -fno-stack-protector \ + -fno-asynchronous-unwind-tables \ + -Wundef \ + -Werror-implicit-function-declaration \ + -Wdeclaration-after-statement \ + -Werror=implicit-int \ + -Werror=strict-prototypes + +arm64_PURGATORY_SRCS += \ + purgatory/arch/arm64/entry.S \ + purgatory/arch/arm64/purgatory-arm64.c + +dist += \ + $(arm64_PURGATORY_SRCS) \ + purgatory/arch/arm64/Makefilepurgatory/arch/arm64/entry.S new file +51
-0@@ -0,0 +1,51 @@ +/* + * ARM64 purgatory. + */ + +.macro size, sym:req + .size \sym, . - \sym +.endm + +.text + +.globl purgatory_start +purgatory_start: + + adr x19, .Lstack + mov sp, x19 + + bl purgatory + + /* Start new image. */ + ldr x17, arm64_kernel_entry + ldr x0, arm64_dtb_addr + mov x1, xzr + mov x2, xzr + mov x3, xzr + br x17 + +size purgatory_start + +.ltorg + +.align 4 + .rept 256 + .quad 0 + .endr +.Lstack: + +.data + +.align 3 + +.globl arm64_kernel_entry +arm64_kernel_entry: + .quad 0 +size arm64_kernel_entry + +.globl arm64_dtb_addr +arm64_dtb_addr: + .quad 0 +size arm64_dtb_addr + +.endpurgatory/arch/arm64/purgatory-arm64.c new file +19
-0@@ -0,0 +1,19 @@ +/* +* ARM64 purgatory. +*/ + +#include <stdint.h> +#include <purgatory.h> + +void putchar (int ch) +{ +/* Nothing for now */ +} + +void post_verification_setup_arch (void ) +{ +} + +void setup_arch (void ) +{ +}Signature · 1 line
2.5.0
_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
Re: [PATCH v3 2/3] arm64: Add arm64 kexec support
Quoted 31 lines · AKASHI Takahiro
Quoted 30 lines · Geoff Levand
kexec/arch/arm64/image-header.h new file +30
-0+/** +* struct arm64_image_header - arm64 kernel image header. +* +* @pe_sig: Optional PE format 'MZ' signature. +* @branch_code: Reserved for instructions to branch to stext. +* @text_offset: The image load offset in LSB byte order. +* @image_size: An estimated size of the memory image size in LSB byte order. +* @flags: Bit flags in LSB byte order: +* Bit 0: Image byte order: 1=MSB. +* Bit 1-2: Kernel page size: 1=4K, 2=16K, 3=64K. +* Bit 3: Image placement: 0=low. +* @reserved_1: Reserved. +* @magic: Magic number, "ARM\x64". +* @pe_header: Optional offset to a PE format header. +**/ + +struct arm64_image_header { +> > > > uint8_t pe_sig[2]; +> > > > uint16_t branch_code[3]; +> > > > uint64_t text_offset; +> > > > uint64_t image_size; +> > > > uint64_t flags; +> > > > uint64_t reserved_1[3]; +> > > > uint8_t magic[4]; +> > > > uint32_t pe_header; +}; + +static const uint8_t arm64_image_magic[4 ] = {'A' ,'R' ,'M' ,0x64U }; +static const uint8_t arm64_image_pe_sig[2 ] = {'M' ,'Z' }; +static const uint64_t arm64_image_flag_be = (1UL <<0 );
Quoted 8 lines
kexec/arch/arm64/image-header.h line 42
Quoted 2 lines
kexec/arch/arm64/image-header.h new file +2
-0+static const uint64_t arm64_image_flag_page_size = (3UL <<1 ); +static const uint64_t arm64_image_flag_placement = (1UL <<3 );Why not define like:
#defineARM64_FLAG_PAGE_SIZE_4K1
#defineARM64_FLAG_PAGE_SIZE_16K2
#defineARM64_FLAG_PAGE_SIZE_64K3
if you havearm64_header_page_size()?
To give them a type, I added these in as enum arm64_header_page_size.
Quoted 23 lines
Quoted 23 lines
kexec/arch/arm64/image-header.h new file +22
-0+ +/** +* arm64_header_check_magic - Helper to check the arm64 image header. +* +* Returns non-zero if header is OK. +*/ + +static inline int arm64_header_check_magic (const struct arm64_image_header *h) +{ +> > > > if (!h) +> > > > > > return 0; + +> > > > return (h->magic[0] == arm64_image_magic[0] +> > > > > > && h->magic[1] == arm64_image_magic[1] +> > > > > > && h->magic[2] == arm64_image_magic[2] +> > > > > > && h->magic[3] == arm64_image_magic[3]); +} + +/** +* arm64_header_check_pe_sig - Helper to check the arm64 image header. +* +* Returns non-zero if 'MZ' signature is found.
Quoted 8 lines
kexec/arch/arm64/image-header.h
Quoted 6 lines
+ */
kexec/arch/arm64/image-header.h new file +5
-0+ +static inline int arm64_header_check_pe_sig (const struct arm64_image_header *h) +{ +> > > > if (!h) +> > > > > > return 0;Why not add
assert()here likeget_phys_offset()?
The assert in get_phys_offset() is to check for incorrect usage. arm64_header_check_pe_sig is a generic routine, and having a null value may be OK.
Quoted 6 lines
kexec/arch/arm64/image-header.h line 116
Quoted 4 lines
kexec/arch/arm64/image-header.h new file +4
-0+ +static inline uint64_t arm64_header_text_offset ( +> > > > const struct arm64_image_header *h) +{Why not check for !h?
ok.
Quoted 95 lines
Quoted 82 lines
kexec/arch/arm64/kexec-arm64.c new file +80
-0+static int get_memory_ranges_dt (struct memory_range *array,unsigned int *count) +{ +> > > > struct region {uint64_t base; uint64_t size;}; +> > > > struct dtb dtb = {.name = "range_dtb"}; +> > > > int offset; +> > > > int result; + +> > > > *count = 0; + +> > > > result = read_1st_dtb(&dtb); + +> > > > if (result) { +> > > > > > goto on_error; +> > > > } + +> > > > result = fdt_check_header(dtb.buf); + +> > > > if (result) { +> > > > > > dbgprintf("%s:%d: %s: fdt_check_header failed:%s\n", __func__, +> > > > > > > > __LINE__, dtb.path, fdt_strerror(result)); +> > > > > > goto on_error; +> > > > } + +> > > > for (offset = 0; ; ) { +> > > > > > const struct region *region; +> > > > > > const struct region *end; +> > > > > > int len; + +> > > > > > offset = fdt_subnode_offset(dtb.buf, offset, "memory"); + +> > > > > > if (offset == -FDT_ERR_NOTFOUND) +> > > > > > > > break; + +> > > > > > if (offset <= 0) { +> > > > > > > > dbgprintf("%s:%d: fdt_subnode_offset failed: %d %s\n", +> > > > > > > > > > __func__, __LINE__, offset, +> > > > > > > > > > fdt_strerror(offset)); +> > > > > > > > goto on_error; +> > > > > > } + +> > > > > > dbgprintf("%s:%d: node_%d %s\n", __func__, __LINE__, offset, +> > > > > > > > fdt_get_name(dtb.buf, offset, NULL)); + +> > > > > > region = fdt_getprop(dtb.buf, offset, "reg", &len); + +> > > > > > if (region <= 0) { +> > > > > > > > dbgprintf("%s:%d: fdt_getprop failed: %d %s\n", +> > > > > > > > > > __func__, __LINE__, offset, +> > > > > > > > > > fdt_strerror(offset)); +> > > > > > > > goto on_error; +> > > > > > } + +> > > > > > for (end = region + len / sizeof(*region); +> > > > > > > > region < end && *count < KEXEC_SEGMENT_MAX; +> > > > > > > > region++) { +> > > > > > > > struct memory_range r; + +> > > > > > > > r.type = RANGE_RAM; +> > > > > > > > r.start = fdt64_to_cpu(region->base); +> > > > > > > > r.end = r.start + fdt64_to_cpu(region->size) - 1; + +> > > > > > > > if (!region->size) { +> > > > > > > > > > dbgprintf("%s:%d: SKIP: %016llx - %016llx\n", +> > > > > > > > > > > > __func__, __LINE__, r.start, r.end); +> > > > > > > > > > continue; +> > > > > > > > } + +> > > > > > > > dbgprintf("%s:%d: RAM: %016llx - %016llx\n", __func__, +> > > > > > > > > > __LINE__, r.start, r.end); + +> > > > > > > > array[(*count)++] = r; + +> > > > > > > > set_phys_offset(r.start); +> > > > > > } +> > > > } + +> > > > if (!*count) { +> > > > > > dbgprintf("%s:%d: %s: No RAM found.\n", __func__, __LINE__, +> > > > > > > > dtb.path); +> > > > > > goto on_error;kexec/arch/arm64/kexec-arm64.c
Quoted 10 lines
kexec/arch/arm64/kexec-arm64.c new file +10
-0+> > > > } + +> > > > dbgprintf("%s:%d: %s: Success\n", __func__, __LINE__, dtb.path); +> > > > result = 0; +> > > > goto on_exit; + +on_error: +> > > > fprintf(stderr, "%s:%d: %s: Unusable device-tree file\n", __func__, +> > > > > > __LINE__, dtb.path); +> > > > result = -1;EFAILED?
Quoted 6 lines
kexec/arch/arm64/kexec-arm64.c
Quoted 4 lines
kexec/arch/arm64/kexec-arm64.c new file +4
-0+ +on_exit: +> > > > free(dtb.buf); +> > > > return -EFAILED;return result?
OK.
Quoted 17 lines
Quoted 17 lines
kexec/arch/arm64/kexec-arm64.c new file +16
-0+} + +/** +* get_memory_ranges - Try to get the memory ranges some how. +*/ + +int get_memory_ranges (struct memory_range **range,int *ranges, +> > > > unsigned long kexec_flags) +{ +> > > > static struct memory_range array[KEXEC_SEGMENT_MAX]; +> > > > unsigned int count; +> > > > int result; + +> > > > result = get_memory_ranges_iomem(array, &count); + +> > > > if (result)
Quoted 8 lines
kexec/arch/arm64/kexec-arm64.c
Quoted 6 lines
+> > > > > > result =
get_memory_ranges_dt(array, &count);kexec/arch/arm64/kexec-arm64.c new file +5
-0+ +> > > > *range = result ? NULL : array; +> > > > *ranges = result ? 0 : count; + +> > > > return -EFAILED;return result?
OK.
Quoted 30 lines
Quoted 30 lines
kexec/arch/arm64/kexec-arm64.c new file +29
-0+} + +int arch_compat_trampoline (struct kexec_info *info) +{ +> > > > return 0; +} + +int machine_verify_elf_rel (struct mem_ehdr *ehdr) +{ +> > > > return (ehdr->e_machine == EM_AARCH64); +} + +void machine_apply_elf_rel (struct mem_ehdr *ehdr,struct mem_sym *UNUSED (sym ), +> > > > unsigned long r_type, void *ptr, unsigned long address, +> > > > unsigned long value) +{ +#if !defined(R_AARCH64_ABS64 ) +# define R_AARCH64_ABS64 257 +#endif + +#if !defined(R_AARCH64_LD_PREL_LO19 ) +# define R_AARCH64_LD_PREL_LO19 273 +#endif + +#if !defined(R_AARCH64_ADR_PREL_LO21 ) +# define R_AARCH64_ADR_PREL_LO21 274 +#endif + +#if !defined(R_AARCH64_JUMP26 )
Quoted 8 lines
kexec/arch/arm64/kexec-arm64.c line 648
Quoted 6 lines
kexec/arch/arm64/kexec-arm64.c new file +6
-0+# define R_AARCH64_JUMP26 282 +#endif + +#if !defined(R_AARCH64_CALL26 ) +# define R_AARCH64_CALL26 283 +#endif I still believe those definitons should go into
elf.h.
They should be comming from the c library headers. When toolchains catch up these can be removed.
Quoted 46 lines
Quoted 46 lines
kexec/arch/arm64/kexec-arm64.h new file +43
-0@@ -0,0 +1,70 @@ +/* +* ARM64 kexec. +*/ + +#if !defined(KEXEC_ARM64_H) +#define KEXEC_ARM64_H + +#include +#include + +#include "image-header.h" +#include "kexec.h" + +#define KEXEC_SEGMENT_MAX 16 + +#define BOOT_BLOCK_VERSION 17 +#define BOOT_BLOCK_LAST_COMP_VERSION 16 +#define COMMAND_LINE_SIZE 512 + +#define KiB(x) ((x) * 1024UL) +#define MiB(x) (KiB(x) * 1024UL) +#define GiB(x) (MiB(x) * 1024UL) + +int elf_arm64_probe(const char *kernel_buf, off_t kernel_size); +int elf_arm64_load(int argc, char **argv, const char *kernel_buf, +> > > > off_t kernel_size, struct kexec_info *info); +void elf_arm64_usage(void); + +int image_arm64_probe(const char *kernel_buf, off_t kernel_size); +int image_arm64_load(int argc, char **argv, const char *kernel_buf, +> > > > off_t kernel_size, struct kexec_info *info); +void image_arm64_usage(void); + +off_t initrd_base; +off_t initrd_size; + +/** + * struct arm64_mem - Memory layout info. + */ + +struct arm64_mem { +> > > > uint64_t phys_offset; +> > > > uint64_t text_offset;
Quoted 8 lines
kexec/arch/arm64/kexec-arm64.h line 48
Quoted 5 lines
kexec/arch/arm64/kexec-arm64.h new file +5
-0+> > > > uint64_t image_size; +> > > > uint64_t page_offset; +}; + +#define arm64_mem_ngv UINT64_MAXIn
image_header.h, you define "const" variables,
here you define a macro.
Yes, because arm64_mem_ngv is used as a static
initializer of arm64_mem.
Quoted 138 lines
Quoted 124 lines
kexec/arch/arm64/kexec-arm64.h new file +22
-0+struct arm64_mem arm64_mem; + +uint64_t get_phys_offset (void ); +uint64_t get_page_offset (void ); + +static inline void reset_page_offset (void ) +{ +> > > > arm64_mem.page_offset = arm64_mem_ngv; +} + +static inline void set_phys_offset (uint64_t v) +{ +> > > > if (arm64_mem.phys_offset == arm64_mem_ngv +> > > > > > || v < arm64_mem.phys_offset) +> > > > > > arm64_mem.phys_offset = v; +} + +int arm64_process_image_header (const struct arm64_image_header *h); +int arm64_load_other_segments (struct kexec_info *info, +> > > > uint64_t kernel_entry); + +#endif kexec/arch/arm64/kexec-elf-arm64.c new file +96
-0@@ -0,0 +1,130 @@ +/* +* ARM64 kexec elf support. +*/ + +#define _GNU_SOURCE + +#include +#include +#include + +#include "kexec-arm64.h" +#include "kexec-elf.h" +#include "kexec-syscall.h" + +int elf_arm64_probe (const char *kernel_buf,off_t kernel_size) +{ +> > > > struct mem_ehdr ehdr; +> > > > int result; + +> > > > result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); + +> > > > if (result < 0) { +> > > > > > dbgprintf("%s: Not an ELF executable.\n", __func__); +> > > > > > goto on_exit; +> > > > } + +> > > > if (ehdr.e_machine != EM_AARCH64) { +> > > > > > dbgprintf("%s: Not an AARCH64 ELF executable.\n", __func__); +> > > > > > result = -1; +> > > > > > goto on_exit; +> > > > } + +> > > > result = 0; +on_exit: +> > > > free_elf_info(&ehdr); +> > > > return result; +} + +int elf_arm64_load (int argc,char **argv,const char *kernel_buf, +> > > > off_t kernel_size, struct kexec_info *info) +{ +> > > > struct mem_ehdr ehdr; +> > > > int result; +> > > > int i; + +> > > > if (info->kexec_flags & KEXEC_ON_CRASH) { +> > > > > > fprintf(stderr, "kexec: kdump not yet supported on arm64\n"); +> > > > > > return -EFAILED; +> > > > } + +> > > > result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); + +> > > > if (result < 0) { +> > > > > > dbgprintf("%s: build_elf_exec_info failed\n", __func__); +> > > > > > goto exit; +> > > > } + +> > > > /* Find and process the arm64 image header. */ + +> > > > for (i = 0; i < ehdr.e_phnum; i++) { +> > > > > > struct mem_phdr *phdr = &ehdr.e_phdr[i]; +> > > > > > const struct arm64_image_header *h; +> > > > > > unsigned long header_offset; + +> > > > > > if (phdr->p_type != PT_LOAD) +> > > > > > > > continue; + +> > > > > > /* +> > > > > > * When CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET=y the image header +> > > > > > * could be offset in the elf segment. The linker script sets +> > > > > > * ehdr.e_entry to the start of text. +> > > > > > */ + +> > > > > > header_offset = ehdr.e_entry - phdr->p_vaddr; + +> > > > > > h = (const struct arm64_image_header *)( +> > > > > > > > kernel_buf + phdr->p_offset + header_offset); + +> > > > > > if (arm64_process_image_header(h)) +> > > > > > > > continue; + +> > > > > > arm64_mem.page_offset = ehdr.e_entry - arm64_mem.text_offset; + +> > > > > > dbgprintf("%s: e_entry: %016llx -> %016lx\n", __func__, +> > > > > > > > ehdr.e_entry, +> > > > > > > > virt_to_phys(ehdr.e_entry)); +> > > > > > dbgprintf("%s: p_vaddr: %016llx -> %016lx\n", __func__, +> > > > > > > > phdr->p_vaddr, +> > > > > > > > virt_to_phys(phdr->p_vaddr)); +> > > > > > dbgprintf("%s: header_offset: %016lx\n", __func__, +> > > > > > > > header_offset); +> > > > > > dbgprintf("%s: text_offset: %016lx\n", __func__, +> > > > > > > > arm64_mem.text_offset); +> > > > > > dbgprintf("%s: image_size: %016lx\n", __func__, +> > > > > > > > arm64_mem.image_size); +> > > > > > dbgprintf("%s: phys_offset: %016lx\n", __func__,kexec/arch/arm64/kexec-elf-arm64.c line 106
Quoted 10 lines
kexec/arch/arm64/kexec-elf-arm64.c new file +10
-0+> > > > > > > > arm64_mem.phys_offset); +> > > > > > dbgprintf("%s: page_offset: %016lx\n", __func__, +> > > > > > > > arm64_mem.page_offset); +> > > > > > dbgprintf("%s: PE format: %s\n", __func__, +> > > > > > > > (arm64_header_check_pe_sig(h) ? "yes" : "no")); + +> > > > > > result = elf_exec_load(&ehdr, info); + +> > > > > > if (result) { +> > > > > > > > fprintf(stderr, "kexec: Elf load failed.\n");dbgprintf?
You use this forbuild_elf_exec_info()above.
Quoted 11 lines
kexec/arch/arm64/kexec-elf-arm64.c line 115
Quoted 9 lines
kexec/arch/arm64/kexec-elf-arm64.c new file +9
-0+> > > > > > > > goto exit; +> > > > > > } + +> > > > > > result = arm64_load_other_segments(info, +> > > > > > > > virt_to_phys(ehdr.e_entry)); +> > > > > > goto exit; +> > > > } + +> > > > fprintf(stderr, "kexec: Bad arm64 image header.\n");Is this an appropriate message?
I changed elf_arm64_load to output dbgprintf during its operation, then a final message to stderr on exit.
Quoted 14 lines
Quoted 14 lines
kexec/arch/arm64/kexec-elf-arm64.c new file +9
-0+> > > > result = -EFAILED; +> > > > goto exit; + +exit: +> > > > reset_page_offset(); +> > > > free_elf_info(&ehdr); +> > > > return result; +} +kexec/arch/arm64/kexec-image-arm64.c new file +1
-0@@ -0,0 +1,44 @@ +/*
Quoted 8 lines
kexec/arch/arm64/kexec-image-arm64.c
Quoted 6 lines
kexec/arch/arm64/kexec-image-arm64.c new file +6
-0+* ARM64 kexec binary image support. +*/ + +#define _GNU_SOURCE + +#includeNot used.
OK.
Thanks for the review.
-Geoff
_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
PATCH v3 2/3 arm64: Add arm64 kexec support
In reply to Geoff LevandAdd kexec reboot support for ARM64 platforms.
--- configure.ac | 3 + kexec/Makefile | 1 + kexec/arch/arm64/Makefile | 40 ++ kexec/arch/arm64/crashdump-arm64.c | 21 + kexec/arch/arm64/crashdump-arm64.h | 12 + kexec/arch/arm64/image-header.h | 144 +++++++ kexec/arch/arm64/include/arch/options.h | 39 ++ kexec/arch/arm64/kexec-arm64.c | 705 ++++++++++++++++++++++++++++++++ kexec/arch/arm64/kexec-arm64.h | 70 ++++ kexec/arch/arm64/kexec-elf-arm64.c | 132 ++++++ kexec/arch/arm64/kexec-image-arm64.c | 41 ++ kexec/kexec-syscall.h | 8 +- purgatory/Makefile | 1 + purgatory/arch/arm64/Makefile | 18 + purgatory/arch/arm64/entry.S | 51 +++ purgatory/arch/arm64/purgatory-arm64.c | 19 + 16 files changed, 1303 insertions(+), 2 deletions(-) create mode 100644 kexec/arch/arm64/Makefile create mode 100644 kexec/arch/arm64/crashdump-arm64.c create mode 100644 kexec/arch/arm64/crashdump-arm64.h create mode 100644 kexec/arch/arm64/image-header.h create mode 100644 kexec/arch/arm64/include/arch/options.h create mode 100644 kexec/arch/arm64/kexec-arm64.c create mode 100644 kexec/arch/arm64/kexec-arm64.h create mode 100644 kexec/arch/arm64/kexec-elf-arm64.c create mode 100644 kexec/arch/arm64/kexec-image-arm64.c create mode 100644 purgatory/arch/arm64/Makefile create mode 100644 purgatory/arch/arm64/entry.S create mode 100644 purgatory/arch/arm64/purgatory-arm64.c
configure.ac +3 -0
@@ -34,6 +34,9 @@ case $target_cpu in ARCH="ppc64" SUBARCH="LE" ;; + aarch64* ) + ARCH="arm64" + ;; arm* ) ARCH="arm" ;;
kexec/Makefile +1 -0
@@ -79,6 +79,7 @@ KEXEC_SRCS += $($(ARCH)_DT_OPS) include $(srcdir)/kexec/arch/alpha/Makefile include $(srcdir)/kexec/arch/arm/Makefile +include $(srcdir)/kexec/arch/arm64/Makefile include $(srcdir)/kexec/arch/i386/Makefile include $(srcdir)/kexec/arch/ia64/Makefile include $(srcdir)/kexec/arch/m68k/Makefile
kexec/arch/arm64/Makefile new file +40 -0
@@ -0,0 +1,40 @@ + +arm64_FS2DT += kexec/fs2dt.c +arm64_FS2DT_INCLUDE += -include $(srcdir)/kexec/arch/arm64/kexec-arm64.h \ + -include $(srcdir)/kexec/arch/arm64/crashdump-arm64.h + +arm64_DT_OPS += kexec/dt-ops.c + +arm64_CPPFLAGS += -I $(srcdir)/kexec/ + +arm64_KEXEC_SRCS += \ + kexec/arch/arm64/kexec-arm64.c \ + kexec/arch/arm64/kexec-image-arm64.c \ + kexec/arch/arm64/kexec-elf-arm64.c \ + kexec/arch/arm64/crashdump-arm64.c + +arm64_ARCH_REUSE_INITRD = +arm64_ADD_SEGMENT = +arm64_VIRT_TO_PHYS = +arm64_PHYS_TO_VIRT = + +dist += $(arm64_KEXEC_SRCS) \ + kexec/arch/arm64/Makefile \ + kexec/arch/arm64/kexec-arm64.h \ + kexec/arch/arm64/crashdump-arm64.h + +ifdef HAVE_LIBFDT + +LIBS += -lfdt + +else + +include $(srcdir)/kexec/libfdt/Makefile.libfdt + +libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%) + +arm64_CPPFLAGS += -I$(srcdir)/kexec/libfdt + +arm64_KEXEC_SRCS += $(libfdt_SRCS) + +endif
kexec/arch/arm64/crashdump-arm64.c new file +21 -0
@@ -0,0 +1,21 @@ +/* +* ARM64 crashdump. +*/ + +#define _GNU_SOURCE + +#include <errno.h> +#include <linux/elf.h> + +#include "kexec.h" +#include "crashdump.h" +#include "crashdump-arm64.h" +#include "kexec-arm64.h" +#include "kexec-elf.h" + +struct memory_ranges usablemem_rgns = {}; + +int is_crashkernel_mem_reserved (void ) +{ +return 0 ; +}
kexec/arch/arm64/crashdump-arm64.h new file +12 -0
@@ -0,0 +1,12 @@ +/* +* ARM64 crashdump. +*/ + +#if !defined(CRASHDUMP_ARM64_H ) +#define CRASHDUMP_ARM64_H + +#include "kexec.h" + +extern struct memory_ranges usablemem_rgns; + +#endif
kexec/arch/arm64/image-header.h new file +144 -0
144 lines not on this page · raw message
kexec/arch/arm64/include/arch/options.h new file +39 -0
@@ -0,0 +1,39 @@ +#if !defined(KEXEC_ARCH_ARM64_OPTIONS_H ) +#define KEXEC_ARCH_ARM64_OPTIONS_H + +#define OPT_APPEND ((OPT_MAX)+0) +#define OPT_DTB ((OPT_MAX)+1) +#define OPT_INITRD ((OPT_MAX)+2) +#define OPT_REUSE_CMDLINE ((OPT_MAX)+3) +#define OPT_ARCH_MAX ((OPT_MAX)+4) + +#define KEXEC_ARCH_OPTIONS \ + KEXEC_OPTIONS \ + { "append", 1, NULL, OPT_APPEND }, \ + { "command-line", 1, NULL, OPT_APPEND }, \ + { "dtb", 1, NULL, OPT_DTB }, \ + { "initrd", 1, NULL, OPT_INITRD }, \ + { "ramdisk", 1, NULL, OPT_INITRD }, \ + { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \ + +#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR/* Only accept long arch options. */ +#define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS +#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR + +static const char arm64_opts_usage[] __attribute__ ((unused)) = +" --append=STRING Set the kernel command line to STRING.\n" +" --command-line=STRING Set the kernel command line to STRING.\n" +" --dtb=FILE Use FILE as the device tree blob.\n" +" --initrd=FILE Use FILE as the kernel initial ramdisk.\n" +" --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n" +" --reuse-cmdline Use kernel command line from running system.\n" ; + +struct arm64_opts { +const char *command_line; +const char *dtb; +const char *initrd; +}; + +extern struct arm64_opts arm64_opts; + +#endif
kexec/arch/arm64/kexec-arm64.c new file +705 -0
705 lines not on this page · raw message
kexec/arch/arm64/kexec-arm64.h new file +70 -0
70 lines not on this page · raw message
kexec/arch/arm64/kexec-elf-arm64.c new file +132 -0
132 lines not on this page · raw message
kexec/arch/arm64/kexec-image-arm64.c new file +41 -0
41 lines not on this page · raw message
kexec/kexec-syscall.h +6 -2
@@ -39,8 +39,8 @@#ifdef __s390__#define __NR_kexec_load 277#endif -#ifdef __arm__ -#define __NR_kexec_load __NR_SYSCALL_BASE + 347 +#if defined(__arm__) || defined(__arm64__) +#define __NR_kexec_load __NR_SYSCALL_BASE + 347#endif #if defined(__mips__)#define __NR_kexec_load 4311
@@ -108,6 +108,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,#define KEXEC_ARCH_PPC64 (21 << 16)#define KEXEC_ARCH_IA_64 (50 << 16)#define KEXEC_ARCH_ARM (40 << 16) +#define KEXEC_ARCH_ARM64 (183 << 16)#define KEXEC_ARCH_S390 (22 << 16)#define KEXEC_ARCH_SH (42 << 16)#define KEXEC_ARCH_MIPS_LE (10 << 16)
@@ -153,5 +154,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,#ifdef __m68k__#define KEXEC_ARCH_NATIVE KEXEC_ARCH_68K#endif +#if defined(__arm64__) +#define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM64 +#endif #endif /* KEXEC_SYSCALL_H */
purgatory/Makefile +1 -0
@@ -19,6 +19,7 @@ dist += purgatory/Makefile $(PURGATORY_SRCS) \ include $(srcdir)/purgatory/arch/alpha/Makefile include $(srcdir)/purgatory/arch/arm/Makefile +include $(srcdir)/purgatory/arch/arm64/Makefile include $(srcdir)/purgatory/arch/i386/Makefile include $(srcdir)/purgatory/arch/ia64/Makefile include $(srcdir)/purgatory/arch/mips/Makefile
purgatory/arch/arm64/Makefile new file +18 -0
@@ -0,0 +1,18 @@ + +arm64_PURGATORY_EXTRA_CFLAGS = \ + -mcmodel=large \ + -fno-stack-protector \ + -fno-asynchronous-unwind-tables \ + -Wundef \ + -Werror-implicit-function-declaration \ + -Wdeclaration-after-statement \ + -Werror=implicit-int \ + -Werror=strict-prototypes + +arm64_PURGATORY_SRCS += \ + purgatory/arch/arm64/entry.S \ + purgatory/arch/arm64/purgatory-arm64.c + +dist += \ + $(arm64_PURGATORY_SRCS) \ + purgatory/arch/arm64/Makefile
purgatory/arch/arm64/entry.S new file +51 -0
52 lines not on this page · raw message
purgatory/arch/arm64/purgatory-arm64.c new file +19 -0
@@ -0,0 +1,19 @@ +/* +* ARM64 purgatory. +*/ + +#include <stdint.h> +#include <purgatory.h> + +void putchar (int ch) +{ +/* Nothing for now */ +} + +void post_verification_setup_arch (void ) +{ +} + +void setup_arch (void ) +{ +}
Signature · 8 lines
2.5.0 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec
Re: [PATCH v3 2/3] arm64: Add arm64 kexec support
In reply to Geoff LevandHi Geoff,
Quoted 14 lines · Geoff Levand
Add kexec reboot support for ARM64 platforms.
Signed-off-by Geoff Levand <[email protected]>---
kexec/arch/arm64/kexec-elf-arm64.c new file +9
-0+ + arm64_mem.page_offset = ehdr.e_entry - arm64_mem.text_offset; + +dbgprintf ("%s: e_entry: %016llx -> %016lx\n" , __func__, + ehdr.e_entry, +virt_to_phys (ehdr.e_entry)); +dbgprintf ("%s: p_vaddr: %016llx -> %016lx\n" , __func__, + phdr->p_vaddr, +virt_to_phys (phdr->p_vaddr));
kexec/arch/arm64/kexec-elf-arm64.c line 99
Quoted 10 lines
kexec/arch/arm64/kexec-elf-arm64.c new file +10
-0+dbgprintf ("%s: header_offset: %016lx\n" , __func__, + header_offset); +dbgprintf ("%s: text_offset: %016lx\n" , __func__, + arm64_mem.text_offset); +dbgprintf ("%s: image_size: %016lx\n" , __func__, + arm64_mem.image_size); +dbgprintf ("%s: phys_offset: %016lx\n" , __func__, + arm64_mem.phys_offset); +dbgprintf ("%s: page_offset: %016lx\n" , __func__, + arm64_mem.page_offset);
Although it works on mustang, I would like to understand few things:
This is what is being printed by kexec-tools:
elf_arm64_load: e_entry: fffffc0008080000 -> 0000004000080000elf_arm64_load: p_vaddr: fffffc0008080000 -> 0000004000080000elf_arm64_load: header_offset: 0000000000000000elf_arm64_load: text_offset: 0000000000080000elf_arm64_load: image_size: 00000000013a0000elf_arm64_load: phys_offset: 0000004000000000elf_arm64_load: page_offset: fffffc0008000000
kernel is having 42 VA Bits, so a debug print in kernel says that PAGE_OFFSET=fffffe0000000000. Notice the difference between the values calculated by kernel and kexec-tools. Isn't it confusing? I think kexec-tools page_offset is text_page_offset and not the one which kernel uses. So, probably we can rename it accordingly. Otherwise, we may sync kexec-tools's virt_to_phys() and vice-versa definitions with that of kernel definitions.
In my case, kernel has kimage_voffset=fffffbc008000000. So kernel translate virtual address fffffc0008080000 as fffffc0008080000 - fffffbc008000000 = 0000004000080000 which is matching to the one calculated by kexec-tools (for e_entry).
~Pratyush
Re: [PATCH v3 2/3] arm64: Add arm64 kexec support
Quoted 10 lines · Pratyush Anand
This is what is being printed by kexec-tools:
elf_arm64_load:e_entry:fffffc0008080000-> 0000004000080000elf_arm64_load:p_vaddr:fffffc0008080000-> 0000004000080000elf_arm64_load:header_offset: 0000000000000000elf_arm64_load:text_offset: 0000000000080000elf_arm64_load:image_size:00000000013a0000elf_arm64_load:phys_offset: 0000004000000000elf_arm64_load:page_offset:fffffc0008000000
Quoted 3 lines
kernel is having 42 VA Bits, so a debug print in kernel says that PAGE_OFFSET=fffffe0000000000. Notice the difference between the values calculated by kernel and kexec-tools. Isn't it confusing?
I renamed page_offset to vp_offset.
-Geoff
_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec
PATCH v3 3/3 arm64: Add support for binary image files
In reply to Geoff LevandFrom: Pratyush Anand <[email protected]>
--- kexec/arch/arm64/kexec-image-arm64.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-)
kexec/arch/arm64/kexec-image-arm64.c +25 -6
@@ -24,21 +24,40 @@ int image_arm64_probe(const char *kernel_buf, off_t kernel_size)return -1 ; } -fprintf (stderr,"kexec: ARM64 binary image files are currently NOT SUPPORTED.\n" ); - -return -1 ; +return 0 ; }int image_arm64_load (int argc,char **argv,const char *kernel_buf,off_t kernel_size,struct kexec_info *info) { -return -EFAILED ; +const struct arm64_image_header *h; +unsigned long image_base; + + h = (const struct arm64_image_header *)(kernel_buf); + +if (arm64_process_image_header (h)) +return -EINVAL ; + +dbgprintf ("%s: text_offset: %016lx\n" , __func__, + arm64_mem.text_offset); +dbgprintf ("%s: image_size: %016lx\n" , __func__, + arm64_mem.image_size); +dbgprintf ("%s: phys_offset: %016lx\n" , __func__, + arm64_mem.phys_offset); +dbgprintf ("%s: PE format: %s\n" , __func__, + (arm64_header_check_pe_sig (h) ?"yes" :"no" )); + + image_base =get_phys_offset () + arm64_mem.text_offset; + +add_segment_phys_virt (info, kernel_buf, kernel_size, image_base, + arm64_mem.image_size,0 ); + +return arm64_load_other_segments (info, image_base); }void image_arm64_usage (void ) {printf (" An ARM64 binary image, compressed or not, big or little endian.\n" -" Typically an Image, Image.gz or Image.lzma file.\n" -" This file type is currently NOT SUPPORTED.\n\n" ); +" Typically an Image, Image.gz or Image.lzma file.\n\n" ); }
Signature · 7 lines
2.5.0 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec