Gentoo Archives: gentoo-commits

From: Yixun Lan <dlan@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/riscv:master commit in: sys-apps/kexec-tools/, sys-apps/kexec-tools/files/
Date: Sat, 02 Jul 2022 11:44:38
Message-Id: 1656754563.31108ac2c9aa23918f46ff3f56e3084d0bb725f2.dlan@gentoo
1 commit: 31108ac2c9aa23918f46ff3f56e3084d0bb725f2
2 Author: Yixun Lan <dlan <AT> gentoo <DOT> org>
3 AuthorDate: Sat Jul 2 09:35:25 2022 +0000
4 Commit: Yixun Lan <dlan <AT> gentoo <DOT> org>
5 CommitDate: Sat Jul 2 09:36:03 2022 +0000
6 URL: https://gitweb.gentoo.org/proj/riscv.git/commit/?id=31108ac2
7
8 sys-apps/kexec-tools: add riscv support
9
10 Signed-off-by: Yixun Lan <dlan <AT> gentoo.org>
11
12 .../files/kexec-tools-2.0.24-riscv.patch | 1513 ++++++++++++++++++++
13 sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild | 9 +-
14 2 files changed, 1516 insertions(+), 6 deletions(-)
15
16 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
17 new file mode 100644
18 index 0000000..1fab497
19 --- /dev/null
20 +++ b/sys-apps/kexec-tools/files/kexec-tools-2.0.24-riscv.patch
21 @@ -0,0 +1,1513 @@
22 +From 6975082921e577ed5034e56010d2b433aeaf6907 Mon Sep 17 00:00:00 2001
23 +From: Nick Kossifidis <mick@×××××××××.gr>
24 +Date: Tue, 5 Oct 2021 15:01:19 +0300
25 +Subject: [PATCH] RISC-V: Add support for riscv kexec/kdump on kexec-tools
26 +
27 +This patch adds support for loading the ELF kernel image. It parses
28 +the current/provided device tree to determine the system's memory
29 +layout, and /proc/iomem for the various kernel segments.
30 +
31 +Tested on Qemu's rv64 virt machine.
32 +
33 +Signed-off-by: Nick Kossifidis <mick@×××××××××.gr>
34 +---
35 + configure.ac | 3 +
36 + include/elf.h | 3 +-
37 + kexec/Makefile | 1 +
38 + kexec/arch/riscv/Makefile | 35 ++
39 + kexec/arch/riscv/crashdump-riscv.c | 140 ++++++++
40 + kexec/arch/riscv/include/arch/options.h | 43 +++
41 + kexec/arch/riscv/kexec-elf-riscv.c | 255 ++++++++++++++
42 + kexec/arch/riscv/kexec-riscv.c | 364 +++++++++++++++++++
43 + kexec/arch/riscv/kexec-riscv.h | 32 ++
44 + kexec/dt-ops.c | 442 +++++++++++++++++++++++-
45 + kexec/dt-ops.h | 7 +
46 + kexec/kexec-syscall.h | 4 +
47 + purgatory/Makefile | 1 +
48 + purgatory/arch/riscv/Makefile | 7 +
49 + 14 files changed, 1335 insertions(+), 2 deletions(-)
50 + create mode 100644 kexec/arch/riscv/Makefile
51 + create mode 100644 kexec/arch/riscv/crashdump-riscv.c
52 + create mode 100644 kexec/arch/riscv/include/arch/options.h
53 + create mode 100644 kexec/arch/riscv/kexec-elf-riscv.c
54 + create mode 100644 kexec/arch/riscv/kexec-riscv.c
55 + create mode 100644 kexec/arch/riscv/kexec-riscv.h
56 + create mode 100644 purgatory/arch/riscv/Makefile
57 +
58 +diff --git a/configure.ac b/configure.ac
59 +index cf8e8a2..d21552c 100644
60 +--- a/configure.ac
61 ++++ b/configure.ac
62 +@@ -58,6 +58,9 @@ case $target_cpu in
63 + hppa*)
64 + ARCH="hppa"
65 + ;;
66 ++ riscv32|riscv64 )
67 ++ ARCH="riscv"
68 ++ ;;
69 + * )
70 + AC_MSG_ERROR([unsupported architecture $target_cpu])
71 + ;;
72 +diff --git a/include/elf.h b/include/elf.h
73 +index b7677a2..123f167 100644
74 +--- a/include/elf.h
75 ++++ b/include/elf.h
76 +@@ -259,7 +259,8 @@ typedef struct
77 + #define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */
78 + #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
79 + #define EM_AARCH64 183 /* ARM AARCH64 */
80 +-#define EM_NUM 184
81 ++#define EM_RISCV 243 /* RISC-V */
82 ++#define EM_NUM 244
83 +
84 + /* If it is necessary to assign new unofficial EM_* values, please
85 + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
86 +diff --git a/kexec/Makefile b/kexec/Makefile
87 +index e69e309..ca17831 100644
88 +--- a/kexec/Makefile
89 ++++ b/kexec/Makefile
90 +@@ -88,6 +88,7 @@ include $(srcdir)/kexec/arch/mips/Makefile
91 + include $(srcdir)/kexec/arch/cris/Makefile
92 + include $(srcdir)/kexec/arch/ppc/Makefile
93 + include $(srcdir)/kexec/arch/ppc64/Makefile
94 ++include $(srcdir)/kexec/arch/riscv/Makefile
95 + include $(srcdir)/kexec/arch/s390/Makefile
96 + include $(srcdir)/kexec/arch/sh/Makefile
97 + include $(srcdir)/kexec/arch/x86_64/Makefile
98 +diff --git a/kexec/arch/riscv/Makefile b/kexec/arch/riscv/Makefile
99 +new file mode 100644
100 +index 0000000..f26cc90
101 +--- /dev/null
102 ++++ b/kexec/arch/riscv/Makefile
103 +@@ -0,0 +1,35 @@
104 ++#
105 ++# kexec riscv
106 ++#
107 ++riscv_KEXEC_SRCS = kexec/arch/riscv/kexec-riscv.c
108 ++riscv_KEXEC_SRCS += kexec/arch/riscv/kexec-elf-riscv.c
109 ++riscv_KEXEC_SRCS += kexec/arch/riscv/crashdump-riscv.c
110 ++
111 ++riscv_MEM_REGIONS = kexec/mem_regions.c
112 ++
113 ++riscv_DT_OPS += kexec/dt-ops.c
114 ++
115 ++riscv_ARCH_REUSE_INITRD =
116 ++
117 ++riscv_CPPFLAGS += -I $(srcdir)/kexec/
118 ++
119 ++dist += kexec/arch/riscv/Makefile $(riscv_KEXEC_SRCS) \
120 ++ kexec/arch/riscv/kexec-riscv.h \
121 ++ kexec/arch/riscv/include/arch/options.h
122 ++
123 ++ifdef HAVE_LIBFDT
124 ++
125 ++LIBS += -lfdt
126 ++
127 ++else
128 ++
129 ++include $(srcdir)/kexec/libfdt/Makefile.libfdt
130 ++
131 ++libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%)
132 ++
133 ++riscv_CPPFLAGS += -I$(srcdir)/kexec/libfdt
134 ++
135 ++riscv_KEXEC_SRCS += $(libfdt_SRCS)
136 ++
137 ++endif
138 ++
139 +diff --git a/kexec/arch/riscv/crashdump-riscv.c b/kexec/arch/riscv/crashdump-riscv.c
140 +new file mode 100644
141 +index 0000000..7fc041e
142 +--- /dev/null
143 ++++ b/kexec/arch/riscv/crashdump-riscv.c
144 +@@ -0,0 +1,140 @@
145 ++#include <errno.h>
146 ++#include <linux/elf.h>
147 ++#include <unistd.h>
148 ++
149 ++#include "kexec.h"
150 ++#include "crashdump.h"
151 ++#include "kexec-elf.h"
152 ++#include "mem_regions.h"
153 ++
154 ++static struct crash_elf_info elf_info = {
155 ++#if __riscv_xlen == 64
156 ++ .class = ELFCLASS64,
157 ++#else
158 ++ .class = ELFCLASS32,
159 ++#endif
160 ++ .data = ELFDATA2LSB,
161 ++ .machine = EM_RISCV,
162 ++};
163 ++
164 ++static struct memory_ranges crash_mem_ranges = {0};
165 ++struct memory_range elfcorehdr_mem = {0};
166 ++
167 ++static unsigned long long get_page_offset(struct kexec_info *info)
168 ++{
169 ++ unsigned long long vaddr_off = 0;
170 ++ unsigned long long page_size = sysconf(_SC_PAGESIZE);
171 ++ unsigned long long init_start = get_kernel_sym("_sinittext");
172 ++
173 ++ /*
174 ++ * Begining of init section is aligned to page size
175 ++ */
176 ++ vaddr_off = init_start - page_size;
177 ++
178 ++ return vaddr_off;
179 ++}
180 ++
181 ++int load_elfcorehdr(struct kexec_info *info)
182 ++{
183 ++ struct memory_range crashkern_range = {0};
184 ++ struct memory_range *ranges = NULL;
185 ++ unsigned long start = 0;
186 ++ unsigned long end = 0;
187 ++ unsigned long buf_size = 0;
188 ++ unsigned long elfcorehdr_addr = 0;
189 ++ void* buf = NULL;
190 ++ int i = 0;
191 ++ int ret = 0;
192 ++
193 ++ ret = parse_iomem_single("Kernel code\n", &start, NULL);
194 ++ if (ret) {
195 ++ fprintf(stderr, "Cannot determine kernel physical base addr\n");
196 ++ return -EINVAL;
197 ++ }
198 ++ elf_info.kern_paddr_start = start;
199 ++
200 ++ ret = parse_iomem_single("Kernel bss\n", NULL, &end);
201 ++ if (ret) {
202 ++ fprintf(stderr, "Cannot determine kernel physical bss addr\n");
203 ++ return -EINVAL;
204 ++ }
205 ++ elf_info.kern_paddr_start = start;
206 ++ elf_info.kern_size = end - start;
207 ++
208 ++ elf_info.kern_vaddr_start = get_kernel_sym("_text");
209 ++ if (!elf_info.kern_vaddr_start) {
210 ++ elf_info.kern_vaddr_start = UINT64_MAX;
211 ++ }
212 ++
213 ++ elf_info.page_offset = get_page_offset(info);
214 ++ dbgprintf("page_offset: %016llx\n", elf_info.page_offset);
215 ++
216 ++ ret = parse_iomem_single("Crash kernel\n", &start, &end);
217 ++ if (ret) {
218 ++ fprintf(stderr, "Cannot determine kernel physical bss addr\n");
219 ++ return -EINVAL;
220 ++ }
221 ++ crashkern_range.start = start;
222 ++ crashkern_range.end = end;
223 ++ crashkern_range.type = RANGE_RESERVED;
224 ++
225 ++ ranges = info->memory_range;
226 ++ for (i = 0; i < info->memory_ranges; i++) {
227 ++ ret = mem_regions_alloc_and_add(&crash_mem_ranges,
228 ++ ranges[i].start,
229 ++ ranges[i].end - ranges[i].start,
230 ++ ranges[i].type);
231 ++ if (ret ) {
232 ++ fprintf(stderr, "Could not create crash_mem_ranges\n");
233 ++ return ret;
234 ++ }
235 ++ }
236 ++
237 ++ ret = mem_regions_alloc_and_exclude(&crash_mem_ranges,
238 ++ &crashkern_range);
239 ++ if (ret) {
240 ++ fprintf(stderr, "Could not exclude crashkern_range\n");
241 ++ return ret;
242 ++ }
243 ++
244 ++#if __riscv_xlen == 64
245 ++ crash_create_elf64_headers(info, &elf_info, crash_mem_ranges.ranges,
246 ++ crash_mem_ranges.size, &buf, &buf_size,
247 ++ ELF_CORE_HEADER_ALIGN);
248 ++
249 ++#else
250 ++ crash_create_elf32_headers(info, &elf_info, crash_mem_ranges.ranges,
251 ++ crash_mem_ranges.size, &buf, &buf_size,
252 ++ ELF_CORE_HEADER_ALIGN);
253 ++#endif
254 ++
255 ++
256 ++ elfcorehdr_addr = add_buffer_phys_virt(info, buf, buf_size,
257 ++ buf_size, 0,
258 ++ crashkern_range.start,
259 ++ crashkern_range.end,
260 ++ -1, 0);
261 ++
262 ++ elfcorehdr_mem.start = elfcorehdr_addr;
263 ++ elfcorehdr_mem.end = elfcorehdr_addr + buf_size - 1;
264 ++
265 ++ dbgprintf("%s: elfcorehdr 0x%llx-0x%llx\n", __func__,
266 ++ elfcorehdr_mem.start, elfcorehdr_mem.end);
267 ++
268 ++ return 0;
269 ++}
270 ++
271 ++int is_crashkernel_mem_reserved(void)
272 ++{
273 ++ uint64_t start = 0;
274 ++ uint64_t end = 0;
275 ++
276 ++ return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ?
277 ++ (start != end) : 0;
278 ++}
279 ++
280 ++int get_crash_kernel_load_range(uint64_t *start, uint64_t *end)
281 ++{
282 ++ return parse_iomem_single("Crash kernel\n", start, end);
283 ++}
284 ++
285 +diff --git a/kexec/arch/riscv/include/arch/options.h b/kexec/arch/riscv/include/arch/options.h
286 +new file mode 100644
287 +index 0000000..7c24184
288 +--- /dev/null
289 ++++ b/kexec/arch/riscv/include/arch/options.h
290 +@@ -0,0 +1,43 @@
291 ++#ifndef KEXEC_ARCH_RISCV_OPTIONS_H
292 ++#define KEXEC_ARCH_RISCV_OPTIONS_H
293 ++
294 ++#define OPT_APPEND ((OPT_MAX)+0)
295 ++#define OPT_DTB ((OPT_MAX)+1)
296 ++#define OPT_INITRD ((OPT_MAX)+2)
297 ++#define OPT_CMDLINE ((OPT_MAX)+3)
298 ++#define OPT_REUSE_CMDLINE ((OPT_MAX)+4)
299 ++#define OPT_ARCH_MAX ((OPT_MAX)+5)
300 ++
301 ++/* Options relevant to the architecture (excluding loader-specific ones),
302 ++ * in this case none:
303 ++ */
304 ++#define KEXEC_ARCH_OPTIONS \
305 ++ KEXEC_OPTIONS \
306 ++ { "append", 1, 0, OPT_APPEND}, \
307 ++ { "dtb", 1, 0, OPT_DTB }, \
308 ++ { "initrd", 1, 0, OPT_INITRD }, \
309 ++ { "command-line", 1, 0, OPT_CMDLINE}, \
310 ++ { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \
311 ++
312 ++
313 ++#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
314 ++
315 ++/* The following two #defines list ALL of the options added by all of the
316 ++ * architecture's loaders.
317 ++ * o main() uses this complete list to scan for its options, ignoring
318 ++ * arch-specific/loader-specific ones.
319 ++ * o Then, arch_process_options() uses this complete list to scan for its
320 ++ * options, ignoring general/loader-specific ones.
321 ++ * o Then, the file_type[n].load re-scans for options, using
322 ++ * KEXEC_ARCH_OPTIONS plus its loader-specific options subset.
323 ++ * Any unrecognised options cause an error here.
324 ++ *
325 ++ * This is done so that main()'s/arch_process_options()'s getopt_long() calls
326 ++ * don't choose a kernel filename from random arguments to options they don't
327 ++ * recognise -- as they now recognise (if not act upon) all possible options.
328 ++ */
329 ++#define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS
330 ++
331 ++#define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR
332 ++
333 ++#endif /* KEXEC_ARCH_RISCV_OPTIONS_H */
334 +diff --git a/kexec/arch/riscv/kexec-elf-riscv.c b/kexec/arch/riscv/kexec-elf-riscv.c
335 +new file mode 100644
336 +index 0000000..f3c011c
337 +--- /dev/null
338 ++++ b/kexec/arch/riscv/kexec-elf-riscv.c
339 +@@ -0,0 +1,255 @@
340 ++/* SPDX-License-Identifier: GPL-2.0 */
341 ++/*
342 ++ * Copyright (C) 2019 FORTH-ICS/CARV
343 ++ * Nick Kossifidis <mick@×××××××××.gr>
344 ++ */
345 ++
346 ++#include "kexec.h"
347 ++#include "dt-ops.h" /* For dtb_set/clear_initrd() */
348 ++#include <elf.h> /* For ELF header handling */
349 ++#include <errno.h> /* For EFBIG/EINVAL */
350 ++#include <unistd.h> /* For getpagesize() */
351 ++#include "kexec-syscall.h" /* For KEXEC_ON_CRASH */
352 ++#include "kexec-riscv.h"
353 ++
354 ++
355 ++/*********\
356 ++* HELPERS *
357 ++\*********/
358 ++
359 ++/*
360 ++ * Go through the available physical memory regions and
361 ++ * find one that can hold an image of the specified size.
362 ++ * Note: This is called after get_memory_ranges so
363 ++ * info->memory_range[] should be populated. Also note that
364 ++ * memory ranges are sorted, so we'll return the first region
365 ++ * that's big enough for holding the image.
366 ++ */
367 ++static int elf_riscv_find_pbase(struct kexec_info *info, off_t *addr,
368 ++ off_t size)
369 ++{
370 ++ int i = 0;
371 ++ off_t start = 0;
372 ++ off_t end = 0;
373 ++ int ret = 0;
374 ++
375 ++ /*
376 ++ * If this image is for a crash kernel, use the region
377 ++ * the primary kernel has already reserved for us.
378 ++ */
379 ++ if (info->kexec_flags & KEXEC_ON_CRASH) {
380 ++ ret = get_crash_kernel_load_range((uint64_t *) &start,
381 ++ (uint64_t *) &end);
382 ++ if (!ret) {
383 ++ /*
384 ++ * Kernel should be aligned to the nearest
385 ++ * hugepage (2MB for RV64, 4MB for RV32).
386 ++ */
387 ++#if __riscv_xlen == 64
388 ++ start = _ALIGN_UP(start, 0x200000);
389 ++#else
390 ++ start = _ALIGN_UP(start, 0x400000);
391 ++#endif
392 ++ if (end > start && ((end - start) >= size)) {
393 ++ *addr = start;
394 ++ return 0;
395 ++ }
396 ++
397 ++ return -EFBIG;
398 ++ } else
399 ++ return ENOCRASHKERNEL;
400 ++ }
401 ++
402 ++ for (i = 0; i < info->memory_ranges; i++) {
403 ++ if (info->memory_range[i].type != RANGE_RAM)
404 ++ continue;
405 ++
406 ++ start = info->memory_range[i].start;
407 ++ end = info->memory_range[i].end;
408 ++
409 ++#if __riscv_xlen == 64
410 ++ start = _ALIGN_UP(start, 0x200000);
411 ++#else
412 ++ start = _ALIGN_UP(start, 0x400000);
413 ++#endif
414 ++
415 ++ if (end > start && ((end - start) >= size)) {
416 ++ *addr = start;
417 ++ return 0;
418 ++ }
419 ++ }
420 ++
421 ++ return -EFBIG;
422 ++}
423 ++
424 ++/**************\
425 ++* ENTRY POINTS *
426 ++\**************/
427 ++
428 ++int elf_riscv_probe(const char *buf, off_t len)
429 ++{
430 ++ struct mem_ehdr ehdr = {0};
431 ++ int ret = 0;
432 ++
433 ++ ret = build_elf_exec_info(buf, len, &ehdr, 0);
434 ++ if (ret < 0)
435 ++ goto cleanup;
436 ++
437 ++ if (ehdr.e_machine != EM_RISCV) {
438 ++ fprintf(stderr, "Not for this architecture.\n");
439 ++ ret = -EINVAL;
440 ++ goto cleanup;
441 ++ }
442 ++
443 ++ ret = 0;
444 ++
445 ++ cleanup:
446 ++ free_elf_info(&ehdr);
447 ++ return ret;
448 ++}
449 ++
450 ++void elf_riscv_usage(void)
451 ++{
452 ++}
453 ++
454 ++int elf_riscv_load(int argc, char **argv, const char *buf, off_t len,
455 ++ struct kexec_info *info)
456 ++{
457 ++ struct mem_ehdr ehdr = {0};
458 ++ struct mem_phdr *phdr = NULL;
459 ++ off_t new_base_addr = 0;
460 ++ off_t kernel_size = 0;
461 ++ off_t page_size = getpagesize();
462 ++ off_t max_addr = 0;
463 ++ off_t old_base_addr = 0;
464 ++ off_t old_start_addr = 0;
465 ++ int i = 0;
466 ++ int ret = 0;
467 ++
468 ++ if (info->file_mode) {
469 ++ fprintf(stderr, "kexec_file not supported on this "
470 ++ "architecture\n");
471 ++ return -EINVAL;
472 ++ }
473 ++
474 ++ /* Parse the ELF file */
475 ++ ret = build_elf_exec_info(buf, len, &ehdr, 0);
476 ++ if (ret < 0) {
477 ++ fprintf(stderr, "ELF exec parse failed\n");
478 ++ return -EINVAL;
479 ++ }
480 ++
481 ++ max_addr = elf_max_addr(&ehdr);
482 ++ old_base_addr = max_addr;
483 ++ old_start_addr = max_addr;
484 ++
485 ++ /*
486 ++ * Get the memory footprint, base physical
487 ++ * and start address of the ELF image
488 ++ */
489 ++ for (i = 0; i < ehdr.e_phnum; i++) {
490 ++ phdr = &ehdr.e_phdr[i];
491 ++ if (phdr->p_type != PT_LOAD)
492 ++ continue;
493 ++
494 ++ /*
495 ++ * Note: According to ELF spec the loadable regions
496 ++ * are sorted on p_vaddr, not p_paddr.
497 ++ */
498 ++ if (old_base_addr > phdr->p_paddr)
499 ++ old_base_addr = phdr->p_paddr;
500 ++
501 ++ if (phdr->p_vaddr == ehdr.e_entry ||
502 ++ phdr->p_paddr == ehdr.e_entry)
503 ++ old_start_addr = phdr->p_paddr;
504 ++
505 ++ kernel_size += _ALIGN_UP(phdr->p_memsz, page_size);
506 ++ }
507 ++
508 ++ if (old_base_addr == max_addr || kernel_size == 0) {
509 ++ fprintf(stderr, "No loadable segments present on the "
510 ++ "provided ELF image\n");
511 ++ return -EINVAL;
512 ++ }
513 ++
514 ++ if (old_start_addr == max_addr) {
515 ++ fprintf(stderr, "Could not find the entry point address of "
516 ++ "provided ELF image\n");
517 ++ return -EINVAL;
518 ++ }
519 ++
520 ++ dbgprintf("Got ELF with total memsz %luKB\n"
521 ++ "Base paddr: 0x%lX, start_addr: 0x%lX\n",
522 ++ kernel_size / 1024, old_base_addr, old_start_addr);
523 ++
524 ++ /* Get a continuous physical region that can hold the kernel */
525 ++ ret = elf_riscv_find_pbase(info, &new_base_addr, kernel_size);
526 ++ if (ret < 0) {
527 ++ fprintf(stderr, "Could not find a memory region for the "
528 ++ "provided ELF image\n");
529 ++ return ret;
530 ++ }
531 ++
532 ++ dbgprintf("New base paddr for the ELF: 0x%lX\n", new_base_addr);
533 ++
534 ++ /* Re-set the base physical address of the ELF */
535 ++ for (i = 0; i < ehdr.e_phnum; i++) {
536 ++ phdr = &ehdr.e_phdr[i];
537 ++ if (phdr->p_type != PT_LOAD)
538 ++ continue;
539 ++
540 ++ phdr->p_paddr -= old_base_addr;
541 ++ phdr->p_paddr += new_base_addr;
542 ++ }
543 ++
544 ++ /* Re-set the entry point address */
545 ++ ehdr.e_entry = (old_start_addr - old_base_addr) + new_base_addr;
546 ++ info->entry = (void *) ehdr.e_entry;
547 ++ dbgprintf("New entry point for the ELF: 0x%llX\n", ehdr.e_entry);
548 ++
549 ++
550 ++ /* Load the ELF executable */
551 ++ ret = elf_exec_load(&ehdr, info);
552 ++ if (ret < 0) {
553 ++ fprintf(stderr, "ELF exec load failed\n");
554 ++ return ret;
555 ++ }
556 ++
557 ++ ret = load_extra_segments(info, new_base_addr,
558 ++ kernel_size, max_addr);
559 ++ return ret;
560 ++}
561 ++
562 ++
563 ++/*******\
564 ++* STUBS *
565 ++\*******/
566 ++
567 ++int machine_verify_elf_rel(struct mem_ehdr *ehdr)
568 ++{
569 ++ if (ehdr->ei_data != ELFDATA2LSB)
570 ++ return 0;
571 ++#if __riscv_xlen == 64
572 ++ if (ehdr->ei_class != ELFCLASS64)
573 ++#else
574 ++ if (ehdr->ei_class != ELFCLASS32)
575 ++#endif
576 ++ return 0;
577 ++ if (ehdr->e_machine != EM_RISCV)
578 ++ return 0;
579 ++ return 1;
580 ++}
581 ++
582 ++void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr),
583 ++ struct mem_sym *UNUSED(sym),
584 ++ unsigned long r_type,
585 ++ void *UNUSED(location),
586 ++ unsigned long UNUSED(address),
587 ++ unsigned long UNUSED(value))
588 ++{
589 ++ switch (r_type) {
590 ++ default:
591 ++ die("Unknown rela relocation: %lu\n", r_type);
592 ++ break;
593 ++ }
594 ++}
595 +diff --git a/kexec/arch/riscv/kexec-riscv.c b/kexec/arch/riscv/kexec-riscv.c
596 +new file mode 100644
597 +index 0000000..d05c47d
598 +--- /dev/null
599 ++++ b/kexec/arch/riscv/kexec-riscv.c
600 +@@ -0,0 +1,364 @@
601 ++/* SPDX-License-Identifier: GPL-2.0 */
602 ++/*
603 ++ * Copyright (C) 2019 FORTH-ICS/CARV
604 ++ * Nick Kossifidis <mick@×××××××××.gr>
605 ++ */
606 ++
607 ++#include "kexec-syscall.h" /* For KEXEC_ARCH_RISCV */
608 ++#include "kexec.h" /* For OPT_MAX and concat_cmdline() */
609 ++#include "mem_regions.h" /* For mem_regions_sort() */
610 ++#include "dt-ops.h" /* For dtb_set_bootargs() */
611 ++#include <arch/options.h> /* For KEXEC_ARCH_OPTIONS */
612 ++#include <getopt.h> /* For struct option */
613 ++#include <sys/stat.h> /* For stat() and struct stat */
614 ++#include <stdlib.h> /* For free() */
615 ++#include <errno.h> /* For EINVAL */
616 ++#include <libfdt.h> /* For DeviceTree handling */
617 ++#include "kexec-riscv.h"
618 ++
619 ++const struct arch_map_entry arches[] = {
620 ++ { "riscv32", KEXEC_ARCH_RISCV },
621 ++ { "riscv64", KEXEC_ARCH_RISCV },
622 ++ { NULL, 0 },
623 ++};
624 ++
625 ++
626 ++struct file_type file_type[] = {
627 ++ {"elf-riscv", elf_riscv_probe, elf_riscv_load, elf_riscv_usage},
628 ++};
629 ++int file_types = sizeof(file_type) / sizeof(file_type[0]);
630 ++
631 ++static const char riscv_opts_usage[] =
632 ++" --append=STRING Append STRING to the kernel command line.\n"
633 ++" --dtb=FILE Use FILE as the device tree blob.\n"
634 ++" --initrd=FILE Use FILE as the kernel initial ramdisk.\n"
635 ++" --cmdline=STRING Use STRING as the kernel's command line.\n"
636 ++" --reuse-cmdline Use kernel command line from running system.\n";
637 ++
638 ++static struct riscv_opts arch_options = {0};
639 ++static struct fdt_image provided_fdt = {0};
640 ++static struct memory_ranges sysmem_ranges = {0};
641 ++
642 ++/****************\
643 ++* COMMON HELPERS *
644 ++\****************/
645 ++
646 ++int load_extra_segments(struct kexec_info *info, uint64_t kernel_base,
647 ++ uint64_t kernel_size, uint64_t max_addr)
648 ++{
649 ++ struct fdt_image *fdt = arch_options.fdt;
650 ++ char *initrd_buf = NULL;
651 ++ off_t initrd_size = 0;
652 ++ uint64_t initrd_base = 0;
653 ++ uint64_t start = 0;
654 ++ uint64_t end = 0;
655 ++ uint64_t min_usable = kernel_base + kernel_size;
656 ++ uint64_t max_usable = max_addr;
657 ++ int ret = 0;
658 ++
659 ++ /* Prepare the device tree */
660 ++ if (info->kexec_flags & KEXEC_ON_CRASH) {
661 ++ ret = load_elfcorehdr(info);
662 ++ if (ret) {
663 ++ fprintf(stderr, "Couldn't create elfcorehdr\n");
664 ++ return ret;
665 ++ }
666 ++
667 ++ ret = dtb_add_range_property(&fdt->buf, &fdt->size,
668 ++ elfcorehdr_mem.start, elfcorehdr_mem.end,
669 ++ "chosen", "linux,elfcorehdr");
670 ++ if (ret) {
671 ++ fprintf(stderr, "Couldn't add elfcorehdr to fdt\n");
672 ++ return ret;
673 ++ }
674 ++
675 ++ ret = get_crash_kernel_load_range(&start, &end);
676 ++ if (ret) {
677 ++ fprintf(stderr, "Couldn't get crashkenel region\n");
678 ++ return ret;
679 ++ }
680 ++
681 ++ ret = dtb_add_range_property(&fdt->buf, &fdt->size, start, end,
682 ++ "memory", "linux,usable-memory");
683 ++ if (ret) {
684 ++ fprintf(stderr, "Couldn't add usable-memory to fdt\n");
685 ++ return ret;
686 ++ }
687 ++
688 ++ max_usable = end;
689 ++ } else {
690 ++ /*
691 ++ * Make sure we remove elfcorehdr and usable-memory
692 ++ * when switching from crash kernel to a normal one.
693 ++ */
694 ++ dtb_delete_property(fdt->buf, "chosen", "linux,elfcorehdr");
695 ++ dtb_delete_property(fdt->buf, "memory", "linux,usable-memory");
696 ++ }
697 ++
698 ++ /* Do we need to include an initrd image ? */
699 ++ if (!arch_options.initrd_path && !arch_options.initrd_end)
700 ++ dtb_clear_initrd(&fdt->buf, &fdt->size);
701 ++ else if (arch_options.initrd_path) {
702 ++ if (arch_options.initrd_end)
703 ++ fprintf(stderr, "Warning: An initrd image was provided"
704 ++ ", will ignore reuseinitrd\n");
705 ++
706 ++ initrd_buf = slurp_file(arch_options.initrd_path,
707 ++ &initrd_size);
708 ++ if (!initrd_buf) {
709 ++ fprintf(stderr, "Couldn't read provided initrd\n");
710 ++ return -EINVAL;
711 ++ }
712 ++
713 ++ initrd_base = add_buffer_phys_virt(info, initrd_buf,
714 ++ initrd_size,
715 ++ initrd_size, 0,
716 ++ min_usable,
717 ++ max_usable, -1, 0);
718 ++
719 ++ dtb_set_initrd(&fdt->buf, &fdt->size, initrd_base,
720 ++ initrd_base + initrd_size);
721 ++
722 ++ dbgprintf("Base addr for initrd image: 0x%lX\n", initrd_base);
723 ++ min_usable = initrd_base;
724 ++ }
725 ++
726 ++ /* Add device tree */
727 ++ add_buffer_phys_virt(info, fdt->buf, fdt->size, fdt->size, 0,
728 ++ min_usable, max_usable, -1, 0);
729 ++
730 ++ return 0;
731 ++}
732 ++
733 ++
734 ++/**************\
735 ++* ENTRY POINTS *
736 ++\**************/
737 ++
738 ++void arch_usage(void)
739 ++{
740 ++ printf(riscv_opts_usage);
741 ++}
742 ++
743 ++int arch_process_options(int argc, char **argv)
744 ++{
745 ++ static const struct option options[] = {
746 ++ KEXEC_ARCH_OPTIONS
747 ++ { 0 },
748 ++ };
749 ++ static const char short_options[] = KEXEC_ARCH_OPT_STR;
750 ++ struct stat st = {0};
751 ++ char *append = NULL;
752 ++ char *cmdline = NULL;
753 ++ void *tmp = NULL;
754 ++ off_t tmp_size = 0;
755 ++ int opt = 0;
756 ++ int ret = 0;
757 ++
758 ++ while ((opt = getopt_long(argc, argv, short_options,
759 ++ options, 0)) != -1) {
760 ++ switch (opt) {
761 ++ case OPT_APPEND:
762 ++ append = optarg;
763 ++ break;
764 ++ case OPT_CMDLINE:
765 ++ if (cmdline)
766 ++ fprintf(stderr,
767 ++ "Warning: Kernel's cmdline "
768 ++ "set twice !\n");
769 ++ cmdline = optarg;
770 ++ break;
771 ++ case OPT_REUSE_CMDLINE:
772 ++ if (cmdline)
773 ++ fprintf(stderr,
774 ++ "Warning: Kernel's cmdline "
775 ++ "set twice !\n");
776 ++ cmdline = get_command_line();
777 ++ break;
778 ++ case OPT_DTB:
779 ++ ret = stat(optarg, &st);
780 ++ if (ret) {
781 ++ fprintf(stderr,
782 ++ "Could not find the provided dtb !\n");
783 ++ return -EINVAL;
784 ++ }
785 ++ arch_options.fdt_path = optarg;
786 ++ break;
787 ++ case OPT_INITRD:
788 ++ ret = stat(optarg, &st);
789 ++ if (ret) {
790 ++ fprintf(stderr,
791 ++ "Could not find the provided "
792 ++ "initrd image !\n");
793 ++ return -EINVAL;
794 ++ }
795 ++ arch_options.initrd_path = optarg;
796 ++ break;
797 ++ default:
798 ++ break;
799 ++ }
800 ++ }
801 ++
802 ++ /* Handle Kernel's command line */
803 ++ if (append && !cmdline)
804 ++ fprintf(stderr, "Warning: No cmdline provided, "
805 ++ "using append string as cmdline\n");
806 ++ if (!append && !cmdline)
807 ++ fprintf(stderr, "Warning: No cmdline or append string "
808 ++ "provided\n");
809 ++
810 ++ if (append || cmdline)
811 ++ /*
812 ++ * Note that this also handles the case where "cmdline"
813 ++ * or "append" is NULL.
814 ++ */
815 ++ arch_options.cmdline = concat_cmdline(cmdline, append);
816 ++
817 ++ /* Handle FDT image */
818 ++ if (!arch_options.fdt_path) {
819 ++ ret = stat("/sys/firmware/fdt", &st);
820 ++ if (ret) {
821 ++ fprintf(stderr, "No dtb provided and "
822 ++ "/sys/firmware/fdt is not present\n");
823 ++ return -EINVAL;
824 ++ }
825 ++ fprintf(stderr, "Warning: No dtb provided, "
826 ++ "using /sys/firmware/fdt\n");
827 ++ arch_options.fdt_path = "/sys/firmware/fdt";
828 ++ }
829 ++
830 ++ tmp = slurp_file(arch_options.fdt_path, &tmp_size);
831 ++ if (!tmp) {
832 ++ fprintf(stderr, "Couldn't read provided fdt\n");
833 ++ return -EINVAL;
834 ++ }
835 ++
836 ++ ret = fdt_check_header(tmp);
837 ++ if (ret) {
838 ++ fprintf(stderr, "Got an ivalid fdt image !\n");
839 ++ free(tmp);
840 ++ return -EINVAL;
841 ++ }
842 ++ provided_fdt.buf = tmp;
843 ++ provided_fdt.size = tmp_size;
844 ++
845 ++ if (arch_options.cmdline) {
846 ++ ret = dtb_set_bootargs(&provided_fdt.buf, &provided_fdt.size,
847 ++ arch_options.cmdline);
848 ++ if (ret < 0) {
849 ++ fprintf(stderr, "Could not set bootargs on "
850 ++ "the fdt image\n");
851 ++ return ret;
852 ++ }
853 ++ }
854 ++
855 ++ arch_options.fdt = &provided_fdt;
856 ++
857 ++ return 0;
858 ++}
859 ++
860 ++/*
861 ++ * This one is called after arch_process_options so we already
862 ++ * have an fdt image in place.
863 ++ */
864 ++void arch_reuse_initrd(void)
865 ++{
866 ++ const uint32_t *prop32 = NULL;
867 ++ uint32_t addr_cells = 0;
868 ++ const void *prop = 0;
869 ++ int prop_size = 0;
870 ++ uint64_t initrd_start = 0;
871 ++ uint64_t initrd_end = 0;
872 ++ int chosen_offset = 0;
873 ++ struct fdt_image *fdt = &provided_fdt;
874 ++
875 ++ chosen_offset = fdt_subnode_offset(fdt->buf, 0, "chosen");
876 ++ if (chosen_offset < 0) {
877 ++ fprintf(stderr, "No /chosen node found on fdt image "
878 ++ "unable to reuse initrd\n");
879 ++ return;
880 ++ }
881 ++
882 ++ prop32 = fdt_getprop(fdt->buf, 0, "#address-cells", NULL);
883 ++ if (!prop32) {
884 ++ fprintf(stderr, "No #address-cells property on root node\n");
885 ++ return;
886 ++ }
887 ++ addr_cells = be32_to_cpu(*prop32);
888 ++
889 ++ prop = fdt_getprop(fdt->buf, chosen_offset,
890 ++ "linux,initrd-start", &prop_size);
891 ++ if (!prop) {
892 ++ fprintf(stderr, "Could not get linux,initrd-start\n");
893 ++ return;
894 ++ }
895 ++ dtb_extract_int_property(&initrd_start, prop, addr_cells);
896 ++
897 ++ prop = fdt_getprop(fdt->buf, chosen_offset,
898 ++ "linux,initrd-end", &prop_size);
899 ++ if (!prop) {
900 ++ fprintf(stderr, "Could not get linux,initrd-end\n");
901 ++ return;
902 ++ }
903 ++ dtb_extract_int_property(&initrd_end, prop, addr_cells);
904 ++
905 ++ arch_options.initrd_start = initrd_start;
906 ++ arch_options.initrd_end = initrd_end;
907 ++ dbgprintf("initrd_start: 0x%lX, initrd_end: 0x%lX\n",
908 ++ initrd_start, initrd_end);
909 ++
910 ++}
911 ++
912 ++int get_memory_ranges(struct memory_range **range, int *num_ranges,
913 ++ unsigned long kexec_flags)
914 ++{
915 ++ const struct fdt_image *fdt = &provided_fdt;
916 ++ struct memory_ranges *extra_ranges = NULL;
917 ++ int i = 0;
918 ++ int ret = 0;
919 ++
920 ++ if (arch_options.initrd_start && arch_options.initrd_end) {
921 ++ int initrd_size = arch_options.initrd_end - arch_options.initrd_start;
922 ++ dbgprintf("Marking current intird image as reserved\n");
923 ++ ret = mem_regions_alloc_and_add(extra_ranges,
924 ++ arch_options.initrd_start,
925 ++ initrd_size,
926 ++ RANGE_RESERVED);
927 ++ if (ret)
928 ++ return ret;
929 ++ }
930 ++
931 ++ ret = dtb_get_memory_ranges(fdt->buf, &sysmem_ranges, extra_ranges);
932 ++ if (ret) {
933 ++ fprintf(stderr, "Could not get memory ranges from device tree (%i) !\n", ret);
934 ++ return ret;
935 ++ }
936 ++
937 ++ *range = sysmem_ranges.ranges;
938 ++ *num_ranges = sysmem_ranges.size;
939 ++
940 ++ dbgprintf("Memory regions:\n");
941 ++ for (i = 0; i < sysmem_ranges.size; i++) {
942 ++ dbgprintf("\t0x%llx - 0x%llx : %s (%i)\n",
943 ++ sysmem_ranges.ranges[i].start,
944 ++ sysmem_ranges.ranges[i].end,
945 ++ sysmem_ranges.ranges[i].type == RANGE_RESERVED ?
946 ++ "RANGE_RESERVED" : "RANGE_RAM",
947 ++ sysmem_ranges.ranges[i].type);
948 ++ }
949 ++
950 ++ return 0;
951 ++}
952 ++
953 ++/*******\
954 ++* STUBS *
955 ++\*******/
956 ++
957 ++int arch_compat_trampoline(struct kexec_info *UNUSED(info))
958 ++{
959 ++ return 0;
960 ++}
961 ++
962 ++void arch_update_purgatory(struct kexec_info *UNUSED(info))
963 ++{
964 ++}
965 +diff --git a/kexec/arch/riscv/kexec-riscv.h b/kexec/arch/riscv/kexec-riscv.h
966 +new file mode 100644
967 +index 0000000..c4323a6
968 +--- /dev/null
969 ++++ b/kexec/arch/riscv/kexec-riscv.h
970 +@@ -0,0 +1,32 @@
971 ++/* SPDX-License-Identifier: GPL-2.0 */
972 ++/*
973 ++ * Copyright (C) 2019 FORTH-ICS/CARV
974 ++ * Nick Kossifidis <mick@×××××××××.gr>
975 ++ */
976 ++
977 ++struct fdt_image {
978 ++ char *buf;
979 ++ off_t size;
980 ++};
981 ++
982 ++struct riscv_opts {
983 ++ char *cmdline;
984 ++ char *fdt_path;
985 ++ char *initrd_path;
986 ++ uint64_t initrd_start;
987 ++ uint64_t initrd_end;
988 ++ struct fdt_image *fdt;
989 ++};
990 ++
991 ++/* crashdump-riscv.c */
992 ++extern struct memory_range elfcorehdr_mem;
993 ++int load_elfcorehdr(struct kexec_info *info);
994 ++
995 ++/* kexec-riscv.c */
996 ++int load_extra_segments(struct kexec_info *info, uint64_t kernel_base,
997 ++ uint64_t kernel_size, uint64_t max_addr);
998 ++
999 ++int elf_riscv_probe(const char *buf, off_t len);
1000 ++void elf_riscv_usage(void);
1001 ++int elf_riscv_load(int argc, char **argv, const char *buf, off_t len,
1002 ++ struct kexec_info *info);
1003 +diff --git a/kexec/dt-ops.c b/kexec/dt-ops.c
1004 +index 0a96b75..3e285ab 100644
1005 +--- a/kexec/dt-ops.c
1006 ++++ b/kexec/dt-ops.c
1007 +@@ -4,9 +4,11 @@
1008 + #include <libfdt.h>
1009 + #include <stdio.h>
1010 + #include <stdlib.h>
1011 ++#include <stdbool.h>
1012 +
1013 + #include "kexec.h"
1014 + #include "dt-ops.h"
1015 ++#include "mem_regions.h"
1016 +
1017 + static const char n_chosen[] = "chosen";
1018 +
1019 +@@ -95,7 +97,7 @@ int dtb_set_property(char **dtb, off_t *dtb_size, const char *node,
1020 +
1021 + strcpy(new_node, "/");
1022 + strcat(new_node, node);
1023 +-
1024 ++
1025 + nodeoffset = fdt_path_offset(new_dtb, new_node);
1026 +
1027 + if (nodeoffset == -FDT_ERR_NOTFOUND) {
1028 +@@ -174,3 +176,441 @@ int dtb_delete_property(char *dtb, const char *node, const char *prop)
1029 + free(new_node);
1030 + return result;
1031 + }
1032 ++
1033 ++static int dtb_get_num_cells(char *dtb, int nodeoffset, uint32_t *addr_cells,
1034 ++ uint32_t *size_cells, bool recursive)
1035 ++{
1036 ++ const uint32_t *prop32 = NULL;
1037 ++ int curr_offset = nodeoffset;
1038 ++ int prop_len = 0;
1039 ++ *addr_cells = 0;
1040 ++ *size_cells = 0;
1041 ++
1042 ++ do {
1043 ++ prop32 = fdt_getprop(dtb, curr_offset, "#address-cells", &prop_len);
1044 ++ curr_offset = fdt_parent_offset(dtb, curr_offset);
1045 ++ } while (!prop32 && prop_len == -FDT_ERR_NOTFOUND && recursive);
1046 ++
1047 ++ if (!prop32) {
1048 ++ dbgprintf("Could not get #address-cells property for %s (%s)\n",
1049 ++ fdt_get_name(dtb, nodeoffset, NULL), fdt_strerror(nodeoffset));
1050 ++ return -EINVAL;
1051 ++ }
1052 ++ *addr_cells = fdt32_to_cpu(*prop32);
1053 ++
1054 ++ curr_offset = nodeoffset;
1055 ++ do {
1056 ++ prop32 = fdt_getprop(dtb, curr_offset, "#size-cells", &prop_len);
1057 ++ curr_offset = fdt_parent_offset(dtb, curr_offset);
1058 ++ } while (!prop32 && prop_len == -FDT_ERR_NOTFOUND && recursive);
1059 ++
1060 ++ if (!prop32) {
1061 ++ dbgprintf("Could not get #size-cells property for %s (%s)\n",
1062 ++ fdt_get_name(dtb, nodeoffset, NULL), fdt_strerror(nodeoffset));
1063 ++ return -EINVAL;
1064 ++ }
1065 ++ *size_cells = fdt32_to_cpu(*prop32);
1066 ++
1067 ++ dbgprintf("%s: #address-cells:%d #size-cells:%d\n",
1068 ++ fdt_get_name(dtb, nodeoffset, NULL), *addr_cells, *size_cells);
1069 ++
1070 ++ return 0;
1071 ++}
1072 ++
1073 ++void dtb_extract_int_property(uint64_t *val, const void *buf, uint32_t cells)
1074 ++{
1075 ++ const uint32_t *prop32 = NULL;
1076 ++ const uint64_t *prop64 = NULL;
1077 ++
1078 ++ if (cells == 1) {
1079 ++ prop32 = (const uint32_t *) buf;
1080 ++ *val = (uint64_t) be32_to_cpu(*prop32);
1081 ++ } else {
1082 ++ /* Skip any leading cells */
1083 ++ prop64 = (const uint64_t *) (uint32_t *)buf + cells - 2;
1084 ++ *val = (uint64_t) be64_to_cpu(*prop64);
1085 ++ }
1086 ++}
1087 ++
1088 ++void dtb_fill_int_property(void *buf, uint64_t val, uint32_t cells)
1089 ++{
1090 ++ uint32_t prop32 = 0;
1091 ++ uint64_t prop64 = 0;
1092 ++
1093 ++ if (cells == 1) {
1094 ++ prop32 = cpu_to_fdt32((uint32_t) val);
1095 ++ memcpy(buf, &prop32, sizeof(uint32_t));
1096 ++ } else {
1097 ++ prop64 = cpu_to_fdt64(val);
1098 ++ /* Skip any leading cells */
1099 ++ memcpy((uint64_t *)(uint32_t *)buf + cells - 2,
1100 ++ &prop64, sizeof(uint64_t));
1101 ++ }
1102 ++}
1103 ++
1104 ++int dtb_add_range_property(char **dtb, off_t *dtb_size, uint64_t start, uint64_t end,
1105 ++ const char *parent, const char *name)
1106 ++{
1107 ++ uint32_t addr_cells = 0;
1108 ++ uint32_t size_cells = 0;
1109 ++ char *nodepath = NULL;
1110 ++ void *prop = NULL;
1111 ++ int nodeoffset = 0;
1112 ++ int prop_size = 0;
1113 ++ int ret = 0;
1114 ++
1115 ++ nodepath = malloc(strlen("/") + strlen(parent) + 1);
1116 ++ if (!nodepath) {
1117 ++ dbgprintf("%s: malloc failed\n", __func__);
1118 ++ return -ENOMEM;
1119 ++ }
1120 ++
1121 ++ strcpy(nodepath, "/");
1122 ++ strcat(nodepath, parent);
1123 ++
1124 ++ nodeoffset = fdt_path_offset(*dtb, nodepath);
1125 ++ if (nodeoffset < 0) {
1126 ++ dbgprintf("%s: fdt_path_offset(%s) failed: %s\n", __func__,
1127 ++ nodepath, fdt_strerror(nodeoffset));
1128 ++ free(nodepath);
1129 ++ return nodeoffset;
1130 ++ }
1131 ++ free(nodepath);
1132 ++
1133 ++ ret = dtb_get_num_cells(*dtb, nodeoffset, &addr_cells, &size_cells, true);
1134 ++ if (ret < 0)
1135 ++ return ret;
1136 ++
1137 ++ /* Can the range fit with the given address/size cells ? */
1138 ++ if ((addr_cells == 1) && (start >= (1ULL << 32)))
1139 ++ return -EINVAL;
1140 ++
1141 ++ if ((size_cells == 1) && ((end - start + 1) >= (1ULL << 32)))
1142 ++ return -EINVAL;
1143 ++
1144 ++ prop_size = sizeof(uint32_t) * (addr_cells + size_cells);
1145 ++ prop = malloc(prop_size);
1146 ++
1147 ++ dtb_fill_int_property(prop, start, addr_cells);
1148 ++ dtb_fill_int_property((void *)((uint32_t *)prop + addr_cells),
1149 ++ end - start + 1, size_cells);
1150 ++
1151 ++ /* Add by node path name */
1152 ++ return dtb_set_property(dtb, dtb_size, parent, name, prop, prop_size);
1153 ++}
1154 ++
1155 ++/************************\
1156 ++* MEMORY RANGES HANDLING *
1157 ++\************************/
1158 ++
1159 ++static int dtb_add_memory_range(struct memory_ranges *mem_ranges, uint64_t start,
1160 ++ uint64_t end, unsigned type)
1161 ++{
1162 ++ struct memory_range this_region = {0};
1163 ++ struct memory_range *ranges = mem_ranges->ranges;
1164 ++ int i = 0;
1165 ++ int ret = 0;
1166 ++
1167 ++ if (start == end) {
1168 ++ dbgprintf("Ignoring empty region\n");
1169 ++ return -EINVAL;
1170 ++ }
1171 ++
1172 ++ /* Check if we are adding an existing region */
1173 ++ for (i = 0; i < mem_ranges->size; i++) {
1174 ++ if (start == ranges[i].start && end == ranges[i].end) {
1175 ++ dbgprintf("Duplicate: 0x%lx - 0x%lx\n", start, end);
1176 ++
1177 ++ if (type == ranges[i].type)
1178 ++ return 0;
1179 ++ else if (type == RANGE_RESERVED) {
1180 ++ ranges[i].type = RANGE_RESERVED;
1181 ++ return 0;
1182 ++ }
1183 ++
1184 ++ dbgprintf("Conflicting types for region: 0x%lx - 0x%lx\n",
1185 ++ start, end);
1186 ++ return -EINVAL;
1187 ++ }
1188 ++ }
1189 ++
1190 ++ /*
1191 ++ * Reserved regions may be part of an existing /memory
1192 ++ * region and shouldn't overlap according to spec, so
1193 ++ * since we add /memory regions first, we can exclude
1194 ++ * reserved regions here from the existing /memory regions
1195 ++ * included in ranges[], so that we don't have the same
1196 ++ * region twice.
1197 ++ */
1198 ++ if (type == RANGE_RESERVED) {
1199 ++ this_region.start = start;
1200 ++ this_region.end = end - 1;
1201 ++ this_region.type = type;
1202 ++ ret = mem_regions_exclude(mem_ranges, &this_region);
1203 ++ if (ret)
1204 ++ return ret;
1205 ++ }
1206 ++
1207 ++ ret = mem_regions_alloc_and_add(mem_ranges, start,
1208 ++ end - start, type);
1209 ++
1210 ++ return ret;
1211 ++}
1212 ++
1213 ++static int dtb_add_memory_region(char *dtb, int nodeoffset,
1214 ++ struct memory_ranges *mem_ranges, int type)
1215 ++{
1216 ++ uint32_t root_addr_cells = 0;
1217 ++ uint32_t root_size_cells = 0;
1218 ++ uint64_t addr = 0;
1219 ++ uint64_t size = 0;
1220 ++ const char *reg = NULL;
1221 ++ int prop_size = 0;
1222 ++ int offset = 0;
1223 ++ int entry_size = 0;
1224 ++ int num_entries = 0;
1225 ++ int ret = 0;
1226 ++
1227 ++ /*
1228 ++ * Get address-cells and size-cells properties (according to
1229 ++ * binding spec these are the same as in the root node)
1230 ++ */
1231 ++ ret = dtb_get_num_cells(dtb, 0, &root_addr_cells, &root_size_cells, false);
1232 ++ if (ret < 0) {
1233 ++ dbgprintf("No address/size cells on root node !\n");
1234 ++ return ret;
1235 ++ }
1236 ++
1237 ++ /*
1238 ++ * Parse the reg array, acording to device tree spec it includes
1239 ++ * an arbitary number of <address><size> pairs
1240 ++ */
1241 ++ entry_size = (root_addr_cells + root_size_cells) * sizeof(uint32_t);
1242 ++ reg = fdt_getprop(dtb, nodeoffset, "reg", &prop_size);
1243 ++ if (!reg) {
1244 ++ dbgprintf("Warning: Malformed memory region with no reg property (%s) !\n",
1245 ++ fdt_get_name(dtb, nodeoffset, NULL));
1246 ++ return -EINVAL;
1247 ++ }
1248 ++
1249 ++ num_entries = prop_size / entry_size;
1250 ++ dbgprintf("Got region with %i entries: %s\n", num_entries,
1251 ++ fdt_get_name(dtb, nodeoffset, NULL));
1252 ++
1253 ++ for (num_entries--; num_entries >= 0; num_entries--) {
1254 ++ offset = num_entries * entry_size;
1255 ++
1256 ++ dtb_extract_int_property(&addr, reg + offset,
1257 ++ root_addr_cells);
1258 ++ offset += root_addr_cells * sizeof(uint32_t);
1259 ++
1260 ++ dtb_extract_int_property(&size, reg + offset,
1261 ++ root_size_cells);
1262 ++
1263 ++ ret = dtb_add_memory_range(mem_ranges, addr,
1264 ++ addr + size, type);
1265 ++ if (ret)
1266 ++ return ret;
1267 ++ }
1268 ++
1269 ++ return 0;
1270 ++}
1271 ++
1272 ++static int dtb_parse_memory_reservations_table(char *dtb, struct memory_ranges *mem_ranges)
1273 ++{
1274 ++ int total_memrsrv = 0;
1275 ++ uint64_t addr = 0;
1276 ++ uint64_t size = 0;
1277 ++ int ret = 0;
1278 ++ int i = 0;
1279 ++
1280 ++ total_memrsrv = fdt_num_mem_rsv(dtb);
1281 ++ for (i = 0; i < total_memrsrv; i++) {
1282 ++ ret = fdt_get_mem_rsv(dtb, i, &addr, &size);
1283 ++ if (ret)
1284 ++ continue;
1285 ++ ret = dtb_add_memory_range(mem_ranges, addr, addr + size - 1,
1286 ++ RANGE_RESERVED);
1287 ++ if (ret)
1288 ++ return ret;
1289 ++ }
1290 ++
1291 ++ return 0;
1292 ++}
1293 ++
1294 ++static int dtb_get_reserved_memory_node(char *dtb)
1295 ++{
1296 ++ uint32_t root_addr_cells = 0;
1297 ++ uint32_t root_size_cells = 0;
1298 ++ uint32_t addr_cells = 0;
1299 ++ uint32_t size_cells = 0;
1300 ++ int prop_size = 0;
1301 ++ int nodeoffset = 0;
1302 ++ int ret = 0;
1303 ++
1304 ++ /* Get address / size cells from root node */
1305 ++ ret = dtb_get_num_cells(dtb, 0, &root_addr_cells, &root_size_cells, false);
1306 ++ if (ret < 0) {
1307 ++ dbgprintf("No address/size cells on root node !\n");
1308 ++ return ret;
1309 ++ }
1310 ++
1311 ++ /* This calls fdt_next_node internaly */
1312 ++ nodeoffset = fdt_subnode_offset(dtb, 0, "reserved-memory");
1313 ++ if (nodeoffset == -FDT_ERR_NOTFOUND) {
1314 ++ return nodeoffset;
1315 ++ } else if (nodeoffset < 0) {
1316 ++ dbgprintf("Error while looking for reserved-memory: %s\n",
1317 ++ fdt_strerror(nodeoffset));
1318 ++ return nodeoffset;
1319 ++ }
1320 ++
1321 ++ /* Look for the ranges property */
1322 ++ fdt_getprop(dtb, nodeoffset, "ranges", &prop_size);
1323 ++ if (prop_size < 0) {
1324 ++ fprintf(stderr, "Malformed reserved-memory node (no ranges property) !\n");
1325 ++ return -EINVAL;
1326 ++ }
1327 ++
1328 ++ /* Verify address-cells / size-cells */
1329 ++ ret = dtb_get_num_cells(dtb, nodeoffset, &addr_cells, &size_cells, false);
1330 ++ if (ret < 0) {
1331 ++ dbgprintf("No address/size cells property on reserved-memory node\n");
1332 ++ return ret;
1333 ++ }
1334 ++
1335 ++ if (addr_cells != root_addr_cells) {
1336 ++ fprintf(stderr, "Invalid #address-cells property on reserved-memory node\n");
1337 ++ return -EINVAL;
1338 ++ }
1339 ++
1340 ++ if (size_cells != root_size_cells) {
1341 ++ fprintf(stderr, "Invalid #size-cells property on reserved-memory node\n");
1342 ++ return -EINVAL;
1343 ++
1344 ++ }
1345 ++
1346 ++ return nodeoffset;
1347 ++}
1348 ++
1349 ++static int dtb_parse_reserved_memory_node(char *dtb, struct memory_ranges *mem_ranges)
1350 ++{
1351 ++ int nodeoffset = 0;
1352 ++ int node_depth = 0;
1353 ++ int parent_depth = 0;
1354 ++ int ret = 0;
1355 ++
1356 ++ nodeoffset = dtb_get_reserved_memory_node(dtb);
1357 ++ if (nodeoffset == -FDT_ERR_NOTFOUND)
1358 ++ return 0;
1359 ++ else if (nodeoffset < 0)
1360 ++ return nodeoffset;
1361 ++
1362 ++ /* Got the parent node, check for sub-nodes */
1363 ++
1364 ++ /* fdt_next_node() increases or decreases depth */
1365 ++ node_depth = parent_depth;
1366 ++ nodeoffset = fdt_next_node(dtb, nodeoffset, &node_depth);
1367 ++ if (ret < 0) {
1368 ++ dbgprintf("Unable to get next node: %s\n",
1369 ++ fdt_strerror(ret));
1370 ++ return -EINVAL;
1371 ++ }
1372 ++
1373 ++ while (node_depth != parent_depth) {
1374 ++
1375 ++ ret = dtb_add_memory_region(dtb, nodeoffset,
1376 ++ mem_ranges, RANGE_RESERVED);
1377 ++ if (ret)
1378 ++ return ret;
1379 ++
1380 ++ nodeoffset = fdt_next_node(dtb, nodeoffset, &node_depth);
1381 ++ if (ret < 0) {
1382 ++ dbgprintf("Unable to get next node: %s\n",
1383 ++ fdt_strerror(ret));
1384 ++ return -EINVAL;
1385 ++ }
1386 ++ }
1387 ++
1388 ++ return 0;
1389 ++}
1390 ++
1391 ++static int dtb_parse_memory_nodes(char *dtb, struct memory_ranges *mem_ranges)
1392 ++{
1393 ++ int nodeoffset = 0;
1394 ++ int num_regions = 0;
1395 ++ const char* dev_type = 0;
1396 ++ int prop_size = 0;
1397 ++ int ret = 0;
1398 ++
1399 ++ for (; ; num_regions++) {
1400 ++ nodeoffset = fdt_subnode_offset(dtb, nodeoffset,
1401 ++ "memory");
1402 ++ if (nodeoffset < 0)
1403 ++ break;
1404 ++
1405 ++ dbgprintf("Got memory node at depth: %i\n", fdt_node_depth(dtb, nodeoffset));
1406 ++
1407 ++ /* Look for the device_type property */
1408 ++ dev_type = fdt_getprop(dtb, nodeoffset, "device_type", &prop_size);
1409 ++ if (prop_size < 0) {
1410 ++ fprintf(stderr, "Malformed /memory node (no device-type property) !\n");
1411 ++ return -EINVAL;
1412 ++ }
1413 ++
1414 ++ if (strncmp(dev_type, "memory", prop_size)) {
1415 ++ dbgprintf("Got unknown dev_type property: %s\n", dev_type);
1416 ++ continue;
1417 ++ }
1418 ++
1419 ++ ret = dtb_add_memory_region(dtb, nodeoffset, mem_ranges, RANGE_RAM);
1420 ++ if (ret)
1421 ++ return ret;
1422 ++ }
1423 ++
1424 ++ if (!num_regions) {
1425 ++ dbgprintf("Malformed dtb, no /memory nodes present !\n");
1426 ++ return -EINVAL;
1427 ++ }
1428 ++
1429 ++ dbgprintf("Got %i /memory nodes\n", num_regions);
1430 ++
1431 ++ return 0;
1432 ++}
1433 ++
1434 ++int dtb_get_memory_ranges(char *dtb, struct memory_ranges *mem_ranges, struct memory_ranges *extra_ranges)
1435 ++{
1436 ++ int i = 0;
1437 ++ int ret = 0;
1438 ++
1439 ++ /* Fill mem_ranges[] by parsing the device tree */
1440 ++ ret = dtb_parse_memory_nodes(dtb, mem_ranges);
1441 ++ if (ret)
1442 ++ return ret;
1443 ++
1444 ++ ret = dtb_parse_memory_reservations_table(dtb, mem_ranges);
1445 ++ if (ret)
1446 ++ return ret;
1447 ++
1448 ++ ret = dtb_parse_reserved_memory_node(dtb, mem_ranges);
1449 ++ if (ret)
1450 ++ return ret;
1451 ++
1452 ++ /* Append any extra ranges provided by the caller (e.g. initrd) */
1453 ++ for (i = 0; extra_ranges != NULL && i < extra_ranges->size; i++) {
1454 ++ dbgprintf("Adding extra range: 0x%llx - 0x%llx (%s)\n",
1455 ++ extra_ranges->ranges[i].start,
1456 ++ extra_ranges->ranges[i].end,
1457 ++ extra_ranges->ranges[i].type == RANGE_RESERVED ?
1458 ++ "RANGE_RESERVED" : "RANGE_RAM");
1459 ++
1460 ++ ret = dtb_add_memory_range(mem_ranges, extra_ranges->ranges[i].start,
1461 ++ extra_ranges->ranges[i].end, extra_ranges->ranges[i].type);
1462 ++ if (ret)
1463 ++ return ret;
1464 ++ }
1465 ++
1466 ++ mem_regions_sort(mem_ranges);
1467 ++
1468 ++ return 0;
1469 ++}
1470 +diff --git a/kexec/dt-ops.h b/kexec/dt-ops.h
1471 +index 03659ce..3014205 100644
1472 +--- a/kexec/dt-ops.h
1473 ++++ b/kexec/dt-ops.h
1474 +@@ -11,4 +11,11 @@ int dtb_set_property(char **dtb, off_t *dtb_size, const char *node,
1475 +
1476 + int dtb_delete_property(char *dtb, const char *node, const char *prop);
1477 +
1478 ++void dtb_extract_int_property(uint64_t *val, const void *buf, uint32_t cells);
1479 ++void dtb_fill_int_property(void *buf, uint64_t val, uint32_t cells);
1480 ++int dtb_add_range_property(char **dtb, off_t *dtb_size, uint64_t start, uint64_t end,
1481 ++ const char *node, const char* parent);
1482 ++int dtb_get_memory_ranges(char *dtb, struct memory_ranges *mem_ranges,
1483 ++ struct memory_ranges *extra_ranges);
1484 ++
1485 + #endif
1486 +diff --git a/kexec/kexec-syscall.h b/kexec/kexec-syscall.h
1487 +index bea29d4..2e99e2b 100644
1488 +--- a/kexec/kexec-syscall.h
1489 ++++ b/kexec/kexec-syscall.h
1490 +@@ -134,6 +134,7 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,
1491 + #define KEXEC_ARCH_MIPS_LE (10 << 16)
1492 + #define KEXEC_ARCH_MIPS ( 8 << 16)
1493 + #define KEXEC_ARCH_CRIS (76 << 16)
1494 ++#define KEXEC_ARCH_RISCV (243 << 16)
1495 +
1496 + #define KEXEC_MAX_SEGMENTS 16
1497 +
1498 +@@ -177,5 +178,8 @@ static inline long kexec_file_load(int kernel_fd, int initrd_fd,
1499 + #if defined(__arm64__)
1500 + #define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM64
1501 + #endif
1502 ++#if defined(__riscv__) || defined(__riscv)
1503 ++#define KEXEC_ARCH_NATIVE KEXEC_ARCH_RISCV
1504 ++#endif
1505 +
1506 + #endif /* KEXEC_SYSCALL_H */
1507 +diff --git a/purgatory/Makefile b/purgatory/Makefile
1508 +index 15adb12..11694e5 100644
1509 +--- a/purgatory/Makefile
1510 ++++ b/purgatory/Makefile
1511 +@@ -25,6 +25,7 @@ include $(srcdir)/purgatory/arch/ia64/Makefile
1512 + include $(srcdir)/purgatory/arch/mips/Makefile
1513 + include $(srcdir)/purgatory/arch/ppc/Makefile
1514 + include $(srcdir)/purgatory/arch/ppc64/Makefile
1515 ++include $(srcdir)/purgatory/arch/riscv/Makefile
1516 + include $(srcdir)/purgatory/arch/s390/Makefile
1517 + include $(srcdir)/purgatory/arch/sh/Makefile
1518 + include $(srcdir)/purgatory/arch/x86_64/Makefile
1519 +diff --git a/purgatory/arch/riscv/Makefile b/purgatory/arch/riscv/Makefile
1520 +new file mode 100644
1521 +index 0000000..8bded71
1522 +--- /dev/null
1523 ++++ b/purgatory/arch/riscv/Makefile
1524 +@@ -0,0 +1,7 @@
1525 ++#
1526 ++# Purgatory riscv
1527 ++#
1528 ++
1529 ++riscv_PURGATORY_SRCS =
1530 ++
1531 ++dist += purgatory/arch/sh/Makefile $(riscv_PURGATORY_SRCS)
1532 +--
1533 +2.35.1
1534 +
1535
1536 diff --git a/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild b/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild
1537 index 5723fa8..7251c1b 100644
1538 --- a/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild
1539 +++ b/sys-apps/kexec-tools/kexec-tools-2.0.24.ebuild
1540 @@ -3,7 +3,7 @@
1541
1542 EAPI=8
1543
1544 -inherit libtool linux-info systemd
1545 +inherit autotools libtool linux-info systemd
1546
1547 if [[ ${PV} == "9999" ]] ; then
1548 inherit git-r3 autotools
1549 @@ -35,6 +35,7 @@ CONFIG_CHECK="~KEXEC"
1550 PATCHES=(
1551 "${FILESDIR}"/${PN}-2.0.4-disable-kexec-test.patch
1552 "${FILESDIR}"/${PN}-2.0.4-out-of-source.patch
1553 + "${FILESDIR}"/${PN}-2.0.24-riscv.patch
1554 )
1555
1556 pkg_setup() {
1557 @@ -48,11 +49,7 @@ src_prepare() {
1558 # Append PURGATORY_EXTRA_CFLAGS flags set by configure, instead of overriding them completely.
1559 sed -e "/^PURGATORY_EXTRA_CFLAGS =/s/=/+=/" -i Makefile.in || die
1560
1561 - if [[ "${PV}" == 9999 ]] ; then
1562 - eautoreconf
1563 - else
1564 - elibtoolize
1565 - fi
1566 + eautoreconf
1567 }
1568
1569 src_configure() {