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