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> --- 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