This patch adds efistub booting support, which is the standard UEFI boot
protocol for us to use.
We use generic efistub, which means we can pass boot information (i.e.,
system table, memory map, kernel command line, initrd) via a light FDT
and drop a lot of non-standard code.
We use a flat mapping to map the efi runtime in the kernel's address
space. In efi, VA = PA; in kernel, VA = PA + PAGE_OFFSET. As a result,
flat mapping is not identity mapping, SetVirtualAddressMap() is still
needed for the efi runtime.
Tested-by: Xi Ruoyao <[email protected]>
Signed-off-by: Huacai Chen <[email protected]>
---
V1 --> V2:
1, Call SetVirtualAddressMap() in stub;
2, Use core kernel data directly in alloc_screen_info();
3, Remove the magic number in MS-DOS header;
4, Disable EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER;
5, Some other small changes suggested by Ard Biesheuvel.
arch/loongarch/Kconfig | 9 ++
arch/loongarch/Makefile | 7 +-
arch/loongarch/boot/Makefile | 8 +-
arch/loongarch/include/asm/efi.h | 10 +-
arch/loongarch/kernel/efi-header.S | 99 +++++++++++++++++++
arch/loongarch/kernel/efi.c | 3 +
arch/loongarch/kernel/head.S | 20 ++++
arch/loongarch/kernel/image-vars.h | 30 ++++++
arch/loongarch/kernel/setup.c | 12 +--
arch/loongarch/kernel/vmlinux.lds.S | 1 +
drivers/firmware/efi/Kconfig | 4 +-
drivers/firmware/efi/libstub/Makefile | 10 ++
drivers/firmware/efi/libstub/efi-stub.c | 31 ++++--
drivers/firmware/efi/libstub/loongarch-stub.c | 60 +++++++++++
include/linux/pe.h | 2 +
15 files changed, 282 insertions(+), 24 deletions(-)
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/Kconfig b/arch/loongarch/Kconfig
index 9478f9646fa5..4cb412a82afa 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -324,6 +324,15 @@ config EFI
This enables the kernel to use EFI runtime services that are
available (such as the EFI variable services).
+config EFI_STUB
+ bool "EFI boot stub support"
+ default y
+ depends on EFI
+ select EFI_GENERIC_STUB
+ help
+ This kernel feature allows the kernel to be loaded directly by
+ EFI firmware without the use of a bootloader.
+
config SMP
bool "Multi-Processing support"
help
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
index ec3de6191276..2bd0a574ed73 100644
--- a/arch/loongarch/Makefile
+++ b/arch/loongarch/Makefile
@@ -7,7 +7,11 @@ boot := arch/loongarch/boot
KBUILD_DEFCONFIG := loongson3_defconfig
-KBUILD_IMAGE = $(boot)/vmlinux
+ifndef CONFIG_EFI_STUB
+KBUILD_IMAGE = $(boot)/vmlinux.elf
+else
+KBUILD_IMAGE = $(boot)/vmlinux.efi
+endif
#
# Select the object file format to substitute into the linker script.
@@ -75,6 +79,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
diff --git a/arch/loongarch/boot/Makefile b/arch/loongarch/boot/Makefile
index 0125b17edc98..fecf34f50e56 100644
--- a/arch/loongarch/boot/Makefile
+++ b/arch/loongarch/boot/Makefile
@@ -8,9 +8,13 @@ drop-sections := .comment .note .options .note.gnu.build-id
strip-flags := $(addprefix --remove-section=,$(drop-sections)) -S
OBJCOPYFLAGS_vmlinux.efi := -O binary $(strip-flags)
-targets := vmlinux
quiet_cmd_strip = STRIP $@
cmd_strip = $(STRIP) -s -o $@ $<
-$(obj)/vmlinux: vmlinux FORCE
+targets := vmlinux.elf
+$(obj)/vmlinux.elf: vmlinux FORCE
$(call if_changed,strip)
+
+targets += vmlinux.efi
+$(obj)/vmlinux.efi: vmlinux FORCE
+ $(call if_changed,objcopy)
diff --git a/arch/loongarch/include/asm/efi.h b/arch/loongarch/include/asm/efi.h
index 9d44c6948be1..c7507a240f30 100644
--- a/arch/loongarch/include/asm/efi.h
+++ b/arch/loongarch/include/asm/efi.h
@@ -18,8 +18,14 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
#define EFI_ALLOC_ALIGN SZ_64K
-struct screen_info *alloc_screen_info(void);
-void free_screen_info(struct screen_info *si);
+static inline struct screen_info *alloc_screen_info(void)
+{
+ return &screen_info;
+}
+
+static inline void free_screen_info(struct screen_info *si)
+{
+}
static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
{
diff --git a/arch/loongarch/kernel/efi-header.S b/arch/loongarch/kernel/efi-header.S
new file mode 100644
index 000000000000..8c1d229a2afa
--- /dev/null
+++ b/arch/loongarch/kernel/efi-header.S
@@ -0,0 +1,99 @@
+/* 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
+.Lcoff_header:
+ .short IMAGE_FILE_MACHINE_LOONGARCH64 /* Machine */
+ .short .Lsection_count /* NumberOfSections */
+ .long 0 /* TimeDateStamp */
+ .long 0 /* PointerToSymbolTable */
+ .long 0 /* NumberOfSymbols */
+ .short .Lsection_table - .Loptional_header /* SizeOfOptionalHeader */
+ .short IMAGE_FILE_DEBUG_STRIPPED | \
+ IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_LINE_NUMS_STRIPPED /* Characteristics */
+
+.Loptional_header:
+ .short PE_OPT_MAGIC_PE32PLUS /* PE32+ format */
+ .byte 0x02 /* MajorLinkerVersion */
+ .byte 0x14 /* MinorLinkerVersion */
+ .long __inittext_end - .Lefi_header_end /* SizeOfCode */
+ .long _end - __initdata_begin /* SizeOfInitializedData */
+ .long 0 /* SizeOfUninitializedData */
+ .long __efistub_efi_pe_entry - _head /* AddressOfEntryPoint */
+ .long .Lefi_header_end - _head /* BaseOfCode */
+
+.Lextra_header_fields:
+ .quad 0 /* ImageBase */
+ .long PECOFF_SEGMENT_ALIGN /* SectionAlignment */
+ .long PECOFF_FILE_ALIGN /* FileAlignment */
+ .short 0 /* MajorOperatingSystemVersion */
+ .short 0 /* MinorOperatingSystemVersion */
+ .short LINUX_EFISTUB_MAJOR_VERSION /* MajorImageVersion */
+ .short LINUX_EFISTUB_MINOR_VERSION /* 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 .Lefi_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 (.Lsection_table - .) / 8 /* NumberOfRvaAndSizes */
+
+ .quad 0 /* ExportTable */
+ .quad 0 /* ImportTable */
+ .quad 0 /* ResourceTable */
+ .quad 0 /* ExceptionTable */
+ .quad 0 /* CertificationTable */
+ .quad 0 /* BaseRelocationTable */
+
+ /* Section table */
+.Lsection_table:
+ .ascii ".text\0\0\0"
+ .long __inittext_end - .Lefi_header_end /* VirtualSize */
+ .long .Lefi_header_end - _head /* VirtualAddress */
+ .long __inittext_end - .Lefi_header_end /* SizeOfRawData */
+ .long .Lefi_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 */
+
+ .set .Lsection_count, (. - .Lsection_table) / 40
+
+ .balign 0x10000 /* PECOFF_SEGMENT_ALIGN */
+.Lefi_header_end:
+ .endm
diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
index a50b60c587fa..1f1f755fb425 100644
--- a/arch/loongarch/kernel/efi.c
+++ b/arch/loongarch/kernel/efi.c
@@ -69,4 +69,7 @@ void __init efi_init(void)
config_tables = early_memremap(efi_config_table, efi_nr_tables * size);
efi_config_parse_tables(config_tables, efi_systab->nr_tables, arch_tables);
early_memunmap(config_tables, efi_nr_tables * size);
+
+ if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI)
+ memblock_reserve(screen_info.lfb_base, screen_info.lfb_size);
}
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index c60eb66793e3..01bac62a6442 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -12,6 +12,26 @@
#include <asm/loongarch.h>
#include <asm/stackframe.h>
+#ifdef CONFIG_EFI_STUB
+
+#include "efi-header.S"
+
+ __HEAD
+
+_head:
+ .word MZ_MAGIC /* "MZ", MS-DOS header */
+ .org 0x3c /* 0x04 ~ 0x3b reserved */
+ .long pe_header - _head /* Offset to the PE header */
+
+pe_header:
+ __EFI_PE_HEADER
+
+SYM_DATA(kernel_asize, .long _end - _text);
+SYM_DATA(kernel_fsize, .long _edata - _text);
+SYM_DATA(kernel_offset, .long kernel_offset - _text);
+
+#endif
+
__REF
SYM_CODE_START(kernel_entry) # kernel entry point
diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h
new file mode 100644
index 000000000000..c901ebb903f2
--- /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_memchr = memchr;
+__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_strrchr = strrchr;
+__efistub_kernel_entry = kernel_entry;
+__efistub_kernel_asize = kernel_asize;
+__efistub_kernel_fsize = kernel_fsize;
+__efistub_kernel_offset = kernel_offset;
+__efistub_screen_info = screen_info;
+
+#endif
+
+#endif /* __LOONGARCH_KERNEL_IMAGE_VARS_H */
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index 23ee293e1cd2..f938aae3e92c 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -49,9 +49,7 @@
#define SMBIOS_CORE_PACKAGE_OFFSET 0x23
#define LOONGSON_EFI_ENABLE (1 << 3)
-#ifdef CONFIG_VT
-struct screen_info screen_info;
-#endif
+struct screen_info screen_info __section(".data");
unsigned long fw_arg0, fw_arg1;
DEFINE_PER_CPU(unsigned long, kernelsp);
@@ -122,16 +120,9 @@ static void __init parse_cpu_table(const struct dmi_header *dm)
static void __init parse_bios_table(const struct dmi_header *dm)
{
- int bios_extern;
char *dmi_data = (char *)dm;
- bios_extern = *(dmi_data + SMBIOS_BIOSEXTERN_OFFSET);
b_info.bios_size = (*(dmi_data + SMBIOS_BIOSSIZE_OFFSET) + 1) << 6;
-
- if (bios_extern & LOONGSON_EFI_ENABLE)
- set_bit(EFI_BOOT, &efi.flags);
- else
- clear_bit(EFI_BOOT, &efi.flags);
}
static void __init find_tokens(const struct dmi_header *dm, void *dummy)
@@ -145,6 +136,7 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
break;
}
}
+
static void __init smbios_parse(void)
{
b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR);
diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
index 69c76f26c1c5..36d042739f3c 100644
--- a/arch/loongarch/kernel/vmlinux.lds.S
+++ b/arch/loongarch/kernel/vmlinux.lds.S
@@ -12,6 +12,7 @@
#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
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 6cb7384ad2ac..cbf1c55dc224 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -107,7 +107,7 @@ config EFI_GENERIC_STUB
config EFI_ARMSTUB_DTB_LOADER
bool "Enable the DTB loader"
- depends on EFI_GENERIC_STUB && !RISCV
+ depends on EFI_GENERIC_STUB && !RISCV && !LOONGARCH
default y
help
Select this config option to add support for the dtb= command
@@ -124,7 +124,7 @@ 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 !RISCV && !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..1588c61939e7 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
@@ -70,6 +72,8 @@ 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/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index f515394cce6e..efb9219d8d49 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -40,14 +40,19 @@
#ifdef CONFIG_ARM64
# define EFI_RT_VIRTUAL_LIMIT DEFAULT_MAP_WINDOW_64
-#elif defined(CONFIG_RISCV)
+#elif defined(CONFIG_RISCV) || defined(CONFIG_LOONGARCH)
# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE_MIN
-#else
+#else /* Only if TASK_SIZE is a constant */
# define EFI_RT_VIRTUAL_LIMIT TASK_SIZE
#endif
+/*
+ * 0: No flat mapping
+ * 1: Flat mapping that VA = PA
+ * 2: Flat mapping that VA = PA + PAGE_OFFSET
+ */
+static int flat_va_mapping;
static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
-static bool flat_va_mapping;
const efi_system_table_t *efi_system_table;
@@ -121,6 +126,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
{
efi_loaded_image_t *image;
efi_status_t status;
+ unsigned long attrib;
unsigned long image_addr;
unsigned long image_size = 0;
/* addr/point and size pairs for memory management*/
@@ -254,9 +260,11 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
* The easiest way to achieve that is to simply use a 1:1 mapping.
*/
prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID);
- flat_va_mapping = prop_tbl &&
- (prop_tbl->memory_protection_attribute &
- EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
+ attrib = prop_tbl ? prop_tbl->memory_protection_attribute : 0;
+ if (attrib & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
+ flat_va_mapping = 1;
+ if (IS_ENABLED(CONFIG_LOONGARCH))
+ flat_va_mapping = 2;
/* force efi_novamap if SetVirtualAddressMap() is unsupported */
efi_novamap |= !(get_supported_rt_services() &
@@ -338,7 +346,16 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
paddr = in->phys_addr;
size = in->num_pages * EFI_PAGE_SIZE;
- in->virt_addr = in->phys_addr;
+ switch (flat_va_mapping) {
+ case 1:
+ in->virt_addr = in->phys_addr;
+ break;
+ case 2:
+ in->virt_addr = in->phys_addr + PAGE_OFFSET;
+ break;
+ default:
+ in->virt_addr = in->phys_addr;
+ }
if (efi_novamap) {
continue;
}
diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c
new file mode 100644
index 000000000000..b7ef8d2df59e
--- /dev/null
+++ b/drivers/firmware/efi/libstub/loongarch-stub.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Yun Liu <[email protected]>
+ * Huacai Chen <[email protected]>
+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
+ */
+
+#include <asm/efi.h>
+#include <asm/addrspace.h>
+#include "efistub.h"
+
+typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long fdt);
+
+extern int kernel_asize;
+extern int kernel_fsize;
+extern int kernel_offset;
+extern kernel_entry_t kernel_entry;
+
+efi_status_t check_platform_features(void)
+{
+ return EFI_SUCCESS;
+}
+
+efi_status_t handle_kernel_image(unsigned long *image_addr,
+ unsigned long *image_size,
+ unsigned long *reserve_addr,
+ unsigned long *reserve_size,
+ efi_loaded_image_t *image,
+ efi_handle_t image_handle)
+{
+ efi_status_t status;
+ unsigned long kernel_addr = 0;
+
+ kernel_addr = (unsigned long)&kernel_offset - kernel_offset;
+
+ status = efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize,
+ PHYSADDR(VMLINUX_LOAD_ADDRESS), SZ_2M, 0x0);
+
+ *image_addr = kernel_addr;
+ *image_size = kernel_asize;
+
+ return status;
+}
+
+void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt, unsigned long fdt_size)
+{
+ kernel_entry_t real_kernel_entry;
+
+ /* Config Direct Mapping */
+ csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
+ csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
+
+ real_kernel_entry = (kernel_entry_t)
+ ((unsigned long)&kernel_entry - entrypoint + VMLINUX_LOAD_ADDRESS);
+
+ if (!efi_novamap)
+ real_kernel_entry(true, fdt);
+ else
+ real_kernel_entry(false, fdt);
+}
diff --git a/include/linux/pe.h b/include/linux/pe.h
index daf09ffffe38..1d3836ef9d92 100644
--- a/include/linux/pe.h
+++ b/include/linux/pe.h
@@ -65,6 +65,8 @@
#define IMAGE_FILE_MACHINE_SH5 0x01a8
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169
+#define IMAGE_FILE_MACHINE_LOONGARCH32 0x6232
+#define IMAGE_FILE_MACHINE_LOONGARCH64 0x6264
/* flags */
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
--
2.31.1
Huacai,
This patch is much better than before.
It works well on qemu virt machine platform, and I reply inline.
在 2022/8/18 11:07, Huacai Chen 写道:
> This patch adds efistub booting support, which is the standard UEFI boot
> protocol for us to use.
>
> We use generic efistub, which means we can pass boot information (i.e.,
> system table, memory map, kernel command line, initrd) via a light FDT
> and drop a lot of non-standard code.
>
> We use a flat mapping to map the efi runtime in the kernel's address
> space. In efi, VA = PA; in kernel, VA = PA + PAGE_OFFSET. As a result,
> flat mapping is not identity mapping, SetVirtualAddressMap() is still
> needed for the efi runtime.
>
> Tested-by: Xi Ruoyao <[email protected]>
> Signed-off-by: Huacai Chen <[email protected]>
> ---
> V1 --> V2:
> 1, Call SetVirtualAddressMap() in stub;
> 2, Use core kernel data directly in alloc_screen_info();
> 3, Remove the magic number in MS-DOS header;
> 4, Disable EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER;
> 5, Some other small changes suggested by Ard Biesheuvel.
>
> arch/loongarch/Kconfig | 9 ++
> arch/loongarch/Makefile | 7 +-
> arch/loongarch/boot/Makefile | 8 +-
> arch/loongarch/include/asm/efi.h | 10 +-
> arch/loongarch/kernel/efi-header.S | 99 +++++++++++++++++++
> arch/loongarch/kernel/efi.c | 3 +
> arch/loongarch/kernel/head.S | 20 ++++
> arch/loongarch/kernel/image-vars.h | 30 ++++++
> arch/loongarch/kernel/setup.c | 12 +--
> arch/loongarch/kernel/vmlinux.lds.S | 1 +
> drivers/firmware/efi/Kconfig | 4 +-
> drivers/firmware/efi/libstub/Makefile | 10 ++
> drivers/firmware/efi/libstub/efi-stub.c | 31 ++++--
> drivers/firmware/efi/libstub/loongarch-stub.c | 60 +++++++++++
> include/linux/pe.h | 2 +
> 15 files changed, 282 insertions(+), 24 deletions(-)
> 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/Kconfig b/arch/loongarch/Kconfig
> index 9478f9646fa5..4cb412a82afa 100644
> --- a/arch/loongarch/Kconfig
> +++ b/arch/loongarch/Kconfig
> @@ -324,6 +324,15 @@ config EFI
> This enables the kernel to use EFI runtime services that are
> available (such as the EFI variable services).
>
> +config EFI_STUB
> + bool "EFI boot stub support"
> + default y
> + depends on EFI
> + select EFI_GENERIC_STUB
> + help
> + This kernel feature allows the kernel to be loaded directly by
> + EFI firmware without the use of a bootloader.
> +
> config SMP
> bool "Multi-Processing support"
> help
> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> index ec3de6191276..2bd0a574ed73 100644
> --- a/arch/loongarch/Makefile
> +++ b/arch/loongarch/Makefile
> @@ -7,7 +7,11 @@ boot := arch/loongarch/boot
>
> KBUILD_DEFCONFIG := loongson3_defconfig
>
> -KBUILD_IMAGE = $(boot)/vmlinux
> +ifndef CONFIG_EFI_STUB
> +KBUILD_IMAGE = $(boot)/vmlinux.elf
> +else
> +KBUILD_IMAGE = $(boot)/vmlinux.efi
> +endif
>
> #
> # Select the object file format to substitute into the linker script.
> @@ -75,6 +79,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
> diff --git a/arch/loongarch/boot/Makefile b/arch/loongarch/boot/Makefile
> index 0125b17edc98..fecf34f50e56 100644
> --- a/arch/loongarch/boot/Makefile
> +++ b/arch/loongarch/boot/Makefile
> @@ -8,9 +8,13 @@ drop-sections := .comment .note .options .note.gnu.build-id
> strip-flags := $(addprefix --remove-section=,$(drop-sections)) -S
> OBJCOPYFLAGS_vmlinux.efi := -O binary $(strip-flags)
>
> -targets := vmlinux
> quiet_cmd_strip = STRIP $@
> cmd_strip = $(STRIP) -s -o $@ $<
>
> -$(obj)/vmlinux: vmlinux FORCE
> +targets := vmlinux.elf
> +$(obj)/vmlinux.elf: vmlinux FORCE
> $(call if_changed,strip)
> +
> +targets += vmlinux.efi
> +$(obj)/vmlinux.efi: vmlinux FORCE
> + $(call if_changed,objcopy)
> diff --git a/arch/loongarch/include/asm/efi.h b/arch/loongarch/include/asm/efi.h
> index 9d44c6948be1..c7507a240f30 100644
> --- a/arch/loongarch/include/asm/efi.h
> +++ b/arch/loongarch/include/asm/efi.h
> @@ -18,8 +18,14 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
>
> #define EFI_ALLOC_ALIGN SZ_64K
>
> -struct screen_info *alloc_screen_info(void);
> -void free_screen_info(struct screen_info *si);
> +static inline struct screen_info *alloc_screen_info(void)
> +{
> + return &screen_info;
> +}
> +
> +static inline void free_screen_info(struct screen_info *si)
> +{
> +}
>
> static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
> {
> diff --git a/arch/loongarch/kernel/efi-header.S b/arch/loongarch/kernel/efi-header.S
> new file mode 100644
> index 000000000000..8c1d229a2afa
> --- /dev/null
> +++ b/arch/loongarch/kernel/efi-header.S
> @@ -0,0 +1,99 @@
> +/* 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
> +.Lcoff_header:
> + .short IMAGE_FILE_MACHINE_LOONGARCH64 /* Machine */
> + .short .Lsection_count /* NumberOfSections */
> + .long 0 /* TimeDateStamp */
> + .long 0 /* PointerToSymbolTable */
> + .long 0 /* NumberOfSymbols */
> + .short .Lsection_table - .Loptional_header /* SizeOfOptionalHeader */
> + .short IMAGE_FILE_DEBUG_STRIPPED | \
> + IMAGE_FILE_EXECUTABLE_IMAGE | \
> + IMAGE_FILE_LINE_NUMS_STRIPPED /* Characteristics */
> +
> +.Loptional_header:
> + .short PE_OPT_MAGIC_PE32PLUS /* PE32+ format */
> + .byte 0x02 /* MajorLinkerVersion */
> + .byte 0x14 /* MinorLinkerVersion */
> + .long __inittext_end - .Lefi_header_end /* SizeOfCode */
> + .long _end - __initdata_begin /* SizeOfInitializedData */
> + .long 0 /* SizeOfUninitializedData */
> + .long __efistub_efi_pe_entry - _head /* AddressOfEntryPoint */
> + .long .Lefi_header_end - _head /* BaseOfCode */
> +
> +.Lextra_header_fields:
> + .quad 0 /* ImageBase */
> + .long PECOFF_SEGMENT_ALIGN /* SectionAlignment */
> + .long PECOFF_FILE_ALIGN /* FileAlignment */
> + .short 0 /* MajorOperatingSystemVersion */
> + .short 0 /* MinorOperatingSystemVersion */
> + .short LINUX_EFISTUB_MAJOR_VERSION /* MajorImageVersion */
> + .short LINUX_EFISTUB_MINOR_VERSION /* 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 .Lefi_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 (.Lsection_table - .) / 8 /* NumberOfRvaAndSizes */
> +
> + .quad 0 /* ExportTable */
> + .quad 0 /* ImportTable */
> + .quad 0 /* ResourceTable */
> + .quad 0 /* ExceptionTable */
> + .quad 0 /* CertificationTable */
> + .quad 0 /* BaseRelocationTable */
> +
> + /* Section table */
> +.Lsection_table:
> + .ascii ".text\0\0\0"
> + .long __inittext_end - .Lefi_header_end /* VirtualSize */
> + .long .Lefi_header_end - _head /* VirtualAddress */
> + .long __inittext_end - .Lefi_header_end /* SizeOfRawData */
> + .long .Lefi_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 */
> +
> + .set .Lsection_count, (. - .Lsection_table) / 40
> +
> + .balign 0x10000 /* PECOFF_SEGMENT_ALIGN */
> +.Lefi_header_end:
> + .endm
> diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
> index a50b60c587fa..1f1f755fb425 100644
> --- a/arch/loongarch/kernel/efi.c
> +++ b/arch/loongarch/kernel/efi.c
> @@ -69,4 +69,7 @@ void __init efi_init(void)
> config_tables = early_memremap(efi_config_table, efi_nr_tables * size);
> efi_config_parse_tables(config_tables, efi_systab->nr_tables, arch_tables);
> early_memunmap(config_tables, efi_nr_tables * size);
> +
> + if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI)
> + memblock_reserve(screen_info.lfb_base, screen_info.lfb_size);
> }
> diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
> index c60eb66793e3..01bac62a6442 100644
> --- a/arch/loongarch/kernel/head.S
> +++ b/arch/loongarch/kernel/head.S
> @@ -12,6 +12,26 @@
> #include <asm/loongarch.h>
> #include <asm/stackframe.h>
>
> +#ifdef CONFIG_EFI_STUB
> +
> +#include "efi-header.S"
> +
> + __HEAD
> +
> +_head:
> + .word MZ_MAGIC /* "MZ", MS-DOS header */
> + .org 0x3c /* 0x04 ~ 0x3b reserved */
> + .long pe_header - _head /* Offset to the PE header */
> +
> +pe_header:
> + __EFI_PE_HEADER
> +
> +SYM_DATA(kernel_asize, .long _end - _text);
> +SYM_DATA(kernel_fsize, .long _edata - _text);
> +SYM_DATA(kernel_offset, .long kernel_offset - _text);
> +
> +#endif
> +
> __REF
>
> SYM_CODE_START(kernel_entry) # kernel entry point
> diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h
> new file mode 100644
> index 000000000000..c901ebb903f2
> --- /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_memchr = memchr;
> +__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_strrchr = strrchr;
> +__efistub_kernel_entry = kernel_entry;
> +__efistub_kernel_asize = kernel_asize;
> +__efistub_kernel_fsize = kernel_fsize;
> +__efistub_kernel_offset = kernel_offset;
> +__efistub_screen_info = screen_info;
> +
> +#endif
> +
> +#endif /* __LOONGARCH_KERNEL_IMAGE_VARS_H */
> diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
> index 23ee293e1cd2..f938aae3e92c 100644
> --- a/arch/loongarch/kernel/setup.c
> +++ b/arch/loongarch/kernel/setup.c
> @@ -49,9 +49,7 @@
> #define SMBIOS_CORE_PACKAGE_OFFSET 0x23
> #define LOONGSON_EFI_ENABLE (1 << 3)
>
> -#ifdef CONFIG_VT
> -struct screen_info screen_info;
> -#endif
> +struct screen_info screen_info __section(".data");
>
> unsigned long fw_arg0, fw_arg1;
> DEFINE_PER_CPU(unsigned long, kernelsp);
> @@ -122,16 +120,9 @@ static void __init parse_cpu_table(const struct dmi_header *dm)
>
> static void __init parse_bios_table(const struct dmi_header *dm)
> {
> - int bios_extern;
> char *dmi_data = (char *)dm;
>
> - bios_extern = *(dmi_data + SMBIOS_BIOSEXTERN_OFFSET);
> b_info.bios_size = (*(dmi_data + SMBIOS_BIOSSIZE_OFFSET) + 1) << 6;
> -
> - if (bios_extern & LOONGSON_EFI_ENABLE)
> - set_bit(EFI_BOOT, &efi.flags);
> - else
> - clear_bit(EFI_BOOT, &efi.flags);
> }
>
> static void __init find_tokens(const struct dmi_header *dm, void *dummy)
> @@ -145,6 +136,7 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
> break;
> }
> }
> +
> static void __init smbios_parse(void)
> {
> b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR);
> diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
> index 69c76f26c1c5..36d042739f3c 100644
> --- a/arch/loongarch/kernel/vmlinux.lds.S
> +++ b/arch/loongarch/kernel/vmlinux.lds.S
> @@ -12,6 +12,7 @@
> #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
> diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
> index 6cb7384ad2ac..cbf1c55dc224 100644
> --- a/drivers/firmware/efi/Kconfig
> +++ b/drivers/firmware/efi/Kconfig
> @@ -107,7 +107,7 @@ config EFI_GENERIC_STUB
>
> config EFI_ARMSTUB_DTB_LOADER
> bool "Enable the DTB loader"
> - depends on EFI_GENERIC_STUB && !RISCV
> + depends on EFI_GENERIC_STUB && !RISCV && !LOONGARCH
> default y
> help
> Select this config option to add support for the dtb= command
> @@ -124,7 +124,7 @@ 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 !RISCV && !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..1588c61939e7 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
>
> @@ -70,6 +72,8 @@ 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/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
> index f515394cce6e..efb9219d8d49 100644
> --- a/drivers/firmware/efi/libstub/efi-stub.c
> +++ b/drivers/firmware/efi/libstub/efi-stub.c
> @@ -40,14 +40,19 @@
>
> #ifdef CONFIG_ARM64
> # define EFI_RT_VIRTUAL_LIMIT DEFAULT_MAP_WINDOW_64
> -#elif defined(CONFIG_RISCV)
> +#elif defined(CONFIG_RISCV) || defined(CONFIG_LOONGARCH)
> # define EFI_RT_VIRTUAL_LIMIT TASK_SIZE_MIN
> -#else
> +#else /* Only if TASK_SIZE is a constant */
> # define EFI_RT_VIRTUAL_LIMIT TASK_SIZE
> #endif
>
> +/*
> + * 0: No flat mapping
> + * 1: Flat mapping that VA = PA
> + * 2: Flat mapping that VA = PA + PAGE_OFFSET
> + */
> +static int flat_va_mapping;
> static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
> -static bool flat_va_mapping;
>
> const efi_system_table_t *efi_system_table;
>
> @@ -121,6 +126,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
> {
> efi_loaded_image_t *image;
> efi_status_t status;
> + unsigned long attrib;
> unsigned long image_addr;
> unsigned long image_size = 0;
> /* addr/point and size pairs for memory management*/
> @@ -254,9 +260,11 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
> * The easiest way to achieve that is to simply use a 1:1 mapping.
> */
> prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID);
> - flat_va_mapping = prop_tbl &&
> - (prop_tbl->memory_protection_attribute &
> - EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
> + attrib = prop_tbl ? prop_tbl->memory_protection_attribute : 0;
> + if (attrib & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
> + flat_va_mapping = 1;
> + if (IS_ENABLED(CONFIG_LOONGARCH))
> + flat_va_mapping = 2;
>
> /* force efi_novamap if SetVirtualAddressMap() is unsupported */
> efi_novamap |= !(get_supported_rt_services() &
> @@ -338,7 +346,16 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
> paddr = in->phys_addr;
> size = in->num_pages * EFI_PAGE_SIZE;
>
> - in->virt_addr = in->phys_addr;
> + switch (flat_va_mapping) {
> + case 1:
> + in->virt_addr = in->phys_addr;
> + break;
> + case 2:
> + in->virt_addr = in->phys_addr + PAGE_OFFSET;
It is useful for cachable runtime memory, however there exists uncachable runtime physical address also.
> + break;
> + default:
> + in->virt_addr = in->phys_addr;
> + }
> if (efi_novamap) {
> continue;
> }
> diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c
> new file mode 100644
> index 000000000000..b7ef8d2df59e
> --- /dev/null
> +++ b/drivers/firmware/efi/libstub/loongarch-stub.c
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Author: Yun Liu <[email protected]>
> + * Huacai Chen <[email protected]>
> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> + */
> +
> +#include <asm/efi.h>
> +#include <asm/addrspace.h>
> +#include "efistub.h"
> +
> +typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long fdt);
> +
> +extern int kernel_asize;
> +extern int kernel_fsize;
> +extern int kernel_offset;
> +extern kernel_entry_t kernel_entry;
> +
> +efi_status_t check_platform_features(void)
> +{
> + return EFI_SUCCESS;
> +}
> +
> +efi_status_t handle_kernel_image(unsigned long *image_addr,
> + unsigned long *image_size,
> + unsigned long *reserve_addr,
> + unsigned long *reserve_size,
> + efi_loaded_image_t *image,
> + efi_handle_t image_handle)
> +{
> + efi_status_t status;
> + unsigned long kernel_addr = 0;
> +
> + kernel_addr = (unsigned long)&kernel_offset - kernel_offset;
> +
> + status = efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize,
> + PHYSADDR(VMLINUX_LOAD_ADDRESS), SZ_2M, 0x0);
> +
> + *image_addr = kernel_addr;
> + *image_size = kernel_asize;
> +
> + return status;
> +}
> +
> +void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt, unsigned long fdt_size)
> +{
> + kernel_entry_t real_kernel_entry;
> +
> + /* Config Direct Mapping */
> + csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
> + csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
> +
> + real_kernel_entry = (kernel_entry_t)
> + ((unsigned long)&kernel_entry - entrypoint + VMLINUX_LOAD_ADDRESS);
> +
> + if (!efi_novamap)
> + real_kernel_entry(true, fdt);
> + else
> + real_kernel_entry(false, fdt);
Do we need turn off mmu and jump to physical kernel entry address ?
Or jump to direct mapped address like this?
regards
bibo,mao
> +}
> diff --git a/include/linux/pe.h b/include/linux/pe.h
> index daf09ffffe38..1d3836ef9d92 100644
> --- a/include/linux/pe.h
> +++ b/include/linux/pe.h
> @@ -65,6 +65,8 @@
> #define IMAGE_FILE_MACHINE_SH5 0x01a8
> #define IMAGE_FILE_MACHINE_THUMB 0x01c2
> #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169
> +#define IMAGE_FILE_MACHINE_LOONGARCH32 0x6232
> +#define IMAGE_FILE_MACHINE_LOONGARCH64 0x6264
>
> /* flags */
> #define IMAGE_FILE_RELOCS_STRIPPED 0x0001
On Thu, 18 Aug 2022 at 05:07, Huacai Chen <[email protected]> wrote:
>
> This patch adds efistub booting support, which is the standard UEFI boot
> protocol for us to use.
>
> We use generic efistub, which means we can pass boot information (i.e.,
> system table, memory map, kernel command line, initrd) via a light FDT
> and drop a lot of non-standard code.
>
> We use a flat mapping to map the efi runtime in the kernel's address
> space. In efi, VA = PA; in kernel, VA = PA + PAGE_OFFSET. As a result,
> flat mapping is not identity mapping, SetVirtualAddressMap() is still
> needed for the efi runtime.
>
> Tested-by: Xi Ruoyao <[email protected]>
> Signed-off-by: Huacai Chen <[email protected]>
> ---
> V1 --> V2:
> 1, Call SetVirtualAddressMap() in stub;
> 2, Use core kernel data directly in alloc_screen_info();
> 3, Remove the magic number in MS-DOS header;
> 4, Disable EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER;
> 5, Some other small changes suggested by Ard Biesheuvel.
>
> arch/loongarch/Kconfig | 9 ++
> arch/loongarch/Makefile | 7 +-
> arch/loongarch/boot/Makefile | 8 +-
> arch/loongarch/include/asm/efi.h | 10 +-
> arch/loongarch/kernel/efi-header.S | 99 +++++++++++++++++++
> arch/loongarch/kernel/efi.c | 3 +
> arch/loongarch/kernel/head.S | 20 ++++
> arch/loongarch/kernel/image-vars.h | 30 ++++++
> arch/loongarch/kernel/setup.c | 12 +--
> arch/loongarch/kernel/vmlinux.lds.S | 1 +
> drivers/firmware/efi/Kconfig | 4 +-
> drivers/firmware/efi/libstub/Makefile | 10 ++
> drivers/firmware/efi/libstub/efi-stub.c | 31 ++++--
> drivers/firmware/efi/libstub/loongarch-stub.c | 60 +++++++++++
> include/linux/pe.h | 2 +
> 15 files changed, 282 insertions(+), 24 deletions(-)
> 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/Kconfig b/arch/loongarch/Kconfig
> index 9478f9646fa5..4cb412a82afa 100644
> --- a/arch/loongarch/Kconfig
> +++ b/arch/loongarch/Kconfig
> @@ -324,6 +324,15 @@ config EFI
> This enables the kernel to use EFI runtime services that are
> available (such as the EFI variable services).
>
> +config EFI_STUB
> + bool "EFI boot stub support"
> + default y
> + depends on EFI
> + select EFI_GENERIC_STUB
> + help
> + This kernel feature allows the kernel to be loaded directly by
> + EFI firmware without the use of a bootloader.
> +
> config SMP
> bool "Multi-Processing support"
> help
> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> index ec3de6191276..2bd0a574ed73 100644
> --- a/arch/loongarch/Makefile
> +++ b/arch/loongarch/Makefile
> @@ -7,7 +7,11 @@ boot := arch/loongarch/boot
>
> KBUILD_DEFCONFIG := loongson3_defconfig
>
> -KBUILD_IMAGE = $(boot)/vmlinux
> +ifndef CONFIG_EFI_STUB
> +KBUILD_IMAGE = $(boot)/vmlinux.elf
> +else
> +KBUILD_IMAGE = $(boot)/vmlinux.efi
> +endif
>
Nit: I am not 100% whether it matters or not, but all other
architectures use := for these assignments.
Also, in order to be able to use vmlinux.elf or vmlinux.efi as a make
target directly, other architectures seem to use something like
all: $(notdir $(KBUILD_IMAGE))
vmlinux.elf vmlinux.efi: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(bootvars-y) $(boot)/$@
Adopting this will make it easier to wire up the generic zboot support too.
> #
> # Select the object file format to substitute into the linker script.
> @@ -75,6 +79,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
> diff --git a/arch/loongarch/boot/Makefile b/arch/loongarch/boot/Makefile
> index 0125b17edc98..fecf34f50e56 100644
> --- a/arch/loongarch/boot/Makefile
> +++ b/arch/loongarch/boot/Makefile
> @@ -8,9 +8,13 @@ drop-sections := .comment .note .options .note.gnu.build-id
> strip-flags := $(addprefix --remove-section=,$(drop-sections)) -S
> OBJCOPYFLAGS_vmlinux.efi := -O binary $(strip-flags)
>
> -targets := vmlinux
> quiet_cmd_strip = STRIP $@
> cmd_strip = $(STRIP) -s -o $@ $<
>
> -$(obj)/vmlinux: vmlinux FORCE
> +targets := vmlinux.elf
> +$(obj)/vmlinux.elf: vmlinux FORCE
> $(call if_changed,strip)
> +
> +targets += vmlinux.efi
> +$(obj)/vmlinux.efi: vmlinux FORCE
> + $(call if_changed,objcopy)
> diff --git a/arch/loongarch/include/asm/efi.h b/arch/loongarch/include/asm/efi.h
> index 9d44c6948be1..c7507a240f30 100644
> --- a/arch/loongarch/include/asm/efi.h
> +++ b/arch/loongarch/include/asm/efi.h
> @@ -18,8 +18,14 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
>
> #define EFI_ALLOC_ALIGN SZ_64K
>
> -struct screen_info *alloc_screen_info(void);
> -void free_screen_info(struct screen_info *si);
> +static inline struct screen_info *alloc_screen_info(void)
> +{
> + return &screen_info;
> +}
> +
> +static inline void free_screen_info(struct screen_info *si)
> +{
> +}
>
> static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
> {
> diff --git a/arch/loongarch/kernel/efi-header.S b/arch/loongarch/kernel/efi-header.S
> new file mode 100644
> index 000000000000..8c1d229a2afa
> --- /dev/null
> +++ b/arch/loongarch/kernel/efi-header.S
> @@ -0,0 +1,99 @@
> +/* 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
> +.Lcoff_header:
> + .short IMAGE_FILE_MACHINE_LOONGARCH64 /* Machine */
> + .short .Lsection_count /* NumberOfSections */
> + .long 0 /* TimeDateStamp */
> + .long 0 /* PointerToSymbolTable */
> + .long 0 /* NumberOfSymbols */
> + .short .Lsection_table - .Loptional_header /* SizeOfOptionalHeader */
> + .short IMAGE_FILE_DEBUG_STRIPPED | \
> + IMAGE_FILE_EXECUTABLE_IMAGE | \
> + IMAGE_FILE_LINE_NUMS_STRIPPED /* Characteristics */
> +
> +.Loptional_header:
> + .short PE_OPT_MAGIC_PE32PLUS /* PE32+ format */
> + .byte 0x02 /* MajorLinkerVersion */
> + .byte 0x14 /* MinorLinkerVersion */
> + .long __inittext_end - .Lefi_header_end /* SizeOfCode */
> + .long _end - __initdata_begin /* SizeOfInitializedData */
> + .long 0 /* SizeOfUninitializedData */
> + .long __efistub_efi_pe_entry - _head /* AddressOfEntryPoint */
> + .long .Lefi_header_end - _head /* BaseOfCode */
> +
> +.Lextra_header_fields:
> + .quad 0 /* ImageBase */
> + .long PECOFF_SEGMENT_ALIGN /* SectionAlignment */
> + .long PECOFF_FILE_ALIGN /* FileAlignment */
> + .short 0 /* MajorOperatingSystemVersion */
> + .short 0 /* MinorOperatingSystemVersion */
> + .short LINUX_EFISTUB_MAJOR_VERSION /* MajorImageVersion */
> + .short LINUX_EFISTUB_MINOR_VERSION /* 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 .Lefi_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 (.Lsection_table - .) / 8 /* NumberOfRvaAndSizes */
> +
> + .quad 0 /* ExportTable */
> + .quad 0 /* ImportTable */
> + .quad 0 /* ResourceTable */
> + .quad 0 /* ExceptionTable */
> + .quad 0 /* CertificationTable */
> + .quad 0 /* BaseRelocationTable */
> +
> + /* Section table */
> +.Lsection_table:
> + .ascii ".text\0\0\0"
> + .long __inittext_end - .Lefi_header_end /* VirtualSize */
> + .long .Lefi_header_end - _head /* VirtualAddress */
> + .long __inittext_end - .Lefi_header_end /* SizeOfRawData */
> + .long .Lefi_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 */
> +
> + .set .Lsection_count, (. - .Lsection_table) / 40
> +
> + .balign 0x10000 /* PECOFF_SEGMENT_ALIGN */
> +.Lefi_header_end:
> + .endm
> diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
> index a50b60c587fa..1f1f755fb425 100644
> --- a/arch/loongarch/kernel/efi.c
> +++ b/arch/loongarch/kernel/efi.c
> @@ -69,4 +69,7 @@ void __init efi_init(void)
> config_tables = early_memremap(efi_config_table, efi_nr_tables * size);
> efi_config_parse_tables(config_tables, efi_systab->nr_tables, arch_tables);
> early_memunmap(config_tables, efi_nr_tables * size);
> +
> + if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI)
> + memblock_reserve(screen_info.lfb_base, screen_info.lfb_size);
> }
> diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
> index c60eb66793e3..01bac62a6442 100644
> --- a/arch/loongarch/kernel/head.S
> +++ b/arch/loongarch/kernel/head.S
> @@ -12,6 +12,26 @@
> #include <asm/loongarch.h>
> #include <asm/stackframe.h>
>
> +#ifdef CONFIG_EFI_STUB
> +
> +#include "efi-header.S"
> +
> + __HEAD
> +
> +_head:
> + .word MZ_MAGIC /* "MZ", MS-DOS header */
> + .org 0x3c /* 0x04 ~ 0x3b reserved */
> + .long pe_header - _head /* Offset to the PE header */
> +
> +pe_header:
> + __EFI_PE_HEADER
> +
> +SYM_DATA(kernel_asize, .long _end - _text);
> +SYM_DATA(kernel_fsize, .long _edata - _text);
> +SYM_DATA(kernel_offset, .long kernel_offset - _text);
> +
These are a bit nasty: could you perhaps add a comment that explains
why exactly we need to emit these values like this? Using
kernel_offset with an offset to itself just to be able to refer to
_text from loongarch-stub.c is especially horrid, so bonus points if
you can find a better way to do that, preferably without asm
variables.
> +#endif
> +
> __REF
>
> SYM_CODE_START(kernel_entry) # kernel entry point
> diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h
> new file mode 100644
> index 000000000000..c901ebb903f2
> --- /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_memchr = memchr;
> +__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_strrchr = strrchr;
> +__efistub_kernel_entry = kernel_entry;
> +__efistub_kernel_asize = kernel_asize;
> +__efistub_kernel_fsize = kernel_fsize;
> +__efistub_kernel_offset = kernel_offset;
> +__efistub_screen_info = screen_info;
> +
> +#endif
> +
> +#endif /* __LOONGARCH_KERNEL_IMAGE_VARS_H */
> diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
> index 23ee293e1cd2..f938aae3e92c 100644
> --- a/arch/loongarch/kernel/setup.c
> +++ b/arch/loongarch/kernel/setup.c
> @@ -49,9 +49,7 @@
> #define SMBIOS_CORE_PACKAGE_OFFSET 0x23
> #define LOONGSON_EFI_ENABLE (1 << 3)
>
> -#ifdef CONFIG_VT
> -struct screen_info screen_info;
> -#endif
> +struct screen_info screen_info __section(".data");
>
> unsigned long fw_arg0, fw_arg1;
> DEFINE_PER_CPU(unsigned long, kernelsp);
> @@ -122,16 +120,9 @@ static void __init parse_cpu_table(const struct dmi_header *dm)
>
> static void __init parse_bios_table(const struct dmi_header *dm)
> {
> - int bios_extern;
> char *dmi_data = (char *)dm;
>
> - bios_extern = *(dmi_data + SMBIOS_BIOSEXTERN_OFFSET);
> b_info.bios_size = (*(dmi_data + SMBIOS_BIOSSIZE_OFFSET) + 1) << 6;
> -
> - if (bios_extern & LOONGSON_EFI_ENABLE)
> - set_bit(EFI_BOOT, &efi.flags);
> - else
> - clear_bit(EFI_BOOT, &efi.flags);
> }
>
Why is this taken from the SMBIOS data?
> static void __init find_tokens(const struct dmi_header *dm, void *dummy)
> @@ -145,6 +136,7 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
> break;
> }
> }
> +
> static void __init smbios_parse(void)
> {
> b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR);
> diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
> index 69c76f26c1c5..36d042739f3c 100644
> --- a/arch/loongarch/kernel/vmlinux.lds.S
> +++ b/arch/loongarch/kernel/vmlinux.lds.S
> @@ -12,6 +12,7 @@
> #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
> diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
> index 6cb7384ad2ac..cbf1c55dc224 100644
> --- a/drivers/firmware/efi/Kconfig
> +++ b/drivers/firmware/efi/Kconfig
> @@ -107,7 +107,7 @@ config EFI_GENERIC_STUB
>
> config EFI_ARMSTUB_DTB_LOADER
> bool "Enable the DTB loader"
> - depends on EFI_GENERIC_STUB && !RISCV
> + depends on EFI_GENERIC_STUB && !RISCV && !LOONGARCH
> default y
> help
> Select this config option to add support for the dtb= command
> @@ -124,7 +124,7 @@ 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 !RISCV && !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..1588c61939e7 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
>
> @@ -70,6 +72,8 @@ 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/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
> index f515394cce6e..efb9219d8d49 100644
> --- a/drivers/firmware/efi/libstub/efi-stub.c
> +++ b/drivers/firmware/efi/libstub/efi-stub.c
> @@ -40,14 +40,19 @@
>
> #ifdef CONFIG_ARM64
> # define EFI_RT_VIRTUAL_LIMIT DEFAULT_MAP_WINDOW_64
> -#elif defined(CONFIG_RISCV)
> +#elif defined(CONFIG_RISCV) || defined(CONFIG_LOONGARCH)
> # define EFI_RT_VIRTUAL_LIMIT TASK_SIZE_MIN
> -#else
> +#else /* Only if TASK_SIZE is a constant */
> # define EFI_RT_VIRTUAL_LIMIT TASK_SIZE
> #endif
>
> +/*
> + * 0: No flat mapping
> + * 1: Flat mapping that VA = PA
> + * 2: Flat mapping that VA = PA + PAGE_OFFSET
> + */
> +static int flat_va_mapping;
> static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
> -static bool flat_va_mapping;
>
Can we change this around a bit?
static bool flat_va_mapping = __is_defined(EFI_RT_FIXED_VIRTUAL_OFFSET);
#ifndef EFI_RT_FIXED_VIRTUAL_OFFSET
#define EFI_RT_FIXED_VIRTUAL_OFFSET 0
#endif
Then, in your arch's asm/efi.h, you can add
#define EFI_RT_FIXED_VIRTUAL_OFFSET PAGE_OFFSET
...
> @@ -254,9 +260,11 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
> * The easiest way to achieve that is to simply use a 1:1 mapping.
> */
> prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID);
> - flat_va_mapping = prop_tbl &&
> - (prop_tbl->memory_protection_attribute &
> - EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
> + attrib = prop_tbl ? prop_tbl->memory_protection_attribute : 0;
> + if (attrib & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
> + flat_va_mapping = 1;
> + if (IS_ENABLED(CONFIG_LOONGARCH))
> + flat_va_mapping = 2;
>
Keep the original code but change it into
flat_va_mapping |= ....
(and drop the rest of the change)
> /* force efi_novamap if SetVirtualAddressMap() is unsupported */
> efi_novamap |= !(get_supported_rt_services() &
> @@ -338,7 +346,16 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
> paddr = in->phys_addr;
> size = in->num_pages * EFI_PAGE_SIZE;
>
> - in->virt_addr = in->phys_addr;
Change this into
in->virt_addr = in->phys_addr + EFI_RT_FIXED_VIRTUAL_OFFSET;
> + switch (flat_va_mapping) {
> + case 1:
> + in->virt_addr = in->phys_addr;
> + break;
> + case 2:
> + in->virt_addr = in->phys_addr + PAGE_OFFSET;
> + break;
> + default:
> + in->virt_addr = in->phys_addr;
> + }
And drop the switch
> if (efi_novamap) {
> continue;
> }
> diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c
> new file mode 100644
> index 000000000000..b7ef8d2df59e
> --- /dev/null
> +++ b/drivers/firmware/efi/libstub/loongarch-stub.c
> @@ -0,0 +1,60 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Author: Yun Liu <[email protected]>
> + * Huacai Chen <[email protected]>
> + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> + */
> +
> +#include <asm/efi.h>
> +#include <asm/addrspace.h>
> +#include "efistub.h"
> +
> +typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long fdt);
> +
> +extern int kernel_asize;
> +extern int kernel_fsize;
> +extern int kernel_offset;
> +extern kernel_entry_t kernel_entry;
> +
> +efi_status_t check_platform_features(void)
> +{
> + return EFI_SUCCESS;
> +}
> +
> +efi_status_t handle_kernel_image(unsigned long *image_addr,
> + unsigned long *image_size,
> + unsigned long *reserve_addr,
> + unsigned long *reserve_size,
> + efi_loaded_image_t *image,
> + efi_handle_t image_handle)
> +{
> + efi_status_t status;
> + unsigned long kernel_addr = 0;
> +
> + kernel_addr = (unsigned long)&kernel_offset - kernel_offset;
> +
> + status = efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize,
> + PHYSADDR(VMLINUX_LOAD_ADDRESS), SZ_2M, 0x0);
> +
> + *image_addr = kernel_addr;
> + *image_size = kernel_asize;
> +
> + return status;
> +}
> +
> +void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt, unsigned long fdt_size)
> +{
> + kernel_entry_t real_kernel_entry;
> +
> + /* Config Direct Mapping */
> + csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
> + csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
> +
> + real_kernel_entry = (kernel_entry_t)
> + ((unsigned long)&kernel_entry - entrypoint + VMLINUX_LOAD_ADDRESS);
> +
> + if (!efi_novamap)
> + real_kernel_entry(true, fdt);
> + else
> + real_kernel_entry(false, fdt);
> +}
> diff --git a/include/linux/pe.h b/include/linux/pe.h
> index daf09ffffe38..1d3836ef9d92 100644
> --- a/include/linux/pe.h
> +++ b/include/linux/pe.h
> @@ -65,6 +65,8 @@
> #define IMAGE_FILE_MACHINE_SH5 0x01a8
> #define IMAGE_FILE_MACHINE_THUMB 0x01c2
> #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169
> +#define IMAGE_FILE_MACHINE_LOONGARCH32 0x6232
> +#define IMAGE_FILE_MACHINE_LOONGARCH64 0x6264
>
> /* flags */
> #define IMAGE_FILE_RELOCS_STRIPPED 0x0001
This is looking really good now! Thanks for taking my feedback so seriously.
We will have to figure out how to queue this up, given that I intend
to queue the generic EFI zboot changes for v6.1 as well.
Hi, Bibo,
On Thu, Aug 18, 2022 at 9:12 PM maobibo <[email protected]> wrote:
>
> Huacai,
>
> This patch is much better than before.
> It works well on qemu virt machine platform, and I reply inline.
>
> 在 2022/8/18 11:07, Huacai Chen 写道:
> > This patch adds efistub booting support, which is the standard UEFI boot
> > protocol for us to use.
> >
> > We use generic efistub, which means we can pass boot information (i.e.,
> > system table, memory map, kernel command line, initrd) via a light FDT
> > and drop a lot of non-standard code.
> >
> > We use a flat mapping to map the efi runtime in the kernel's address
> > space. In efi, VA = PA; in kernel, VA = PA + PAGE_OFFSET. As a result,
> > flat mapping is not identity mapping, SetVirtualAddressMap() is still
> > needed for the efi runtime.
> >
> > Tested-by: Xi Ruoyao <[email protected]>
> > Signed-off-by: Huacai Chen <[email protected]>
> > ---
> > V1 --> V2:
> > 1, Call SetVirtualAddressMap() in stub;
> > 2, Use core kernel data directly in alloc_screen_info();
> > 3, Remove the magic number in MS-DOS header;
> > 4, Disable EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER;
> > 5, Some other small changes suggested by Ard Biesheuvel.
> >
> > arch/loongarch/Kconfig | 9 ++
> > arch/loongarch/Makefile | 7 +-
> > arch/loongarch/boot/Makefile | 8 +-
> > arch/loongarch/include/asm/efi.h | 10 +-
> > arch/loongarch/kernel/efi-header.S | 99 +++++++++++++++++++
> > arch/loongarch/kernel/efi.c | 3 +
> > arch/loongarch/kernel/head.S | 20 ++++
> > arch/loongarch/kernel/image-vars.h | 30 ++++++
> > arch/loongarch/kernel/setup.c | 12 +--
> > arch/loongarch/kernel/vmlinux.lds.S | 1 +
> > drivers/firmware/efi/Kconfig | 4 +-
> > drivers/firmware/efi/libstub/Makefile | 10 ++
> > drivers/firmware/efi/libstub/efi-stub.c | 31 ++++--
> > drivers/firmware/efi/libstub/loongarch-stub.c | 60 +++++++++++
> > include/linux/pe.h | 2 +
> > 15 files changed, 282 insertions(+), 24 deletions(-)
> > 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/Kconfig b/arch/loongarch/Kconfig
> > index 9478f9646fa5..4cb412a82afa 100644
> > --- a/arch/loongarch/Kconfig
> > +++ b/arch/loongarch/Kconfig
> > @@ -324,6 +324,15 @@ config EFI
> > This enables the kernel to use EFI runtime services that are
> > available (such as the EFI variable services).
> >
> > +config EFI_STUB
> > + bool "EFI boot stub support"
> > + default y
> > + depends on EFI
> > + select EFI_GENERIC_STUB
> > + help
> > + This kernel feature allows the kernel to be loaded directly by
> > + EFI firmware without the use of a bootloader.
> > +
> > config SMP
> > bool "Multi-Processing support"
> > help
> > diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> > index ec3de6191276..2bd0a574ed73 100644
> > --- a/arch/loongarch/Makefile
> > +++ b/arch/loongarch/Makefile
> > @@ -7,7 +7,11 @@ boot := arch/loongarch/boot
> >
> > KBUILD_DEFCONFIG := loongson3_defconfig
> >
> > -KBUILD_IMAGE = $(boot)/vmlinux
> > +ifndef CONFIG_EFI_STUB
> > +KBUILD_IMAGE = $(boot)/vmlinux.elf
> > +else
> > +KBUILD_IMAGE = $(boot)/vmlinux.efi
> > +endif
> >
> > #
> > # Select the object file format to substitute into the linker script.
> > @@ -75,6 +79,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
> > diff --git a/arch/loongarch/boot/Makefile b/arch/loongarch/boot/Makefile
> > index 0125b17edc98..fecf34f50e56 100644
> > --- a/arch/loongarch/boot/Makefile
> > +++ b/arch/loongarch/boot/Makefile
> > @@ -8,9 +8,13 @@ drop-sections := .comment .note .options .note.gnu.build-id
> > strip-flags := $(addprefix --remove-section=,$(drop-sections)) -S
> > OBJCOPYFLAGS_vmlinux.efi := -O binary $(strip-flags)
> >
> > -targets := vmlinux
> > quiet_cmd_strip = STRIP $@
> > cmd_strip = $(STRIP) -s -o $@ $<
> >
> > -$(obj)/vmlinux: vmlinux FORCE
> > +targets := vmlinux.elf
> > +$(obj)/vmlinux.elf: vmlinux FORCE
> > $(call if_changed,strip)
> > +
> > +targets += vmlinux.efi
> > +$(obj)/vmlinux.efi: vmlinux FORCE
> > + $(call if_changed,objcopy)
> > diff --git a/arch/loongarch/include/asm/efi.h b/arch/loongarch/include/asm/efi.h
> > index 9d44c6948be1..c7507a240f30 100644
> > --- a/arch/loongarch/include/asm/efi.h
> > +++ b/arch/loongarch/include/asm/efi.h
> > @@ -18,8 +18,14 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
> >
> > #define EFI_ALLOC_ALIGN SZ_64K
> >
> > -struct screen_info *alloc_screen_info(void);
> > -void free_screen_info(struct screen_info *si);
> > +static inline struct screen_info *alloc_screen_info(void)
> > +{
> > + return &screen_info;
> > +}
> > +
> > +static inline void free_screen_info(struct screen_info *si)
> > +{
> > +}
> >
> > static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
> > {
> > diff --git a/arch/loongarch/kernel/efi-header.S b/arch/loongarch/kernel/efi-header.S
> > new file mode 100644
> > index 000000000000..8c1d229a2afa
> > --- /dev/null
> > +++ b/arch/loongarch/kernel/efi-header.S
> > @@ -0,0 +1,99 @@
> > +/* 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
> > +.Lcoff_header:
> > + .short IMAGE_FILE_MACHINE_LOONGARCH64 /* Machine */
> > + .short .Lsection_count /* NumberOfSections */
> > + .long 0 /* TimeDateStamp */
> > + .long 0 /* PointerToSymbolTable */
> > + .long 0 /* NumberOfSymbols */
> > + .short .Lsection_table - .Loptional_header /* SizeOfOptionalHeader */
> > + .short IMAGE_FILE_DEBUG_STRIPPED | \
> > + IMAGE_FILE_EXECUTABLE_IMAGE | \
> > + IMAGE_FILE_LINE_NUMS_STRIPPED /* Characteristics */
> > +
> > +.Loptional_header:
> > + .short PE_OPT_MAGIC_PE32PLUS /* PE32+ format */
> > + .byte 0x02 /* MajorLinkerVersion */
> > + .byte 0x14 /* MinorLinkerVersion */
> > + .long __inittext_end - .Lefi_header_end /* SizeOfCode */
> > + .long _end - __initdata_begin /* SizeOfInitializedData */
> > + .long 0 /* SizeOfUninitializedData */
> > + .long __efistub_efi_pe_entry - _head /* AddressOfEntryPoint */
> > + .long .Lefi_header_end - _head /* BaseOfCode */
> > +
> > +.Lextra_header_fields:
> > + .quad 0 /* ImageBase */
> > + .long PECOFF_SEGMENT_ALIGN /* SectionAlignment */
> > + .long PECOFF_FILE_ALIGN /* FileAlignment */
> > + .short 0 /* MajorOperatingSystemVersion */
> > + .short 0 /* MinorOperatingSystemVersion */
> > + .short LINUX_EFISTUB_MAJOR_VERSION /* MajorImageVersion */
> > + .short LINUX_EFISTUB_MINOR_VERSION /* 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 .Lefi_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 (.Lsection_table - .) / 8 /* NumberOfRvaAndSizes */
> > +
> > + .quad 0 /* ExportTable */
> > + .quad 0 /* ImportTable */
> > + .quad 0 /* ResourceTable */
> > + .quad 0 /* ExceptionTable */
> > + .quad 0 /* CertificationTable */
> > + .quad 0 /* BaseRelocationTable */
> > +
> > + /* Section table */
> > +.Lsection_table:
> > + .ascii ".text\0\0\0"
> > + .long __inittext_end - .Lefi_header_end /* VirtualSize */
> > + .long .Lefi_header_end - _head /* VirtualAddress */
> > + .long __inittext_end - .Lefi_header_end /* SizeOfRawData */
> > + .long .Lefi_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 */
> > +
> > + .set .Lsection_count, (. - .Lsection_table) / 40
> > +
> > + .balign 0x10000 /* PECOFF_SEGMENT_ALIGN */
> > +.Lefi_header_end:
> > + .endm
> > diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
> > index a50b60c587fa..1f1f755fb425 100644
> > --- a/arch/loongarch/kernel/efi.c
> > +++ b/arch/loongarch/kernel/efi.c
> > @@ -69,4 +69,7 @@ void __init efi_init(void)
> > config_tables = early_memremap(efi_config_table, efi_nr_tables * size);
> > efi_config_parse_tables(config_tables, efi_systab->nr_tables, arch_tables);
> > early_memunmap(config_tables, efi_nr_tables * size);
> > +
> > + if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI)
> > + memblock_reserve(screen_info.lfb_base, screen_info.lfb_size);
> > }
> > diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
> > index c60eb66793e3..01bac62a6442 100644
> > --- a/arch/loongarch/kernel/head.S
> > +++ b/arch/loongarch/kernel/head.S
> > @@ -12,6 +12,26 @@
> > #include <asm/loongarch.h>
> > #include <asm/stackframe.h>
> >
> > +#ifdef CONFIG_EFI_STUB
> > +
> > +#include "efi-header.S"
> > +
> > + __HEAD
> > +
> > +_head:
> > + .word MZ_MAGIC /* "MZ", MS-DOS header */
> > + .org 0x3c /* 0x04 ~ 0x3b reserved */
> > + .long pe_header - _head /* Offset to the PE header */
> > +
> > +pe_header:
> > + __EFI_PE_HEADER
> > +
> > +SYM_DATA(kernel_asize, .long _end - _text);
> > +SYM_DATA(kernel_fsize, .long _edata - _text);
> > +SYM_DATA(kernel_offset, .long kernel_offset - _text);
> > +
> > +#endif
> > +
> > __REF
> >
> > SYM_CODE_START(kernel_entry) # kernel entry point
> > diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h
> > new file mode 100644
> > index 000000000000..c901ebb903f2
> > --- /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_memchr = memchr;
> > +__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_strrchr = strrchr;
> > +__efistub_kernel_entry = kernel_entry;
> > +__efistub_kernel_asize = kernel_asize;
> > +__efistub_kernel_fsize = kernel_fsize;
> > +__efistub_kernel_offset = kernel_offset;
> > +__efistub_screen_info = screen_info;
> > +
> > +#endif
> > +
> > +#endif /* __LOONGARCH_KERNEL_IMAGE_VARS_H */
> > diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
> > index 23ee293e1cd2..f938aae3e92c 100644
> > --- a/arch/loongarch/kernel/setup.c
> > +++ b/arch/loongarch/kernel/setup.c
> > @@ -49,9 +49,7 @@
> > #define SMBIOS_CORE_PACKAGE_OFFSET 0x23
> > #define LOONGSON_EFI_ENABLE (1 << 3)
> >
> > -#ifdef CONFIG_VT
> > -struct screen_info screen_info;
> > -#endif
> > +struct screen_info screen_info __section(".data");
> >
> > unsigned long fw_arg0, fw_arg1;
> > DEFINE_PER_CPU(unsigned long, kernelsp);
> > @@ -122,16 +120,9 @@ static void __init parse_cpu_table(const struct dmi_header *dm)
> >
> > static void __init parse_bios_table(const struct dmi_header *dm)
> > {
> > - int bios_extern;
> > char *dmi_data = (char *)dm;
> >
> > - bios_extern = *(dmi_data + SMBIOS_BIOSEXTERN_OFFSET);
> > b_info.bios_size = (*(dmi_data + SMBIOS_BIOSSIZE_OFFSET) + 1) << 6;
> > -
> > - if (bios_extern & LOONGSON_EFI_ENABLE)
> > - set_bit(EFI_BOOT, &efi.flags);
> > - else
> > - clear_bit(EFI_BOOT, &efi.flags);
> > }
> >
> > static void __init find_tokens(const struct dmi_header *dm, void *dummy)
> > @@ -145,6 +136,7 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
> > break;
> > }
> > }
> > +
> > static void __init smbios_parse(void)
> > {
> > b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR);
> > diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
> > index 69c76f26c1c5..36d042739f3c 100644
> > --- a/arch/loongarch/kernel/vmlinux.lds.S
> > +++ b/arch/loongarch/kernel/vmlinux.lds.S
> > @@ -12,6 +12,7 @@
> > #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
> > diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
> > index 6cb7384ad2ac..cbf1c55dc224 100644
> > --- a/drivers/firmware/efi/Kconfig
> > +++ b/drivers/firmware/efi/Kconfig
> > @@ -107,7 +107,7 @@ config EFI_GENERIC_STUB
> >
> > config EFI_ARMSTUB_DTB_LOADER
> > bool "Enable the DTB loader"
> > - depends on EFI_GENERIC_STUB && !RISCV
> > + depends on EFI_GENERIC_STUB && !RISCV && !LOONGARCH
> > default y
> > help
> > Select this config option to add support for the dtb= command
> > @@ -124,7 +124,7 @@ 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 !RISCV && !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..1588c61939e7 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
> >
> > @@ -70,6 +72,8 @@ 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/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
> > index f515394cce6e..efb9219d8d49 100644
> > --- a/drivers/firmware/efi/libstub/efi-stub.c
> > +++ b/drivers/firmware/efi/libstub/efi-stub.c
> > @@ -40,14 +40,19 @@
> >
> > #ifdef CONFIG_ARM64
> > # define EFI_RT_VIRTUAL_LIMIT DEFAULT_MAP_WINDOW_64
> > -#elif defined(CONFIG_RISCV)
> > +#elif defined(CONFIG_RISCV) || defined(CONFIG_LOONGARCH)
> > # define EFI_RT_VIRTUAL_LIMIT TASK_SIZE_MIN
> > -#else
> > +#else /* Only if TASK_SIZE is a constant */
> > # define EFI_RT_VIRTUAL_LIMIT TASK_SIZE
> > #endif
> >
> > +/*
> > + * 0: No flat mapping
> > + * 1: Flat mapping that VA = PA
> > + * 2: Flat mapping that VA = PA + PAGE_OFFSET
> > + */
> > +static int flat_va_mapping;
> > static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
> > -static bool flat_va_mapping;
> >
> > const efi_system_table_t *efi_system_table;
> >
> > @@ -121,6 +126,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
> > {
> > efi_loaded_image_t *image;
> > efi_status_t status;
> > + unsigned long attrib;
> > unsigned long image_addr;
> > unsigned long image_size = 0;
> > /* addr/point and size pairs for memory management*/
> > @@ -254,9 +260,11 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
> > * The easiest way to achieve that is to simply use a 1:1 mapping.
> > */
> > prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID);
> > - flat_va_mapping = prop_tbl &&
> > - (prop_tbl->memory_protection_attribute &
> > - EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
> > + attrib = prop_tbl ? prop_tbl->memory_protection_attribute : 0;
> > + if (attrib & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
> > + flat_va_mapping = 1;
> > + if (IS_ENABLED(CONFIG_LOONGARCH))
> > + flat_va_mapping = 2;
> >
> > /* force efi_novamap if SetVirtualAddressMap() is unsupported */
> > efi_novamap |= !(get_supported_rt_services() &
> > @@ -338,7 +346,16 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
> > paddr = in->phys_addr;
> > size = in->num_pages * EFI_PAGE_SIZE;
> >
> > - in->virt_addr = in->phys_addr;
> > + switch (flat_va_mapping) {
> > + case 1:
> > + in->virt_addr = in->phys_addr;
> > + break;
> > + case 2:
> > + in->virt_addr = in->phys_addr + PAGE_OFFSET;
> It is useful for cachable runtime memory, however there exists uncachable runtime physical address also.
Yes, so we will change to use the UNCACHE_BASE, as discussed.
>
> > + break;
> > + default:
> > + in->virt_addr = in->phys_addr;
> > + }
> > if (efi_novamap) {
> > continue;
> > }
> > diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c
> > new file mode 100644
> > index 000000000000..b7ef8d2df59e
> > --- /dev/null
> > +++ b/drivers/firmware/efi/libstub/loongarch-stub.c
> > @@ -0,0 +1,60 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Author: Yun Liu <[email protected]>
> > + * Huacai Chen <[email protected]>
> > + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > + */
> > +
> > +#include <asm/efi.h>
> > +#include <asm/addrspace.h>
> > +#include "efistub.h"
> > +
> > +typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long fdt);
> > +
> > +extern int kernel_asize;
> > +extern int kernel_fsize;
> > +extern int kernel_offset;
> > +extern kernel_entry_t kernel_entry;
> > +
> > +efi_status_t check_platform_features(void)
> > +{
> > + return EFI_SUCCESS;
> > +}
> > +
> > +efi_status_t handle_kernel_image(unsigned long *image_addr,
> > + unsigned long *image_size,
> > + unsigned long *reserve_addr,
> > + unsigned long *reserve_size,
> > + efi_loaded_image_t *image,
> > + efi_handle_t image_handle)
> > +{
> > + efi_status_t status;
> > + unsigned long kernel_addr = 0;
> > +
> > + kernel_addr = (unsigned long)&kernel_offset - kernel_offset;
> > +
> > + status = efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize,
> > + PHYSADDR(VMLINUX_LOAD_ADDRESS), SZ_2M, 0x0);
> > +
> > + *image_addr = kernel_addr;
> > + *image_size = kernel_asize;
> > +
> > + return status;
> > +}
> > +
> > +void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt, unsigned long fdt_size)
> > +{
> > + kernel_entry_t real_kernel_entry;
> > +
> > + /* Config Direct Mapping */
> > + csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
> > + csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
> > +
> > + real_kernel_entry = (kernel_entry_t)
> > + ((unsigned long)&kernel_entry - entrypoint + VMLINUX_LOAD_ADDRESS);
> > +
> > + if (!efi_novamap)
> > + real_kernel_entry(true, fdt);
> > + else
> > + real_kernel_entry(false, fdt);
> Do we need turn off mmu and jump to physical kernel entry address ?
> Or jump to direct mapped address like this?
I don't think so, we will immediately turn on mmu after jumping, this
operation seems meaningless.
Huacai
>
> regards
> bibo,mao
>
> > +}
> > diff --git a/include/linux/pe.h b/include/linux/pe.h
> > index daf09ffffe38..1d3836ef9d92 100644
> > --- a/include/linux/pe.h
> > +++ b/include/linux/pe.h
> > @@ -65,6 +65,8 @@
> > #define IMAGE_FILE_MACHINE_SH5 0x01a8
> > #define IMAGE_FILE_MACHINE_THUMB 0x01c2
> > #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169
> > +#define IMAGE_FILE_MACHINE_LOONGARCH32 0x6232
> > +#define IMAGE_FILE_MACHINE_LOONGARCH64 0x6264
> >
> > /* flags */
> > #define IMAGE_FILE_RELOCS_STRIPPED 0x0001
>
Hi, Ard,
On Fri, Aug 19, 2022 at 1:04 AM Ard Biesheuvel <[email protected]> wrote:
>
> On Thu, 18 Aug 2022 at 05:07, Huacai Chen <[email protected]> wrote:
> >
> > This patch adds efistub booting support, which is the standard UEFI boot
> > protocol for us to use.
> >
> > We use generic efistub, which means we can pass boot information (i.e.,
> > system table, memory map, kernel command line, initrd) via a light FDT
> > and drop a lot of non-standard code.
> >
> > We use a flat mapping to map the efi runtime in the kernel's address
> > space. In efi, VA = PA; in kernel, VA = PA + PAGE_OFFSET. As a result,
> > flat mapping is not identity mapping, SetVirtualAddressMap() is still
> > needed for the efi runtime.
> >
> > Tested-by: Xi Ruoyao <[email protected]>
> > Signed-off-by: Huacai Chen <[email protected]>
> > ---
> > V1 --> V2:
> > 1, Call SetVirtualAddressMap() in stub;
> > 2, Use core kernel data directly in alloc_screen_info();
> > 3, Remove the magic number in MS-DOS header;
> > 4, Disable EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER;
> > 5, Some other small changes suggested by Ard Biesheuvel.
> >
> > arch/loongarch/Kconfig | 9 ++
> > arch/loongarch/Makefile | 7 +-
> > arch/loongarch/boot/Makefile | 8 +-
> > arch/loongarch/include/asm/efi.h | 10 +-
> > arch/loongarch/kernel/efi-header.S | 99 +++++++++++++++++++
> > arch/loongarch/kernel/efi.c | 3 +
> > arch/loongarch/kernel/head.S | 20 ++++
> > arch/loongarch/kernel/image-vars.h | 30 ++++++
> > arch/loongarch/kernel/setup.c | 12 +--
> > arch/loongarch/kernel/vmlinux.lds.S | 1 +
> > drivers/firmware/efi/Kconfig | 4 +-
> > drivers/firmware/efi/libstub/Makefile | 10 ++
> > drivers/firmware/efi/libstub/efi-stub.c | 31 ++++--
> > drivers/firmware/efi/libstub/loongarch-stub.c | 60 +++++++++++
> > include/linux/pe.h | 2 +
> > 15 files changed, 282 insertions(+), 24 deletions(-)
> > 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/Kconfig b/arch/loongarch/Kconfig
> > index 9478f9646fa5..4cb412a82afa 100644
> > --- a/arch/loongarch/Kconfig
> > +++ b/arch/loongarch/Kconfig
> > @@ -324,6 +324,15 @@ config EFI
> > This enables the kernel to use EFI runtime services that are
> > available (such as the EFI variable services).
> >
> > +config EFI_STUB
> > + bool "EFI boot stub support"
> > + default y
> > + depends on EFI
> > + select EFI_GENERIC_STUB
> > + help
> > + This kernel feature allows the kernel to be loaded directly by
> > + EFI firmware without the use of a bootloader.
> > +
> > config SMP
> > bool "Multi-Processing support"
> > help
> > diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> > index ec3de6191276..2bd0a574ed73 100644
> > --- a/arch/loongarch/Makefile
> > +++ b/arch/loongarch/Makefile
> > @@ -7,7 +7,11 @@ boot := arch/loongarch/boot
> >
> > KBUILD_DEFCONFIG := loongson3_defconfig
> >
> > -KBUILD_IMAGE = $(boot)/vmlinux
> > +ifndef CONFIG_EFI_STUB
> > +KBUILD_IMAGE = $(boot)/vmlinux.elf
> > +else
> > +KBUILD_IMAGE = $(boot)/vmlinux.efi
> > +endif
> >
>
> Nit: I am not 100% whether it matters or not, but all other
> architectures use := for these assignments.
>
> Also, in order to be able to use vmlinux.elf or vmlinux.efi as a make
> target directly, other architectures seem to use something like
>
> all: $(notdir $(KBUILD_IMAGE))
>
> vmlinux.elf vmlinux.efi: vmlinux
> $(Q)$(MAKE) $(build)=$(boot) $(bootvars-y) $(boot)/$@
>
> Adopting this will make it easier to wire up the generic zboot support too.
OK, I will change the Makefile as you suggested.
>
> > #
> > # Select the object file format to substitute into the linker script.
> > @@ -75,6 +79,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
> > diff --git a/arch/loongarch/boot/Makefile b/arch/loongarch/boot/Makefile
> > index 0125b17edc98..fecf34f50e56 100644
> > --- a/arch/loongarch/boot/Makefile
> > +++ b/arch/loongarch/boot/Makefile
> > @@ -8,9 +8,13 @@ drop-sections := .comment .note .options .note.gnu.build-id
> > strip-flags := $(addprefix --remove-section=,$(drop-sections)) -S
> > OBJCOPYFLAGS_vmlinux.efi := -O binary $(strip-flags)
> >
> > -targets := vmlinux
> > quiet_cmd_strip = STRIP $@
> > cmd_strip = $(STRIP) -s -o $@ $<
> >
> > -$(obj)/vmlinux: vmlinux FORCE
> > +targets := vmlinux.elf
> > +$(obj)/vmlinux.elf: vmlinux FORCE
> > $(call if_changed,strip)
> > +
> > +targets += vmlinux.efi
> > +$(obj)/vmlinux.efi: vmlinux FORCE
> > + $(call if_changed,objcopy)
> > diff --git a/arch/loongarch/include/asm/efi.h b/arch/loongarch/include/asm/efi.h
> > index 9d44c6948be1..c7507a240f30 100644
> > --- a/arch/loongarch/include/asm/efi.h
> > +++ b/arch/loongarch/include/asm/efi.h
> > @@ -18,8 +18,14 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
> >
> > #define EFI_ALLOC_ALIGN SZ_64K
> >
> > -struct screen_info *alloc_screen_info(void);
> > -void free_screen_info(struct screen_info *si);
> > +static inline struct screen_info *alloc_screen_info(void)
> > +{
> > + return &screen_info;
> > +}
> > +
> > +static inline void free_screen_info(struct screen_info *si)
> > +{
> > +}
> >
> > static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
> > {
> > diff --git a/arch/loongarch/kernel/efi-header.S b/arch/loongarch/kernel/efi-header.S
> > new file mode 100644
> > index 000000000000..8c1d229a2afa
> > --- /dev/null
> > +++ b/arch/loongarch/kernel/efi-header.S
> > @@ -0,0 +1,99 @@
> > +/* 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
> > +.Lcoff_header:
> > + .short IMAGE_FILE_MACHINE_LOONGARCH64 /* Machine */
> > + .short .Lsection_count /* NumberOfSections */
> > + .long 0 /* TimeDateStamp */
> > + .long 0 /* PointerToSymbolTable */
> > + .long 0 /* NumberOfSymbols */
> > + .short .Lsection_table - .Loptional_header /* SizeOfOptionalHeader */
> > + .short IMAGE_FILE_DEBUG_STRIPPED | \
> > + IMAGE_FILE_EXECUTABLE_IMAGE | \
> > + IMAGE_FILE_LINE_NUMS_STRIPPED /* Characteristics */
> > +
> > +.Loptional_header:
> > + .short PE_OPT_MAGIC_PE32PLUS /* PE32+ format */
> > + .byte 0x02 /* MajorLinkerVersion */
> > + .byte 0x14 /* MinorLinkerVersion */
> > + .long __inittext_end - .Lefi_header_end /* SizeOfCode */
> > + .long _end - __initdata_begin /* SizeOfInitializedData */
> > + .long 0 /* SizeOfUninitializedData */
> > + .long __efistub_efi_pe_entry - _head /* AddressOfEntryPoint */
> > + .long .Lefi_header_end - _head /* BaseOfCode */
> > +
> > +.Lextra_header_fields:
> > + .quad 0 /* ImageBase */
> > + .long PECOFF_SEGMENT_ALIGN /* SectionAlignment */
> > + .long PECOFF_FILE_ALIGN /* FileAlignment */
> > + .short 0 /* MajorOperatingSystemVersion */
> > + .short 0 /* MinorOperatingSystemVersion */
> > + .short LINUX_EFISTUB_MAJOR_VERSION /* MajorImageVersion */
> > + .short LINUX_EFISTUB_MINOR_VERSION /* 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 .Lefi_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 (.Lsection_table - .) / 8 /* NumberOfRvaAndSizes */
> > +
> > + .quad 0 /* ExportTable */
> > + .quad 0 /* ImportTable */
> > + .quad 0 /* ResourceTable */
> > + .quad 0 /* ExceptionTable */
> > + .quad 0 /* CertificationTable */
> > + .quad 0 /* BaseRelocationTable */
> > +
> > + /* Section table */
> > +.Lsection_table:
> > + .ascii ".text\0\0\0"
> > + .long __inittext_end - .Lefi_header_end /* VirtualSize */
> > + .long .Lefi_header_end - _head /* VirtualAddress */
> > + .long __inittext_end - .Lefi_header_end /* SizeOfRawData */
> > + .long .Lefi_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 */
> > +
> > + .set .Lsection_count, (. - .Lsection_table) / 40
> > +
> > + .balign 0x10000 /* PECOFF_SEGMENT_ALIGN */
> > +.Lefi_header_end:
> > + .endm
> > diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c
> > index a50b60c587fa..1f1f755fb425 100644
> > --- a/arch/loongarch/kernel/efi.c
> > +++ b/arch/loongarch/kernel/efi.c
> > @@ -69,4 +69,7 @@ void __init efi_init(void)
> > config_tables = early_memremap(efi_config_table, efi_nr_tables * size);
> > efi_config_parse_tables(config_tables, efi_systab->nr_tables, arch_tables);
> > early_memunmap(config_tables, efi_nr_tables * size);
> > +
> > + if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI)
> > + memblock_reserve(screen_info.lfb_base, screen_info.lfb_size);
> > }
> > diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
> > index c60eb66793e3..01bac62a6442 100644
> > --- a/arch/loongarch/kernel/head.S
> > +++ b/arch/loongarch/kernel/head.S
> > @@ -12,6 +12,26 @@
> > #include <asm/loongarch.h>
> > #include <asm/stackframe.h>
> >
> > +#ifdef CONFIG_EFI_STUB
> > +
> > +#include "efi-header.S"
> > +
> > + __HEAD
> > +
> > +_head:
> > + .word MZ_MAGIC /* "MZ", MS-DOS header */
> > + .org 0x3c /* 0x04 ~ 0x3b reserved */
> > + .long pe_header - _head /* Offset to the PE header */
> > +
> > +pe_header:
> > + __EFI_PE_HEADER
> > +
> > +SYM_DATA(kernel_asize, .long _end - _text);
> > +SYM_DATA(kernel_fsize, .long _edata - _text);
> > +SYM_DATA(kernel_offset, .long kernel_offset - _text);
> > +
>
> These are a bit nasty: could you perhaps add a comment that explains
> why exactly we need to emit these values like this? Using
> kernel_offset with an offset to itself just to be able to refer to
> _text from loongarch-stub.c is especially horrid, so bonus points if
> you can find a better way to do that, preferably without asm
> variables.
This is due to a link problem. Our vmlinux is not PIC, but the stub is
PIC, then the stub code cannot access _text and other symbols defined
in vmlinux.lds.S, because the link address is too far for the stub.
>
> > +#endif
> > +
> > __REF
> >
> > SYM_CODE_START(kernel_entry) # kernel entry point
> > diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h
> > new file mode 100644
> > index 000000000000..c901ebb903f2
> > --- /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_memchr = memchr;
> > +__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_strrchr = strrchr;
> > +__efistub_kernel_entry = kernel_entry;
> > +__efistub_kernel_asize = kernel_asize;
> > +__efistub_kernel_fsize = kernel_fsize;
> > +__efistub_kernel_offset = kernel_offset;
> > +__efistub_screen_info = screen_info;
> > +
> > +#endif
> > +
> > +#endif /* __LOONGARCH_KERNEL_IMAGE_VARS_H */
> > diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
> > index 23ee293e1cd2..f938aae3e92c 100644
> > --- a/arch/loongarch/kernel/setup.c
> > +++ b/arch/loongarch/kernel/setup.c
> > @@ -49,9 +49,7 @@
> > #define SMBIOS_CORE_PACKAGE_OFFSET 0x23
> > #define LOONGSON_EFI_ENABLE (1 << 3)
> >
> > -#ifdef CONFIG_VT
> > -struct screen_info screen_info;
> > -#endif
> > +struct screen_info screen_info __section(".data");
> >
> > unsigned long fw_arg0, fw_arg1;
> > DEFINE_PER_CPU(unsigned long, kernelsp);
> > @@ -122,16 +120,9 @@ static void __init parse_cpu_table(const struct dmi_header *dm)
> >
> > static void __init parse_bios_table(const struct dmi_header *dm)
> > {
> > - int bios_extern;
> > char *dmi_data = (char *)dm;
> >
> > - bios_extern = *(dmi_data + SMBIOS_BIOSEXTERN_OFFSET);
> > b_info.bios_size = (*(dmi_data + SMBIOS_BIOSSIZE_OFFSET) + 1) << 6;
> > -
> > - if (bios_extern & LOONGSON_EFI_ENABLE)
> > - set_bit(EFI_BOOT, &efi.flags);
> > - else
> > - clear_bit(EFI_BOOT, &efi.flags);
> > }
> >
>
> Why is this taken from the SMBIOS data?
This is removing obsolete code. Before we use generic stub, we use
SMBIOS as an indication whether we have efi support.
>
> > static void __init find_tokens(const struct dmi_header *dm, void *dummy)
> > @@ -145,6 +136,7 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
> > break;
> > }
> > }
> > +
> > static void __init smbios_parse(void)
> > {
> > b_info.bios_vendor = (void *)dmi_get_system_info(DMI_BIOS_VENDOR);
> > diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
> > index 69c76f26c1c5..36d042739f3c 100644
> > --- a/arch/loongarch/kernel/vmlinux.lds.S
> > +++ b/arch/loongarch/kernel/vmlinux.lds.S
> > @@ -12,6 +12,7 @@
> > #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
> > diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
> > index 6cb7384ad2ac..cbf1c55dc224 100644
> > --- a/drivers/firmware/efi/Kconfig
> > +++ b/drivers/firmware/efi/Kconfig
> > @@ -107,7 +107,7 @@ config EFI_GENERIC_STUB
> >
> > config EFI_ARMSTUB_DTB_LOADER
> > bool "Enable the DTB loader"
> > - depends on EFI_GENERIC_STUB && !RISCV
> > + depends on EFI_GENERIC_STUB && !RISCV && !LOONGARCH
> > default y
> > help
> > Select this config option to add support for the dtb= command
> > @@ -124,7 +124,7 @@ 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 !RISCV && !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..1588c61939e7 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
> >
> > @@ -70,6 +72,8 @@ 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/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
> > index f515394cce6e..efb9219d8d49 100644
> > --- a/drivers/firmware/efi/libstub/efi-stub.c
> > +++ b/drivers/firmware/efi/libstub/efi-stub.c
> > @@ -40,14 +40,19 @@
> >
> > #ifdef CONFIG_ARM64
> > # define EFI_RT_VIRTUAL_LIMIT DEFAULT_MAP_WINDOW_64
> > -#elif defined(CONFIG_RISCV)
> > +#elif defined(CONFIG_RISCV) || defined(CONFIG_LOONGARCH)
> > # define EFI_RT_VIRTUAL_LIMIT TASK_SIZE_MIN
> > -#else
> > +#else /* Only if TASK_SIZE is a constant */
> > # define EFI_RT_VIRTUAL_LIMIT TASK_SIZE
> > #endif
> >
> > +/*
> > + * 0: No flat mapping
> > + * 1: Flat mapping that VA = PA
> > + * 2: Flat mapping that VA = PA + PAGE_OFFSET
> > + */
> > +static int flat_va_mapping;
> > static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
> > -static bool flat_va_mapping;
> >
>
> Can we change this around a bit?
>
> static bool flat_va_mapping = __is_defined(EFI_RT_FIXED_VIRTUAL_OFFSET);
>
> #ifndef EFI_RT_FIXED_VIRTUAL_OFFSET
> #define EFI_RT_FIXED_VIRTUAL_OFFSET 0
> #endif
>
> Then, in your arch's asm/efi.h, you can add
>
> #define EFI_RT_FIXED_VIRTUAL_OFFSET PAGE_OFFSET
Good idea, I will change to use the new method and send V3 asap.
Huacai
>
> ...
> > @@ -254,9 +260,11 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
> > * The easiest way to achieve that is to simply use a 1:1 mapping.
> > */
> > prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID);
> > - flat_va_mapping = prop_tbl &&
> > - (prop_tbl->memory_protection_attribute &
> > - EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
> > + attrib = prop_tbl ? prop_tbl->memory_protection_attribute : 0;
> > + if (attrib & EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
> > + flat_va_mapping = 1;
> > + if (IS_ENABLED(CONFIG_LOONGARCH))
> > + flat_va_mapping = 2;
> >
>
> Keep the original code but change it into
>
> flat_va_mapping |= ....
>
> (and drop the rest of the change)
>
> > /* force efi_novamap if SetVirtualAddressMap() is unsupported */
> > efi_novamap |= !(get_supported_rt_services() &
> > @@ -338,7 +346,16 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
> > paddr = in->phys_addr;
> > size = in->num_pages * EFI_PAGE_SIZE;
> >
> > - in->virt_addr = in->phys_addr;
>
> Change this into
>
> in->virt_addr = in->phys_addr + EFI_RT_FIXED_VIRTUAL_OFFSET;
>
> > + switch (flat_va_mapping) {
> > + case 1:
> > + in->virt_addr = in->phys_addr;
> > + break;
> > + case 2:
> > + in->virt_addr = in->phys_addr + PAGE_OFFSET;
> > + break;
> > + default:
> > + in->virt_addr = in->phys_addr;
> > + }
>
> And drop the switch
>
> > if (efi_novamap) {
> > continue;
> > }
> > diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c
> > new file mode 100644
> > index 000000000000..b7ef8d2df59e
> > --- /dev/null
> > +++ b/drivers/firmware/efi/libstub/loongarch-stub.c
> > @@ -0,0 +1,60 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Author: Yun Liu <[email protected]>
> > + * Huacai Chen <[email protected]>
> > + * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
> > + */
> > +
> > +#include <asm/efi.h>
> > +#include <asm/addrspace.h>
> > +#include "efistub.h"
> > +
> > +typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long fdt);
> > +
> > +extern int kernel_asize;
> > +extern int kernel_fsize;
> > +extern int kernel_offset;
> > +extern kernel_entry_t kernel_entry;
> > +
> > +efi_status_t check_platform_features(void)
> > +{
> > + return EFI_SUCCESS;
> > +}
> > +
> > +efi_status_t handle_kernel_image(unsigned long *image_addr,
> > + unsigned long *image_size,
> > + unsigned long *reserve_addr,
> > + unsigned long *reserve_size,
> > + efi_loaded_image_t *image,
> > + efi_handle_t image_handle)
> > +{
> > + efi_status_t status;
> > + unsigned long kernel_addr = 0;
> > +
> > + kernel_addr = (unsigned long)&kernel_offset - kernel_offset;
> > +
> > + status = efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize,
> > + PHYSADDR(VMLINUX_LOAD_ADDRESS), SZ_2M, 0x0);
> > +
> > + *image_addr = kernel_addr;
> > + *image_size = kernel_asize;
> > +
> > + return status;
> > +}
> > +
> > +void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt, unsigned long fdt_size)
> > +{
> > + kernel_entry_t real_kernel_entry;
> > +
> > + /* Config Direct Mapping */
> > + csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
> > + csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
> > +
> > + real_kernel_entry = (kernel_entry_t)
> > + ((unsigned long)&kernel_entry - entrypoint + VMLINUX_LOAD_ADDRESS);
> > +
> > + if (!efi_novamap)
> > + real_kernel_entry(true, fdt);
> > + else
> > + real_kernel_entry(false, fdt);
> > +}
> > diff --git a/include/linux/pe.h b/include/linux/pe.h
> > index daf09ffffe38..1d3836ef9d92 100644
> > --- a/include/linux/pe.h
> > +++ b/include/linux/pe.h
> > @@ -65,6 +65,8 @@
> > #define IMAGE_FILE_MACHINE_SH5 0x01a8
> > #define IMAGE_FILE_MACHINE_THUMB 0x01c2
> > #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169
> > +#define IMAGE_FILE_MACHINE_LOONGARCH32 0x6232
> > +#define IMAGE_FILE_MACHINE_LOONGARCH64 0x6264
> >
> > /* flags */
> > #define IMAGE_FILE_RELOCS_STRIPPED 0x0001
>
> This is looking really good now! Thanks for taking my feedback so seriously.
>
> We will have to figure out how to queue this up, given that I intend
> to queue the generic EFI zboot changes for v6.1 as well.