]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/pe.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / boot / efi / pe.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /*
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * Copyright (C) 2015 Kay Sievers <kay@vrfy.org>
14 */
15
16 #include <efi.h>
17 #include <efilib.h>
18
19 #include "pe.h"
20 #include "util.h"
21
22 struct DosFileHeader {
23 UINT8 Magic[2];
24 UINT16 LastSize;
25 UINT16 nBlocks;
26 UINT16 nReloc;
27 UINT16 HdrSize;
28 UINT16 MinAlloc;
29 UINT16 MaxAlloc;
30 UINT16 ss;
31 UINT16 sp;
32 UINT16 Checksum;
33 UINT16 ip;
34 UINT16 cs;
35 UINT16 RelocPos;
36 UINT16 nOverlay;
37 UINT16 reserved[4];
38 UINT16 OEMId;
39 UINT16 OEMInfo;
40 UINT16 reserved2[10];
41 UINT32 ExeHeader;
42 } __attribute__((packed));
43
44 #define PE_HEADER_MACHINE_I386 0x014c
45 #define PE_HEADER_MACHINE_X64 0x8664
46 struct PeFileHeader {
47 UINT16 Machine;
48 UINT16 NumberOfSections;
49 UINT32 TimeDateStamp;
50 UINT32 PointerToSymbolTable;
51 UINT32 NumberOfSymbols;
52 UINT16 SizeOfOptionalHeader;
53 UINT16 Characteristics;
54 } __attribute__((packed));
55
56 struct PeHeader {
57 UINT8 Magic[4];
58 struct PeFileHeader FileHeader;
59 } __attribute__((packed));
60
61 struct PeSectionHeader {
62 UINT8 Name[8];
63 UINT32 VirtualSize;
64 UINT32 VirtualAddress;
65 UINT32 SizeOfRawData;
66 UINT32 PointerToRawData;
67 UINT32 PointerToRelocations;
68 UINT32 PointerToLinenumbers;
69 UINT16 NumberOfRelocations;
70 UINT16 NumberOfLinenumbers;
71 UINT32 Characteristics;
72 } __attribute__((packed));
73
74 EFI_STATUS pe_memory_locate_sections(CHAR8 *base, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
75 struct DosFileHeader *dos;
76 struct PeHeader *pe;
77 UINTN i;
78 UINTN offset;
79
80 dos = (struct DosFileHeader *)base;
81
82 if (CompareMem(dos->Magic, "MZ", 2) != 0)
83 return EFI_LOAD_ERROR;
84
85 pe = (struct PeHeader *)&base[dos->ExeHeader];
86 if (CompareMem(pe->Magic, "PE\0\0", 4) != 0)
87 return EFI_LOAD_ERROR;
88
89 /* PE32+ Subsystem type */
90 if (pe->FileHeader.Machine != PE_HEADER_MACHINE_X64 &&
91 pe->FileHeader.Machine != PE_HEADER_MACHINE_I386)
92 return EFI_LOAD_ERROR;
93
94 if (pe->FileHeader.NumberOfSections > 96)
95 return EFI_LOAD_ERROR;
96
97 offset = dos->ExeHeader + sizeof(*pe) + pe->FileHeader.SizeOfOptionalHeader;
98
99 for (i = 0; i < pe->FileHeader.NumberOfSections; i++) {
100 struct PeSectionHeader *sect;
101 UINTN j;
102
103 sect = (struct PeSectionHeader *)&base[offset];
104 for (j = 0; sections[j]; j++) {
105 if (CompareMem(sect->Name, sections[j], strlena(sections[j])) != 0)
106 continue;
107
108 if (addrs)
109 addrs[j] = (UINTN)sect->VirtualAddress;
110 if (offsets)
111 offsets[j] = (UINTN)sect->PointerToRawData;
112 if (sizes)
113 sizes[j] = (UINTN)sect->VirtualSize;
114 }
115 offset += sizeof(*sect);
116 }
117
118 return EFI_SUCCESS;
119 }
120
121 EFI_STATUS pe_file_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
122 EFI_FILE_HANDLE handle;
123 struct DosFileHeader dos;
124 struct PeHeader pe;
125 UINTN len;
126 UINTN headerlen;
127 EFI_STATUS err;
128 CHAR8 *header = NULL;
129
130 err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL);
131 if (EFI_ERROR(err))
132 return err;
133
134 /* MS-DOS stub */
135 len = sizeof(dos);
136 err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos);
137 if (EFI_ERROR(err))
138 goto out;
139 if (len != sizeof(dos)) {
140 err = EFI_LOAD_ERROR;
141 goto out;
142 }
143
144 err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader);
145 if (EFI_ERROR(err))
146 goto out;
147
148 len = sizeof(pe);
149 err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe);
150 if (EFI_ERROR(err))
151 goto out;
152 if (len != sizeof(pe)) {
153 err = EFI_LOAD_ERROR;
154 goto out;
155 }
156
157 headerlen = sizeof(dos) + sizeof(pe) + pe.FileHeader.SizeOfOptionalHeader + pe.FileHeader.NumberOfSections * sizeof(struct PeSectionHeader);
158 header = AllocatePool(headerlen);
159 if (!header) {
160 err = EFI_OUT_OF_RESOURCES;
161 goto out;
162 }
163 len = headerlen;
164 err = uefi_call_wrapper(handle->SetPosition, 2, handle, 0);
165 if (EFI_ERROR(err))
166 goto out;
167
168 err = uefi_call_wrapper(handle->Read, 3, handle, &len, header);
169 if (EFI_ERROR(err)) {
170 goto out;
171 }
172 if (len != headerlen) {
173 err = EFI_LOAD_ERROR;
174 goto out;
175 }
176
177 err = pe_memory_locate_sections(header, sections, addrs, offsets, sizes);
178 out:
179 if (header)
180 FreePool(header);
181 uefi_call_wrapper(handle->Close, 1, handle);
182 return err;
183 }