lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Sat, 30 Apr 2022 18:02:14 +0800
From:   Huacai Chen <chenhuacai@...il.com>
To:     Arnd Bergmann <arnd@...db.de>
Cc:     Huacai Chen <chenhuacai@...ngson.cn>,
        Andy Lutomirski <luto@...nel.org>,
        Thomas Gleixner <tglx@...utronix.de>,
        Peter Zijlstra <peterz@...radead.org>,
        Andrew Morton <akpm@...ux-foundation.org>,
        David Airlie <airlied@...ux.ie>,
        Jonathan Corbet <corbet@....net>,
        Linus Torvalds <torvalds@...ux-foundation.org>,
        linux-arch <linux-arch@...r.kernel.org>,
        "open list:DOCUMENTATION" <linux-doc@...r.kernel.org>,
        Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
        Xuefeng Li <lixuefeng@...ngson.cn>,
        Yanteng Si <siyanteng@...ngson.cn>,
        Guo Ren <guoren@...nel.org>, Xuerui Wang <kernel@...0n.name>,
        Jiaxun Yang <jiaxun.yang@...goat.com>,
        Ard Biesheuvel <ardb@...nel.org>
Subject: Re: [PATCH V9 20/24] LoongArch: Add efistub booting support

Hi, Arnd,

On Sat, Apr 30, 2022 at 5:56 PM Arnd Bergmann <arnd@...db.de> wrote:
>
> On Sat, Apr 30, 2022 at 11:05 AM Huacai Chen <chenhuacai@...ngson.cn> wrote:
> >
> > This patch adds efistub booting support, which is the standard UEFI boot
> > protocol for us to use.
> >
> > Signed-off-by: Huacai Chen <chenhuacai@...ngson.cn>
>
> It's good to see that you completed this. Unfortunately you did not add Ard
> Biesheuvel to Cc, he is the one who needs to review this code. Adding him
> to Cc now, with the full patch quoted below for him (no more comments
> from me there).
I'm sorry I forgot that.

