[PATCH V9 21/24] LoongArch: Add zboot (compressed kernel) support

Huacai Chen chenhuacai at gmail.com
Sat Apr 30 22:22:25 PDT 2022


Hi, Arnd,

On Sat, Apr 30, 2022 at 7:02 PM Arnd Bergmann <arnd at arndb.de> wrote:
>
> On Sat, Apr 30, 2022 at 11:05 AM Huacai Chen <chenhuacai at loongson.cn> wrote:
> >
> > This patch adds zboot (self-extracting compressed kernel) support, all
> > existing in-kernel compressing algorithm and efistub are supported.
> >
> > Signed-off-by: Huacai Chen <chenhuacai at loongson.cn>
>
> I have no objections to adding a decompressor in principle, and
> the implementation seems reasonable. However, I think we should try to
> be consistent between architectures. On both arm64 and riscv, the
> maintainers decided to not include a decompressor and instead leave
> it up to the boot loader to decompress the kernel and enter it from there.
X86, ARM32 and MIPS already support self-extracting kernel, and in
5.17 we even support self-extracting modules. So I think a
self-extracting kernel is better than a pure compressed kernel.

>
> As I understand it, this is not part of the UEFI boot flow though, so it
> means that you don't get any compressed kernel images at all when
> booting using UEFI (let me know if that is wrong). I assume this is why
> you decided to include the decompressor here after all.
>
> I think we should first aim for consistency here, and handle this the
> same way across the modern architectures, either leaving the
> decompressor code out, or adding it consistently. Maybe it would
> even be possible to have the decompressor code as part of the
> EFI stub and share it between the three architectures (x86 and
> 32-bit arm already support loading compressed kernels using EFI).
>
> Adding the arm64, risc-v and uefi maintainers for further discussion here,
> see full below.
Keeping consistency across architectures (support self-extracting for
all modern architectures) looks good to me, but can we do that after
this series? I think that needs a long time to discuss and develop.

