blob: 04c406f9aee35cd7597a6ff8c749cc14c7e6cf13 [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>
Ingo Molnar5520b7e2017-01-27 11:59:46 +010012
Matt Fleming291f3632011-12-12 21:27:52 +000013#include <asm/efi.h>
Ingo Molnar5520b7e2017-01-27 11:59:46 +010014#include <asm/e820/types.h>
Matt Fleming291f3632011-12-12 21:27:52 +000015#include <asm/setup.h>
16#include <asm/desc.h>
17
Andrey Ryabinin393f2032015-02-13 14:39:56 -080018#include "../string.h"
Matt Fleming291f3632011-12-12 21:27:52 +000019#include "eboot.h"
20
21static efi_system_table_t *sys_table;
22
Matt Fleming84be8802014-09-23 10:37:43 +010023static struct efi_config *efi_early;
24
Ard Biesheuvel243b6752014-11-05 17:00:56 +010025__pure const struct efi_config *__efi_early(void)
26{
27 return efi_early;
28}
Matt Fleming204b0a12014-03-22 10:09:01 +000029
Matt Fleming54b52d82014-01-10 15:27:14 +000030#define BOOT_SERVICES(bits) \
31static void setup_boot_services##bits(struct efi_config *c) \
32{ \
33 efi_system_table_##bits##_t *table; \
Matt Fleming54b52d82014-01-10 15:27:14 +000034 \
35 table = (typeof(table))sys_table; \
36 \
Lukas Wunner0a637ee2016-08-22 12:01:21 +020037 c->boot_services = table->boottime; \
Matt Fleming54b52d82014-01-10 15:27:14 +000038 c->text_output = table->con_out; \
Matt Fleming54b52d82014-01-10 15:27:14 +000039}
40BOOT_SERVICES(32);
41BOOT_SERVICES(64);
42
Ard Biesheuvelbd669472014-07-02 14:54:42 +020043void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
Matt Fleming54b52d82014-01-10 15:27:14 +000044
45static efi_status_t
Matt Flemingc116e8d2014-01-16 11:35:43 +000046__file_size32(void *__fh, efi_char16_t *filename_16,
47 void **handle, u64 *file_sz)
Matt Fleming54b52d82014-01-10 15:27:14 +000048{
Matt Flemingc116e8d2014-01-16 11:35:43 +000049 efi_file_handle_32_t *h, *fh = __fh;
Matt Fleming54b52d82014-01-10 15:27:14 +000050 efi_file_info_t *info;
51 efi_status_t status;
52 efi_guid_t info_guid = EFI_FILE_INFO_ID;
53 u32 info_sz;
54
55 status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
56 EFI_FILE_MODE_READ, (u64)0);
57 if (status != EFI_SUCCESS) {
58 efi_printk(sys_table, "Failed to open file: ");
59 efi_char16_printk(sys_table, filename_16);
60 efi_printk(sys_table, "\n");
61 return status;
62 }
63
64 *handle = h;
65
66 info_sz = 0;
67 status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
68 &info_sz, NULL);
69 if (status != EFI_BUFFER_TOO_SMALL) {
70 efi_printk(sys_table, "Failed to get file info size\n");
71 return status;
72 }
73
74grow:
Matt Fleming204b0a12014-03-22 10:09:01 +000075 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
76 info_sz, (void **)&info);
Matt Fleming54b52d82014-01-10 15:27:14 +000077 if (status != EFI_SUCCESS) {
78 efi_printk(sys_table, "Failed to alloc mem for file info\n");
79 return status;
80 }
81
82 status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
83 &info_sz, info);
84 if (status == EFI_BUFFER_TOO_SMALL) {
Matt Fleming204b0a12014-03-22 10:09:01 +000085 efi_call_early(free_pool, info);
Matt Fleming54b52d82014-01-10 15:27:14 +000086 goto grow;
87 }
88
89 *file_sz = info->file_size;
Matt Fleming204b0a12014-03-22 10:09:01 +000090 efi_call_early(free_pool, info);
Matt Fleming54b52d82014-01-10 15:27:14 +000091
92 if (status != EFI_SUCCESS)
93 efi_printk(sys_table, "Failed to get initrd info\n");
94
95 return status;
96}
97
Matt Flemingc116e8d2014-01-16 11:35:43 +000098static efi_status_t
99__file_size64(void *__fh, efi_char16_t *filename_16,
100 void **handle, u64 *file_sz)
101{
102 efi_file_handle_64_t *h, *fh = __fh;
103 efi_file_info_t *info;
104 efi_status_t status;
105 efi_guid_t info_guid = EFI_FILE_INFO_ID;
Matt Fleming396f1a02014-04-10 13:30:13 +0100106 u64 info_sz;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000107
108 status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16,
109 EFI_FILE_MODE_READ, (u64)0);
110 if (status != EFI_SUCCESS) {
111 efi_printk(sys_table, "Failed to open file: ");
112 efi_char16_printk(sys_table, filename_16);
113 efi_printk(sys_table, "\n");
114 return status;
115 }
116
117 *handle = h;
118
119 info_sz = 0;
120 status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
121 &info_sz, NULL);
122 if (status != EFI_BUFFER_TOO_SMALL) {
123 efi_printk(sys_table, "Failed to get file info size\n");
124 return status;
125 }
126
127grow:
Matt Fleming204b0a12014-03-22 10:09:01 +0000128 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
129 info_sz, (void **)&info);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000130 if (status != EFI_SUCCESS) {
131 efi_printk(sys_table, "Failed to alloc mem for file info\n");
132 return status;
133 }
134
135 status = efi_early->call((unsigned long)h->get_info, h, &info_guid,
136 &info_sz, info);
137 if (status == EFI_BUFFER_TOO_SMALL) {
Matt Fleming204b0a12014-03-22 10:09:01 +0000138 efi_call_early(free_pool, info);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000139 goto grow;
140 }
141
142 *file_sz = info->file_size;
Matt Fleming204b0a12014-03-22 10:09:01 +0000143 efi_call_early(free_pool, info);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000144
145 if (status != EFI_SUCCESS)
146 efi_printk(sys_table, "Failed to get initrd info\n");
147
148 return status;
149}
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200150efi_status_t
Matt Flemingc116e8d2014-01-16 11:35:43 +0000151efi_file_size(efi_system_table_t *sys_table, void *__fh,
152 efi_char16_t *filename_16, void **handle, u64 *file_sz)
153{
154 if (efi_early->is64)
155 return __file_size64(__fh, filename_16, handle, file_sz);
156
157 return __file_size32(__fh, filename_16, handle, file_sz);
158}
159
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200160efi_status_t
Matt Fleming47514c92014-04-10 14:11:45 +0100161efi_file_read(void *handle, unsigned long *size, void *addr)
Matt Fleming54b52d82014-01-10 15:27:14 +0000162{
Matt Flemingc116e8d2014-01-16 11:35:43 +0000163 unsigned long func;
164
165 if (efi_early->is64) {
Matt Fleming47514c92014-04-10 14:11:45 +0100166 efi_file_handle_64_t *fh = handle;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000167
168 func = (unsigned long)fh->read;
169 return efi_early->call(func, handle, size, addr);
170 } else {
Matt Fleming47514c92014-04-10 14:11:45 +0100171 efi_file_handle_32_t *fh = handle;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000172
173 func = (unsigned long)fh->read;
174 return efi_early->call(func, handle, size, addr);
175 }
Matt Fleming54b52d82014-01-10 15:27:14 +0000176}
177
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200178efi_status_t efi_file_close(void *handle)
Matt Fleming54b52d82014-01-10 15:27:14 +0000179{
Matt Flemingc116e8d2014-01-16 11:35:43 +0000180 if (efi_early->is64) {
Matt Fleming47514c92014-04-10 14:11:45 +0100181 efi_file_handle_64_t *fh = handle;
Matt Fleming54b52d82014-01-10 15:27:14 +0000182
Matt Flemingc116e8d2014-01-16 11:35:43 +0000183 return efi_early->call((unsigned long)fh->close, handle);
184 } else {
Matt Fleming47514c92014-04-10 14:11:45 +0100185 efi_file_handle_32_t *fh = handle;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000186
187 return efi_early->call((unsigned long)fh->close, handle);
188 }
Matt Fleming54b52d82014-01-10 15:27:14 +0000189}
190
Matt Flemingc116e8d2014-01-16 11:35:43 +0000191static inline efi_status_t __open_volume32(void *__image, void **__fh)
Matt Fleming54b52d82014-01-10 15:27:14 +0000192{
193 efi_file_io_interface_t *io;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000194 efi_loaded_image_32_t *image = __image;
195 efi_file_handle_32_t *fh;
Matt Fleming54b52d82014-01-10 15:27:14 +0000196 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
197 efi_status_t status;
198 void *handle = (void *)(unsigned long)image->device_handle;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000199 unsigned long func;
Matt Fleming54b52d82014-01-10 15:27:14 +0000200
Matt Fleming204b0a12014-03-22 10:09:01 +0000201 status = efi_call_early(handle_protocol, handle,
202 &fs_proto, (void **)&io);
Matt Fleming54b52d82014-01-10 15:27:14 +0000203 if (status != EFI_SUCCESS) {
204 efi_printk(sys_table, "Failed to handle fs_proto\n");
205 return status;
206 }
207
208 func = (unsigned long)io->open_volume;
209 status = efi_early->call(func, io, &fh);
210 if (status != EFI_SUCCESS)
211 efi_printk(sys_table, "Failed to open volume\n");
212
213 *__fh = fh;
214 return status;
215}
216
Matt Flemingc116e8d2014-01-16 11:35:43 +0000217static inline efi_status_t __open_volume64(void *__image, void **__fh)
Matt Fleming54b52d82014-01-10 15:27:14 +0000218{
Matt Flemingc116e8d2014-01-16 11:35:43 +0000219 efi_file_io_interface_t *io;
220 efi_loaded_image_64_t *image = __image;
221 efi_file_handle_64_t *fh;
222 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
223 efi_status_t status;
224 void *handle = (void *)(unsigned long)image->device_handle;
225 unsigned long func;
226
Matt Fleming204b0a12014-03-22 10:09:01 +0000227 status = efi_call_early(handle_protocol, handle,
228 &fs_proto, (void **)&io);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000229 if (status != EFI_SUCCESS) {
230 efi_printk(sys_table, "Failed to handle fs_proto\n");
231 return status;
232 }
233
234 func = (unsigned long)io->open_volume;
235 status = efi_early->call(func, io, &fh);
236 if (status != EFI_SUCCESS)
237 efi_printk(sys_table, "Failed to open volume\n");
238
239 *__fh = fh;
240 return status;
241}
242
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200243efi_status_t
Matt Flemingc116e8d2014-01-16 11:35:43 +0000244efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
245{
246 if (efi_early->is64)
247 return __open_volume64(__image, __fh);
248
249 return __open_volume32(__image, __fh);
250}
251
Ard Biesheuvelbd669472014-07-02 14:54:42 +0200252void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
Matt Flemingc116e8d2014-01-16 11:35:43 +0000253{
Matt Fleming54b52d82014-01-10 15:27:14 +0000254 unsigned long output_string;
255 size_t offset;
Matt Fleming54b52d82014-01-10 15:27:14 +0000256
Matt Flemingc116e8d2014-01-16 11:35:43 +0000257 if (efi_early->is64) {
258 struct efi_simple_text_output_protocol_64 *out;
259 u64 *func;
Matt Fleming54b52d82014-01-10 15:27:14 +0000260
Matt Flemingc116e8d2014-01-16 11:35:43 +0000261 offset = offsetof(typeof(*out), output_string);
262 output_string = efi_early->text_output + offset;
Matt Fleming115c6622014-09-24 11:56:10 +0100263 out = (typeof(out))(unsigned long)efi_early->text_output;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000264 func = (u64 *)output_string;
265
Matt Fleming115c6622014-09-24 11:56:10 +0100266 efi_early->call(*func, out, str);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000267 } else {
268 struct efi_simple_text_output_protocol_32 *out;
269 u32 *func;
270
271 offset = offsetof(typeof(*out), output_string);
272 output_string = efi_early->text_output + offset;
Matt Fleming115c6622014-09-24 11:56:10 +0100273 out = (typeof(out))(unsigned long)efi_early->text_output;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000274 func = (u32 *)output_string;
275
Matt Fleming115c6622014-09-24 11:56:10 +0100276 efi_early->call(*func, out, str);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000277 }
Matt Fleming54b52d82014-01-10 15:27:14 +0000278}
Lee, Chun-Yideb94102012-12-20 19:33:22 +0800279
Matt Flemingc116e8d2014-01-16 11:35:43 +0000280static efi_status_t
281__setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom)
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700282{
Matt Flemingc116e8d2014-01-16 11:35:43 +0000283 struct pci_setup_rom *rom = NULL;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700284 efi_status_t status;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000285 unsigned long size;
286 uint64_t attributes;
287
288 status = efi_early->call(pci->attributes, pci,
289 EfiPciIoAttributeOperationGet, 0, 0,
290 &attributes);
291 if (status != EFI_SUCCESS)
292 return status;
293
294 if (!pci->romimage || !pci->romsize)
295 return EFI_INVALID_PARAMETER;
296
297 size = pci->romsize + sizeof(*rom);
298
Matt Fleming204b0a12014-03-22 10:09:01 +0000299 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
Andre Müller77e21e82014-09-10 01:00:22 +0200300 if (status != EFI_SUCCESS) {
301 efi_printk(sys_table, "Failed to alloc mem for rom\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000302 return status;
Andre Müller77e21e82014-09-10 01:00:22 +0200303 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000304
305 memset(rom, 0, sizeof(*rom));
306
307 rom->data.type = SETUP_PCI;
308 rom->data.len = size - sizeof(struct setup_data);
309 rom->data.next = 0;
310 rom->pcilen = pci->romsize;
311 *__rom = rom;
312
313 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
314 PCI_VENDOR_ID, 1, &(rom->vendor));
315
Andre Müller77e21e82014-09-10 01:00:22 +0200316 if (status != EFI_SUCCESS) {
317 efi_printk(sys_table, "Failed to read rom->vendor\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000318 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200319 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000320
321 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
322 PCI_DEVICE_ID, 1, &(rom->devid));
323
Andre Müller77e21e82014-09-10 01:00:22 +0200324 if (status != EFI_SUCCESS) {
325 efi_printk(sys_table, "Failed to read rom->devid\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000326 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200327 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000328
329 status = efi_early->call(pci->get_location, pci, &(rom->segment),
330 &(rom->bus), &(rom->device), &(rom->function));
331
332 if (status != EFI_SUCCESS)
333 goto free_struct;
334
335 memcpy(rom->romdata, pci->romimage, pci->romsize);
336 return status;
337
338free_struct:
Matt Fleming204b0a12014-03-22 10:09:01 +0000339 efi_call_early(free_pool, rom);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000340 return status;
341}
342
Matt Fleming56394ab2014-09-11 09:04:25 +0100343static void
Matt Flemingc116e8d2014-01-16 11:35:43 +0000344setup_efi_pci32(struct boot_params *params, void **pci_handle,
345 unsigned long size)
346{
347 efi_pci_io_protocol_32 *pci = NULL;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700348 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000349 u32 *handles = (u32 *)(unsigned long)pci_handle;
350 efi_status_t status;
351 unsigned long nr_pci;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700352 struct setup_data *data;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000353 int i;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700354
Jan Beulichbc754792013-01-18 12:35:14 +0000355 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700356
357 while (data && data->next)
Jan Beulichbc754792013-01-18 12:35:14 +0000358 data = (struct setup_data *)(unsigned long)data->next;
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700359
Matt Flemingc116e8d2014-01-16 11:35:43 +0000360 nr_pci = size / sizeof(u32);
361 for (i = 0; i < nr_pci; i++) {
362 struct pci_setup_rom *rom = NULL;
363 u32 h = handles[i];
364
Matt Fleming204b0a12014-03-22 10:09:01 +0000365 status = efi_call_early(handle_protocol, h,
366 &pci_proto, (void **)&pci);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000367
368 if (status != EFI_SUCCESS)
369 continue;
370
371 if (!pci)
372 continue;
373
374 status = __setup_efi_pci32(pci, &rom);
375 if (status != EFI_SUCCESS)
376 continue;
377
378 if (data)
379 data->next = (unsigned long)rom;
380 else
381 params->hdr.setup_data = (unsigned long)rom;
382
383 data = (struct setup_data *)rom;
384
385 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000386}
387
388static efi_status_t
389__setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom)
390{
391 struct pci_setup_rom *rom;
392 efi_status_t status;
393 unsigned long size;
394 uint64_t attributes;
395
396 status = efi_early->call(pci->attributes, pci,
397 EfiPciIoAttributeOperationGet, 0,
398 &attributes);
399 if (status != EFI_SUCCESS)
400 return status;
401
402 if (!pci->romimage || !pci->romsize)
403 return EFI_INVALID_PARAMETER;
404
405 size = pci->romsize + sizeof(*rom);
406
Matt Fleming204b0a12014-03-22 10:09:01 +0000407 status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
Andre Müller77e21e82014-09-10 01:00:22 +0200408 if (status != EFI_SUCCESS) {
409 efi_printk(sys_table, "Failed to alloc mem for rom\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000410 return status;
Andre Müller77e21e82014-09-10 01:00:22 +0200411 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000412
413 rom->data.type = SETUP_PCI;
414 rom->data.len = size - sizeof(struct setup_data);
415 rom->data.next = 0;
416 rom->pcilen = pci->romsize;
417 *__rom = rom;
418
419 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
420 PCI_VENDOR_ID, 1, &(rom->vendor));
421
Andre Müller77e21e82014-09-10 01:00:22 +0200422 if (status != EFI_SUCCESS) {
423 efi_printk(sys_table, "Failed to read rom->vendor\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000424 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200425 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000426
427 status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
428 PCI_DEVICE_ID, 1, &(rom->devid));
429
Andre Müller77e21e82014-09-10 01:00:22 +0200430 if (status != EFI_SUCCESS) {
431 efi_printk(sys_table, "Failed to read rom->devid\n");
Matt Flemingc116e8d2014-01-16 11:35:43 +0000432 goto free_struct;
Andre Müller77e21e82014-09-10 01:00:22 +0200433 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000434
435 status = efi_early->call(pci->get_location, pci, &(rom->segment),
436 &(rom->bus), &(rom->device), &(rom->function));
437
438 if (status != EFI_SUCCESS)
439 goto free_struct;
440
441 memcpy(rom->romdata, pci->romimage, pci->romsize);
442 return status;
443
444free_struct:
Matt Fleming204b0a12014-03-22 10:09:01 +0000445 efi_call_early(free_pool, rom);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000446 return status;
447
448}
449
Matt Fleming56394ab2014-09-11 09:04:25 +0100450static void
Matt Flemingc116e8d2014-01-16 11:35:43 +0000451setup_efi_pci64(struct boot_params *params, void **pci_handle,
452 unsigned long size)
453{
454 efi_pci_io_protocol_64 *pci = NULL;
455 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
456 u64 *handles = (u64 *)(unsigned long)pci_handle;
457 efi_status_t status;
458 unsigned long nr_pci;
459 struct setup_data *data;
460 int i;
461
462 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
463
464 while (data && data->next)
465 data = (struct setup_data *)(unsigned long)data->next;
466
467 nr_pci = size / sizeof(u64);
468 for (i = 0; i < nr_pci; i++) {
469 struct pci_setup_rom *rom = NULL;
470 u64 h = handles[i];
471
Matt Fleming204b0a12014-03-22 10:09:01 +0000472 status = efi_call_early(handle_protocol, h,
473 &pci_proto, (void **)&pci);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000474
475 if (status != EFI_SUCCESS)
476 continue;
477
478 if (!pci)
479 continue;
480
481 status = __setup_efi_pci64(pci, &rom);
482 if (status != EFI_SUCCESS)
483 continue;
484
485 if (data)
486 data->next = (unsigned long)rom;
487 else
488 params->hdr.setup_data = (unsigned long)rom;
489
490 data = (struct setup_data *)rom;
491
492 }
Matt Flemingc116e8d2014-01-16 11:35:43 +0000493}
494
Matt Fleming56394ab2014-09-11 09:04:25 +0100495/*
496 * There's no way to return an informative status from this function,
497 * because any analysis (and printing of error messages) needs to be
498 * done directly at the EFI function call-site.
499 *
500 * For example, EFI_INVALID_PARAMETER could indicate a bug or maybe we
501 * just didn't find any PCI devices, but there's no way to tell outside
502 * the context of the call.
503 */
504static void setup_efi_pci(struct boot_params *params)
Matt Flemingc116e8d2014-01-16 11:35:43 +0000505{
506 efi_status_t status;
507 void **pci_handle = NULL;
508 efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
509 unsigned long size = 0;
510
Matt Fleming204b0a12014-03-22 10:09:01 +0000511 status = efi_call_early(locate_handle,
512 EFI_LOCATE_BY_PROTOCOL,
513 &pci_proto, NULL, &size, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700514
515 if (status == EFI_BUFFER_TOO_SMALL) {
Matt Fleming204b0a12014-03-22 10:09:01 +0000516 status = efi_call_early(allocate_pool,
517 EFI_LOADER_DATA,
518 size, (void **)&pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700519
Andre Müller77e21e82014-09-10 01:00:22 +0200520 if (status != EFI_SUCCESS) {
521 efi_printk(sys_table, "Failed to alloc mem for pci_handle\n");
Matt Fleming56394ab2014-09-11 09:04:25 +0100522 return;
Andre Müller77e21e82014-09-10 01:00:22 +0200523 }
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700524
Matt Fleming204b0a12014-03-22 10:09:01 +0000525 status = efi_call_early(locate_handle,
526 EFI_LOCATE_BY_PROTOCOL, &pci_proto,
527 NULL, &size, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700528 }
529
530 if (status != EFI_SUCCESS)
531 goto free_handle;
532
Matt Flemingc116e8d2014-01-16 11:35:43 +0000533 if (efi_early->is64)
Matt Fleming56394ab2014-09-11 09:04:25 +0100534 setup_efi_pci64(params, pci_handle, size);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000535 else
Matt Fleming56394ab2014-09-11 09:04:25 +0100536 setup_efi_pci32(params, pci_handle, size);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700537
538free_handle:
Matt Fleming204b0a12014-03-22 10:09:01 +0000539 efi_call_early(free_pool, pci_handle);
Matthew Garrettdd5fc852012-12-05 14:33:26 -0700540}
541
Lukas Wunner58c54752016-11-12 21:32:36 +0000542static void retrieve_apple_device_properties(struct boot_params *boot_params)
543{
544 efi_guid_t guid = APPLE_PROPERTIES_PROTOCOL_GUID;
545 struct setup_data *data, *new;
546 efi_status_t status;
547 u32 size = 0;
548 void *p;
549
550 status = efi_call_early(locate_protocol, &guid, NULL, &p);
551 if (status != EFI_SUCCESS)
552 return;
553
554 if (efi_table_attr(apple_properties_protocol, version, p) != 0x10000) {
555 efi_printk(sys_table, "Unsupported properties proto version\n");
556 return;
557 }
558
559 efi_call_proto(apple_properties_protocol, get_all, p, NULL, &size);
560 if (!size)
561 return;
562
563 do {
564 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
565 size + sizeof(struct setup_data), &new);
566 if (status != EFI_SUCCESS) {
567 efi_printk(sys_table,
568 "Failed to alloc mem for properties\n");
569 return;
570 }
571
572 status = efi_call_proto(apple_properties_protocol, get_all, p,
573 new->data, &size);
574
575 if (status == EFI_BUFFER_TOO_SMALL)
576 efi_call_early(free_pool, new);
577 } while (status == EFI_BUFFER_TOO_SMALL);
578
579 new->type = SETUP_APPLE_PROPERTIES;
580 new->len = size;
581 new->next = 0;
582
583 data = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
584 if (!data)
585 boot_params->hdr.setup_data = (unsigned long)new;
586 else {
587 while (data->next)
588 data = (struct setup_data *)(unsigned long)data->next;
589 data->next = (unsigned long)new;
590 }
591}
592
593static void setup_quirks(struct boot_params *boot_params)
594{
595 efi_char16_t const apple[] = { 'A', 'p', 'p', 'l', 'e', 0 };
596 efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long)
597 efi_table_attr(efi_system_table, fw_vendor, sys_table);
598
599 if (!memcmp(fw_vendor, apple, sizeof(apple))) {
600 if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
601 retrieve_apple_device_properties(boot_params);
602 }
603}
604
Matt Flemingc116e8d2014-01-16 11:35:43 +0000605static efi_status_t
606setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
Matt Fleming291f3632011-12-12 21:27:52 +0000607{
Matt Flemingc116e8d2014-01-16 11:35:43 +0000608 struct efi_uga_draw_protocol *uga = NULL, *first_uga;
609 efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
Matt Fleming291f3632011-12-12 21:27:52 +0000610 unsigned long nr_ugas;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000611 u32 *handles = (u32 *)uga_handle;;
Colin Ian Kingac0e94b2016-07-20 11:11:06 +0100612 efi_status_t status = EFI_INVALID_PARAMETER;
Matt Fleming291f3632011-12-12 21:27:52 +0000613 int i;
614
Matt Fleming291f3632011-12-12 21:27:52 +0000615 first_uga = NULL;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000616 nr_ugas = size / sizeof(u32);
Matt Fleming291f3632011-12-12 21:27:52 +0000617 for (i = 0; i < nr_ugas; i++) {
618 efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
Matt Fleming291f3632011-12-12 21:27:52 +0000619 u32 w, h, depth, refresh;
620 void *pciio;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000621 u32 handle = handles[i];
Matt Fleming291f3632011-12-12 21:27:52 +0000622
Matt Fleming204b0a12014-03-22 10:09:01 +0000623 status = efi_call_early(handle_protocol, handle,
624 &uga_proto, (void **)&uga);
Matt Fleming291f3632011-12-12 21:27:52 +0000625 if (status != EFI_SUCCESS)
626 continue;
627
Matt Fleming204b0a12014-03-22 10:09:01 +0000628 efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
Matt Fleming291f3632011-12-12 21:27:52 +0000629
Matt Fleming54b52d82014-01-10 15:27:14 +0000630 status = efi_early->call((unsigned long)uga->get_mode, uga,
631 &w, &h, &depth, &refresh);
Matt Fleming291f3632011-12-12 21:27:52 +0000632 if (status == EFI_SUCCESS && (!first_uga || pciio)) {
Matt Flemingc116e8d2014-01-16 11:35:43 +0000633 *width = w;
634 *height = h;
Matt Fleming291f3632011-12-12 21:27:52 +0000635
636 /*
637 * Once we've found a UGA supporting PCIIO,
638 * don't bother looking any further.
639 */
640 if (pciio)
641 break;
642
643 first_uga = uga;
644 }
645 }
646
Matt Flemingc116e8d2014-01-16 11:35:43 +0000647 return status;
648}
649
650static efi_status_t
651setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
652{
653 struct efi_uga_draw_protocol *uga = NULL, *first_uga;
654 efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
655 unsigned long nr_ugas;
656 u64 *handles = (u64 *)uga_handle;;
Colin Ian Kingac0e94b2016-07-20 11:11:06 +0100657 efi_status_t status = EFI_INVALID_PARAMETER;
Matt Flemingc116e8d2014-01-16 11:35:43 +0000658 int i;
659
660 first_uga = NULL;
661 nr_ugas = size / sizeof(u64);
662 for (i = 0; i < nr_ugas; i++) {
663 efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
664 u32 w, h, depth, refresh;
665 void *pciio;
666 u64 handle = handles[i];
667
Matt Fleming204b0a12014-03-22 10:09:01 +0000668 status = efi_call_early(handle_protocol, handle,
669 &uga_proto, (void **)&uga);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000670 if (status != EFI_SUCCESS)
671 continue;
672
Matt Fleming204b0a12014-03-22 10:09:01 +0000673 efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000674
675 status = efi_early->call((unsigned long)uga->get_mode, uga,
676 &w, &h, &depth, &refresh);
677 if (status == EFI_SUCCESS && (!first_uga || pciio)) {
678 *width = w;
679 *height = h;
680
681 /*
682 * Once we've found a UGA supporting PCIIO,
683 * don't bother looking any further.
684 */
685 if (pciio)
686 break;
687
688 first_uga = uga;
689 }
690 }
691
692 return status;
693}
694
695/*
696 * See if we have Universal Graphics Adapter (UGA) protocol
697 */
698static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
699 unsigned long size)
700{
701 efi_status_t status;
702 u32 width, height;
703 void **uga_handle = NULL;
704
Matt Fleming204b0a12014-03-22 10:09:01 +0000705 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
706 size, (void **)&uga_handle);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000707 if (status != EFI_SUCCESS)
708 return status;
709
Matt Fleming204b0a12014-03-22 10:09:01 +0000710 status = efi_call_early(locate_handle,
711 EFI_LOCATE_BY_PROTOCOL,
712 uga_proto, NULL, &size, uga_handle);
Matt Flemingc116e8d2014-01-16 11:35:43 +0000713 if (status != EFI_SUCCESS)
714 goto free_handle;
715
716 height = 0;
717 width = 0;
718
719 if (efi_early->is64)
720 status = setup_uga64(uga_handle, size, &width, &height);
721 else
722 status = setup_uga32(uga_handle, size, &width, &height);
723
724 if (!width && !height)
Matt Fleming291f3632011-12-12 21:27:52 +0000725 goto free_handle;
726
727 /* EFI framebuffer */
728 si->orig_video_isVGA = VIDEO_TYPE_EFI;
729
730 si->lfb_depth = 32;
731 si->lfb_width = width;
732 si->lfb_height = height;
733
734 si->red_size = 8;
735 si->red_pos = 16;
736 si->green_size = 8;
737 si->green_pos = 8;
738 si->blue_size = 8;
739 si->blue_pos = 0;
740 si->rsvd_size = 8;
741 si->rsvd_pos = 24;
742
Matt Fleming291f3632011-12-12 21:27:52 +0000743free_handle:
Matt Fleming204b0a12014-03-22 10:09:01 +0000744 efi_call_early(free_pool, uga_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000745 return status;
746}
747
748void setup_graphics(struct boot_params *boot_params)
749{
750 efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
751 struct screen_info *si;
752 efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
753 efi_status_t status;
754 unsigned long size;
755 void **gop_handle = NULL;
756 void **uga_handle = NULL;
757
758 si = &boot_params->screen_info;
759 memset(si, 0, sizeof(*si));
760
761 size = 0;
Matt Fleming204b0a12014-03-22 10:09:01 +0000762 status = efi_call_early(locate_handle,
763 EFI_LOCATE_BY_PROTOCOL,
764 &graphics_proto, NULL, &size, gop_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000765 if (status == EFI_BUFFER_TOO_SMALL)
Ard Biesheuvel2c23b732016-04-25 21:06:48 +0100766 status = efi_setup_gop(NULL, si, &graphics_proto, size);
Matt Fleming291f3632011-12-12 21:27:52 +0000767
768 if (status != EFI_SUCCESS) {
769 size = 0;
Matt Fleming204b0a12014-03-22 10:09:01 +0000770 status = efi_call_early(locate_handle,
771 EFI_LOCATE_BY_PROTOCOL,
772 &uga_proto, NULL, &size, uga_handle);
Matt Fleming291f3632011-12-12 21:27:52 +0000773 if (status == EFI_BUFFER_TOO_SMALL)
774 setup_uga(si, &uga_proto, size);
775 }
776}
777
Matt Fleming291f3632011-12-12 21:27:52 +0000778/*
779 * Because the x86 boot code expects to be passed a boot_params we
780 * need to create one ourselves (usually the bootloader would create
781 * one for us).
Matt Fleming7e8213c2014-04-08 13:14:00 +0100782 *
783 * The caller is responsible for filling out ->code32_start in the
784 * returned boot_params.
Matt Fleming291f3632011-12-12 21:27:52 +0000785 */
Matt Fleming54b52d82014-01-10 15:27:14 +0000786struct boot_params *make_boot_params(struct efi_config *c)
Matt Fleming291f3632011-12-12 21:27:52 +0000787{
Matt Fleming9ca8f722012-07-19 10:23:48 +0100788 struct boot_params *boot_params;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100789 struct apm_bios_info *bi;
790 struct setup_header *hdr;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100791 efi_loaded_image_t *image;
Matt Fleming54b52d82014-01-10 15:27:14 +0000792 void *options, *handle;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100793 efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
Matt Fleming291f3632011-12-12 21:27:52 +0000794 int options_size = 0;
795 efi_status_t status;
Roy Franz5fef3872013-09-22 15:45:33 -0700796 char *cmdline_ptr;
Matt Fleming291f3632011-12-12 21:27:52 +0000797 u16 *s2;
798 u8 *s1;
799 int i;
Roy Franz46f45822013-09-22 15:45:39 -0700800 unsigned long ramdisk_addr;
801 unsigned long ramdisk_size;
Matt Fleming291f3632011-12-12 21:27:52 +0000802
Matt Fleming54b52d82014-01-10 15:27:14 +0000803 efi_early = c;
804 sys_table = (efi_system_table_t *)(unsigned long)efi_early->table;
805 handle = (void *)(unsigned long)efi_early->image_handle;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100806
807 /* Check if we were booted by the EFI firmware */
808 if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
809 return NULL;
810
Matt Fleming54b52d82014-01-10 15:27:14 +0000811 if (efi_early->is64)
812 setup_boot_services64(efi_early);
813 else
814 setup_boot_services32(efi_early);
815
Matt Fleming204b0a12014-03-22 10:09:01 +0000816 status = efi_call_early(handle_protocol, handle,
817 &proto, (void *)&image);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100818 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700819 efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +0100820 return NULL;
821 }
822
Roy Franz40e45302013-09-22 15:45:29 -0700823 status = efi_low_alloc(sys_table, 0x4000, 1,
824 (unsigned long *)&boot_params);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100825 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -0700826 efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +0100827 return NULL;
828 }
829
830 memset(boot_params, 0x0, 0x4000);
831
832 hdr = &boot_params->hdr;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100833 bi = &boot_params->apm_bios_info;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100834
835 /* Copy the second sector to boot_params */
836 memcpy(&hdr->jump, image->image_base + 512, 512);
837
838 /*
839 * Fill out some of the header fields ourselves because the
840 * EFI firmware loader doesn't load the first sector.
841 */
842 hdr->root_flags = 1;
843 hdr->vid_mode = 0xffff;
844 hdr->boot_flag = 0xAA55;
845
Matt Fleming291f3632011-12-12 21:27:52 +0000846 hdr->type_of_loader = 0x21;
847
848 /* Convert unicode cmdline to ascii */
H. Peter Anvinc625d1c2013-09-20 09:55:39 -0500849 cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
Roy Franz5fef3872013-09-22 15:45:33 -0700850 if (!cmdline_ptr)
851 goto fail;
852 hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
Roy Franz98b228f2015-04-15 16:32:24 -0700853 /* Fill in upper bits of command line address, NOP on 32 bit */
854 boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
Matt Fleming291f3632011-12-12 21:27:52 +0000855
856 hdr->ramdisk_image = 0;
857 hdr->ramdisk_size = 0;
858
Matt Fleming291f3632011-12-12 21:27:52 +0000859 /* Clear APM BIOS info */
860 memset(bi, 0, sizeof(*bi));
861
Matt Fleming5a17dae2014-08-05 11:52:11 +0100862 status = efi_parse_options(cmdline_ptr);
863 if (status != EFI_SUCCESS)
864 goto fail2;
865
Roy Franz46f45822013-09-22 15:45:39 -0700866 status = handle_cmdline_files(sys_table, image,
867 (char *)(unsigned long)hdr->cmd_line_ptr,
Yinghai Lu47226ad2014-09-03 21:50:07 -0700868 "initrd=", hdr->initrd_addr_max,
Roy Franz46f45822013-09-22 15:45:39 -0700869 &ramdisk_addr, &ramdisk_size);
Yinghai Lu47226ad2014-09-03 21:50:07 -0700870
871 if (status != EFI_SUCCESS &&
872 hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) {
873 efi_printk(sys_table, "Trying to load files to higher address\n");
874 status = handle_cmdline_files(sys_table, image,
875 (char *)(unsigned long)hdr->cmd_line_ptr,
876 "initrd=", -1UL,
877 &ramdisk_addr, &ramdisk_size);
878 }
879
Matt Fleming9ca8f722012-07-19 10:23:48 +0100880 if (status != EFI_SUCCESS)
881 goto fail2;
Yinghai Lu4bf71112014-06-14 12:23:41 -0700882 hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
883 hdr->ramdisk_size = ramdisk_size & 0xffffffff;
884 boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
885 boot_params->ext_ramdisk_size = (u64)ramdisk_size >> 32;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100886
887 return boot_params;
888fail2:
Roy Franz0e1cadb2013-09-22 15:45:38 -0700889 efi_free(sys_table, options_size, hdr->cmd_line_ptr);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100890fail:
Roy Franz40e45302013-09-22 15:45:29 -0700891 efi_free(sys_table, 0x4000, (unsigned long)boot_params);
Matt Fleming9ca8f722012-07-19 10:23:48 +0100892 return NULL;
893}
894
Linn Crosettod2078d52013-09-22 19:59:08 -0600895static void add_e820ext(struct boot_params *params,
896 struct setup_data *e820ext, u32 nr_entries)
Matt Fleming9ca8f722012-07-19 10:23:48 +0100897{
Linn Crosettod2078d52013-09-22 19:59:08 -0600898 struct setup_data *data;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100899 efi_status_t status;
Linn Crosettod2078d52013-09-22 19:59:08 -0600900 unsigned long size;
901
902 e820ext->type = SETUP_E820_EXT;
Ingo Molnar8ec67d92017-01-27 12:54:38 +0100903 e820ext->len = nr_entries * sizeof(struct e820_entry);
Linn Crosettod2078d52013-09-22 19:59:08 -0600904 e820ext->next = 0;
905
906 data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
907
908 while (data && data->next)
909 data = (struct setup_data *)(unsigned long)data->next;
910
911 if (data)
912 data->next = (unsigned long)e820ext;
913 else
914 params->hdr.setup_data = (unsigned long)e820ext;
915}
916
917static efi_status_t setup_e820(struct boot_params *params,
918 struct setup_data *e820ext, u32 e820ext_size)
919{
Ingo Molnar61a50102017-01-27 13:54:38 +0100920 struct e820_entry *e820_table = &params->e820_table[0];
Linn Crosettod2078d52013-09-22 19:59:08 -0600921 struct efi_info *efi = &params->efi_info;
Ingo Molnar8ec67d92017-01-27 12:54:38 +0100922 struct e820_entry *prev = NULL;
Linn Crosettod2078d52013-09-22 19:59:08 -0600923 u32 nr_entries;
924 u32 nr_desc;
Matt Fleming9ca8f722012-07-19 10:23:48 +0100925 int i;
Matt Fleming291f3632011-12-12 21:27:52 +0000926
Matt Fleming291f3632011-12-12 21:27:52 +0000927 nr_entries = 0;
Linn Crosettod2078d52013-09-22 19:59:08 -0600928 nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size;
929
930 for (i = 0; i < nr_desc; i++) {
Matt Fleming291f3632011-12-12 21:27:52 +0000931 efi_memory_desc_t *d;
932 unsigned int e820_type = 0;
Linn Crosettod2078d52013-09-22 19:59:08 -0600933 unsigned long m = efi->efi_memmap;
Matt Fleming291f3632011-12-12 21:27:52 +0000934
Dmitry Skorodumov7cc03e42015-07-28 18:38:32 +0400935#ifdef CONFIG_X86_64
936 m |= (u64)efi->efi_memmap_hi << 32;
937#endif
938
Linn Crosettod2078d52013-09-22 19:59:08 -0600939 d = (efi_memory_desc_t *)(m + (i * efi->efi_memdesc_size));
Matt Fleming291f3632011-12-12 21:27:52 +0000940 switch (d->type) {
941 case EFI_RESERVED_TYPE:
942 case EFI_RUNTIME_SERVICES_CODE:
943 case EFI_RUNTIME_SERVICES_DATA:
944 case EFI_MEMORY_MAPPED_IO:
945 case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
946 case EFI_PAL_CODE:
947 e820_type = E820_RESERVED;
948 break;
949
950 case EFI_UNUSABLE_MEMORY:
951 e820_type = E820_UNUSABLE;
952 break;
953
954 case EFI_ACPI_RECLAIM_MEMORY:
955 e820_type = E820_ACPI;
956 break;
957
958 case EFI_LOADER_CODE:
959 case EFI_LOADER_DATA:
960 case EFI_BOOT_SERVICES_CODE:
961 case EFI_BOOT_SERVICES_DATA:
962 case EFI_CONVENTIONAL_MEMORY:
963 e820_type = E820_RAM;
964 break;
965
966 case EFI_ACPI_MEMORY_NVS:
967 e820_type = E820_NVS;
968 break;
969
Dan Williamsad5fb872015-04-03 12:05:28 -0400970 case EFI_PERSISTENT_MEMORY:
971 e820_type = E820_PMEM;
972 break;
973
Matt Fleming291f3632011-12-12 21:27:52 +0000974 default:
975 continue;
976 }
977
978 /* Merge adjacent mappings */
979 if (prev && prev->type == e820_type &&
Linn Crosettod2078d52013-09-22 19:59:08 -0600980 (prev->addr + prev->size) == d->phys_addr) {
Matt Fleming291f3632011-12-12 21:27:52 +0000981 prev->size += d->num_pages << 12;
Linn Crosettod2078d52013-09-22 19:59:08 -0600982 continue;
Matt Fleming291f3632011-12-12 21:27:52 +0000983 }
Linn Crosettod2078d52013-09-22 19:59:08 -0600984
Ingo Molnar61a50102017-01-27 13:54:38 +0100985 if (nr_entries == ARRAY_SIZE(params->e820_table)) {
Ingo Molnar8ec67d92017-01-27 12:54:38 +0100986 u32 need = (nr_desc - i) * sizeof(struct e820_entry) +
Linn Crosettod2078d52013-09-22 19:59:08 -0600987 sizeof(struct setup_data);
988
989 if (!e820ext || e820ext_size < need)
990 return EFI_BUFFER_TOO_SMALL;
991
992 /* boot_params map full, switch to e820 extended */
Ingo Molnar61a50102017-01-27 13:54:38 +0100993 e820_table = (struct e820_entry *)e820ext->data;
Linn Crosettod2078d52013-09-22 19:59:08 -0600994 }
995
Ingo Molnar61a50102017-01-27 13:54:38 +0100996 e820_table->addr = d->phys_addr;
997 e820_table->size = d->num_pages << PAGE_SHIFT;
998 e820_table->type = e820_type;
999 prev = e820_table++;
Linn Crosettod2078d52013-09-22 19:59:08 -06001000 nr_entries++;
Matt Fleming291f3632011-12-12 21:27:52 +00001001 }
1002
Ingo Molnar61a50102017-01-27 13:54:38 +01001003 if (nr_entries > ARRAY_SIZE(params->e820_table)) {
1004 u32 nr_e820ext = nr_entries - ARRAY_SIZE(params->e820_table);
Linn Crosettod2078d52013-09-22 19:59:08 -06001005
1006 add_e820ext(params, e820ext, nr_e820ext);
1007 nr_entries -= nr_e820ext;
1008 }
1009
1010 params->e820_entries = (u8)nr_entries;
1011
1012 return EFI_SUCCESS;
1013}
1014
1015static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
1016 u32 *e820ext_size)
1017{
1018 efi_status_t status;
1019 unsigned long size;
1020
1021 size = sizeof(struct setup_data) +
Ingo Molnar8ec67d92017-01-27 12:54:38 +01001022 sizeof(struct e820_entry) * nr_desc;
Linn Crosettod2078d52013-09-22 19:59:08 -06001023
1024 if (*e820ext) {
Matt Fleming204b0a12014-03-22 10:09:01 +00001025 efi_call_early(free_pool, *e820ext);
Linn Crosettod2078d52013-09-22 19:59:08 -06001026 *e820ext = NULL;
1027 *e820ext_size = 0;
1028 }
1029
Matt Fleming204b0a12014-03-22 10:09:01 +00001030 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
1031 size, (void **)e820ext);
Linn Crosettod2078d52013-09-22 19:59:08 -06001032 if (status == EFI_SUCCESS)
1033 *e820ext_size = size;
1034
1035 return status;
1036}
1037
Jeffrey Hugod6493402016-08-29 14:38:54 -06001038struct exit_boot_struct {
1039 struct boot_params *boot_params;
1040 struct efi_info *efi;
1041 struct setup_data *e820ext;
1042 __u32 e820ext_size;
1043 bool is64;
1044};
1045
1046static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
1047 struct efi_boot_memmap *map,
1048 void *priv)
1049{
1050 static bool first = true;
1051 const char *signature;
1052 __u32 nr_desc;
1053 efi_status_t status;
1054 struct exit_boot_struct *p = priv;
1055
1056 if (first) {
1057 nr_desc = *map->buff_size / *map->desc_size;
Ingo Molnar61a50102017-01-27 13:54:38 +01001058 if (nr_desc > ARRAY_SIZE(p->boot_params->e820_table)) {
Jeffrey Hugod6493402016-08-29 14:38:54 -06001059 u32 nr_e820ext = nr_desc -
Ingo Molnar61a50102017-01-27 13:54:38 +01001060 ARRAY_SIZE(p->boot_params->e820_table);
Jeffrey Hugod6493402016-08-29 14:38:54 -06001061
1062 status = alloc_e820ext(nr_e820ext, &p->e820ext,
1063 &p->e820ext_size);
1064 if (status != EFI_SUCCESS)
1065 return status;
1066 }
1067 first = false;
1068 }
1069
1070 signature = p->is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
1071 memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));
1072
1073 p->efi->efi_systab = (unsigned long)sys_table_arg;
1074 p->efi->efi_memdesc_size = *map->desc_size;
1075 p->efi->efi_memdesc_version = *map->desc_ver;
1076 p->efi->efi_memmap = (unsigned long)*map->map;
1077 p->efi->efi_memmap_size = *map->map_size;
1078
1079#ifdef CONFIG_X86_64
1080 p->efi->efi_systab_hi = (unsigned long)sys_table_arg >> 32;
1081 p->efi->efi_memmap_hi = (unsigned long)*map->map >> 32;
1082#endif
1083
1084 return EFI_SUCCESS;
1085}
1086
Linn Crosettod2078d52013-09-22 19:59:08 -06001087static efi_status_t exit_boot(struct boot_params *boot_params,
Matt Flemingb8ff87a2014-01-10 15:54:31 +00001088 void *handle, bool is64)
Linn Crosettod2078d52013-09-22 19:59:08 -06001089{
Jeffrey Hugodadb57a2016-08-29 14:38:51 -06001090 unsigned long map_sz, key, desc_size, buff_size;
Linn Crosettod2078d52013-09-22 19:59:08 -06001091 efi_memory_desc_t *mem_map;
1092 struct setup_data *e820ext;
1093 __u32 e820ext_size;
Linn Crosettod2078d52013-09-22 19:59:08 -06001094 efi_status_t status;
1095 __u32 desc_version;
Jeffrey Hugodadb57a2016-08-29 14:38:51 -06001096 struct efi_boot_memmap map;
Jeffrey Hugod6493402016-08-29 14:38:54 -06001097 struct exit_boot_struct priv;
Linn Crosettod2078d52013-09-22 19:59:08 -06001098
Jeffrey Hugod6493402016-08-29 14:38:54 -06001099 map.map = &mem_map;
1100 map.map_size = &map_sz;
1101 map.desc_size = &desc_size;
1102 map.desc_ver = &desc_version;
1103 map.key_ptr = &key;
1104 map.buff_size = &buff_size;
1105 priv.boot_params = boot_params;
1106 priv.efi = &boot_params->efi_info;
1107 priv.e820ext = NULL;
1108 priv.e820ext_size = 0;
1109 priv.is64 = is64;
Linn Crosettod2078d52013-09-22 19:59:08 -06001110
Jeffrey Hugod6493402016-08-29 14:38:54 -06001111 /* Might as well exit boot services now */
1112 status = efi_exit_boot_services(sys_table, handle, &map, &priv,
1113 exit_boot_func);
Linn Crosettod2078d52013-09-22 19:59:08 -06001114 if (status != EFI_SUCCESS)
1115 return status;
1116
Jeffrey Hugod6493402016-08-29 14:38:54 -06001117 e820ext = priv.e820ext;
1118 e820ext_size = priv.e820ext_size;
Linn Crosettod2078d52013-09-22 19:59:08 -06001119 /* Historic? */
1120 boot_params->alt_mem_k = 32 * 1024;
1121
1122 status = setup_e820(boot_params, e820ext, e820ext_size);
1123 if (status != EFI_SUCCESS)
1124 return status;
Matt Fleming291f3632011-12-12 21:27:52 +00001125
1126 return EFI_SUCCESS;
Matt Fleming291f3632011-12-12 21:27:52 +00001127}
1128
Matt Fleming9ca8f722012-07-19 10:23:48 +01001129/*
1130 * On success we return a pointer to a boot_params structure, and NULL
1131 * on failure.
1132 */
Matt Fleming54b52d82014-01-10 15:27:14 +00001133struct boot_params *efi_main(struct efi_config *c,
Matt Fleming9ca8f722012-07-19 10:23:48 +01001134 struct boot_params *boot_params)
1135{
Matt Fleming54b52d82014-01-10 15:27:14 +00001136 struct desc_ptr *gdt = NULL;
Matt Fleming9ca8f722012-07-19 10:23:48 +01001137 efi_loaded_image_t *image;
1138 struct setup_header *hdr = &boot_params->hdr;
1139 efi_status_t status;
1140 struct desc_struct *desc;
Matt Fleming54b52d82014-01-10 15:27:14 +00001141 void *handle;
1142 efi_system_table_t *_table;
1143 bool is64;
1144
1145 efi_early = c;
1146
1147 _table = (efi_system_table_t *)(unsigned long)efi_early->table;
1148 handle = (void *)(unsigned long)efi_early->image_handle;
1149 is64 = efi_early->is64;
Matt Fleming9ca8f722012-07-19 10:23:48 +01001150
1151 sys_table = _table;
1152
1153 /* Check if we were booted by the EFI firmware */
1154 if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
1155 goto fail;
1156
Matt Fleming54b52d82014-01-10 15:27:14 +00001157 if (is64)
1158 setup_boot_services64(efi_early);
1159 else
1160 setup_boot_services32(efi_early);
1161
Matt Fleming9ca8f722012-07-19 10:23:48 +01001162 setup_graphics(boot_params);
Matt Fleming291f3632011-12-12 21:27:52 +00001163
Matt Fleming56394ab2014-09-11 09:04:25 +01001164 setup_efi_pci(boot_params);
Matthew Garrettdd5fc852012-12-05 14:33:26 -07001165
Lukas Wunner58c54752016-11-12 21:32:36 +00001166 setup_quirks(boot_params);
1167
Matt Fleming204b0a12014-03-22 10:09:01 +00001168 status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
1169 sizeof(*gdt), (void **)&gdt);
Matt Fleming9fa7ded2012-02-20 13:20:59 +00001170 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -07001171 efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001172 goto fail;
Matt Fleming9fa7ded2012-02-20 13:20:59 +00001173 }
Matt Fleming291f3632011-12-12 21:27:52 +00001174
1175 gdt->size = 0x800;
Roy Franz40e45302013-09-22 15:45:29 -07001176 status = efi_low_alloc(sys_table, gdt->size, 8,
Roy Franz876dc362013-09-22 15:45:28 -07001177 (unsigned long *)&gdt->address);
Matt Fleming9fa7ded2012-02-20 13:20:59 +00001178 if (status != EFI_SUCCESS) {
Roy Franz876dc362013-09-22 15:45:28 -07001179 efi_printk(sys_table, "Failed to alloc mem for gdt\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001180 goto fail;
Matt Fleming9fa7ded2012-02-20 13:20:59 +00001181 }
Matt Fleming291f3632011-12-12 21:27:52 +00001182
Matt Fleming9ca8f722012-07-19 10:23:48 +01001183 /*
1184 * If the kernel isn't already loaded at the preferred load
1185 * address, relocate it.
1186 */
1187 if (hdr->pref_address != hdr->code32_start) {
Roy Franz4a9f3a72013-09-22 15:45:32 -07001188 unsigned long bzimage_addr = hdr->code32_start;
1189 status = efi_relocate_kernel(sys_table, &bzimage_addr,
1190 hdr->init_size, hdr->init_size,
1191 hdr->pref_address,
1192 hdr->kernel_alignment);
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001193 if (status != EFI_SUCCESS) {
1194 efi_printk(sys_table, "efi_relocate_kernel() failed!\n");
Matt Fleming9ca8f722012-07-19 10:23:48 +01001195 goto fail;
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001196 }
Roy Franz4a9f3a72013-09-22 15:45:32 -07001197
1198 hdr->pref_address = hdr->code32_start;
1199 hdr->code32_start = bzimage_addr;
Matt Fleming9ca8f722012-07-19 10:23:48 +01001200 }
1201
Matt Flemingb8ff87a2014-01-10 15:54:31 +00001202 status = exit_boot(boot_params, handle, is64);
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001203 if (status != EFI_SUCCESS) {
1204 efi_printk(sys_table, "exit_boot() failed!\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001205 goto fail;
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001206 }
Matt Fleming291f3632011-12-12 21:27:52 +00001207
1208 memset((char *)gdt->address, 0x0, gdt->size);
1209 desc = (struct desc_struct *)gdt->address;
1210
1211 /* The first GDT is a dummy and the second is unused. */
1212 desc += 2;
1213
1214 desc->limit0 = 0xffff;
1215 desc->base0 = 0x0000;
1216 desc->base1 = 0x0000;
1217 desc->type = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
1218 desc->s = DESC_TYPE_CODE_DATA;
1219 desc->dpl = 0;
1220 desc->p = 1;
1221 desc->limit = 0xf;
1222 desc->avl = 0;
1223 desc->l = 0;
1224 desc->d = SEG_OP_SIZE_32BIT;
1225 desc->g = SEG_GRANULARITY_4KB;
1226 desc->base2 = 0x00;
1227
1228 desc++;
1229 desc->limit0 = 0xffff;
1230 desc->base0 = 0x0000;
1231 desc->base1 = 0x0000;
1232 desc->type = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
1233 desc->s = DESC_TYPE_CODE_DATA;
1234 desc->dpl = 0;
1235 desc->p = 1;
1236 desc->limit = 0xf;
1237 desc->avl = 0;
1238 desc->l = 0;
1239 desc->d = SEG_OP_SIZE_32BIT;
1240 desc->g = SEG_GRANULARITY_4KB;
1241 desc->base2 = 0x00;
1242
1243#ifdef CONFIG_X86_64
1244 /* Task segment value */
1245 desc++;
1246 desc->limit0 = 0x0000;
1247 desc->base0 = 0x0000;
1248 desc->base1 = 0x0000;
1249 desc->type = SEG_TYPE_TSS;
1250 desc->s = 0;
1251 desc->dpl = 0;
1252 desc->p = 1;
1253 desc->limit = 0x0;
1254 desc->avl = 0;
1255 desc->l = 0;
1256 desc->d = 0;
1257 desc->g = SEG_GRANULARITY_4KB;
1258 desc->base2 = 0x00;
1259#endif /* CONFIG_X86_64 */
1260
Matt Fleming291f3632011-12-12 21:27:52 +00001261 asm volatile("cli");
Bart Kuivenhoven0ce6cda2013-09-23 11:45:28 +02001262 asm volatile ("lgdt %0" : : "m" (*gdt));
Matt Fleming291f3632011-12-12 21:27:52 +00001263
1264 return boot_params;
1265fail:
Ulf Winkelvosfb86b242014-07-10 02:12:41 +02001266 efi_printk(sys_table, "efi_main() failed!\n");
Matt Fleming291f3632011-12-12 21:27:52 +00001267 return NULL;
1268}