1/*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// Refer to https://llvm.org/doxygen/Object_2COFF_8h_source.html and Microsoft Portable Executable
18// and Common Object File Format Specification for more detail.
19
20// See https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types
21#define IMAGE_FILE_MACHINE_RISCV64 0x5064
22
23// See https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#characteristics
24#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
25
26// See https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-image-only
27#define PE32_PLUS_HEADER_MAGIC 0x020b
28
29// See https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#windows-subsystem
30#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
31
32.macro DATA_DIRECTORY name
33\name\()_data_directory:
34  .long 0  // support::ulittle32_t RelativeVirtualAddress;
35  .long 0  // support::ulittle32_t Size;
36.endm
37
38.section .efi_header,"a"
39.global dos_header
40
41// MS-DOS Stub
42dos_header:
43  .short 0x5a4d    // Magic 'MZ'
44  .short 0         // support::ulittle16_t UsedBytesInTheLastPage;
45  .short 0         // support::ulittle16_t FileSizeInPages;
46  .short 0         // support::ulittle16_t NumberOfRelocationItems;
47  .short 0         // support::ulittle16_t HeaderSizeInParagraphs;
48  .short 0         // support::ulittle16_t MinimumExtraParagraphs;
49  .short 0         // support::ulittle16_t MaximumExtraParagraphs;
50  .short 0         // support::ulittle16_t InitialRelativeSS;
51  .short 0         // support::ulittle16_t InitialSP;
52  .short 0         // support::ulittle16_t Checksum;
53  .short 0         // support::ulittle16_t InitialIP;
54  .short 0         // support::ulittle16_t InitialRelativeCS;
55  .short 0         // support::ulittle16_t AddressOfRelocationTable;
56  .short 0         // support::ulittle16_t OverlayNumber;
57  .skip 2*4        // support::ulittle16_t Reserved[4];
58  .short 0         // support::ulittle16_t OEMid;
59  .short 0         // support::ulittle16_t OEMinfo;
60  .skip 2*10       // support::ulittle16_t Reserved2[10];
61  // Even though we fixed `dos_header` at 0x00, we still need to subtract it to
62  // indicate this is relative offset. Otherwise linker complains about referencing
63  // an absolute address when linking with `-fPIE` (position independent executable)
64  .long signature - dos_header  // support::ulittle32_t AddressOfNewExeHeader;
65
66// Signature
67signature:
68  .long 0x00004550  // "PE\0\0"
69
70// COFF File Header
71coff_file_header:
72  .short IMAGE_FILE_MACHINE_RISCV64            // support::ulittle16_t Machine;
73   // ".reloc" and ".text"
74  .short 2                                     // support::ulittle16_t NumberOfSections;
75  .long 0                                      // support::ulittle32_t TimeDateStamp;
76  .long 0                                      // support::ulittle32_t PointerToSymbolTable;
77  .long 0                                      // support::ulittle32_t NumberOfSymbols;
78  .short section_table_start - pe32plus_header // support::ulittle16_t SizeOfOptionalHeader;
79  .short IMAGE_FILE_EXECUTABLE_IMAGE           // support::ulittle16_t Characteristics;
80
81// PE32+ Optional Header
82pe32plus_header:
83  .short PE32_PLUS_HEADER_MAGIC           // support::ulittle16_t Magic;
84  .byte 0                                 // uint8_t MajorLinkerVersion;
85  .byte 0                                 // uint8_t MinorLinkerVersion;
86  .long _end - dos_header                 // support::ulittle32_t SizeOfCode;
87  .long 0                                 // support::ulittle32_t SizeOfInitializedData;
88  .long 0                                 // support::ulittle32_t SizeOfUninitializedData;
89  .long _start - dos_header               // support::ulittle32_t AddressOfEntryPoint;
90  .long dos_header - dos_header           // support::ulittle32_t BaseOfCode;
91  .quad 0                                 // support::ulittle64_t ImageBase;
92  .long 512                               // support::ulittle32_t SectionAlignment;
93  .long 512                               // support::ulittle32_t FileAlignment;
94  .short 0                                // support::ulittle16_t MajorOperatingSystemVersion;
95  .short 0                                // support::ulittle16_t MinorOperatingSystemVersion;
96  .short 0                                // support::ulittle16_t MajorImageVersion;
97  .short 0                                // support::ulittle16_t MinorImageVersion;
98  .short 0                                // support::ulittle16_t MajorSubsystemVersion;
99  .short 0                                // support::ulittle16_t MinorSubsystemVersion;
100  .long 0                                 // support::ulittle32_t Win32VersionValue;
101  .long _end - dos_header                 // support::ulittle32_t SizeOfImage;
102  .long end_of_header - dos_header        // support::ulittle32_t SizeOfHeaders;
103  .long 0                                 // support::ulittle32_t CheckSum;
104  .short IMAGE_SUBSYSTEM_EFI_APPLICATION  // support::ulittle16_t Subsystem;
105  .short 0                                // support::ulittle16_t DLLCharacteristics;
106  .quad 0                                 // support::ulittle64_t SizeOfStackReserve;
107  .quad 0                                 // support::ulittle64_t SizeOfStackCommit;
108  .quad 0                                 // support::ulittle64_t SizeOfHeapReserve;
109  .quad 0                                 // support::ulittle64_t SizeOfHeapCommit;
110  .long 0                                 // support::ulittle32_t LoaderFlags;
111  // 16 data directories in total
112  .long 16                                // support::ulittle32_t NumberOfRvaAndSize;
113
114  // The following are data directories mostly for place holder purpose for now. Entries
115  // such as certification_table might be needed for secure boot in the future.
116  DATA_DIRECTORY export_table
117  DATA_DIRECTORY import_table
118  DATA_DIRECTORY resource_table
119  DATA_DIRECTORY exception_table
120  DATA_DIRECTORY certification_table
121  DATA_DIRECTORY base_relocation_table
122  DATA_DIRECTORY debug
123  DATA_DIRECTORY architecture_data
124  DATA_DIRECTORY global_ptr
125  DATA_DIRECTORY tls_table
126  DATA_DIRECTORY load_config_table
127  DATA_DIRECTORY bound_inport
128  DATA_DIRECTORY import_address_table
129  DATA_DIRECTORY delay_import_descriptor
130  DATA_DIRECTORY CLR_runtime_header
131  .quad 0
132
133// Section Table
134section_table_start:
135// .reloc. May be expected by some PE32+ loader
136reloc_section:
137  .ascii  ".reloc"
138  .byte 0
139  .byte 0           // 8 bytes of `char Name[COFF::NameSize];`
140  .long 0           // support::ulittle32_t VirtualSize;
141  .long 0           // support::ulittle32_t VirtualAddress;
142  .long 0           // support::ulittle32_t SizeOfRawData;
143  .long 0           // support::ulittle32_t PointerToRawData;
144  .long 0           // support::ulittle32_t PointerToRelocations;
145  .long 0           // support::ulittle32_t PointerToLinenumbers;
146  .short 0          // support::ulittle16_t NumberOfRelocations;
147  .short 0          // support::ulittle16_t NumberOfLinenumbers;
148  // https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-flags
149  // We use the same value as Clang would generate with "-Wl,/subsystem:efi_application"
150  // IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE |
151  // IMAGE_SCN_MEM_READ
152  .long 0x42000040  // support::ulittle32_t Characteristics;
153
154// .text
155text_section:
156  .ascii  ".text"
157  .byte  0
158  .byte  0
159  .byte  0                          // 8 bytes of `char Name[COFF::NameSize];`
160  .long _end - end_of_header        // support::ulittle32_t VirtualSize;
161  .long end_of_header - dos_header  // support::ulittle32_t VirtualAddress;
162  .long _end - end_of_header        // support::ulittle32_t SizeOfRawData;
163  .long end_of_header - dos_header  // support::ulittle32_t PointerToRawData;
164  .long 0                           // support::ulittle32_t PointerToRelocations;
165  .long 0                           // support::ulittle32_t PointerToLinenumbers;
166  .short 0                          // support::ulittle16_t NumberOfRelocations;
167  .short 0                          // support::ulittle16_t NumberOfLinenumbers;
168  // IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA |
169  // IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
170  // We use the same value as Clang would generate with "-Wl,/subsystem:efi_application"
171  .long 0x60000020                  // support::ulittle32_t Characteristics;
172
173end_of_header:
174
175// Traditionally, PE/COFF header occupies the entire first page. We keep this pattern.
176.align 9
177
178_start:
179  // Behave like a function call.
180  addi sp, sp, -8*3
181  sd ra, 0(sp)
182  sd t0, 8(sp)
183  sd t1, 16(sp)
184
185  // Save the EFI image handle from a0
186  mv t0, a0
187  // Save the EFI system table from a1
188  mv t1, a1
189
190  // Get the program load address (same as dos_header), and .dynamic section address.
191  lla a0, dos_header
192  lla a1, _DYNAMIC
193  // Apply relocation fixup
194  call ApplyRelocationHangIfFail
195
196  // Now call efi_main.
197  mv a0, t0
198  mv a1, t1
199  call efi_main
200
201  // Prepare to return.
202  ld ra, 0(sp)
203  ld t0, 8(sp)
204  ld t1, 16(sp)
205  add sp, sp, 8*3
206  ret
207