add kexecboot
This allows booting a new image from a running OS, creating a phram mtd for the root squashfs * enable CONFIG_KEXEC * add modules/kexecboot * patch kexec-tools to add --map-file option for the squashfs * patch kernel kexec code to call new kernel with DTB
This commit is contained in:
parent
429ffa8e7d
commit
4b19568f1b
6 changed files with 243 additions and 0 deletions
|
@ -74,6 +74,7 @@ in {
|
||||||
IKCONFIG_PROC = "y";
|
IKCONFIG_PROC = "y";
|
||||||
PROC_FS = "y";
|
PROC_FS = "y";
|
||||||
|
|
||||||
|
KEXEC = "y";
|
||||||
MODULES = "y";
|
MODULES = "y";
|
||||||
MODULE_SIG = "y";
|
MODULE_SIG = "y";
|
||||||
DEBUG_FS = "y";
|
DEBUG_FS = "y";
|
||||||
|
|
50
modules/kexecboot.nix
Normal file
50
modules/kexecboot.nix
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
config
|
||||||
|
, pkgs
|
||||||
|
, lib
|
||||||
|
, ...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) mkOption mkForce types concatStringsSep;
|
||||||
|
in {
|
||||||
|
imports = [ ./ramdisk.nix ];
|
||||||
|
config = {
|
||||||
|
boot.ramdisk.enable = true;
|
||||||
|
|
||||||
|
kernel.config.MIPS_CMDLINE_FROM_DTB = "y";
|
||||||
|
kernel.config.MIPS_CMDLINE_FROM_BOOTLOADER = mkForce "n";
|
||||||
|
|
||||||
|
outputs.kexecboot =
|
||||||
|
let o = config.outputs; in
|
||||||
|
pkgs.runCommand "kexecboot" {} ''
|
||||||
|
mkdir $out
|
||||||
|
cd $out
|
||||||
|
ln -s ${o.squashfs} squashfs
|
||||||
|
ln -s ${o.kernel} kernel
|
||||||
|
ln -s ${o.manifest} manifest
|
||||||
|
ln -s ${o.boot-sh} boot.sh
|
||||||
|
ln -s ${pkgs.kexec-tools}/bin/kexec ./kexec
|
||||||
|
ln -s ${o.dtb} dtb
|
||||||
|
'';
|
||||||
|
|
||||||
|
outputs.boot-sh =
|
||||||
|
let
|
||||||
|
inherit (pkgs) kexec-tools;
|
||||||
|
inherit (pkgs.lib.trivial) toHexString;
|
||||||
|
inherit (config.outputs) squashfs kernel;
|
||||||
|
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||||
|
in
|
||||||
|
pkgs.buildPackages.runCommand "boot.sh.sh" {
|
||||||
|
} ''
|
||||||
|
squashfsStart=${toString (100 * 1024 * 1024)}
|
||||||
|
squashfsBytes=$(stat -L -c %s ${squashfs})
|
||||||
|
append_cmd="mtdparts=phram0:''${squashfsBytes}(rootfs) phram.phram=phram0,''${squashfsStart},''${squashfsBytes} memmap=''${squashfsBytes}\$''${squashfsStart}";
|
||||||
|
cat > $out <<EOF
|
||||||
|
#!/bin/sh
|
||||||
|
test -d \$1
|
||||||
|
cd \$1
|
||||||
|
./kexec -f -d --map-file squashfs@$squashfsStart --dtb dtb --command-line '${cmdline} $append_cmd' kernel
|
||||||
|
EOF
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
11
overlay.nix
11
overlay.nix
|
@ -6,6 +6,17 @@ in
|
||||||
extraPkgs // {
|
extraPkgs // {
|
||||||
strace = prev.strace.override { libunwind = null; };
|
strace = prev.strace.override { libunwind = null; };
|
||||||
|
|
||||||
|
kexec-tools = prev.kexec-tools.overrideAttrs(o: {
|
||||||
|
patches = o.patches ++ [
|
||||||
|
(fetchpatch {
|
||||||
|
# merge user command line options into DTB chosen
|
||||||
|
url = "https://patch-diff.githubusercontent.com/raw/horms/kexec-tools/pull/3.patch";
|
||||||
|
hash = "sha256-MvlJhuex9dlawwNZJ1sJ33YPWn1/q4uKotqkC/4d2tk=";
|
||||||
|
})
|
||||||
|
pkgs/kexec-map-file.patch
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
s6 = prev.s6.overrideAttrs(o:
|
s6 = prev.s6.overrideAttrs(o:
|
||||||
let patch = fetchpatch {
|
let patch = fetchpatch {
|
||||||
# add "p" directive in s6-log
|
# add "p" directive in s6-log
|
||||||
|
|
|
@ -61,6 +61,11 @@ stdenv.mkDerivation rec {
|
||||||
'';
|
'';
|
||||||
|
|
||||||
patchScripts = ''
|
patchScripts = ''
|
||||||
|
# Make kexec pass dtb in register when invoking new kernel. The
|
||||||
|
# code to do this is already present, but bracketed by UHI_BOOT
|
||||||
|
# which we can't enable.
|
||||||
|
sed -i arch/mips/kernel/machine_kexec.c -e 's/CONFIG_UHI_BOOT/CONFIG_MIPS/g'
|
||||||
|
|
||||||
patchShebangs scripts/
|
patchShebangs scripts/
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
|
172
pkgs/kexec-map-file.patch
Normal file
172
pkgs/kexec-map-file.patch
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
From 35b8bad0343a4afd9ad914e377e64bd02667c563 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Barlow <dan@telent.net>
|
||||||
|
Date: Sun, 19 Mar 2023 17:30:30 +0000
|
||||||
|
Subject: [PATCH] add --map-file option to map arbitrary files into physmem
|
||||||
|
|
||||||
|
This is useful e.g. in conjunction with the MTD PHRAM device on
|
||||||
|
embedded devices: a kernel can be booted with kexec and a root
|
||||||
|
filesystem entirely in RAM to see if it works before writing it
|
||||||
|
to flash.
|
||||||
|
---
|
||||||
|
kexec/kexec.8 | 14 ++++++++++++-
|
||||||
|
kexec/kexec.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
kexec/kexec.h | 4 +++-
|
||||||
|
3 files changed, 73 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/kexec/kexec.8 b/kexec/kexec.8
|
||||||
|
index 3a344c5..3140ccb 100644
|
||||||
|
--- a/kexec/kexec.8
|
||||||
|
+++ b/kexec/kexec.8
|
||||||
|
@@ -143,10 +143,17 @@ into the current kernel.
|
||||||
|
.B \-p\ (\-\-load\-panic)
|
||||||
|
Load the new kernel for use on panic.
|
||||||
|
.TP
|
||||||
|
-.BI \-t\ (\-\-type= type )
|
||||||
|
+.BI \-m\ (\-\-type= type )
|
||||||
|
Specify that the new kernel is of this
|
||||||
|
.I type.
|
||||||
|
.TP
|
||||||
|
+.BI \-t\ (\-\-map-file= filename@addr )
|
||||||
|
+Read
|
||||||
|
+.I filename
|
||||||
|
+and arrange for it to be mapped into physical memory at the address
|
||||||
|
+.I addr.
|
||||||
|
+This option may be repeated if there are multiple files to map.
|
||||||
|
+.TP
|
||||||
|
.BI \-s\ (\-\-kexec-file-syscall)
|
||||||
|
Specify that the new KEXEC_FILE_LOAD syscall should be used exclusively.
|
||||||
|
.TP
|
||||||
|
@@ -206,6 +213,11 @@ Reuse initrd from first boot.
|
||||||
|
.BI \-\-print-ckr-size
|
||||||
|
Print crash kernel region size, if available.
|
||||||
|
|
||||||
|
+.PP
|
||||||
|
+Options taking an
|
||||||
|
+.I addr
|
||||||
|
+parameter will accept a memory address written in hexadecimal (with leading
|
||||||
|
+0x), or octal (leading 0), or decimal (no leading sigil).
|
||||||
|
|
||||||
|
.SH SUPPORTED KERNEL FILE TYPES AND OPTIONS
|
||||||
|
.B Beoboot-x86
|
||||||
|
diff --git a/kexec/kexec.c b/kexec/kexec.c
|
||||||
|
index 36bb2ad..c3b40a4 100644
|
||||||
|
--- a/kexec/kexec.c
|
||||||
|
+++ b/kexec/kexec.c
|
||||||
|
@@ -63,6 +63,13 @@ static unsigned long kexec_flags = 0;
|
||||||
|
static unsigned long kexec_file_flags = 0;
|
||||||
|
int kexec_debug = 0;
|
||||||
|
|
||||||
|
+#define MAPPED_FILES_MAX 10 /* arbitrary number */
|
||||||
|
+struct mapped_file {
|
||||||
|
+ const char *filename;
|
||||||
|
+ unsigned long long phys_address;
|
||||||
|
+} mapped_files[MAPPED_FILES_MAX] = { { .filename = NULL } };
|
||||||
|
+
|
||||||
|
+
|
||||||
|
void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int nr_mr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
@@ -771,6 +778,19 @@ static int my_load(const char *type, int fileind, int argc, char **argv,
|
||||||
|
}
|
||||||
|
info.kexec_flags |= native_arch;
|
||||||
|
|
||||||
|
+ for(struct mapped_file *m = mapped_files; m->filename; m++) {
|
||||||
|
+ off_t file_size = 0;
|
||||||
|
+ char *buf = slurp_file(m->filename, &file_size);
|
||||||
|
+ add_buffer(&info,
|
||||||
|
+ buf, file_size, file_size, sizeof (void *),
|
||||||
|
+ m->phys_address,
|
||||||
|
+ mem_max, 1);
|
||||||
|
+ free(m->filename);
|
||||||
|
+ /* do we free() memory returned by slurp_file()?
|
||||||
|
+ * we don't know if it was mmaped, so maybe not
|
||||||
|
+ */
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
result = file_type[i].load(argc, argv, kernel_buf, kernel_size, &info);
|
||||||
|
if (result < 0) {
|
||||||
|
switch (result) {
|
||||||
|
@@ -1035,6 +1055,8 @@ void usage(void)
|
||||||
|
" load code into.\n"
|
||||||
|
" --mem-max=<addr> Specify the highest memory address to\n"
|
||||||
|
" load code into.\n"
|
||||||
|
+ " --map-file=<filename@addr> Map a file into memory for the\n"
|
||||||
|
+ " new kernel before kexec.\n"
|
||||||
|
" --reuseinitrd Reuse initrd from first boot.\n"
|
||||||
|
" --print-ckr-size Print crash kernel region size.\n"
|
||||||
|
" --load-preserve-context Load the new kernel and preserve\n"
|
||||||
|
@@ -1396,6 +1418,33 @@ static void print_crashkernel_region_size(void)
|
||||||
|
printf("%" PRIu64 "\n", (start != end) ? (end - start + 1) : 0UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int add_mapped_file(char * optarg)
|
||||||
|
+{
|
||||||
|
+ char *at = strchr(optarg, '@');
|
||||||
|
+ if(!at)
|
||||||
|
+ return 1;
|
||||||
|
+
|
||||||
|
+ struct mapped_file *m = mapped_files;
|
||||||
|
+ struct mapped_file *m_end = mapped_files +
|
||||||
|
+ ((sizeof mapped_files) / (sizeof mapped_files[0]));
|
||||||
|
+
|
||||||
|
+ while(m->filename && m < m_end)
|
||||||
|
+ m++;
|
||||||
|
+
|
||||||
|
+ if(m >= m_end)
|
||||||
|
+ return 1;
|
||||||
|
+
|
||||||
|
+ m->phys_address = strtoull(at + 1, NULL, 0);
|
||||||
|
+ if(m->phys_address == 0)
|
||||||
|
+ return 1;
|
||||||
|
+
|
||||||
|
+ m->filename = strndup(optarg, at - optarg);
|
||||||
|
+
|
||||||
|
+ (m+1)->filename = NULL;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int has_opt_load = 0;
|
||||||
|
@@ -1521,6 +1570,14 @@ int main(int argc, char *argv[])
|
||||||
|
kexec_file_flags |= KEXEC_FILE_ON_CRASH;
|
||||||
|
kexec_flags = KEXEC_ON_CRASH;
|
||||||
|
break;
|
||||||
|
+ case OPT_MAP_FILE:
|
||||||
|
+ if(add_mapped_file(optarg)) {
|
||||||
|
+ fprintf(stderr,
|
||||||
|
+ "Bad option value or too many mapped files in --mapped-file=%s\n",
|
||||||
|
+ optarg);
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
case OPT_MEM_MIN:
|
||||||
|
mem_min = strtoul(optarg, &endptr, 0);
|
||||||
|
if (*endptr) {
|
||||||
|
diff --git a/kexec/kexec.h b/kexec/kexec.h
|
||||||
|
index 0d820ad..78022b6 100644
|
||||||
|
--- a/kexec/kexec.h
|
||||||
|
+++ b/kexec/kexec.h
|
||||||
|
@@ -224,6 +224,7 @@ extern int file_types;
|
||||||
|
#define OPT_STATUS 'S'
|
||||||
|
#define OPT_MEM_MIN 256
|
||||||
|
#define OPT_MEM_MAX 257
|
||||||
|
+#define OPT_MAP_FILE 'm'
|
||||||
|
#define OPT_REUSE_INITRD 258
|
||||||
|
#define OPT_LOAD_PRESERVE_CONTEXT 259
|
||||||
|
#define OPT_LOAD_JUMP_BACK_HELPER 260
|
||||||
|
@@ -258,8 +259,9 @@ extern int file_types;
|
||||||
|
{ "debug", 0, 0, OPT_DEBUG }, \
|
||||||
|
{ "status", 0, 0, OPT_STATUS }, \
|
||||||
|
{ "print-ckr-size", 0, 0, OPT_PRINT_CKR_SIZE }, \
|
||||||
|
+ { "map-file", 1, 0, OPT_MAP_FILE }, \
|
||||||
|
|
||||||
|
-#define KEXEC_OPT_STR "h?vdfixyluet:pscaS"
|
||||||
|
+#define KEXEC_OPT_STR "h?vdfixyluet:pscaSm"
|
||||||
|
|
||||||
|
extern void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int nr_mr);
|
||||||
|
extern void die(const char *fmt, ...)
|
||||||
|
--
|
||||||
|
2.38.1
|
||||||
|
|
|
@ -20,6 +20,10 @@ let
|
||||||
}
|
}
|
||||||
patches ${src}/target/linux/generic/backport-5.15/*.patch
|
patches ${src}/target/linux/generic/backport-5.15/*.patch
|
||||||
patches ${src}/target/linux/generic/pending-5.15/*.patch
|
patches ${src}/target/linux/generic/pending-5.15/*.patch
|
||||||
|
# This patch breaks passing the DTB to kexeced kernel, so let's
|
||||||
|
# get rid of it. It's not needed anyway as we pass the cmdline
|
||||||
|
# in the dtb
|
||||||
|
patch --batch -p1 --reverse < ${src}/target/linux/generic/pending-5.15/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch
|
||||||
patches ${src}/target/linux/generic/hack-5.15/*.patch
|
patches ${src}/target/linux/generic/hack-5.15/*.patch
|
||||||
patches ${src}/target/linux/${family}/patches-5.15/*.patch
|
patches ${src}/target/linux/${family}/patches-5.15/*.patch
|
||||||
'';
|
'';
|
||||||
|
|
Loading…
Reference in a new issue