blob: 42548168bdc398a740807791ed96f4fe34d58625 [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
Matt Fleming0f905a42012-11-20 13:07:46 +000016#undef memcpy /* Use memcpy from misc.c */
17
Matt Fleming291f3632011-12-12 21:27:52 +000018#include "eboot.h"
19
20static efi_system_table_t *sys_table;
21
Matt Fleming54b52d82014-01-10 15:27:14 +000022static struct efi_config *efi_early;
23
24#define BOOT_SERVICES(bits) \
25static void setup_boot_services##bits(struct efi_config *c) \
26{ \
27 efi_system_table_##bits##_t *table; \
28 efi_boot_services_##bits##_t *bt; \
29 \
30 table = (typeof(table))sys_table; \
31 \
32 c->text_output = table->con_out; \
33 \
34 bt = (typeof(bt))(unsigned long)(table->boottime); \
35 \
36 c->allocate_pool = bt->allocate_pool; \
37 c->allocate_pages = bt->allocate_pages; \
38 c->get_memory_map = bt->get_memory_map; \
39 c->free_pool = bt->free_pool; \
40 c->free_pages = bt->free_pages; \
41 c->locate_handle = bt->locate_handle; \
42 c->handle_protocol = bt->handle_protocol; \
43 c->exit_boot_services = bt->exit_boot_services; \
44}
45BOOT_SERVICES(32);
46BOOT_SERVICES(64);
47
48static void efi_printk(efi_system_table_t *, char *);
49static void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
50
51static efi_status_t
52efi_file_size(efi_system_table_t *sys_table, void *__fh,
53 efi_char16_t *filename_16, void **handle, u64 *file_sz)
54{
55 efi_file_handle_t *h, *fh = __fh;
56 efi_file_info_t *info;
57 efi_status_t status;
58 efi_guid_t info_guid = EFI_FILE_INFO_ID;
59 u32 info_sz;
60
61 status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
62 EFI_FILE_MODE_READ, (u64)0);
63 if (status != EFI_SUCCESS) {
64 efi_printk(sys_table, "Failed to open file: ");
65 efi_char16_printk(sys_table, filename_16);
66 efi_printk(sys_table, "\n");
67 return status;
68 }
69
70 *handle = h;
71
72 info_sz = 0;
73 status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
74 &info_sz, NULL);
75 if (status != EFI_BUFFER_TOO_SMALL) {
76 efi_printk(sys_table, "Failed to get file info size\n");
77 return status;
78 }
79
80grow:
81 status = efi_early->call(efi_early->allocate_pool, EFI_LOADER_DATA,
82 info_sz, (void **)&info);
83 if (status != EFI_SUCCESS) {
84 efi_printk(sys_table, "Failed to alloc mem for file info\n");
85 return status;
86 }
87
88 status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
89 &info_sz, info);
90 if (status == EFI_BUFFER_TOO_SMALL) {
91 efi_early->call(efi_early->free_pool, info);
92 goto grow;
93 }
94
95 *file_sz = info->file_size;
96 efi_early->call(efi_early->free_pool, info);
97
98 if (status != EFI_SUCCESS)
99 efi_printk(sys_table, "Failed to get initrd info\n");
100
101 return status;
102}
103
104static inline efi_status_t
105efi_file_read(void *__fh, void *handle, unsigned long *size, void *addr)
106{
107 efi_file_handle_t *fh = __fh;
108 return efi_early->call((unsigned long)fh->read, handle, size, addr);
109}
110
111static inline efi_status_t efi_file_close(void *__fh, void *handle)
112{
113 efi_file_handle_t *fh = __fh;
114
115 return efi_early->call((unsigned long)fh->close, handle);
116}
117
118static inline efi_status_t
119efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
120{
121 efi_file_io_interface_t *io;
122 efi_loaded_image_t *image = __image;
123 efi_file_handle_t *fh;
124 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
125 efi_status_t status;
126 void *handle = (void *)(unsigned long)image->device_handle;
127 u32 func;
128
129 status = efi_early->call(efi_early->handle_protocol, handle,
130 &fs_proto, (void **)&io);
131 if (status != EFI_SUCCESS) {
132 efi_printk(sys_table, "Failed to handle fs_proto\n");
133 return status;
134 }
135
136 func = (unsigned long)io->open_volume;
137 status = efi_early->call(func, io, &fh);
138 if (status != EFI_SUCCESS)
139 efi_printk(sys_table, "Failed to open volume\n");
140
141 *__fh = fh;
142 return status;
143}
144
145static inline void
146efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
147{
148 struct efi_simple_text_output_protocol *out;
149 unsigned long output_string;
150 size_t offset;
151 unsigned long *func;
152
153 offset = offsetof(typeof(*out), output_string);
154 output_string = efi_early->text_output + offset;
155 func = (unsigned long *)output_string;
156
157 efi_early->call(*func, efi_early->text_output, str);
158}
Lee, Chun-Yideb94102012-12-20 19:33:22 +0800159
Roy Franz7721da42013-09-22 15:45:27 -0700160#include "../../../../drivers/firmware/efi/efi-stub-helper.c"
Lee, Chun-Yideb94102012-12-20 19:33:22 +0800161
Matt Fleming291f3632011-12-12 21:27:52 +0000162static void find_bits(unsigned long mask, u8 *pos, u8 *size)
163{
164 u8 first, len;
165
166 first = 0;
167 len = 0;
168
169 if (mask) {
170 while (!(mask & 0x1)) {
171 mask = mask >> 1;
172 first++;
173 }
174
175 while (mask & 0x1) {
176 mask = mask >> 1;
177 len++;
178 }
179 }
180
181 *pos = first;
182 *size = len;
183}
184
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700185static efi_status_t setup_efi_pci(struct boot_params *params)
186{
187 efi_pci_io_protocol *pci;
188 efi_status_t status;
Matt Fleming54b52d82014-01-10 15:27:14 +0000189 void **pci_handle = NULL;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700190 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
191 unsigned long nr_pci, size = 0;
192 int i;
193 struct setup_data *data;
194
Jan Beulichbc754792013-01-18 12:35:14 +0000195 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700196
197 while (data && data->next)
Jan Beulichbc754792013-01-18 12:35:14 +0000198 data = (struct setup_data *)(unsigned long)data->next;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700199
Matt Fleming54b52d82014-01-10 15:27:14 +0000200 status = efi_early->call(efi_early->locate_handle,
201 EFI_LOCATE_BY_PROTOCOL,
202 &pci_proto, NULL, &size, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700203
204 if (status == EFI_BUFFER_TOO_SMALL) {
Matt Fleming54b52d82014-01-10 15:27:14 +0000205 status = efi_early->call(efi_early->allocate_pool,
206 EFI_LOADER_DATA,
207 size, (void **)&pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700208
209 if (status != EFI_SUCCESS)
210 return status;
211
Matt Fleming54b52d82014-01-10 15:27:14 +0000212 status = efi_early->call(efi_early->locate_handle,
213 EFI_LOCATE_BY_PROTOCOL, &pci_proto,
214 NULL, &size, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700215 }
216
217 if (status != EFI_SUCCESS)
218 goto free_handle;
219
220 nr_pci = size / sizeof(void *);
221 for (i = 0; i < nr_pci; i++) {
222 void *h = pci_handle[i];
223 uint64_t attributes;
224 struct pci_setup_rom *rom;
225
Matt Fleming54b52d82014-01-10 15:27:14 +0000226 status = efi_early->call(efi_early->handle_protocol, h,
227 &pci_proto, (void **)&pci);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700228
229 if (status != EFI_SUCCESS)
230 continue;
231
232 if (!pci)
233 continue;
234
David Woodhouseb607e212013-01-07 22:09:49 +0000235#ifdef CONFIG_X86_64
Matt Fleming54b52d82014-01-10 15:27:14 +0000236 status = efi_early->call((unsigned long)pci->attributes, pci,
237 EfiPciIoAttributeOperationGet, 0,
238 &attributes);
David Woodhouseb607e212013-01-07 22:09:49 +0000239#else
Matt Fleming54b52d82014-01-10 15:27:14 +0000240 status = efi_early->call((unsigned long)pci->attributes, pci,
241 EfiPciIoAttributeOperationGet, 0, 0,
242 &attributes);
David Woodhouseb607e212013-01-07 22:09:49 +0000243#endif
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700244 if (status != EFI_SUCCESS)
245 continue;
246
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700247 if (!pci->romimage || !pci->romsize)
248 continue;
249
250 size = pci->romsize + sizeof(*rom);
251
Matt Fleming54b52d82014-01-10 15:27:14 +0000252 status = efi_early->call(efi_early->allocate_pool,
253 EFI_LOADER_DATA, size, &rom);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700254
255 if (status != EFI_SUCCESS)
256 continue;
257
258 rom->data.type = SETUP_PCI;
259 rom->data.len = size - sizeof(struct setup_data);
260 rom->data.next = 0;
261 rom->pcilen = pci->romsize;
262
Matt Fleming54b52d82014-01-10 15:27:14 +0000263 status = efi_early->call((unsigned long)pci->pci.read, pci,
264 EfiPciIoWidthUint16, PCI_VENDOR_ID,
265 1, &(rom->vendor));
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700266
267 if (status != EFI_SUCCESS)
268 goto free_struct;
269
Matt Fleming54b52d82014-01-10 15:27:14 +0000270 status = efi_early->call((unsigned long)pci->pci.read, pci,
271 EfiPciIoWidthUint16, PCI_DEVICE_ID,
272 1, &(rom->devid));
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700273
274 if (status != EFI_SUCCESS)
275 goto free_struct;
276
Matt Fleming54b52d82014-01-10 15:27:14 +0000277 status = efi_early->call((unsigned long)pci->get_location, pci,
278 &(rom->segment), &(rom->bus),
279 &(rom->device), &(rom->function));
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700280
281 if (status != EFI_SUCCESS)
282 goto free_struct;
283
284 memcpy(rom->romdata, pci->romimage, pci->romsize);
285
286 if (data)
Jan Beulichbc754792013-01-18 12:35:14 +0000287 data->next = (unsigned long)rom;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700288 else
Jan Beulichbc754792013-01-18 12:35:14 +0000289 params->hdr.setup_data = (unsigned long)rom;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700290
291 data = (struct setup_data *)rom;
292
293 continue;
294 free_struct:
Matt Fleming54b52d82014-01-10 15:27:14 +0000295 efi_early->call(efi_early->free_pool, rom);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700296 }
297
298free_handle:
Matt Fleming54b52d82014-01-10 15:27:14 +0000299 efi_early->call(efi_early->free_pool, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700300 return status;
301}
302
Matt Fleming291f3632011-12-12 21:27:52 +0000303/*
304 * See if we have Graphics Output Protocol
305 */
306static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,
307 unsigned long size)
308{
309 struct efi_graphics_output_protocol *gop, *first_gop;
310 struct efi_pixel_bitmask pixel_info;
311 unsigned long nr_gops;
312 efi_status_t status;
Matt Fleming54b52d82014-01-10 15:27:14 +0000313 void **gop_handle = NULL;
Matt Fleming291f3632011-12-12 21:27:52 +0000314 u16 width, height;
315 u32 fb_base, fb_size;
316 u32 pixels_per_scan_line;
317 int pixel_format;
318 int i;
319
Matt Fleming54b52d82014-01-10 15:27:14 +0000320 status = efi_early->call(efi_early->allocate_pool, EFI_LOADER_DATA,
321 size, (void **)&gop_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000322 if (status != EFI_SUCCESS)
323 return status;
324
Matt Fleming54b52d82014-01-10 15:27:14 +0000325 status = efi_early->call(efi_early->locate_handle,
326 EFI_LOCATE_BY_PROTOCOL,
327 proto, NULL, &size, gop_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000328 if (status != EFI_SUCCESS)
329 goto free_handle;
330
331 first_gop = NULL;
332
333 nr_gops = size / sizeof(void *);
334 for (i = 0; i < nr_gops; i++) {
335 struct efi_graphics_output_mode_info *info;
Matthew Garrett38cb5ef2012-07-26 18:00:27 -0400336 efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID;
337 bool conout_found = false;
338 void *dummy;
Matt Fleming291f3632011-12-12 21:27:52 +0000339 void *h = gop_handle[i];
340
Matt Fleming54b52d82014-01-10 15:27:14 +0000341 status = efi_early->call(efi_early->handle_protocol, h,
342 proto, (void **)&gop);
Matt Fleming291f3632011-12-12 21:27:52 +0000343 if (status != EFI_SUCCESS)
344 continue;
345
Matt Fleming54b52d82014-01-10 15:27:14 +0000346 status = efi_early->call(efi_early->handle_protocol, h,
347 &conout_proto, &dummy);
Matthew Garrett38cb5ef2012-07-26 18:00:27 -0400348 if (status == EFI_SUCCESS)
349 conout_found = true;
Matt Fleming291f3632011-12-12 21:27:52 +0000350
Matt Fleming54b52d82014-01-10 15:27:14 +0000351 status = efi_early->call((unsigned long)gop->query_mode, gop,
352 gop->mode->mode, &size, &info);
Matthew Garrett38cb5ef2012-07-26 18:00:27 -0400353 if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
Matt Fleming291f3632011-12-12 21:27:52 +0000354 /*
Matthew Garrett38cb5ef2012-07-26 18:00:27 -0400355 * Systems that use the UEFI Console Splitter may
356 * provide multiple GOP devices, not all of which are
357 * backed by real hardware. The workaround is to search
358 * for a GOP implementing the ConOut protocol, and if
359 * one isn't found, to just fall back to the first GOP.
Matt Fleming291f3632011-12-12 21:27:52 +0000360 */
361 width = info->horizontal_resolution;
362 height = info->vertical_resolution;
363 fb_base = gop->mode->frame_buffer_base;
364 fb_size = gop->mode->frame_buffer_size;
365 pixel_format = info->pixel_format;
366 pixel_info = info->pixel_information;
367 pixels_per_scan_line = info->pixels_per_scan_line;
368
369 /*
Matthew Garrett38cb5ef2012-07-26 18:00:27 -0400370 * Once we've found a GOP supporting ConOut,
Matt Fleming291f3632011-12-12 21:27:52 +0000371 * don't bother looking any further.
372 */
David Woodhouse70a479c2013-01-07 21:52:16 +0000373 first_gop = gop;
Matthew Garrett38cb5ef2012-07-26 18:00:27 -0400374 if (conout_found)
Matt Fleming291f3632011-12-12 21:27:52 +0000375 break;
Matt Fleming291f3632011-12-12 21:27:52 +0000376 }
377 }
378
379 /* Did we find any GOPs? */
380 if (!first_gop)
381 goto free_handle;
382
383 /* EFI framebuffer */
384 si->orig_video_isVGA = VIDEO_TYPE_EFI;
385
386 si->lfb_width = width;
387 si->lfb_height = height;
388 si->lfb_base = fb_base;
Matt Fleming291f3632011-12-12 21:27:52 +0000389 si->pages = 1;
390
391 if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {
392 si->lfb_depth = 32;
393 si->lfb_linelength = pixels_per_scan_line * 4;
394 si->red_size = 8;
395 si->red_pos = 0;
396 si->green_size = 8;
397 si->green_pos = 8;
398 si->blue_size = 8;
399 si->blue_pos = 16;
400 si->rsvd_size = 8;
401 si->rsvd_pos = 24;
402 } else if (pixel_format == PIXEL_BGR_RESERVED_8BIT_PER_COLOR) {
403 si->lfb_depth = 32;
404 si->lfb_linelength = pixels_per_scan_line * 4;
405 si->red_size = 8;
406 si->red_pos = 16;
407 si->green_size = 8;
408 si->green_pos = 8;
409 si->blue_size = 8;
410 si->blue_pos = 0;
411 si->rsvd_size = 8;
412 si->rsvd_pos = 24;
413 } else if (pixel_format == PIXEL_BIT_MASK) {
414 find_bits(pixel_info.red_mask, &si->red_pos, &si->red_size);
415 find_bits(pixel_info.green_mask, &si->green_pos,
416 &si->green_size);
417 find_bits(pixel_info.blue_mask, &si->blue_pos, &si->blue_size);
418 find_bits(pixel_info.reserved_mask, &si->rsvd_pos,
419 &si->rsvd_size);
420 si->lfb_depth = si->red_size + si->green_size +
421 si->blue_size + si->rsvd_size;
422 si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8;
423 } else {
424 si->lfb_depth = 4;
425 si->lfb_linelength = si->lfb_width / 2;
426 si->red_size = 0;
427 si->red_pos = 0;
428 si->green_size = 0;
429 si->green_pos = 0;
430 si->blue_size = 0;
431 si->blue_pos = 0;
432 si->rsvd_size = 0;
433 si->rsvd_pos = 0;
434 }
435
Matthew Garrette9b10952012-07-27 17:20:49 -0400436 si->lfb_size = si->lfb_linelength * si->lfb_height;
437
Matthew Garrettf462ed92012-07-27 12:58:53 -0400438 si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS;
439
Matt Fleming291f3632011-12-12 21:27:52 +0000440free_handle:
Matt Fleming54b52d82014-01-10 15:27:14 +0000441 efi_early->call(efi_early->free_pool, gop_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000442 return status;
443}
444
445/*
446 * See if we have Universal Graphics Adapter (UGA) protocol
447 */
448static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
449 unsigned long size)
450{
451 struct efi_uga_draw_protocol *uga, *first_uga;
452 unsigned long nr_ugas;
453 efi_status_t status;
454 u32 width, height;
455 void **uga_handle = NULL;
456 int i;
457
Matt Fleming54b52d82014-01-10 15:27:14 +0000458 status = efi_early->call(efi_early->allocate_pool, EFI_LOADER_DATA,
459 size, (void **)&uga_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000460 if (status != EFI_SUCCESS)
461 return status;
462
Matt Fleming54b52d82014-01-10 15:27:14 +0000463 status = efi_early->call(efi_early->locate_handle,
464 EFI_LOCATE_BY_PROTOCOL,
465 uga_proto, NULL, &size, uga_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000466 if (status != EFI_SUCCESS)
467 goto free_handle;
468
469 first_uga = NULL;
470
471 nr_ugas = size / sizeof(void *);
472 for (i = 0; i < nr_ugas; i++) {
473 efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
474 void *handle = uga_handle[i];
475 u32 w, h, depth, refresh;
476 void *pciio;
477
Matt Fleming54b52d82014-01-10 15:27:14 +0000478 status = efi_early->call(efi_early->handle_protocol, handle,
479 uga_proto, (void **)&uga);
Matt Fleming291f3632011-12-12 21:27:52 +0000480 if (status != EFI_SUCCESS)
481 continue;
482
Matt Fleming54b52d82014-01-10 15:27:14 +0000483 efi_early->call(efi_early->handle_protocol, handle,
484 &pciio_proto, &pciio);
Matt Fleming291f3632011-12-12 21:27:52 +0000485
Matt Fleming54b52d82014-01-10 15:27:14 +0000486 status = efi_early->call((unsigned long)uga->get_mode, uga,
487 &w, &h, &depth, &refresh);
Matt Fleming291f3632011-12-12 21:27:52 +0000488 if (status == EFI_SUCCESS && (!first_uga || pciio)) {
489 width = w;
490 height = h;
491
492 /*
493 * Once we've found a UGA supporting PCIIO,
494 * don't bother looking any further.
495 */
496 if (pciio)
497 break;
498
499 first_uga = uga;
500 }
501 }
502
503 if (!first_uga)
504 goto free_handle;
505
506 /* EFI framebuffer */
507 si->orig_video_isVGA = VIDEO_TYPE_EFI;
508
509 si->lfb_depth = 32;
510 si->lfb_width = width;
511 si->lfb_height = height;
512
513 si->red_size = 8;
514 si->red_pos = 16;
515 si->green_size = 8;
516 si->green_pos = 8;
517 si->blue_size = 8;
518 si->blue_pos = 0;
519 si->rsvd_size = 8;
520 si->rsvd_pos = 24;
521
522
523free_handle:
Matt Fleming54b52d82014-01-10 15:27:14 +0000524 efi_early->call(efi_early->free_pool, uga_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000525 return status;
526}
527
528void setup_graphics(struct boot_params *boot_params)
529{
530 efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
531 struct screen_info *si;
532 efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
533 efi_status_t status;
534 unsigned long size;
535 void **gop_handle = NULL;
536 void **uga_handle = NULL;
537
538 si = &boot_params->screen_info;
539 memset(si, 0, sizeof(*si));
540
541 size = 0;
Matt Fleming54b52d82014-01-10 15:27:14 +0000542 status = efi_early->call(efi_early->locate_handle,
543 EFI_LOCATE_BY_PROTOCOL,
544 &graphics_proto, NULL, &size, gop_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000545 if (status == EFI_BUFFER_TOO_SMALL)
546 status = setup_gop(si, &graphics_proto, size);
547
548 if (status != EFI_SUCCESS) {
549 size = 0;
Matt Fleming54b52d82014-01-10 15:27:14 +0000550 status = efi_early->call(efi_early->locate_handle,
551 EFI_LOCATE_BY_PROTOCOL,
552 &uga_proto, NULL, &size, uga_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000553 if (status == EFI_BUFFER_TOO_SMALL)
554 setup_uga(si, &uga_proto, size);
555 }
556}
557
Matt Fleming291f3632011-12-12 21:27:52 +0000558/*
559 * Because the x86 boot code expects to be passed a boot_params we
560 * need to create one ourselves (usually the bootloader would create
561 * one for us).
562 */
Matt Fleming54b52d82014-01-10 15:27:14 +0000563struct boot_params *make_boot_params(struct efi_config *c)
Matt Fleming291f3632011-12-12 21:27:52 +0000564{
Matt Fleming9ca8f722012-07-19 10:23:48 +0100565 struct boot_params *boot_params;
566 struct sys_desc_table *sdt;
567 struct apm_bios_info *bi;
568 struct setup_header *hdr;
569 struct efi_info *efi;
570 efi_loaded_image_t *image;
Matt Fleming54b52d82014-01-10 15:27:14 +0000571 void *options, *handle;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100572 efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
Matt Fleming291f3632011-12-12 21:27:52 +0000573 int options_size = 0;
574 efi_status_t status;
Roy Franz5fef3872013-09-22 15:45:33 -0700575 char *cmdline_ptr;
Matt Fleming291f3632011-12-12 21:27:52 +0000576 u16 *s2;
577 u8 *s1;
578 int i;
Roy Franz46f45822013-09-22 15:45:39 -0700579 unsigned long ramdisk_addr;
580 unsigned long ramdisk_size;
Matt Fleming291f3632011-12-12 21:27:52 +0000581
Matt Fleming54b52d82014-01-10 15:27:14 +0000582 efi_early = c;
583 sys_table = (efi_system_table_t *)(unsigned long)efi_early->table;
584 handle = (void *)(unsigned long)efi_early->image_handle;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100585
586 /* Check if we were booted by the EFI firmware */
587 if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
588 return NULL;
589
Matt Fleming54b52d82014-01-10 15:27:14 +0000590 if (efi_early->is64)
591 setup_boot_services64(efi_early);
592 else
593 setup_boot_services32(efi_early);
594
595 status = efi_early->call(efi_early->handle_protocol, handle,
596 &proto, (void *)&image);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100597 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700598 efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +0100599 return NULL;
600 }
601
Roy Franz40e45302013-09-22 15:45:29 -0700602 status = efi_low_alloc(sys_table, 0x4000, 1,
603 (unsigned long *)&boot_params);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100604 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700605 efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +0100606 return NULL;
607 }
608
609 memset(boot_params, 0x0, 0x4000);
610
611 hdr = &boot_params->hdr;
612 efi = &boot_params->efi_info;
613 bi = &boot_params->apm_bios_info;
614 sdt = &boot_params->sys_desc_table;
615
616 /* Copy the second sector to boot_params */
617 memcpy(&hdr->jump, image->image_base + 512, 512);
618
619 /*
620 * Fill out some of the header fields ourselves because the
621 * EFI firmware loader doesn't load the first sector.
622 */
623 hdr->root_flags = 1;
624 hdr->vid_mode = 0xffff;
625 hdr->boot_flag = 0xAA55;
626
627 hdr->code32_start = (__u64)(unsigned long)image->image_base;
628
Matt Fleming291f3632011-12-12 21:27:52 +0000629 hdr->type_of_loader = 0x21;
630
631 /* Convert unicode cmdline to ascii */
Roy Franz5fef3872013-09-22 15:45:33 -0700632 cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image,
633 &options_size);
634 if (!cmdline_ptr)
635 goto fail;
636 hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
Matt Fleming291f3632011-12-12 21:27:52 +0000637
638 hdr->ramdisk_image = 0;
639 hdr->ramdisk_size = 0;
640
Matt Fleming291f3632011-12-12 21:27:52 +0000641 /* Clear APM BIOS info */
642 memset(bi, 0, sizeof(*bi));
643
644 memset(sdt, 0, sizeof(*sdt));
645
Roy Franz46f45822013-09-22 15:45:39 -0700646 status = handle_cmdline_files(sys_table, image,
647 (char *)(unsigned long)hdr->cmd_line_ptr,
648 "initrd=", hdr->initrd_addr_max,
649 &ramdisk_addr, &ramdisk_size);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100650 if (status != EFI_SUCCESS)
651 goto fail2;
Roy Franz46f45822013-09-22 15:45:39 -0700652 hdr->ramdisk_image = ramdisk_addr;
653 hdr->ramdisk_size = ramdisk_size;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100654
655 return boot_params;
656fail2:
Roy Franz0e1cadb2013-09-22 15:45:38 -0700657 efi_free(sys_table, options_size, hdr->cmd_line_ptr);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100658fail:
Roy Franz40e45302013-09-22 15:45:29 -0700659 efi_free(sys_table, 0x4000, (unsigned long)boot_params);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100660 return NULL;
661}
662
Linn Crosettod2078d52013-09-22 19:59:08 -0600663static void add_e820ext(struct boot_params *params,
664 struct setup_data *e820ext, u32 nr_entries)
Matt Fleming9ca8f722012-07-19 10:23:48 +0100665{
Linn Crosettod2078d52013-09-22 19:59:08 -0600666 struct setup_data *data;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100667 efi_status_t status;
Linn Crosettod2078d52013-09-22 19:59:08 -0600668 unsigned long size;
669
670 e820ext->type = SETUP_E820_EXT;
671 e820ext->len = nr_entries * sizeof(struct e820entry);
672 e820ext->next = 0;
673
674 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
675
676 while (data && data->next)
677 data = (struct setup_data *)(unsigned long)data->next;
678
679 if (data)
680 data->next = (unsigned long)e820ext;
681 else
682 params->hdr.setup_data = (unsigned long)e820ext;
683}
684
685static efi_status_t setup_e820(struct boot_params *params,
686 struct setup_data *e820ext, u32 e820ext_size)
687{
688 struct e820entry *e820_map = &params->e820_map[0];
689 struct efi_info *efi = &params->efi_info;
690 struct e820entry *prev = NULL;
691 u32 nr_entries;
692 u32 nr_desc;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100693 int i;
Matt Fleming291f3632011-12-12 21:27:52 +0000694
Matt Fleming291f3632011-12-12 21:27:52 +0000695 nr_entries = 0;
Linn Crosettod2078d52013-09-22 19:59:08 -0600696 nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size;
697
698 for (i = 0; i < nr_desc; i++) {
Matt Fleming291f3632011-12-12 21:27:52 +0000699 efi_memory_desc_t *d;
700 unsigned int e820_type = 0;
Linn Crosettod2078d52013-09-22 19:59:08 -0600701 unsigned long m = efi->efi_memmap;
Matt Fleming291f3632011-12-12 21:27:52 +0000702
Linn Crosettod2078d52013-09-22 19:59:08 -0600703 d = (efi_memory_desc_t *)(m + (i * efi->efi_memdesc_size));
Matt Fleming291f3632011-12-12 21:27:52 +0000704 switch (d->type) {
705 case EFI_RESERVED_TYPE:
706 case EFI_RUNTIME_SERVICES_CODE:
707 case EFI_RUNTIME_SERVICES_DATA:
708 case EFI_MEMORY_MAPPED_IO:
709 case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
710 case EFI_PAL_CODE:
711 e820_type = E820_RESERVED;
712 break;
713
714 case EFI_UNUSABLE_MEMORY:
715 e820_type = E820_UNUSABLE;
716 break;
717
718 case EFI_ACPI_RECLAIM_MEMORY:
719 e820_type = E820_ACPI;
720 break;
721
722 case EFI_LOADER_CODE:
723 case EFI_LOADER_DATA:
724 case EFI_BOOT_SERVICES_CODE:
725 case EFI_BOOT_SERVICES_DATA:
726 case EFI_CONVENTIONAL_MEMORY:
727 e820_type = E820_RAM;
728 break;
729
730 case EFI_ACPI_MEMORY_NVS:
731 e820_type = E820_NVS;
732 break;
733
734 default:
735 continue;
736 }
737
738 /* Merge adjacent mappings */
739 if (prev && prev->type == e820_type &&
Linn Crosettod2078d52013-09-22 19:59:08 -0600740 (prev->addr + prev->size) == d->phys_addr) {
Matt Fleming291f3632011-12-12 21:27:52 +0000741 prev->size += d->num_pages << 12;
Linn Crosettod2078d52013-09-22 19:59:08 -0600742 continue;
Matt Fleming291f3632011-12-12 21:27:52 +0000743 }
Linn Crosettod2078d52013-09-22 19:59:08 -0600744
745 if (nr_entries == ARRAY_SIZE(params->e820_map)) {
746 u32 need = (nr_desc - i) * sizeof(struct e820entry) +
747 sizeof(struct setup_data);
748
749 if (!e820ext || e820ext_size < need)
750 return EFI_BUFFER_TOO_SMALL;
751
752 /* boot_params map full, switch to e820 extended */
753 e820_map = (struct e820entry *)e820ext->data;
754 }
755
756 e820_map->addr = d->phys_addr;
757 e820_map->size = d->num_pages << PAGE_SHIFT;
758 e820_map->type = e820_type;
759 prev = e820_map++;
760 nr_entries++;
Matt Fleming291f3632011-12-12 21:27:52 +0000761 }
762
Linn Crosettod2078d52013-09-22 19:59:08 -0600763 if (nr_entries > ARRAY_SIZE(params->e820_map)) {
764 u32 nr_e820ext = nr_entries - ARRAY_SIZE(params->e820_map);
765
766 add_e820ext(params, e820ext, nr_e820ext);
767 nr_entries -= nr_e820ext;
768 }
769
770 params->e820_entries = (u8)nr_entries;
771
772 return EFI_SUCCESS;
773}
774
775static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
776 u32 *e820ext_size)
777{
778 efi_status_t status;
779 unsigned long size;
780
781 size = sizeof(struct setup_data) +
782 sizeof(struct e820entry) * nr_desc;
783
784 if (*e820ext) {
Matt Fleming54b52d82014-01-10 15:27:14 +0000785 efi_early->call(efi_early->free_pool, *e820ext);
Linn Crosettod2078d52013-09-22 19:59:08 -0600786 *e820ext = NULL;
787 *e820ext_size = 0;
788 }
789
Matt Fleming54b52d82014-01-10 15:27:14 +0000790 status = efi_early->call(efi_early->allocate_pool, EFI_LOADER_DATA,
791 size, (void **)e820ext);
Linn Crosettod2078d52013-09-22 19:59:08 -0600792 if (status == EFI_SUCCESS)
793 *e820ext_size = size;
794
795 return status;
796}
797
798static efi_status_t exit_boot(struct boot_params *boot_params,
799 void *handle)
800{
801 struct efi_info *efi = &boot_params->efi_info;
802 unsigned long map_sz, key, desc_size;
803 efi_memory_desc_t *mem_map;
804 struct setup_data *e820ext;
805 __u32 e820ext_size;
806 __u32 nr_desc, prev_nr_desc;
807 efi_status_t status;
808 __u32 desc_version;
809 bool called_exit = false;
810 u8 nr_entries;
811 int i;
812
813 nr_desc = 0;
814 e820ext = NULL;
815 e820ext_size = 0;
816
817get_map:
818 status = efi_get_memory_map(sys_table, &mem_map, &map_sz, &desc_size,
819 &desc_version, &key);
820
821 if (status != EFI_SUCCESS)
822 return status;
823
824 prev_nr_desc = nr_desc;
825 nr_desc = map_sz / desc_size;
826 if (nr_desc > prev_nr_desc &&
827 nr_desc > ARRAY_SIZE(boot_params->e820_map)) {
828 u32 nr_e820ext = nr_desc - ARRAY_SIZE(boot_params->e820_map);
829
830 status = alloc_e820ext(nr_e820ext, &e820ext, &e820ext_size);
831 if (status != EFI_SUCCESS)
832 goto free_mem_map;
833
Matt Fleming54b52d82014-01-10 15:27:14 +0000834 efi_early->call(efi_early->free_pool, mem_map);
Linn Crosettod2078d52013-09-22 19:59:08 -0600835 goto get_map; /* Allocated memory, get map again */
836 }
837
838 memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32));
839 efi->efi_systab = (unsigned long)sys_table;
840 efi->efi_memdesc_size = desc_size;
841 efi->efi_memdesc_version = desc_version;
842 efi->efi_memmap = (unsigned long)mem_map;
843 efi->efi_memmap_size = map_sz;
844
845#ifdef CONFIG_X86_64
846 efi->efi_systab_hi = (unsigned long)sys_table >> 32;
847 efi->efi_memmap_hi = (unsigned long)mem_map >> 32;
848#endif
849
850 /* Might as well exit boot services now */
Matt Fleming54b52d82014-01-10 15:27:14 +0000851 status = efi_early->call(efi_early->exit_boot_services, handle, key);
Linn Crosettod2078d52013-09-22 19:59:08 -0600852 if (status != EFI_SUCCESS) {
853 /*
854 * ExitBootServices() will fail if any of the event
855 * handlers change the memory map. In which case, we
856 * must be prepared to retry, but only once so that
857 * we're guaranteed to exit on repeated failures instead
858 * of spinning forever.
859 */
860 if (called_exit)
861 goto free_mem_map;
862
863 called_exit = true;
Matt Fleming54b52d82014-01-10 15:27:14 +0000864 efi_early->call(efi_early->free_pool, mem_map);
Linn Crosettod2078d52013-09-22 19:59:08 -0600865 goto get_map;
866 }
867
868 /* Historic? */
869 boot_params->alt_mem_k = 32 * 1024;
870
871 status = setup_e820(boot_params, e820ext, e820ext_size);
872 if (status != EFI_SUCCESS)
873 return status;
Matt Fleming291f3632011-12-12 21:27:52 +0000874
875 return EFI_SUCCESS;
876
877free_mem_map:
Matt Fleming54b52d82014-01-10 15:27:14 +0000878 efi_early->call(efi_early->free_pool, mem_map);
Matt Fleming291f3632011-12-12 21:27:52 +0000879 return status;
880}
881
Matt Fleming9ca8f722012-07-19 10:23:48 +0100882/*
883 * On success we return a pointer to a boot_params structure, and NULL
884 * on failure.
885 */
Matt Fleming54b52d82014-01-10 15:27:14 +0000886struct boot_params *efi_main(struct efi_config *c,
Matt Fleming9ca8f722012-07-19 10:23:48 +0100887 struct boot_params *boot_params)
888{
Matt Fleming54b52d82014-01-10 15:27:14 +0000889 struct desc_ptr *gdt = NULL;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100890 efi_loaded_image_t *image;
891 struct setup_header *hdr = &boot_params->hdr;
892 efi_status_t status;
893 struct desc_struct *desc;
Matt Fleming54b52d82014-01-10 15:27:14 +0000894 void *handle;
895 efi_system_table_t *_table;
896 bool is64;
897
898 efi_early = c;
899
900 _table = (efi_system_table_t *)(unsigned long)efi_early->table;
901 handle = (void *)(unsigned long)efi_early->image_handle;
902 is64 = efi_early->is64;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100903
904 sys_table = _table;
905
906 /* Check if we were booted by the EFI firmware */
907 if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
908 goto fail;
909
Matt Fleming54b52d82014-01-10 15:27:14 +0000910 if (is64)
911 setup_boot_services64(efi_early);
912 else
913 setup_boot_services32(efi_early);
914
Matt Fleming9ca8f722012-07-19 10:23:48 +0100915 setup_graphics(boot_params);
Matt Fleming291f3632011-12-12 21:27:52 +0000916
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700917 setup_efi_pci(boot_params);
918
Matt Fleming54b52d82014-01-10 15:27:14 +0000919 status = efi_early->call(efi_early->allocate_pool, EFI_LOADER_DATA,
920 sizeof(*gdt), (void **)&gdt);
Matt Fleming9fa7ded2012-02-20 13:20:59 +0000921 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700922 efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
Matt Fleming291f3632011-12-12 21:27:52 +0000923 goto fail;
Matt Fleming9fa7ded2012-02-20 13:20:59 +0000924 }
Matt Fleming291f3632011-12-12 21:27:52 +0000925
926 gdt->size = 0x800;
Roy Franz40e45302013-09-22 15:45:29 -0700927 status = efi_low_alloc(sys_table, gdt->size, 8,
Roy Franz876dc362013-09-22 15:45:28 -0700928 (unsigned long *)&gdt->address);
Matt Fleming9fa7ded2012-02-20 13:20:59 +0000929 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700930 efi_printk(sys_table, "Failed to alloc mem for gdt\n");
Matt Fleming291f3632011-12-12 21:27:52 +0000931 goto fail;
Matt Fleming9fa7ded2012-02-20 13:20:59 +0000932 }
Matt Fleming291f3632011-12-12 21:27:52 +0000933
Matt Fleming9ca8f722012-07-19 10:23:48 +0100934 /*
935 * If the kernel isn't already loaded at the preferred load
936 * address, relocate it.
937 */
938 if (hdr->pref_address != hdr->code32_start) {
Roy Franz4a9f3a72013-09-22 15:45:32 -0700939 unsigned long bzimage_addr = hdr->code32_start;
940 status = efi_relocate_kernel(sys_table, &bzimage_addr,
941 hdr->init_size, hdr->init_size,
942 hdr->pref_address,
943 hdr->kernel_alignment);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100944 if (status != EFI_SUCCESS)
945 goto fail;
Roy Franz4a9f3a72013-09-22 15:45:32 -0700946
947 hdr->pref_address = hdr->code32_start;
948 hdr->code32_start = bzimage_addr;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100949 }
950
951 status = exit_boot(boot_params, handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000952 if (status != EFI_SUCCESS)
953 goto fail;
954
955 memset((char *)gdt->address, 0x0, gdt->size);
956 desc = (struct desc_struct *)gdt->address;
957
958 /* The first GDT is a dummy and the second is unused. */
959 desc += 2;
960
961 desc->limit0 = 0xffff;
962 desc->base0 = 0x0000;
963 desc->base1 = 0x0000;
964 desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
965 desc->s = DESC_TYPE_CODE_DATA;
966 desc->dpl = 0;
967 desc->p = 1;
968 desc->limit = 0xf;
969 desc->avl = 0;
970 desc->l = 0;
971 desc->d = SEG_OP_SIZE_32BIT;
972 desc->g = SEG_GRANULARITY_4KB;
973 desc->base2 = 0x00;
974
975 desc++;
976 desc->limit0 = 0xffff;
977 desc->base0 = 0x0000;
978 desc->base1 = 0x0000;
979 desc->type = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
980 desc->s = DESC_TYPE_CODE_DATA;
981 desc->dpl = 0;
982 desc->p = 1;
983 desc->limit = 0xf;
984 desc->avl = 0;
985 desc->l = 0;
986 desc->d = SEG_OP_SIZE_32BIT;
987 desc->g = SEG_GRANULARITY_4KB;
988 desc->base2 = 0x00;
989
990#ifdef CONFIG_X86_64
991 /* Task segment value */
992 desc++;
993 desc->limit0 = 0x0000;
994 desc->base0 = 0x0000;
995 desc->base1 = 0x0000;
996 desc->type = SEG_TYPE_TSS;
997 desc->s = 0;
998 desc->dpl = 0;
999 desc->p = 1;
1000 desc->limit = 0x0;
1001 desc->avl = 0;
1002 desc->l = 0;
1003 desc->d = 0;
1004 desc->g = SEG_GRANULARITY_4KB;
1005 desc->base2 = 0x00;
1006#endif /* CONFIG_X86_64 */
1007
Matt Fleming291f3632011-12-12 21:27:52 +00001008 asm volatile("cli");
Bart Kuivenhoven0ce6cda2013-09-23 11:45:28 +02001009 asm volatile ("lgdt %0" : : "m" (*gdt));
Matt Fleming291f3632011-12-12 21:27:52 +00001010
1011 return boot_params;
1012fail:
1013 return NULL;
1014}