Skip to content

Commit

Permalink
kexec/zboot: Add arch independent zboot support
Browse files Browse the repository at this point in the history
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 <[email protected]>
[Modified by Pingfan to export kernel fd]
Signed-off-by: Pingfan Liu <[email protected]>
To: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Simon Horman <[email protected]>
  • Loading branch information
jlintonarm authored and horms committed Aug 1, 2023
1 parent 16efb3a commit 061ea74
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
15 changes: 15 additions & 0 deletions include/kexec-pe-zboot.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions kexec/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
131 changes: 131 additions & 0 deletions kexec/kexec-pe-zboot.c
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 061ea74

Please sign in to comment.