Commit | Line | Data |
---|---|---|
291f3632 MF |
1 | /* ----------------------------------------------------------------------- |
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> | |
dd5fc854 | 11 | #include <linux/pci.h> |
291f3632 MF |
12 | #include <asm/efi.h> |
13 | #include <asm/setup.h> | |
14 | #include <asm/desc.h> | |
15 | ||
0f905a43 MF |
16 | #undef memcpy /* Use memcpy from misc.c */ |
17 | ||
291f3632 MF |
18 | #include "eboot.h" |
19 | ||
20 | static efi_system_table_t *sys_table; | |
21 | ||
291f3632 | 22 | |
7721da4c | 23 | #include "../../../../drivers/firmware/efi/efi-stub-helper.c" |
291f3632 | 24 | |
291f3632 | 25 | |
291f3632 MF |
26 | |
27 | static void find_bits(unsigned long mask, u8 *pos, u8 *size) | |
28 | { | |
29 | u8 first, len; | |
30 | ||
31 | first = 0; | |
32 | len = 0; | |
33 | ||
34 | if (mask) { | |
35 | while (!(mask & 0x1)) { | |
36 | mask = mask >> 1; | |
37 | first++; | |
38 | } | |
39 | ||
40 | while (mask & 0x1) { | |
41 | mask = mask >> 1; | |
42 | len++; | |
43 | } | |
44 | } | |
45 | ||
46 | *pos = first; | |
47 | *size = len; | |
48 | } | |
49 | ||
dd5fc854 MG |
50 | static efi_status_t setup_efi_pci(struct boot_params *params) |
51 | { | |
52 | efi_pci_io_protocol *pci; | |
53 | efi_status_t status; | |
54 | void **pci_handle; | |
55 | efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; | |
56 | unsigned long nr_pci, size = 0; | |
57 | int i; | |
58 | struct setup_data *data; | |
59 | ||
bc754790 | 60 | data = (struct setup_data *)(unsigned long)params->hdr.setup_data; |
dd5fc854 MG |
61 | |
62 | while (data && data->next) | |
bc754790 | 63 | data = (struct setup_data *)(unsigned long)data->next; |
dd5fc854 MG |
64 | |
65 | status = efi_call_phys5(sys_table->boottime->locate_handle, | |
66 | EFI_LOCATE_BY_PROTOCOL, &pci_proto, | |
67 | NULL, &size, pci_handle); | |
68 | ||
69 | if (status == EFI_BUFFER_TOO_SMALL) { | |
70 | status = efi_call_phys3(sys_table->boottime->allocate_pool, | |
71 | EFI_LOADER_DATA, size, &pci_handle); | |
72 | ||
73 | if (status != EFI_SUCCESS) | |
74 | return status; | |
75 | ||
76 | status = efi_call_phys5(sys_table->boottime->locate_handle, | |
77 | EFI_LOCATE_BY_PROTOCOL, &pci_proto, | |
78 | NULL, &size, pci_handle); | |
79 | } | |
80 | ||
81 | if (status != EFI_SUCCESS) | |
82 | goto free_handle; | |
83 | ||
84 | nr_pci = size / sizeof(void *); | |
85 | for (i = 0; i < nr_pci; i++) { | |
86 | void *h = pci_handle[i]; | |
87 | uint64_t attributes; | |
88 | struct pci_setup_rom *rom; | |
89 | ||
90 | status = efi_call_phys3(sys_table->boottime->handle_protocol, | |
91 | h, &pci_proto, &pci); | |
92 | ||
93 | if (status != EFI_SUCCESS) | |
94 | continue; | |
95 | ||
96 | if (!pci) | |
97 | continue; | |
98 | ||
b607e212 | 99 | #ifdef CONFIG_X86_64 |
dd5fc854 MG |
100 | status = efi_call_phys4(pci->attributes, pci, |
101 | EfiPciIoAttributeOperationGet, 0, | |
102 | &attributes); | |
b607e212 DW |
103 | #else |
104 | status = efi_call_phys5(pci->attributes, pci, | |
105 | EfiPciIoAttributeOperationGet, 0, 0, | |
106 | &attributes); | |
107 | #endif | |
dd5fc854 MG |
108 | if (status != EFI_SUCCESS) |
109 | continue; | |
110 | ||
dd5fc854 MG |
111 | if (!pci->romimage || !pci->romsize) |
112 | continue; | |
113 | ||
114 | size = pci->romsize + sizeof(*rom); | |
115 | ||
116 | status = efi_call_phys3(sys_table->boottime->allocate_pool, | |
117 | EFI_LOADER_DATA, size, &rom); | |
118 | ||
119 | if (status != EFI_SUCCESS) | |
120 | continue; | |
121 | ||
122 | rom->data.type = SETUP_PCI; | |
123 | rom->data.len = size - sizeof(struct setup_data); | |
124 | rom->data.next = 0; | |
125 | rom->pcilen = pci->romsize; | |
126 | ||
127 | status = efi_call_phys5(pci->pci.read, pci, | |
128 | EfiPciIoWidthUint16, PCI_VENDOR_ID, | |
129 | 1, &(rom->vendor)); | |
130 | ||
131 | if (status != EFI_SUCCESS) | |
132 | goto free_struct; | |
133 | ||
134 | status = efi_call_phys5(pci->pci.read, pci, | |
135 | EfiPciIoWidthUint16, PCI_DEVICE_ID, | |
136 | 1, &(rom->devid)); | |
137 | ||
138 | if (status != EFI_SUCCESS) | |
139 | goto free_struct; | |
140 | ||
141 | status = efi_call_phys5(pci->get_location, pci, | |
142 | &(rom->segment), &(rom->bus), | |
143 | &(rom->device), &(rom->function)); | |
144 | ||
145 | if (status != EFI_SUCCESS) | |
146 | goto free_struct; | |
147 | ||
148 | memcpy(rom->romdata, pci->romimage, pci->romsize); | |
149 | ||
150 | if (data) | |
bc754790 | 151 | data->next = (unsigned long)rom; |
dd5fc854 | 152 | else |
bc754790 | 153 | params->hdr.setup_data = (unsigned long)rom; |
dd5fc854 MG |
154 | |
155 | data = (struct setup_data *)rom; | |
156 | ||
157 | continue; | |
158 | free_struct: | |
159 | efi_call_phys1(sys_table->boottime->free_pool, rom); | |
160 | } | |
161 | ||
162 | free_handle: | |
163 | efi_call_phys1(sys_table->boottime->free_pool, pci_handle); | |
164 | return status; | |
165 | } | |
166 | ||
291f3632 MF |
167 | /* |
168 | * See if we have Graphics Output Protocol | |
169 | */ | |
170 | static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto, | |
171 | unsigned long size) | |
172 | { | |
173 | struct efi_graphics_output_protocol *gop, *first_gop; | |
174 | struct efi_pixel_bitmask pixel_info; | |
175 | unsigned long nr_gops; | |
176 | efi_status_t status; | |
177 | void **gop_handle; | |
178 | u16 width, height; | |
179 | u32 fb_base, fb_size; | |
180 | u32 pixels_per_scan_line; | |
181 | int pixel_format; | |
182 | int i; | |
183 | ||
184 | status = efi_call_phys3(sys_table->boottime->allocate_pool, | |
185 | EFI_LOADER_DATA, size, &gop_handle); | |
186 | if (status != EFI_SUCCESS) | |
187 | return status; | |
188 | ||
189 | status = efi_call_phys5(sys_table->boottime->locate_handle, | |
190 | EFI_LOCATE_BY_PROTOCOL, proto, | |
191 | NULL, &size, gop_handle); | |
192 | if (status != EFI_SUCCESS) | |
193 | goto free_handle; | |
194 | ||
195 | first_gop = NULL; | |
196 | ||
197 | nr_gops = size / sizeof(void *); | |
198 | for (i = 0; i < nr_gops; i++) { | |
199 | struct efi_graphics_output_mode_info *info; | |
38cb5ef4 MG |
200 | efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; |
201 | bool conout_found = false; | |
202 | void *dummy; | |
291f3632 MF |
203 | void *h = gop_handle[i]; |
204 | ||
205 | status = efi_call_phys3(sys_table->boottime->handle_protocol, | |
206 | h, proto, &gop); | |
207 | if (status != EFI_SUCCESS) | |
208 | continue; | |
209 | ||
38cb5ef4 MG |
210 | status = efi_call_phys3(sys_table->boottime->handle_protocol, |
211 | h, &conout_proto, &dummy); | |
212 | ||
213 | if (status == EFI_SUCCESS) | |
214 | conout_found = true; | |
291f3632 MF |
215 | |
216 | status = efi_call_phys4(gop->query_mode, gop, | |
217 | gop->mode->mode, &size, &info); | |
38cb5ef4 | 218 | if (status == EFI_SUCCESS && (!first_gop || conout_found)) { |
291f3632 | 219 | /* |
38cb5ef4 MG |
220 | * Systems that use the UEFI Console Splitter may |
221 | * provide multiple GOP devices, not all of which are | |
222 | * backed by real hardware. The workaround is to search | |
223 | * for a GOP implementing the ConOut protocol, and if | |
224 | * one isn't found, to just fall back to the first GOP. | |
291f3632 MF |
225 | */ |
226 | width = info->horizontal_resolution; | |
227 | height = info->vertical_resolution; | |
228 | fb_base = gop->mode->frame_buffer_base; | |
229 | fb_size = gop->mode->frame_buffer_size; | |
230 | pixel_format = info->pixel_format; | |
231 | pixel_info = info->pixel_information; | |
232 | pixels_per_scan_line = info->pixels_per_scan_line; | |
233 | ||
234 | /* | |
38cb5ef4 | 235 | * Once we've found a GOP supporting ConOut, |
291f3632 MF |
236 | * don't bother looking any further. |
237 | */ | |
70a479cb | 238 | first_gop = gop; |
38cb5ef4 | 239 | if (conout_found) |
291f3632 | 240 | break; |
291f3632 MF |
241 | } |
242 | } | |
243 | ||
244 | /* Did we find any GOPs? */ | |
245 | if (!first_gop) | |
246 | goto free_handle; | |
247 | ||
248 | /* EFI framebuffer */ | |
249 | si->orig_video_isVGA = VIDEO_TYPE_EFI; | |
250 | ||
251 | si->lfb_width = width; | |
252 | si->lfb_height = height; | |
253 | si->lfb_base = fb_base; | |
291f3632 MF |
254 | si->pages = 1; |
255 | ||
256 | if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) { | |
257 | si->lfb_depth = 32; | |
258 | si->lfb_linelength = pixels_per_scan_line * 4; | |
259 | si->red_size = 8; | |
260 | si->red_pos = 0; | |
261 | si->green_size = 8; | |
262 | si->green_pos = 8; | |
263 | si->blue_size = 8; | |
264 | si->blue_pos = 16; | |
265 | si->rsvd_size = 8; | |
266 | si->rsvd_pos = 24; | |
267 | } else if (pixel_format == PIXEL_BGR_RESERVED_8BIT_PER_COLOR) { | |
268 | si->lfb_depth = 32; | |
269 | si->lfb_linelength = pixels_per_scan_line * 4; | |
270 | si->red_size = 8; | |
271 | si->red_pos = 16; | |
272 | si->green_size = 8; | |
273 | si->green_pos = 8; | |
274 | si->blue_size = 8; | |
275 | si->blue_pos = 0; | |
276 | si->rsvd_size = 8; | |
277 | si->rsvd_pos = 24; | |
278 | } else if (pixel_format == PIXEL_BIT_MASK) { | |
279 | find_bits(pixel_info.red_mask, &si->red_pos, &si->red_size); | |
280 | find_bits(pixel_info.green_mask, &si->green_pos, | |
281 | &si->green_size); | |
282 | find_bits(pixel_info.blue_mask, &si->blue_pos, &si->blue_size); | |
283 | find_bits(pixel_info.reserved_mask, &si->rsvd_pos, | |
284 | &si->rsvd_size); | |
285 | si->lfb_depth = si->red_size + si->green_size + | |
286 | si->blue_size + si->rsvd_size; | |
287 | si->lfb_linelength = (pixels_per_scan_line * si->lfb_depth) / 8; | |
288 | } else { | |
289 | si->lfb_depth = 4; | |
290 | si->lfb_linelength = si->lfb_width / 2; | |
291 | si->red_size = 0; | |
292 | si->red_pos = 0; | |
293 | si->green_size = 0; | |
294 | si->green_pos = 0; | |
295 | si->blue_size = 0; | |
296 | si->blue_pos = 0; | |
297 | si->rsvd_size = 0; | |
298 | si->rsvd_pos = 0; | |
299 | } | |
300 | ||
e9b10953 MG |
301 | si->lfb_size = si->lfb_linelength * si->lfb_height; |
302 | ||
f462ed93 MG |
303 | si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; |
304 | ||
291f3632 MF |
305 | free_handle: |
306 | efi_call_phys1(sys_table->boottime->free_pool, gop_handle); | |
307 | return status; | |
308 | } | |
309 | ||
310 | /* | |
311 | * See if we have Universal Graphics Adapter (UGA) protocol | |
312 | */ | |
313 | static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto, | |
314 | unsigned long size) | |
315 | { | |
316 | struct efi_uga_draw_protocol *uga, *first_uga; | |
317 | unsigned long nr_ugas; | |
318 | efi_status_t status; | |
319 | u32 width, height; | |
320 | void **uga_handle = NULL; | |
321 | int i; | |
322 | ||
323 | status = efi_call_phys3(sys_table->boottime->allocate_pool, | |
324 | EFI_LOADER_DATA, size, &uga_handle); | |
325 | if (status != EFI_SUCCESS) | |
326 | return status; | |
327 | ||
328 | status = efi_call_phys5(sys_table->boottime->locate_handle, | |
329 | EFI_LOCATE_BY_PROTOCOL, uga_proto, | |
330 | NULL, &size, uga_handle); | |
331 | if (status != EFI_SUCCESS) | |
332 | goto free_handle; | |
333 | ||
334 | first_uga = NULL; | |
335 | ||
336 | nr_ugas = size / sizeof(void *); | |
337 | for (i = 0; i < nr_ugas; i++) { | |
338 | efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID; | |
339 | void *handle = uga_handle[i]; | |
340 | u32 w, h, depth, refresh; | |
341 | void *pciio; | |
342 | ||
343 | status = efi_call_phys3(sys_table->boottime->handle_protocol, | |
344 | handle, uga_proto, &uga); | |
345 | if (status != EFI_SUCCESS) | |
346 | continue; | |
347 | ||
348 | efi_call_phys3(sys_table->boottime->handle_protocol, | |
349 | handle, &pciio_proto, &pciio); | |
350 | ||
351 | status = efi_call_phys5(uga->get_mode, uga, &w, &h, | |
352 | &depth, &refresh); | |
353 | if (status == EFI_SUCCESS && (!first_uga || pciio)) { | |
354 | width = w; | |
355 | height = h; | |
356 | ||
357 | /* | |
358 | * Once we've found a UGA supporting PCIIO, | |
359 | * don't bother looking any further. | |
360 | */ | |
361 | if (pciio) | |
362 | break; | |
363 | ||
364 | first_uga = uga; | |
365 | } | |
366 | } | |
367 | ||
368 | if (!first_uga) | |
369 | goto free_handle; | |
370 | ||
371 | /* EFI framebuffer */ | |
372 | si->orig_video_isVGA = VIDEO_TYPE_EFI; | |
373 | ||
374 | si->lfb_depth = 32; | |
375 | si->lfb_width = width; | |
376 | si->lfb_height = height; | |
377 | ||
378 | si->red_size = 8; | |
379 | si->red_pos = 16; | |
380 | si->green_size = 8; | |
381 | si->green_pos = 8; | |
382 | si->blue_size = 8; | |
383 | si->blue_pos = 0; | |
384 | si->rsvd_size = 8; | |
385 | si->rsvd_pos = 24; | |
386 | ||
387 | ||
388 | free_handle: | |
389 | efi_call_phys1(sys_table->boottime->free_pool, uga_handle); | |
390 | return status; | |
391 | } | |
392 | ||
393 | void setup_graphics(struct boot_params *boot_params) | |
394 | { | |
395 | efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; | |
396 | struct screen_info *si; | |
397 | efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID; | |
398 | efi_status_t status; | |
399 | unsigned long size; | |
400 | void **gop_handle = NULL; | |
401 | void **uga_handle = NULL; | |
402 | ||
403 | si = &boot_params->screen_info; | |
404 | memset(si, 0, sizeof(*si)); | |
405 | ||
406 | size = 0; | |
407 | status = efi_call_phys5(sys_table->boottime->locate_handle, | |
408 | EFI_LOCATE_BY_PROTOCOL, &graphics_proto, | |
409 | NULL, &size, gop_handle); | |
410 | if (status == EFI_BUFFER_TOO_SMALL) | |
411 | status = setup_gop(si, &graphics_proto, size); | |
412 | ||
413 | if (status != EFI_SUCCESS) { | |
414 | size = 0; | |
415 | status = efi_call_phys5(sys_table->boottime->locate_handle, | |
416 | EFI_LOCATE_BY_PROTOCOL, &uga_proto, | |
417 | NULL, &size, uga_handle); | |
418 | if (status == EFI_BUFFER_TOO_SMALL) | |
419 | setup_uga(si, &uga_proto, size); | |
420 | } | |
421 | } | |
422 | ||
291f3632 MF |
423 | |
424 | /* | |
425 | * Because the x86 boot code expects to be passed a boot_params we | |
426 | * need to create one ourselves (usually the bootloader would create | |
427 | * one for us). | |
428 | */ | |
9ca8f72a | 429 | struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table) |
291f3632 | 430 | { |
9ca8f72a MF |
431 | struct boot_params *boot_params; |
432 | struct sys_desc_table *sdt; | |
433 | struct apm_bios_info *bi; | |
434 | struct setup_header *hdr; | |
435 | struct efi_info *efi; | |
436 | efi_loaded_image_t *image; | |
437 | void *options; | |
9ca8f72a | 438 | efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; |
291f3632 MF |
439 | int options_size = 0; |
440 | efi_status_t status; | |
5fef3870 | 441 | char *cmdline_ptr; |
291f3632 MF |
442 | u16 *s2; |
443 | u8 *s1; | |
444 | int i; | |
46f4582e RF |
445 | unsigned long ramdisk_addr; |
446 | unsigned long ramdisk_size; | |
291f3632 | 447 | |
9ca8f72a MF |
448 | sys_table = _table; |
449 | ||
450 | /* Check if we were booted by the EFI firmware */ | |
451 | if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) | |
452 | return NULL; | |
453 | ||
454 | status = efi_call_phys3(sys_table->boottime->handle_protocol, | |
455 | handle, &proto, (void *)&image); | |
456 | if (status != EFI_SUCCESS) { | |
876dc36a | 457 | efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); |
9ca8f72a MF |
458 | return NULL; |
459 | } | |
460 | ||
40e4530a RF |
461 | status = efi_low_alloc(sys_table, 0x4000, 1, |
462 | (unsigned long *)&boot_params); | |
9ca8f72a | 463 | if (status != EFI_SUCCESS) { |
876dc36a | 464 | efi_printk(sys_table, "Failed to alloc lowmem for boot params\n"); |
9ca8f72a MF |
465 | return NULL; |
466 | } | |
467 | ||
468 | memset(boot_params, 0x0, 0x4000); | |
469 | ||
470 | hdr = &boot_params->hdr; | |
471 | efi = &boot_params->efi_info; | |
472 | bi = &boot_params->apm_bios_info; | |
473 | sdt = &boot_params->sys_desc_table; | |
474 | ||
475 | /* Copy the second sector to boot_params */ | |
476 | memcpy(&hdr->jump, image->image_base + 512, 512); | |
477 | ||
478 | /* | |
479 | * Fill out some of the header fields ourselves because the | |
480 | * EFI firmware loader doesn't load the first sector. | |
481 | */ | |
482 | hdr->root_flags = 1; | |
483 | hdr->vid_mode = 0xffff; | |
484 | hdr->boot_flag = 0xAA55; | |
485 | ||
486 | hdr->code32_start = (__u64)(unsigned long)image->image_base; | |
487 | ||
291f3632 MF |
488 | hdr->type_of_loader = 0x21; |
489 | ||
490 | /* Convert unicode cmdline to ascii */ | |
5fef3870 RF |
491 | cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image, |
492 | &options_size); | |
493 | if (!cmdline_ptr) | |
494 | goto fail; | |
495 | hdr->cmd_line_ptr = (unsigned long)cmdline_ptr; | |
291f3632 MF |
496 | |
497 | hdr->ramdisk_image = 0; | |
498 | hdr->ramdisk_size = 0; | |
499 | ||
291f3632 MF |
500 | /* Clear APM BIOS info */ |
501 | memset(bi, 0, sizeof(*bi)); | |
502 | ||
503 | memset(sdt, 0, sizeof(*sdt)); | |
504 | ||
46f4582e RF |
505 | status = handle_cmdline_files(sys_table, image, |
506 | (char *)(unsigned long)hdr->cmd_line_ptr, | |
507 | "initrd=", hdr->initrd_addr_max, | |
508 | &ramdisk_addr, &ramdisk_size); | |
9ca8f72a MF |
509 | if (status != EFI_SUCCESS) |
510 | goto fail2; | |
46f4582e RF |
511 | hdr->ramdisk_image = ramdisk_addr; |
512 | hdr->ramdisk_size = ramdisk_size; | |
9ca8f72a MF |
513 | |
514 | return boot_params; | |
515 | fail2: | |
0e1cadb0 | 516 | efi_free(sys_table, options_size, hdr->cmd_line_ptr); |
9ca8f72a | 517 | fail: |
40e4530a | 518 | efi_free(sys_table, 0x4000, (unsigned long)boot_params); |
9ca8f72a MF |
519 | return NULL; |
520 | } | |
521 | ||
522 | static efi_status_t exit_boot(struct boot_params *boot_params, | |
523 | void *handle) | |
524 | { | |
525 | struct efi_info *efi = &boot_params->efi_info; | |
526 | struct e820entry *e820_map = &boot_params->e820_map[0]; | |
527 | struct e820entry *prev = NULL; | |
528 | unsigned long size, key, desc_size, _size; | |
529 | efi_memory_desc_t *mem_map; | |
530 | efi_status_t status; | |
531 | __u32 desc_version; | |
d3768d88 | 532 | bool called_exit = false; |
9ca8f72a MF |
533 | u8 nr_entries; |
534 | int i; | |
291f3632 | 535 | |
d3768d88 | 536 | get_map: |
ae8e9060 RF |
537 | status = efi_get_memory_map(sys_table, &mem_map, &size, &desc_size, |
538 | &desc_version, &key); | |
291f3632 MF |
539 | |
540 | if (status != EFI_SUCCESS) | |
ae8e9060 | 541 | return status; |
291f3632 | 542 | |
9ca8f72a | 543 | memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32)); |
291f3632 MF |
544 | efi->efi_systab = (unsigned long)sys_table; |
545 | efi->efi_memdesc_size = desc_size; | |
546 | efi->efi_memdesc_version = desc_version; | |
547 | efi->efi_memmap = (unsigned long)mem_map; | |
548 | efi->efi_memmap_size = size; | |
549 | ||
550 | #ifdef CONFIG_X86_64 | |
551 | efi->efi_systab_hi = (unsigned long)sys_table >> 32; | |
552 | efi->efi_memmap_hi = (unsigned long)mem_map >> 32; | |
553 | #endif | |
554 | ||
555 | /* Might as well exit boot services now */ | |
556 | status = efi_call_phys2(sys_table->boottime->exit_boot_services, | |
557 | handle, key); | |
d3768d88 ZB |
558 | if (status != EFI_SUCCESS) { |
559 | /* | |
560 | * ExitBootServices() will fail if any of the event | |
561 | * handlers change the memory map. In which case, we | |
562 | * must be prepared to retry, but only once so that | |
563 | * we're guaranteed to exit on repeated failures instead | |
564 | * of spinning forever. | |
565 | */ | |
566 | if (called_exit) | |
567 | goto free_mem_map; | |
568 | ||
569 | called_exit = true; | |
ae8e9060 | 570 | efi_call_phys1(sys_table->boottime->free_pool, mem_map); |
d3768d88 ZB |
571 | goto get_map; |
572 | } | |
291f3632 MF |
573 | |
574 | /* Historic? */ | |
575 | boot_params->alt_mem_k = 32 * 1024; | |
576 | ||
577 | /* | |
578 | * Convert the EFI memory map to E820. | |
579 | */ | |
580 | nr_entries = 0; | |
581 | for (i = 0; i < size / desc_size; i++) { | |
582 | efi_memory_desc_t *d; | |
583 | unsigned int e820_type = 0; | |
584 | unsigned long m = (unsigned long)mem_map; | |
585 | ||
586 | d = (efi_memory_desc_t *)(m + (i * desc_size)); | |
587 | switch (d->type) { | |
588 | case EFI_RESERVED_TYPE: | |
589 | case EFI_RUNTIME_SERVICES_CODE: | |
590 | case EFI_RUNTIME_SERVICES_DATA: | |
591 | case EFI_MEMORY_MAPPED_IO: | |
592 | case EFI_MEMORY_MAPPED_IO_PORT_SPACE: | |
593 | case EFI_PAL_CODE: | |
594 | e820_type = E820_RESERVED; | |
595 | break; | |
596 | ||
597 | case EFI_UNUSABLE_MEMORY: | |
598 | e820_type = E820_UNUSABLE; | |
599 | break; | |
600 | ||
601 | case EFI_ACPI_RECLAIM_MEMORY: | |
602 | e820_type = E820_ACPI; | |
603 | break; | |
604 | ||
605 | case EFI_LOADER_CODE: | |
606 | case EFI_LOADER_DATA: | |
607 | case EFI_BOOT_SERVICES_CODE: | |
608 | case EFI_BOOT_SERVICES_DATA: | |
609 | case EFI_CONVENTIONAL_MEMORY: | |
610 | e820_type = E820_RAM; | |
611 | break; | |
612 | ||
613 | case EFI_ACPI_MEMORY_NVS: | |
614 | e820_type = E820_NVS; | |
615 | break; | |
616 | ||
617 | default: | |
618 | continue; | |
619 | } | |
620 | ||
621 | /* Merge adjacent mappings */ | |
622 | if (prev && prev->type == e820_type && | |
623 | (prev->addr + prev->size) == d->phys_addr) | |
624 | prev->size += d->num_pages << 12; | |
625 | else { | |
626 | e820_map->addr = d->phys_addr; | |
627 | e820_map->size = d->num_pages << 12; | |
628 | e820_map->type = e820_type; | |
629 | prev = e820_map++; | |
630 | nr_entries++; | |
631 | } | |
632 | } | |
633 | ||
634 | boot_params->e820_entries = nr_entries; | |
635 | ||
636 | return EFI_SUCCESS; | |
637 | ||
638 | free_mem_map: | |
ae8e9060 | 639 | efi_call_phys1(sys_table->boottime->free_pool, mem_map); |
291f3632 MF |
640 | return status; |
641 | } | |
642 | ||
9ca8f72a MF |
643 | |
644 | /* | |
645 | * On success we return a pointer to a boot_params structure, and NULL | |
646 | * on failure. | |
647 | */ | |
648 | struct boot_params *efi_main(void *handle, efi_system_table_t *_table, | |
649 | struct boot_params *boot_params) | |
650 | { | |
651 | struct desc_ptr *gdt, *idt; | |
652 | efi_loaded_image_t *image; | |
653 | struct setup_header *hdr = &boot_params->hdr; | |
654 | efi_status_t status; | |
655 | struct desc_struct *desc; | |
656 | ||
657 | sys_table = _table; | |
658 | ||
659 | /* Check if we were booted by the EFI firmware */ | |
660 | if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) | |
661 | goto fail; | |
662 | ||
663 | setup_graphics(boot_params); | |
291f3632 | 664 | |
dd5fc854 MG |
665 | setup_efi_pci(boot_params); |
666 | ||
291f3632 MF |
667 | status = efi_call_phys3(sys_table->boottime->allocate_pool, |
668 | EFI_LOADER_DATA, sizeof(*gdt), | |
669 | (void **)&gdt); | |
9fa7deda | 670 | if (status != EFI_SUCCESS) { |
876dc36a | 671 | efi_printk(sys_table, "Failed to alloc mem for gdt structure\n"); |
291f3632 | 672 | goto fail; |
9fa7deda | 673 | } |
291f3632 MF |
674 | |
675 | gdt->size = 0x800; | |
40e4530a | 676 | status = efi_low_alloc(sys_table, gdt->size, 8, |
876dc36a | 677 | (unsigned long *)&gdt->address); |
9fa7deda | 678 | if (status != EFI_SUCCESS) { |
876dc36a | 679 | efi_printk(sys_table, "Failed to alloc mem for gdt\n"); |
291f3632 | 680 | goto fail; |
9fa7deda | 681 | } |
291f3632 MF |
682 | |
683 | status = efi_call_phys3(sys_table->boottime->allocate_pool, | |
684 | EFI_LOADER_DATA, sizeof(*idt), | |
685 | (void **)&idt); | |
9fa7deda | 686 | if (status != EFI_SUCCESS) { |
876dc36a | 687 | efi_printk(sys_table, "Failed to alloc mem for idt structure\n"); |
291f3632 | 688 | goto fail; |
9fa7deda | 689 | } |
291f3632 MF |
690 | |
691 | idt->size = 0; | |
692 | idt->address = 0; | |
693 | ||
9ca8f72a MF |
694 | /* |
695 | * If the kernel isn't already loaded at the preferred load | |
696 | * address, relocate it. | |
697 | */ | |
698 | if (hdr->pref_address != hdr->code32_start) { | |
4a9f3a7c RF |
699 | unsigned long bzimage_addr = hdr->code32_start; |
700 | status = efi_relocate_kernel(sys_table, &bzimage_addr, | |
701 | hdr->init_size, hdr->init_size, | |
702 | hdr->pref_address, | |
703 | hdr->kernel_alignment); | |
9ca8f72a MF |
704 | if (status != EFI_SUCCESS) |
705 | goto fail; | |
4a9f3a7c RF |
706 | |
707 | hdr->pref_address = hdr->code32_start; | |
708 | hdr->code32_start = bzimage_addr; | |
9ca8f72a MF |
709 | } |
710 | ||
711 | status = exit_boot(boot_params, handle); | |
291f3632 MF |
712 | if (status != EFI_SUCCESS) |
713 | goto fail; | |
714 | ||
715 | memset((char *)gdt->address, 0x0, gdt->size); | |
716 | desc = (struct desc_struct *)gdt->address; | |
717 | ||
718 | /* The first GDT is a dummy and the second is unused. */ | |
719 | desc += 2; | |
720 | ||
721 | desc->limit0 = 0xffff; | |
722 | desc->base0 = 0x0000; | |
723 | desc->base1 = 0x0000; | |
724 | desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ; | |
725 | desc->s = DESC_TYPE_CODE_DATA; | |
726 | desc->dpl = 0; | |
727 | desc->p = 1; | |
728 | desc->limit = 0xf; | |
729 | desc->avl = 0; | |
730 | desc->l = 0; | |
731 | desc->d = SEG_OP_SIZE_32BIT; | |
732 | desc->g = SEG_GRANULARITY_4KB; | |
733 | desc->base2 = 0x00; | |
734 | ||
735 | desc++; | |
736 | desc->limit0 = 0xffff; | |
737 | desc->base0 = 0x0000; | |
738 | desc->base1 = 0x0000; | |
739 | desc->type = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE; | |
740 | desc->s = DESC_TYPE_CODE_DATA; | |
741 | desc->dpl = 0; | |
742 | desc->p = 1; | |
743 | desc->limit = 0xf; | |
744 | desc->avl = 0; | |
745 | desc->l = 0; | |
746 | desc->d = SEG_OP_SIZE_32BIT; | |
747 | desc->g = SEG_GRANULARITY_4KB; | |
748 | desc->base2 = 0x00; | |
749 | ||
750 | #ifdef CONFIG_X86_64 | |
751 | /* Task segment value */ | |
752 | desc++; | |
753 | desc->limit0 = 0x0000; | |
754 | desc->base0 = 0x0000; | |
755 | desc->base1 = 0x0000; | |
756 | desc->type = SEG_TYPE_TSS; | |
757 | desc->s = 0; | |
758 | desc->dpl = 0; | |
759 | desc->p = 1; | |
760 | desc->limit = 0x0; | |
761 | desc->avl = 0; | |
762 | desc->l = 0; | |
763 | desc->d = 0; | |
764 | desc->g = SEG_GRANULARITY_4KB; | |
765 | desc->base2 = 0x00; | |
766 | #endif /* CONFIG_X86_64 */ | |
767 | ||
768 | asm volatile ("lidt %0" : : "m" (*idt)); | |
769 | asm volatile ("lgdt %0" : : "m" (*gdt)); | |
770 | ||
771 | asm volatile("cli"); | |
772 | ||
773 | return boot_params; | |
774 | fail: | |
775 | return NULL; | |
776 | } |