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() { |