Re: [PATCH] kexec-tools: add support for PARISC architecture

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 19.09.19 20:26, Sven Schnelle wrote:
> This patch adds support for the parisc Architecture. kexec support
> for parisc is included with linux-5.4.
>
> Signed-off-by: Sven Schnelle <svens@xxxxxxxxxxxxxx>

Tested-by: Helge Deller <deller@xxxxxx>

> ---
>  configure.ac                           |   3 +
>  kexec/Makefile                         |   1 +
>  kexec/arch/hppa/Makefile               |  13 ++
>  kexec/arch/hppa/include/arch/options.h |  32 +++++
>  kexec/arch/hppa/kexec-elf-hppa.c       | 159 +++++++++++++++++++++++++
>  kexec/arch/hppa/kexec-elf-rel-hppa.c   |  37 ++++++
>  kexec/arch/hppa/kexec-hppa.c           | 148 +++++++++++++++++++++++
>  kexec/arch/hppa/kexec-hppa.h           |   9 ++
>  kexec/kexec-syscall.h                  |   4 +
>  9 files changed, 406 insertions(+)
>  create mode 100644 kexec/arch/hppa/Makefile
>  create mode 100644 kexec/arch/hppa/include/arch/options.h
>  create mode 100644 kexec/arch/hppa/kexec-elf-hppa.c
>  create mode 100644 kexec/arch/hppa/kexec-elf-rel-hppa.c
>  create mode 100644 kexec/arch/hppa/kexec-hppa.c
>  create mode 100644 kexec/arch/hppa/kexec-hppa.h
>
> diff --git a/configure.ac b/configure.ac
> index 8474f7d..f025823 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -55,6 +55,9 @@ case $target_cpu in
>  	ia64|x86_64|alpha|m68k )
>  		ARCH="$target_cpu"
>  		;;
> +	hppa*)
> +		ARCH="hppa"
> +		;;
>  	* )
>  		AC_MSG_ERROR([unsupported architecture $target_cpu])
>  		;;
> diff --git a/kexec/Makefile b/kexec/Makefile
> index 4db84d8..8e3e9ea 100644
> --- a/kexec/Makefile
> +++ b/kexec/Makefile
> @@ -92,6 +92,7 @@ include $(srcdir)/kexec/arch/ppc64/Makefile
>  include $(srcdir)/kexec/arch/s390/Makefile
>  include $(srcdir)/kexec/arch/sh/Makefile
>  include $(srcdir)/kexec/arch/x86_64/Makefile
> +include $(srcdir)/kexec/arch/hppa/Makefile
>
>  KEXEC_SRCS += $($(ARCH)_KEXEC_SRCS)
>
> diff --git a/kexec/arch/hppa/Makefile b/kexec/arch/hppa/Makefile
> new file mode 100644
> index 0000000..e98f6da
> --- /dev/null
> +++ b/kexec/arch/hppa/Makefile
> @@ -0,0 +1,13 @@
> +#
> +# kexec hppa (linux booting linux)
> +#
> +hppa_KEXEC_SRCS =  kexec/arch/hppa/kexec-hppa.c
> +hppa_KEXEC_SRCS += kexec/arch/hppa/kexec-elf-hppa.c
> +hppa_KEXEC_SRCS += kexec/arch/hppa/kexec-elf-rel-hppa.c
> +
> +hppa_ADD_SEGMENT =
> +hppa_VIRT_TO_PHYS =
> +
> +dist += kexec/arch/hppa/Makefile $(hppa_KEXEC_SRCS)			\
> +	kexec/arch/hppa/kexec-hppa.h					\
> +	kexec/arch/hppa/include/arch/options.h
> diff --git a/kexec/arch/hppa/include/arch/options.h b/kexec/arch/hppa/include/arch/options.h
> new file mode 100644
> index 0000000..a936140
> --- /dev/null
> +++ b/kexec/arch/hppa/include/arch/options.h
> @@ -0,0 +1,32 @@
> +#ifndef KEXEC_ARCH_HPPA_OPTIONS_H
> +#define KEXEC_ARCH_HPPA_OPTIONS_H
> +
> +#define OPT_ARCH_MAX   (OPT_MAX+0)
> +
> +#define KEXEC_ARCH_OPTIONS \
> +	KEXEC_OPTIONS
> +
> +#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
> +
> +#define KEXEC_ALL_OPTIONS \
> +	KEXEC_ARCH_OPTIONS \
> +	{ "command-line",	1, 0, OPT_APPEND },		\
> +	{ "reuse-cmdline",	0, 0, OPT_REUSE_CMDLINE },	\
> +	{ "append",		1, 0, OPT_APPEND },		\
> +	{ "initrd",		1, 0, OPT_RAMDISK },		\
> +	{ "ramdisk",		1, 0, OPT_RAMDISK },
> +
> +
> +#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR "a:r:s:"
> +
> +/* See the other architectures for details of these; HPPA has no
> + * loader-specific options yet.
> + */
> +#define OPT_ARCH_MAX       (OPT_MAX+0)
> +
> +#define OPT_APPEND		(OPT_ARCH_MAX+0)
> +#define OPT_REUSE_CMDLINE	(OPT_ARCH_MAX+1)
> +#define OPT_RAMDISK		(OPT_ARCH_MAX+2)
> +
> +#define MAX_MEMORY_RANGES 16
> +#endif /* KEXEC_ARCH_HPPA_OPTIONS_H */
> diff --git a/kexec/arch/hppa/kexec-elf-hppa.c b/kexec/arch/hppa/kexec-elf-hppa.c
> new file mode 100644
> index 0000000..d3ef0e9
> --- /dev/null
> +++ b/kexec/arch/hppa/kexec-elf-hppa.c
> @@ -0,0 +1,159 @@
> +/*
> + * kexec-elf-hppa.c - kexec Elf loader for hppa
> + *
> + * Copyright (c) 2019 Sven Schnelle <svens@xxxxxxxxxxxxxx>
> + *
> + * This source code is licensed under the GNU General Public License,
> + * Version 2.  See the file COPYING for more details.
> +*/
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <getopt.h>
> +#include <elf.h>
> +#include <boot/elf_boot.h>
> +#include <ip_checksum.h>
> +#include "../../kexec.h"
> +#include "../../kexec-elf.h"
> +#include "../../kexec-syscall.h"
> +#include "kexec-hppa.h"
> +#include <arch/options.h>
> +
> +#define PAGE_SIZE	4096
> +
> +extern unsigned long phys_offset;
> +
> +int elf_hppa_probe(const char *buf, off_t len)
> +{
> +	struct mem_ehdr ehdr;
> +	int result;
> +	result = build_elf_exec_info(buf, len, &ehdr, 0);
> +	if (result < 0)
> +		goto out;
> +
> +	phys_offset = ehdr.e_entry & 0xf0000000;
> +	/* Verify the architecuture specific bits */
> +	if (ehdr.e_machine != EM_PARISC) {
> +		/* for a different architecture */
> +		fprintf(stderr, "Not for this architecture.\n");
> +		result = -1;
> +		goto out;
> +	}
> +	result = 0;
> + out:
> +	free_elf_info(&ehdr);
> +	return result;
> +}
> +
> +void elf_hppa_usage(void)
> +{
> +	printf("    --command-line=STRING Set the kernel command line to STRING\n"
> +	       "    --append=STRING       Set the kernel command line to STRING\n"
> +	       "    --reuse-cmdline       Use kernel command line from running system.\n"
> +	       "    --ramdisk=FILE        Use FILE as the kernel's initial ramdisk.\n"
> +	       "    --initrd=FILE         Use FILE as the kernel's initial ramdisk.\n"
> +	       );
> +}
> +
> +int elf_hppa_load(int argc, char **argv, const char *buf, off_t len,
> +	struct kexec_info *info)
> +{
> +	struct mem_ehdr ehdr;
> +	char *cmdline = NULL, *ramdisk = NULL;
> +	int opt, result, i;
> +	unsigned long ramdisk_addr = 0;
> +	off_t ramdisk_size = 0;
> +
> +	static const struct option options[] = {
> +		KEXEC_ALL_OPTIONS
> +		{ 0,                    0, NULL, 0 },
> +	};
> +
> +	static const char short_options[] = KEXEC_ALL_OPT_STR "d";
> +
> +	while ((opt = getopt_long(argc, argv, short_options, options, 0)) !=
> +		-1) {
> +		switch (opt) {
> +		default:
> +			/* Ignore core options */
> +			if (opt < OPT_ARCH_MAX)
> +				break;
> +		case OPT_APPEND:
> +			cmdline = strdup(optarg);
> +			break;
> +		case OPT_REUSE_CMDLINE:
> +			cmdline = get_command_line();
> +			break;
> +		case OPT_RAMDISK:
> +			ramdisk = optarg;
> +			break;
> +		}
> +	}
> +
> +	if (info->file_mode) {
> +		if (cmdline) {
> +			info->command_line = cmdline;
> +			info->command_line_len = strlen(cmdline) + 1;
> +		}
> +
> +		if (ramdisk) {
> +			info->initrd_fd = open(ramdisk, O_RDONLY);
> +			if (info->initrd_fd == -1) {
> +				fprintf(stderr, "Could not open initrd file "
> +					"%s:%s\n", ramdisk, strerror(errno));
> +				return -1;
> +			}
> +		}
> +		return 0;
> +	}
> +
> +	result = build_elf_exec_info(buf, len, &ehdr, 0);
> +	if (result < 0)
> +		die("ELF exec parse failed\n");
> +
> +	/* Fixup PT_LOAD segments that include the ELF header (offset zero) */
> +	for (i = 0; i < ehdr.e_phnum; i++) {
> +		struct mem_phdr *phdr;
> +		phdr = &ehdr.e_phdr[i];
> +		if (phdr->p_type != PT_LOAD || phdr->p_offset)
> +			continue;
> +
> +		dbgprintf("Removing ELF header from segment %d\n", i);
> +		phdr->p_paddr += PAGE_SIZE;
> +		phdr->p_vaddr += PAGE_SIZE;
> +		phdr->p_filesz -= PAGE_SIZE;
> +		phdr->p_memsz -= PAGE_SIZE;
> +		phdr->p_offset += PAGE_SIZE;
> +		phdr->p_data += PAGE_SIZE;
> +	}
> +
> +	/* Load the ELF data */
> +	result = elf_exec_load(&ehdr, info);
> +	if (result < 0)
> +		die("ELF exec load failed\n");
> +
> +	info->entry = (void *)virt_to_phys(ehdr.e_entry);
> +
> +
> +	/* Load ramdisk */
> +	if (ramdisk) {
> +		void *initrd = slurp_decompress_file(ramdisk, &ramdisk_size);
> +		/* Store ramdisk at top of first memory chunk */
> +		ramdisk_addr = _ALIGN_DOWN(info->memory_range[0].end -
> +					   ramdisk_size + 1, PAGE_SIZE);
> +		if (!buf)
> +			die("Ramdisk load failed\n");
> +		add_buffer(info, initrd, ramdisk_size, ramdisk_size,
> +			   PAGE_SIZE, ramdisk_addr, info->memory_range[0].end,
> +			   1);
> +	}
> +
> +	return 0;
> +}
> diff --git a/kexec/arch/hppa/kexec-elf-rel-hppa.c b/kexec/arch/hppa/kexec-elf-rel-hppa.c
> new file mode 100644
> index 0000000..661b67b
> --- /dev/null
> +++ b/kexec/arch/hppa/kexec-elf-rel-hppa.c
> @@ -0,0 +1,37 @@
> +/*
> + * kexec-elf-rel-hppa.c - kexec Elf relocation routines
> + *
> + * Copyright (C) 2019 Sven Schnelle <svens@xxxxxxxxxxxxxx>
> + *
> + * This source code is licensed under the GNU General Public License,
> + * Version 2.  See the file COPYING for more details.
> +*/
> +
> +#include <stdio.h>
> +#include <elf.h>
> +#include "../../kexec.h"
> +#include "../../kexec-elf.h"
> +
> +int machine_verify_elf_rel(struct mem_ehdr *ehdr)
> +{
> +	if (ehdr->ei_data != ELFDATA2MSB)
> +		return 0;
> +	if (ehdr->e_machine != EM_PARISC)
> +		return 0;
> +	return 1;
> +}
> +
> +void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr),
> +			   struct mem_sym *UNUSED(sym),
> +			   unsigned long r_type,
> +			   void *UNUSED(location),
> +			   unsigned long UNUSED(address),
> +			   unsigned long UNUSED(value))
> +{
> +	switch (r_type) {
> +	default:
> +		die("Unknown rela relocation: %lu\n", r_type);
> +		break;
> +	}
> +	return;
> +}
> diff --git a/kexec/arch/hppa/kexec-hppa.c b/kexec/arch/hppa/kexec-hppa.c
> new file mode 100644
> index 0000000..77c9739
> --- /dev/null
> +++ b/kexec/arch/hppa/kexec-hppa.c
> @@ -0,0 +1,148 @@
> +/*
> + * kexec-hppa.c - kexec for hppa
> + *
> + * Copyright (C) 2019 Sven Schnelle <svens@xxxxxxxxxxxxxx>
> + *
> + * This source code is licensed under the GNU General Public License,
> + * Version 2.  See the file COPYING for more details.
> + */
> +
> +#include <stddef.h>
> +#include <stdio.h>
> +#include <errno.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <getopt.h>
> +#include "../../kexec.h"
> +#include "../../kexec-syscall.h"
> +#include "kexec-hppa.h"
> +#include <arch/options.h>
> +
> +#define SYSTEM_RAM "System RAM\n"
> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
> +
> +static struct memory_range memory_range[MAX_MEMORY_RANGES];
> +unsigned long phys_offset;
> +
> +/* Return a sorted list of available memory ranges. */
> +int get_memory_ranges(struct memory_range **range, int *ranges,
> +		unsigned long UNUSED(kexec_flags))
> +{
> +	const char *iomem = proc_iomem();
> +	int memory_ranges = 0;
> +	char line[512];
> +	FILE *fp;
> +
> +	fp = fopen(iomem, "r");
> +
> +	if (!fp) {
> +		fprintf(stderr, "Cannot open %s: %s\n",
> +			iomem, strerror(errno));
> +		return -1;
> +	}
> +
> +	while(fgets(line, sizeof(line), fp) != 0) {
> +		unsigned long long start, end;
> +		char *str;
> +		int type;
> +		int consumed;
> +		int count;
> +
> +
> +		count = sscanf(line, "%llx-%llx : %n", &start, &end, &consumed);
> +
> +		if (count != 2)
> +			continue;
> +
> +		str = line + consumed;
> +
> +		if (memcmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) == 0) {
> +			type = RANGE_RAM;
> +		} else if (memcmp(str, "reserved\n", 9) == 0) {
> +			type = RANGE_RESERVED;
> +		} else {
> +			continue;
> +		}
> +
> +		memory_range[memory_ranges].start = start;
> +		memory_range[memory_ranges].end = end;
> +		memory_range[memory_ranges].type = type;
> +		if (++memory_ranges >= MAX_MEMORY_RANGES)
> +			break;
> +	}
> +	fclose(fp);
> +	*range = memory_range;
> +	*ranges = memory_ranges;
> +
> +	dbgprint_mem_range("MEMORY RANGES", *range, *ranges);
> +	return 0;
> +}
> +
> +struct file_type file_type[] = {
> +	{"elf-hppa", elf_hppa_probe, elf_hppa_load, elf_hppa_usage},
> +};
> +int file_types = ARRAY_SIZE(file_type);
> +
> +void arch_usage(void)
> +{
> +}
> +
> +int arch_process_options(int argc, char **argv)
> +{
> +	static const struct option options[] = {
> +		KEXEC_ALL_OPTIONS
> +		{ 0,			0, NULL, 0 },
> +	};
> +	static const char short_options[] = KEXEC_ALL_OPT_STR;
> +	int opt;
> +
> +	opterr = 0; /* Don't complain about unrecognized options here */
> +	while ((opt = getopt_long(argc, argv, short_options, options, 0)) !=
> +		-1) {
> +		switch (opt) {
> +		default:
> +			break;
> +		}
> +	}
> +	/* Reset getopt for the next pass; called in other source modules */
> +	opterr = 1;
> +	optind = 1;
> +	return 0;
> +}
> +
> +const struct arch_map_entry arches[] = {
> +	{ "parisc64", KEXEC_ARCH_HPPA },
> +	{ "parisc", KEXEC_ARCH_HPPA },
> +	{ NULL, 0 },
> +};
> +
> +int arch_compat_trampoline(struct kexec_info *UNUSED(info))
> +{
> +	return 0;
> +}
> +
> +void arch_update_purgatory(struct kexec_info *UNUSED(info))
> +{
> +}
> +
> +int is_crashkernel_mem_reserved(void)
> +{
> +	return 0;
> +}
> +
> +int get_crash_kernel_load_range(uint64_t *start, uint64_t *end)
> +{
> +	/* Crash kernel region size is not exposed by the system */
> +	return -1;
> +}
> +
> +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);
> +}
> +
> +unsigned long virt_to_phys(unsigned long addr)
> +{
> +	return addr - phys_offset;
> +}
> diff --git a/kexec/arch/hppa/kexec-hppa.h b/kexec/arch/hppa/kexec-hppa.h
> new file mode 100644
> index 0000000..485e5b6
> --- /dev/null
> +++ b/kexec/arch/hppa/kexec-hppa.h
> @@ -0,0 +1,9 @@
> +#ifndef KEXEC_HPPA_H
> +#define KEXEC_HPPA_H
> +
> +int elf_hppa_probe(const char *buf, off_t len);
> +int elf_hppa_load(int argc, char **argv, const char *buf, off_t len,
> +		  struct kexec_info *info);
> +void elf_hppa_usage(void);
> +
> +#endif /* KEXEC_HPPA_H */
> diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h
> index 92d51d3..bea29d4 100644
> --- a/kexec/kexec-syscall.h
> +++ b/kexec/kexec-syscall.h
> @@ -74,6 +74,9 @@
>  #ifdef __aarch64__
>  #define __NR_kexec_file_load	294
>  #endif
> +#ifdef __hppa__
> +#define __NR_kexec_file_load	355
> +#endif
>
>  #ifndef __NR_kexec_file_load
>  /* system call not available for the arch */
> @@ -119,6 +122,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,
>  #define KEXEC_ARCH_DEFAULT ( 0 << 16)
>  #define KEXEC_ARCH_386     ( 3 << 16)
>  #define KEXEC_ARCH_68K     ( 4 << 16)
> +#define KEXEC_ARCH_HPPA    (15 << 16)
>  #define KEXEC_ARCH_X86_64  (62 << 16)
>  #define KEXEC_ARCH_PPC     (20 << 16)
>  #define KEXEC_ARCH_PPC64   (21 << 16)
>





[Index of Archives]     [Linux SoC]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux