public inbox for kexec@lists.infradead.org
 help / color / mirror / Atom feed
From: Pingfan Liu <piliu@redhat.com>
To: kexec@lists.infradead.org
Cc: Jeremy Linton <jeremy.linton@arm.com>,
	Pingfan Liu <piliu@redhat.com>,
	horms@verge.net.au, ardb@kernel.org
Subject: [PATCHv7 3/5] kexec/zboot: Add arch independent zboot support
Date: Thu,  3 Aug 2023 10:41:50 +0800	[thread overview]
Message-ID: <20230803024152.11663-4-piliu@redhat.com> (raw)
In-Reply-To: <20230803024152.11663-1-piliu@redhat.com>

From: Jeremy Linton <jeremy.linton@arm.com>

The linux kernel CONFIG_ZBOOT option creates
self decompressing PE kernel images. So this means
that kexec should have a generic understanding of
the format which may be used by multiple arches.

So lets add an arch independent validation
and decompression routine.

Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
[Modified by Pingfan to export kernel fd]
Signed-off-by: Pingfan Liu <piliu@redhat.com>
To: kexec@lists.infradead.org
Cc: horms@verge.net.au
Cc: ardb@kernel.org
Cc: jeremy.linton@arm.com
---
 include/Makefile         |   1 +
 include/kexec-pe-zboot.h |  15 +++++
 kexec/Makefile           |   1 +
 kexec/kexec-pe-zboot.c   | 131 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 148 insertions(+)
 create mode 100644 include/kexec-pe-zboot.h
 create mode 100644 kexec/kexec-pe-zboot.c

diff --git a/include/Makefile b/include/Makefile
index 621ce9f..cd88a26 100644
--- a/include/Makefile
+++ b/include/Makefile
@@ -1,6 +1,7 @@
 dist += include/Makefile		\
 	include/config.h		\
 	include/config.h.in		\
+	include/kexec-pe-zboot.h	\
 	include/kexec-uImage.h		\
 	include/x86/x86-linux.h		\
 	include/x86/mb_info.h		\
diff --git a/include/kexec-pe-zboot.h b/include/kexec-pe-zboot.h
new file mode 100644
index 0000000..c588ca2
--- /dev/null
+++ b/include/kexec-pe-zboot.h
@@ -0,0 +1,15 @@
+#ifndef __KEXEC_PE_ZBOOT_H__
+#define __KEXEC_PE_ZBOOT_H__
+
+/* see drivers/firmware/efi/libstub/zboot-header.S */
+struct linux_pe_zboot_header {
+	uint32_t mz_magic;
+        uint32_t image_type;
+        uint32_t payload_offset;
+        uint32_t payload_size;
+        uint32_t reserved[2];
+        uint32_t compress_type;
+};
+
+int pez_prepare(const char *crude_buf, off_t buf_sz, int *kernel_fd);
+#endif
diff --git a/kexec/Makefile b/kexec/Makefile
index 8a52e8d..11682bf 100644
--- a/kexec/Makefile
+++ b/kexec/Makefile
@@ -17,6 +17,7 @@ KEXEC_SRCS_base += kexec/kexec-elf-exec.c
 KEXEC_SRCS_base += kexec/kexec-elf-core.c
 KEXEC_SRCS_base += kexec/kexec-elf-rel.c
 KEXEC_SRCS_base += kexec/kexec-elf-boot.c
+KEXEC_SRCS_base += kexec/kexec-pe-zboot.c
 KEXEC_SRCS_base += kexec/kexec-iomem.c
 KEXEC_SRCS_base += kexec/firmware_memmap.c
 KEXEC_SRCS_base += kexec/crashdump.c