Huacai
>
>       Arnd
>
> > ---
> >  arch/loongarch/Kbuild                         |   3 +
> >  arch/loongarch/Kconfig                        |   8 +
> >  arch/loongarch/Makefile                       |  18 +-
> >  arch/loongarch/boot/Makefile                  |  23 +
> >  arch/loongarch/kernel/efi-header.S            | 100 +++++
> >  arch/loongarch/kernel/head.S                  |  44 +-
> >  arch/loongarch/kernel/image-vars.h            |  30 ++
> >  arch/loongarch/kernel/vmlinux.lds.S           |  23 +-
> >  drivers/firmware/efi/Kconfig                  |   4 +-
> >  drivers/firmware/efi/libstub/Makefile         |  14 +-
> >  drivers/firmware/efi/libstub/loongarch-stub.c | 425 ++++++++++++++++++
> >  include/linux/pe.h                            |   1 +
> >  12 files changed, 680 insertions(+), 13 deletions(-)
> >  create mode 100644 arch/loongarch/boot/Makefile
> >  create mode 100644 arch/loongarch/kernel/efi-header.S
> >  create mode 100644 arch/loongarch/kernel/image-vars.h
> >  create mode 100644 drivers/firmware/efi/libstub/loongarch-stub.c
> >
> > diff --git a/arch/loongarch/Kbuild b/arch/loongarch/Kbuild
> > index 1ad35aabdd16..ab5373d0a24f 100644
> > --- a/arch/loongarch/Kbuild
> > +++ b/arch/loongarch/Kbuild
> > @@ -1,3 +1,6 @@
> >  obj-y += kernel/
> >  obj-y += mm/
> >  obj-y += vdso/
> > +
> > +# for cleaning
> > +subdir- += boot
> > diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
> > index 44b763046893..55225ee5f868 100644
> > --- a/arch/loongarch/Kconfig
> > +++ b/arch/loongarch/Kconfig
> > @@ -265,6 +265,14 @@ config EFI
> >           resultant kernel should continue to boot on existing non-EFI
> >           platforms.
> >
> > +config EFI_STUB
> > +       bool "EFI boot stub support"
> > +       default y
> > +       depends on EFI
> > +       help
> > +         This kernel feature allows the kernel to be loaded directly by
> > +         EFI firmware without the use of a bootloader.
> > +
> >  config FORCE_MAX_ZONEORDER
> >         int "Maximum zone order"
> >         range 14 64 if PAGE_SIZE_64KB
> > diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> > index c4b3f53cd276..d88a792dafbe 100644
> > --- a/arch/loongarch/Makefile
> > +++ b/arch/loongarch/Makefile
> > @@ -3,6 +3,14 @@
> >  # Author: Huacai Chen <chenhuacai@...ngson.cn>
> >  # Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> >
> > +boot   := arch/loongarch/boot
> > +
> > +ifndef CONFIG_EFI_STUB
> > +KBUILD_IMAGE   = $(boot)/vmlinux
> > +else
> > +KBUILD_IMAGE   = $(boot)/vmlinux.efi
> > +endif
> > +
> >  #
> >  # Select the object file format to substitute into the linker script.
> >  #
> > @@ -30,8 +38,6 @@ ld-emul                       = $(64bit-emul)
> >  cflags-y               += -mabi=lp64s
> >  endif
> >
> > -all-y                  := vmlinux
> > -
> >  #
> >  # GCC uses -G0 -mabicalls -fpic as default.  We don't want PIC in the kernel
> >  # code since it only slows down the whole thing.  At some point we might make
> > @@ -75,6 +81,7 @@ endif
> >  head-y := arch/loongarch/kernel/head.o
> >
> >  libs-y += arch/loongarch/lib/
> > +libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
> >
> >  ifeq ($(KBUILD_EXTMOD),)
> >  prepare: vdso_prepare
> > @@ -86,12 +93,13 @@ PHONY += vdso_install
> >  vdso_install:
> >         $(Q)$(MAKE) $(build)=arch/loongarch/vdso $@
> >
> > -all:   $(all-y)
> > +all:   $(KBUILD_IMAGE)
> >
> > -CLEAN_FILES += vmlinux
> > +$(KBUILD_IMAGE): vmlinux
> > +       $(Q)$(MAKE) $(build)=$(boot) $(bootvars-y) $@
> >
> >  install:
> > -       $(Q)install -D -m 755 vmlinux $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE)
> > +       $(Q)install -D -m 755 $(KBUILD_IMAGE) $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE)
> >         $(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
> > new file mode 100644
> > index 000000000000..66f2293c34b2
> > --- /dev/null
> > +++ b/arch/loongarch/boot/Makefile
> > @@ -0,0 +1,23 @@
> > +#
> > +# arch/loongarch/boot/Makefile
> > +#
> > +# Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > +#
> > +
> > +drop-sections := .comment .note .options .note.gnu.build-id
> > +strip-flags   := $(addprefix --remove-section=,$(drop-sections)) -S
> > +
> > +targets := vmlinux
> > +quiet_cmd_strip = STRIP          $@
> > +      cmd_strip = $(STRIP) -s $@
> > +
> > +$(obj)/vmlinux: vmlinux FORCE
> > +       $(call if_changed,copy)
> > +       $(call if_changed,strip)
> > +
> > +targets += vmlinux.efi
> > +quiet_cmd_eficopy = OBJCOPY $@
> > +      cmd_eficopy = $(OBJCOPY) -O binary $(strip-flags) $< $@
> > +
> > +$(obj)/vmlinux.efi: $(obj)/vmlinux FORCE
> > +       $(call if_changed,eficopy)
> > diff --git a/arch/loongarch/kernel/efi-header.S b/arch/loongarch/kernel/efi-header.S
> > new file mode 100644
> > index 000000000000..ceb44524944a
> > --- /dev/null
> > +++ b/arch/loongarch/kernel/efi-header.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   __inittext_end - efi_header_end         /* SizeOfCode */
> > +       .long   _end - __initdata_begin                 /* 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   __inittext_end - efi_header_end         /* VirtualSize */
> > +       .long   efi_header_end - _head                  /* VirtualAddress */
> > +       .long   __inittext_end - 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 - __initdata_begin                 /* VirtualSize */
> > +       .long   __initdata_begin - _head                /* VirtualAddress */
> > +       .long   _edata - __initdata_begin               /* SizeOfRawData */
> > +       .long   __initdata_begin - _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/kernel/head.S b/arch/loongarch/kernel/head.S
> > index b4a0b28da3e7..361b72e8bfc5 100644
> > --- a/arch/loongarch/kernel/head.S
> > +++ b/arch/loongarch/kernel/head.S
> > @@ -11,11 +11,53 @@
> >  #include <asm/regdef.h>
> >  #include <asm/loongarch.h>
> >  #include <asm/stackframe.h>
> > +#include <generated/compile.h>
> > +#include <generated/utsrelease.h>
> >
> > -SYM_ENTRY(_stext, SYM_L_GLOBAL, SYM_A_NONE)
> > +#ifdef CONFIG_EFI_STUB
> > +
> > +#include "efi-header.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 VMLINUX_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
> >
> >         __REF
> >
> > +SYM_ENTRY(_stext, SYM_L_GLOBAL, SYM_A_NONE)
> > +
> >  SYM_CODE_START(kernel_entry)                   # kernel entry point
> >
> >         /* Config direct window and set PG */
> > diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h
> > new file mode 100644
> > index 000000000000..0162402b6212
> > --- /dev/null
> > +++ b/arch/loongarch/kernel/image-vars.h
> > @@ -0,0 +1,30 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > + */
> > +#ifndef __LOONGARCH_KERNEL_IMAGE_VARS_H
> > +#define __LOONGARCH_KERNEL_IMAGE_VARS_H
> > +
> > +#ifdef CONFIG_EFI_STUB
> > +
> > +__efistub_memcmp               = memcmp;
> > +__efistub_memcpy               = memcpy;
> > +__efistub_memmove              = memmove;
> > +__efistub_memset               = memset;
> > +__efistub_strcat               = strcat;
> > +__efistub_strcmp               = strcmp;
> > +__efistub_strlen               = strlen;
> > +__efistub_strncat              = strncat;
> > +__efistub_strnstr              = strnstr;
> > +__efistub_strnlen              = strnlen;
> > +__efistub_strpbrk              = strpbrk;
> > +__efistub_strsep               = strsep;
> > +__efistub_kernel_entry         = kernel_entry;
> > +__efistub_kernel_asize         = kernel_asize;
> > +__efistub_kernel_fsize         = kernel_fsize;
> > +__efistub_kernel_vaddr         = kernel_vaddr;
> > +__efistub_kernel_offset                = kernel_offset;
> > +
> > +#endif
> > +
> > +#endif /* __LOONGARCH_KERNEL_IMAGE_VARS_H */
> > diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
> > index 02abfaaa4892..7da4c4d7c50d 100644
> > --- a/arch/loongarch/kernel/vmlinux.lds.S
> > +++ b/arch/loongarch/kernel/vmlinux.lds.S
> > @@ -12,6 +12,14 @@
> >  #define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir)
> >
> >  #include <asm-generic/vmlinux.lds.h>
> > +#include "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)
> > @@ -27,6 +35,9 @@ SECTIONS
> >         . = VMLINUX_LOAD_ADDRESS;
> >
> >         _text = .;
> > +       HEAD_TEXT_SECTION
> > +
> > +       . = ALIGN(PECOFF_SEGMENT_ALIGN);
> >         .text : {
> >                 TEXT_TEXT
> >                 SCHED_TEXT
> > @@ -38,11 +49,12 @@ SECTIONS
> >                 *(.fixup)
> >                 *(.gnu.warning)
> >         } :text = 0
> > +       . = ALIGN(PECOFF_SEGMENT_ALIGN);
> >         _etext = .;
> >
> >         EXCEPTION_TABLE(16)
> >
> > -       . = ALIGN(PAGE_SIZE);
> > +       . = ALIGN(PECOFF_SEGMENT_ALIGN);
> >         __init_begin = .;
> >         __inittext_begin = .;
> >
> > @@ -51,6 +63,7 @@ SECTIONS
> >                 EXIT_TEXT
> >         }
> >
> > +       . = ALIGN(PECOFF_SEGMENT_ALIGN);
> >         __inittext_end = .;
> >
> >         __initdata_begin = .;
> > @@ -60,6 +73,10 @@ SECTIONS
> >                 EXIT_DATA
> >         }
> >
> > +       .init.bss : {
> > +               *(.init.bss)
> > +       }
> > +       . = ALIGN(PECOFF_SEGMENT_ALIGN);
> >         __initdata_end = .;
> >
> >         __init_end = .;
> > @@ -71,11 +88,11 @@ SECTIONS
> >         .sdata : {
> >                 *(.sdata)
> >         }
> > -
> > -       . = ALIGN(SZ_64K);
> > +       .edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGN); }
> >         _edata =  .;
> >
> >         BSS_SECTION(0, SZ_64K, 8)
> > +       . = ALIGN(PECOFF_SEGMENT_ALIGN);
> >
> >         _end = .;
> >
> > diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
> > index 2c3dac5ecb36..ecb4e0b1295a 100644
> > --- a/drivers/firmware/efi/Kconfig
> > +++ b/drivers/firmware/efi/Kconfig
> > @@ -121,9 +121,9 @@ config EFI_ARMSTUB_DTB_LOADER
> >
> >  config EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER
> >         bool "Enable the command line initrd loader" if !X86
> > -       depends on EFI_STUB && (EFI_GENERIC_STUB || X86)
> > -       default y if X86
> >         depends on !RISCV
> > +       depends on EFI_STUB && (EFI_GENERIC_STUB || X86 || LOONGARCH)
> > +       default y if (X86 || LOONGARCH)
> >         help
> >           Select this config option to add support for the initrd= command
> >           line parameter, allowing an initrd that resides on the same volume
> > diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
> > index d0537573501e..663e9d317299 100644
> > --- a/drivers/firmware/efi/libstub/Makefile
> > +++ b/drivers/firmware/efi/libstub/Makefile
> > @@ -26,6 +26,8 @@ cflags-$(CONFIG_ARM)          := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
> >                                    $(call cc-option,-mno-single-pic-base)
> >  cflags-$(CONFIG_RISCV)         := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
> >                                    -fpic
> > +cflags-$(CONFIG_LOONGARCH)     := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
> > +                                  -fpic
> >
> >  cflags-$(CONFIG_EFI_GENERIC_STUB) += -I$(srctree)/scripts/dtc/libfdt
> >
> > @@ -55,7 +57,7 @@ KCOV_INSTRUMENT                       := n
> >  lib-y                          := efi-stub-helper.o gop.o secureboot.o tpm.o \
> >                                    file.o mem.o random.o randomalloc.o pci.o \
> >                                    skip_spaces.o lib-cmdline.o lib-ctype.o \
> > -                                  alignedmem.o relocate.o vsprintf.o
> > +                                  alignedmem.o relocate.o string.o vsprintf.o
> >
> >  # include the stub's generic dependencies from lib/ when building for ARM/arm64
> >  efi-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
> > @@ -63,13 +65,15 @@ efi-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
> >  $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
> >         $(call if_changed_rule,cc_o_c)
> >
> > -lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o fdt.o string.o \
> > +lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o fdt.o \
> >                                    $(patsubst %.c,lib-%.o,$(efi-deps-y))
> >
> >  lib-$(CONFIG_ARM)              += arm32-stub.o
> >  lib-$(CONFIG_ARM64)            += arm64-stub.o
> >  lib-$(CONFIG_X86)              += x86-stub.o
> >  lib-$(CONFIG_RISCV)            += riscv-stub.o
> > +lib-$(CONFIG_LOONGARCH)                += loongarch-stub.o
> > +
> >  CFLAGS_arm32-stub.o            := -DTEXT_OFFSET=$(TEXT_OFFSET)
> >
> >  # Even when -mbranch-protection=none is set, Clang will generate a
> > @@ -125,6 +129,12 @@ STUBCOPY_FLAGS-$(CONFIG_RISCV)     += --prefix-alloc-sections=.init \
> >                                    --prefix-symbols=__efistub_
> >  STUBCOPY_RELOC-$(CONFIG_RISCV) := R_RISCV_HI20
> >
> > +# For LoongArch, keep all the symbols in .init section and make sure that no
> > +# absolute symbols references doesn't exist.
> > +STUBCOPY_FLAGS-$(CONFIG_LOONGARCH)     += --prefix-alloc-sections=.init \
> > +                                          --prefix-symbols=__efistub_
> > +STUBCOPY_RELOC-$(CONFIG_LOONGARCH)     := R_LARCH_MARK_LA
> > +
> >  $(obj)/%.stub.o: $(obj)/%.o FORCE
> >         $(call if_changed,stubcopy)
> >
> > diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c
> > new file mode 100644
> > index 000000000000..399641a0b0cb
> > --- /dev/null
> > +++ b/drivers/firmware/efi/libstub/loongarch-stub.c
> > @@ -0,0 +1,425 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Author: Yun Liu <liuyun@...ngson.cn>
> > + *         Huacai Chen <chenhuacai@...ngson.cn>
> > + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > + */
> > +
> > +#include <linux/efi.h>
> > +#include <linux/sort.h>
> > +#include <asm/efi.h>
> > +#include <asm/addrspace.h>
> > +#include <asm/boot_param.h>
> > +#include "efistub.h"
> > +
> > +#define MAX_ARG_COUNT          128
> > +#define CMDLINE_MAX_SIZE       0x200
> > +
> > +static int argc;
> > +static char **argv;
> > +const efi_system_table_t *efi_system_table;
> > +static efi_guid_t screen_info_guid = LINUX_EFI_LARCH_SCREEN_INFO_TABLE_GUID;
> > +static unsigned int map_entry[LOONGSON3_BOOT_MEM_MAP_MAX];
> > +static struct efi_mmap mmap_array[EFI_MAX_MEMORY_TYPE][LOONGSON3_BOOT_MEM_MAP_MAX];
> > +
> > +struct exit_boot_struct {
> > +       struct boot_params *bp;
> > +       unsigned int *runtime_entry_count;
> > +};
> > +
> > +typedef void (*kernel_entry_t)(int argc, char *argv[], struct boot_params *boot_p);
> > +
> > +extern int kernel_asize;
> > +extern int kernel_fsize;
> > +extern int kernel_offset;
> > +extern unsigned long kernel_vaddr;
> > +extern kernel_entry_t kernel_entry;
> > +
> > +unsigned char efi_crc8(char *buff, int size)
> > +{
> > +       int sum, cnt;
> > +
> > +       for (sum = 0, cnt = 0; cnt < size; cnt++)
> > +               sum = (char) (sum + *(buff + cnt));
> > +
> > +       return (char)(0x100 - sum);
> > +}
> > +
> > +struct screen_info *alloc_screen_info(void)
> > +{
> > +       efi_status_t status;
> > +       struct screen_info *si;
> > +
> > +       status = efi_bs_call(allocate_pool,
> > +                       EFI_RUNTIME_SERVICES_DATA, sizeof(*si), (void **)&si);
> > +       if (status != EFI_SUCCESS)
> > +               return NULL;
> > +
> > +       status = efi_bs_call(install_configuration_table, &screen_info_guid, si);
> > +       if (status == EFI_SUCCESS)
> > +               return si;
> > +
> > +       efi_bs_call(free_pool, si);
> > +
> > +       return NULL;
> > +}
> > +
> > +static void setup_graphics(void)
> > +{
> > +       unsigned long size;
> > +       efi_status_t status;
> > +       efi_guid_t gop_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
> > +       void **gop_handle = NULL;
> > +       struct screen_info *si = NULL;
> > +
> > +       size = 0;
> > +       status = efi_bs_call(locate_handle, EFI_LOCATE_BY_PROTOCOL,
> > +                               &gop_proto, NULL, &size, gop_handle);
> > +       if (status == EFI_BUFFER_TOO_SMALL) {
> > +               si = alloc_screen_info();
> > +               efi_setup_gop(si, &gop_proto, size);
> > +       }
> > +}
> > +
> > +struct boot_params *bootparams_init(efi_system_table_t *sys_table)
> > +{
> > +       efi_status_t status;
> > +       struct boot_params *p;
> > +       unsigned char sig[8] = {'B', 'P', 'I', '0', '1', '0', '0', '2'};
> > +
> > +       status = efi_bs_call(allocate_pool, EFI_RUNTIME_SERVICES_DATA, SZ_64K, (void **)&p);
> > +       if (status != EFI_SUCCESS)
> > +               return NULL;
> > +
> > +       memset(p, 0, SZ_64K);
> > +       memcpy(&p->signature, sig, sizeof(long));
> > +
> > +       return p;
> > +}
> > +
> > +static unsigned long convert_priv_cmdline(char *cmdline_ptr,
> > +               unsigned long rd_addr, unsigned long rd_size)
> > +{
> > +       unsigned int rdprev_size;
> > +       unsigned int cmdline_size;
> > +       efi_status_t status;
> > +       char *pstr, *substr;
> > +       char *initrd_ptr = NULL;
> > +       char convert_str[CMDLINE_MAX_SIZE];
> > +       static char cmdline_array[CMDLINE_MAX_SIZE];
> > +
> > +       cmdline_size = strlen(cmdline_ptr);
> > +       snprintf(cmdline_array, CMDLINE_MAX_SIZE, "kernel ");
> > +
> > +       initrd_ptr = strstr(cmdline_ptr, "initrd=");
> > +       if (!initrd_ptr) {
> > +               snprintf(cmdline_array, CMDLINE_MAX_SIZE, "kernel %s", cmdline_ptr);
> > +               goto completed;
> > +       }
> > +       snprintf(convert_str, CMDLINE_MAX_SIZE, " initrd=0x%lx,0x%lx", rd_addr, rd_size);
> > +       rdprev_size = cmdline_size - strlen(initrd_ptr);
> > +       strncat(cmdline_array, cmdline_ptr, rdprev_size);
> > +
> > +       cmdline_ptr = strnstr(initrd_ptr, " ", CMDLINE_MAX_SIZE);
> > +       strcat(cmdline_array, convert_str);
> > +       if (!cmdline_ptr)
> > +               goto completed;
> > +
> > +       strcat(cmdline_array, cmdline_ptr);
> > +
> > +completed:
> > +       status = efi_allocate_pages((MAX_ARG_COUNT + 1) * (sizeof(char *)),
> > +                                       (unsigned long *)&argv, ULONG_MAX);
> > +       if (status != EFI_SUCCESS) {
> > +               efi_err("Alloc argv mmap_array error\n");
> > +               return status;
> > +       }
> > +
> > +       argc = 0;
> > +       pstr = cmdline_array;
> > +
> > +       substr = strsep(&pstr, " \t");
> > +       while (substr != NULL) {
> > +               if (strlen(substr)) {
> > +                       argv[argc++] = substr;
> > +                       if (argc == MAX_ARG_COUNT) {
> > +                               efi_err("Argv mmap_array full!\n");
> > +                               break;
> > +                       }
> > +               }
> > +               substr = strsep(&pstr, " \t");
> > +       }
> > +
> > +       return EFI_SUCCESS;
> > +}
> > +
> > +unsigned int efi_memmap_sort(struct loongsonlist_mem_map *memmap,
> > +                       unsigned int index, unsigned int mem_type)
> > +{
> > +       unsigned int i, t;
> > +       unsigned long msize;
> > +
> > +       for (i = 0; i < map_entry[mem_type]; i = t) {
> > +               msize = mmap_array[mem_type][i].mem_size;
> > +               for (t = i + 1; t < map_entry[mem_type]; t++) {
> > +                       if (mmap_array[mem_type][i].mem_start + msize <
> > +                                       mmap_array[mem_type][t].mem_start)
> > +                               break;
> > +
> > +                       msize += mmap_array[mem_type][t].mem_size;
> > +               }
> > +               memmap->map[index].mem_type = mem_type;
> > +               memmap->map[index].mem_start = mmap_array[mem_type][i].mem_start;
> > +               memmap->map[index].mem_size = msize;
> > +               memmap->map[index].attribute = mmap_array[mem_type][i].attribute;
> > +               index++;
> > +       }
> > +
> > +       return index;
> > +}
> > +
> > +static efi_status_t mk_mmap(struct efi_boot_memmap *map, struct boot_params *p)
> > +{
> > +       char checksum;
> > +       unsigned int i;
> > +       unsigned int nr_desc;
> > +       unsigned int mem_type;
> > +       unsigned long count;
> > +       efi_memory_desc_t *mem_desc;
> > +       struct loongsonlist_mem_map *mhp = NULL;
> > +
> > +       memset(map_entry, 0, sizeof(map_entry));
> > +       memset(mmap_array, 0, sizeof(mmap_array));
> > +
> > +       if (!strncmp((char *)p, "BPI", 3)) {
> > +               p->flags |= BPI_FLAGS_UEFI_SUPPORTED;
> > +               p->systemtable = (efi_system_table_t *)efi_system_table;
> > +               p->extlist_offset = sizeof(*p) + sizeof(unsigned long);
> > +               mhp = (struct loongsonlist_mem_map *)((char *)p + p->extlist_offset);
> > +
> > +               memcpy(&mhp->header.signature, "MEM", sizeof(unsigned long));
> > +               mhp->header.length = sizeof(*mhp);
> > +               mhp->desc_version = *map->desc_ver;
> > +               mhp->map_count = 0;
> > +       }
> > +       if (!(*(map->map_size)) || !(*(map->desc_size)) || !mhp) {
> > +               efi_err("get memory info error\n");
> > +               return EFI_INVALID_PARAMETER;
> > +       }
> > +       nr_desc = *(map->map_size) / *(map->desc_size);
> > +
> > +       /*
> > +        * According to UEFI SPEC, mmap_buf is the accurate Memory Map
> > +        * mmap_array now we can fill platform specific memory structure.
> > +        */
> > +       for (i = 0; i < nr_desc; i++) {
> > +               mem_desc = (efi_memory_desc_t *)((void *)(*map->map) + (i * (*(map->desc_size))));
> > +               switch (mem_desc->type) {
> > +               case EFI_RESERVED_TYPE:
> > +               case EFI_RUNTIME_SERVICES_CODE:
> > +               case EFI_RUNTIME_SERVICES_DATA:
> > +               case EFI_MEMORY_MAPPED_IO:
> > +               case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
> > +               case EFI_UNUSABLE_MEMORY:
> > +               case EFI_PAL_CODE:
> > +                       mem_type = ADDRESS_TYPE_RESERVED;
> > +                       break;
> > +
> > +               case EFI_ACPI_MEMORY_NVS:
> > +                       mem_type = ADDRESS_TYPE_NVS;
> > +                       break;
> > +
> > +               case EFI_ACPI_RECLAIM_MEMORY:
> > +                       mem_type = ADDRESS_TYPE_ACPI;
> > +                       break;
> > +
> > +               case EFI_LOADER_CODE:
> > +               case EFI_LOADER_DATA:
> > +               case EFI_PERSISTENT_MEMORY:
> > +               case EFI_BOOT_SERVICES_CODE:
> > +               case EFI_BOOT_SERVICES_DATA:
> > +               case EFI_CONVENTIONAL_MEMORY:
> > +                       mem_type = ADDRESS_TYPE_SYSRAM;
> > +                       break;
> > +
> > +               default:
> > +                       continue;
> > +               }
> > +
> > +               mmap_array[mem_type][map_entry[mem_type]].mem_type = mem_type;
> > +               mmap_array[mem_type][map_entry[mem_type]].mem_start =
> > +                                               mem_desc->phys_addr & TO_PHYS_MASK;
> > +               mmap_array[mem_type][map_entry[mem_type]].mem_size =
> > +                                               mem_desc->num_pages << EFI_PAGE_SHIFT;
> > +               mmap_array[mem_type][map_entry[mem_type]].attribute =
> > +                                               mem_desc->attribute;
> > +               map_entry[mem_type]++;
> > +       }
> > +
> > +       count = mhp->map_count;
> > +       /* Sort EFI memmap and add to BPI for kernel */
> > +       for (i = 0; i < LOONGSON3_BOOT_MEM_MAP_MAX; i++) {
> > +               if (!map_entry[i])
> > +                       continue;
> > +               count = efi_memmap_sort(mhp, count, i);
> > +       }
> > +
> > +       mhp->map_count = count;
> > +       mhp->header.checksum = 0;
> > +
> > +       checksum = efi_crc8((char *)mhp, mhp->header.length);
> > +       mhp->header.checksum = checksum;
> > +
> > +       return EFI_SUCCESS;
> > +}
> > +
> > +static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)
> > +{
> > +       efi_status_t status;
> > +       struct exit_boot_struct *p = priv;
> > +
> > +       status = mk_mmap(map, p->bp);
> > +       if (status != EFI_SUCCESS) {
> > +               efi_err("Make kernel memory map failed!\n");
> > +               return status;
> > +       }
> > +
> > +       return EFI_SUCCESS;
> > +}
> > +
> > +static efi_status_t exit_boot_services(struct boot_params *boot_params, void *handle)
> > +{
> > +       unsigned int desc_version;
> > +       unsigned int runtime_entry_count = 0;
> > +       unsigned long map_size, key, desc_size, buff_size;
> > +       efi_status_t status;
> > +       efi_memory_desc_t *mem_map;
> > +       struct efi_boot_memmap map;
> > +       struct exit_boot_struct priv;
> > +
> > +       map.map                 = &mem_map;
> > +       map.map_size            = &map_size;
> > +       map.desc_size           = &desc_size;
> > +       map.desc_ver            = &desc_version;
> > +       map.key_ptr             = &key;
> > +       map.buff_size           = &buff_size;
> > +       status = efi_get_memory_map(&map);
> > +       if (status != EFI_SUCCESS) {
> > +               efi_err("Unable to retrieve UEFI memory map.\n");
> > +               return status;
> > +       }
> > +
> > +       priv.bp = boot_params;
> > +       priv.runtime_entry_count = &runtime_entry_count;
> > +
> > +       /* Might as well exit boot services now */
> > +       status = efi_exit_boot_services(handle, &map, &priv, exit_boot_func);
> > +       if (status != EFI_SUCCESS)
> > +               return status;
> > +
> > +       return EFI_SUCCESS;
> > +}
> > +
> > +/*
> > + * EFI entry point for the LoongArch EFI stub.
> > + */
> > +efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, efi_system_table_t *sys_table)
> > +{
> > +       unsigned int cmdline_size = 0;
> > +       unsigned long kernel_addr = 0;
> > +       unsigned long initrd_addr = 0;
> > +       unsigned long initrd_size = 0;
> > +       enum efi_secureboot_mode secure_boot;
> > +       char *cmdline_ptr = NULL;
> > +       struct boot_params *boot_p;
> > +       efi_status_t status;
> > +       efi_loaded_image_t *image;
> > +       efi_guid_t loaded_image_proto;
> > +       kernel_entry_t real_kernel_entry;
> > +
> > +       /* Config Direct Mapping */
> > +       csr_writeq(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
> > +       csr_writeq(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
> > +
> > +       efi_system_table = sys_table;
> > +       loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
> > +       kernel_addr = (unsigned long)&kernel_offset - kernel_offset;
> > +       real_kernel_entry = (kernel_entry_t)
> > +               ((unsigned long)&kernel_entry - kernel_addr + kernel_vaddr);
> > +
> > +       /* Check if we were booted by the EFI firmware */
> > +       if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
> > +               goto fail;
> > +
> > +       /*
> > +        * Get a handle to the loaded image protocol.  This is used to get
> > +        * information about the running image, such as size and the command
> > +        * line.
> > +        */
> > +       status = sys_table->boottime->handle_protocol(handle,
> > +                                       &loaded_image_proto, (void *)&image);
> > +       if (status != EFI_SUCCESS) {
> > +               efi_err("Failed to get loaded image protocol\n");
> > +               goto fail;
> > +       }
> > +
> > +       /* Get the command line from EFI, using the LOADED_IMAGE protocol. */
> > +       cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
> > +       if (!cmdline_ptr) {
> > +               efi_err("Getting command line failed!\n");
> > +               goto fail_free_cmdline;
> > +       }
> > +
> > +#ifdef CONFIG_CMDLINE_BOOL
> > +       if (cmdline_size == 0)
> > +               efi_parse_options(CONFIG_CMDLINE);
> > +#endif
> > +       if (!IS_ENABLED(CONFIG_CMDLINE_OVERRIDE) && cmdline_size > 0)
> > +               efi_parse_options(cmdline_ptr);
> > +
> > +       efi_info("Booting Linux Kernel...\n");
> > +
> > +       efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize,
> > +                           PHYSADDR(kernel_vaddr), SZ_2M, PHYSADDR(kernel_vaddr));
> > +
> > +       setup_graphics();
> > +       secure_boot = efi_get_secureboot();
> > +       efi_enable_reset_attack_mitigation();
> > +
> > +       status = efi_load_initrd(image, &initrd_addr, &initrd_size, SZ_4G, ULONG_MAX);
> > +       if (status != EFI_SUCCESS) {
> > +               efi_err("Failed get initrd addr!\n");
> > +               goto fail_free;
> > +       }
> > +
> > +       status = convert_priv_cmdline(cmdline_ptr, initrd_addr, initrd_size);
> > +       if (status != EFI_SUCCESS) {
> > +               efi_err("Covert cmdline failed!\n");
> > +               goto fail_free;
> > +       }
> > +
> > +       boot_p = bootparams_init(sys_table);
> > +       if (!boot_p) {
> > +               efi_err("Create BPI struct error!\n");
> > +               goto fail;
> > +       }
> > +
> > +       status = exit_boot_services(boot_p, handle);
> > +       if (status != EFI_SUCCESS) {
> > +               efi_err("exit_boot services failed!\n");
> > +               goto fail_free;
> > +       }
> > +
> > +       real_kernel_entry(argc, argv, boot_p);
> > +
> > +       return EFI_SUCCESS;
> > +
> > +fail_free:
> > +       efi_free(initrd_size, initrd_addr);
> > +
> > +fail_free_cmdline:
> > +       efi_free(cmdline_size, (unsigned long)cmdline_ptr);
> > +
> > +fail:
> > +       return status;
> > +}
> > diff --git a/include/linux/pe.h b/include/linux/pe.h
> > index daf09ffffe38..f4bb0b6a416d 100644
> > --- a/include/linux/pe.h
> > +++ b/include/linux/pe.h
> > @@ -65,6 +65,7 @@
> >  #define        IMAGE_FILE_MACHINE_SH5          0x01a8
> >  #define        IMAGE_FILE_MACHINE_THUMB        0x01c2
> >  #define        IMAGE_FILE_MACHINE_WCEMIPSV2    0x0169
> > +#define        IMAGE_FILE_MACHINE_LOONGARCH    0x6264
> >
> >  /* flags */
> >  #define IMAGE_FILE_RELOCS_STRIPPED           0x0001
> > --
> > 2.27.0
> >

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