EFI boot support for loongarch

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE+9lifEBpyUIVN1cpw08iOZLZjyQFAmMXEPMACgkQw08iOZLZ
 jySwXwv+LUbReZM78R3bA39fYnUU3McEcdZtRlFpoqjueZU55TTVnWyvwdCOzaFd
 ZsjoNY0NUT2AnO0kH8aXwy9uD+cHxgfl5DDhff+MuHoNOO3XTEq8leBVjRuY8Po6
 +PyjP0uszHPo8rDlz2/yIauyJ/kwrDd/ptpxPiBOvdEVRIBxVBvhQdSrfoPPX6vl
 A61SFJRIWZ5cH3ACerNiwcMyhYuybmBhx2OX4mrLh1TfzMMMv5+J4EC0hdFdapr2
 tP859NfFotUX6KySsoAuEolUNqIG0ET67DWiLrxrz9BBffs+IaTpBopFSyXAT15t
 R+sF4CLPj0K70H5dCyszzCBvrpnQE1Maumoc1ob2dbW6st1xzVnk9Flpdw1z1Eaj
 tSfBX1Pv5SKWGJQrbgTa39zCp/WIpAvtxqxSxPWrkLByWOFtn8HI/aRZIjqhimjv
 s/Hri2UhhETayrHs0DapPrN5M5oZ3qHgSsuPDCG94MfDUJYvBUTUyLG9XfxNw4nD
 PgBhTrB8
 =/T5q
 -----END PGP SIGNATURE-----

Merge tag 'efi-loongarch-for-v6.1' into efi/next

EFI boot support for loongarch
This commit is contained in:
Ard Biesheuvel 2022-09-06 11:50:16 +02:00
commit 4bf2329882
15 changed files with 275 additions and 26 deletions

View File

@ -317,6 +317,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

View File

@ -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
@ -86,10 +91,10 @@ PHONY += vdso_install
vdso_install:
$(Q)$(MAKE) $(build)=arch/loongarch/vdso $@
all: $(KBUILD_IMAGE)
all: $(notdir $(KBUILD_IMAGE))
$(KBUILD_IMAGE): vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(bootvars-y) $@
vmlinux.elf vmlinux.efi: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(bootvars-y) $(boot)/$@
install:
$(Q)install -D -m 755 $(KBUILD_IMAGE) $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE)

View File

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

View File

@ -17,9 +17,16 @@ void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
#define arch_efi_call_virt_teardown()
#define EFI_ALLOC_ALIGN SZ_64K
#define EFI_RT_VIRTUAL_OFFSET CSR_DMW0_BASE
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)
{

View File

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

View File

@ -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);
}

View File

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

View File

@ -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 */

View File

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

View File

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

View File

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

View File

@ -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)) \
-fpie
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 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)

View File

@ -40,14 +40,22 @@
#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
/*
* Some architectures map the EFI regions into the kernel's linear map using a
* fixed offset.
*/
#ifndef EFI_RT_VIRTUAL_OFFSET
#define EFI_RT_VIRTUAL_OFFSET 0
#endif
static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
static bool flat_va_mapping;
static bool flat_va_mapping = (EFI_RT_VIRTUAL_OFFSET != 0);
const efi_system_table_t *efi_system_table;
@ -254,8 +262,8 @@ 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 &
flat_va_mapping |= prop_tbl &&
(prop_tbl->memory_protection_attribute &
EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
/* force efi_novamap if SetVirtualAddressMap() is unsupported */
@ -338,7 +346,7 @@ 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;
in->virt_addr = in->phys_addr + EFI_RT_VIRTUAL_OFFSET;
if (efi_novamap) {
continue;
}

View File

@ -0,0 +1,60 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Author: Yun Liu <liuyun@loongson.cn>
* Huacai Chen <chenhuacai@loongson.cn>
* 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);
}

View File

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