eboot.c 22.4 KB
Newer Older
M
Matt Fleming 已提交
1 2 3 4 5 6 7 8 9 10
/* -----------------------------------------------------------------------
 *
 *   Copyright 2011 Intel Corporation; author Matt Fleming
 *
 *   This file is part of the Linux kernel, and is made available under
 *   the terms of the GNU General Public License version 2.
 *
 * ----------------------------------------------------------------------- */

#include <linux/efi.h>
11
#include <linux/pci.h>
12

M
Matt Fleming 已提交
13
#include <asm/efi.h>
14
#include <asm/e820/types.h>
M
Matt Fleming 已提交
15 16 17
#include <asm/setup.h>
#include <asm/desc.h>

18
#include "../string.h"
M
Matt Fleming 已提交
19 20 21 22
#include "eboot.h"

static efi_system_table_t *sys_table;

23 24
static struct efi_config *efi_early;

A
Ard Biesheuvel 已提交
25 26 27 28
__pure const struct efi_config *__efi_early(void)
{
	return efi_early;
}
29

30 31 32 33 34 35 36
#define BOOT_SERVICES(bits)						\
static void setup_boot_services##bits(struct efi_config *c)		\
{									\
	efi_system_table_##bits##_t *table;				\
									\
	table = (typeof(table))sys_table;				\
									\
I
Ingo Molnar 已提交
37 38 39
	c->runtime_services	= table->runtime;			\
	c->boot_services	= table->boottime;			\
	c->text_output		= table->con_out;			\
40 41 42
}
BOOT_SERVICES(32);
BOOT_SERVICES(64);
M
Matt Fleming 已提交
43

44
void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
45
{
46 47
	efi_call_proto(efi_simple_text_output_protocol, output_string,
		       efi_early->text_output, str);
48 49
}

50
static efi_status_t
51
preserve_pci_rom_image(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom)
52
{
53
	struct pci_setup_rom *rom = NULL;
54
	efi_status_t status;
55
	unsigned long size;
56
	uint64_t romsize;
57
	void *romimage;
58

59
	/*
60 61
	 * Some firmware images contain EFI function pointers at the place where
	 * the romimage and romsize fields are supposed to be. Typically the EFI
62 63 64 65
	 * code is mapped at high addresses, translating to an unrealistically
	 * large romsize. The UEFI spec limits the size of option ROMs to 16
	 * MiB so we reject any ROMs over 16 MiB in size to catch this.
	 */
66 67 68
	romimage = (void *)(unsigned long)efi_table_attr(efi_pci_io_protocol,
							 romimage, pci);
	romsize = efi_table_attr(efi_pci_io_protocol, romsize, pci);
69
	if (!romimage || !romsize || romsize > SZ_16M)
70
		return EFI_INVALID_PARAMETER;
71

72
	size = romsize + sizeof(*rom);
73

74
	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
75
	if (status != EFI_SUCCESS) {
I
Ingo Molnar 已提交
76
		efi_printk(sys_table, "Failed to allocate memory for 'rom'\n");
77
		return status;
78
	}
79

80 81
	memset(rom, 0, sizeof(*rom));

I
Ingo Molnar 已提交
82 83 84 85
	rom->data.type	= SETUP_PCI;
	rom->data.len	= size - sizeof(struct setup_data);
	rom->data.next	= 0;
	rom->pcilen	= pci->romsize;
86 87
	*__rom = rom;

88 89 90
	status = efi_call_proto(efi_pci_io_protocol, pci.read, pci,
				EfiPciIoWidthUint16, PCI_VENDOR_ID, 1,
				&rom->vendor);
91

92 93
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to read rom->vendor\n");
94
		goto free_struct;
95
	}
96

97 98 99
	status = efi_call_proto(efi_pci_io_protocol, pci.read, pci,
				EfiPciIoWidthUint16, PCI_DEVICE_ID, 1,
				&rom->devid);
100

101 102
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to read rom->devid\n");
103
		goto free_struct;
104
	}
105

106 107 108
	status = efi_call_proto(efi_pci_io_protocol, get_location, pci,
				&rom->segment, &rom->bus, &rom->device,
				&rom->function);
109 110 111 112

	if (status != EFI_SUCCESS)
		goto free_struct;

113
	memcpy(rom->romdata, romimage, romsize);
114 115 116
	return status;

free_struct:
117
	efi_call_early(free_pool, rom);
118 119 120
	return status;
}