Huacai
>
>        Arnd
>
> > ---
> >  arch/loongarch/Kbuild                         |   2 +-
> >  arch/loongarch/Kconfig                        |  11 ++
> >  arch/loongarch/Makefile                       |  26 ++-
> >  arch/loongarch/boot/Makefile                  |  55 ++++++
> >  arch/loongarch/boot/boot.lds.S                |  64 +++++++
> >  arch/loongarch/boot/decompress.c              |  98 +++++++++++
> >  arch/loongarch/boot/string.c                  | 166 ++++++++++++++++++
> >  arch/loongarch/boot/zheader.S                 | 100 +++++++++++
> >  arch/loongarch/boot/zkernel.S                 |  99 +++++++++++
> >  arch/loongarch/tools/Makefile                 |  15 ++
> >  arch/loongarch/tools/calc_vmlinuz_load_addr.c |  51 ++++++
> >  arch/loongarch/tools/elf-entry.c              |  66 +++++++
> >  12 files changed, 749 insertions(+), 4 deletions(-)
> >  create mode 100644 arch/loongarch/boot/boot.lds.S
> >  create mode 100644 arch/loongarch/boot/decompress.c
> >  create mode 100644 arch/loongarch/boot/string.c
> >  create mode 100644 arch/loongarch/boot/zheader.S
> >  create mode 100644 arch/loongarch/boot/zkernel.S
> >  create mode 100644 arch/loongarch/tools/Makefile
> >  create mode 100644 arch/loongarch/tools/calc_vmlinuz_load_addr.c
> >  create mode 100644 arch/loongarch/tools/elf-entry.c
> >
> > diff --git a/arch/loongarch/Kbuild b/arch/loongarch/Kbuild
> > index ab5373d0a24f..d907fdd7ca08 100644
> > --- a/arch/loongarch/Kbuild
> > +++ b/arch/loongarch/Kbuild
> > @@ -3,4 +3,4 @@ obj-y += mm/
> >  obj-y += vdso/
> >
> >  # for cleaning
> > -subdir- += boot
> > +subdir- += boot tools
> > diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> > index 55225ee5f868..6c1042746b2d 100644
> > --- a/arch/loongarch/Kconfig
> > +++ b/arch/loongarch/Kconfig
> > @@ -107,6 +107,7 @@ config LOONGARCH
> >         select PERF_USE_VMALLOC
> >         select RTC_LIB
> >         select SPARSE_IRQ
> > +       select SYS_SUPPORTS_ZBOOT
> >         select SYSCTL_EXCEPTION_TRACE
> >         select SWIOTLB
> >         select TRACE_IRQFLAGS_SUPPORT
> > @@ -143,6 +144,16 @@ config LOCKDEP_SUPPORT
> >         bool
> >         default y
> >
> > +config SYS_SUPPORTS_ZBOOT
> > +       bool
> > +       select HAVE_KERNEL_GZIP
> > +       select HAVE_KERNEL_BZIP2
> > +       select HAVE_KERNEL_LZ4
> > +       select HAVE_KERNEL_LZMA
> > +       select HAVE_KERNEL_LZO
> > +       select HAVE_KERNEL_XZ
> > +       select HAVE_KERNEL_ZSTD
> > +
> >  config MACH_LOONGSON32
> >         def_bool 32BIT
> >
> > diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> > index d88a792dafbe..1ed5b8466565 100644
> > --- a/arch/loongarch/Makefile
> > +++ b/arch/loongarch/Makefile
> > @@ -5,12 +5,31 @@
> >
> >  boot   := arch/loongarch/boot
> >
> > +ifndef CONFIG_SYS_SUPPORTS_ZBOOT
> > +
> >  ifndef CONFIG_EFI_STUB
> >  KBUILD_IMAGE   = $(boot)/vmlinux
> >  else
> >  KBUILD_IMAGE   = $(boot)/vmlinux.efi
> >  endif
> >
> > +else
> > +
> > +ifndef CONFIG_EFI_STUB
> > +KBUILD_IMAGE   = $(boot)/vmlinuz
> > +else
> > +KBUILD_IMAGE   = $(boot)/vmlinuz.efi
> > +endif
> > +
> > +endif
> > +
> > +load-y         = 0x9000000000200000
> > +bootvars-y     = VMLINUX_LOAD_ADDRESS=$(load-y)
> > +
> > +archscripts: scripts_basic
> > +       $(Q)$(MAKE) $(build)=arch/loongarch/tools elf-entry
> > +       $(Q)$(MAKE) $(build)=arch/loongarch/tools calc_vmlinuz_load_addr
> > +
> >  #
> >  # Select the object file format to substitute into the linker script.
> >  #
> > @@ -55,9 +74,6 @@ KBUILD_CFLAGS_MODULE          += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
> >  cflags-y += -ffreestanding
> >  cflags-y += $(call as-option,-Wa$(comma)-mno-fix-loongson3-llsc,)
> >
> > -load-y         = 0x9000000000200000
> > -bootvars-y     = VMLINUX_LOAD_ADDRESS=$(load-y)
> > -
> >  drivers-$(CONFIG_PCI)          += arch/loongarch/pci/
> >
> >  KBUILD_AFLAGS  += $(cflags-y)
> > @@ -99,7 +115,11 @@ $(KBUILD_IMAGE): vmlinux
> >         $(Q)$(MAKE) $(build)=$(boot) $(bootvars-y) $@
> >
> >  install:
> > +ifndef CONFIG_SYS_SUPPORTS_ZBOOT
> >         $(Q)install -D -m 755 $(KBUILD_IMAGE) $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE)
> > +else
> > +       $(Q)install -D -m 755 $(KBUILD_IMAGE) $(INSTALL_PATH)/vmlinuz-$(KERNELRELEASE)
> > +endif
> >         $(Q)install -D -m 644 .config $(INSTALL_PATH)/config-$(KERNELRELEASE)
> >         $(Q)install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE)
> >
> > diff --git a/arch/loongarch/boot/Makefile b/arch/loongarch/boot/Makefile
> > index 66f2293c34b2..c26a36004ae2 100644
> > --- a/arch/loongarch/boot/Makefile
> > +++ b/arch/loongarch/boot/Makefile
> > @@ -21,3 +21,58 @@ quiet_cmd_eficopy = OBJCOPY $@
> >
> >  $(obj)/vmlinux.efi: $(obj)/vmlinux FORCE
> >         $(call if_changed,eficopy)
> > +
> > +# zboot
> > +extra-y        += boot.lds
> > +$(obj)/boot.lds: $(obj)/vmlinux.bin FORCE
> > +CPPFLAGS_boot.lds = $(KBUILD_CPPFLAGS) -DVMLINUZ_LOAD_ADDRESS=$(zload-y)
> > +
> > +entry-y        = $(shell $(objtree)/arch/loongarch/tools/elf-entry $(obj)/vmlinux)
> > +zload-y = $(shell $(objtree)/arch/loongarch/tools/calc_vmlinuz_load_addr \
> > +                               $(obj)/vmlinux.bin $(VMLINUX_LOAD_ADDRESS))
> > +
> > +BOOT_HEAP_SIZE := 0x400000
> > +BOOT_STACK_SIZE        := 0x002000
> > +
> > +KBUILD_AFLAGS := $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
> > +       -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \
> > +       -DBOOT_STACK_SIZE=$(BOOT_STACK_SIZE)
> > +
> > +KBUILD_CFLAGS := $(KBUILD_CFLAGS) -fpic -D__KERNEL__ \
> > +       -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \
> > +       -DBOOT_STACK_SIZE=$(BOOT_STACK_SIZE)
> > +
> > +targets += vmlinux.bin
> > +OBJCOPYFLAGS_vmlinux.bin := $(OBJCOPYFLAGS) -O binary $(strip-flags)
> > +$(obj)/vmlinux.bin: $(obj)/vmlinux FORCE
> > +       $(call if_changed,objcopy)
> > +
> > +tool_$(CONFIG_KERNEL_GZIP)    = gzip
> > +tool_$(CONFIG_KERNEL_BZIP2)   = bzip2_with_size
> > +tool_$(CONFIG_KERNEL_LZ4)     = lz4_with_size
> > +tool_$(CONFIG_KERNEL_LZMA)    = lzma_with_size
> > +tool_$(CONFIG_KERNEL_LZO)     = lzo_with_size
> > +tool_$(CONFIG_KERNEL_XZ)      = xzkern_with_size
> > +tool_$(CONFIG_KERNEL_ZSTD)    = zstd22_with_size
> > +
> > +targets += vmlinux.bin.z
> > +$(obj)/vmlinux.bin.z: $(obj)/vmlinux.bin FORCE
> > +       $(call if_changed,$(tool_y))
> > +
> > +targets += $(notdir $(vmlinuzobjs-y))
> > +vmlinuzobjs-y := $(obj)/zkernel.o $(obj)/decompress.o $(obj)/string.o
> > +vmlinuzobjs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
> > +$(obj)/zkernel.o: $(obj)/vmlinux.bin.z
> > +AFLAGS_zkernel.o = $(KBUILD_AFLAGS) -DVMLINUZ_LOAD_ADDRESS=$(zload-y) -DKERNEL_ENTRY=$(entry-y)
> > +
> > +quiet_cmd_zld = LD      $@
> > +      cmd_zld = $(LD) $(KBUILD_LDFLAGS) -T $< $(vmlinuzobjs-y) -o $@
> > +
> > +targets += vmlinuz
> > +$(obj)/vmlinuz: $(src)/boot.lds $(vmlinuzobjs-y) FORCE
> > +       $(call if_changed,zld)
> > +       $(call if_changed,strip)
> > +
> > +targets += vmlinuz.efi
> > +$(obj)/vmlinuz.efi: $(obj)/vmlinuz FORCE
> > +       $(call if_changed,eficopy)
> > diff --git a/arch/loongarch/boot/boot.lds.S b/arch/loongarch/boot/boot.lds.S
> > new file mode 100644
> > index 000000000000..23e698782afd
> > --- /dev/null
> > +++ b/arch/loongarch/boot/boot.lds.S
> > @@ -0,0 +1,64 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * ld.script for compressed kernel support of LoongArch
> > + *
> > + * Author: Huacai Chen <chenhuacai at loongson.cn>
> > + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > + */
> > +
> > +#include "../kernel/image-vars.h"
> > +
> > +/*
> > + * Max avaliable Page Size is 64K, so we set SectionAlignment
> > + * field of EFI application to 64K.
> > + */
> > +PECOFF_FILE_ALIGN = 0x200;
> > +PECOFF_SEGMENT_ALIGN = 0x10000;
> > +
> > +OUTPUT_ARCH(loongarch)
> > +ENTRY(kernel_entry)
> > +PHDRS {
> > +       text PT_LOAD FLAGS(7); /* RWX */
> > +}
> > +SECTIONS
> > +{
> > +       . = VMLINUZ_LOAD_ADDRESS;
> > +
> > +       _text = .;
> > +       .head.text : {
> > +               *(.head.text)
> > +       }
> > +
> > +       .text : {
> > +               *(.text)
> > +               *(.init.text)
> > +               *(.rodata)
> > +       }: text
> > +
> > +       . = ALIGN(PECOFF_SEGMENT_ALIGN);
> > +       _data = .;
> > +       .data : {
> > +               *(.data)
> > +               *(.init.data)
> > +               /* Put the compressed image here */
> > +               __image_begin = .;
> > +               *(.image)
> > +               __image_end = .;
> > +               CONSTRUCTORS
> > +               . = ALIGN(PECOFF_FILE_ALIGN);
> > +       }
> > +       _edata = .;
> > +
> > +       .bss : {
> > +               *(.bss)
> > +               *(.init.bss)
> > +       }
> > +       . = ALIGN(PECOFF_SEGMENT_ALIGN);
> > +       _end = .;
> > +
> > +       /DISCARD/ : {
> > +               *(.options)
> > +               *(.comment)
> > +               *(.note)
> > +       }
> > +}
> > diff --git a/arch/loongarch/boot/decompress.c b/arch/loongarch/boot/decompress.c
> > new file mode 100644
> > index 000000000000..8f55fcd8f285
> > --- /dev/null
> > +++ b/arch/loongarch/boot/decompress.c
> > @@ -0,0 +1,98 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Author: Huacai Chen <chenhuacai at loongson.cn>
> > + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > + */
> > +
> > +#include <linux/types.h>
> > +#include <linux/kernel.h>
> > +#include <linux/string.h>
> > +#include <linux/libfdt.h>
> > +
> > +#include <asm/addrspace.h>
> > +
> > +/*
> > + * These two variables specify the free mem region
> > + * that can be used for temporary malloc area
> > + */
> > +unsigned long free_mem_ptr;
> > +unsigned long free_mem_end_ptr;
> > +
> > +/* The linker tells us where the image is. */
> > +extern unsigned char __image_begin, __image_end;
> > +
> > +#define puts(s) do {} while (0)
> > +#define puthex(val) do {} while (0)
> > +
> > +void error(char *x)
> > +{
> > +       puts("\n\n");
> > +       puts(x);
> > +       puts("\n\n -- System halted");
> > +
> > +       while (1)
> > +               ;       /* Halt */
> > +}
> > +
> > +/* activate the code for pre-boot environment */
> > +#define STATIC static
> > +
> > +#include "../../../../lib/ashldi3.c"
> > +
> > +#ifdef CONFIG_KERNEL_GZIP
> > +#include "../../../../lib/decompress_inflate.c"
> > +#endif
> > +
> > +#ifdef CONFIG_KERNEL_BZIP2
> > +#include "../../../../lib/decompress_bunzip2.c"
> > +#endif
> > +
> > +#ifdef CONFIG_KERNEL_LZ4
> > +#include "../../../../lib/decompress_unlz4.c"
> > +#endif
> > +
> > +#ifdef CONFIG_KERNEL_LZMA
> > +#include "../../../../lib/decompress_unlzma.c"
> > +#endif
> > +
> > +#ifdef CONFIG_KERNEL_LZO
> > +#include "../../../../lib/decompress_unlzo.c"
> > +#endif
> > +
> > +#ifdef CONFIG_KERNEL_XZ
> > +#include "../../../../lib/decompress_unxz.c"
> > +#endif
> > +
> > +#ifdef CONFIG_KERNEL_ZSTD
> > +#include "../../../../lib/decompress_unzstd.c"
> > +#endif
> > +
> > +void decompress_kernel(unsigned long boot_heap_start)
> > +{
> > +       unsigned long zimage_start, zimage_size;
> > +
> > +       zimage_start = (unsigned long)(&__image_begin);
> > +       zimage_size = (unsigned long)(&__image_end) -
> > +           (unsigned long)(&__image_begin);
> > +
> > +       puts("zimage at:     ");
> > +       puthex(zimage_start);
> > +       puts(" ");
> > +       puthex(zimage_size + zimage_start);
> > +       puts("\n");
> > +
> > +       /* This area are prepared for mallocing when decompressing */
> > +       free_mem_ptr = boot_heap_start;
> > +       free_mem_end_ptr = boot_heap_start + BOOT_HEAP_SIZE;
> > +
> > +       /* Display standard Linux/LoongArch boot prompt */
> > +       puts("Uncompressing Linux at load address ");
> > +       puthex(VMLINUX_LOAD_ADDRESS);
> > +       puts("\n");
> > +
> > +       /* Decompress the kernel with according algorithm */
> > +       __decompress((char *)zimage_start, zimage_size, 0, 0,
> > +                  (void *)VMLINUX_LOAD_ADDRESS, 0, 0, error);
> > +
> > +       puts("Now, booting the kernel...\n");
> > +}
> > diff --git a/arch/loongarch/boot/string.c b/arch/loongarch/boot/string.c
> > new file mode 100644
> > index 000000000000..3f746e7c2bb5
> > --- /dev/null
> > +++ b/arch/loongarch/boot/string.c
> > @@ -0,0 +1,166 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * arch/loongarch/boot/string.c
> > + *
> > + * Very small subset of simple string routines
> > + */
> > +
> > +#include <linux/types.h>
> > +
> > +void __weak *memset(void *s, int c, size_t n)
> > +{
> > +       int i;
> > +       char *ss = s;
> > +
> > +       for (i = 0; i < n; i++)
> > +               ss[i] = c;
> > +       return s;
> > +}
> > +
> > +void __weak *memcpy(void *dest, const void *src, size_t n)
> > +{
> > +       int i;
> > +       const char *s = src;
> > +       char *d = dest;
> > +
> > +       for (i = 0; i < n; i++)
> > +               d[i] = s[i];
> > +       return dest;
> > +}
> > +
> > +void __weak *memmove(void *dest, const void *src, size_t n)
> > +{
> > +       int i;
> > +       const char *s = src;
> > +       char *d = dest;
> > +
> > +       if (d < s) {
> > +               for (i = 0; i < n; i++)
> > +                       d[i] = s[i];
> > +       } else if (d > s) {
> > +               for (i = n - 1; i >= 0; i--)
> > +                       d[i] = s[i];
> > +       }
> > +
> > +       return dest;
> > +}
> > +
> > +int __weak memcmp(const void *cs, const void *ct, size_t count)
> > +{
> > +       int res = 0;
> > +       const unsigned char *su1, *su2;
> > +
> > +       for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) {
> > +               res = *su1 - *su2;
> > +               if (res != 0)
> > +                       break;
> > +       }
> > +       return res;
> > +}
> > +
> > +int __weak strcmp(const char *str1, const char *str2)
> > +{
> > +       int delta = 0;
> > +       const unsigned char *s1 = (const unsigned char *)str1;
> > +       const unsigned char *s2 = (const unsigned char *)str2;
> > +
> > +       while (*s1 || *s2) {
> > +               delta = *s1 - *s2;
> > +               if (delta)
> > +                       return delta;
> > +               s1++;
> > +               s2++;
> > +       }
> > +       return 0;
> > +}
> > +
> > +size_t __weak strlen(const char *s)
> > +{
> > +       const char *sc;
> > +
> > +       for (sc = s; *sc != '\0'; ++sc)
> > +               /* nothing */;
> > +       return sc - s;
> > +}
> > +
> > +size_t __weak strnlen(const char *s, size_t count)
> > +{
> > +       const char *sc;
> > +
> > +       for (sc = s; count-- && *sc != '\0'; ++sc)
> > +               /* nothing */;
> > +       return sc - s;
> > +}
> > +
> > +char * __weak strnstr(const char *s1, const char *s2, size_t len)
> > +{
> > +       size_t l2;
> > +
> > +       l2 = strlen(s2);
> > +       if (!l2)
> > +               return (char *)s1;
> > +       while (len >= l2) {
> > +               len--;
> > +               if (!memcmp(s1, s2, l2))
> > +                       return (char *)s1;
> > +               s1++;
> > +       }
> > +       return NULL;
> > +}
> > +
> > +#undef strcat
> > +char * __weak strcat(char *dest, const char *src)
> > +{
> > +       char *tmp = dest;
> > +
> > +       while (*dest)
> > +               dest++;
> > +       while ((*dest++ = *src++) != '\0')
> > +               ;
> > +       return tmp;
> > +}
> > +
> > +char * __weak strncat(char *dest, const char *src, size_t count)
> > +{
> > +       char *tmp = dest;
> > +
> > +       if (count) {
> > +               while (*dest)
> > +                       dest++;
> > +               while ((*dest++ = *src++) != 0) {
> > +                       if (--count == 0) {
> > +                               *dest = '\0';
> > +                               break;
> > +                       }
> > +               }
> > +       }
> > +       return tmp;
> > +}
> > +
> > +char * __weak strpbrk(const char *cs, const char *ct)
> > +{
> > +       const char *sc1, *sc2;
> > +
> > +       for (sc1 = cs; *sc1 != '\0'; ++sc1) {
> > +               for (sc2 = ct; *sc2 != '\0'; ++sc2) {
> > +                       if (*sc1 == *sc2)
> > +                               return (char *)sc1;
> > +               }
> > +       }
> > +       return NULL;
> > +}
> > +
> > +char * __weak strsep(char **s, const char *ct)
> > +{
> > +       char *sbegin = *s;
> > +       char *end;
> > +
> > +       if (sbegin == NULL)
> > +               return NULL;
> > +
> > +       end = strpbrk(sbegin, ct);
> > +       if (end)
> > +               *end++ = '\0';
> > +       *s = end;
> > +       return sbegin;
> > +}
> > diff --git a/arch/loongarch/boot/zheader.S b/arch/loongarch/boot/zheader.S
> > new file mode 100644
> > index 000000000000..4bc50d953ec7
> > --- /dev/null
> > +++ b/arch/loongarch/boot/zheader.S
> > @@ -0,0 +1,100 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > + */
> > +
> > +#include <linux/pe.h>
> > +#include <linux/sizes.h>
> > +
> > +       .macro  __EFI_PE_HEADER
> > +       .long   PE_MAGIC
> > +coff_header:
> > +       .short  IMAGE_FILE_MACHINE_LOONGARCH            /* Machine */
> > +       .short  section_count                           /* NumberOfSections */
> > +       .long   0                                       /* TimeDateStamp */
> > +       .long   0                                       /* PointerToSymbolTable */
> > +       .long   0                                       /* NumberOfSymbols */
> > +       .short  section_table - optional_header         /* SizeOfOptionalHeader */
> > +       .short  IMAGE_FILE_DEBUG_STRIPPED | \
> > +               IMAGE_FILE_EXECUTABLE_IMAGE | \
> > +               IMAGE_FILE_LINE_NUMS_STRIPPED           /* Characteristics */
> > +
> > +optional_header:
> > +       .short  PE_OPT_MAGIC_PE32PLUS                   /* PE32+ format */
> > +       .byte   0x02                                    /* MajorLinkerVersion */
> > +       .byte   0x14                                    /* MinorLinkerVersion */
> > +       .long   _data - efi_header_end                  /* SizeOfCode */
> > +       .long   _end - _data                            /* SizeOfInitializedData */
> > +       .long   0                                       /* SizeOfUninitializedData */
> > +       .long   __efistub_efi_pe_entry - _head          /* AddressOfEntryPoint */
> > +       .long   efi_header_end - _head                  /* BaseOfCode */
> > +
> > +extra_header_fields:
> > +       .quad   0                                       /* ImageBase */
> > +       .long   PECOFF_SEGMENT_ALIGN                    /* SectionAlignment */
> > +       .long   PECOFF_FILE_ALIGN                       /* FileAlignment */
> > +       .short  0                                       /* MajorOperatingSystemVersion */
> > +       .short  0                                       /* MinorOperatingSystemVersion */
> > +       .short  0                                       /* MajorImageVersion */
> > +       .short  0                                       /* MinorImageVersion */
> > +       .short  0                                       /* MajorSubsystemVersion */
> > +       .short  0                                       /* MinorSubsystemVersion */
> > +       .long   0                                       /* Win32VersionValue */
> > +
> > +       .long   _end - _head                            /* SizeOfImage */
> > +
> > +       /* Everything before the kernel image is considered part of the header */
> > +       .long   efi_header_end - _head                  /* SizeOfHeaders */
> > +       .long   0                                       /* CheckSum */
> > +       .short  IMAGE_SUBSYSTEM_EFI_APPLICATION         /* Subsystem */
> > +       .short  0                                       /* DllCharacteristics */
> > +       .quad   0                                       /* SizeOfStackReserve */
> > +       .quad   0                                       /* SizeOfStackCommit */
> > +       .quad   0                                       /* SizeOfHeapReserve */
> > +       .quad   0                                       /* SizeOfHeapCommit */
> > +       .long   0                                       /* LoaderFlags */
> > +       .long   (section_table - .) / 8                 /* NumberOfRvaAndSizes */
> > +
> > +       .quad   0                                       /* ExportTable */
> > +       .quad   0                                       /* ImportTable */
> > +       .quad   0                                       /* ResourceTable */
> > +       .quad   0                                       /* ExceptionTable */
> > +       .quad   0                                       /* CertificationTable */
> > +       .quad   0                                       /* BaseRelocationTable */
> > +
> > +       /* Section table */
> > +section_table:
> > +       .ascii  ".text\0\0\0"
> > +       .long   _data - efi_header_end                  /* VirtualSize */
> > +       .long   efi_header_end - _head                  /* VirtualAddress */
> > +       .long   _data - efi_header_end                  /* SizeOfRawData */
> > +       .long   efi_header_end - _head                  /* PointerToRawData */
> > +
> > +       .long   0                                       /* PointerToRelocations */
> > +       .long   0                                       /* PointerToLineNumbers */
> > +       .short  0                                       /* NumberOfRelocations */
> > +       .short  0                                       /* NumberOfLineNumbers */
> > +       .long   IMAGE_SCN_CNT_CODE | \
> > +               IMAGE_SCN_MEM_READ | \
> > +               IMAGE_SCN_MEM_EXECUTE                   /* Characteristics */
> > +
> > +       .ascii  ".data\0\0\0"
> > +       .long   _end - _data                            /* VirtualSize */
> > +       .long   _data - _head                           /* VirtualAddress */
> > +       .long   _edata - _data                          /* SizeOfRawData */
> > +       .long   _data - _head                           /* PointerToRawData */
> > +
> > +       .long   0                                       /* PointerToRelocations */
> > +       .long   0                                       /* PointerToLineNumbers */
> > +       .short  0                                       /* NumberOfRelocations */
> > +       .short  0                                       /* NumberOfLineNumbers */
> > +       .long   IMAGE_SCN_CNT_INITIALIZED_DATA | \
> > +               IMAGE_SCN_MEM_READ | \
> > +               IMAGE_SCN_MEM_WRITE                     /* Characteristics */
> > +
> > +       .org 0x20e
> > +       .word kernel_version - 512 -  _head
> > +
> > +       .set    section_count, (. - section_table) / 40
> > +efi_header_end:
> > +       .endm
> > diff --git a/arch/loongarch/boot/zkernel.S b/arch/loongarch/boot/zkernel.S
> > new file mode 100644
> > index 000000000000..13a8a14a2328
> > --- /dev/null
> > +++ b/arch/loongarch/boot/zkernel.S
> > @@ -0,0 +1,99 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/linkage.h>
> > +#include <asm/addrspace.h>
> > +#include <asm/asm.h>
> > +#include <asm/loongarch.h>
> > +#include <asm/regdef.h>
> > +#include <generated/compile.h>
> > +#include <generated/utsrelease.h>
> > +
> > +#ifdef CONFIG_EFI_STUB
> > +
> > +#include "zheader.S"
> > +
> > +       __HEAD
> > +
> > +_head:
> > +       /* "MZ", MS-DOS header */
> > +       .word   MZ_MAGIC
> > +       .org    0x28
> > +       .ascii  "Loongson\0"
> > +       .org    0x3c
> > +       /* Offset to the PE header */
> > +       .long   pe_header - _head
> > +
> > +pe_header:
> > +       __EFI_PE_HEADER
> > +
> > +kernel_asize:
> > +       .long _end - _text
> > +
> > +kernel_fsize:
> > +       .long _edata - _text
> > +
> > +kernel_vaddr:
> > +       .quad VMLINUZ_LOAD_ADDRESS
> > +
> > +kernel_offset:
> > +       .long kernel_offset - _text
> > +
> > +kernel_version:
> > +       .ascii  UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") " UTS_VERSION "\0"
> > +
> > +SYM_L_GLOBAL(kernel_asize)
> > +SYM_L_GLOBAL(kernel_fsize)
> > +SYM_L_GLOBAL(kernel_vaddr)
> > +SYM_L_GLOBAL(kernel_offset)
> > +
> > +#endif
> > +
> > +       __INIT
> > +
> > +SYM_CODE_START(kernel_entry)
> > +       /* Save boot rom start args */
> > +       move    s0, a0
> > +       move    s1, a1
> > +       move    s2, a2
> > +       move    s3, a3
> > +
> > +       /* Config Direct Mapping */
> > +       li.d    t0, CSR_DMW0_INIT
> > +       csrwr   t0, LOONGARCH_CSR_DMWIN0
> > +       li.d    t0, CSR_DMW1_INIT
> > +       csrwr   t0, LOONGARCH_CSR_DMWIN1
> > +
> > +       /* Clear BSS */
> > +       la.abs  a0, _edata
> > +       la.abs  a2, _end
> > +1:     st.d    zero, a0, 0
> > +       addi.d  a0, a0, 8
> > +       bne     a2, a0, 1b
> > +
> > +       la.abs  a0, .heap          /* heap address */
> > +       la.abs  sp, .stack + 8192  /* stack address */
> > +
> > +       la      ra, 2f
> > +       la      t4, decompress_kernel
> > +       jirl    zero, t4, 0
> > +2:
> > +       move    a0, s0
> > +       move    a1, s1
> > +       move    a2, s2
> > +       move    a3, s3
> > +       PTR_LI  t4, KERNEL_ENTRY
> > +       jirl    zero, t4, 0
> > +3:
> > +       b       3b
> > +SYM_CODE_END(kernel_entry)
> > +
> > +       .comm .heap, BOOT_HEAP_SIZE, 4
> > +       .comm .stack, BOOT_STACK_SIZE, 4
> > +
> > +       .align 4
> > +       .section .image, "a", %progbits
> > +       .incbin "arch/loongarch/boot/vmlinux.bin.z"
> > diff --git a/arch/loongarch/tools/Makefile b/arch/loongarch/tools/Makefile
> > new file mode 100644
> > index 000000000000..8a6181c82a91
> > --- /dev/null
> > +++ b/arch/loongarch/tools/Makefile
> > @@ -0,0 +1,15 @@
> > +#
> > +# arch/loongarch/boot/Makefile
> > +#
> > +# Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > +#
> > +
> > +hostprogs := elf-entry
> > +PHONY += elf-entry
> > +elf-entry: $(obj)/elf-entry
> > +       @:
> > +
> > +hostprogs += calc_vmlinuz_load_addr
> > +PHONY += calc_vmlinuz_load_addr
> > +calc_vmlinuz_load_addr: $(obj)/calc_vmlinuz_load_addr
> > +       @:
> > diff --git a/arch/loongarch/tools/calc_vmlinuz_load_addr.c b/arch/loongarch/tools/calc_vmlinuz_load_addr.c
> > new file mode 100644
> > index 000000000000..5e2ca6b4dff6
> > --- /dev/null
> > +++ b/arch/loongarch/tools/calc_vmlinuz_load_addr.c
> > @@ -0,0 +1,51 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > + */
> > +
> > +#include <errno.h>
> > +#include <stdint.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <sys/stat.h>
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +       unsigned long long vmlinux_size, vmlinux_load_addr, vmlinuz_load_addr;
> > +       struct stat sb;
> > +
> > +       if (argc != 3) {
> > +               fprintf(stderr, "Usage: %s <pathname> <vmlinux_load_addr>\n", argv[0]);
> > +               return EXIT_FAILURE;
> > +       }
> > +
> > +       if (stat(argv[1], &sb) == -1) {
> > +               perror("stat");
> > +               return EXIT_FAILURE;
> > +       }
> > +
> > +       /* Convert hex characters to dec number */
> > +       errno = 0;
> > +       if (sscanf(argv[2], "%llx", &vmlinux_load_addr) != 1) {
> > +               if (errno != 0)
> > +                       perror("sscanf");
> > +               else
> > +                       fprintf(stderr, "No matching characters\n");
> > +
> > +               return EXIT_FAILURE;
> > +       }
> > +
> > +       vmlinux_size = (uint64_t)sb.st_size;
> > +       vmlinuz_load_addr = vmlinux_load_addr + vmlinux_size;
> > +
> > +       /*
> > +        * Align with 64KB: KEXEC needs load sections to be aligned to PAGE_SIZE,
> > +        * which may be as large as 64KB depending on the kernel configuration.
> > +        */
> > +
> > +       vmlinuz_load_addr += (0x10000 - vmlinux_size % 0x10000);
> > +
> > +       printf("0x%llx\n", vmlinuz_load_addr);
> > +
> > +       return EXIT_SUCCESS;
> > +}
> > diff --git a/arch/loongarch/tools/elf-entry.c b/arch/loongarch/tools/elf-entry.c
> > new file mode 100644
> > index 000000000000..c80721e0dee1
> > --- /dev/null
> > +++ b/arch/loongarch/tools/elf-entry.c
> > @@ -0,0 +1,66 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +#include <elf.h>
> > +#include <inttypes.h>
> > +#include <stdint.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +
> > +__attribute__((noreturn))
> > +static void die(const char *msg)
> > +{
> > +       fputs(msg, stderr);
> > +       exit(EXIT_FAILURE);
> > +}
> > +
> > +int main(int argc, const char *argv[])
> > +{
> > +       uint64_t entry;
> > +       size_t nread;
> > +       FILE *file;
> > +       union {
> > +               Elf32_Ehdr ehdr32;
> > +               Elf64_Ehdr ehdr64;
> > +       } hdr;
> > +
> > +       if (argc != 2)
> > +               die("Usage: elf-entry <elf-file>\n");
> > +
> > +       file = fopen(argv[1], "r");
> > +       if (!file) {
> > +               perror("Unable to open input file");
> > +               return EXIT_FAILURE;
> > +       }
> > +
> > +       nread = fread(&hdr, 1, sizeof(hdr), file);
> > +       if (nread != sizeof(hdr)) {
> > +               fclose(file);
> > +               perror("Unable to read input file");
> > +               return EXIT_FAILURE;
> > +       }
> > +
> > +       if (memcmp(hdr.ehdr32.e_ident, ELFMAG, SELFMAG)) {
> > +               fclose(file);
> > +               die("Input is not an ELF\n");
> > +       }
> > +
> > +       switch (hdr.ehdr32.e_ident[EI_CLASS]) {
> > +       case ELFCLASS32:
> > +               /* Sign extend to form a canonical address */
> > +               entry = (int64_t)(int32_t)hdr.ehdr32.e_entry;
> > +               break;
> > +
> > +       case ELFCLASS64:
> > +               entry = hdr.ehdr64.e_entry;
> > +               break;
> > +
> > +       default:
> > +               fclose(file);
> > +               die("Invalid ELF class\n");
> > +       }
> > +
> > +       fclose(file);
> > +       printf("0x%016" PRIx64 "\n", entry);
> > +
> > +       return EXIT_SUCCESS;
> > +}
> > --
> > 2.27.0
> >



More information about the linux-riscv mailing list