eboot.c 26.5 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>
M
Matt Fleming 已提交
12 13 14 15
#include <asm/efi.h>
#include <asm/setup.h>
#include <asm/desc.h>

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

static efi_system_table_t *sys_table;

21 22
static struct efi_config *efi_early;

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

28 29 30 31 32 33 34
#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;				\
									\
35
	c->boot_services = table->boottime;				\
36 37 38 39
	c->text_output = table->con_out;				\
}
BOOT_SERVICES(32);
BOOT_SERVICES(64);
M
Matt Fleming 已提交
40

41 42 43 44 45 46 47 48 49 50
static inline efi_status_t __open_volume32(void *__image, void **__fh)
{
	efi_file_io_interface_t *io;
	efi_loaded_image_32_t *image = __image;
	efi_file_handle_32_t *fh;
	efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
	efi_status_t status;
	void *handle = (void *)(unsigned long)image->device_handle;
	unsigned long func;

51 52
	status = efi_call_early(handle_protocol, handle,
				&fs_proto, (void **)&io);
53 54 55 56 57 58 59 60 61
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to handle fs_proto\n");
		return status;
	}

	func = (unsigned long)io->open_volume;
	status = efi_early->call(func, io, &fh);
	if (status != EFI_SUCCESS)
		efi_printk(sys_table, "Failed to open volume\n");
M
Matt Fleming 已提交
62

63 64
	*__fh = fh;
	return status;
65 66
}

67
static inline efi_status_t __open_volume64(void *__image, void **__fh)
68 69
{
	efi_file_io_interface_t *io;
70 71
	efi_loaded_image_64_t *image = __image;
	efi_file_handle_64_t *fh;
72 73 74
	efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
	efi_status_t status;
	void *handle = (void *)(unsigned long)image->device_handle;
75
	unsigned long func;
76

77 78
	status = efi_call_early(handle_protocol, handle,
				&fs_proto, (void **)&io);
79 80 81 82
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to handle fs_proto\n");
		return status;
	}
M
Matt Fleming 已提交
83

84 85 86 87 88 89 90 91 92
	func = (unsigned long)io->open_volume;
	status = efi_early->call(func, io, &fh);
	if (status != EFI_SUCCESS)
		efi_printk(sys_table, "Failed to open volume\n");

	*__fh = fh;
	return status;
}

93
efi_status_t
94 95 96 97 98 99 100 101
efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh)
{
	if (efi_early->is64)
		return __open_volume64(__image, __fh);

	return __open_volume32(__image, __fh);
}

102
void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
103
{
104 105
	efi_call_proto(efi_simple_text_output_protocol, output_string,
		       efi_early->text_output, str);
106 107
}

108 109
static efi_status_t
__setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom)
110
{
111
	struct pci_setup_rom *rom = NULL;
112
	efi_status_t status;
113 114
	unsigned long size;
	uint64_t attributes;
115

116 117 118 119 120
	status = efi_early->call(pci->attributes, pci,
				 EfiPciIoAttributeOperationGet, 0, 0,
				 &attributes);
	if (status != EFI_SUCCESS)
		return status;
121

122 123
	if (!pci->romimage || !pci->romsize)
		return EFI_INVALID_PARAMETER;
124

125
	size = pci->romsize + sizeof(*rom);
126

127
	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
128 129
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to alloc mem for rom\n");
130
		return status;
131
	}
132

133 134 135 136 137 138 139 140 141 142
	memset(rom, 0, sizeof(*rom));

	rom->data.type = SETUP_PCI;
	rom->data.len = size - sizeof(struct setup_data);
	rom->data.next = 0;
	rom->pcilen = pci->romsize;
	*__rom = rom;

	status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
				 PCI_VENDOR_ID, 1, &(rom->vendor));
143

144 145
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to read rom->vendor\n");
146
		goto free_struct;
147
	}
148 149 150 151

	status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
				 PCI_DEVICE_ID, 1, &(rom->devid));

152 153
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to read rom->devid\n");
154
		goto free_struct;
155
	}
156 157 158 159 160 161 162 163 164 165 166

	status = efi_early->call(pci->get_location, pci, &(rom->segment),
				 &(rom->bus), &(rom->device), &(rom->function));

	if (status != EFI_SUCCESS)
		goto free_struct;

	memcpy(rom->romdata, pci->romimage, pci->romsize);
	return status;

free_struct:
167
	efi_call_early(free_pool, rom);
168 169 170
	return status;
}

171
static void
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
setup_efi_pci32(struct boot_params *params, void **pci_handle,
		unsigned long size)
{
	efi_pci_io_protocol_32 *pci = NULL;
	efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
	u32 *handles = (u32 *)(unsigned long)pci_handle;
	efi_status_t status;
	unsigned long nr_pci;
	struct setup_data *data;
	int i;

	data = (struct setup_data *)(unsigned long)params->hdr.setup_data;

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

188
	nr_pci = size / sizeof(u32);
189
	for (i = 0; i < nr_pci; i++) {
190 191
		struct pci_setup_rom *rom = NULL;
		u32 h = handles[i];
192

193 194
		status = efi_call_early(handle_protocol, h,
					&pci_proto, (void **)&pci);
195 196 197 198 199 200 201

		if (status != EFI_SUCCESS)
			continue;

		if (!pci)
			continue;

202
		status = __setup_efi_pci32(pci, &rom);
203 204 205
		if (status != EFI_SUCCESS)
			continue;

206 207 208 209 210 211
		if (data)
			data->next = (unsigned long)rom;
		else
			params->hdr.setup_data = (unsigned long)rom;

		data = (struct setup_data *)rom;
212

213 214
	}
}
215

216 217 218 219 220 221 222
static efi_status_t
__setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom)
{
	struct pci_setup_rom *rom;
	efi_status_t status;
	unsigned long size;
	uint64_t attributes;
223

224 225 226 227 228
	status = efi_early->call(pci->attributes, pci,
				 EfiPciIoAttributeOperationGet, 0,
				 &attributes);
	if (status != EFI_SUCCESS)
		return status;
229

230 231
	if (!pci->romimage || !pci->romsize)
		return EFI_INVALID_PARAMETER;
232

233
	size = pci->romsize + sizeof(*rom);
234

235
	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);
236 237
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to alloc mem for rom\n");
238
		return status;
239
	}
240 241 242 243 244 245 246 247 248 249

	rom->data.type = SETUP_PCI;
	rom->data.len = size - sizeof(struct setup_data);
	rom->data.next = 0;
	rom->pcilen = pci->romsize;
	*__rom = rom;

	status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
				 PCI_VENDOR_ID, 1, &(rom->vendor));

250 251
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to read rom->vendor\n");
252
		goto free_struct;
253
	}
254 255 256 257

	status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16,
				 PCI_DEVICE_ID, 1, &(rom->devid));

258 259
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to read rom->devid\n");
260
		goto free_struct;
261
	}
262 263 264 265 266 267 268 269 270 271 272

	status = efi_early->call(pci->get_location, pci, &(rom->segment),
				 &(rom->bus), &(rom->device), &(rom->function));

	if (status != EFI_SUCCESS)
		goto free_struct;

	memcpy(rom->romdata, pci->romimage, pci->romsize);
	return status;

free_struct:
273
	efi_call_early(free_pool, rom);
274 275 276 277
	return status;

}

278
static void
279 280 281 282 283 284 285 286 287 288
setup_efi_pci64(struct boot_params *params, void **pci_handle,
		unsigned long size)
{
	efi_pci_io_protocol_64 *pci = NULL;
	efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
	u64 *handles = (u64 *)(unsigned long)pci_handle;
	efi_status_t status;
	unsigned long nr_pci;
	struct setup_data *data;
	int i;
289

290 291 292 293 294 295 296 297 298 299
	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 / sizeof(u64);
	for (i = 0; i < nr_pci; i++) {
		struct pci_setup_rom *rom = NULL;
		u64 h = handles[i];

300 301
		status = efi_call_early(handle_protocol, h,
					&pci_proto, (void **)&pci);
302 303

		if (status != EFI_SUCCESS)
304 305 306 307
			continue;

		if (!pci)
			continue;
308

309 310 311
		status = __setup_efi_pci64(pci, &rom);
		if (status != EFI_SUCCESS)
			continue;
312 313

		if (data)
314
			data->next = (unsigned long)rom;
315
		else
316
			params->hdr.setup_data = (unsigned long)rom;
317 318 319 320 321 322

		data = (struct setup_data *)rom;

	}
}

323 324 325 326 327 328 329 330 331 332
/*
 * 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 已提交
333 334
{
	efi_status_t status;
335 336 337
	void **pci_handle = NULL;
	efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
	unsigned long size = 0;
M
Matt Fleming 已提交
338

339 340 341
	status = efi_call_early(locate_handle,
				EFI_LOCATE_BY_PROTOCOL,
				&pci_proto, NULL, &size, pci_handle);
M
Matt Fleming 已提交
342

343
	if (status == EFI_BUFFER_TOO_SMALL) {
344 345 346
		status = efi_call_early(allocate_pool,
					EFI_LOADER_DATA,
					size, (void **)&pci_handle);
M
Matt Fleming 已提交
347

348 349
		if (status != EFI_SUCCESS) {
			efi_printk(sys_table, "Failed to alloc mem for pci_handle\n");
350
			return;
351
		}
M
Matt Fleming 已提交
352

353 354 355
		status = efi_call_early(locate_handle,
					EFI_LOCATE_BY_PROTOCOL, &pci_proto,
					NULL, &size, pci_handle);
M
Matt Fleming 已提交
356 357
	}

358
	if (status != EFI_SUCCESS)
M
Matt Fleming 已提交
359 360
		goto free_handle;

361
	if (efi_early->is64)
362
		setup_efi_pci64(params, pci_handle, size);
363
	else
364
		setup_efi_pci32(params, pci_handle, size);
M
Matt Fleming 已提交
365

366
free_handle:
367
	efi_call_early(free_pool, pci_handle);
368
}
M
Matt Fleming 已提交
369

370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
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) {
			efi_printk(sys_table,
					"Failed to alloc mem for properties\n");
			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;
	if (!data)
		boot_params->hdr.setup_data = (unsigned long)new;
	else {
		while (data->next)
			data = (struct setup_data *)(unsigned long)data->next;
		data->next = (unsigned long)new;
	}
}

static void setup_quirks(struct boot_params *boot_params)
{
	efi_char16_t const apple[] = { 'A', 'p', 'p', 'l', 'e', 0 };
	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);
	}
}

433 434 435 436 437 438 439
static efi_status_t
setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
{
	struct efi_uga_draw_protocol *uga = NULL, *first_uga;
	efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
	unsigned long nr_ugas;
	u32 *handles = (u32 *)uga_handle;;
440
	efi_status_t status = EFI_INVALID_PARAMETER;
441 442
	int i;

M
Matt Fleming 已提交
443
	first_uga = NULL;
444 445 446 447 448 449 450
	nr_ugas = size / sizeof(u32);
	for (i = 0; i < nr_ugas; i++) {
		efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
		u32 w, h, depth, refresh;
		void *pciio;
		u32 handle = handles[i];

451 452
		status = efi_call_early(handle_protocol, handle,
					&uga_proto, (void **)&uga);
453 454 455
		if (status != EFI_SUCCESS)
			continue;

456
		efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476

		status = efi_early->call((unsigned long)uga->get_mode, uga,
					 &w, &h, &depth, &refresh);
		if (status == EFI_SUCCESS && (!first_uga || pciio)) {
			*width = w;
			*height = h;

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

			first_uga = uga;
		}
	}

	return status;
}
M
Matt Fleming 已提交
477

478 479 480 481 482 483 484
static efi_status_t
setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
{
	struct efi_uga_draw_protocol *uga = NULL, *first_uga;
	efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
	unsigned long nr_ugas;
	u64 *handles = (u64 *)uga_handle;;
485
	efi_status_t status = EFI_INVALID_PARAMETER;
486 487 488 489
	int i;

	first_uga = NULL;
	nr_ugas = size / sizeof(u64);
M
Matt Fleming 已提交
490 491 492 493
	for (i = 0; i < nr_ugas; i++) {
		efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID;
		u32 w, h, depth, refresh;
		void *pciio;
494
		u64 handle = handles[i];
M
Matt Fleming 已提交
495

496 497
		status = efi_call_early(handle_protocol, handle,
					&uga_proto, (void **)&uga);
M
Matt Fleming 已提交
498 499 500
		if (status != EFI_SUCCESS)
			continue;

501
		efi_call_early(handle_protocol, handle, &pciio_proto, &pciio);
M
Matt Fleming 已提交
502

503 504
		status = efi_early->call((unsigned long)uga->get_mode, uga,
					 &w, &h, &depth, &refresh);
M
Matt Fleming 已提交
505
		if (status == EFI_SUCCESS && (!first_uga || pciio)) {
506 507
			*width = w;
			*height = h;
M
Matt Fleming 已提交
508 509 510 511 512 513 514 515 516 517 518 519

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

			first_uga = uga;
		}
	}

520 521 522 523 524 525 526 527 528 529 530 531 532
	return status;
}

/*
 * See if we have Universal Graphics Adapter (UGA) protocol
 */
static efi_status_t setup_uga(struct screen_info *si, efi_guid_t *uga_proto,
			      unsigned long size)
{
	efi_status_t status;
	u32 width, height;
	void **uga_handle = NULL;

533 534
	status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
				size, (void **)&uga_handle);
535 536 537
	if (status != EFI_SUCCESS)
		return status;

538 539 540
	status = efi_call_early(locate_handle,
				EFI_LOCATE_BY_PROTOCOL,
				uga_proto, NULL, &size, uga_handle);
541 542 543 544 545 546 547 548 549 550 551 552
	if (status != EFI_SUCCESS)
		goto free_handle;

	height = 0;
	width = 0;

	if (efi_early->is64)
		status = setup_uga64(uga_handle, size, &width, &height);
	else
		status = setup_uga32(uga_handle, size, &width, &height);

	if (!width && !height)
M
Matt Fleming 已提交
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
		goto free_handle;

	/* EFI framebuffer */
	si->orig_video_isVGA = VIDEO_TYPE_EFI;

	si->lfb_depth = 32;
	si->lfb_width = width;
	si->lfb_height = height;

	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;

free_handle:
572
	efi_call_early(free_pool, uga_handle);
M
Matt Fleming 已提交
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
	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;
590 591 592
	status = efi_call_early(locate_handle,
				EFI_LOCATE_BY_PROTOCOL,
				&graphics_proto, NULL, &size, gop_handle);
M
Matt Fleming 已提交
593
	if (status == EFI_BUFFER_TOO_SMALL)
594
		status = efi_setup_gop(NULL, si, &graphics_proto, size);
M
Matt Fleming 已提交
595 596 597

	if (status != EFI_SUCCESS) {
		size = 0;
598 599 600
		status = efi_call_early(locate_handle,
					EFI_LOCATE_BY_PROTOCOL,
					&uga_proto, NULL, &size, uga_handle);
M
Matt Fleming 已提交
601 602 603 604 605 606 607 608 609
		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).
610 611 612
 *
 * The caller is responsible for filling out ->code32_start in the
 * returned boot_params.
M
Matt Fleming 已提交
613
 */
614
struct boot_params *make_boot_params(struct efi_config *c)
M
Matt Fleming 已提交
615
{
M
Matt Fleming 已提交
616 617 618 619
	struct boot_params *boot_params;
	struct apm_bios_info *bi;
	struct setup_header *hdr;
	efi_loaded_image_t *image;
620
	void *options, *handle;
M
Matt Fleming 已提交
621
	efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
M
Matt Fleming 已提交
622 623
	int options_size = 0;
	efi_status_t status;
624
	char *cmdline_ptr;
M
Matt Fleming 已提交
625 626 627
	u16 *s2;
	u8 *s1;
	int i;
628 629
	unsigned long ramdisk_addr;
	unsigned long ramdisk_size;
M
Matt Fleming 已提交
630

631 632 633
	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 已提交
634 635 636 637 638

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

639 640 641 642 643
	if (efi_early->is64)
		setup_boot_services64(efi_early);
	else
		setup_boot_services32(efi_early);

644 645
	status = efi_call_early(handle_protocol, handle,
				&proto, (void *)&image);
M
Matt Fleming 已提交
646
	if (status != EFI_SUCCESS) {
647
		efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
M
Matt Fleming 已提交
648 649 650
		return NULL;
	}

651 652
	status = efi_low_alloc(sys_table, 0x4000, 1,
			       (unsigned long *)&boot_params);
M
Matt Fleming 已提交
653
	if (status != EFI_SUCCESS) {
654
		efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
M
Matt Fleming 已提交
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
		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.
	 */
	hdr->root_flags = 1;
	hdr->vid_mode = 0xffff;
	hdr->boot_flag = 0xAA55;

M
Matt Fleming 已提交
674 675 676
	hdr->type_of_loader = 0x21;

	/* Convert unicode cmdline to ascii */
677
	cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
678 679 680
	if (!cmdline_ptr)
		goto fail;
	hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
681 682
	/* 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 已提交
683 684 685 686 687 688 689

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

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

690 691 692 693
	status = efi_parse_options(cmdline_ptr);
	if (status != EFI_SUCCESS)
		goto fail2;

694 695
	status = handle_cmdline_files(sys_table, image,
				      (char *)(unsigned long)hdr->cmd_line_ptr,
696
				      "initrd=", hdr->initrd_addr_max,
697
				      &ramdisk_addr, &ramdisk_size);
698 699 700 701 702 703 704 705 706 707

	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 已提交
708 709
	if (status != EFI_SUCCESS)
		goto fail2;
710 711 712 713
	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 已提交
714 715 716

	return boot_params;
fail2:
717
	efi_free(sys_table, options_size, hdr->cmd_line_ptr);
M
Matt Fleming 已提交
718
fail:
719
	efi_free(sys_table, 0x4000, (unsigned long)boot_params);
M
Matt Fleming 已提交
720 721 722
	return NULL;
}

723 724
static void add_e820ext(struct boot_params *params,
			struct setup_data *e820ext, u32 nr_entries)
M
Matt Fleming 已提交
725
{
726
	struct setup_data *data;
M
Matt Fleming 已提交
727
	efi_status_t status;
728
	unsigned long size;
M
Matt Fleming 已提交
729

730 731 732
	e820ext->type = SETUP_E820_EXT;
	e820ext->len = nr_entries * sizeof(struct e820entry);
	e820ext->next = 0;
M
Matt Fleming 已提交
733

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

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

739 740 741 742 743
	if (data)
		data->next = (unsigned long)e820ext;
	else
		params->hdr.setup_data = (unsigned long)e820ext;
}
M
Matt Fleming 已提交
744

745 746 747 748 749 750 751 752 753
static efi_status_t setup_e820(struct boot_params *params,
			       struct setup_data *e820ext, u32 e820ext_size)
{
	struct e820entry *e820_map = &params->e820_map[0];
	struct efi_info *efi = &params->efi_info;
	struct e820entry *prev = NULL;
	u32 nr_entries;
	u32 nr_desc;
	int i;
M
Matt Fleming 已提交
754 755

	nr_entries = 0;
756 757 758
	nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size;

	for (i = 0; i < nr_desc; i++) {
M
Matt Fleming 已提交
759 760
		efi_memory_desc_t *d;
		unsigned int e820_type = 0;
761
		unsigned long m = efi->efi_memmap;
M
Matt Fleming 已提交
762

763 764 765 766
#ifdef CONFIG_X86_64
		m |= (u64)efi->efi_memmap_hi << 32;
#endif

767
		d = (efi_memory_desc_t *)(m + (i * efi->efi_memdesc_size));
M
Matt Fleming 已提交
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
		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:
			e820_type = E820_RESERVED;
			break;

		case EFI_UNUSABLE_MEMORY:
			e820_type = E820_UNUSABLE;
			break;

		case EFI_ACPI_RECLAIM_MEMORY:
			e820_type = E820_ACPI;
			break;

		case EFI_LOADER_CODE:
		case EFI_LOADER_DATA:
		case EFI_BOOT_SERVICES_CODE:
		case EFI_BOOT_SERVICES_DATA:
		case EFI_CONVENTIONAL_MEMORY:
			e820_type = E820_RAM;
			break;

		case EFI_ACPI_MEMORY_NVS:
			e820_type = E820_NVS;
			break;

798 799 800 801
		case EFI_PERSISTENT_MEMORY:
			e820_type = E820_PMEM;
			break;

M
Matt Fleming 已提交
802 803 804 805 806 807
		default:
			continue;
		}

		/* Merge adjacent mappings */
		if (prev && prev->type == e820_type &&
808
		    (prev->addr + prev->size) == d->phys_addr) {
M
Matt Fleming 已提交
809
			prev->size += d->num_pages << 12;
810
			continue;
M
Matt Fleming 已提交
811
		}
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828

		if (nr_entries == ARRAY_SIZE(params->e820_map)) {
			u32 need = (nr_desc - i) * sizeof(struct e820entry) +
				   sizeof(struct setup_data);

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

			/* boot_params map full, switch to e820 extended */
			e820_map = (struct e820entry *)e820ext->data;
		}

		e820_map->addr = d->phys_addr;
		e820_map->size = d->num_pages << PAGE_SHIFT;
		e820_map->type = e820_type;
		prev = e820_map++;
		nr_entries++;
M
Matt Fleming 已提交
829 830
	}

831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
	if (nr_entries > ARRAY_SIZE(params->e820_map)) {
		u32 nr_e820ext = nr_entries - ARRAY_SIZE(params->e820_map);

		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) +
		sizeof(struct e820entry) * nr_desc;

	if (*e820ext) {
853
		efi_call_early(free_pool, *e820ext);
854 855 856 857
		*e820ext = NULL;
		*e820ext_size = 0;
	}

858 859
	status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
				size, (void **)e820ext);