121 122 123 124 125 126 127 128 129 130
/*
 * There's no way to return an informative status from this function,
 * because any analysis (and printing of error messages) needs to be
 * done directly at the EFI function call-site.
 *
 * For example, EFI_INVALID_PARAMETER could indicate a bug or maybe we
 * just didn't find any PCI devices, but there's no way to tell outside
 * the context of the call.
 */
static void setup_efi_pci(struct boot_params *params)
M
Matt Fleming 已提交
131 132
{
	efi_status_t status;
133 134 135
	void **pci_handle = NULL;
	efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
	unsigned long size = 0;
136 137 138
	unsigned long nr_pci;
	struct setup_data *data;
	int i;
M
Matt Fleming 已提交
139

140 141 142
	status = efi_call_early(locate_handle,
				EFI_LOCATE_BY_PROTOCOL,
				&pci_proto, NULL, &size, pci_handle);
M
Matt Fleming 已提交
143

144
	if (status == EFI_BUFFER_TOO_SMALL) {
145 146 147
		status = efi_call_early(allocate_pool,
					EFI_LOADER_DATA,
					size, (void **)&pci_handle);
M
Matt Fleming 已提交
148

149
		if (status != EFI_SUCCESS) {
I
Ingo Molnar 已提交
150
			efi_printk(sys_table, "Failed to allocate memory for 'pci_handle'\n");
151
			return;
152
		}
M
Matt Fleming 已提交
153

154 155 156
		status = efi_call_early(locate_handle,
					EFI_LOCATE_BY_PROTOCOL, &pci_proto,
					NULL, &size, pci_handle);
M
Matt Fleming 已提交
157 158
	}

159
	if (status != EFI_SUCCESS)
M
Matt Fleming 已提交
160 161
		goto free_handle;

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
	data = (struct setup_data *)(unsigned long)params->hdr.setup_data;

	while (data && data->next)
		data = (struct setup_data *)(unsigned long)data->next;

	nr_pci = size / (efi_is_64bit() ? sizeof(u64) : sizeof(u32));
	for (i = 0; i < nr_pci; i++) {
		efi_pci_io_protocol_t *pci = NULL;
		struct pci_setup_rom *rom;

		status = efi_call_early(handle_protocol,
					efi_is_64bit() ? ((u64 *)pci_handle)[i]
						       : ((u32 *)pci_handle)[i],
					&pci_proto, (void **)&pci);
		if (status != EFI_SUCCESS || !pci)
			continue;

		status = preserve_pci_rom_image(pci, &rom);
		if (status != EFI_SUCCESS)
			continue;

		if (data)
			data->next = (unsigned long)rom;
		else
			params->hdr.setup_data = (unsigned long)rom;

		data = (struct setup_data *)rom;
	}
M
Matt Fleming 已提交
190

191
free_handle:
192
	efi_call_early(free_pool, pci_handle);
193
}
M
Matt Fleming 已提交
194

195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
static void retrieve_apple_device_properties(struct boot_params *boot_params)
{
	efi_guid_t guid = APPLE_PROPERTIES_PROTOCOL_GUID;
	struct setup_data *data, *new;
	efi_status_t status;
	u32 size = 0;
	void *p;

	status = efi_call_early(locate_protocol, &guid, NULL, &p);
	if (status != EFI_SUCCESS)
		return;

	if (efi_table_attr(apple_properties_protocol, version, p) != 0x10000) {
		efi_printk(sys_table, "Unsupported properties proto version\n");
		return;
	}

	efi_call_proto(apple_properties_protocol, get_all, p, NULL, &size);
	if (!size)
		return;

	do {
		status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
					size + sizeof(struct setup_data), &new);
		if (status != EFI_SUCCESS) {
I
Ingo Molnar 已提交
220
			efi_printk(sys_table, "Failed to allocate memory for 'properties'\n");
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
			return;
		}

		status = efi_call_proto(apple_properties_protocol, get_all, p,
					new->data, &size);

		if (status == EFI_BUFFER_TOO_SMALL)
			efi_call_early(free_pool, new);
	} while (status == EFI_BUFFER_TOO_SMALL);

	new->type = SETUP_APPLE_PROPERTIES;
	new->len  = size;
	new->next = 0;

	data = (struct setup_data *)(unsigned long)boot_params->hdr.setup_data;
I
Ingo Molnar 已提交
236
	if (!data) {
237
		boot_params->hdr.setup_data = (unsigned long)new;
I
Ingo Molnar 已提交
238
	} else {
239 240 241 242 243 244
		while (data->next)
			data = (struct setup_data *)(unsigned long)data->next;
		data->next = (unsigned long)new;
	}
}

