Skip to content

Commit cb7d2dd

Browse files
atishp04palmer-dabbelt
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] [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 <[email protected]> Reviewed-by: Anup Patel <[email protected]> Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent e8dcb61 commit cb7d2dd

File tree

5 files changed

+212
-2
lines changed

5 files changed

+212
-2
lines changed

arch/riscv/include/asm/sections.h

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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 */

arch/riscv/kernel/efi-header.S

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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

arch/riscv/kernel/head.S

+16
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <asm/csr.h>
1313
#include <asm/hwcap.h>
1414
#include <asm/image.h>
15+
#include "efi-header.S"
1516

1617
__HEAD
1718
ENTRY(_start)
@@ -21,10 +22,18 @@ ENTRY(_start)
2122
* Do not modify it without modifying the structure and all bootloaders
2223
* that expects this header format!!
2324
*/
25+
#ifdef CONFIG_EFI
26+
/*
27+
* This instruction decodes to "MZ" ASCII required by UEFI.
28+
*/
29+
c.li s4,-13
30+
j _start_kernel
31+
#else
2432
/* jump to start kernel */
2533
j _start_kernel
2634
/* reserved */
2735
.word 0
36+
#endif
2837
.balign 8
2938
#if __riscv_xlen == 64
3039
/* Image load offset(2MB) from start of RAM */
@@ -42,7 +51,14 @@ ENTRY(_start)
4251
.ascii RISCV_IMAGE_MAGIC
4352
.balign 4
4453
.ascii RISCV_IMAGE_MAGIC2
54+
#ifdef CONFIG_EFI
55+
.word pe_head_start - _start
56+
pe_head_start:
57+
58+
__EFI_PE_HEADER
59+
#else
4560
.word 0
61+
#endif
4662

4763
.align 2
4864
#ifdef CONFIG_MMU

arch/riscv/kernel/image-vars.h

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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 */

arch/riscv/kernel/vmlinux.lds.S

+21-2
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@
1010
#include <asm/cache.h>
1111
#include <asm/thread_info.h>
1212
#include <asm/set_memory.h>
13+
#include "image-vars.h"
1314

1415
#include <linux/sizes.h>
1516
OUTPUT_ARCH(riscv)
1617
ENTRY(_start)
1718

1819
jiffies = jiffies_64;
1920

21+
PECOFF_SECTION_ALIGNMENT = 0x1000;
22+
PECOFF_FILE_ALIGNMENT = 0x200;
23+
2024
SECTIONS
2125
{
2226
/* Beginning of code and text segment */
@@ -67,6 +71,11 @@ SECTIONS
6771
_etext = .;
6872
}
6973

74+
#ifdef CONFIG_EFI
75+
. = ALIGN(PECOFF_SECTION_ALIGNMENT);
76+
__pecoff_text_end = .;
77+
#endif
78+
7079
/* Start of data section */
7180
_sdata = .;
7281
RO_DATA(SECTION_ALIGN)
@@ -83,16 +92,26 @@ SECTIONS
8392
.sdata : {
8493
__global_pointer$ = . + 0x800;
8594
*(.sdata*)
86-
/* End of data section */
87-
_edata = .;
8895
}
8996

97+
#ifdef CONFIG_EFI
98+
.pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); }
99+
__pecoff_data_raw_size = ABSOLUTE(. - __pecoff_text_end);
100+
#endif
101+
102+
/* End of data section */
103+
_edata = .;
104+
90105
BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 0)
91106

92107
.rel.dyn : {
93108
*(.rel.dyn*)
94109
}
95110

111+
#ifdef CONFIG_EFI
112+
. = ALIGN(PECOFF_SECTION_ALIGNMENT);
113+
__pecoff_data_virt_size = ABSOLUTE(. - __pecoff_text_end);
114+
#endif
96115
_end = .;
97116

98117
STABS_DEBUG

0 commit comments

Comments
 (0)