860 861 862 863 864 865
	if (status == EFI_SUCCESS)
		*e820ext_size = size;

	return status;
}

866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
struct exit_boot_struct {
	struct boot_params *boot_params;
	struct efi_info *efi;
	struct setup_data *e820ext;
	__u32 e820ext_size;
	bool is64;
};

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;
		if (nr_desc > ARRAY_SIZE(p->boot_params->e820_map)) {
			u32 nr_e820ext = nr_desc -
					ARRAY_SIZE(p->boot_params->e820_map);

			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));

	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;

#ifdef CONFIG_X86_64
	p->efi->efi_systab_hi = (unsigned long)sys_table_arg >> 32;
	p->efi->efi_memmap_hi = (unsigned long)*map->map >> 32;
#endif

	return EFI_SUCCESS;
}

915
static efi_status_t exit_boot(struct boot_params *boot_params,
916
			      void *handle, bool is64)
917
{
918
	unsigned long map_sz, key, desc_size, buff_size;
919 920 921 922 923
	efi_memory_desc_t *mem_map;
	struct setup_data *e820ext;
	__u32 e820ext_size;
	efi_status_t status;
	__u32 desc_version;
924
	struct efi_boot_memmap map;
925 926 927 928 929 930 931 932 933 934 935 936 937
	struct exit_boot_struct priv;

	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;
938

939 940 941
	/* Might as well exit boot services now */
	status = efi_exit_boot_services(sys_table, handle, &map, &priv,
					exit_boot_func);
942 943 944
	if (status != EFI_SUCCESS)
		return status;

945 946
	e820ext = priv.e820ext;
	e820ext_size = priv.e820ext_size;
947 948 949 950 951 952
	/* Historic? */
	boot_params->alt_mem_k = 32 * 1024;

	status = setup_e820(boot_params, e820ext, e820ext_size);
	if (status != EFI_SUCCESS)
		return status;
M
Matt Fleming 已提交
953 954 955 956

	return EFI_SUCCESS;
}

M
Matt Fleming 已提交
957 958 959 960
/*
 * On success we return a pointer to a boot_params structure, and NULL
 * on failure.
 */
961
struct boot_params *efi_main(struct efi_config *c,
M
Matt Fleming 已提交
962 963
			     struct boot_params *boot_params)
{
964
	struct desc_ptr *gdt = NULL;
M
Matt Fleming 已提交
965 966 967 968
	efi_loaded_image_t *image;
	struct setup_header *hdr = &boot_params->hdr;
	efi_status_t status;
	struct desc_struct *desc;
969 970 971 972 973 974 975 976 977
	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 已提交
978 979 980 981 982 983 984

	sys_table = _table;

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

985 986 987 988 989
	if (is64)
		setup_boot_services64(efi_early);
	else
		setup_boot_services32(efi_early);

M
Matt Fleming 已提交
990
	setup_graphics(boot_params);
M
Matt Fleming 已提交
991

992
	setup_efi_pci(boot_params);
993

994 995
	setup_quirks(boot_params);

996 997
	status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
				sizeof(*gdt), (void **)&gdt);
998
	if (status != EFI_SUCCESS) {
999
		efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");
M
Matt Fleming 已提交
1000
		goto fail;
1001
	}
M
Matt Fleming 已提交
1002 1003

	gdt->size = 0x800;
1004
	status = efi_low_alloc(sys_table, gdt->size, 8,
1005
			   (unsigned long *)&gdt->address);
1006
	if (status != EFI_SUCCESS) {
1007
		efi_printk(sys_table, "Failed to alloc mem for gdt\n");
M
Matt Fleming 已提交
1008
		goto fail;
1009
	}
M
Matt Fleming 已提交
1010

M
Matt Fleming 已提交
1011 1012 1013 1014 1015
	/*
	 * If the kernel isn't already loaded at the preferred load
	 * address, relocate it.
	 */
	if (hdr->pref_address != hdr->code32_start) {
1016 1017 1018 1019 1020
		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);
1021 1022
		if (status != EFI_SUCCESS) {
			efi_printk(sys_table, "efi_relocate_kernel() failed!\n");
M
Matt Fleming 已提交
1023
			goto fail;
1024
		}
1025 1026 1027

		hdr->pref_address = hdr->code32_start;
		hdr->code32_start = bzimage_addr;
M
Matt Fleming 已提交
1028 1029
	}

1030
	status = exit_boot(boot_params, handle, is64);
1031 1032
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "exit_boot() failed!\n");
M
Matt Fleming 已提交
1033
		goto fail;
1034
	}
M
Matt Fleming 已提交
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089

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

	/* The first GDT is a dummy and the second is unused. */
	desc += 2;

	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->limit = 0xf;
	desc->avl = 0;
	desc->l = 0;
	desc->d = SEG_OP_SIZE_32BIT;
	desc->g = SEG_GRANULARITY_4KB;
	desc->base2 = 0x00;

	desc++;
	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->limit = 0xf;
	desc->avl = 0;
	desc->l = 0;
	desc->d = SEG_OP_SIZE_32BIT;
	desc->g = SEG_GRANULARITY_4KB;
	desc->base2 = 0x00;

#ifdef CONFIG_X86_64
	/* Task segment value */
	desc++;
	desc->limit0 = 0x0000;
	desc->base0 = 0x0000;
	desc->base1 = 0x0000;
	desc->type = SEG_TYPE_TSS;
	desc->s = 0;
	desc->dpl = 0;
	desc->p = 1;
	desc->limit = 0x0;
	desc->avl = 0;
	desc->l = 0;
	desc->d = 0;
	desc->g = SEG_GRANULARITY_4KB;
	desc->base2 = 0x00;
#endif /* CONFIG_X86_64 */

	asm volatile("cli");
1090
	asm volatile ("lgdt %0" : : "m" (*gdt));
M
Matt Fleming 已提交
1091 1092 1093

	return boot_params;
fail:
1094
	efi_printk(sys_table, "efi_main() failed!\n");
M
Matt Fleming 已提交
1095 1096
	return NULL;
}