blob: f99978db6b6fac3f6d2ba75e4b7a3cf2ea182ebc [file] [log] [blame]
Matt Fleming291f3632011-12-12 21:27:52 +00001/* -----------------------------------------------------------------------
2 *
3 * Copyright 2011 Intel Corporation; author Matt Fleming
4 *
5 * This file is part of the Linux kernel, and is made available under
6 * the terms of the GNU General Public License version 2.
7 *
8 * ----------------------------------------------------------------------- */
9
10#include <linux/efi.h>
Matthew Garrettdd5fc852012-12-05 14:33:26 -070011#include <linux/pci.h>
Matt Fleming291f3632011-12-12 21:27:52 +000012#include <asm/efi.h>
13#include <asm/setup.h>
14#include <asm/desc.h>
15
Andrey Ryabinin393f2032015-02-13 14:39:56 -080016#include "../string.h"
Matt Fleming291f3632011-12-12 21:27:52 +000017#include "eboot.h"
18
19static efi_system_table_t *sys_table;
20
Matt Fleming84be8802014-09-23 10:37:43 +010021static struct efi_config *efi_early;
22
Ard Biesheuvel243b6752014-11-05 17:00:56 +010023__pure const struct efi_config *__efi_early(void)
24{
25 return efi_early;
26}
Matt Fleming204b0a12014-03-22 10:09:01 +000027
Matt Fleming54b52d82014-01-10 15:27:14 +000028#define BOOT_SERVICES(bits) \
29static void setup_boot_services##bits(struct efi_config *c) \
30{ \
31 efi_system_table_##bits##_t *table; \
Matt Fleming54b52d82014-01-10 15:27:14 +000032 \
33 table = (typeof(table))sys_table; \
34 \
David Howellsa2cd2f32017-02-06 11:22:40 +000035 c->runtime_services = table->runtime; \
Lukas Wunner0a637ee2016-08-22 12:01:21 +020036 c->boot_services = table->boottime; \
Matt Fleming54b52d82014-01-10 15:27:14 +000037 c->text_output = table->con_out; \
Matt Fleming54b52d82014-01-10 15:27:14 +000038}
39BOOT_SERVICES(32);
40BOOT_SERVICES(64);
41
Matt Flemingc116e8d2014-01-16 11:35:43 +000042static inline efi_status_t __open_volume32(void *__image, void **__fh)
Matt Fleming54b52d82014-01-10 15:27:14 +000043{
44 efi_file_io_interface_t *io;
Matt Flemingc116e8d2014-01-16 11:35:43 +000045 efi_loaded_image_32_t *image = __image;
46 efi_file_handle_32_t *fh;
Matt Fleming54b52d82014-01-10 15:27:14 +000047 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
48 efi_status_t status;
49 void *handle = (void *)(unsigned long)image->device_handle;
Matt Flemingc116e8d2014-01-16 11:35:43 +000050 unsigned long func;
Matt Fleming54b52d82014-01-10 15:27:14 +000051
Matt Fleming204b0a12014-03-22 10:09:01 +000052 status = efi_call_early(handle_protocol, handle,
53 &fs_proto, (void **)&io);
Matt Fleming54b52d82014-01-10 15:27:14 +000054 if (status != EFI_SUCCESS) {
55 efi_printk(sys_table, "Failed to handle fs_proto\n");
56 return status;
57 }
58
59 func = (unsigned long)io->open_volume;
60 status = efi_early->call(func, io, &fh);
61 if (status != EFI_SUCCESS)
62 efi_printk(sys_table, "Failed to open volume\n");
63
64 *__fh = fh;
65 return status;
66}
67
Matt Flemingc116e8d2014-01-16 11:35:43 +000068static inline efi_status_t __open_volume64(void *__image, void **__fh)
Matt Fleming54b52d82014-01-10 15:27:14 +000069{
Matt Flemingc116e8d2014-01-16 11:35:43 +000070 efi_file_io_interface_t *io;
71 efi_loaded_image_64_t *image = __image;
72 efi_file_handle_64_t *fh;
73 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
74 efi_status_t status;
75 void *handle = (void *)(unsigned long)image->device_handle;
76 unsigned long func;
77
Matt Fleming204b0a12014-03-22 10:09:01 +000078 status = efi_call_early(handle_protocol, handle,
79 &fs_proto, (void **)&io);
Matt Flemingc116e8d2014-01-16 11:35:43 +000080 if (status != EFI_SUCCESS) {
81 efi_printk(sys_table, "Failed to handle fs_proto\n");
82 return status;
83 }
84
85 func = (unsigned long)io->open_volume;
86 status = efi_early->call(func, io, &fh);
87 if (status != EFI_SUCCESS)
88 efi_printk(sys_table, "Failed to open volume\n");
89
90 *__fh = fh;
91 return status;
92}
93
Ard Biesheuvelbd669472014-07-02 14:54:42 +020094efi_status_t
Matt Flemingc116e8d2014-01-16 11:35:43 +000095efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
96{
97 if (efi_early->is64)
98 return __open_volume64(__image, __fh);
99
100 return __open_volume32(__image, __fh);
101}
102
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200103void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
Matt Flemingc116e8d2014-01-16 11:35:43 +0000104{
Lukas Wunnerdb4545d2017-01-31 13:21:34 +0000105 efi_call_proto(efi_simple_text_output_protocol, output_string,
106 efi_early->text_output, str);
Matt Fleming54b52d82014-01-10 15:27:14 +0000107}
Lee, Chun-Yideb94102012-12-20 19:33:22 +0800108
Matt Flemingc116e8d2014-01-16 11:35:43 +0000109static efi_status_t
110__setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom)
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700111{
Matt Flemingc116e8d2014-01-16 11:35:43 +0000112 struct pci_setup_rom *rom = NULL;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700113 efi_status_t status;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000114 unsigned long size;
115 uint64_t attributes;
116
117 status = efi_early->call(pci->attributes, pci,
118 EfiPciIoAttributeOperationGet, 0, 0,
119 &attributes);
120 if (status != EFI_SUCCESS)
121 return status;
122
123 if (!pci->romimage || !pci->romsize)
124 return EFI_INVALID_PARAMETER;
125
126 size = pci->romsize + sizeof(*rom);
127
Matt Fleming204b0a12014-03-22 10:09:01 +0000128 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
Andre Müller77e21e82014-09-10 01:00:22 +0200129 if (status != EFI_SUCCESS) {
130 efi_printk(sys_table, "Failed to alloc mem for rom\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000131 return status;
Andre Müller77e21e82014-09-10 01:00:22 +0200132 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000133
134 memset(rom, 0, sizeof(*rom));
135
136 rom->data.type = SETUP_PCI;
137 rom->data.len = size - sizeof(struct setup_data);
138 rom->data.next = 0;
139 rom->pcilen = pci->romsize;
140 *__rom = rom;
141
142 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
143 PCI_VENDOR_ID, 1, &(rom->vendor));
144
Andre Müller77e21e82014-09-10 01:00:22 +0200145 if (status != EFI_SUCCESS) {
146 efi_printk(sys_table, "Failed to read rom->vendor\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000147 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200148 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000149
150 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
151 PCI_DEVICE_ID, 1, &(rom->devid));
152
Andre Müller77e21e82014-09-10 01:00:22 +0200153 if (status != EFI_SUCCESS) {
154 efi_printk(sys_table, "Failed to read rom->devid\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000155 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200156 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000157
158 status = efi_early->call(pci->get_location, pci, &(rom->segment),
159 &(rom->bus), &(rom->device), &(rom->function));
160
161 if (status != EFI_SUCCESS)
162 goto free_struct;
163
164 memcpy(rom->romdata, pci->romimage, pci->romsize);
165 return status;
166
167free_struct:
Matt Fleming204b0a12014-03-22 10:09:01 +0000168 efi_call_early(free_pool, rom);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000169 return status;
170}
171
Matt Fleming56394ab2014-09-11 09:04:25 +0100172static void
Matt Flemingc116e8d2014-01-16 11:35:43 +0000173setup_efi_pci32(struct boot_params *params, void **pci_handle,
174 unsigned long size)
175{
176 efi_pci_io_protocol_32 *pci = NULL;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700177 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000178 u32 *handles = (u32 *)(unsigned long)pci_handle;
179 efi_status_t status;
180 unsigned long nr_pci;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700181 struct setup_data *data;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000182 int i;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700183
Jan Beulichbc754792013-01-18 12:35:14 +0000184 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700185
186 while (data && data->next)
Jan Beulichbc754792013-01-18 12:35:14 +0000187 data = (struct setup_data *)(unsigned long)data->next;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700188
Matt Flemingc116e8d2014-01-16 11:35:43 +0000189 nr_pci = size / sizeof(u32);
190 for (i = 0; i < nr_pci; i++) {
191 struct pci_setup_rom *rom = NULL;
192 u32 h = handles[i];
193
Matt Fleming204b0a12014-03-22 10:09:01 +0000194 status = efi_call_early(handle_protocol, h,
195 &pci_proto, (void **)&pci);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000196
197 if (status != EFI_SUCCESS)
198 continue;
199
200 if (!pci)
201 continue;
202
203 status = __setup_efi_pci32(pci, &rom);
204 if (status != EFI_SUCCESS)
205 continue;
206
207 if (data)
208 data->next = (unsigned long)rom;
209 else
210 params->hdr.setup_data = (unsigned long)rom;
211
212 data = (struct setup_data *)rom;
213
214 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000215}
216
217static efi_status_t
218__setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom)
219{
220 struct pci_setup_rom *rom;
221 efi_status_t status;
222 unsigned long size;
223 uint64_t attributes;
224
225 status = efi_early->call(pci->attributes, pci,
226 EfiPciIoAttributeOperationGet, 0,
227 &attributes);
228 if (status != EFI_SUCCESS)
229 return status;
230
231 if (!pci->romimage || !pci->romsize)
232 return EFI_INVALID_PARAMETER;
233
234 size = pci->romsize + sizeof(*rom);
235
Matt Fleming204b0a12014-03-22 10:09:01 +0000236 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
Andre Müller77e21e82014-09-10 01:00:22 +0200237 if (status != EFI_SUCCESS) {
238 efi_printk(sys_table, "Failed to alloc mem for rom\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000239 return status;
Andre Müller77e21e82014-09-10 01:00:22 +0200240 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000241
242 rom->data.type = SETUP_PCI;
243 rom->data.len = size - sizeof(struct setup_data);
244 rom->data.next = 0;
245 rom->pcilen = pci->romsize;
246 *__rom = rom;
247
248 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
249 PCI_VENDOR_ID, 1, &(rom->vendor));
250
Andre Müller77e21e82014-09-10 01:00:22 +0200251 if (status != EFI_SUCCESS) {
252 efi_printk(sys_table, "Failed to read rom->vendor\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000253 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200254 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000255
256 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
257 PCI_DEVICE_ID, 1, &(rom->devid));
258
Andre Müller77e21e82014-09-10 01:00:22 +0200259 if (status != EFI_SUCCESS) {
260 efi_printk(sys_table, "Failed to read rom->devid\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000261 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200262 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000263
264 status = efi_early->call(pci->get_location, pci, &(rom->segment),
265 &(rom->bus), &(rom->device), &(rom->function));
266
267 if (status != EFI_SUCCESS)
268 goto free_struct;
269
270 memcpy(rom->romdata, pci->romimage, pci->romsize);
271 return status;
272
273free_struct:
Matt Fleming204b0a12014-03-22 10:09:01 +0000274 efi_call_early(free_pool, rom);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000275 return status;
276
277}
278
Matt Fleming56394ab2014-09-11 09:04:25 +0100279static void
Matt Flemingc116e8d2014-01-16 11:35:43 +0000280setup_efi_pci64(struct boot_params *params, void **pci_handle,
281 unsigned long size)
282{
283 efi_pci_io_protocol_64 *pci = NULL;
284 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
285 u64 *handles = (u64 *)(unsigned long)pci_handle;
286 efi_status_t status;
287 unsigned long nr_pci;
288 struct setup_data *data;
289 int i;
290
291 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
292
293 while (data && data->next)
294 data = (struct setup_data *)(unsigned long)data->next;
295
296 nr_pci = size / sizeof(u64);
297 for (i = 0; i < nr_pci; i++) {
298 struct pci_setup_rom *rom = NULL;
299 u64 h = handles[i];
300
Matt Fleming204b0a12014-03-22 10:09:01 +0000301 status = efi_call_early(handle_protocol, h,
302 &pci_proto, (void **)&pci);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000303
304 if (status != EFI_SUCCESS)
305 continue;
306
307 if (!pci)
308 continue;
309
310 status = __setup_efi_pci64(pci, &rom);
311 if (status != EFI_SUCCESS)
312 continue;
313
314 if (data)
315 data->next = (unsigned long)rom;
316 else
317 params->hdr.setup_data = (unsigned long)rom;
318
319 data = (struct setup_data *)rom;
320
321 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000322}
323
Matt Fleming56394ab2014-09-11 09:04:25 +0100324/*
325 * There's no way to return an informative status from this function,
326 * because any analysis (and printing of error messages) needs to be
327 * done directly at the EFI function call-site.
328 *
329 * For example, EFI_INVALID_PARAMETER could indicate a bug or maybe we
330 * just didn't find any PCI devices, but there's no way to tell outside
331 * the context of the call.
332 */
333static void setup_efi_pci(struct boot_params *params)
Matt Flemingc116e8d2014-01-16 11:35:43 +0000334{
335 efi_status_t status;
336 void **pci_handle = NULL;
337 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
338 unsigned long size = 0;
339
Matt Fleming204b0a12014-03-22 10:09:01 +0000340 status = efi_call_early(locate_handle,
341 EFI_LOCATE_BY_PROTOCOL,
342 &pci_proto, NULL, &size, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700343
344 if (status == EFI_BUFFER_TOO_SMALL) {
Matt Fleming204b0a12014-03-22 10:09:01 +0000345 status = efi_call_early(allocate_pool,
346 EFI_LOADER_DATA,
347 size, (void **)&pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700348
Andre Müller77e21e82014-09-10 01:00:22 +0200349 if (status != EFI_SUCCESS) {
350 efi_printk(sys_table, "Failed to alloc mem for pci_handle\n");
Matt Fleming56394ab2014-09-11 09:04:25 +0100351 return;
Andre Müller77e21e82014-09-10 01:00:22 +0200352 }
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700353
Matt Fleming204b0a12014-03-22 10:09:01 +0000354 status = efi_call_early(locate_handle,
355 EFI_LOCATE_BY_PROTOCOL, &pci_proto,
356 NULL, &size, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700357 }
358
359 if (status != EFI_SUCCESS)
360 goto free_handle;
361
Matt Flemingc116e8d2014-01-16 11:35:43 +0000362 if (efi_early->is64)
Matt Fleming56394ab2014-09-11 09:04:25 +0100363 setup_efi_pci64(params, pci_handle, size);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000364 else
Matt Fleming56394ab2014-09-11 09:04:25 +0100365 setup_efi_pci32(params, pci_handle, size);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700366
367free_handle:
Matt Fleming204b0a12014-03-22 10:09:01 +0000368 efi_call_early(free_pool, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700369}
370
Lukas Wunner58c54752016-11-12 21:32:36 +0000371static void retrieve_apple_device_properties(struct boot_params *boot_params)
372{
373 efi_guid_t guid = APPLE_PROPERTIES_PROTOCOL_GUID;
374 struct setup_data *data, *new;
375 efi_status_t status;
376 u32 size = 0;
377 void *p;
378
379 status = efi_call_early(locate_protocol, &guid, NULL, &p);
380 if (status != EFI_SUCCESS)
381 return;
382
383 if (efi_table_attr(apple_properties_protocol, version, p) != 0x10000) {
384 efi_printk(sys_table, "Unsupported properties proto version\n");
385 return;
386 }
387
388 efi_call_proto(apple_properties_protocol, get_all, p, NULL, &size);
389 if (!size)
390 return;
391
392 do {
393 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
394 size + sizeof(struct setup_data), &new);
395 if (status != EFI_SUCCESS) {
396 efi_printk(sys_table,
397 "Failed to alloc mem for properties\n");
398 return;
399 }
400
401 status = efi_call_proto(apple_properties_protocol, get_all, p,
402 new->data, &size);
403
404 if (status == EFI_BUFFER_TOO_SMALL)
405 efi_call_early(free_pool, new);
406 } while (status == EFI_BUFFER_TOO_SMALL);
407
408 new->type = SETUP_APPLE_PROPERTIES;
409 new->len = size;
410 new->next = 0;
411
412 data = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
413 if (!data)
414 boot_params->hdr.setup_data = (unsigned long)new;
415 else {
416 while (data->next)
417 data = (struct setup_data *)(unsigned long)data->next;
418 data->next = (unsigned long)new;
419 }
420}
421
422static void setup_quirks(struct boot_params *boot_params)
423{
424 efi_char16_t const apple[] = { 'A', 'p', 'p', 'l', 'e', 0 };
425 efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long)
426 efi_table_attr(efi_system_table, fw_vendor, sys_table);
427
428 if (!memcmp(fw_vendor, apple, sizeof(apple))) {
429 if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
430 retrieve_apple_device_properties(boot_params);
431 }
432}
433
Matt Flemingc116e8d2014-01-16 11:35:43 +0000434static efi_status_t
435setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
Matt Fleming291f3632011-12-12 21:27:52 +0000436{
Matt Flemingc116e8d2014-01-16 11:35:43 +0000437 struct efi_uga_draw_protocol *uga = NULL, *first_uga;
438 efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
Matt Fleming291f3632011-12-12 21:27:52 +0000439 unsigned long nr_ugas;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000440 u32 *handles = (u32 *)uga_handle;;
Colin Ian Kingac0e94b2016-07-20 11:11:06 +0100441 efi_status_t status = EFI_INVALID_PARAMETER;
Matt Fleming291f3632011-12-12 21:27:52 +0000442 int i;
443
Matt Fleming291f3632011-12-12 21:27:52 +0000444 first_uga = NULL;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000445 nr_ugas = size / sizeof(u32);
Matt Fleming291f3632011-12-12 21:27:52 +0000446 for (i = 0; i < nr_ugas; i++) {
447 efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
Matt Fleming291f3632011-12-12 21:27:52 +0000448 u32 w, h, depth, refresh;
449 void *pciio;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000450 u32 handle = handles[i];
Matt Fleming291f3632011-12-12 21:27:52 +0000451
Matt Fleming204b0a12014-03-22 10:09:01 +0000452 status = efi_call_early(handle_protocol, handle,
453 &uga_proto, (void **)&uga);
Matt Fleming291f3632011-12-12 21:27:52 +0000454 if (status != EFI_SUCCESS)
455 continue;
456
Matt Fleming204b0a12014-03-22 10:09:01 +0000457 efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
Matt Fleming291f3632011-12-12 21:27:52 +0000458
Matt Fleming54b52d82014-01-10 15:27:14 +0000459 status = efi_early->call((unsigned long)uga->get_mode, uga,
460 &w, &h, &depth, &refresh);
Matt Fleming291f3632011-12-12 21:27:52 +0000461 if (status == EFI_SUCCESS && (!first_uga || pciio)) {
Matt Flemingc116e8d2014-01-16 11:35:43 +0000462 *width = w;
463 *height = h;
Matt Fleming291f3632011-12-12 21:27:52 +0000464
465 /*
466 * Once we've found a UGA supporting PCIIO,
467 * don't bother looking any further.
468 */
469 if (pciio)
470 break;
471
472 first_uga = uga;
473 }
474 }
475
Matt Flemingc116e8d2014-01-16 11:35:43 +0000476 return status;
477}
478
479static efi_status_t
480setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
481{
482 struct efi_uga_draw_protocol *uga = NULL, *first_uga;
483 efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
484 unsigned long nr_ugas;
485 u64 *handles = (u64 *)uga_handle;;
Colin Ian Kingac0e94b2016-07-20 11:11:06 +0100486 efi_status_t status = EFI_INVALID_PARAMETER;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000487 int i;
488
489 first_uga = NULL;
490 nr_ugas = size / sizeof(u64);
491 for (i = 0; i < nr_ugas; i++) {
492 efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
493 u32 w, h, depth, refresh;
494 void *pciio;
495 u64 handle = handles[i];
496
Matt Fleming204b0a12014-03-22 10:09:01 +0000497 status = efi_call_early(handle_protocol, handle,
498 &uga_proto, (void **)&uga);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000499 if (status != EFI_SUCCESS)
500 continue;
501
Matt Fleming204b0a12014-03-22 10:09:01 +0000502 efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000503
504 status = efi_early->call((unsigned long)uga->get_mode, uga,
505 &w, &h, &depth, &refresh);
506 if (status == EFI_SUCCESS && (!first_uga || pciio)) {
507 *width = w;
508 *height = h;
509
510 /*
511 * Once we've found a UGA supporting PCIIO,
512 * don't bother looking any further.
513 */
514 if (pciio)
515 break;
516
517 first_uga = uga;
518 }
519 }
520
521 return status;
522}
523
524/*
525 * See if we have Universal Graphics Adapter (UGA) protocol
526 */
527static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
528 unsigned long size)
529{
530 efi_status_t status;
531 u32 width, height;
532 void **uga_handle = NULL;
533
Matt Fleming204b0a12014-03-22 10:09:01 +0000534 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
535 size, (void **)&uga_handle);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000536 if (status != EFI_SUCCESS)
537 return status;
538
Matt Fleming204b0a12014-03-22 10:09:01 +0000539 status = efi_call_early(locate_handle,
540 EFI_LOCATE_BY_PROTOCOL,
541 uga_proto, NULL, &size, uga_handle);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000542 if (status != EFI_SUCCESS)
543 goto free_handle;
544
545 height = 0;
546 width = 0;
547
548 if (efi_early->is64)
549 status = setup_uga64(uga_handle, size, &width, &height);
550 else
551 status = setup_uga32(uga_handle, size, &width, &height);
552
553 if (!width && !height)
Matt Fleming291f3632011-12-12 21:27:52 +0000554 goto free_handle;
555
556 /* EFI framebuffer */
557 si->orig_video_isVGA = VIDEO_TYPE_EFI;
558
559 si->lfb_depth = 32;
560 si->lfb_width = width;
561 si->lfb_height = height;
562
563 si->red_size = 8;
564 si->red_pos = 16;
565 si->green_size = 8;
566 si->green_pos = 8;
567 si->blue_size = 8;
568 si->blue_pos = 0;
569 si->rsvd_size = 8;
570 si->rsvd_pos = 24;
571
Matt Fleming291f3632011-12-12 21:27:52 +0000572free_handle:
Matt Fleming204b0a12014-03-22 10:09:01 +0000573 efi_call_early(free_pool, uga_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000574 return status;
575}
576
577void setup_graphics(struct boot_params *boot_params)
578{
579 efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
580 struct screen_info *si;
581 efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
582 efi_status_t status;
583 unsigned long size;
584 void **gop_handle = NULL;
585 void **uga_handle = NULL;
586
587 si = &boot_params->screen_info;
588 memset(si, 0, sizeof(*si));
589
590 size = 0;
Matt Fleming204b0a12014-03-22 10:09:01 +0000591 status = efi_call_early(locate_handle,
592 EFI_LOCATE_BY_PROTOCOL,
593 &graphics_proto, NULL, &size, gop_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000594 if (status == EFI_BUFFER_TOO_SMALL)
Ard Biesheuvel2c23b732016-04-25 21:06:48 +0100595 status = efi_setup_gop(NULL, si, &graphics_proto, size);
Matt Fleming291f3632011-12-12 21:27:52 +0000596
597 if (status != EFI_SUCCESS) {
598 size = 0;
Matt Fleming204b0a12014-03-22 10:09:01 +0000599 status = efi_call_early(locate_handle,
600 EFI_LOCATE_BY_PROTOCOL,
601 &uga_proto, NULL, &size, uga_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000602 if (status == EFI_BUFFER_TOO_SMALL)
603 setup_uga(si, &uga_proto, size);
604 }
605}
606
Matt Fleming291f3632011-12-12 21:27:52 +0000607/*
608 * Because the x86 boot code expects to be passed a boot_params we
609 * need to create one ourselves (usually the bootloader would create
610 * one for us).
Matt Fleming7e8213c2014-04-08 13:14:00 +0100611 *
612 * The caller is responsible for filling out ->code32_start in the
613 * returned boot_params.
Matt Fleming291f3632011-12-12 21:27:52 +0000614 */
Matt Fleming54b52d82014-01-10 15:27:14 +0000615struct boot_params *make_boot_params(struct efi_config *c)
Matt Fleming291f3632011-12-12 21:27:52 +0000616{
Matt Fleming9ca8f722012-07-19 10:23:48 +0100617 struct boot_params *boot_params;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100618 struct apm_bios_info *bi;
619 struct setup_header *hdr;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100620 efi_loaded_image_t *image;
Matt Fleming54b52d82014-01-10 15:27:14 +0000621 void *options, *handle;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100622 efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
Matt Fleming291f3632011-12-12 21:27:52 +0000623 int options_size = 0;
624 efi_status_t status;
Roy Franz5fef3872013-09-22 15:45:33 -0700625 char *cmdline_ptr;
Matt Fleming291f3632011-12-12 21:27:52 +0000626 u16 *s2;
627 u8 *s1;
628 int i;
Roy Franz46f45822013-09-22 15:45:39 -0700629 unsigned long ramdisk_addr;
630 unsigned long ramdisk_size;
Matt Fleming291f3632011-12-12 21:27:52 +0000631
Matt Fleming54b52d82014-01-10 15:27:14 +0000632 efi_early = c;
633 sys_table = (efi_system_table_t *)(unsigned long)efi_early->table;
634 handle = (void *)(unsigned long)efi_early->image_handle;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100635
636 /* Check if we were booted by the EFI firmware */
637 if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
638 return NULL;
639
Matt Fleming54b52d82014-01-10 15:27:14 +0000640 if (efi_early->is64)
641 setup_boot_services64(efi_early);
642 else
643 setup_boot_services32(efi_early);
644
Matt Fleming204b0a12014-03-22 10:09:01 +0000645 status = efi_call_early(handle_protocol, handle,
646 &proto, (void *)&image);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100647 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700648 efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +0100649 return NULL;
650 }
651
Roy Franz40e45302013-09-22 15:45:29 -0700652 status = efi_low_alloc(sys_table, 0x4000, 1,
653 (unsigned long *)&boot_params);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100654 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700655 efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +0100656 return NULL;
657 }
658
659 memset(boot_params, 0x0, 0x4000);
660
661 hdr = &boot_params->hdr;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100662 bi = &boot_params->apm_bios_info;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100663
664 /* Copy the second sector to boot_params */
665 memcpy(&hdr->jump, image->image_base + 512, 512);
666
667 /*
668 * Fill out some of the header fields ourselves because the
669 * EFI firmware loader doesn't load the first sector.
670 */
671 hdr->root_flags = 1;
672 hdr->vid_mode = 0xffff;
673 hdr->boot_flag = 0xAA55;
674
Matt Fleming291f3632011-12-12 21:27:52 +0000675 hdr->type_of_loader = 0x21;
676
677 /* Convert unicode cmdline to ascii */
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500678 cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
Roy Franz5fef3872013-09-22 15:45:33 -0700679 if (!cmdline_ptr)
680 goto fail;
681 hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
Roy Franz98b228f2015-04-15 16:32:24 -0700682 /* Fill in upper bits of command line address, NOP on 32 bit */
683 boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
Matt Fleming291f3632011-12-12 21:27:52 +0000684
685 hdr->ramdisk_image = 0;
686 hdr->ramdisk_size = 0;
687
Matt Fleming291f3632011-12-12 21:27:52 +0000688 /* Clear APM BIOS info */
689 memset(bi, 0, sizeof(*bi));
690
Matt Fleming5a17dae2014-08-05 11:52:11 +0100691 status = efi_parse_options(cmdline_ptr);
692 if (status != EFI_SUCCESS)
693 goto fail2;
694
Roy Franz46f45822013-09-22 15:45:39 -0700695 status = handle_cmdline_files(sys_table, image,
696 (char *)(unsigned long)hdr->cmd_line_ptr,
Yinghai Lu47226ad2014-09-03 21:50:07 -0700697 "initrd=", hdr->initrd_addr_max,
Roy Franz46f45822013-09-22 15:45:39 -0700698 &ramdisk_addr, &ramdisk_size);
Yinghai Lu47226ad2014-09-03 21:50:07 -0700699
700 if (status != EFI_SUCCESS &&
701 hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) {
702 efi_printk(sys_table, "Trying to load files to higher address\n");
703 status = handle_cmdline_files(sys_table, image,
704 (char *)(unsigned long)hdr->cmd_line_ptr,
705 "initrd=", -1UL,
706 &ramdisk_addr, &ramdisk_size);
707 }
708
Matt Fleming9ca8f722012-07-19 10:23:48 +0100709 if (status != EFI_SUCCESS)
710 goto fail2;
Yinghai Lu4bf71112014-06-14 12:23:41 -0700711 hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
712 hdr->ramdisk_size = ramdisk_size & 0xffffffff;
713 boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
714 boot_params->ext_ramdisk_size = (u64)ramdisk_size >> 32;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100715
716 return boot_params;
717fail2:
Roy Franz0e1cadb2013-09-22 15:45:38 -0700718 efi_free(sys_table, options_size, hdr->cmd_line_ptr);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100719fail:
Roy Franz40e45302013-09-22 15:45:29 -0700720 efi_free(sys_table, 0x4000, (unsigned long)boot_params);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100721 return NULL;
722}
723
Linn Crosettod2078d52013-09-22 19:59:08 -0600724static void add_e820ext(struct boot_params *params,
725 struct setup_data *e820ext, u32 nr_entries)
Matt Fleming9ca8f722012-07-19 10:23:48 +0100726{
Linn Crosettod2078d52013-09-22 19:59:08 -0600727 struct setup_data *data;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100728 efi_status_t status;
Linn Crosettod2078d52013-09-22 19:59:08 -0600729 unsigned long size;
730
731 e820ext->type = SETUP_E820_EXT;
732 e820ext->len = nr_entries * sizeof(struct e820entry);
733 e820ext->next = 0;
734
735 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
736
737 while (data && data->next)
738 data = (struct setup_data *)(unsigned long)data->next;
739
740 if (data)
741 data->next = (unsigned long)e820ext;
742 else
743 params->hdr.setup_data = (unsigned long)e820ext;
744}
745
746static efi_status_t setup_e820(struct boot_params *params,
747 struct setup_data *e820ext, u32 e820ext_size)
748{
749 struct e820entry *e820_map = &params->e820_map[0];
750 struct efi_info *efi = &params->efi_info;
751 struct e820entry *prev = NULL;
752 u32 nr_entries;
753 u32 nr_desc;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100754 int i;
Matt Fleming291f3632011-12-12 21:27:52 +0000755
Matt Fleming291f3632011-12-12 21:27:52 +0000756 nr_entries = 0;
Linn Crosettod2078d52013-09-22 19:59:08 -0600757 nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size;
758
759 for (i = 0; i < nr_desc; i++) {
Matt Fleming291f3632011-12-12 21:27:52 +0000760 efi_memory_desc_t *d;
761 unsigned int e820_type = 0;
Linn Crosettod2078d52013-09-22 19:59:08 -0600762 unsigned long m = efi->efi_memmap;
Matt Fleming291f3632011-12-12 21:27:52 +0000763
Dmitry Skorodumov7cc03e42015-07-28 18:38:32 +0400764#ifdef CONFIG_X86_64
765 m |= (u64)efi->efi_memmap_hi << 32;
766#endif
767
Linn Crosettod2078d52013-09-22 19:59:08 -0600768 d = (efi_memory_desc_t *)(m + (i * efi->efi_memdesc_size));
Matt Fleming291f3632011-12-12 21:27:52 +0000769 switch (d->type) {
770 case EFI_RESERVED_TYPE:
771 case EFI_RUNTIME_SERVICES_CODE:
772 case EFI_RUNTIME_SERVICES_DATA:
773 case EFI_MEMORY_MAPPED_IO:
774 case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
775 case EFI_PAL_CODE:
776 e820_type = E820_RESERVED;
777 break;
778
779 case EFI_UNUSABLE_MEMORY:
780 e820_type = E820_UNUSABLE;
781 break;
782
783 case EFI_ACPI_RECLAIM_MEMORY:
784 e820_type = E820_ACPI;
785 break;
786
787 case EFI_LOADER_CODE:
788 case EFI_LOADER_DATA:
789 case EFI_BOOT_SERVICES_CODE:
790 case EFI_BOOT_SERVICES_DATA:
791 case EFI_CONVENTIONAL_MEMORY:
792 e820_type = E820_RAM;
793 break;
794
795 case EFI_ACPI_MEMORY_NVS:
796 e820_type = E820_NVS;
797 break;
798
Dan Williamsad5fb872015-04-03 12:05:28 -0400799 case EFI_PERSISTENT_MEMORY:
800 e820_type = E820_PMEM;
801 break;
802
Matt Fleming291f3632011-12-12 21:27:52 +0000803 default:
804 continue;
805 }
806
807 /* Merge adjacent mappings */
808 if (prev && prev->type == e820_type &&
Linn Crosettod2078d52013-09-22 19:59:08 -0600809 (prev->addr + prev->size) == d->phys_addr) {
Matt Fleming291f3632011-12-12 21:27:52 +0000810 prev->size += d->num_pages << 12;
Linn Crosettod2078d52013-09-22 19:59:08 -0600811 continue;
Matt Fleming291f3632011-12-12 21:27:52 +0000812 }
Linn Crosettod2078d52013-09-22 19:59:08 -0600813
814 if (nr_entries == ARRAY_SIZE(params->e820_map)) {
815 u32 need = (nr_desc - i) * sizeof(struct e820entry) +
816 sizeof(struct setup_data);
817
818 if (!e820ext || e820ext_size < need)
819 return EFI_BUFFER_TOO_SMALL;
820
821 /* boot_params map full, switch to e820 extended */
822 e820_map = (struct e820entry *)e820ext->data;
823 }
824
825 e820_map->addr = d->phys_addr;
826 e820_map->size = d->num_pages << PAGE_SHIFT;
827 e820_map->type = e820_type;
828 prev = e820_map++;
829 nr_entries++;
Matt Fleming291f3632011-12-12 21:27:52 +0000830 }
831
Linn Crosettod2078d52013-09-22 19:59:08 -0600832 if (nr_entries > ARRAY_SIZE(params->e820_map)) {
833 u32 nr_e820ext = nr_entries - ARRAY_SIZE(params->e820_map);
834
835 add_e820ext(params, e820ext, nr_e820ext);
836 nr_entries -= nr_e820ext;
837 }
838
839 params->e820_entries = (u8)nr_entries;
840
841 return EFI_SUCCESS;
842}
843
844static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
845 u32 *e820ext_size)
846{
847 efi_status_t status;
848 unsigned long size;
849
850 size = sizeof(struct setup_data) +
851 sizeof(struct e820entry) * nr_desc;
852
853 if (*e820ext) {
Matt Fleming204b0a12014-03-22 10:09:01 +0000854 efi_call_early(free_pool, *e820ext);
Linn Crosettod2078d52013-09-22 19:59:08 -0600855 *e820ext = NULL;
856 *e820ext_size = 0;
857 }
858
Matt Fleming204b0a12014-03-22 10:09:01 +0000859 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
860 size, (void **)e820ext);
Linn Crosettod2078d52013-09-22 19:59:08 -0600861 if (status == EFI_SUCCESS)
862 *e820ext_size = size;
863
864 return status;
865}
866
Jeffrey Hugod6493402016-08-29 14:38:54 -0600867struct exit_boot_struct {
868 struct boot_params *boot_params;
869 struct efi_info *efi;
870 struct setup_data *e820ext;
871 __u32 e820ext_size;
872 bool is64;
873};
874
875static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
876 struct efi_boot_memmap *map,
877 void *priv)
878{
879 static bool first = true;
880 const char *signature;
881 __u32 nr_desc;
882 efi_status_t status;
883 struct exit_boot_struct *p = priv;
884
885 if (first) {
886 nr_desc = *map->buff_size / *map->desc_size;
887 if (nr_desc > ARRAY_SIZE(p->boot_params->e820_map)) {
888 u32 nr_e820ext = nr_desc -
889 ARRAY_SIZE(p->boot_params->e820_map);
890
891 status = alloc_e820ext(nr_e820ext, &p->e820ext,
892 &p->e820ext_size);
893 if (status != EFI_SUCCESS)
894 return status;
895 }
896 first = false;
897 }
898
899 signature = p->is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
900 memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
901
902 p->efi->efi_systab = (unsigned long)sys_table_arg;
903 p->efi->efi_memdesc_size = *map->desc_size;
904 p->efi->efi_memdesc_version = *map->desc_ver;
905 p->efi->efi_memmap = (unsigned long)*map->map;
906 p->efi->efi_memmap_size = *map->map_size;
907
908#ifdef CONFIG_X86_64
909 p->efi->efi_systab_hi = (unsigned long)sys_table_arg >> 32;
910 p->efi->efi_memmap_hi = (unsigned long)*map->map >> 32;
911#endif
912
913 return EFI_SUCCESS;
914}
915
Linn Crosettod2078d52013-09-22 19:59:08 -0600916static efi_status_t exit_boot(struct boot_params *boot_params,
Matt Flemingb8ff87a2014-01-10 15:54:31 +0000917 void *handle, bool is64)
Linn Crosettod2078d52013-09-22 19:59:08 -0600918{
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600919 unsigned long map_sz, key, desc_size, buff_size;
Linn Crosettod2078d52013-09-22 19:59:08 -0600920 efi_memory_desc_t *mem_map;
921 struct setup_data *e820ext;
922 __u32 e820ext_size;
Linn Crosettod2078d52013-09-22 19:59:08 -0600923 efi_status_t status;
924 __u32 desc_version;
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600925 struct efi_boot_memmap map;
Jeffrey Hugod6493402016-08-29 14:38:54 -0600926 struct exit_boot_struct priv;
Linn Crosettod2078d52013-09-22 19:59:08 -0600927
Jeffrey Hugod6493402016-08-29 14:38:54 -0600928 map.map = &mem_map;
929 map.map_size = &map_sz;
930 map.desc_size = &desc_size;
931 map.desc_ver = &desc_version;
932 map.key_ptr = &key;
933 map.buff_size = &buff_size;
934 priv.boot_params = boot_params;
935 priv.efi = &boot_params->efi_info;
936 priv.e820ext = NULL;
937 priv.e820ext_size = 0;
938 priv.is64 = is64;
Linn Crosettod2078d52013-09-22 19:59:08 -0600939
Jeffrey Hugod6493402016-08-29 14:38:54 -0600940 /* Might as well exit boot services now */
941 status = efi_exit_boot_services(sys_table, handle, &map, &priv,
942 exit_boot_func);
Linn Crosettod2078d52013-09-22 19:59:08 -0600943 if (status != EFI_SUCCESS)
944 return status;
945
Jeffrey Hugod6493402016-08-29 14:38:54 -0600946 e820ext = priv.e820ext;
947 e820ext_size = priv.e820ext_size;
Linn Crosettod2078d52013-09-22 19:59:08 -0600948 /* Historic? */
949 boot_params->alt_mem_k = 32 * 1024;
950
951 status = setup_e820(boot_params, e820ext, e820ext_size);
952 if (status != EFI_SUCCESS)
953 return status;
Matt Fleming291f3632011-12-12 21:27:52 +0000954
955 return EFI_SUCCESS;
Matt Fleming291f3632011-12-12 21:27:52 +0000956}
957
Matt Fleming9ca8f722012-07-19 10:23:48 +0100958/*
959 * On success we return a pointer to a boot_params structure, and NULL
960 * on failure.
961 */
Matt Fleming54b52d82014-01-10 15:27:14 +0000962struct boot_params *efi_main(struct efi_config *c,
Matt Fleming9ca8f722012-07-19 10:23:48 +0100963 struct boot_params *boot_params)
964{
Matt Fleming54b52d82014-01-10 15:27:14 +0000965 struct desc_ptr *gdt = NULL;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100966 efi_loaded_image_t *image;
967 struct setup_header *hdr = &boot_params->hdr;
968 efi_status_t status;
969 struct desc_struct *desc;
Matt Fleming54b52d82014-01-10 15:27:14 +0000970 void *handle;
971 efi_system_table_t *_table;
972 bool is64;
973
974 efi_early = c;
975
976 _table = (efi_system_table_t *)(unsigned long)efi_early->table;
977 handle = (void *)(unsigned long)efi_early->image_handle;
978 is64 = efi_early->is64;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100979
980 sys_table = _table;
981
982 /* Check if we were booted by the EFI firmware */
983 if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
984 goto fail;
985
Matt Fleming54b52d82014-01-10 15:27:14 +0000986 if (is64)
987 setup_boot_services64(efi_early);
988 else
989 setup_boot_services32(efi_early);
990
Matt Fleming9ca8f722012-07-19 10:23:48 +0100991 setup_graphics(boot_params);
Matt Fleming291f3632011-12-12 21:27:52 +0000992
Matt Fleming56394ab2014-09-11 09:04:25 +0100993 setup_efi_pci(boot_params);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700994
Lukas Wunner58c54752016-11-12 21:32:36 +0000995 setup_quirks(boot_params);
996
Matt Fleming204b0a12014-03-22 10:09:01 +0000997 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
998 sizeof(*gdt), (void **)&gdt);
Matt Fleming9fa7ded2012-02-20 13:20:59 +0000999 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -07001000 efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001001 goto fail;
Matt Fleming9fa7ded2012-02-20 13:20:59 +00001002 }
Matt Fleming291f3632011-12-12 21:27:52 +00001003
1004 gdt->size = 0x800;
Roy Franz40e45302013-09-22 15:45:29 -07001005 status = efi_low_alloc(sys_table, gdt->size, 8,
Roy Franz876dc362013-09-22 15:45:28 -07001006 (unsigned long *)&gdt->address);
Matt Fleming9fa7ded2012-02-20 13:20:59 +00001007 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -07001008 efi_printk(sys_table, "Failed to alloc mem for gdt\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001009 goto fail;
Matt Fleming9fa7ded2012-02-20 13:20:59 +00001010 }
Matt Fleming291f3632011-12-12 21:27:52 +00001011
Matt Fleming9ca8f722012-07-19 10:23:48 +01001012 /*
1013 * If the kernel isn't already loaded at the preferred load
1014 * address, relocate it.
1015 */
1016 if (hdr->pref_address != hdr->code32_start) {
Roy Franz4a9f3a72013-09-22 15:45:32 -07001017 unsigned long bzimage_addr = hdr->code32_start;
1018 status = efi_relocate_kernel(sys_table, &bzimage_addr,
1019 hdr->init_size, hdr->init_size,
1020 hdr->pref_address,
1021 hdr->kernel_alignment);
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001022 if (status != EFI_SUCCESS) {
1023 efi_printk(sys_table, "efi_relocate_kernel() failed!\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +01001024 goto fail;
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001025 }
Roy Franz4a9f3a72013-09-22 15:45:32 -07001026
1027 hdr->pref_address = hdr->code32_start;
1028 hdr->code32_start = bzimage_addr;
Matt Fleming9ca8f722012-07-19 10:23:48 +01001029 }
1030
Matt Flemingb8ff87a2014-01-10 15:54:31 +00001031 status = exit_boot(boot_params, handle, is64);
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001032 if (status != EFI_SUCCESS) {
1033 efi_printk(sys_table, "exit_boot() failed!\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001034 goto fail;
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001035 }
Matt Fleming291f3632011-12-12 21:27:52 +00001036
1037 memset((char *)gdt->address, 0x0, gdt->size);
1038 desc = (struct desc_struct *)gdt->address;
1039
1040 /* The first GDT is a dummy and the second is unused. */
1041 desc += 2;
1042
1043 desc->limit0 = 0xffff;
1044 desc->base0 = 0x0000;
1045 desc->base1 = 0x0000;
1046 desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
1047 desc->s = DESC_TYPE_CODE_DATA;
1048 desc->dpl = 0;
1049 desc->p = 1;
1050 desc->limit = 0xf;
1051 desc->avl = 0;
1052 desc->l = 0;
1053 desc->d = SEG_OP_SIZE_32BIT;
1054 desc->g = SEG_GRANULARITY_4KB;
1055 desc->base2 = 0x00;
1056
1057 desc++;
1058 desc->limit0 = 0xffff;
1059 desc->base0 = 0x0000;
1060 desc->base1 = 0x0000;
1061 desc->type = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
1062 desc->s = DESC_TYPE_CODE_DATA;
1063 desc->dpl = 0;
1064 desc->p = 1;
1065 desc->limit = 0xf;
1066 desc->avl = 0;
1067 desc->l = 0;
1068 desc->d = SEG_OP_SIZE_32BIT;
1069 desc->g = SEG_GRANULARITY_4KB;
1070 desc->base2 = 0x00;
1071
1072#ifdef CONFIG_X86_64
1073 /* Task segment value */
1074 desc++;
1075 desc->limit0 = 0x0000;
1076 desc->base0 = 0x0000;
1077 desc->base1 = 0x0000;
1078 desc->type = SEG_TYPE_TSS;
1079 desc->s = 0;
1080 desc->dpl = 0;
1081 desc->p = 1;
1082 desc->limit = 0x0;
1083 desc->avl = 0;
1084 desc->l = 0;
1085 desc->d = 0;
1086 desc->g = SEG_GRANULARITY_4KB;
1087 desc->base2 = 0x00;
1088#endif /* CONFIG_X86_64 */
1089
Matt Fleming291f3632011-12-12 21:27:52 +00001090 asm volatile("cli");
Bart Kuivenhoven0ce6cda2013-09-23 11:45:28 +02001091 asm volatile ("lgdt %0" : : "m" (*gdt));
Matt Fleming291f3632011-12-12 21:27:52 +00001092
1093 return boot_params;
1094fail:
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001095 efi_printk(sys_table, "efi_main() failed!\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001096 return NULL;
1097}