blob: 6d3aeabbce68b75c2a7db3dae8ba7bcf8853eee3 [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 \
Lukas Wunner0a637ee2016-08-22 12:01:21 +020035 c->boot_services = table->boottime; \
Matt Fleming54b52d82014-01-10 15:27:14 +000036 c->text_output = table->con_out; \
Matt Fleming54b52d82014-01-10 15:27:14 +000037}
38BOOT_SERVICES(32);
39BOOT_SERVICES(64);
40
Matt Flemingc116e8d2014-01-16 11:35:43 +000041static inline efi_status_t __open_volume32(void *__image, void **__fh)
Matt Fleming54b52d82014-01-10 15:27:14 +000042{
43 efi_file_io_interface_t *io;
Matt Flemingc116e8d2014-01-16 11:35:43 +000044 efi_loaded_image_32_t *image = __image;
45 efi_file_handle_32_t *fh;
Matt Fleming54b52d82014-01-10 15:27:14 +000046 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
47 efi_status_t status;
48 void *handle = (void *)(unsigned long)image->device_handle;
Matt Flemingc116e8d2014-01-16 11:35:43 +000049 unsigned long func;
Matt Fleming54b52d82014-01-10 15:27:14 +000050
Matt Fleming204b0a12014-03-22 10:09:01 +000051 status = efi_call_early(handle_protocol, handle,
52 &fs_proto, (void **)&io);
Matt Fleming54b52d82014-01-10 15:27:14 +000053 if (status != EFI_SUCCESS) {
54 efi_printk(sys_table, "Failed to handle fs_proto\n");
55 return status;
56 }
57
58 func = (unsigned long)io->open_volume;
59 status = efi_early->call(func, io, &fh);
60 if (status != EFI_SUCCESS)
61 efi_printk(sys_table, "Failed to open volume\n");
62
63 *__fh = fh;
64 return status;
65}
66
Matt Flemingc116e8d2014-01-16 11:35:43 +000067static inline efi_status_t __open_volume64(void *__image, void **__fh)
Matt Fleming54b52d82014-01-10 15:27:14 +000068{
Matt Flemingc116e8d2014-01-16 11:35:43 +000069 efi_file_io_interface_t *io;
70 efi_loaded_image_64_t *image = __image;
71 efi_file_handle_64_t *fh;
72 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
73 efi_status_t status;
74 void *handle = (void *)(unsigned long)image->device_handle;
75 unsigned long func;
76
Matt Fleming204b0a12014-03-22 10:09:01 +000077 status = efi_call_early(handle_protocol, handle,
78 &fs_proto, (void **)&io);
Matt Flemingc116e8d2014-01-16 11:35:43 +000079 if (status != EFI_SUCCESS) {
80 efi_printk(sys_table, "Failed to handle fs_proto\n");
81 return status;
82 }
83
84 func = (unsigned long)io->open_volume;
85 status = efi_early->call(func, io, &fh);
86 if (status != EFI_SUCCESS)
87 efi_printk(sys_table, "Failed to open volume\n");
88
89 *__fh = fh;
90 return status;
91}
92
Ard Biesheuvelbd669472014-07-02 14:54:42 +020093efi_status_t
Matt Flemingc116e8d2014-01-16 11:35:43 +000094efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
95{
96 if (efi_early->is64)
97 return __open_volume64(__image, __fh);
98
99 return __open_volume32(__image, __fh);
100}
101
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200102void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
Matt Flemingc116e8d2014-01-16 11:35:43 +0000103{
Lukas Wunnerdb4545d2017-01-31 13:21:34 +0000104 efi_call_proto(efi_simple_text_output_protocol, output_string,
105 efi_early->text_output, str);
Matt Fleming54b52d82014-01-10 15:27:14 +0000106}
Lee, Chun-Yideb94102012-12-20 19:33:22 +0800107
Matt Flemingc116e8d2014-01-16 11:35:43 +0000108static efi_status_t
109__setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom)
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700110{
Matt Flemingc116e8d2014-01-16 11:35:43 +0000111 struct pci_setup_rom *rom = NULL;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700112 efi_status_t status;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000113 unsigned long size;
114 uint64_t attributes;
115
116 status = efi_early->call(pci->attributes, pci,
117 EfiPciIoAttributeOperationGet, 0, 0,
118 &attributes);
119 if (status != EFI_SUCCESS)
120 return status;
121
122 if (!pci->romimage || !pci->romsize)
123 return EFI_INVALID_PARAMETER;
124
125 size = pci->romsize + sizeof(*rom);
126
Matt Fleming204b0a12014-03-22 10:09:01 +0000127 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
Andre Müller77e21e82014-09-10 01:00:22 +0200128 if (status != EFI_SUCCESS) {
129 efi_printk(sys_table, "Failed to alloc mem for rom\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000130 return status;
Andre Müller77e21e82014-09-10 01:00:22 +0200131 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000132
133 memset(rom, 0, sizeof(*rom));
134
135 rom->data.type = SETUP_PCI;
136 rom->data.len = size - sizeof(struct setup_data);
137 rom->data.next = 0;
138 rom->pcilen = pci->romsize;
139 *__rom = rom;
140
141 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
142 PCI_VENDOR_ID, 1, &(rom->vendor));
143
Andre Müller77e21e82014-09-10 01:00:22 +0200144 if (status != EFI_SUCCESS) {
145 efi_printk(sys_table, "Failed to read rom->vendor\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000146 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200147 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000148
149 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
150 PCI_DEVICE_ID, 1, &(rom->devid));
151
Andre Müller77e21e82014-09-10 01:00:22 +0200152 if (status != EFI_SUCCESS) {
153 efi_printk(sys_table, "Failed to read rom->devid\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000154 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200155 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000156
157 status = efi_early->call(pci->get_location, pci, &(rom->segment),
158 &(rom->bus), &(rom->device), &(rom->function));
159
160 if (status != EFI_SUCCESS)
161 goto free_struct;
162
163 memcpy(rom->romdata, pci->romimage, pci->romsize);
164 return status;
165
166free_struct:
Matt Fleming204b0a12014-03-22 10:09:01 +0000167 efi_call_early(free_pool, rom);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000168 return status;
169}
170
Matt Fleming56394ab2014-09-11 09:04:25 +0100171static void
Matt Flemingc116e8d2014-01-16 11:35:43 +0000172setup_efi_pci32(struct boot_params *params, void **pci_handle,
173 unsigned long size)
174{
175 efi_pci_io_protocol_32 *pci = NULL;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700176 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000177 u32 *handles = (u32 *)(unsigned long)pci_handle;
178 efi_status_t status;
179 unsigned long nr_pci;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700180 struct setup_data *data;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000181 int i;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700182
Jan Beulichbc754792013-01-18 12:35:14 +0000183 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700184
185 while (data && data->next)
Jan Beulichbc754792013-01-18 12:35:14 +0000186 data = (struct setup_data *)(unsigned long)data->next;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700187
Matt Flemingc116e8d2014-01-16 11:35:43 +0000188 nr_pci = size / sizeof(u32);
189 for (i = 0; i < nr_pci; i++) {
190 struct pci_setup_rom *rom = NULL;
191 u32 h = handles[i];
192
Matt Fleming204b0a12014-03-22 10:09:01 +0000193 status = efi_call_early(handle_protocol, h,
194 &pci_proto, (void **)&pci);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000195
196 if (status != EFI_SUCCESS)
197 continue;
198
199 if (!pci)
200 continue;
201
202 status = __setup_efi_pci32(pci, &rom);
203 if (status != EFI_SUCCESS)
204 continue;
205
206 if (data)
207 data->next = (unsigned long)rom;
208 else
209 params->hdr.setup_data = (unsigned long)rom;
210
211 data = (struct setup_data *)rom;
212
213 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000214}
215
216static efi_status_t
217__setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom)
218{
219 struct pci_setup_rom *rom;
220 efi_status_t status;
221 unsigned long size;
222 uint64_t attributes;
223
224 status = efi_early->call(pci->attributes, pci,
225 EfiPciIoAttributeOperationGet, 0,
226 &attributes);
227 if (status != EFI_SUCCESS)
228 return status;
229
230 if (!pci->romimage || !pci->romsize)
231 return EFI_INVALID_PARAMETER;
232
233 size = pci->romsize + sizeof(*rom);
234
Matt Fleming204b0a12014-03-22 10:09:01 +0000235 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
Andre Müller77e21e82014-09-10 01:00:22 +0200236 if (status != EFI_SUCCESS) {
237 efi_printk(sys_table, "Failed to alloc mem for rom\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000238 return status;
Andre Müller77e21e82014-09-10 01:00:22 +0200239 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000240
241 rom->data.type = SETUP_PCI;
242 rom->data.len = size - sizeof(struct setup_data);
243 rom->data.next = 0;
244 rom->pcilen = pci->romsize;
245 *__rom = rom;
246
247 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
248 PCI_VENDOR_ID, 1, &(rom->vendor));
249
Andre Müller77e21e82014-09-10 01:00:22 +0200250 if (status != EFI_SUCCESS) {
251 efi_printk(sys_table, "Failed to read rom->vendor\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000252 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200253 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000254
255 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
256 PCI_DEVICE_ID, 1, &(rom->devid));
257
Andre Müller77e21e82014-09-10 01:00:22 +0200258 if (status != EFI_SUCCESS) {
259 efi_printk(sys_table, "Failed to read rom->devid\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000260 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200261 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000262
263 status = efi_early->call(pci->get_location, pci, &(rom->segment),
264 &(rom->bus), &(rom->device), &(rom->function));
265
266 if (status != EFI_SUCCESS)
267 goto free_struct;
268
269 memcpy(rom->romdata, pci->romimage, pci->romsize);
270 return status;
271
272free_struct:
Matt Fleming204b0a12014-03-22 10:09:01 +0000273 efi_call_early(free_pool, rom);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000274 return status;
275
276}
277
Matt Fleming56394ab2014-09-11 09:04:25 +0100278static void
Matt Flemingc116e8d2014-01-16 11:35:43 +0000279setup_efi_pci64(struct boot_params *params, void **pci_handle,
280 unsigned long size)
281{
282 efi_pci_io_protocol_64 *pci = NULL;
283 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
284 u64 *handles = (u64 *)(unsigned long)pci_handle;
285 efi_status_t status;
286 unsigned long nr_pci;
287 struct setup_data *data;
288 int i;
289
290 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
291
292 while (data && data->next)
293 data = (struct setup_data *)(unsigned long)data->next;
294
295 nr_pci = size / sizeof(u64);
296 for (i = 0; i < nr_pci; i++) {
297 struct pci_setup_rom *rom = NULL;
298 u64 h = handles[i];
299
Matt Fleming204b0a12014-03-22 10:09:01 +0000300 status = efi_call_early(handle_protocol, h,
301 &pci_proto, (void **)&pci);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000302
303 if (status != EFI_SUCCESS)
304 continue;
305
306 if (!pci)
307 continue;
308
309 status = __setup_efi_pci64(pci, &rom);
310 if (status != EFI_SUCCESS)
311 continue;
312
313 if (data)
314 data->next = (unsigned long)rom;
315 else
316 params->hdr.setup_data = (unsigned long)rom;
317
318 data = (struct setup_data *)rom;
319
320 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000321}
322
Matt Fleming56394ab2014-09-11 09:04:25 +0100323/*
324 * There's no way to return an informative status from this function,
325 * because any analysis (and printing of error messages) needs to be
326 * done directly at the EFI function call-site.
327 *
328 * For example, EFI_INVALID_PARAMETER could indicate a bug or maybe we
329 * just didn't find any PCI devices, but there's no way to tell outside
330 * the context of the call.
331 */
332static void setup_efi_pci(struct boot_params *params)
Matt Flemingc116e8d2014-01-16 11:35:43 +0000333{
334 efi_status_t status;
335 void **pci_handle = NULL;
336 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
337 unsigned long size = 0;
338
Matt Fleming204b0a12014-03-22 10:09:01 +0000339 status = efi_call_early(locate_handle,
340 EFI_LOCATE_BY_PROTOCOL,
341 &pci_proto, NULL, &size, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700342
343 if (status == EFI_BUFFER_TOO_SMALL) {
Matt Fleming204b0a12014-03-22 10:09:01 +0000344 status = efi_call_early(allocate_pool,
345 EFI_LOADER_DATA,
346 size, (void **)&pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700347
Andre Müller77e21e82014-09-10 01:00:22 +0200348 if (status != EFI_SUCCESS) {
349 efi_printk(sys_table, "Failed to alloc mem for pci_handle\n");
Matt Fleming56394ab2014-09-11 09:04:25 +0100350 return;
Andre Müller77e21e82014-09-10 01:00:22 +0200351 }
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700352
Matt Fleming204b0a12014-03-22 10:09:01 +0000353 status = efi_call_early(locate_handle,
354 EFI_LOCATE_BY_PROTOCOL, &pci_proto,
355 NULL, &size, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700356 }
357
358 if (status != EFI_SUCCESS)
359 goto free_handle;
360
Matt Flemingc116e8d2014-01-16 11:35:43 +0000361 if (efi_early->is64)
Matt Fleming56394ab2014-09-11 09:04:25 +0100362 setup_efi_pci64(params, pci_handle, size);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000363 else
Matt Fleming56394ab2014-09-11 09:04:25 +0100364 setup_efi_pci32(params, pci_handle, size);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700365
366free_handle:
Matt Fleming204b0a12014-03-22 10:09:01 +0000367 efi_call_early(free_pool, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700368}
369
Lukas Wunner58c54752016-11-12 21:32:36 +0000370static void retrieve_apple_device_properties(struct boot_params *boot_params)
371{
372 efi_guid_t guid = APPLE_PROPERTIES_PROTOCOL_GUID;
373 struct setup_data *data, *new;
374 efi_status_t status;
375 u32 size = 0;
376 void *p;
377
378 status = efi_call_early(locate_protocol, &guid, NULL, &p);
379 if (status != EFI_SUCCESS)
380 return;
381
382 if (efi_table_attr(apple_properties_protocol, version, p) != 0x10000) {
383 efi_printk(sys_table, "Unsupported properties proto version\n");
384 return;
385 }
386
387 efi_call_proto(apple_properties_protocol, get_all, p, NULL, &size);
388 if (!size)
389 return;
390
391 do {
392 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
393 size + sizeof(struct setup_data), &new);
394 if (status != EFI_SUCCESS) {
395 efi_printk(sys_table,
396 "Failed to alloc mem for properties\n");
397 return;
398 }
399
400 status = efi_call_proto(apple_properties_protocol, get_all, p,
401 new->data, &size);
402
403 if (status == EFI_BUFFER_TOO_SMALL)
404 efi_call_early(free_pool, new);
405 } while (status == EFI_BUFFER_TOO_SMALL);
406
407 new->type = SETUP_APPLE_PROPERTIES;
408 new->len = size;
409 new->next = 0;
410
411 data = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
412 if (!data)
413 boot_params->hdr.setup_data = (unsigned long)new;
414 else {
415 while (data->next)
416 data = (struct setup_data *)(unsigned long)data->next;
417 data->next = (unsigned long)new;
418 }
419}
420
421static void setup_quirks(struct boot_params *boot_params)
422{
423 efi_char16_t const apple[] = { 'A', 'p', 'p', 'l', 'e', 0 };
424 efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long)
425 efi_table_attr(efi_system_table, fw_vendor, sys_table);
426
427 if (!memcmp(fw_vendor, apple, sizeof(apple))) {
428 if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
429 retrieve_apple_device_properties(boot_params);
430 }
431}
432
Matt Flemingc116e8d2014-01-16 11:35:43 +0000433static efi_status_t
434setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
Matt Fleming291f3632011-12-12 21:27:52 +0000435{
Matt Flemingc116e8d2014-01-16 11:35:43 +0000436 struct efi_uga_draw_protocol *uga = NULL, *first_uga;
437 efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
Matt Fleming291f3632011-12-12 21:27:52 +0000438 unsigned long nr_ugas;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000439 u32 *handles = (u32 *)uga_handle;;
Colin Ian Kingac0e94b2016-07-20 11:11:06 +0100440 efi_status_t status = EFI_INVALID_PARAMETER;
Matt Fleming291f3632011-12-12 21:27:52 +0000441 int i;
442
Matt Fleming291f3632011-12-12 21:27:52 +0000443 first_uga = NULL;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000444 nr_ugas = size / sizeof(u32);
Matt Fleming291f3632011-12-12 21:27:52 +0000445 for (i = 0; i < nr_ugas; i++) {
446 efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
Matt Fleming291f3632011-12-12 21:27:52 +0000447 u32 w, h, depth, refresh;
448 void *pciio;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000449 u32 handle = handles[i];
Matt Fleming291f3632011-12-12 21:27:52 +0000450
Matt Fleming204b0a12014-03-22 10:09:01 +0000451 status = efi_call_early(handle_protocol, handle,
452 &uga_proto, (void **)&uga);
Matt Fleming291f3632011-12-12 21:27:52 +0000453 if (status != EFI_SUCCESS)
454 continue;
455
Matt Fleming204b0a12014-03-22 10:09:01 +0000456 efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
Matt Fleming291f3632011-12-12 21:27:52 +0000457
Matt Fleming54b52d82014-01-10 15:27:14 +0000458 status = efi_early->call((unsigned long)uga->get_mode, uga,
459 &w, &h, &depth, &refresh);
Matt Fleming291f3632011-12-12 21:27:52 +0000460 if (status == EFI_SUCCESS && (!first_uga || pciio)) {
Matt Flemingc116e8d2014-01-16 11:35:43 +0000461 *width = w;
462 *height = h;
Matt Fleming291f3632011-12-12 21:27:52 +0000463
464 /*
465 * Once we've found a UGA supporting PCIIO,
466 * don't bother looking any further.
467 */
468 if (pciio)
469 break;
470
471 first_uga = uga;
472 }
473 }
474
Matt Flemingc116e8d2014-01-16 11:35:43 +0000475 return status;
476}
477
478static efi_status_t
479setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
480{
481 struct efi_uga_draw_protocol *uga = NULL, *first_uga;
482 efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
483 unsigned long nr_ugas;
484 u64 *handles = (u64 *)uga_handle;;
Colin Ian Kingac0e94b2016-07-20 11:11:06 +0100485 efi_status_t status = EFI_INVALID_PARAMETER;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000486 int i;
487
488 first_uga = NULL;
489 nr_ugas = size / sizeof(u64);
490 for (i = 0; i < nr_ugas; i++) {
491 efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
492 u32 w, h, depth, refresh;
493 void *pciio;
494 u64 handle = handles[i];
495
Matt Fleming204b0a12014-03-22 10:09:01 +0000496 status = efi_call_early(handle_protocol, handle,
497 &uga_proto, (void **)&uga);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000498 if (status != EFI_SUCCESS)
499 continue;
500
Matt Fleming204b0a12014-03-22 10:09:01 +0000501 efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000502
503 status = efi_early->call((unsigned long)uga->get_mode, uga,
504 &w, &h, &depth, &refresh);
505 if (status == EFI_SUCCESS && (!first_uga || pciio)) {
506 *width = w;
507 *height = h;
508
509 /*
510 * Once we've found a UGA supporting PCIIO,
511 * don't bother looking any further.
512 */
513 if (pciio)
514 break;
515
516 first_uga = uga;
517 }
518 }
519
520 return status;
521}
522
523/*
524 * See if we have Universal Graphics Adapter (UGA) protocol
525 */
526static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
527 unsigned long size)
528{
529 efi_status_t status;
530 u32 width, height;
531 void **uga_handle = NULL;
532
Matt Fleming204b0a12014-03-22 10:09:01 +0000533 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
534 size, (void **)&uga_handle);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000535 if (status != EFI_SUCCESS)
536 return status;
537
Matt Fleming204b0a12014-03-22 10:09:01 +0000538 status = efi_call_early(locate_handle,
539 EFI_LOCATE_BY_PROTOCOL,
540 uga_proto, NULL, &size, uga_handle);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000541 if (status != EFI_SUCCESS)
542 goto free_handle;
543
544 height = 0;
545 width = 0;
546
547 if (efi_early->is64)
548 status = setup_uga64(uga_handle, size, &width, &height);
549 else
550 status = setup_uga32(uga_handle, size, &width, &height);
551
552 if (!width && !height)
Matt Fleming291f3632011-12-12 21:27:52 +0000553 goto free_handle;
554
555 /* EFI framebuffer */
556 si->orig_video_isVGA = VIDEO_TYPE_EFI;
557
558 si->lfb_depth = 32;
559 si->lfb_width = width;
560 si->lfb_height = height;
561
562 si->red_size = 8;
563 si->red_pos = 16;
564 si->green_size = 8;
565 si->green_pos = 8;
566 si->blue_size = 8;
567 si->blue_pos = 0;
568 si->rsvd_size = 8;
569 si->rsvd_pos = 24;
570
Matt Fleming291f3632011-12-12 21:27:52 +0000571free_handle:
Matt Fleming204b0a12014-03-22 10:09:01 +0000572 efi_call_early(free_pool, uga_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000573 return status;
574}
575
576void setup_graphics(struct boot_params *boot_params)
577{
578 efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
579 struct screen_info *si;
580 efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
581 efi_status_t status;
582 unsigned long size;
583 void **gop_handle = NULL;
584 void **uga_handle = NULL;
585
586 si = &boot_params->screen_info;
587 memset(si, 0, sizeof(*si));
588
589 size = 0;
Matt Fleming204b0a12014-03-22 10:09:01 +0000590 status = efi_call_early(locate_handle,
591 EFI_LOCATE_BY_PROTOCOL,
592 &graphics_proto, NULL, &size, gop_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000593 if (status == EFI_BUFFER_TOO_SMALL)
Ard Biesheuvel2c23b732016-04-25 21:06:48 +0100594 status = efi_setup_gop(NULL, si, &graphics_proto, size);
Matt Fleming291f3632011-12-12 21:27:52 +0000595
596 if (status != EFI_SUCCESS) {
597 size = 0;
Matt Fleming204b0a12014-03-22 10:09:01 +0000598 status = efi_call_early(locate_handle,
599 EFI_LOCATE_BY_PROTOCOL,
600 &uga_proto, NULL, &size, uga_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000601 if (status == EFI_BUFFER_TOO_SMALL)
602 setup_uga(si, &uga_proto, size);
603 }
604}
605
Matt Fleming291f3632011-12-12 21:27:52 +0000606/*
607 * Because the x86 boot code expects to be passed a boot_params we
608 * need to create one ourselves (usually the bootloader would create
609 * one for us).
Matt Fleming7e8213c2014-04-08 13:14:00 +0100610 *
611 * The caller is responsible for filling out ->code32_start in the
612 * returned boot_params.
Matt Fleming291f3632011-12-12 21:27:52 +0000613 */
Matt Fleming54b52d82014-01-10 15:27:14 +0000614struct boot_params *make_boot_params(struct efi_config *c)
Matt Fleming291f3632011-12-12 21:27:52 +0000615{
Matt Fleming9ca8f722012-07-19 10:23:48 +0100616 struct boot_params *boot_params;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100617 struct apm_bios_info *bi;
618 struct setup_header *hdr;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100619 efi_loaded_image_t *image;
Matt Fleming54b52d82014-01-10 15:27:14 +0000620 void *options, *handle;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100621 efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
Matt Fleming291f3632011-12-12 21:27:52 +0000622 int options_size = 0;
623 efi_status_t status;
Roy Franz5fef3872013-09-22 15:45:33 -0700624 char *cmdline_ptr;
Matt Fleming291f3632011-12-12 21:27:52 +0000625 u16 *s2;
626 u8 *s1;
627 int i;
Roy Franz46f45822013-09-22 15:45:39 -0700628 unsigned long ramdisk_addr;
629 unsigned long ramdisk_size;
Matt Fleming291f3632011-12-12 21:27:52 +0000630
Matt Fleming54b52d82014-01-10 15:27:14 +0000631 efi_early = c;
632 sys_table = (efi_system_table_t *)(unsigned long)efi_early->table;
633 handle = (void *)(unsigned long)efi_early->image_handle;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100634
635 /* Check if we were booted by the EFI firmware */
636 if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
637 return NULL;
638
Matt Fleming54b52d82014-01-10 15:27:14 +0000639 if (efi_early->is64)
640 setup_boot_services64(efi_early);
641 else
642 setup_boot_services32(efi_early);
643
Matt Fleming204b0a12014-03-22 10:09:01 +0000644 status = efi_call_early(handle_protocol, handle,
645 &proto, (void *)&image);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100646 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700647 efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +0100648 return NULL;
649 }
650
Roy Franz40e45302013-09-22 15:45:29 -0700651 status = efi_low_alloc(sys_table, 0x4000, 1,
652 (unsigned long *)&boot_params);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100653 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700654 efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +0100655 return NULL;
656 }
657
658 memset(boot_params, 0x0, 0x4000);
659
660 hdr = &boot_params->hdr;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100661 bi = &boot_params->apm_bios_info;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100662
663 /* Copy the second sector to boot_params */
664 memcpy(&hdr->jump, image->image_base + 512, 512);
665
666 /*
667 * Fill out some of the header fields ourselves because the
668 * EFI firmware loader doesn't load the first sector.
669 */
670 hdr->root_flags = 1;
671 hdr->vid_mode = 0xffff;
672 hdr->boot_flag = 0xAA55;
673
Matt Fleming291f3632011-12-12 21:27:52 +0000674 hdr->type_of_loader = 0x21;
675
676 /* Convert unicode cmdline to ascii */
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500677 cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
Roy Franz5fef3872013-09-22 15:45:33 -0700678 if (!cmdline_ptr)
679 goto fail;
680 hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
Roy Franz98b228f2015-04-15 16:32:24 -0700681 /* Fill in upper bits of command line address, NOP on 32 bit */
682 boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
Matt Fleming291f3632011-12-12 21:27:52 +0000683
684 hdr->ramdisk_image = 0;
685 hdr->ramdisk_size = 0;
686
Matt Fleming291f3632011-12-12 21:27:52 +0000687 /* Clear APM BIOS info */
688 memset(bi, 0, sizeof(*bi));
689
Matt Fleming5a17dae2014-08-05 11:52:11 +0100690 status = efi_parse_options(cmdline_ptr);
691 if (status != EFI_SUCCESS)
692 goto fail2;
693
Roy Franz46f45822013-09-22 15:45:39 -0700694 status = handle_cmdline_files(sys_table, image,
695 (char *)(unsigned long)hdr->cmd_line_ptr,
Yinghai Lu47226ad2014-09-03 21:50:07 -0700696 "initrd=", hdr->initrd_addr_max,
Roy Franz46f45822013-09-22 15:45:39 -0700697 &ramdisk_addr, &ramdisk_size);
Yinghai Lu47226ad2014-09-03 21:50:07 -0700698
699 if (status != EFI_SUCCESS &&
700 hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) {
701 efi_printk(sys_table, "Trying to load files to higher address\n");
702 status = handle_cmdline_files(sys_table, image,
703 (char *)(unsigned long)hdr->cmd_line_ptr,
704 "initrd=", -1UL,
705 &ramdisk_addr, &ramdisk_size);
706 }
707
Matt Fleming9ca8f722012-07-19 10:23:48 +0100708 if (status != EFI_SUCCESS)
709 goto fail2;
Yinghai Lu4bf71112014-06-14 12:23:41 -0700710 hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
711 hdr->ramdisk_size = ramdisk_size & 0xffffffff;
712 boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
713 boot_params->ext_ramdisk_size = (u64)ramdisk_size >> 32;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100714
715 return boot_params;
716fail2:
Roy Franz0e1cadb2013-09-22 15:45:38 -0700717 efi_free(sys_table, options_size, hdr->cmd_line_ptr);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100718fail:
Roy Franz40e45302013-09-22 15:45:29 -0700719 efi_free(sys_table, 0x4000, (unsigned long)boot_params);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100720 return NULL;
721}
722
Linn Crosettod2078d52013-09-22 19:59:08 -0600723static void add_e820ext(struct boot_params *params,
724 struct setup_data *e820ext, u32 nr_entries)
Matt Fleming9ca8f722012-07-19 10:23:48 +0100725{
Linn Crosettod2078d52013-09-22 19:59:08 -0600726 struct setup_data *data;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100727 efi_status_t status;
Linn Crosettod2078d52013-09-22 19:59:08 -0600728 unsigned long size;
729
730 e820ext->type = SETUP_E820_EXT;
731 e820ext->len = nr_entries * sizeof(struct e820entry);
732 e820ext->next = 0;
733
734 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
735
736 while (data && data->next)
737 data = (struct setup_data *)(unsigned long)data->next;
738
739 if (data)
740 data->next = (unsigned long)e820ext;
741 else
742 params->hdr.setup_data = (unsigned long)e820ext;
743}
744
745static efi_status_t setup_e820(struct boot_params *params,
746 struct setup_data *e820ext, u32 e820ext_size)
747{
748 struct e820entry *e820_map = &params->e820_map[0];
749 struct efi_info *efi = &params->efi_info;
750 struct e820entry *prev = NULL;
751 u32 nr_entries;
752 u32 nr_desc;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100753 int i;
Matt Fleming291f3632011-12-12 21:27:52 +0000754
Matt Fleming291f3632011-12-12 21:27:52 +0000755 nr_entries = 0;
Linn Crosettod2078d52013-09-22 19:59:08 -0600756 nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size;
757
758 for (i = 0; i < nr_desc; i++) {
Matt Fleming291f3632011-12-12 21:27:52 +0000759 efi_memory_desc_t *d;
760 unsigned int e820_type = 0;
Linn Crosettod2078d52013-09-22 19:59:08 -0600761 unsigned long m = efi->efi_memmap;
Matt Fleming291f3632011-12-12 21:27:52 +0000762
Dmitry Skorodumov7cc03e42015-07-28 18:38:32 +0400763#ifdef CONFIG_X86_64
764 m |= (u64)efi->efi_memmap_hi << 32;
765#endif
766
Linn Crosettod2078d52013-09-22 19:59:08 -0600767 d = (efi_memory_desc_t *)(m + (i * efi->efi_memdesc_size));
Matt Fleming291f3632011-12-12 21:27:52 +0000768 switch (d->type) {
769 case EFI_RESERVED_TYPE:
770 case EFI_RUNTIME_SERVICES_CODE:
771 case EFI_RUNTIME_SERVICES_DATA:
772 case EFI_MEMORY_MAPPED_IO:
773 case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
774 case EFI_PAL_CODE:
775 e820_type = E820_RESERVED;
776 break;
777
778 case EFI_UNUSABLE_MEMORY:
779 e820_type = E820_UNUSABLE;
780 break;
781
782 case EFI_ACPI_RECLAIM_MEMORY:
783 e820_type = E820_ACPI;
784 break;
785
786 case EFI_LOADER_CODE:
787 case EFI_LOADER_DATA:
788 case EFI_BOOT_SERVICES_CODE:
789 case EFI_BOOT_SERVICES_DATA:
790 case EFI_CONVENTIONAL_MEMORY:
791 e820_type = E820_RAM;
792 break;
793
794 case EFI_ACPI_MEMORY_NVS:
795 e820_type = E820_NVS;
796 break;
797
Dan Williamsad5fb872015-04-03 12:05:28 -0400798 case EFI_PERSISTENT_MEMORY:
799 e820_type = E820_PMEM;
800 break;
801
Matt Fleming291f3632011-12-12 21:27:52 +0000802 default:
803 continue;
804 }
805
806 /* Merge adjacent mappings */
807 if (prev && prev->type == e820_type &&
Linn Crosettod2078d52013-09-22 19:59:08 -0600808 (prev->addr + prev->size) == d->phys_addr) {
Matt Fleming291f3632011-12-12 21:27:52 +0000809 prev->size += d->num_pages << 12;
Linn Crosettod2078d52013-09-22 19:59:08 -0600810 continue;
Matt Fleming291f3632011-12-12 21:27:52 +0000811 }
Linn Crosettod2078d52013-09-22 19:59:08 -0600812
813 if (nr_entries == ARRAY_SIZE(params->e820_map)) {
814 u32 need = (nr_desc - i) * sizeof(struct e820entry) +
815 sizeof(struct setup_data);
816
817 if (!e820ext || e820ext_size < need)
818 return EFI_BUFFER_TOO_SMALL;
819
820 /* boot_params map full, switch to e820 extended */
821 e820_map = (struct e820entry *)e820ext->data;
822 }
823
824 e820_map->addr = d->phys_addr;
825 e820_map->size = d->num_pages << PAGE_SHIFT;
826 e820_map->type = e820_type;
827 prev = e820_map++;
828 nr_entries++;
Matt Fleming291f3632011-12-12 21:27:52 +0000829 }
830
Linn Crosettod2078d52013-09-22 19:59:08 -0600831 if (nr_entries > ARRAY_SIZE(params->e820_map)) {
832 u32 nr_e820ext = nr_entries - ARRAY_SIZE(params->e820_map);
833
834 add_e820ext(params, e820ext, nr_e820ext);
835 nr_entries -= nr_e820ext;
836 }
837
838 params->e820_entries = (u8)nr_entries;
839
840 return EFI_SUCCESS;
841}
842
843static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
844 u32 *e820ext_size)
845{
846 efi_status_t status;
847 unsigned long size;
848
849 size = sizeof(struct setup_data) +
850 sizeof(struct e820entry) * nr_desc;
851
852 if (*e820ext) {
Matt Fleming204b0a12014-03-22 10:09:01 +0000853 efi_call_early(free_pool, *e820ext);
Linn Crosettod2078d52013-09-22 19:59:08 -0600854 *e820ext = NULL;
855 *e820ext_size = 0;
856 }
857
Matt Fleming204b0a12014-03-22 10:09:01 +0000858 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
859 size, (void **)e820ext);
Linn Crosettod2078d52013-09-22 19:59:08 -0600860 if (status == EFI_SUCCESS)
861 *e820ext_size = size;
862
863 return status;
864}
865
Jeffrey Hugod6493402016-08-29 14:38:54 -0600866struct exit_boot_struct {
867 struct boot_params *boot_params;
868 struct efi_info *efi;
869 struct setup_data *e820ext;
870 __u32 e820ext_size;
871 bool is64;
872};
873
874static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
875 struct efi_boot_memmap *map,
876 void *priv)
877{
878 static bool first = true;
879 const char *signature;
880 __u32 nr_desc;
881 efi_status_t status;
882 struct exit_boot_struct *p = priv;
883
884 if (first) {
885 nr_desc = *map->buff_size / *map->desc_size;
886 if (nr_desc > ARRAY_SIZE(p->boot_params->e820_map)) {
887 u32 nr_e820ext = nr_desc -
888 ARRAY_SIZE(p->boot_params->e820_map);
889
890 status = alloc_e820ext(nr_e820ext, &p->e820ext,
891 &p->e820ext_size);
892 if (status != EFI_SUCCESS)
893 return status;
894 }
895 first = false;
896 }
897
898 signature = p->is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
899 memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
900
901 p->efi->efi_systab = (unsigned long)sys_table_arg;
902 p->efi->efi_memdesc_size = *map->desc_size;
903 p->efi->efi_memdesc_version = *map->desc_ver;
904 p->efi->efi_memmap = (unsigned long)*map->map;
905 p->efi->efi_memmap_size = *map->map_size;
906
907#ifdef CONFIG_X86_64
908 p->efi->efi_systab_hi = (unsigned long)sys_table_arg >> 32;
909 p->efi->efi_memmap_hi = (unsigned long)*map->map >> 32;
910#endif
911
912 return EFI_SUCCESS;
913}
914
Linn Crosettod2078d52013-09-22 19:59:08 -0600915static efi_status_t exit_boot(struct boot_params *boot_params,
Matt Flemingb8ff87a2014-01-10 15:54:31 +0000916 void *handle, bool is64)
Linn Crosettod2078d52013-09-22 19:59:08 -0600917{
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600918 unsigned long map_sz, key, desc_size, buff_size;
Linn Crosettod2078d52013-09-22 19:59:08 -0600919 efi_memory_desc_t *mem_map;
920 struct setup_data *e820ext;
921 __u32 e820ext_size;
Linn Crosettod2078d52013-09-22 19:59:08 -0600922 efi_status_t status;
923 __u32 desc_version;
Jeffrey Hugodadb57a2016-08-29 14:38:51 -0600924 struct efi_boot_memmap map;
Jeffrey Hugod6493402016-08-29 14:38:54 -0600925 struct exit_boot_struct priv;
Linn Crosettod2078d52013-09-22 19:59:08 -0600926
Jeffrey Hugod6493402016-08-29 14:38:54 -0600927 map.map = &mem_map;
928 map.map_size = &map_sz;
929 map.desc_size = &desc_size;
930 map.desc_ver = &desc_version;
931 map.key_ptr = &key;
932 map.buff_size = &buff_size;
933 priv.boot_params = boot_params;
934 priv.efi = &boot_params->efi_info;
935 priv.e820ext = NULL;
936 priv.e820ext_size = 0;
937 priv.is64 = is64;
Linn Crosettod2078d52013-09-22 19:59:08 -0600938
Jeffrey Hugod6493402016-08-29 14:38:54 -0600939 /* Might as well exit boot services now */
940 status = efi_exit_boot_services(sys_table, handle, &map, &priv,
941 exit_boot_func);
Linn Crosettod2078d52013-09-22 19:59:08 -0600942 if (status != EFI_SUCCESS)
943 return status;
944
Jeffrey Hugod6493402016-08-29 14:38:54 -0600945 e820ext = priv.e820ext;
946 e820ext_size = priv.e820ext_size;
Linn Crosettod2078d52013-09-22 19:59:08 -0600947 /* Historic? */
948 boot_params->alt_mem_k = 32 * 1024;
949
950 status = setup_e820(boot_params, e820ext, e820ext_size);
951 if (status != EFI_SUCCESS)
952 return status;
Matt Fleming291f3632011-12-12 21:27:52 +0000953
954 return EFI_SUCCESS;
Matt Fleming291f3632011-12-12 21:27:52 +0000955}
956
Matt Fleming9ca8f722012-07-19 10:23:48 +0100957/*
958 * On success we return a pointer to a boot_params structure, and NULL
959 * on failure.
960 */
Matt Fleming54b52d82014-01-10 15:27:14 +0000961struct boot_params *efi_main(struct efi_config *c,
Matt Fleming9ca8f722012-07-19 10:23:48 +0100962 struct boot_params *boot_params)
963{
Matt Fleming54b52d82014-01-10 15:27:14 +0000964 struct desc_ptr *gdt = NULL;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100965 efi_loaded_image_t *image;
966 struct setup_header *hdr = &boot_params->hdr;
967 efi_status_t status;
968 struct desc_struct *desc;
Matt Fleming54b52d82014-01-10 15:27:14 +0000969 void *handle;
970 efi_system_table_t *_table;
971 bool is64;
972
973 efi_early = c;
974
975 _table = (efi_system_table_t *)(unsigned long)efi_early->table;
976 handle = (void *)(unsigned long)efi_early->image_handle;
977 is64 = efi_early->is64;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100978
979 sys_table = _table;
980
981 /* Check if we were booted by the EFI firmware */
982 if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
983 goto fail;
984
Matt Fleming54b52d82014-01-10 15:27:14 +0000985 if (is64)
986 setup_boot_services64(efi_early);
987 else
988 setup_boot_services32(efi_early);
989
Matt Fleming9ca8f722012-07-19 10:23:48 +0100990 setup_graphics(boot_params);
Matt Fleming291f3632011-12-12 21:27:52 +0000991
Matt Fleming56394ab2014-09-11 09:04:25 +0100992 setup_efi_pci(boot_params);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700993
Lukas Wunner58c54752016-11-12 21:32:36 +0000994 setup_quirks(boot_params);
995
Matt Fleming204b0a12014-03-22 10:09:01 +0000996 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
997 sizeof(*gdt), (void **)&gdt);
Matt Fleming9fa7ded2012-02-20 13:20:59 +0000998 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700999 efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001000 goto fail;
Matt Fleming9fa7ded2012-02-20 13:20:59 +00001001 }
Matt Fleming291f3632011-12-12 21:27:52 +00001002
1003 gdt->size = 0x800;
Roy Franz40e45302013-09-22 15:45:29 -07001004 status = efi_low_alloc(sys_table, gdt->size, 8,
Roy Franz876dc362013-09-22 15:45:28 -07001005 (unsigned long *)&gdt->address);
Matt Fleming9fa7ded2012-02-20 13:20:59 +00001006 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -07001007 efi_printk(sys_table, "Failed to alloc mem for gdt\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001008 goto fail;
Matt Fleming9fa7ded2012-02-20 13:20:59 +00001009 }
Matt Fleming291f3632011-12-12 21:27:52 +00001010
Matt Fleming9ca8f722012-07-19 10:23:48 +01001011 /*
1012 * If the kernel isn't already loaded at the preferred load
1013 * address, relocate it.
1014 */
1015 if (hdr->pref_address != hdr->code32_start) {
Roy Franz4a9f3a72013-09-22 15:45:32 -07001016 unsigned long bzimage_addr = hdr->code32_start;
1017 status = efi_relocate_kernel(sys_table, &bzimage_addr,
1018 hdr->init_size, hdr->init_size,
1019 hdr->pref_address,
1020 hdr->kernel_alignment);
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001021 if (status != EFI_SUCCESS) {
1022 efi_printk(sys_table, "efi_relocate_kernel() failed!\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +01001023 goto fail;
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001024 }
Roy Franz4a9f3a72013-09-22 15:45:32 -07001025
1026 hdr->pref_address = hdr->code32_start;
1027 hdr->code32_start = bzimage_addr;
Matt Fleming9ca8f722012-07-19 10:23:48 +01001028 }
1029
Matt Flemingb8ff87a2014-01-10 15:54:31 +00001030 status = exit_boot(boot_params, handle, is64);
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001031 if (status != EFI_SUCCESS) {
1032 efi_printk(sys_table, "exit_boot() failed!\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001033 goto fail;
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001034 }
Matt Fleming291f3632011-12-12 21:27:52 +00001035
1036 memset((char *)gdt->address, 0x0, gdt->size);
1037 desc = (struct desc_struct *)gdt->address;
1038
1039 /* The first GDT is a dummy and the second is unused. */
1040 desc += 2;
1041
1042 desc->limit0 = 0xffff;
1043 desc->base0 = 0x0000;
1044 desc->base1 = 0x0000;
1045 desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
1046 desc->s = DESC_TYPE_CODE_DATA;
1047 desc->dpl = 0;
1048 desc->p = 1;
1049 desc->limit = 0xf;
1050 desc->avl = 0;
1051 desc->l = 0;
1052 desc->d = SEG_OP_SIZE_32BIT;
1053 desc->g = SEG_GRANULARITY_4KB;
1054 desc->base2 = 0x00;
1055
1056 desc++;
1057 desc->limit0 = 0xffff;
1058 desc->base0 = 0x0000;
1059 desc->base1 = 0x0000;
1060 desc->type = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
1061 desc->s = DESC_TYPE_CODE_DATA;
1062 desc->dpl = 0;
1063 desc->p = 1;
1064 desc->limit = 0xf;
1065 desc->avl = 0;
1066 desc->l = 0;
1067 desc->d = SEG_OP_SIZE_32BIT;
1068 desc->g = SEG_GRANULARITY_4KB;
1069 desc->base2 = 0x00;
1070
1071#ifdef CONFIG_X86_64
1072 /* Task segment value */
1073 desc++;
1074 desc->limit0 = 0x0000;
1075 desc->base0 = 0x0000;
1076 desc->base1 = 0x0000;
1077 desc->type = SEG_TYPE_TSS;
1078 desc->s = 0;
1079 desc->dpl = 0;
1080 desc->p = 1;
1081 desc->limit = 0x0;
1082 desc->avl = 0;
1083 desc->l = 0;
1084 desc->d = 0;
1085 desc->g = SEG_GRANULARITY_4KB;
1086 desc->base2 = 0x00;
1087#endif /* CONFIG_X86_64 */
1088
Matt Fleming291f3632011-12-12 21:27:52 +00001089 asm volatile("cli");
Bart Kuivenhoven0ce6cda2013-09-23 11:45:28 +02001090 asm volatile ("lgdt %0" : : "m" (*gdt));
Matt Fleming291f3632011-12-12 21:27:52 +00001091
1092 return boot_params;
1093fail:
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001094 efi_printk(sys_table, "efi_main() failed!\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001095 return NULL;
1096}