245 246
static const efi_char16_t apple[] = L"Apple";

247 248 249 250 251 252 253 254 255 256 257
static void setup_quirks(struct boot_params *boot_params)
{
	efi_char16_t *fw_vendor = (efi_char16_t *)(unsigned long)
		efi_table_attr(efi_system_table, fw_vendor, sys_table);

	if (!memcmp(fw_vendor, apple, sizeof(apple))) {
		if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
			retrieve_apple_device_properties(boot_params);
	}
}

258 259 260
/*
 * See if we have Universal Graphics Adapter (UGA) protocol
 */
261
static efi_status_t
262
setup_uga(struct screen_info *si, efi_guid_t *uga_proto, unsigned long size)
263
{
264 265 266
	efi_status_t status;
	u32 width, height;
	void **uga_handle = NULL;
267
	efi_uga_draw_protocol_t *uga = NULL, *first_uga;
268 269 270
	unsigned long nr_ugas;
	int i;

271 272 273 274
	status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
				size, (void **)&uga_handle);
	if (status != EFI_SUCCESS)
		return status;
275

276 277 278 279 280
	status = efi_call_early(locate_handle,
				EFI_LOCATE_BY_PROTOCOL,
				uga_proto, NULL, &size, uga_handle);
	if (status != EFI_SUCCESS)
		goto free_handle;
M
Matt Fleming 已提交
281

282 283
	height = 0;
	width = 0;
284 285

	first_uga = NULL;
286
	nr_ugas = size / (efi_is_64bit() ? sizeof(u64) : sizeof(u32));
M
Matt Fleming 已提交
287 288 289 290
	for (i = 0; i < nr_ugas; i++) {
		efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
		u32 w, h, depth, refresh;
		void *pciio;
291 292
		unsigned long handle = efi_is_64bit() ? ((u64 *)uga_handle)[i]
						      : ((u32 *)uga_handle)[i];
M
Matt Fleming 已提交
293

294
		status = efi_call_early(handle_protocol, handle,
295
					uga_proto, (void **)&uga);
M
Matt Fleming 已提交
296 297 298
		if (status != EFI_SUCCESS)
			continue;

299
		pciio = NULL;
300
		efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
M
Matt Fleming 已提交
301

302 303
		status = efi_call_proto(efi_uga_draw_protocol, get_mode, uga,
					&w, &h, &depth, &refresh);
M
Matt Fleming 已提交
304
		if (status == EFI_SUCCESS && (!first_uga || pciio)) {
305 306
			width = w;
			height = h;
M
Matt Fleming 已提交
307 308 309 310 311 312 313 314 315 316 317 318

			/*
			 * Once we've found a UGA supporting PCIIO,
			 * don't bother looking any further.
			 */
			if (pciio)
				break;

			first_uga = uga;
		}
	}

319
	if (!width && !height)
M
Matt Fleming 已提交
320 321 322
		goto free_handle;

	/* EFI framebuffer */
I
Ingo Molnar 已提交
323
	si->orig_video_isVGA	= VIDEO_TYPE_EFI;
M
Matt Fleming 已提交
324

I
Ingo Molnar 已提交
325 326 327
	si->lfb_depth		= 32;
	si->lfb_width		= width;
	si->lfb_height		= height;
M
Matt Fleming 已提交
328

I
Ingo Molnar 已提交
329 330 331 332 333 334 335 336
	si->red_size		= 8;
	si->red_pos		= 16;
	si->green_size		= 8;
	si->green_pos		= 8;
	si->blue_size		= 8;
	si->blue_pos		= 0;
	si->rsvd_size		= 8;
	si->rsvd_pos		= 24;
M
Matt Fleming 已提交
337 338

free_handle:
339
	efi_call_early(free_pool, uga_handle);
I
Ingo Molnar 已提交
340

M
Matt Fleming 已提交
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
	return status;
}

void setup_graphics(struct boot_params *boot_params)
{
	efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
	struct screen_info *si;
	efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
	efi_status_t status;
	unsigned long size;
	void **gop_handle = NULL;
	void **uga_handle = NULL;

	si = &boot_params->screen_info;
	memset(si, 0, sizeof(*si));

	size = 0;
358 359 360
	status = efi_call_early(locate_handle,
				EFI_LOCATE_BY_PROTOCOL,
				&graphics_proto, NULL, &size, gop_handle);
M
Matt Fleming 已提交
361
	if (status == EFI_BUFFER_TOO_SMALL)
362
		status = efi_setup_gop(NULL, si, &graphics_proto, size);
M
Matt Fleming 已提交
363 364 365

	if (status != EFI_SUCCESS) {
		size = 0;
366 367 368
		status = efi_call_early(locate_handle,
					EFI_LOCATE_BY_PROTOCOL,
					&uga_proto, NULL, &size, uga_handle);
M
Matt Fleming 已提交
369 370 371 372 373 374 375 376 377
		if (status == EFI_BUFFER_TOO_SMALL)
			setup_uga(si, &uga_proto, size);
	}
}

/*
 * Because the x86 boot code expects to be passed a boot_params we
 * need to create one ourselves (usually the bootloader would create
 * one for us).
378 379 380
 *
 * The caller is responsible for filling out ->code32_start in the
 * returned boot_params.
M
Matt Fleming 已提交
381
 */
382
struct boot_params *make_boot_params(struct efi_config *c)
M
Matt Fleming 已提交
383
{
M
Matt Fleming 已提交
384 385 386 387
	struct boot_params *boot_params;
	struct apm_bios_info *bi;
	struct setup_header *hdr;
	efi_loaded_image_t *image;
388
	void *options, *handle;
M
Matt Fleming 已提交
389
	efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
M
Matt Fleming 已提交
390 391
	int options_size = 0;
	efi_status_t status;
392
	char *cmdline_ptr;
M
Matt Fleming 已提交
393 394 395
	u16 *s2;
	u8 *s1;
	int i;
396 397
	unsigned long ramdisk_addr;
	unsigned long ramdisk_size;
M
Matt Fleming 已提交
398

399 400 401
	efi_early = c;
	sys_table = (efi_system_table_t *)(unsigned long)efi_early->table;
	handle = (void *)(unsigned long)efi_early->image_handle;
M
Matt Fleming 已提交
402 403 404 405 406

	/* Check if we were booted by the EFI firmware */
	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
		return NULL;

407 408 409 410 411
	if (efi_early->is64)
		setup_boot_services64(efi_early);
	else
		setup_boot_services32(efi_early);

412 413
	status = efi_call_early(handle_protocol, handle,
				&proto, (void *)&image);
M
Matt Fleming 已提交
414
	if (status != EFI_SUCCESS) {
415
		efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
M
Matt Fleming 已提交
416 417 418
		return NULL;
	}

419 420
	status = efi_low_alloc(sys_table, 0x4000, 1,
			       (unsigned long *)&boot_params);
M
Matt Fleming 已提交
421
	if (status != EFI_SUCCESS) {
I
Ingo Molnar 已提交
422
		efi_printk(sys_table, "Failed to allocate lowmem for boot params\n");
M
Matt Fleming 已提交
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
		return NULL;
	}

	memset(boot_params, 0x0, 0x4000);

	hdr = &boot_params->hdr;
	bi = &boot_params->apm_bios_info;

	/* Copy the second sector to boot_params */
	memcpy(&hdr->jump, image->image_base + 512, 512);

	/*
	 * Fill out some of the header fields ourselves because the
	 * EFI firmware loader doesn't load the first sector.
	 */
I
Ingo Molnar 已提交
438 439 440
	hdr->root_flags	= 1;
	hdr->vid_mode	= 0xffff;
	hdr->boot_flag	= 0xAA55;
M
Matt Fleming 已提交
441

M
Matt Fleming 已提交
442 443 444
	hdr->type_of_loader = 0x21;

	/* Convert unicode cmdline to ascii */
445
	cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
446 447
	if (!cmdline_ptr)
		goto fail;
I
Ingo Molnar 已提交
448

449
	hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
450 451
	/* Fill in upper bits of command line address, NOP on 32 bit  */
	boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;
M
Matt Fleming 已提交
452 453 454 455 456 457 458

	hdr->ramdisk_image = 0;
	hdr->ramdisk_size = 0;

	/* Clear APM BIOS info */
	memset(bi, 0, sizeof(*bi));

459 460 461 462
	status = efi_parse_options(cmdline_ptr);
	if (status != EFI_SUCCESS)
		goto fail2;

463 464
	status = handle_cmdline_files(sys_table, image,
				      (char *)(unsigned long)hdr->cmd_line_ptr,
465
				      "initrd=", hdr->initrd_addr_max,
466
				      &ramdisk_addr, &ramdisk_size);
467 468 469 470 471 472 473 474 475 476

	if (status != EFI_SUCCESS &&
	    hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) {
		efi_printk(sys_table, "Trying to load files to higher address\n");
		status = handle_cmdline_files(sys_table, image,
				      (char *)(unsigned long)hdr->cmd_line_ptr,
				      "initrd=", -1UL,
				      &ramdisk_addr, &ramdisk_size);
	}

M
Matt Fleming 已提交
477 478
	if (status != EFI_SUCCESS)
		goto fail2;
479 480 481 482
	hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
	hdr->ramdisk_size  = ramdisk_size & 0xffffffff;
	boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
	boot_params->ext_ramdisk_size  = (u64)ramdisk_size >> 32;
M
Matt Fleming 已提交
483 484

	return boot_params;
I
Ingo Molnar 已提交
485

M
Matt Fleming 已提交
486
fail2:
487
	efi_free(sys_table, options_size, hdr->cmd_line_ptr);
M
Matt Fleming 已提交
488
fail:
489
	efi_free(sys_table, 0x4000, (unsigned long)boot_params);
I
Ingo Molnar 已提交
490

M
Matt Fleming 已提交
491 492 493
	return NULL;
}

