public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/riscv:master commit in: sys-apps/kexec-tools/, sys-apps/kexec-tools/files/
@ 2022-07-02 11:44 Yixun Lan
  0 siblings, 0 replies; 2+ messages in thread
From: Yixun Lan @ 2022-07-02 11:44 UTC (permalink / raw
  To: gentoo-commits

commit:     31108ac2c9aa23918f46ff3f56e3084d0bb725f2
Author:     Yixun Lan <dlan <AT> gentoo <DOT> org>
AuthorDate: Sat Jul  2 09:35:25 2022 +0000
Commit:     Yixun Lan <dlan <AT> gentoo <DOT> org>
CommitDate: Sat Jul  2 09:36:03 2022 +0000
URL:        https://gitweb.gentoo.org/proj/riscv.git/commit/?id=31108ac2

sys-apps/kexec-tools: add riscv support

Signed-off-by: Yixun Lan <dlan <AT> gentoo.org>

 .../files/kexec-tools-2.0.24-riscv.patch           | 1513 ++++++++++++++++++++
 sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild     |    9 +-
 2 files changed, 1516 insertions(+), 6 deletions(-)

diff --git a/sys-apps/kexec-tools/files/kexec-tools-2.0.24-riscv.patch b/sys-apps/kexec-tools/files/kexec-tools-2.0.24-riscv.patch
new file mode 100644
index 0000000..1fab497
--- /dev/null
+++ b/sys-apps/kexec-tools/files/kexec-tools-2.0.24-riscv.patch
@@ -0,0 +1,1513 @@
+From 6975082921e577ed5034e56010d2b433aeaf6907 Mon Sep 17 00:00:00 2001
+From: Nick Kossifidis <mick@ics.forth.gr>
+Date: Tue, 5 Oct 2021 15:01:19 +0300
+Subject: [PATCH] RISC-V: Add support for riscv kexec/kdump on kexec-tools
+
+This patch adds support for loading the ELF kernel image. It parses
+the current/provided device tree to determine the system's memory
+layout, and /proc/iomem for the various kernel segments.
+
+Tested on Qemu's rv64 virt machine.
+
+Signed-off-by: Nick Kossifidis <mick@ics.forth.gr>
+---
+ configure.ac                            |   3 +
+ include/elf.h                           |   3 +-
+ kexec/Makefile                          |   1 +
+ kexec/arch/riscv/Makefile               |  35 ++
+ kexec/arch/riscv/crashdump-riscv.c      | 140 ++++++++
+ kexec/arch/riscv/include/arch/options.h |  43 +++
+ kexec/arch/riscv/kexec-elf-riscv.c      | 255 ++++++++++++++
+ kexec/arch/riscv/kexec-riscv.c          | 364 +++++++++++++++++++
+ kexec/arch/riscv/kexec-riscv.h          |  32 ++
+ kexec/dt-ops.c                          | 442 +++++++++++++++++++++++-
+ kexec/dt-ops.h                          |   7 +
+ kexec/kexec-syscall.h                   |   4 +
+ purgatory/Makefile                      |   1 +
+ purgatory/arch/riscv/Makefile           |   7 +
+ 14 files changed, 1335 insertions(+), 2 deletions(-)
+ create mode 100644 kexec/arch/riscv/Makefile
+ create mode 100644 kexec/arch/riscv/crashdump-riscv.c
+ create mode 100644 kexec/arch/riscv/include/arch/options.h
+ create mode 100644 kexec/arch/riscv/kexec-elf-riscv.c
+ create mode 100644 kexec/arch/riscv/kexec-riscv.c
+ create mode 100644 kexec/arch/riscv/kexec-riscv.h
+ create mode 100644 purgatory/arch/riscv/Makefile
+
+diff --git a/configure.ac b/configure.ac
+index cf8e8a2..d21552c 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -58,6 +58,9 @@ case $target_cpu in
+ 	hppa*)
+ 		ARCH="hppa"
+ 		;;
++	riscv32|riscv64 )
++		ARCH="riscv"
++		;;
+ 	* )
+ 		AC_MSG_ERROR([unsupported architecture $target_cpu])
+ 		;;
+diff --git a/include/elf.h b/include/elf.h
+index b7677a2..123f167 100644
+--- a/include/elf.h
++++ b/include/elf.h
+@@ -259,7 +259,8 @@ typedef struct
+ #define EM_ARC_A5	93		/* ARC Cores Tangent-A5 */
+ #define EM_XTENSA	94		/* Tensilica Xtensa Architecture */
+ #define EM_AARCH64	183		/* ARM AARCH64 */
+-#define EM_NUM		184
++#define EM_RISCV	243		/* RISC-V */
++#define EM_NUM		244
+ 
+ /* If it is necessary to assign new unofficial EM_* values, please
+    pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+diff --git a/kexec/Makefile b/kexec/Makefile
+index e69e309..ca17831 100644
+--- a/kexec/Makefile
++++ b/kexec/Makefile
+@@ -88,6 +88,7 @@ include $(srcdir)/kexec/arch/mips/Makefile
+ include $(srcdir)/kexec/arch/cris/Makefile
+ include $(srcdir)/kexec/arch/ppc/Makefile
+ include $(srcdir)/kexec/arch/ppc64/Makefile
++include $(srcdir)/kexec/arch/riscv/Makefile
+ include $(srcdir)/kexec/arch/s390/Makefile
+ include $(srcdir)/kexec/arch/sh/Makefile
+ include $(srcdir)/kexec/arch/x86_64/Makefile
+diff --git a/kexec/arch/riscv/Makefile b/kexec/arch/riscv/Makefile
+new file mode 100644
+index 0000000..f26cc90
+--- /dev/null
++++ b/kexec/arch/riscv/Makefile
+@@ -0,0 +1,35 @@
++#
++# kexec riscv
++#
++riscv_KEXEC_SRCS =  kexec/arch/riscv/kexec-riscv.c
++riscv_KEXEC_SRCS += kexec/arch/riscv/kexec-elf-riscv.c
++riscv_KEXEC_SRCS += kexec/arch/riscv/crashdump-riscv.c
++
++riscv_MEM_REGIONS = kexec/mem_regions.c
++
++riscv_DT_OPS += kexec/dt-ops.c
++
++riscv_ARCH_REUSE_INITRD =
++
++riscv_CPPFLAGS += -I $(srcdir)/kexec/
++
++dist += kexec/arch/riscv/Makefile $(riscv_KEXEC_SRCS)			\
++	kexec/arch/riscv/kexec-riscv.h					\
++	kexec/arch/riscv/include/arch/options.h
++
++ifdef HAVE_LIBFDT
++
++LIBS += -lfdt
++
++else
++
++include $(srcdir)/kexec/libfdt/Makefile.libfdt
++
++libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%)
++
++riscv_CPPFLAGS += -I$(srcdir)/kexec/libfdt
++
++riscv_KEXEC_SRCS += $(libfdt_SRCS)
++
++endif
++
+diff --git a/kexec/arch/riscv/crashdump-riscv.c b/kexec/arch/riscv/crashdump-riscv.c
+new file mode 100644
+index 0000000..7fc041e
+--- /dev/null
++++ b/kexec/arch/riscv/crashdump-riscv.c
+@@ -0,0 +1,140 @@
++#include <errno.h>
++#include <linux/elf.h>
++#include <unistd.h>
++
++#include "kexec.h"
++#include "crashdump.h"
++#include "kexec-elf.h"
++#include "mem_regions.h"
++
++static struct crash_elf_info elf_info = {
++#if __riscv_xlen == 64
++	.class		= ELFCLASS64,
++#else
++	.class		= ELFCLASS32,
++#endif
++	.data		= ELFDATA2LSB,
++	.machine	= EM_RISCV,
++};
++
++static struct memory_ranges crash_mem_ranges = {0};
++struct memory_range elfcorehdr_mem = {0};
++
++static unsigned long long get_page_offset(struct kexec_info *info)
++{
++	unsigned long long vaddr_off = 0;
++	unsigned long long page_size = sysconf(_SC_PAGESIZE);
++	unsigned long long init_start = get_kernel_sym("_sinittext");
++
++	/*
++	 * Begining of init section is aligned to page size
++	 */
++	vaddr_off = init_start - page_size;
++
++	return vaddr_off;
++}
++
++int load_elfcorehdr(struct kexec_info *info)
++{
++	struct memory_range crashkern_range = {0};
++	struct memory_range *ranges = NULL;
++	unsigned long start = 0;
++	unsigned long end = 0;
++	unsigned long buf_size = 0;
++	unsigned long elfcorehdr_addr = 0;
++	void* buf = NULL;
++	int i = 0;
++	int ret = 0;
++
++	ret = parse_iomem_single("Kernel code\n", &start, NULL);
++	if (ret) {
++		fprintf(stderr, "Cannot determine kernel physical base addr\n");
++		return -EINVAL;
++	}
++	elf_info.kern_paddr_start = start;
++
++	ret = parse_iomem_single("Kernel bss\n", NULL, &end);
++	if (ret) {
++		fprintf(stderr, "Cannot determine kernel physical bss addr\n");
++		return -EINVAL;
++	}
++	elf_info.kern_paddr_start = start;
++	elf_info.kern_size = end - start;
++
++	elf_info.kern_vaddr_start = get_kernel_sym("_text");
++	if (!elf_info.kern_vaddr_start) {
++		elf_info.kern_vaddr_start = UINT64_MAX;
++	}
++
++	elf_info.page_offset = get_page_offset(info);
++	dbgprintf("page_offset:   %016llx\n", elf_info.page_offset);
++
++	ret = parse_iomem_single("Crash kernel\n", &start, &end);
++	if (ret) {
++		fprintf(stderr, "Cannot determine kernel physical bss addr\n");
++		return -EINVAL;
++	}
++	crashkern_range.start = start;
++	crashkern_range.end = end;
++	crashkern_range.type = RANGE_RESERVED;
++
++	ranges = info->memory_range;
++	for (i = 0; i < info->memory_ranges; i++) {
++		ret = mem_regions_alloc_and_add(&crash_mem_ranges,
++						ranges[i].start,
++						ranges[i].end - ranges[i].start,
++						ranges[i].type);
++		if (ret ) {
++			fprintf(stderr, "Could not create crash_mem_ranges\n");
++			return ret;
++		}
++	}
++
++	ret = mem_regions_alloc_and_exclude(&crash_mem_ranges,
++					    &crashkern_range);
++	if (ret) {
++		fprintf(stderr, "Could not exclude crashkern_range\n");
++		return ret;
++	}
++
++#if __riscv_xlen == 64
++	crash_create_elf64_headers(info, &elf_info, crash_mem_ranges.ranges,
++				   crash_mem_ranges.size, &buf, &buf_size,
++				   ELF_CORE_HEADER_ALIGN);
++
++#else
++	crash_create_elf32_headers(info, &elf_info, crash_mem_ranges.ranges,
++				   crash_mem_ranges.size, &buf, &buf_size,
++				   ELF_CORE_HEADER_ALIGN);
++#endif
++
++
++	elfcorehdr_addr = add_buffer_phys_virt(info, buf, buf_size,
++					       buf_size, 0,
++					       crashkern_range.start,
++					       crashkern_range.end,
++					       -1, 0);
++
++	elfcorehdr_mem.start = elfcorehdr_addr;
++	elfcorehdr_mem.end = elfcorehdr_addr + buf_size - 1;
++
++	dbgprintf("%s: elfcorehdr 0x%llx-0x%llx\n", __func__,
++		  elfcorehdr_mem.start, elfcorehdr_mem.end);
++
++	return 0;
++}
++
++int is_crashkernel_mem_reserved(void)
++{
++	uint64_t start = 0;
++	uint64_t end = 0;
++
++	return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ?
++	       (start != end) : 0;
++}
++
++int get_crash_kernel_load_range(uint64_t *start, uint64_t *end)
++{
++	return parse_iomem_single("Crash kernel\n", start, end);
++}
++
+diff --git a/kexec/arch/riscv/include/arch/options.h b/kexec/arch/riscv/include/arch/options.h
+new file mode 100644
+index 0000000..7c24184
+--- /dev/null
++++ b/kexec/arch/riscv/include/arch/options.h
+@@ -0,0 +1,43 @@
++#ifndef KEXEC_ARCH_RISCV_OPTIONS_H
++#define KEXEC_ARCH_RISCV_OPTIONS_H
++
++#define OPT_APPEND		((OPT_MAX)+0)
++#define OPT_DTB			((OPT_MAX)+1)
++#define OPT_INITRD		((OPT_MAX)+2)
++#define OPT_CMDLINE		((OPT_MAX)+3)
++#define OPT_REUSE_CMDLINE	((OPT_MAX)+4)
++#define OPT_ARCH_MAX		((OPT_MAX)+5)
++
++/* Options relevant to the architecture (excluding loader-specific ones),
++ * in this case none:
++ */
++#define KEXEC_ARCH_OPTIONS \
++	KEXEC_OPTIONS \
++	{ "append",		1, 0, OPT_APPEND}, \
++	{ "dtb",		1, 0, OPT_DTB }, \
++	{ "initrd",		1, 0, OPT_INITRD }, \
++	{ "command-line",	1, 0, OPT_CMDLINE}, \
++	{ "reuse-cmdline",	0, NULL, OPT_REUSE_CMDLINE }, \
++
++
++#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
++
++/* The following two #defines list ALL of the options added by all of the
++ * architecture's loaders.
++ * o	main() uses this complete list to scan for its options, ignoring
++ *	arch-specific/loader-specific ones.
++ * o	Then, arch_process_options() uses this complete list to scan for its
++ *	options, ignoring general/loader-specific ones.
++ * o	Then, the file_type[n].load re-scans for options, using
++ *	KEXEC_ARCH_OPTIONS plus its loader-specific options subset.
++ *	Any unrecognised options cause an error here.
++ *
++ * This is done so that main()'s/arch_process_options()'s getopt_long() calls
++ * don't choose a kernel filename from random arguments to options they don't
++ * recognise -- as they now recognise (if not act upon) all possible options.
++ */
++#define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS
++
++#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR
++
++#endif /* KEXEC_ARCH_RISCV_OPTIONS_H */
+diff --git a/kexec/arch/riscv/kexec-elf-riscv.c b/kexec/arch/riscv/kexec-elf-riscv.c
+new file mode 100644
+index 0000000..f3c011c
+--- /dev/null
++++ b/kexec/arch/riscv/kexec-elf-riscv.c
+@@ -0,0 +1,255 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2019 FORTH-ICS/CARV
++ *              Nick Kossifidis <mick@ics.forth.gr>
++ */
++
++#include "kexec.h"
++#include "dt-ops.h"		/* For dtb_set/clear_initrd() */
++#include <elf.h>		/* For ELF header handling */
++#include <errno.h>		/* For EFBIG/EINVAL */
++#include <unistd.h>		/* For getpagesize() */
++#include "kexec-syscall.h"	/* For KEXEC_ON_CRASH */
++#include "kexec-riscv.h"
++
++
++/*********\
++* HELPERS *
++\*********/
++
++/*
++ * Go through the available physical memory regions and
++ * find one that can hold an image of the specified size.
++ * Note: This is called after get_memory_ranges so
++ * info->memory_range[] should be populated. Also note that
++ * memory ranges are sorted, so we'll return the first region
++ * that's big enough for holding the image.
++ */
++static int elf_riscv_find_pbase(struct kexec_info *info, off_t *addr,
++				off_t size)
++{
++	int i = 0;
++	off_t start = 0;
++	off_t end = 0;
++	int ret = 0;
++
++	/*
++	 * If this image is for a crash kernel, use the region
++	 * the primary kernel has already reserved for us.
++	 */
++	if (info->kexec_flags & KEXEC_ON_CRASH) {
++		ret = get_crash_kernel_load_range((uint64_t *) &start,
++						  (uint64_t *) &end);
++		if (!ret) {
++			/*
++			 * Kernel should be aligned to the nearest
++			 * hugepage (2MB for RV64, 4MB for RV32).
++			 */
++#if __riscv_xlen == 64
++			start = _ALIGN_UP(start, 0x200000);
++#else
++			start = _ALIGN_UP(start, 0x400000);
++#endif
++			if (end > start && ((end - start) >= size)) {
++				*addr = start;
++				return 0;
++			}
++
++			return -EFBIG;
++		} else
++			return ENOCRASHKERNEL;
++	}
++
++	for (i = 0; i < info->memory_ranges; i++) {
++		if (info->memory_range[i].type != RANGE_RAM)
++			continue;
++
++		start = info->memory_range[i].start;
++		end = info->memory_range[i].end;
++
++#if __riscv_xlen == 64
++		start = _ALIGN_UP(start, 0x200000);
++#else
++		start = _ALIGN_UP(start, 0x400000);
++#endif
++
++		if (end > start && ((end - start) >= size)) {
++			*addr = start;
++			return 0;
++		}
++	}
++
++	return -EFBIG;
++}
++
++/**************\
++* ENTRY POINTS *
++\**************/
++
++int elf_riscv_probe(const char *buf, off_t len)
++{
++	struct mem_ehdr ehdr = {0};
++	int ret = 0;
++
++	ret = build_elf_exec_info(buf, len, &ehdr, 0);
++	if (ret < 0)
++		goto cleanup;
++
++	if (ehdr.e_machine != EM_RISCV) {
++		fprintf(stderr, "Not for this architecture.\n");
++		ret = -EINVAL;
++		goto cleanup;
++	}
++
++	ret = 0;
++
++ cleanup:
++	free_elf_info(&ehdr);
++	return ret;
++}
++
++void elf_riscv_usage(void)
++{
++}
++
++int elf_riscv_load(int argc, char **argv, const char *buf, off_t len,
++		   struct kexec_info *info)
++{
++	struct mem_ehdr ehdr = {0};
++	struct mem_phdr *phdr = NULL;
++	off_t new_base_addr = 0;
++	off_t kernel_size = 0;
++	off_t page_size = getpagesize();
++	off_t max_addr = 0;
++	off_t old_base_addr = 0;
++	off_t old_start_addr = 0;
++	int i = 0;
++	int ret = 0;
++
++	if (info->file_mode) {
++		fprintf(stderr, "kexec_file not supported on this "
++				"architecture\n");
++		return -EINVAL;
++	}
++
++	/* Parse the ELF file */
++	ret = build_elf_exec_info(buf, len, &ehdr, 0);
++	if (ret < 0) {
++		fprintf(stderr, "ELF exec parse failed\n");
++		return -EINVAL;
++	}
++
++	max_addr = elf_max_addr(&ehdr);
++	old_base_addr = max_addr;
++	old_start_addr = max_addr;
++
++	/*
++	 * Get the memory footprint, base physical
++	 * and start address of the ELF image
++	 */
++	for (i = 0; i < ehdr.e_phnum; i++) {
++		phdr = &ehdr.e_phdr[i];
++		if (phdr->p_type != PT_LOAD)
++			continue;
++
++		/*
++		 * Note: According to ELF spec the loadable regions
++		 * are sorted on p_vaddr, not p_paddr.
++		 */
++		if (old_base_addr > phdr->p_paddr)
++			old_base_addr = phdr->p_paddr;
++
++		if (phdr->p_vaddr == ehdr.e_entry ||
++		    phdr->p_paddr == ehdr.e_entry)
++			old_start_addr = phdr->p_paddr;
++
++		kernel_size += _ALIGN_UP(phdr->p_memsz, page_size);
++	}
++
++	if (old_base_addr == max_addr || kernel_size == 0) {
++		fprintf(stderr, "No loadable segments present on the "
++				"provided ELF image\n");
++		return -EINVAL;
++	}
++
++	if (old_start_addr == max_addr) {
++		fprintf(stderr, "Could not find the entry point address of "
++				"provided ELF image\n");
++		return -EINVAL;
++	}
++
++	dbgprintf("Got ELF with total memsz %luKB\n"
++		  "Base paddr: 0x%lX, start_addr: 0x%lX\n",
++		  kernel_size / 1024, old_base_addr, old_start_addr);
++
++	/* Get a continuous physical region that can hold the kernel */
++	ret = elf_riscv_find_pbase(info, &new_base_addr, kernel_size);
++	if (ret < 0) {
++		fprintf(stderr, "Could not find a memory region for the "
++				"provided ELF image\n");
++		return ret;
++	}
++
++	dbgprintf("New base paddr for the ELF: 0x%lX\n", new_base_addr);
++
++	/* Re-set the base physical address of the ELF */
++	for (i = 0; i < ehdr.e_phnum; i++) {
++		phdr = &ehdr.e_phdr[i];
++		if (phdr->p_type != PT_LOAD)
++			continue;
++
++		phdr->p_paddr -= old_base_addr;
++		phdr->p_paddr += new_base_addr;
++	}
++
++	/* Re-set the entry point address */
++	ehdr.e_entry = (old_start_addr - old_base_addr) + new_base_addr;
++	info->entry = (void *) ehdr.e_entry;
++	dbgprintf("New entry point for the ELF: 0x%llX\n", ehdr.e_entry);
++
++
++	/* Load the ELF executable */
++	ret = elf_exec_load(&ehdr, info);
++	if (ret < 0) {
++		fprintf(stderr, "ELF exec load failed\n");
++		return ret;
++	}
++
++	ret = load_extra_segments(info, new_base_addr,
++				  kernel_size, max_addr);
++	return ret;
++}
++
++
++/*******\
++* STUBS *
++\*******/
++
++int machine_verify_elf_rel(struct mem_ehdr *ehdr)
++{
++	if (ehdr->ei_data != ELFDATA2LSB)
++		return 0;
++#if __riscv_xlen == 64
++	if (ehdr->ei_class != ELFCLASS64)
++#else
++	if (ehdr->ei_class != ELFCLASS32)
++#endif
++		return 0;
++	if (ehdr->e_machine != EM_RISCV)
++		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;
++	}
++}
+diff --git a/kexec/arch/riscv/kexec-riscv.c b/kexec/arch/riscv/kexec-riscv.c
+new file mode 100644
+index 0000000..d05c47d
+--- /dev/null
++++ b/kexec/arch/riscv/kexec-riscv.c
+@@ -0,0 +1,364 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2019 FORTH-ICS/CARV
++ *              Nick Kossifidis <mick@ics.forth.gr>
++ */
++
++#include "kexec-syscall.h"	/* For KEXEC_ARCH_RISCV */
++#include "kexec.h"		/* For OPT_MAX and concat_cmdline() */
++#include "mem_regions.h"	/* For mem_regions_sort() */
++#include "dt-ops.h"		/* For dtb_set_bootargs() */
++#include <arch/options.h>	/* For KEXEC_ARCH_OPTIONS */
++#include <getopt.h>		/* For struct option */
++#include <sys/stat.h>		/* For stat() and struct stat */
++#include <stdlib.h>		/* For free() */
++#include <errno.h>		/* For EINVAL */
++#include <libfdt.h>		/* For DeviceTree handling */
++#include "kexec-riscv.h"
++
++const struct arch_map_entry arches[] = {
++	{ "riscv32", KEXEC_ARCH_RISCV },
++	{ "riscv64", KEXEC_ARCH_RISCV },
++	{ NULL, 0 },
++};
++
++
++struct file_type file_type[] = {
++	{"elf-riscv", elf_riscv_probe, elf_riscv_load, elf_riscv_usage},
++};
++int file_types = sizeof(file_type) / sizeof(file_type[0]);
++
++static const char riscv_opts_usage[] =
++"	--append=STRING		Append STRING to the kernel command line.\n"
++"	--dtb=FILE		Use FILE as the device tree blob.\n"
++"	--initrd=FILE		Use FILE as the kernel initial ramdisk.\n"
++"	--cmdline=STRING	Use STRING as the kernel's command line.\n"
++"	--reuse-cmdline		Use kernel command line from running system.\n";
++
++static struct riscv_opts arch_options = {0};
++static struct fdt_image provided_fdt = {0};
++static struct memory_ranges sysmem_ranges = {0};
++
++/****************\
++* COMMON HELPERS *
++\****************/
++
++int load_extra_segments(struct kexec_info *info, uint64_t kernel_base,
++			uint64_t kernel_size, uint64_t max_addr)
++{
++	struct fdt_image *fdt = arch_options.fdt;
++	char *initrd_buf = NULL;
++	off_t initrd_size = 0;
++	uint64_t initrd_base = 0;
++	uint64_t start = 0;
++	uint64_t end = 0;
++	uint64_t min_usable = kernel_base + kernel_size;
++	uint64_t max_usable = max_addr;
++	int ret = 0;
++
++	/* Prepare the device tree */
++	if (info->kexec_flags & KEXEC_ON_CRASH) {
++		ret = load_elfcorehdr(info);
++		if (ret) {
++			fprintf(stderr, "Couldn't create elfcorehdr\n");
++			return ret;
++		}
++
++		ret = dtb_add_range_property(&fdt->buf, &fdt->size,
++					     elfcorehdr_mem.start, elfcorehdr_mem.end,
++					     "chosen", "linux,elfcorehdr");
++		if (ret) {
++			fprintf(stderr, "Couldn't add elfcorehdr to fdt\n");
++			return ret;
++		}
++
++		ret = get_crash_kernel_load_range(&start, &end);
++		if (ret) {
++			fprintf(stderr, "Couldn't get crashkenel region\n");
++			return ret;
++		}
++
++		ret = dtb_add_range_property(&fdt->buf, &fdt->size, start, end,
++					     "memory", "linux,usable-memory");
++		if (ret) {
++			fprintf(stderr, "Couldn't add usable-memory to fdt\n");
++			return ret;
++		}
++
++		max_usable = end;
++	} else {
++		/*
++		 * Make sure we remove elfcorehdr and usable-memory
++		 * when switching from crash kernel to a normal one.
++		 */
++		dtb_delete_property(fdt->buf, "chosen", "linux,elfcorehdr");
++		dtb_delete_property(fdt->buf, "memory", "linux,usable-memory");
++	}
++
++	/* Do we need to include an initrd image ? */
++	if (!arch_options.initrd_path && !arch_options.initrd_end)
++		dtb_clear_initrd(&fdt->buf, &fdt->size);
++	else if (arch_options.initrd_path) {
++		if (arch_options.initrd_end)
++			fprintf(stderr, "Warning: An initrd image was provided"
++					", will ignore reuseinitrd\n");
++
++		initrd_buf = slurp_file(arch_options.initrd_path,
++					&initrd_size);
++		if (!initrd_buf) {
++			fprintf(stderr, "Couldn't read provided initrd\n");
++			return -EINVAL;
++		}
++
++		initrd_base = add_buffer_phys_virt(info, initrd_buf,
++						   initrd_size,
++						   initrd_size, 0,
++						   min_usable,
++						   max_usable, -1, 0);
++
++		dtb_set_initrd(&fdt->buf, &fdt->size, initrd_base,
++			       initrd_base + initrd_size);
++
++		dbgprintf("Base addr for initrd image: 0x%lX\n", initrd_base);
++		min_usable = initrd_base;
++	}
++
++	/* Add device tree */
++	add_buffer_phys_virt(info, fdt->buf, fdt->size, fdt->size, 0,
++			     min_usable, max_usable, -1, 0);
++
++	return 0;
++}
++
++
++/**************\
++* ENTRY POINTS *
++\**************/
++
++void arch_usage(void)
++{
++	printf(riscv_opts_usage);
++}
++
++int arch_process_options(int argc, char **argv)
++{
++	static const struct option options[] = {
++		KEXEC_ARCH_OPTIONS
++		{ 0 },
++	};
++	static const char short_options[] = KEXEC_ARCH_OPT_STR;
++	struct stat st = {0};
++	char *append = NULL;
++	char *cmdline = NULL;
++	void *tmp = NULL;
++	off_t tmp_size = 0;
++	int opt = 0;
++	int ret = 0;
++
++	while ((opt = getopt_long(argc, argv, short_options,
++				  options, 0)) != -1) {
++		switch (opt) {
++		case OPT_APPEND:
++			append = optarg;
++			break;
++		case OPT_CMDLINE:
++			if (cmdline)
++				fprintf(stderr,
++					"Warning: Kernel's cmdline "
++					"set twice !\n");
++			cmdline = optarg;
++			break;
++		case OPT_REUSE_CMDLINE:
++			if (cmdline)
++				fprintf(stderr,
++					"Warning: Kernel's cmdline "
++					"set twice !\n");
++			cmdline = get_command_line();
++			break;
++		case OPT_DTB:
++			ret = stat(optarg, &st);
++			if (ret) {
++				fprintf(stderr,
++					"Could not find the provided dtb !\n");
++				return -EINVAL;
++			}
++			arch_options.fdt_path = optarg;
++			break;
++		case OPT_INITRD:
++			ret = stat(optarg, &st);
++			if (ret) {
++				fprintf(stderr,
++					"Could not find the provided "
++					"initrd image !\n");
++				return -EINVAL;
++			}
++			arch_options.initrd_path = optarg;
++			break;
++		default:
++			break;
++		}
++	}
++
++	/* Handle Kernel's command line */
++	if (append && !cmdline)
++		fprintf(stderr, "Warning: No cmdline provided, "
++				"using append string as cmdline\n");
++	if (!append && !cmdline)
++		fprintf(stderr, "Warning: No cmdline or append string "
++				"provided\n");
++
++	if (append || cmdline)
++		/*
++		 * Note that this also handles the case where "cmdline"
++		 * or "append" is NULL.
++		 */
++		arch_options.cmdline = concat_cmdline(cmdline, append);
++
++	/* Handle FDT image */
++	if (!arch_options.fdt_path) {
++		ret = stat("/sys/firmware/fdt", &st);
++		if (ret) {
++			fprintf(stderr, "No dtb provided and "
++					"/sys/firmware/fdt is not present\n");
++			return -EINVAL;
++		}
++		fprintf(stderr, "Warning: No dtb provided, "
++				"using /sys/firmware/fdt\n");
++		arch_options.fdt_path = "/sys/firmware/fdt";
++	}
++
++	tmp = slurp_file(arch_options.fdt_path, &tmp_size);
++	if (!tmp) {
++		fprintf(stderr, "Couldn't read provided fdt\n");
++		return -EINVAL;
++	}
++
++	ret = fdt_check_header(tmp);
++	if (ret) {
++		fprintf(stderr, "Got an ivalid fdt image !\n");
++		free(tmp);
++		return -EINVAL;
++	}
++	provided_fdt.buf = tmp;
++	provided_fdt.size = tmp_size;
++
++	if (arch_options.cmdline) {
++		ret = dtb_set_bootargs(&provided_fdt.buf, &provided_fdt.size,
++				       arch_options.cmdline);
++		if (ret < 0) {
++			fprintf(stderr, "Could not set bootargs on "
++					"the fdt image\n");
++			return ret;
++		}
++	}
++
++	arch_options.fdt = &provided_fdt;
++
++	return 0;
++}
++
++/*
++ * This one is called after arch_process_options so we already
++ * have an fdt image in place.
++ */
++void arch_reuse_initrd(void)
++{
++	const uint32_t *prop32 = NULL;
++	uint32_t addr_cells = 0;
++	const void *prop = 0;
++	int prop_size = 0;
++	uint64_t initrd_start = 0;
++	uint64_t initrd_end = 0;
++	int chosen_offset = 0;
++	struct fdt_image *fdt = &provided_fdt;
++
++	chosen_offset = fdt_subnode_offset(fdt->buf, 0, "chosen");
++	if (chosen_offset < 0) {
++		fprintf(stderr, "No /chosen node found on fdt image "
++				"unable to reuse initrd\n");
++		return;
++	}
++
++	prop32 = fdt_getprop(fdt->buf, 0, "#address-cells", NULL);
++	if (!prop32) {
++		fprintf(stderr, "No #address-cells property on root node\n");
++		return;
++	}
++	addr_cells = be32_to_cpu(*prop32);
++
++	prop = fdt_getprop(fdt->buf, chosen_offset,
++			   "linux,initrd-start", &prop_size);
++	if (!prop) {
++		fprintf(stderr, "Could not get linux,initrd-start\n");
++		return;
++	}
++	dtb_extract_int_property(&initrd_start, prop, addr_cells);
++
++	prop = fdt_getprop(fdt->buf, chosen_offset,
++			   "linux,initrd-end", &prop_size);
++	if (!prop) {
++		fprintf(stderr, "Could not get linux,initrd-end\n");
++		return;
++	}
++	dtb_extract_int_property(&initrd_end, prop, addr_cells);
++
++	arch_options.initrd_start = initrd_start;
++	arch_options.initrd_end = initrd_end;
++	dbgprintf("initrd_start: 0x%lX, initrd_end: 0x%lX\n",
++		  initrd_start, initrd_end);
++
++}
++
++int get_memory_ranges(struct memory_range **range, int *num_ranges,
++		      unsigned long kexec_flags)
++{
++	const struct fdt_image *fdt = &provided_fdt;
++	struct memory_ranges *extra_ranges = NULL;
++	int i = 0;
++	int ret = 0;
++
++	if (arch_options.initrd_start && arch_options.initrd_end) {
++		int initrd_size = arch_options.initrd_end - arch_options.initrd_start;
++		dbgprintf("Marking current intird image as reserved\n");
++		ret = mem_regions_alloc_and_add(extra_ranges,
++						arch_options.initrd_start,
++						initrd_size,
++						RANGE_RESERVED);
++		if (ret)
++			return ret;
++	}
++
++	ret = dtb_get_memory_ranges(fdt->buf, &sysmem_ranges, extra_ranges);
++	if (ret) {
++		fprintf(stderr, "Could not get memory ranges from device tree (%i) !\n", ret);
++		return ret;
++	}
++
++	*range = sysmem_ranges.ranges;
++	*num_ranges = sysmem_ranges.size;
++
++	dbgprintf("Memory regions:\n");
++	for (i = 0; i < sysmem_ranges.size; i++) {
++		dbgprintf("\t0x%llx - 0x%llx : %s (%i)\n",
++			  sysmem_ranges.ranges[i].start,
++			  sysmem_ranges.ranges[i].end,
++			  sysmem_ranges.ranges[i].type == RANGE_RESERVED ?
++			  "RANGE_RESERVED" : "RANGE_RAM",
++			  sysmem_ranges.ranges[i].type);
++	}
++
++	return 0;
++}
++
++/*******\
++* STUBS *
++\*******/
++
++int arch_compat_trampoline(struct kexec_info *UNUSED(info))
++{
++	return 0;
++}
++
++void arch_update_purgatory(struct kexec_info *UNUSED(info))
++{
++}
+diff --git a/kexec/arch/riscv/kexec-riscv.h b/kexec/arch/riscv/kexec-riscv.h
+new file mode 100644
+index 0000000..c4323a6
+--- /dev/null
++++ b/kexec/arch/riscv/kexec-riscv.h
+@@ -0,0 +1,32 @@
++/* SPDX-License-Identifier: GPL-2.0 */
++/*
++ * Copyright (C) 2019 FORTH-ICS/CARV
++ *              Nick Kossifidis <mick@ics.forth.gr>
++ */
++
++struct fdt_image {
++	char	*buf;
++	off_t	size;
++};
++
++struct riscv_opts {
++	char *cmdline;
++	char *fdt_path;
++	char *initrd_path;
++	uint64_t initrd_start;
++	uint64_t initrd_end;
++	struct fdt_image *fdt;
++};
++
++/* crashdump-riscv.c */
++extern struct memory_range elfcorehdr_mem;
++int load_elfcorehdr(struct kexec_info *info);
++
++/* kexec-riscv.c */
++int load_extra_segments(struct kexec_info *info, uint64_t kernel_base,
++			uint64_t kernel_size, uint64_t max_addr);
++
++int elf_riscv_probe(const char *buf, off_t len);
++void elf_riscv_usage(void);
++int elf_riscv_load(int argc, char **argv, const char *buf, off_t len,
++		   struct kexec_info *info);
+diff --git a/kexec/dt-ops.c b/kexec/dt-ops.c
+index 0a96b75..3e285ab 100644
+--- a/kexec/dt-ops.c
++++ b/kexec/dt-ops.c
+@@ -4,9 +4,11 @@
+ #include <libfdt.h>
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <stdbool.h>
+ 
+ #include "kexec.h"
+ #include "dt-ops.h"
++#include "mem_regions.h"
+ 
+ static const char n_chosen[] = "chosen";
+ 
+@@ -95,7 +97,7 @@ int dtb_set_property(char **dtb, off_t *dtb_size, const char *node,
+ 
+ 	strcpy(new_node, "/");
+ 	strcat(new_node, node);
+-	
++
+ 	nodeoffset = fdt_path_offset(new_dtb, new_node);
+ 
+ 	if (nodeoffset == -FDT_ERR_NOTFOUND) {
+@@ -174,3 +176,441 @@ int dtb_delete_property(char *dtb, const char *node, const char *prop)
+ 	free(new_node);
+ 	return result;
+ }
++
++static int dtb_get_num_cells(char *dtb, int nodeoffset, uint32_t *addr_cells,
++			     uint32_t *size_cells, bool recursive)
++{
++	const uint32_t *prop32 = NULL;
++	int curr_offset = nodeoffset;
++	int prop_len = 0;
++	*addr_cells = 0;
++	*size_cells = 0;
++
++	do {
++		prop32 = fdt_getprop(dtb, curr_offset, "#address-cells", &prop_len);
++		curr_offset = fdt_parent_offset(dtb, curr_offset);
++	} while (!prop32 && prop_len == -FDT_ERR_NOTFOUND && recursive);
++
++	if (!prop32) {
++		dbgprintf("Could not get #address-cells property for %s (%s)\n",
++			  fdt_get_name(dtb, nodeoffset, NULL), fdt_strerror(nodeoffset));
++		return -EINVAL;
++	}
++	*addr_cells = fdt32_to_cpu(*prop32);
++
++	curr_offset = nodeoffset;
++	do {
++		prop32 = fdt_getprop(dtb, curr_offset, "#size-cells", &prop_len);
++		curr_offset = fdt_parent_offset(dtb, curr_offset);
++	} while (!prop32 && prop_len == -FDT_ERR_NOTFOUND && recursive);
++
++	if (!prop32) {
++		dbgprintf("Could not get #size-cells property for %s (%s)\n",
++			  fdt_get_name(dtb, nodeoffset, NULL), fdt_strerror(nodeoffset));
++		return -EINVAL;
++	}
++	*size_cells = fdt32_to_cpu(*prop32);
++
++	dbgprintf("%s: #address-cells:%d #size-cells:%d\n",
++		 fdt_get_name(dtb, nodeoffset, NULL), *addr_cells, *size_cells);
++
++	return 0;
++}
++
++void dtb_extract_int_property(uint64_t *val, const void *buf, uint32_t cells)
++{
++	const uint32_t *prop32 = NULL;
++	const uint64_t *prop64 = NULL;
++
++	if (cells == 1) {
++		prop32 = (const uint32_t *) buf;
++		*val = (uint64_t) be32_to_cpu(*prop32);
++	} else {
++		/* Skip any leading cells */
++		prop64 = (const uint64_t *) (uint32_t *)buf + cells - 2;
++		*val = (uint64_t) be64_to_cpu(*prop64);
++	}
++}
++
++void dtb_fill_int_property(void *buf, uint64_t val, uint32_t cells)
++{
++	uint32_t prop32 = 0;
++	uint64_t prop64 = 0;
++
++	if (cells == 1) {
++		prop32 = cpu_to_fdt32((uint32_t) val);
++		memcpy(buf, &prop32, sizeof(uint32_t));
++	} else {
++		prop64 = cpu_to_fdt64(val);
++		/* Skip any leading cells */
++		memcpy((uint64_t *)(uint32_t *)buf + cells - 2,
++		       &prop64, sizeof(uint64_t));
++	}
++}
++
++int dtb_add_range_property(char **dtb, off_t *dtb_size, uint64_t start, uint64_t end,
++			   const char *parent, const char *name)
++{
++	uint32_t addr_cells = 0;
++	uint32_t size_cells = 0;
++	char *nodepath = NULL;
++	void *prop = NULL;
++	int nodeoffset = 0;
++	int prop_size = 0;
++	int ret = 0;
++
++	nodepath = malloc(strlen("/") + strlen(parent) + 1);
++	if (!nodepath) {
++		dbgprintf("%s: malloc failed\n", __func__);
++		return -ENOMEM;
++	}
++
++	strcpy(nodepath, "/");
++	strcat(nodepath, parent);
++
++	nodeoffset = fdt_path_offset(*dtb, nodepath);
++	if (nodeoffset < 0) {
++		dbgprintf("%s: fdt_path_offset(%s) failed: %s\n", __func__,
++			  nodepath, fdt_strerror(nodeoffset));
++		free(nodepath);
++		return nodeoffset;
++	}
++	free(nodepath);
++
++	ret = dtb_get_num_cells(*dtb, nodeoffset, &addr_cells, &size_cells, true);
++	if (ret < 0)
++		return ret;
++
++	/* Can the range fit with the given address/size cells ? */
++	if ((addr_cells == 1) && (start >= (1ULL << 32)))
++		return -EINVAL;
++
++	if ((size_cells == 1) && ((end - start + 1) >= (1ULL << 32)))
++		return -EINVAL;
++
++	prop_size = sizeof(uint32_t) * (addr_cells + size_cells);
++	prop = malloc(prop_size);
++
++	dtb_fill_int_property(prop, start, addr_cells);
++	dtb_fill_int_property((void *)((uint32_t *)prop + addr_cells),
++			      end - start + 1, size_cells);
++
++	/* Add by node path name */
++	return dtb_set_property(dtb, dtb_size, parent, name, prop, prop_size);
++}
++
++/************************\
++* MEMORY RANGES HANDLING *
++\************************/
++
++static int dtb_add_memory_range(struct memory_ranges *mem_ranges, uint64_t start,
++				uint64_t end, unsigned type)
++{
++	struct memory_range this_region = {0};
++	struct memory_range *ranges = mem_ranges->ranges;
++	int i = 0;
++	int ret = 0;
++
++	if (start == end) {
++		dbgprintf("Ignoring empty region\n");
++		return -EINVAL;
++	}
++
++	/* Check if we are adding an existing region */
++	for (i = 0; i < mem_ranges->size; i++) {
++		if (start == ranges[i].start && end == ranges[i].end) {
++			dbgprintf("Duplicate: 0x%lx - 0x%lx\n", start, end);
++
++			if (type == ranges[i].type)
++				return 0;
++			else if (type == RANGE_RESERVED) {
++				ranges[i].type = RANGE_RESERVED;
++				return 0;
++			}
++
++			dbgprintf("Conflicting types for region: 0x%lx - 0x%lx\n",
++				  start, end);
++			return -EINVAL;
++		}
++	}
++
++	/*
++	 * Reserved regions may be part of an existing /memory
++	 * region and shouldn't overlap according to spec, so
++	 * since we add /memory regions first, we can exclude
++	 * reserved regions here from the existing /memory regions
++	 * included in ranges[], so that we don't have the same
++	 * region twice.
++	 */
++	if (type == RANGE_RESERVED) {
++		this_region.start = start;
++		this_region.end = end - 1;
++		this_region.type = type;
++		ret = mem_regions_exclude(mem_ranges, &this_region);
++		if (ret)
++			return ret;
++	}
++
++	ret = mem_regions_alloc_and_add(mem_ranges, start,
++					end - start, type);
++
++	return ret;
++}
++
++static int dtb_add_memory_region(char *dtb, int nodeoffset,
++				 struct memory_ranges *mem_ranges, int type)
++{
++	uint32_t root_addr_cells = 0;
++	uint32_t root_size_cells = 0;
++	uint64_t addr = 0;
++	uint64_t size = 0;
++	const char *reg = NULL;
++	int prop_size = 0;
++	int offset = 0;
++	int entry_size = 0;
++	int num_entries = 0;
++	int ret = 0;
++
++	/*
++	 * Get address-cells and size-cells properties (according to
++	 * binding spec these are the same as in the root node)
++	 */
++	ret = dtb_get_num_cells(dtb, 0, &root_addr_cells, &root_size_cells, false);
++	if (ret < 0) {
++		dbgprintf("No address/size cells on root node !\n");
++		return ret;
++	}
++
++	/*
++	 * Parse the reg array, acording to device tree spec it includes
++	 * an arbitary number of <address><size> pairs
++	 */
++	entry_size = (root_addr_cells + root_size_cells) * sizeof(uint32_t);
++	reg = fdt_getprop(dtb, nodeoffset, "reg", &prop_size);
++	if (!reg) {
++		dbgprintf("Warning: Malformed memory region with no reg property (%s) !\n",
++			  fdt_get_name(dtb, nodeoffset, NULL));
++		return -EINVAL;
++	}
++
++	num_entries = prop_size / entry_size;
++	dbgprintf("Got region with %i entries: %s\n", num_entries,
++		  fdt_get_name(dtb, nodeoffset, NULL));
++
++	for (num_entries--; num_entries >= 0; num_entries--) {
++		offset = num_entries * entry_size;
++
++		dtb_extract_int_property(&addr, reg + offset,
++					 root_addr_cells);
++		offset += root_addr_cells * sizeof(uint32_t);
++
++		dtb_extract_int_property(&size, reg + offset,
++					 root_size_cells);
++
++		ret = dtb_add_memory_range(mem_ranges, addr,
++					   addr + size, type);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int dtb_parse_memory_reservations_table(char *dtb, struct memory_ranges *mem_ranges)
++{
++	int total_memrsrv = 0;
++	uint64_t addr = 0;
++	uint64_t size = 0;
++	int ret = 0;
++	int i = 0;
++
++	total_memrsrv = fdt_num_mem_rsv(dtb);
++	for (i = 0; i < total_memrsrv; i++) {
++		ret = fdt_get_mem_rsv(dtb, i, &addr, &size);
++		if (ret)
++			continue;
++		ret = dtb_add_memory_range(mem_ranges, addr, addr + size - 1,
++					   RANGE_RESERVED);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
++static int dtb_get_reserved_memory_node(char *dtb)
++{
++	uint32_t root_addr_cells = 0;
++	uint32_t root_size_cells = 0;
++	uint32_t addr_cells = 0;
++	uint32_t size_cells = 0;
++	int prop_size = 0;
++	int nodeoffset = 0;
++	int ret = 0;
++
++	/* Get address / size cells from root node */
++	ret = dtb_get_num_cells(dtb, 0, &root_addr_cells, &root_size_cells, false);
++	if (ret < 0) {
++		dbgprintf("No address/size cells on root node !\n");
++		return ret;
++	}
++
++	/* This calls fdt_next_node internaly */
++	nodeoffset = fdt_subnode_offset(dtb, 0, "reserved-memory");
++	if (nodeoffset == -FDT_ERR_NOTFOUND) {
++		return nodeoffset;
++	} else if (nodeoffset < 0) {
++		dbgprintf("Error while looking for reserved-memory: %s\n",
++			fdt_strerror(nodeoffset));
++		return nodeoffset;
++	}
++
++	/* Look for the ranges property */
++	fdt_getprop(dtb, nodeoffset, "ranges", &prop_size);
++	if (prop_size < 0) {
++		fprintf(stderr, "Malformed reserved-memory node (no ranges property) !\n");
++		return -EINVAL;
++	}
++
++	/* Verify address-cells / size-cells */
++	ret = dtb_get_num_cells(dtb, nodeoffset, &addr_cells, &size_cells, false);
++	if (ret < 0) {
++		dbgprintf("No address/size cells property on reserved-memory node\n");
++		return ret;
++	}
++
++	if (addr_cells != root_addr_cells) {
++		fprintf(stderr, "Invalid #address-cells property on reserved-memory node\n");
++		return -EINVAL;
++	}
++
++	if (size_cells != root_size_cells) {
++		fprintf(stderr, "Invalid #size-cells property on reserved-memory node\n");
++		return -EINVAL;
++
++	}
++
++	return nodeoffset;
++}
++
++static int dtb_parse_reserved_memory_node(char *dtb, struct memory_ranges *mem_ranges)
++{
++	int nodeoffset = 0;
++	int node_depth = 0;
++	int parent_depth = 0;
++	int ret = 0;
++
++	nodeoffset = dtb_get_reserved_memory_node(dtb);
++	if (nodeoffset == -FDT_ERR_NOTFOUND)
++		return 0;
++	else if (nodeoffset < 0)
++		return nodeoffset;
++
++	/* Got the parent node, check for sub-nodes */
++
++	/* fdt_next_node() increases or decreases depth */
++	node_depth = parent_depth;
++	nodeoffset = fdt_next_node(dtb, nodeoffset, &node_depth);
++	if (ret < 0) {
++		dbgprintf("Unable to get next node: %s\n",
++			  fdt_strerror(ret));
++		return -EINVAL;
++	}
++
++	while (node_depth != parent_depth) {
++
++		ret = dtb_add_memory_region(dtb, nodeoffset,
++					    mem_ranges, RANGE_RESERVED);
++		if (ret)
++			return ret;
++
++		nodeoffset = fdt_next_node(dtb, nodeoffset, &node_depth);
++		if (ret < 0) {
++			dbgprintf("Unable to get next node: %s\n",
++				  fdt_strerror(ret));
++			return -EINVAL;
++		}
++	}
++
++	return 0;
++}
++
++static int dtb_parse_memory_nodes(char *dtb, struct memory_ranges *mem_ranges)
++{
++	int nodeoffset = 0;
++	int num_regions = 0;
++	const char* dev_type = 0;
++	int prop_size = 0;
++	int ret = 0;
++
++	for (; ; num_regions++) {
++		nodeoffset = fdt_subnode_offset(dtb, nodeoffset,
++						 "memory");
++		if (nodeoffset < 0)
++			break;
++
++		dbgprintf("Got memory node at depth: %i\n", fdt_node_depth(dtb, nodeoffset));
++
++		/* Look for the device_type  property */
++		dev_type = fdt_getprop(dtb, nodeoffset, "device_type", &prop_size);
++		if (prop_size < 0) {
++			fprintf(stderr, "Malformed /memory node (no device-type property) !\n");
++			return -EINVAL;
++		}
++
++		if (strncmp(dev_type, "memory", prop_size)) {
++			dbgprintf("Got unknown dev_type property: %s\n", dev_type);
++			continue;
++		}
++
++		ret = dtb_add_memory_region(dtb, nodeoffset, mem_ranges, RANGE_RAM);
++		if (ret)
++			return ret;
++	}
++
++	if (!num_regions) {
++		dbgprintf("Malformed dtb, no /memory nodes present !\n");
++		return -EINVAL;
++	}
++
++	dbgprintf("Got %i /memory nodes\n", num_regions);
++
++	return 0;
++}
++
++int dtb_get_memory_ranges(char *dtb, struct memory_ranges *mem_ranges, struct memory_ranges *extra_ranges)
++{
++	int i = 0;
++	int ret = 0;
++
++	/* Fill mem_ranges[] by parsing the device tree */
++	ret = dtb_parse_memory_nodes(dtb, mem_ranges);
++	if (ret)
++		return ret;
++
++	ret = dtb_parse_memory_reservations_table(dtb, mem_ranges);
++	if (ret)
++		return ret;
++
++	ret = dtb_parse_reserved_memory_node(dtb, mem_ranges);
++	if (ret)
++		return ret;
++
++	/* Append any extra ranges provided by the caller (e.g. initrd) */
++	for (i = 0; extra_ranges != NULL && i < extra_ranges->size; i++) {
++		dbgprintf("Adding extra range: 0x%llx - 0x%llx (%s)\n",
++			  extra_ranges->ranges[i].start,
++			  extra_ranges->ranges[i].end,
++			  extra_ranges->ranges[i].type == RANGE_RESERVED ?
++                          "RANGE_RESERVED" : "RANGE_RAM");
++
++		ret = dtb_add_memory_range(mem_ranges, extra_ranges->ranges[i].start,
++                                extra_ranges->ranges[i].end, extra_ranges->ranges[i].type);
++		if (ret)
++			return ret;
++	}
++
++	mem_regions_sort(mem_ranges);
++
++	return 0;
++}
+diff --git a/kexec/dt-ops.h b/kexec/dt-ops.h
+index 03659ce..3014205 100644
+--- a/kexec/dt-ops.h
++++ b/kexec/dt-ops.h
+@@ -11,4 +11,11 @@ int dtb_set_property(char **dtb, off_t *dtb_size, const char *node,
+ 
+ int dtb_delete_property(char *dtb, const char *node, const char *prop);
+ 
++void dtb_extract_int_property(uint64_t *val, const void *buf, uint32_t cells);
++void dtb_fill_int_property(void *buf, uint64_t val, uint32_t cells);
++int dtb_add_range_property(char **dtb, off_t *dtb_size, uint64_t start, uint64_t end,
++                           const char *node, const char* parent);
++int dtb_get_memory_ranges(char *dtb, struct memory_ranges *mem_ranges,
++			  struct memory_ranges *extra_ranges);
++
+ #endif
+diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h
+index bea29d4..2e99e2b 100644
+--- a/kexec/kexec-syscall.h
++++ b/kexec/kexec-syscall.h
+@@ -134,6 +134,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,
+ #define KEXEC_ARCH_MIPS_LE (10 << 16)
+ #define KEXEC_ARCH_MIPS    ( 8 << 16)
+ #define KEXEC_ARCH_CRIS    (76 << 16)
++#define KEXEC_ARCH_RISCV   (243 << 16)
+ 
+ #define KEXEC_MAX_SEGMENTS 16
+ 
+@@ -177,5 +178,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,
+ #if defined(__arm64__)
+ #define KEXEC_ARCH_NATIVE	KEXEC_ARCH_ARM64
+ #endif
++#if defined(__riscv__) || defined(__riscv)
++#define KEXEC_ARCH_NATIVE	KEXEC_ARCH_RISCV
++#endif
+ 
+ #endif /* KEXEC_SYSCALL_H */
+diff --git a/purgatory/Makefile b/purgatory/Makefile
+index 15adb12..11694e5 100644
+--- a/purgatory/Makefile
++++ b/purgatory/Makefile
+@@ -25,6 +25,7 @@ include $(srcdir)/purgatory/arch/ia64/Makefile
+ include $(srcdir)/purgatory/arch/mips/Makefile
+ include $(srcdir)/purgatory/arch/ppc/Makefile
+ include $(srcdir)/purgatory/arch/ppc64/Makefile
++include $(srcdir)/purgatory/arch/riscv/Makefile
+ include $(srcdir)/purgatory/arch/s390/Makefile
+ include $(srcdir)/purgatory/arch/sh/Makefile
+ include $(srcdir)/purgatory/arch/x86_64/Makefile
+diff --git a/purgatory/arch/riscv/Makefile b/purgatory/arch/riscv/Makefile
+new file mode 100644
+index 0000000..8bded71
+--- /dev/null
++++ b/purgatory/arch/riscv/Makefile
+@@ -0,0 +1,7 @@
++#
++# Purgatory riscv
++#
++
++riscv_PURGATORY_SRCS =
++
++dist += purgatory/arch/sh/Makefile $(riscv_PURGATORY_SRCS)
+-- 
+2.35.1
+

diff --git a/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild b/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild
index 5723fa8..7251c1b 100644
--- a/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild
+++ b/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild
@@ -3,7 +3,7 @@
 
 EAPI=8
 
-inherit libtool linux-info systemd
+inherit autotools libtool linux-info systemd
 
 if [[ ${PV} == "9999" ]] ; then
 	inherit git-r3 autotools
@@ -35,6 +35,7 @@ CONFIG_CHECK="~KEXEC"
 PATCHES=(
 	"${FILESDIR}"/${PN}-2.0.4-disable-kexec-test.patch
 	"${FILESDIR}"/${PN}-2.0.4-out-of-source.patch
+	"${FILESDIR}"/${PN}-2.0.24-riscv.patch
 )
 
 pkg_setup() {
@@ -48,11 +49,7 @@ src_prepare() {
 	# Append PURGATORY_EXTRA_CFLAGS flags set by configure, instead of overriding them completely.
 	sed -e "/^PURGATORY_EXTRA_CFLAGS =/s/=/+=/" -i Makefile.in || die
 
-	if [[ "${PV}" == 9999 ]] ; then
-		eautoreconf
-	else
-		elibtoolize
-	fi
+	eautoreconf
 }
 
 src_configure() {


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [gentoo-commits] proj/riscv:master commit in: sys-apps/kexec-tools/, sys-apps/kexec-tools/files/
@ 2022-07-02 11:44 Yixun Lan
  0 siblings, 0 replies; 2+ messages in thread
From: Yixun Lan @ 2022-07-02 11:44 UTC (permalink / raw
  To: gentoo-commits

commit:     dd7015229da7ba9823e0d446231d6bd4c819c396
Author:     Yixun Lan <dlan <AT> gentoo <DOT> org>
AuthorDate: Sat Jul  2 09:34:07 2022 +0000
Commit:     Yixun Lan <dlan <AT> gentoo <DOT> org>
CommitDate: Sat Jul  2 09:34:20 2022 +0000
URL:        https://gitweb.gentoo.org/proj/riscv.git/commit/?id=dd701522

sys-apps/kexec-tools: import original 2.0.24 from official tree

Signed-off-by: Yixun Lan <dlan <AT> gentoo.org>

 sys-apps/kexec-tools/Manifest                      |   1 +
 sys-apps/kexec-tools/files/90_kexec                |   9 +
 sys-apps/kexec-tools/files/README.Gentoo           |  33 ++++
 sys-apps/kexec-tools/files/kexec-r2.init           | 200 +++++++++++++++++++++
 .../kexec-tools-2.0.4-disable-kexec-test.patch     |  17 ++
 .../files/kexec-tools-2.0.4-out-of-source.patch    |  24 +++
 sys-apps/kexec-tools/files/kexec.conf              |  16 ++
 sys-apps/kexec-tools/files/kexec.conf-2.0.4        |  34 ++++
 sys-apps/kexec-tools/files/kexec.service           |  16 ++
 sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild     | 124 +++++++++++++
 sys-apps/kexec-tools/metadata.xml                  |  13 ++
 11 files changed, 487 insertions(+)

diff --git a/sys-apps/kexec-tools/Manifest b/sys-apps/kexec-tools/Manifest
new file mode 100644
index 0000000..d6b3aa3
--- /dev/null
+++ b/sys-apps/kexec-tools/Manifest
@@ -0,0 +1 @@
+DIST kexec-tools-2.0.24.tar.xz 303808 BLAKE2B 8188602f1b843c1dccc0307131f8c9ec0426c6cb3de898040352c1fed5f6d4bd7c58a0c2bf54290b91c8fe3401180df682959ee6c41693d07acc199c087c7db2 SHA512 ef7cf78246e2d729d81a3649791a5a23c385353cc75cbe8ef279616329fdaccc876d614c7f51e1456822a13a11520296070d9897467d24310399909e049c3822

diff --git a/sys-apps/kexec-tools/files/90_kexec b/sys-apps/kexec-tools/files/90_kexec
new file mode 100644
index 0000000..40bad42
--- /dev/null
+++ b/sys-apps/kexec-tools/files/90_kexec
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+version="$1" ; shift
+image="$1" ; shift
+
+exec sed \
+	-e "s:\"vmlinuz-.*\":\"vmlinuz-${version}\":" \
+	-e "s:/boot/initramfs-.*\.img:/boot/initramfs-${version}\.img:" \
+	-i /etc/kexec.conf

diff --git a/sys-apps/kexec-tools/files/README.Gentoo b/sys-apps/kexec-tools/files/README.Gentoo
new file mode 100644
index 0000000..7735e32
--- /dev/null
+++ b/sys-apps/kexec-tools/files/README.Gentoo
@@ -0,0 +1,33 @@
+Usage
+=====
+
+Do
+ $ man 8 kexec
+for full understanding of the underlying kexec command.
+Gentoo offers a wrapper to the bare kexec command through
+/etc/init.d/kexec.
+
+Configuration
+-------------
+
+Configuration is done in /etc/conf.d/kexec, which is self-documented.
+
+Usage
+-----
+
+In Gentoo, kexec is invoked, i.e., the new kernel will be booted when
+rebooting, by reboot (8) command or by pressing Ctrl+Alt+Del.
+
+If you want to use kexec once, just run
+ $ /etc/init.d/kexec start
+
+It'll reserve kexec call at reboot. Later on, you can reboot anytime,
+letting kexec starts another (or the same) kernel. When all is done in
+the runlevel 6 - killing processes, unmounting volumes, etc - kexec
+starts the new kernel instead of doing the normal hardware reboot.
+
+If you want kexec to be run every time you reboot, add it to a runlevel:
+ $ rc-update add kexec <runlevel>
+
+If you want to reboot in the normal way this time, do:
+ $ touch /nokexec

diff --git a/sys-apps/kexec-tools/files/kexec-r2.init b/sys-apps/kexec-tools/files/kexec-r2.init
new file mode 100644
index 0000000..0578f51
--- /dev/null
+++ b/sys-apps/kexec-tools/files/kexec-r2.init
@@ -0,0 +1,200 @@
+#!/sbin/openrc-run
+# Copyright 1999-2020 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# Set up some defaults.
+: "${LOAD_DURING_SHUTDOWN:=yes}"
+: "${BOOTPART:=/boot}"
+: "${DONT_MOUNT_BOOT:=no}"
+
+depend() {
+	need localmount
+}
+
+auto_prefix_bootpath() {
+	# Only auto-add prefix to relative paths.
+	case $1 in
+		*/*) echo "$1";;
+		*)   echo "${BOOTPART}/$1" ;;
+	esac
+}
+
+get_genkernel_arch() {
+	case $1 in
+		x86_64) echo "amd64" ;;
+		i[3456]86) echo "x86" ;;
+		*) echo "$1" ;;
+	esac
+}
+
+image_path() {
+	# Do no sanity checking if the user has set a value.
+	if [ -n "${KNAME}" ]; then
+		auto_prefix_bootpath "${KNAME}"
+		return
+	fi
+
+	local x kver="$(uname -r)" karch="$(uname -m)"
+	local gkarch="$(get_genkernel_arch $karch)"
+	for x in \
+		"bzImage" \
+		"vmlinux" \
+		"vmlinuz" \
+		"kernel" \
+		"bzImage-${kver}" \
+		"vmlinux-${kver}" \
+		"vmlinuz-${kver}" \
+		"kernel-genkernel-${karch}-${kver}" \
+		"kernel-genkernel-${gkarch}-${kver}" \
+		"kernel-${kver}" \
+		"kernel-${karch}"; do
+		if [ -e "${BOOTPART}/${x}" ]; then
+			echo "${BOOTPART}/${x}"
+			return
+		fi
+	done
+
+	return 1
+}
+
+initrd_path() {
+	# Do no sanity checking if the user has set a value.
+	if [ -n "${INITRD}" ]; then
+		auto_prefix_bootpath "${INITRD}"
+		return 0
+	fi
+
+	local x kver="$(uname -r)" karch="$(uname -m)"
+	local gkarch="$(get_genkernel_arch $karch)"
+	for x in \
+		"initrd" \
+		"initramfs" \
+		"initrd.img-${kver}" \
+		"initrd-${kver}.img" \
+		"initrd-${kver}" \
+		"initramfs-${kver}.img" \
+		"initramfs-genkernel-${karch}-${kver}" \
+		"initramfs-genkernel-${gkarch}-${kver}"; do
+		if [ -e "${BOOTPART}/${x}" ]; then
+			echo "${BOOTPART}/${x}"
+			return 0
+		fi
+	done
+
+	return 1
+}
+
+mount_boot() {
+	[ "${DONT_MOUNT_BOOT}" != "no" ] && return 1
+	mountinfo -q "${BOOTPART}" && return 1
+
+	ebegin "Mounting ${BOOTPART}"
+	mount "${BOOTPART}"
+	eend $?
+}
+
+load_image() {
+	if [ "${KNAME}" = "-" ]; then
+		ebegin "Disabling kexec"
+		kexec -u
+		eend $?
+		return  # eend preserved $? for us.
+	fi
+
+	local img initrd="$(initrd_path)" mounted=false kparamopt initrdopt
+
+	if ! img="$(image_path)"; then
+		if mount_boot; then
+			if img="$(image_path)"; then
+				mounted=true
+				initrd="$(initrd_path)"
+			else
+				eerror "No kernel image found in ${BOOTPART}!"
+				umount "${BOOTPART}"
+				return 1
+			fi
+		else
+			eerror "No kernel image found in ${BOOTPART}!"
+			return 1
+		fi
+	fi
+
+	local is_rootpart_autodetected=no
+	if [ -z "${ROOTPART}" ]; then
+		ROOTPART="$(readlink -f "$(sed -n '/^\/[^ ]* \/ / s,^\([^ ]*\).*,\1,p' /proc/mounts)")"
+		is_rootpart_autodetected=yes
+	fi
+
+	local is_reusing_cmdline=no
+	if [ -z "${KPARAM}" ]; then
+		kparamopt="--reuse-cmdline"
+		is_reusing_cmdline=yes
+	fi
+
+	if ! yesno "${is_rootpart_autodetected}" || ! yesno "${is_reusing_cmdline}"; then
+		# Only append root when explicit set in config or
+		# if we aren't re-using kernel cmdline
+		KPARAM="${KPARAM:+"${KPARAM} "}root=${ROOTPART}"
+	fi
+
+	if [ -n "${initrd}" ]; then
+		initrdopt="--initrd=${initrd}"
+	fi
+
+	local msg
+	[ -n "${initrd}" ] && \
+		msg=" (with ${initrd})"
+	ebegin "Using kernel image ${img}${msg} for kexec"
+
+	kexec ${KEXEC_OPT_ARGS} ${kparamopt} \
+		-l "${img}" ${KPARAM:+--append="${KPARAM}"} ${initrdopt}
+	local ret=$?
+
+	${mounted} && umount "${BOOTPART}"
+	eend ${ret}
+	return ${ret}
+}
+
+start() {
+	if [ "${LOAD_DURING_SHUTDOWN}" = "yes" ]; then
+		local mounted
+		if mount_boot; then
+			mounted=true
+		fi
+		if ! image_path >/dev/null; then
+			ewarn "Cannot find kernel image!"
+			ewarn "Please make sure a valid kernel image is present before reboot."
+			return 0
+		fi
+		if [ -n "${mounted}" ]; then
+			ebegin "Unmounting ${BOOTPART}"
+			umount "${BOOTPART}"
+			eend $?
+		fi
+		# $? is already set to the previous calls.
+		return
+	else
+		load_image
+	fi
+}
+
+stop() {
+	if ! yesno ${RC_REBOOT}; then
+		ebegin "Not rebooting; disabling kexec"
+		kexec -u
+		eend $?
+		return
+	fi
+
+	if [ -f /nokexec ]; then
+		ebegin "Rebooting; disabling kexec due to /nokexec"
+		rm -f /nokexec
+		kexec -u
+		eend $?
+		return
+	fi
+
+	if [ "${LOAD_DURING_SHUTDOWN}" = "yes" ]; then
+		load_image
+	fi
+}

diff --git a/sys-apps/kexec-tools/files/kexec-tools-2.0.4-disable-kexec-test.patch b/sys-apps/kexec-tools/files/kexec-tools-2.0.4-disable-kexec-test.patch
new file mode 100644
index 0000000..6fc73f2
--- /dev/null
+++ b/sys-apps/kexec-tools/files/kexec-tools-2.0.4-disable-kexec-test.patch
@@ -0,0 +1,17 @@
+diff --git kexec-tools-2.0.3/kexec_test/Makefile kexec-tools-2.0.3/kexec_test/Makefile
+index fec6210..2ed4d51 100644
+--- kexec-tools-2.0.3/kexec_test/Makefile
++++ kexec-tools-2.0.3/kexec_test/Makefile
+@@ -8,12 +8,6 @@ dist += kexec_test/Makefile $(KEXEC_TEST_SRCS)				\
+ 	kexec_test/x86-setup-legacy-pic.S
+ 
+ BUILD_KEXEC_TEST = no
+-ifeq ($(ARCH),i386)
+-BUILD_KEXEC_TEST = yes
+-endif
+-ifeq ($(ARCH),x86_64)
+-BUILD_KEXEC_TEST = yes
+-endif
+ 
+ ifeq ($(BUILD_KEXEC_TEST),yes)
+ 

diff --git a/sys-apps/kexec-tools/files/kexec-tools-2.0.4-out-of-source.patch b/sys-apps/kexec-tools/files/kexec-tools-2.0.4-out-of-source.patch
new file mode 100644
index 0000000..64c6cd8
--- /dev/null
+++ b/sys-apps/kexec-tools/files/kexec-tools-2.0.4-out-of-source.patch
@@ -0,0 +1,24 @@
+ Makefile.in | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/Makefile.in b/Makefile.in
+index c1859d1..1aa8559 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -44,7 +44,7 @@ TARGET_CFLAGS	= @TARGET_CFLAGS@
+ 
+ # Base compiler flags. These are extended by the subcomponent-Makefiles
+ # where necessary.
+-CPPFLAGS	= @CPPFLAGS@ -I$(srcdir)/include -I$(srcdir)/util_lib/include \
++CPPFLAGS	= @CPPFLAGS@ -I$(top_builddir)/include -I$(srcdir)/include -I$(srcdir)/util_lib/include \
+ 			-Iinclude/ $($(ARCH)_CPPFLAGS)
+ CFLAGS		= @CFLAGS@ -fno-strict-aliasing -Wall -Wstrict-prototypes
+ PURGATORY_EXTRA_CFLAGS = @PURGATORY_EXTRA_CFLAGS@
+@@ -77,6 +77,7 @@ pkgincludedir = $(includedir)/$(PACKAGE_NAME)
+ DESTDIR =
+ 
+ srcdir		= @srcdir@
++top_builddir = @top_builddir@
+ VPATH		= .:$(srcdir)
+ 
+ # install paths

diff --git a/sys-apps/kexec-tools/files/kexec.conf b/sys-apps/kexec-tools/files/kexec.conf
new file mode 100644
index 0000000..aa829b9
--- /dev/null
+++ b/sys-apps/kexec-tools/files/kexec.conf
@@ -0,0 +1,16 @@
+# Kernel image pathname, relative from /boot.
+KNAME="bzimage"
+
+# Additional arguments passed to kexec (8)
+# Following arguments are support:
+#
+# --reuse-cmdline
+#   Use the current boot command line
+#
+# --command-line=string
+#   Use a different command line
+#
+# --initrd=file
+#   Specify an initrd to use
+#
+KEXEC_OPT_ARGS="--reuse-cmdline"

diff --git a/sys-apps/kexec-tools/files/kexec.conf-2.0.4 b/sys-apps/kexec-tools/files/kexec.conf-2.0.4
new file mode 100644
index 0000000..b71ea2b
--- /dev/null
+++ b/sys-apps/kexec-tools/files/kexec.conf-2.0.4
@@ -0,0 +1,34 @@
+# Load kexec kernel image into memory during shutdown instead of bootup
+# (default: yes)
+#LOAD_DURING_SHUTDOWN="yes"
+
+# Additional arguments passed to kexec (8)
+#KEXEC_OPT_ARGS=""
+
+# Kernel image partition. Mounted automatically if not.
+# (default: /boot)
+#BOOTPART="/boot"
+
+# Root partition (should be autodetected)
+#ROOTPART="/dev/hda3"
+
+# Kernel image pathname, relative from BOOTPART.
+# If it's one of 
+# {kernel-genkernel,bzImage,vmlinuz,kernel}-<currently running kernel version>,
+# or bzImage, vmlinuz (without suffix),
+# then it's automaticaly detected.
+# Setting it to "-" will disable kexec.
+#KNAME="vmlinuz-3.9.0"
+
+# Initrd
+# Same automatic detection restriction as for KNAME apply.
+# initramfs-genkernel-<currently running kernel version>,
+# initrd{,.img}-<currently running kernel version>{,.img}
+# will be detected.
+#INITRD="/boot/fbsplash-emergence-1024x768"
+
+# Kernel parameters (should be autodetected)
+#KPARAM="splash=silent,theme:emergence"
+
+# Do not try to mount /boot
+# DONT_MOUNT_BOOT="yes"

diff --git a/sys-apps/kexec-tools/files/kexec.service b/sys-apps/kexec-tools/files/kexec.service
new file mode 100644
index 0000000..289aae0
--- /dev/null
+++ b/sys-apps/kexec-tools/files/kexec.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=Gracefully restart the box
+Documentation=man:kexec(8)
+After=boot.mount
+Before=shutdown.target umount.target final.target
+ConditionPathExists=!/nokexec
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+EnvironmentFile=/etc/kexec.conf
+ExecStart=/usr/sbin/kexec -l /boot/${KNAME} ${KEXEC_OPT_ARGS}
+ExecStop=/usr/sbin/kexec -l /boot/${KNAME} ${KEXEC_OPT_ARGS}
+
+[Install]
+WantedBy=multi-user.target

diff --git a/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild b/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild
new file mode 100644
index 0000000..5723fa8
--- /dev/null
+++ b/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild
@@ -0,0 +1,124 @@
+# Copyright 1999-2022 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+inherit libtool linux-info systemd
+
+if [[ ${PV} == "9999" ]] ; then
+	inherit git-r3 autotools
+	EGIT_REPO_URI="https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git"
+else
+	SRC_URI="https://www.kernel.org/pub/linux/utils/kernel/kexec/${P/_/-}.tar.xz"
+	[[ "${PV}" == *_rc* ]] || \
+	KEYWORDS="~amd64 ~arm64 ~ppc64 ~x86"
+fi
+
+DESCRIPTION="Load another kernel from the currently executing Linux kernel"
+HOMEPAGE="https://kernel.org/pub/linux/utils/kernel/kexec/"
+
+LICENSE="GPL-2"
+SLOT="0"
+IUSE="booke lzma xen zlib"
+
+REQUIRED_USE="lzma? ( zlib )"
+
+DEPEND="
+	lzma? ( app-arch/xz-utils )
+	zlib? ( sys-libs/zlib )"
+RDEPEND="${DEPEND}"
+
+S="${WORKDIR}/${P/_/-}"
+
+CONFIG_CHECK="~KEXEC"
+
+PATCHES=(
+	"${FILESDIR}"/${PN}-2.0.4-disable-kexec-test.patch
+	"${FILESDIR}"/${PN}-2.0.4-out-of-source.patch
+)
+
+pkg_setup() {
+	# GNU Make's $(COMPILE.S) passes ASFLAGS to $(CCAS), CCAS=$(CC)
+	export ASFLAGS="${CCASFLAGS}"
+}
+
+src_prepare() {
+	default
+
+	# Append PURGATORY_EXTRA_CFLAGS flags set by configure, instead of overriding them completely.
+	sed -e "/^PURGATORY_EXTRA_CFLAGS =/s/=/+=/" -i Makefile.in || die
+
+	if [[ "${PV}" == 9999 ]] ; then
+		eautoreconf
+	else
+		elibtoolize
+	fi
+}
+
+src_configure() {
+	local myeconfargs=(
+		$(use_with booke)
+		$(use_with lzma)
+		$(use_with xen)
+		$(use_with zlib)
+	)
+	econf "${myeconfargs[@]}"
+}
+
+src_compile() {
+	# Respect CFLAGS for purgatory.
+	# purgatory/Makefile uses PURGATORY_EXTRA_CFLAGS variable.
+	# -mfunction-return=thunk and -mindirect-branch=thunk conflict with
+	# -mcmodel=large which is added by build system.
+	# Replace them with -mfunction-return=thunk-inline and -mindirect-branch=thunk-inline.
+	local flag flags=()
+	for flag in ${CFLAGS}; do
+		[[ ${flag} == -mfunction-return=thunk ]] && flag="-mfunction-return=thunk-inline"
+		[[ ${flag} == -mindirect-branch=thunk ]] && flag="-mindirect-branch=thunk-inline"
+		flags+=("${flag}")
+	done
+	local -x PURGATORY_EXTRA_CFLAGS="${flags[*]}"
+
+	default
+}
+
+src_install() {
+	default
+
+	dodoc "${FILESDIR}"/README.Gentoo
+
+	newinitd "${FILESDIR}"/kexec-r2.init kexec
+	newconfd "${FILESDIR}"/kexec.conf-2.0.4 kexec
+
+	insinto /etc
+	doins "${FILESDIR}"/kexec.conf
+
+	insinto /etc/kernel/postinst.d
+	doins "${FILESDIR}"/90_kexec
+
+	systemd_dounit "${FILESDIR}"/kexec.service
+}
+
+pkg_postinst() {
+	if systemd_is_booted || has_version sys-apps/systemd; then
+		elog "For systemd support the new config file is"
+		elog "   /etc/kexec.conf"
+		elog "Please adopt it to your needs as there is no autoconfig anymore"
+	fi
+
+	local n_root_args=$(grep -o -- '\<root=' /proc/cmdline 2>/dev/null | wc -l)
+	local has_rootpart_set=no
+	if [[ -f "${EROOT}/etc/conf.d/kexec" ]]; then
+		if grep -q -E -- '^ROOTPART=' "${EROOT}/etc/conf.d/kexec" 2>/dev/null; then
+			has_rootpart_set=yes
+		fi
+	fi
+
+	if [[ ${n_root_args} -gt 1 && "${has_rootpart_set}" == "no"  ]]; then
+		ewarn "WARNING: Multiple root arguments (root=) on kernel command-line detected!"
+		ewarn "This was probably caused by a previous version of ${PN}."
+		ewarn "Please reboot system once *without* kexec to avoid boot problems"
+		ewarn "in case running system and initramfs do not agree on detected"
+		ewarn "root device name!"
+	fi
+}

diff --git a/sys-apps/kexec-tools/metadata.xml b/sys-apps/kexec-tools/metadata.xml
new file mode 100644
index 0000000..d56b5de
--- /dev/null
+++ b/sys-apps/kexec-tools/metadata.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "https://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+  <maintainer type="project">
+    <email>base-system@gentoo.org</email>
+    <name>Gentoo Base System</name>
+  </maintainer>
+  <use>
+    <flag name="lzma">Enables support for LZMA compressed kernel images</flag>
+    <flag name="booke">Include support for Book-E memory management</flag>
+    <flag name="xen">Enable extended xen support</flag>
+  </use>
+</pkgmetadata>


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-07-02 11:44 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-07-02 11:44 [gentoo-commits] proj/riscv:master commit in: sys-apps/kexec-tools/, sys-apps/kexec-tools/files/ Yixun Lan
  -- strict thread matches above, loose matches on Subject: below --
2022-07-02 11:44 Yixun Lan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox