RISC-V: Add PE/COFF header for EFI stub

Linux kernel Image can appear as an EFI application With appropriate
PE/COFF header fields in the beginning of the Image header. An EFI
application loader can directly load a Linux kernel Image and an EFI
stub residing in kernel can boot Linux kernel directly.

Add the necessary PE/COFF header.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Link: https://lore.kernel.org/r/20200421033336.9663-3-atish.patra@wdc.com
[ardb: - use C prefix for c.li to ensure the expected opcode is emitted
- align all image sections according to PE/COFF section alignment ]
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>

authored by Atish Patra and committed by Palmer Dabbelt cb7d2dd5 e8dcb61f

+212 -2
+13
arch/riscv/include/asm/sections.h
···
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2020 Western Digital Corporation or its affiliates. 4 + */ 5 + #ifndef __ASM_SECTIONS_H 6 + #define __ASM_SECTIONS_H 7 + 8 + #include <asm-generic/sections.h> 9 + 10 + extern char _start[]; 11 + extern char _start_kernel[]; 12 + 13 + #endif /* __ASM_SECTIONS_H */
+111
arch/riscv/kernel/efi-header.S
···
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2020 Western Digital Corporation or its affiliates. 4 + * Adapted from arch/arm64/kernel/efi-header.S 5 + */ 6 + 7 + #include <linux/pe.h> 8 + #include <linux/sizes.h> 9 + 10 + .macro __EFI_PE_HEADER 11 + .long PE_MAGIC 12 + coff_header: 13 + #ifdef CONFIG_64BIT 14 + .short IMAGE_FILE_MACHINE_RISCV64 // Machine 15 + #else 16 + .short IMAGE_FILE_MACHINE_RISCV32 // Machine 17 + #endif 18 + .short section_count // NumberOfSections 19 + .long 0 // TimeDateStamp 20 + .long 0 // PointerToSymbolTable 21 + .long 0 // NumberOfSymbols 22 + .short section_table - optional_header // SizeOfOptionalHeader 23 + .short IMAGE_FILE_DEBUG_STRIPPED | \ 24 + IMAGE_FILE_EXECUTABLE_IMAGE | \ 25 + IMAGE_FILE_LINE_NUMS_STRIPPED // Characteristics 26 + 27 + optional_header: 28 + #ifdef CONFIG_64BIT 29 + .short PE_OPT_MAGIC_PE32PLUS // PE32+ format 30 + #else 31 + .short PE_OPT_MAGIC_PE32 // PE32 format 32 + #endif 33 + .byte 0x02 // MajorLinkerVersion 34 + .byte 0x14 // MinorLinkerVersion 35 + .long __pecoff_text_end - efi_header_end // SizeOfCode 36 + .long __pecoff_data_virt_size // SizeOfInitializedData 37 + .long 0 // SizeOfUninitializedData 38 + .long __efistub_efi_pe_entry - _start // AddressOfEntryPoint 39 + .long efi_header_end - _start // BaseOfCode 40 + #ifdef CONFIG_32BIT 41 + .long __pecoff_text_end - _start // BaseOfData 42 + #endif 43 + 44 + extra_header_fields: 45 + .quad 0 // ImageBase 46 + .long PECOFF_SECTION_ALIGNMENT // SectionAlignment 47 + .long PECOFF_FILE_ALIGNMENT // FileAlignment 48 + .short 0 // MajorOperatingSystemVersion 49 + .short 0 // MinorOperatingSystemVersion 50 + .short LINUX_EFISTUB_MAJOR_VERSION // MajorImageVersion 51 + .short LINUX_EFISTUB_MINOR_VERSION // MinorImageVersion 52 + .short 0 // MajorSubsystemVersion 53 + .short 0 // MinorSubsystemVersion 54 + .long 0 // Win32VersionValue 55 + 56 + .long _end - _start // SizeOfImage 57 + 58 + // Everything before the kernel image is considered part of the header 59 + .long efi_header_end - _start // SizeOfHeaders 60 + .long 0 // CheckSum 61 + .short IMAGE_SUBSYSTEM_EFI_APPLICATION // Subsystem 62 + .short 0 // DllCharacteristics 63 + .quad 0 // SizeOfStackReserve 64 + .quad 0 // SizeOfStackCommit 65 + .quad 0 // SizeOfHeapReserve 66 + .quad 0 // SizeOfHeapCommit 67 + .long 0 // LoaderFlags 68 + .long (section_table - .) / 8 // NumberOfRvaAndSizes 69 + 70 + .quad 0 // ExportTable 71 + .quad 0 // ImportTable 72 + .quad 0 // ResourceTable 73 + .quad 0 // ExceptionTable 74 + .quad 0 // CertificationTable 75 + .quad 0 // BaseRelocationTable 76 + 77 + // Section table 78 + section_table: 79 + .ascii ".text\0\0\0" 80 + .long __pecoff_text_end - efi_header_end // VirtualSize 81 + .long efi_header_end - _start // VirtualAddress 82 + .long __pecoff_text_end - efi_header_end // SizeOfRawData 83 + .long efi_header_end - _start // PointerToRawData 84 + 85 + .long 0 // PointerToRelocations 86 + .long 0 // PointerToLineNumbers 87 + .short 0 // NumberOfRelocations 88 + .short 0 // NumberOfLineNumbers 89 + .long IMAGE_SCN_CNT_CODE | \ 90 + IMAGE_SCN_MEM_READ | \ 91 + IMAGE_SCN_MEM_EXECUTE // Characteristics 92 + 93 + .ascii ".data\0\0\0" 94 + .long __pecoff_data_virt_size // VirtualSize 95 + .long __pecoff_text_end - _start // VirtualAddress 96 + .long __pecoff_data_raw_size // SizeOfRawData 97 + .long __pecoff_text_end - _start // PointerToRawData 98 + 99 + .long 0 // PointerToRelocations 100 + .long 0 // PointerToLineNumbers 101 + .short 0 // NumberOfRelocations 102 + .short 0 // NumberOfLineNumbers 103 + .long IMAGE_SCN_CNT_INITIALIZED_DATA | \ 104 + IMAGE_SCN_MEM_READ | \ 105 + IMAGE_SCN_MEM_WRITE // Characteristics 106 + 107 + .set section_count, (. - section_table) / 40 108 + 109 + .balign 0x1000 110 + efi_header_end: 111 + .endm
+16
arch/riscv/kernel/head.S
··· 12 #include <asm/csr.h> 13 #include <asm/hwcap.h> 14 #include <asm/image.h> 15 16 __HEAD 17 ENTRY(_start) ··· 22 * Do not modify it without modifying the structure and all bootloaders 23 * that expects this header format!! 24 */ 25 /* jump to start kernel */ 26 j _start_kernel 27 /* reserved */ 28 .word 0 29 .balign 8 30 #if __riscv_xlen == 64 31 /* Image load offset(2MB) from start of RAM */ ··· 51 .ascii RISCV_IMAGE_MAGIC 52 .balign 4 53 .ascii RISCV_IMAGE_MAGIC2 54 .word 0 55 56 .align 2 57 #ifdef CONFIG_MMU
··· 12 #include <asm/csr.h> 13 #include <asm/hwcap.h> 14 #include <asm/image.h> 15 + #include "efi-header.S" 16 17 __HEAD 18 ENTRY(_start) ··· 21 * Do not modify it without modifying the structure and all bootloaders 22 * that expects this header format!! 23 */ 24 + #ifdef CONFIG_EFI 25 + /* 26 + * This instruction decodes to "MZ" ASCII required by UEFI. 27 + */ 28 + c.li s4,-13 29 + j _start_kernel 30 + #else 31 /* jump to start kernel */ 32 j _start_kernel 33 /* reserved */ 34 .word 0 35 + #endif 36 .balign 8 37 #if __riscv_xlen == 64 38 /* Image load offset(2MB) from start of RAM */ ··· 42 .ascii RISCV_IMAGE_MAGIC 43 .balign 4 44 .ascii RISCV_IMAGE_MAGIC2 45 + #ifdef CONFIG_EFI 46 + .word pe_head_start - _start 47 + pe_head_start: 48 + 49 + __EFI_PE_HEADER 50 + #else 51 .word 0 52 + #endif 53 54 .align 2 55 #ifdef CONFIG_MMU
+51
arch/riscv/kernel/image-vars.h
···
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2020 Western Digital Corporation or its affiliates. 4 + * Linker script variables to be set after section resolution, as 5 + * ld.lld does not like variables assigned before SECTIONS is processed. 6 + * Based on arch/arm64/kerne/image-vars.h 7 + */ 8 + #ifndef __RISCV_KERNEL_IMAGE_VARS_H 9 + #define __RISCV_KERNEL_IMAGE_VARS_H 10 + 11 + #ifndef LINKER_SCRIPT 12 + #error This file should only be included in vmlinux.lds.S 13 + #endif 14 + 15 + #ifdef CONFIG_EFI 16 + 17 + /* 18 + * The EFI stub has its own symbol namespace prefixed by __efistub_, to 19 + * isolate it from the kernel proper. The following symbols are legally 20 + * accessed by the stub, so provide some aliases to make them accessible. 21 + * Only include data symbols here, or text symbols of functions that are 22 + * guaranteed to be safe when executed at another offset than they were 23 + * linked at. The routines below are all implemented in assembler in a 24 + * position independent manner 25 + */ 26 + __efistub_memcmp = memcmp; 27 + __efistub_memchr = memchr; 28 + __efistub_memcpy = memcpy; 29 + __efistub_memmove = memmove; 30 + __efistub_memset = memset; 31 + __efistub_strlen = strlen; 32 + __efistub_strnlen = strnlen; 33 + __efistub_strcmp = strcmp; 34 + __efistub_strncmp = strncmp; 35 + __efistub_strrchr = strrchr; 36 + 37 + #ifdef CONFIG_KASAN 38 + __efistub___memcpy = memcpy; 39 + __efistub___memmove = memmove; 40 + __efistub___memset = memset; 41 + #endif 42 + 43 + __efistub__start = _start; 44 + __efistub__start_kernel = _start_kernel; 45 + __efistub__end = _end; 46 + __efistub__edata = _edata; 47 + __efistub_screen_info = screen_info; 48 + 49 + #endif 50 + 51 + #endif /* __RISCV_KERNEL_IMAGE_VARS_H */
+21 -2
arch/riscv/kernel/vmlinux.lds.S
··· 10 #include <asm/cache.h> 11 #include <asm/thread_info.h> 12 #include <asm/set_memory.h> 13 14 #include <linux/sizes.h> 15 OUTPUT_ARCH(riscv) 16 ENTRY(_start) 17 18 jiffies = jiffies_64; 19 20 SECTIONS 21 { ··· 71 _etext = .; 72 } 73 74 /* Start of data section */ 75 _sdata = .; 76 RO_DATA(SECTION_ALIGN) ··· 92 .sdata : { 93 __global_pointer$ = . + 0x800; 94 *(.sdata*) 95 - /* End of data section */ 96 - _edata = .; 97 } 98 99 BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0) 100 ··· 108 *(.rel.dyn*) 109 } 110 111 _end = .; 112 113 STABS_DEBUG
··· 10 #include <asm/cache.h> 11 #include <asm/thread_info.h> 12 #include <asm/set_memory.h> 13 + #include "image-vars.h" 14 15 #include <linux/sizes.h> 16 OUTPUT_ARCH(riscv) 17 ENTRY(_start) 18 19 jiffies = jiffies_64; 20 + 21 + PECOFF_SECTION_ALIGNMENT = 0x1000; 22 + PECOFF_FILE_ALIGNMENT = 0x200; 23 24 SECTIONS 25 { ··· 67 _etext = .; 68 } 69 70 + #ifdef CONFIG_EFI 71 + . = ALIGN(PECOFF_SECTION_ALIGNMENT); 72 + __pecoff_text_end = .; 73 + #endif 74 + 75 /* Start of data section */ 76 _sdata = .; 77 RO_DATA(SECTION_ALIGN) ··· 83 .sdata : { 84 __global_pointer$ = . + 0x800; 85 *(.sdata*) 86 } 87 + 88 + #ifdef CONFIG_EFI 89 + .pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); } 90 + __pecoff_data_raw_size = ABSOLUTE(. - __pecoff_text_end); 91 + #endif 92 + 93 + /* End of data section */ 94 + _edata = .; 95 96 BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0) 97 ··· 93 *(.rel.dyn*) 94 } 95 96 + #ifdef CONFIG_EFI 97 + . = ALIGN(PECOFF_SECTION_ALIGNMENT); 98 + __pecoff_data_virt_size = ABSOLUTE(. - __pecoff_text_end); 99 + #endif 100 _end = .; 101 102 STABS_DEBUG