494 495
static void add_e820ext(struct boot_params *params,
			struct setup_data *e820ext, u32 nr_entries)
M
Matt Fleming 已提交
496
{
497
	struct setup_data *data;
M
Matt Fleming 已提交
498
	efi_status_t status;
499
	unsigned long size;
M
Matt Fleming 已提交
500

501
	e820ext->type = SETUP_E820_EXT;
I
Ingo Molnar 已提交
502
	e820ext->len  = nr_entries * sizeof(struct boot_e820_entry);
503
	e820ext->next = 0;
M
Matt Fleming 已提交
504

505
	data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
M
Matt Fleming 已提交
506

507 508
	while (data && data->next)
		data = (struct setup_data *)(unsigned long)data->next;
509

510 511 512 513 514
	if (data)
		data->next = (unsigned long)e820ext;
	else
		params->hdr.setup_data = (unsigned long)e820ext;
}
M
Matt Fleming 已提交
515

I
Ingo Molnar 已提交
516 517
static efi_status_t
setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_size)
518
{
519
	struct boot_e820_entry *entry = params->e820_table;
520
	struct efi_info *efi = &params->efi_info;
521
	struct boot_e820_entry *prev = NULL;
522 523 524
	u32 nr_entries;
	u32 nr_desc;
	int i;
M
Matt Fleming 已提交
525 526

	nr_entries = 0;
527 528 529
	nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size;

	for (i = 0; i < nr_desc; i++) {
M
Matt Fleming 已提交
530 531
		efi_memory_desc_t *d;
		unsigned int e820_type = 0;
532
		unsigned long m = efi->efi_memmap;
M
Matt Fleming 已提交
533

534 535 536 537
#ifdef CONFIG_X86_64
		m |= (u64)efi->efi_memmap_hi << 32;
#endif

538
		d = efi_early_memdesc_ptr(m, efi->efi_memdesc_size, i);
M
Matt Fleming 已提交
539 540 541 542 543 544 545
		switch (d->type) {
		case EFI_RESERVED_TYPE:
		case EFI_RUNTIME_SERVICES_CODE:
		case EFI_RUNTIME_SERVICES_DATA:
		case EFI_MEMORY_MAPPED_IO:
		case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
		case EFI_PAL_CODE:
546
			e820_type = E820_TYPE_RESERVED;
M
Matt Fleming 已提交
547 548 549
			break;

		case EFI_UNUSABLE_MEMORY:
550
			e820_type = E820_TYPE_UNUSABLE;
M
Matt Fleming 已提交
551 552 553
			break;

		case EFI_ACPI_RECLAIM_MEMORY:
554
			e820_type = E820_TYPE_ACPI;
M
Matt Fleming 已提交
555 556 557 558 559 560 561
			break;

		case EFI_LOADER_CODE:
		case EFI_LOADER_DATA:
		case EFI_BOOT_SERVICES_CODE:
		case EFI_BOOT_SERVICES_DATA:
		case EFI_CONVENTIONAL_MEMORY:
562
			e820_type = E820_TYPE_RAM;
M
Matt Fleming 已提交
563 564 565
			break;

		case EFI_ACPI_MEMORY_NVS:
566
			e820_type = E820_TYPE_NVS;
M
Matt Fleming 已提交
567 568
			break;

569
		case EFI_PERSISTENT_MEMORY:
570
			e820_type = E820_TYPE_PMEM;
571 572
			break;

M
Matt Fleming 已提交
573 574 575 576 577 578
		default:
			continue;
		}

		/* Merge adjacent mappings */
		if (prev && prev->type == e820_type &&
579
		    (prev->addr + prev->size) == d->phys_addr) {
M
Matt Fleming 已提交
580
			prev->size += d->num_pages << 12;
581
			continue;
M
Matt Fleming 已提交
582
		}
583

584
		if (nr_entries == ARRAY_SIZE(params->e820_table)) {
585
			u32 need = (nr_desc - i) * sizeof(struct e820_entry) +
586 587 588 589 590 591
				   sizeof(struct setup_data);

			if (!e820ext || e820ext_size < need)
				return EFI_BUFFER_TOO_SMALL;

			/* boot_params map full, switch to e820 extended */
592
			entry = (struct boot_e820_entry *)e820ext->data;
593 594
		}

595 596 597 598
		entry->addr = d->phys_addr;
		entry->size = d->num_pages << PAGE_SHIFT;
		entry->type = e820_type;
		prev = entry++;
599
		nr_entries++;
M
Matt Fleming 已提交
600 601
	}

602 603
	if (nr_entries > ARRAY_SIZE(params->e820_table)) {
		u32 nr_e820ext = nr_entries - ARRAY_SIZE(params->e820_table);
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620

		add_e820ext(params, e820ext, nr_e820ext);
		nr_entries -= nr_e820ext;
	}

	params->e820_entries = (u8)nr_entries;

	return EFI_SUCCESS;
}

static efi_status_t alloc_e820ext(u32 nr_desc, struct setup_data **e820ext,
				  u32 *e820ext_size)
{
	efi_status_t status;
	unsigned long size;

	size = sizeof(struct setup_data) +
621
		sizeof(struct e820_entry) * nr_desc;
622 623

	if (*e820ext) {
624
		efi_call_early(free_pool, *e820ext);
625 626 627 628
		*e820ext = NULL;
		*e820ext_size = 0;
	}

629 630
	status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
				size, (void **)e820ext);
631 632 633 634 635 636
	if (status == EFI_SUCCESS)
		*e820ext_size = size;

	return status;
}

637
struct exit_boot_struct {
I
Ingo Molnar 已提交
638 639 640 641 642
	struct boot_params	*boot_params;
	struct efi_info		*efi;
	struct setup_data	*e820ext;
	__u32			e820ext_size;
	bool			is64;
643 644 645 646 647 648 649 650 651 652 653 654 655 656
};

static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
				   struct efi_boot_memmap *map,
				   void *priv)
{
	static bool first = true;
	const char *signature;
	__u32 nr_desc;
	efi_status_t status;
	struct exit_boot_struct *p = priv;

	if (first) {
		nr_desc = *map->buff_size / *map->desc_size;
657
		if (nr_desc > ARRAY_SIZE(p->boot_params->e820_table)) {
658
			u32 nr_e820ext = nr_desc -
659
					ARRAY_SIZE(p->boot_params->e820_table);
660 661 662 663 664 665 666 667 668 669 670 671

			status = alloc_e820ext(nr_e820ext, &p->e820ext,
					       &p->e820ext_size);
			if (status != EFI_SUCCESS)
				return status;
		}
		first = false;
	}

	signature = p->is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE;
	memcpy(&p->efi->efi_loader_signature, signature, sizeof(__u32));

I
Ingo Molnar 已提交
672 673 674 675 676
	p->efi->efi_systab		= (unsigned long)sys_table_arg;
	p->efi->efi_memdesc_size	= *map->desc_size;
	p->efi->efi_memdesc_version	= *map->desc_ver;
	p->efi->efi_memmap		= (unsigned long)*map->map;
	p->efi->efi_memmap_size		= *map->map_size;
677 678

#ifdef CONFIG_X86_64
I
Ingo Molnar 已提交
679 680
	p->efi->efi_systab_hi		= (unsigned long)sys_table_arg >> 32;
	p->efi->efi_memmap_hi		= (unsigned long)*map->map >> 32;
681 682 683 684 685
#endif

	return EFI_SUCCESS;
}

686
static efi_status_t exit_boot(struct boot_params *boot_params,
687
			      void *handle, bool is64)
688
{
689
	unsigned long map_sz, key, desc_size, buff_size;
690 691 692 693 694
	efi_memory_desc_t *mem_map;
	struct setup_data *e820ext;
	__u32 e820ext_size;
	efi_status_t status;
	__u32 desc_version;
695
	struct efi_boot_memmap map;
696 697
	struct exit_boot_struct priv;

I
Ingo Molnar 已提交
698 699 700 701 702 703 704 705 706 707 708
	map.map			= &mem_map;
	map.map_size		= &map_sz;
	map.desc_size		= &desc_size;
	map.desc_ver		= &desc_version;
	map.key_ptr		= &key;
	map.buff_size		= &buff_size;
	priv.boot_params	= boot_params;
	priv.efi		= &boot_params->efi_info;
	priv.e820ext		= NULL;
	priv.e820ext_size	= 0;
	priv.is64		= is64;
709

710 711 712
	/* Might as well exit boot services now */
	status = efi_exit_boot_services(sys_table, handle, &map, &priv,
					exit_boot_func);
713 714 715
	if (status != EFI_SUCCESS)
		return status;

I
Ingo Molnar 已提交
716 717 718
	e820ext			= priv.e820ext;
	e820ext_size		= priv.e820ext_size;

719
	/* Historic? */
I
Ingo Molnar 已提交
720
	boot_params->alt_mem_k	= 32 * 1024;
721 722 723 724

	status = setup_e820(boot_params, e820ext, e820ext_size);
	if (status != EFI_SUCCESS)
		return status;
M
Matt Fleming 已提交
725 726 727 728

	return EFI_SUCCESS;
}

M
Matt Fleming 已提交
729 730 731 732
/*
 * On success we return a pointer to a boot_params structure, and NULL
 * on failure.
 */
I
Ingo Molnar 已提交
733 734
struct boot_params *
efi_main(struct efi_config *c, struct boot_params *boot_params)
M
Matt Fleming 已提交
735
{
736
	struct desc_ptr *gdt = NULL;
M
Matt Fleming 已提交
737 738 739 740
	efi_loaded_image_t *image;
	struct setup_header *hdr = &boot_params->hdr;
	efi_status_t status;
	struct desc_struct *desc;
741 742 743 744 745 746 747 748 749
	void *handle;
	efi_system_table_t *_table;
	bool is64;

	efi_early = c;

	_table = (efi_system_table_t *)(unsigned long)efi_early->table;
	handle = (void *)(unsigned long)efi_early->image_handle;
	is64 = efi_early->is64;
M
Matt Fleming 已提交
750 751 752 753 754 755 756

	sys_table = _table;

	/* Check if we were booted by the EFI firmware */
	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
		goto fail;

757 758 759 760 761
	if (is64)
		setup_boot_services64(efi_early);
	else
		setup_boot_services32(efi_early);

762 763 764 765 766 767
	/*
	 * If the boot loader gave us a value for secure_boot then we use that,
	 * otherwise we ask the BIOS.
	 */
	if (boot_params->secure_boot == efi_secureboot_mode_unset)
		boot_params->secure_boot = efi_get_secureboot(sys_table);
768 769 770

	/* Ask the firmware to clear memory on unclean shutdown */
	efi_enable_reset_attack_mitigation(sys_table);
771
	efi_retrieve_tpm2_eventlog(sys_table);
772

M
Matt Fleming 已提交
773
	setup_graphics(boot_params);
M
Matt Fleming 已提交
774

775
	setup_efi_pci(boot_params);
776

777 778
	setup_quirks(boot_params);

779 780
	status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
				sizeof(*gdt), (void **)&gdt);
781
	if (status != EFI_SUCCESS) {
I
Ingo Molnar 已提交
782
		efi_printk(sys_table, "Failed to allocate memory for 'gdt' structure\n");
M
Matt Fleming 已提交
783
		goto fail;
784
	}
M
Matt Fleming 已提交
785 786

	gdt->size = 0x800;
787
	status = efi_low_alloc(sys_table, gdt->size, 8,
788
			   (unsigned long *)&gdt->address);
789
	if (status != EFI_SUCCESS) {
I
Ingo Molnar 已提交
790
		efi_printk(sys_table, "Failed to allocate memory for 'gdt'\n");
M
Matt Fleming 已提交
791
		goto fail;
792
	}
M
Matt Fleming 已提交
793

M
Matt Fleming 已提交
794 795 796 797 798
	/*
	 * If the kernel isn't already loaded at the preferred load
	 * address, relocate it.
	 */
	if (hdr->pref_address != hdr->code32_start) {
799 800 801 802 803
		unsigned long bzimage_addr = hdr->code32_start;
		status = efi_relocate_kernel(sys_table, &bzimage_addr,
					     hdr->init_size, hdr->init_size,
					     hdr->pref_address,
					     hdr->kernel_alignment);
804 805
		if (status != EFI_SUCCESS) {
			efi_printk(sys_table, "efi_relocate_kernel() failed!\n");
M
Matt Fleming 已提交
806
			goto fail;
807
		}
808 809 810

		hdr->pref_address = hdr->code32_start;
		hdr->code32_start = bzimage_addr;
M
Matt Fleming 已提交
811 812
	}