diff --git a/kexec/kexec-pe-zboot.c b/kexec/kexec-pe-zboot.c
new file mode 100644
index 0000000..2f2e052
--- /dev/null
+++ b/kexec/kexec-pe-zboot.c
@@ -0,0 +1,131 @@
+/*
+ * Generic PE compressed Image (vmlinuz, ZBOOT) support.
+ *
+ * Several distros use 'make zinstall' with CONFIG_ZBOOT
+ * enabled to create UEFI PE images that contain
+ * a decompressor and a compressed kernel image.
+ *
+ * Currently we cannot use kexec_file_load() to load vmlinuz
+ * PE images that self decompress.
+ *
+ * To support ZBOOT, we should:
+ * a). Copy the compressed contents of vmlinuz to a temporary file.
+ * b). Decompress (gunzip-decompress) the contents inside the
+ *     temporary file.
+ * c). Validate the resulting image and write it back to the
+ *     temporary file.
+ * d). Pass the 'fd' of the temporary file to the kernel space.
+ *
+ * This module contains the arch independent code for the above,
+ * arch specific PE and image checks should wrap calls
+ * to functions in this module.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "kexec.h"
+#include <kexec-pe-zboot.h>
+
+#define FILENAME_IMAGE		"/tmp/ImageXXXXXX"
+
+/*
+ * Returns -1 : in case of error/invalid format (not a valid PE+compressed ZBOOT format.
+ *
+ * crude_buf: the content, which is read from the kernel file without any processing
+ */
+int pez_prepare(const char *crude_buf, off_t buf_sz, int *kernel_fd)
+{
+	int ret = -1;
+	int fd = 0;
+	char *fname = NULL;
+	char *kernel_uncompressed_buf = NULL;
+	off_t decompressed_size = 0;
+	const struct linux_pe_zboot_header *z;
+
+	z = (const struct linux_pe_zboot_header *)(crude_buf);
+
+	if (memcmp(&z->image_type, "zimg", sizeof(z->image_type))) {
+		dbgprintf("%s: PE doesn't contain a compressed kernel.\n", __func__);
+		return -1;
+	}
+
+	/*
+	 * At the moment its possible to create images with more compression
+	 * algorithms than are supported here, error out if we detect that.
+	 */
+	if (memcmp(&z->compress_type, "gzip", 4) &&
+	    memcmp(&z->compress_type, "lzma", 4)) {
+		dbgprintf("%s: kexec can only decompress gziped and lzma images.\n", __func__);
+		return -1;
+	}
+
+	if (buf_sz < z->payload_offset + z->payload_size) {
+		dbgprintf("%s: PE too small to contain complete payload.\n", __func__);
+		return -1;
+	}
+
+	if (!(fname = strdup(FILENAME_IMAGE))) {
+		dbgprintf("%s: Can't duplicate strings\n", __func__);
+		return -1;
+	}
+
+	if ((fd = mkstemp(fname)) < 0) {
+		dbgprintf("%s: Can't open file %s\n", __func__,	fname);
+		ret = -1;
+		goto fail_mkstemp;
+	}
+
+	if (write(fd, &crude_buf[z->payload_offset],
+		  z->payload_size) != z->payload_size) {
+		dbgprintf("%s: Can't write the compressed file %s\n",
+				__func__, fname);
+		ret = -1;
+		goto fail_write;
+	}
+
+	kernel_uncompressed_buf = slurp_decompress_file(fname,
+							&decompressed_size);
+
+	dbgprintf("%s: decompressed size %ld\n", __func__, decompressed_size);
+
+	lseek(fd, 0, SEEK_SET);
+
+	if (write(fd,  kernel_uncompressed_buf,
+		  decompressed_size) != decompressed_size) {
+		dbgprintf("%s: Can't write the decompressed file %s\n",
+				__func__, fname);
+		ret = -1;
+		goto fail_bad_header;
+	}
+
+	*kernel_fd = open(fname, O_RDONLY);
+	if (*kernel_fd == -1) {
+		dbgprintf("%s: Failed to open file %s\n",
+				__func__, fname);
+		ret = -1;
+		goto fail_bad_header;
+	}
+
+	dbgprintf("%s: done\n", __func__);
+
+	ret = 0;
+	goto fail_write;
+
+fail_bad_header:
+	free(kernel_uncompressed_buf);
+
+fail_write:
+	if (fd >= 0)
+		close(fd);
+
+	unlink(fname);
+
+fail_mkstemp:
+	free(fname);
+
+	return ret;
+}
-- 
2.31.1


_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec

  parent reply	other threads:[~2023-08-03  2:42 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-03  2:41 [PATCHv7 0/5] arm64: zboot support Pingfan Liu
2023-08-03  2:41 ` [PATCHv7 1/5] kexec/arm64: Simplify the code for zImage Pingfan Liu
2023-08-07 13:21   ` Simon Horman
2023-08-07 13:26     ` Dave Young
2023-08-10 12:11       ` Simon Horman
2023-08-11  0:31         ` Dave Young
2023-08-03  2:41 ` [PATCHv7 2/5] kexec: Introduce a member kernel_fd in kexec_info Pingfan Liu
2023-08-11  1:23   ` Dave Young
2023-08-03  2:41 ` Pingfan Liu [this message]
2023-08-07 13:22   ` [PATCHv7 3/5] kexec/zboot: Add arch independent zboot support Simon Horman
2023-08-07 15:22     ` Pingfan Liu
2023-08-03  2:41 ` [PATCHv7 4/5] arm64: Add ZBOOT PE containing compressed image support Pingfan Liu
2023-08-03  2:41 ` [PATCHv7 5/5] arm64: Hook up the ZBOOT support as vmlinuz Pingfan Liu
2023-08-11  7:29 ` [PATCHv7 0/5] arm64: zboot support Simon Horman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230803024152.11663-4-piliu@redhat.com \
    --to=piliu@redhat.com \
    --cc=ardb@kernel.org \
    --cc=horms@verge.net.au \
    --cc=jeremy.linton@arm.com \
    --cc=kexec@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox