Hi, Arnd, On Sat, Apr 30, 2022 at 7:02 PM Arnd Bergmann <arnd@xxxxxxxx> wrote: > > On Sat, Apr 30, 2022 at 11:05 AM Huacai Chen <chenhuacai@xxxxxxxxxxx> 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@xxxxxxxxxxx> > > 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@xxxxxxxxxxx> > > + * 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@xxxxxxxxxxx> > > + * 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 > >