813
	status = exit_boot(boot_params, handle, is64);
814 815
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "exit_boot() failed!\n");
M
Matt Fleming 已提交
816
		goto fail;
817
	}
M
Matt Fleming 已提交
818 819 820 821

	memset((char *)gdt->address, 0x0, gdt->size);
	desc = (struct desc_struct *)gdt->address;

822 823 824 825 826
	/* The first GDT is a dummy. */
	desc++;

	if (IS_ENABLED(CONFIG_X86_64)) {
		/* __KERNEL32_CS */
I
Ingo Molnar 已提交
827 828 829 830 831 832 833 834 835 836 837 838 839 840
		desc->limit0	= 0xffff;
		desc->base0	= 0x0000;
		desc->base1	= 0x0000;
		desc->type	= SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
		desc->s		= DESC_TYPE_CODE_DATA;
		desc->dpl	= 0;
		desc->p		= 1;
		desc->limit1	= 0xf;
		desc->avl	= 0;
		desc->l		= 0;
		desc->d		= SEG_OP_SIZE_32BIT;
		desc->g		= SEG_GRANULARITY_4KB;
		desc->base2	= 0x00;

841 842 843 844 845
		desc++;
	} else {
		/* Second entry is unused on 32-bit */
		desc++;
	}
M
Matt Fleming 已提交
846

847
	/* __KERNEL_CS */
I
Ingo Molnar 已提交
848 849 850 851 852 853 854 855 856 857
	desc->limit0	= 0xffff;
	desc->base0	= 0x0000;
	desc->base1	= 0x0000;
	desc->type	= SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
	desc->s		= DESC_TYPE_CODE_DATA;
	desc->dpl	= 0;
	desc->p		= 1;
	desc->limit1	= 0xf;
	desc->avl	= 0;

858 859 860 861 862 863 864
	if (IS_ENABLED(CONFIG_X86_64)) {
		desc->l = 1;
		desc->d = 0;
	} else {
		desc->l = 0;
		desc->d = SEG_OP_SIZE_32BIT;
	}
I
Ingo Molnar 已提交
865 866
	desc->g		= SEG_GRANULARITY_4KB;
	desc->base2	= 0x00;
M
Matt Fleming 已提交
867
	desc++;
868 869

	/* __KERNEL_DS */
I
Ingo Molnar 已提交
870 871 872 873 874 875 876 877 878 879 880 881 882
	desc->limit0	= 0xffff;
	desc->base0	= 0x0000;
	desc->base1	= 0x0000;
	desc->type	= SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
	desc->s		= DESC_TYPE_CODE_DATA;
	desc->dpl	= 0;
	desc->p		= 1;
	desc->limit1	= 0xf;
	desc->avl	= 0;
	desc->l		= 0;
	desc->d		= SEG_OP_SIZE_32BIT;
	desc->g		= SEG_GRANULARITY_4KB;
	desc->base2	= 0x00;
M
Matt Fleming 已提交
883
	desc++;
884 885 886

	if (IS_ENABLED(CONFIG_X86_64)) {
		/* Task segment value */
I
Ingo Molnar 已提交
887 888 889 890 891 892 893 894 895 896 897 898 899
		desc->limit0	= 0x0000;
		desc->base0	= 0x0000;
		desc->base1	= 0x0000;
		desc->type	= SEG_TYPE_TSS;
		desc->s		= 0;
		desc->dpl	= 0;
		desc->p		= 1;
		desc->limit1	= 0x0;
		desc->avl	= 0;
		desc->l		= 0;
		desc->d		= 0;
		desc->g		= SEG_GRANULARITY_4KB;
		desc->base2	= 0x00;
900 901
		desc++;
	}
M
Matt Fleming 已提交
902 903

	asm volatile("cli");
904
	asm volatile ("lgdt %0" : : "m" (*gdt));
M
Matt Fleming 已提交
905 906 907

	return boot_params;
fail:
908
	efi_printk(sys_table, "efi_main() failed!\n");
I
Ingo Molnar 已提交
909

M
Matt Fleming 已提交
910 911
	return NULL;
}