[PATCH 3/5] LoongArch: PE format image loading support

Info Skymem info at skymem.com
Wed Sep 28 03:06:48 PDT 2022


Hi,
thank you for your information.

On our website you can find email addresses of companies and people.
https://www.skymem.info

In short, it’s like Google for emails.

Best regards,
Robert,
Skymem team

On Wed, Sep 28, 2022 at 4:31 AM Youling Tang <tangyouling at loongson.cn> wrote:
>
> The LoongArch kernel will mainly use the vmlinux.efi image in PE format,
> so add it support.
>
> I tested this on LoongArch 3A5000 machine and works as expected,
>
> kexec:
>   $ sudo kexec -l /boot/vmlinux.efi --reuse-cmdline
>   $ sudo kexec -e
>
> kdump:
>   $ sudo kexec -p /boot/vmlinux-kdump.efi --reuse-cmdline --append="nr_cpus=1"
>   # echo c > /proc/sysrq_trigger
>
> Signed-off-by: Youling Tang <tangyouling at loongson.cn>
> ---
>  kexec/arch/loongarch/Makefile              |   2 +
>  kexec/arch/loongarch/image-header.h        |  79 ++++++++++++++
>  kexec/arch/loongarch/kexec-elf-loongarch.c |   3 +
>  kexec/arch/loongarch/kexec-loongarch.c     |  19 ++++
>  kexec/arch/loongarch/kexec-loongarch.h     |   9 ++
>  kexec/arch/loongarch/kexec-pei-loongarch.c | 117 +++++++++++++++++++++
>  6 files changed, 229 insertions(+)
>  create mode 100644 kexec/arch/loongarch/image-header.h
>  create mode 100644 kexec/arch/loongarch/kexec-pei-loongarch.c
>
> diff --git a/kexec/arch/loongarch/Makefile b/kexec/arch/loongarch/Makefile
> index e5e190a..3b33b96 100644
> --- a/kexec/arch/loongarch/Makefile
> +++ b/kexec/arch/loongarch/Makefile
> @@ -3,6 +3,7 @@
>  #
>  loongarch_KEXEC_SRCS =  kexec/arch/loongarch/kexec-loongarch.c
>  loongarch_KEXEC_SRCS += kexec/arch/loongarch/kexec-elf-loongarch.c
> +loongarch_KEXEC_SRCS += kexec/arch/loongarch/kexec-pei-loongarch.c
>  loongarch_KEXEC_SRCS += kexec/arch/loongarch/kexec-elf-rel-loongarch.c
>  loongarch_KEXEC_SRCS += kexec/arch/loongarch/crashdump-loongarch.c
>
> @@ -16,5 +17,6 @@ loongarch_VIRT_TO_PHYS =
>
>  dist += kexec/arch/loongarch/Makefile $(loongarch_KEXEC_SRCS)                  \
>         kexec/arch/loongarch/kexec-loongarch.h                                  \
> +       kexec/arch/loongarch/image-header.h                                     \
>         kexec/arch/loongarch/crashdump-loongarch.h                              \
>         kexec/arch/loongarch/include/arch/options.h
> diff --git a/kexec/arch/loongarch/image-header.h b/kexec/arch/loongarch/image-header.h
> new file mode 100644
> index 0000000..3b75765
> --- /dev/null
> +++ b/kexec/arch/loongarch/image-header.h
> @@ -0,0 +1,79 @@
> +/*
> + * LoongArch binary image header.
> + */
> +
> +#if !defined(__LOONGARCH_IMAGE_HEADER_H)
> +#define __LOONGARCH_IMAGE_HEADER_H
> +
> +#include <endian.h>
> +#include <stdint.h>
> +
> +/**
> + * struct loongarch_image_header
> + *
> + * @pe_sig: Optional PE format 'MZ' signature.
> + * @reserved_1: Reserved.
> + * @kernel_entry: Kernel image entry pointer.
> + * @image_size: An estimated size of the memory image size in LSB byte order.
> + * @text_offset: The image load offset in LSB byte order.
> + * @reserved_2: Reserved.
> + * @reserved_3: Reserved.
> + * @pe_header: Optional offset to a PE format header.
> + **/
> +
> +struct loongarch_image_header {
> +       uint8_t pe_sig[2];
> +       uint16_t reserved_1[3];
> +       uint64_t kernel_entry;
> +       uint64_t image_size;
> +       uint64_t text_offset;
> +       uint64_t reserved_2[3];
> +       uint32_t reserved_3;
> +       uint32_t pe_header;
> +};
> +
> +static const uint8_t loongarch_image_pe_sig[2] = {'M', 'Z'};
> +
> +/**
> + * loongarch_header_check_pe_sig - Helper to check the loongarch image header.
> + *
> + * Returns non-zero if 'MZ' signature is found.
> + */
> +
> +static inline int loongarch_header_check_pe_sig(const struct loongarch_image_header *h)
> +{
> +       if (!h)
> +               return 0;
> +
> +       return (h->pe_sig[0] == loongarch_image_pe_sig[0]
> +               && h->pe_sig[1] == loongarch_image_pe_sig[1]);
> +}
> +
> +static inline uint64_t loongarch_header_text_offset(
> +       const struct loongarch_image_header *h)
> +{
> +       if (!h)
> +               return 0;
> +
> +       return le64toh(h->text_offset);
> +}
> +
> +static inline uint64_t loongarch_header_image_size(
> +       const struct loongarch_image_header *h)
> +{
> +       if (!h)
> +               return 0;
> +
> +       return le64toh(h->image_size);
> +}
> +
> +static inline uint64_t loongarch_header_kernel_entry(
> +       const struct loongarch_image_header *h)
> +{
> +       if (!h)
> +               return 0;
> +
> +       return le64toh(h->kernel_entry);
> +}
> +
> +#endif
> diff --git a/kexec/arch/loongarch/kexec-elf-loongarch.c b/kexec/arch/loongarch/kexec-elf-loongarch.c
> index a5ec356..2bf128f 100644
> --- a/kexec/arch/loongarch/kexec-elf-loongarch.c
> +++ b/kexec/arch/loongarch/kexec-elf-loongarch.c
> @@ -50,6 +50,7 @@ out:
>  int elf_loongarch_load(int argc, char **argv, const char *kernel_buf,
>         off_t kernel_size, struct kexec_info *info)
>  {
> +       const struct loongarch_image_header *header = NULL;
>         unsigned long kernel_segment;
>         struct mem_ehdr ehdr;
>         int result;
> @@ -76,6 +77,8 @@ int elf_loongarch_load(int argc, char **argv, const char *kernel_buf,
>                 loongarch_mem.text_offset);
>         dbgprintf("%s: phys_offset:    %016lx\n", __func__,
>                 loongarch_mem.phys_offset);
> +       dbgprintf("%s: PE format:      %s\n", __func__,
> +               (loongarch_header_check_pe_sig(header) ? "yes" : "no"));
>
>         /* create and initialize elf core header segment */
>         if (info->kexec_flags & KEXEC_ON_CRASH) {
> diff --git a/kexec/arch/loongarch/kexec-loongarch.c b/kexec/arch/loongarch/kexec-loongarch.c
> index ce7db2c..3fdba01 100644
> --- a/kexec/arch/loongarch/kexec-loongarch.c
> +++ b/kexec/arch/loongarch/kexec-loongarch.c
> @@ -165,6 +165,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
>
>  struct file_type file_type[] = {
>         {"elf-loongarch", elf_loongarch_probe, elf_loongarch_load, elf_loongarch_usage},
> +       {"pei-loongarch", pei_loongarch_probe, pei_loongarch_load, pei_loongarch_usage},
>  };
>  int file_types = sizeof(file_type) / sizeof(file_type[0]);
>
> @@ -172,6 +173,24 @@ int file_types = sizeof(file_type) / sizeof(file_type[0]);
>
>  struct loongarch_mem loongarch_mem;
>
> +/**
> + * loongarch_process_image_header - Process the loongarch image header.
> + */
> +
> +int loongarch_process_image_header(const struct loongarch_image_header *h)
> +{
> +
> +       if (!loongarch_header_check_pe_sig(h))
> +               return EFAILED;
> +
> +       if (h->image_size) {
> +               loongarch_mem.text_offset = loongarch_header_text_offset(h);
> +               loongarch_mem.image_size = loongarch_header_image_size(h);
> +       }
> +
> +       return 0;
> +}
> +
>  void arch_usage(void)
>  {
>         printf(loongarch_opts_usage);
> diff --git a/kexec/arch/loongarch/kexec-loongarch.h b/kexec/arch/loongarch/kexec-loongarch.h
> index cb9b79a..5120a26 100644
> --- a/kexec/arch/loongarch/kexec-loongarch.h
> +++ b/kexec/arch/loongarch/kexec-loongarch.h
> @@ -3,6 +3,8 @@
>
>  #include <sys/types.h>
>
> +#include "image-header.h"
> +
>  #define BOOT_BLOCK_VERSION 17
>  #define BOOT_BLOCK_LAST_COMP_VERSION 16
>
> @@ -21,6 +23,13 @@ int elf_loongarch_load(int argc, char **argv, const char *buf, off_t len,
>         struct kexec_info *info);
>  void elf_loongarch_usage(void);
>
> +int pei_loongarch_probe(const char *buf, off_t len);
> +int pei_loongarch_load(int argc, char **argv, const char *buf, off_t len,
> +       struct kexec_info *info);
> +void pei_loongarch_usage(void);
> +
> +int loongarch_process_image_header(const struct loongarch_image_header *h);
> +
>  unsigned long loongarch_locate_kernel_segment(struct kexec_info *info);
>  int loongarch_load_other_segments(struct kexec_info *info,
>         unsigned long hole_min);
> diff --git a/kexec/arch/loongarch/kexec-pei-loongarch.c b/kexec/arch/loongarch/kexec-pei-loongarch.c
> new file mode 100644
> index 0000000..f86ac61
> --- /dev/null
> +++ b/kexec/arch/loongarch/kexec-pei-loongarch.c
> @@ -0,0 +1,117 @@
> +/*
> + * LoongArch kexec PE format binary image support.
> + *
> + * Copyright (C) 2022 Loongson Technology Corporation Limited.
> + *   Youling Tang <tangyouling at loongson.cn>
> + *
> + * derived from kexec-image-arm64.c
> + *
> + * This source code is licensed under the GNU General Public License,
> + * Version 2.  See the file COPYING for more details.
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <limits.h>
> +#include <errno.h>
> +#include <elf.h>
> +
> +#include "kexec.h"
> +#include "kexec-elf.h"
> +#include "image-header.h"
> +#include "kexec-syscall.h"
> +#include "crashdump-loongarch.h"
> +#include "kexec-loongarch.h"
> +#include "arch/options.h"
> +
> +int pei_loongarch_probe(const char *kernel_buf, off_t kernel_size)
> +{
> +       const struct loongarch_image_header *h;
> +
> +       if (kernel_size < sizeof(struct loongarch_image_header)) {
> +               dbgprintf("%s: No loongarch image header.\n", __func__);
> +               return -1;
> +       }
> +
> +       h = (const struct loongarch_image_header *)(kernel_buf);
> +
> +       if (!loongarch_header_check_pe_sig(h)) {
> +               dbgprintf("%s: Bad loongarch PE image header.\n", __func__);
> +               return -1;
> +       }
> +
> +       return 0;
> +}
> +
> +int pei_loongarch_load(int argc, char **argv, const char *buf,
> +       off_t len, struct kexec_info *info)
> +{
> +       int result;
> +       unsigned long hole_min = 0;
> +       unsigned long kernel_segment, kernel_entry;
> +       const struct loongarch_image_header *header;
> +
> +       header = (const struct loongarch_image_header *)(buf);
> +
> +       if (loongarch_process_image_header(header))
> +               return EFAILED;
> +
> +       kernel_segment = loongarch_locate_kernel_segment(info);
> +
> +       if (kernel_segment == ULONG_MAX) {
> +               dbgprintf("%s: Kernel segment is not allocated\n", __func__);
> +               result = EFAILED;
> +               goto exit;
> +       }
> +
> +       kernel_entry = virt_to_phys(loongarch_header_kernel_entry(header));
> +
> +       dbgprintf("%s: kernel_segment: %016lx\n", __func__, kernel_segment);
> +       dbgprintf("%s: kernel_entry:   %016lx\n", __func__, kernel_entry);
> +       dbgprintf("%s: image_size:     %016lx\n", __func__,
> +               loongarch_mem.image_size);
> +       dbgprintf("%s: text_offset:    %016lx\n", __func__,
> +               loongarch_mem.text_offset);
> +       dbgprintf("%s: phys_offset:    %016lx\n", __func__,
> +               loongarch_mem.phys_offset);
> +       dbgprintf("%s: PE format:      %s\n", __func__,
> +               (loongarch_header_check_pe_sig(header) ? "yes" : "no"));
> +
> +       /* Get kernel entry point */
> +       info->entry = (void *)kernel_entry;
> +
> +       hole_min = kernel_segment + loongarch_mem.image_size;
> +
> +       /* Create and initialize elf core header segment */
> +       if (info->kexec_flags & KEXEC_ON_CRASH) {
> +               result = load_crashdump_segments(info);
> +               if (result) {
> +                       dbgprintf("%s: Creating eflcorehdr failed.\n",
> +                                                               __func__);
> +                       goto exit;
> +               }
> +       }
> +
> +       /* Load the kernel */
> +       add_segment(info, buf, len, kernel_segment, loongarch_mem.image_size);
> +
> +       /* Prepare and load dtb and initrd data */
> +       result = loongarch_load_other_segments(info, hole_min);
> +       if (result) {
> +               fprintf(stderr, "kexec: Load dtb and initrd segments failed.\n");
> +               goto exit;
> +       }
> +
> +exit:
> +       if (result)
> +               fprintf(stderr, "kexec: load failed.\n");
> +
> +       return result;
> +}
> +
> +void pei_loongarch_usage(void)
> +{
> +       printf(
> +"     An LoongArch PE format binary image, uncompressed, little endian.\n"
> +"     Typically a vmlinux.efi file.\n\n");
> +}
> --
> 2.36.0
>
>
> _______________________________________________
> kexec mailing list
> kexec at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec



More information about the kexec mailing list