diff options
Diffstat (limited to 'arch/x86/boot/compressed/eboot.c')
| -rw-r--r-- | arch/x86/boot/compressed/eboot.c | 1680 | 
1 files changed, 938 insertions, 742 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index b7388a425f0..0331d765c2b 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -19,215 +19,273 @@  static efi_system_table_t *sys_table; -static void efi_char16_printk(efi_char16_t *str) -{ -	struct efi_simple_text_output_protocol *out; - -	out = (struct efi_simple_text_output_protocol *)sys_table->con_out; -	efi_call_phys2(out->output_string, out, str); +static struct efi_config *efi_early; + +#define efi_call_early(f, ...)						\ +	efi_early->call(efi_early->f, __VA_ARGS__); + +#define BOOT_SERVICES(bits)						\ +static void setup_boot_services##bits(struct efi_config *c)		\ +{									\ +	efi_system_table_##bits##_t *table;				\ +	efi_boot_services_##bits##_t *bt;				\ +									\ +	table = (typeof(table))sys_table;				\ +									\ +	c->text_output = table->con_out;				\ +									\ +	bt = (typeof(bt))(unsigned long)(table->boottime);		\ +									\ +	c->allocate_pool = bt->allocate_pool;				\ +	c->allocate_pages = bt->allocate_pages;				\ +	c->get_memory_map = bt->get_memory_map;				\ +	c->free_pool = bt->free_pool;					\ +	c->free_pages = bt->free_pages;					\ +	c->locate_handle = bt->locate_handle;				\ +	c->handle_protocol = bt->handle_protocol;			\ +	c->exit_boot_services = bt->exit_boot_services;			\  } +BOOT_SERVICES(32); +BOOT_SERVICES(64); + +static void efi_printk(efi_system_table_t *, char *); +static void efi_char16_printk(efi_system_table_t *, efi_char16_t *); -static void efi_printk(char *str) +static efi_status_t +__file_size32(void *__fh, efi_char16_t *filename_16, +	      void **handle, u64 *file_sz)  { -	char *s8; +	efi_file_handle_32_t *h, *fh = __fh; +	efi_file_info_t *info; +	efi_status_t status; +	efi_guid_t info_guid = EFI_FILE_INFO_ID; +	u32 info_sz; -	for (s8 = str; *s8; s8++) { -		efi_char16_t ch[2] = { 0 }; +	status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16, +				 EFI_FILE_MODE_READ, (u64)0); +	if (status != EFI_SUCCESS) { +		efi_printk(sys_table, "Failed to open file: "); +		efi_char16_printk(sys_table, filename_16); +		efi_printk(sys_table, "\n"); +		return status; +	} -		ch[0] = *s8; -		if (*s8 == '\n') { -			efi_char16_t nl[2] = { '\r', 0 }; -			efi_char16_printk(nl); -		} +	*handle = h; -		efi_char16_printk(ch); +	info_sz = 0; +	status = efi_early->call((unsigned long)h->get_info, h, &info_guid, +				 &info_sz, NULL); +	if (status != EFI_BUFFER_TOO_SMALL) { +		efi_printk(sys_table, "Failed to get file info size\n"); +		return status;  	} -} -static efi_status_t __get_map(efi_memory_desc_t **map, unsigned long *map_size, -			      unsigned long *desc_size) -{ -	efi_memory_desc_t *m = NULL; -	efi_status_t status; -	unsigned long key; -	u32 desc_version; - -	*map_size = sizeof(*m) * 32; -again: -	/* -	 * Add an additional efi_memory_desc_t because we're doing an -	 * allocation which may be in a new descriptor region. -	 */ -	*map_size += sizeof(*m); -	status = efi_call_phys3(sys_table->boottime->allocate_pool, -				EFI_LOADER_DATA, *map_size, (void **)&m); -	if (status != EFI_SUCCESS) -		goto fail; +grow: +	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, +				info_sz, (void **)&info); +	if (status != EFI_SUCCESS) { +		efi_printk(sys_table, "Failed to alloc mem for file info\n"); +		return status; +	} -	status = efi_call_phys5(sys_table->boottime->get_memory_map, map_size, -				m, &key, desc_size, &desc_version); +	status = efi_early->call((unsigned long)h->get_info, h, &info_guid, +				 &info_sz, info);  	if (status == EFI_BUFFER_TOO_SMALL) { -		efi_call_phys1(sys_table->boottime->free_pool, m); -		goto again; +		efi_call_early(free_pool, info); +		goto grow;  	} +	*file_sz = info->file_size; +	efi_call_early(free_pool, info); +  	if (status != EFI_SUCCESS) -		efi_call_phys1(sys_table->boottime->free_pool, m); +		efi_printk(sys_table, "Failed to get initrd info\n"); -fail: -	*map = m;  	return status;  } -/* - * Allocate at the highest possible address that is not above 'max'. - */ -static efi_status_t high_alloc(unsigned long size, unsigned long align, -			      unsigned long *addr, unsigned long max) +static efi_status_t +__file_size64(void *__fh, efi_char16_t *filename_16, +	      void **handle, u64 *file_sz)  { -	unsigned long map_size, desc_size; -	efi_memory_desc_t *map; +	efi_file_handle_64_t *h, *fh = __fh; +	efi_file_info_t *info;  	efi_status_t status; -	unsigned long nr_pages; -	u64 max_addr = 0; -	int i; +	efi_guid_t info_guid = EFI_FILE_INFO_ID; +	u64 info_sz; -	status = __get_map(&map, &map_size, &desc_size); -	if (status != EFI_SUCCESS) -		goto fail; +	status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16, +				 EFI_FILE_MODE_READ, (u64)0); +	if (status != EFI_SUCCESS) { +		efi_printk(sys_table, "Failed to open file: "); +		efi_char16_printk(sys_table, filename_16); +		efi_printk(sys_table, "\n"); +		return status; +	} -	nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; -again: -	for (i = 0; i < map_size / desc_size; i++) { -		efi_memory_desc_t *desc; -		unsigned long m = (unsigned long)map; -		u64 start, end; +	*handle = h; -		desc = (efi_memory_desc_t *)(m + (i * desc_size)); -		if (desc->type != EFI_CONVENTIONAL_MEMORY) -			continue; +	info_sz = 0; +	status = efi_early->call((unsigned long)h->get_info, h, &info_guid, +				 &info_sz, NULL); +	if (status != EFI_BUFFER_TOO_SMALL) { +		efi_printk(sys_table, "Failed to get file info size\n"); +		return status; +	} -		if (desc->num_pages < nr_pages) -			continue; +grow: +	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, +				info_sz, (void **)&info); +	if (status != EFI_SUCCESS) { +		efi_printk(sys_table, "Failed to alloc mem for file info\n"); +		return status; +	} -		start = desc->phys_addr; -		end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); +	status = efi_early->call((unsigned long)h->get_info, h, &info_guid, +				 &info_sz, info); +	if (status == EFI_BUFFER_TOO_SMALL) { +		efi_call_early(free_pool, info); +		goto grow; +	} -		if ((start + size) > end || (start + size) > max) -			continue; +	*file_sz = info->file_size; +	efi_call_early(free_pool, info); -		if (end - size > max) -			end = max; +	if (status != EFI_SUCCESS) +		efi_printk(sys_table, "Failed to get initrd info\n"); -		if (round_down(end - size, align) < start) -			continue; +	return status; +} +static efi_status_t +efi_file_size(efi_system_table_t *sys_table, void *__fh, +	      efi_char16_t *filename_16, void **handle, u64 *file_sz) +{ +	if (efi_early->is64) +		return __file_size64(__fh, filename_16, handle, file_sz); -		start = round_down(end - size, align); +	return __file_size32(__fh, filename_16, handle, file_sz); +} -		/* -		 * Don't allocate at 0x0. It will confuse code that -		 * checks pointers against NULL. -		 */ -		if (start == 0x0) -			continue; +static inline efi_status_t +efi_file_read(void *handle, unsigned long *size, void *addr) +{ +	unsigned long func; -		if (start > max_addr) -			max_addr = start; -	} +	if (efi_early->is64) { +		efi_file_handle_64_t *fh = handle; -	if (!max_addr) -		status = EFI_NOT_FOUND; -	else { -		status = efi_call_phys4(sys_table->boottime->allocate_pages, -					EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, -					nr_pages, &max_addr); -		if (status != EFI_SUCCESS) { -			max = max_addr; -			max_addr = 0; -			goto again; -		} +		func = (unsigned long)fh->read; +		return efi_early->call(func, handle, size, addr); +	} else { +		efi_file_handle_32_t *fh = handle; -		*addr = max_addr; +		func = (unsigned long)fh->read; +		return efi_early->call(func, handle, size, addr);  	} +} -free_pool: -	efi_call_phys1(sys_table->boottime->free_pool, map); +static inline efi_status_t efi_file_close(void *handle) +{ +	if (efi_early->is64) { +		efi_file_handle_64_t *fh = handle; -fail: -	return status; +		return efi_early->call((unsigned long)fh->close, handle); +	} else { +		efi_file_handle_32_t *fh = handle; + +		return efi_early->call((unsigned long)fh->close, handle); +	}  } -/* - * Allocate at the lowest possible address. - */ -static efi_status_t low_alloc(unsigned long size, unsigned long align, -			      unsigned long *addr) +static inline efi_status_t __open_volume32(void *__image, void **__fh)  { -	unsigned long map_size, desc_size; -	efi_memory_desc_t *map; +	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; -	unsigned long nr_pages; -	int i; +	void *handle = (void *)(unsigned long)image->device_handle; +	unsigned long func; -	status = __get_map(&map, &map_size, &desc_size); +	status = efi_call_early(handle_protocol, handle, +				&fs_proto, (void **)&io); +	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) -		goto fail; +		efi_printk(sys_table, "Failed to open volume\n"); -	nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; -	for (i = 0; i < map_size / desc_size; i++) { -		efi_memory_desc_t *desc; -		unsigned long m = (unsigned long)map; -		u64 start, end; +	*__fh = fh; +	return status; +} -		desc = (efi_memory_desc_t *)(m + (i * desc_size)); +static inline efi_status_t __open_volume64(void *__image, void **__fh) +{ +	efi_file_io_interface_t *io; +	efi_loaded_image_64_t *image = __image; +	efi_file_handle_64_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; -		if (desc->type != EFI_CONVENTIONAL_MEMORY) -			continue; +	status = efi_call_early(handle_protocol, handle, +				&fs_proto, (void **)&io); +	if (status != EFI_SUCCESS) { +		efi_printk(sys_table, "Failed to handle fs_proto\n"); +		return status; +	} -		if (desc->num_pages < nr_pages) -			continue; +	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"); -		start = desc->phys_addr; -		end = start + desc->num_pages * (1UL << EFI_PAGE_SHIFT); +	*__fh = fh; +	return status; +} -		/* -		 * Don't allocate at 0x0. It will confuse code that -		 * checks pointers against NULL. Skip the first 8 -		 * bytes so we start at a nice even number. -		 */ -		if (start == 0x0) -			start += 8; +static inline efi_status_t +efi_open_volume(efi_system_table_t *sys_table, void *__image, void **__fh) +{ +	if (efi_early->is64) +		return __open_volume64(__image, __fh); -		start = round_up(start, align); -		if ((start + size) > end) -			continue; +	return __open_volume32(__image, __fh); +} -		status = efi_call_phys4(sys_table->boottime->allocate_pages, -					EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, -					nr_pages, &start); -		if (status == EFI_SUCCESS) { -			*addr = start; -			break; -		} -	} +static void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str) +{ +	unsigned long output_string; +	size_t offset; -	if (i == map_size / desc_size) -		status = EFI_NOT_FOUND; +	if (efi_early->is64) { +		struct efi_simple_text_output_protocol_64 *out; +		u64 *func; -free_pool: -	efi_call_phys1(sys_table->boottime->free_pool, map); -fail: -	return status; -} +		offset = offsetof(typeof(*out), output_string); +		output_string = efi_early->text_output + offset; +		func = (u64 *)output_string; -static void low_free(unsigned long size, unsigned long addr) -{ -	unsigned long nr_pages; +		efi_early->call(*func, efi_early->text_output, str); +	} else { +		struct efi_simple_text_output_protocol_32 *out; +		u32 *func; + +		offset = offsetof(typeof(*out), output_string); +		output_string = efi_early->text_output + offset; +		func = (u32 *)output_string; -	nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; -	efi_call_phys2(sys_table->boottime->free_pages, addr, nr_pages); +		efi_early->call(*func, efi_early->text_output, str); +	}  } +#include "../../../../drivers/firmware/efi/efi-stub-helper.c" +  static void find_bits(unsigned long mask, u8 *pos, u8 *size)  {  	u8 first, len; @@ -251,105 +309,97 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)  	*size = len;  } -static efi_status_t setup_efi_pci(struct boot_params *params) +static efi_status_t +__setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom)  { -	efi_pci_io_protocol *pci; +	struct pci_setup_rom *rom = NULL;  	efi_status_t status; -	void **pci_handle; -	efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; -	unsigned long nr_pci, size = 0; -	int i; -	struct setup_data *data; - -	data = (struct setup_data *)(unsigned long)params->hdr.setup_data; +	unsigned long size; +	uint64_t attributes; -	while (data && data->next) -		data = (struct setup_data *)(unsigned long)data->next; +	status = efi_early->call(pci->attributes, pci, +				 EfiPciIoAttributeOperationGet, 0, 0, +				 &attributes); +	if (status != EFI_SUCCESS) +		return status; -	status = efi_call_phys5(sys_table->boottime->locate_handle, -				EFI_LOCATE_BY_PROTOCOL, &pci_proto, -				NULL, &size, pci_handle); +	if (!pci->romimage || !pci->romsize) +		return EFI_INVALID_PARAMETER; -	if (status == EFI_BUFFER_TOO_SMALL) { -		status = efi_call_phys3(sys_table->boottime->allocate_pool, -					EFI_LOADER_DATA, size, &pci_handle); +	size = pci->romsize + sizeof(*rom); -		if (status != EFI_SUCCESS) -			return status; +	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom); +	if (status != EFI_SUCCESS) +		return status; -		status = efi_call_phys5(sys_table->boottime->locate_handle, -					EFI_LOCATE_BY_PROTOCOL, &pci_proto, -					NULL, &size, pci_handle); -	} +	memset(rom, 0, sizeof(*rom)); -	if (status != EFI_SUCCESS) -		goto free_handle; +	rom->data.type = SETUP_PCI; +	rom->data.len = size - sizeof(struct setup_data); +	rom->data.next = 0; +	rom->pcilen = pci->romsize; +	*__rom = rom; -	nr_pci = size / sizeof(void *); -	for (i = 0; i < nr_pci; i++) { -		void *h = pci_handle[i]; -		uint64_t attributes; -		struct pci_setup_rom *rom; +	status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, +				 PCI_VENDOR_ID, 1, &(rom->vendor)); -		status = efi_call_phys3(sys_table->boottime->handle_protocol, -					h, &pci_proto, &pci); +	if (status != EFI_SUCCESS) +		goto free_struct; -		if (status != EFI_SUCCESS) -			continue; +	status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, +				 PCI_DEVICE_ID, 1, &(rom->devid)); -		if (!pci) -			continue; +	if (status != EFI_SUCCESS) +		goto free_struct; -#ifdef CONFIG_X86_64 -		status = efi_call_phys4(pci->attributes, pci, -					EfiPciIoAttributeOperationGet, 0, -					&attributes); -#else -		status = efi_call_phys5(pci->attributes, pci, -					EfiPciIoAttributeOperationGet, 0, 0, -					&attributes); -#endif -		if (status != EFI_SUCCESS) -			continue; +	status = efi_early->call(pci->get_location, pci, &(rom->segment), +				 &(rom->bus), &(rom->device), &(rom->function)); -		if (!pci->romimage || !pci->romsize) -			continue; +	if (status != EFI_SUCCESS) +		goto free_struct; -		size = pci->romsize + sizeof(*rom); +	memcpy(rom->romdata, pci->romimage, pci->romsize); +	return status; -		status = efi_call_phys3(sys_table->boottime->allocate_pool, -				EFI_LOADER_DATA, size, &rom); +free_struct: +	efi_call_early(free_pool, rom); +	return status; +} -		if (status != EFI_SUCCESS) -			continue; +static efi_status_t +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; -		rom->data.type = SETUP_PCI; -		rom->data.len = size - sizeof(struct setup_data); -		rom->data.next = 0; -		rom->pcilen = pci->romsize; +	data = (struct setup_data *)(unsigned long)params->hdr.setup_data; -		status = efi_call_phys5(pci->pci.read, pci, -					EfiPciIoWidthUint16, PCI_VENDOR_ID, -					1, &(rom->vendor)); +	while (data && data->next) +		data = (struct setup_data *)(unsigned long)data->next; -		if (status != EFI_SUCCESS) -			goto free_struct; +	nr_pci = size / sizeof(u32); +	for (i = 0; i < nr_pci; i++) { +		struct pci_setup_rom *rom = NULL; +		u32 h = handles[i]; -		status = efi_call_phys5(pci->pci.read, pci, -					EfiPciIoWidthUint16, PCI_DEVICE_ID, -					1, &(rom->devid)); +		status = efi_call_early(handle_protocol, h, +					&pci_proto, (void **)&pci);  		if (status != EFI_SUCCESS) -			goto free_struct; +			continue; -		status = efi_call_phys5(pci->get_location, pci, -					&(rom->segment), &(rom->bus), -					&(rom->device), &(rom->function)); +		if (!pci) +			continue; +		status = __setup_efi_pci32(pci, &rom);  		if (status != EFI_SUCCESS) -			goto free_struct; - -		memcpy(rom->romdata, pci->romimage, pci->romsize); +			continue;  		if (data)  			data->next = (unsigned long)rom; @@ -358,105 +408,155 @@ static efi_status_t setup_efi_pci(struct boot_params *params)  		data = (struct setup_data *)rom; -		continue; -	free_struct: -		efi_call_phys1(sys_table->boottime->free_pool, rom);  	} -free_handle: -	efi_call_phys1(sys_table->boottime->free_pool, pci_handle);  	return status;  } -/* - * See if we have Graphics Output Protocol - */ -static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto, -			      unsigned long size) +static efi_status_t +__setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom)  { -	struct efi_graphics_output_protocol *gop, *first_gop; -	struct efi_pixel_bitmask pixel_info; -	unsigned long nr_gops; +	struct pci_setup_rom *rom;  	efi_status_t status; -	void **gop_handle; -	u16 width, height; -	u32 fb_base, fb_size; -	u32 pixels_per_scan_line; -	int pixel_format; -	int i; +	unsigned long size; +	uint64_t attributes; -	status = efi_call_phys3(sys_table->boottime->allocate_pool, -				EFI_LOADER_DATA, size, &gop_handle); +	status = efi_early->call(pci->attributes, pci, +				 EfiPciIoAttributeOperationGet, 0, +				 &attributes);  	if (status != EFI_SUCCESS)  		return status; -	status = efi_call_phys5(sys_table->boottime->locate_handle, -				EFI_LOCATE_BY_PROTOCOL, proto, -				NULL, &size, gop_handle); +	if (!pci->romimage || !pci->romsize) +		return EFI_INVALID_PARAMETER; + +	size = pci->romsize + sizeof(*rom); + +	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom);  	if (status != EFI_SUCCESS) -		goto free_handle; +		return status; -	first_gop = NULL; +	rom->data.type = SETUP_PCI; +	rom->data.len = size - sizeof(struct setup_data); +	rom->data.next = 0; +	rom->pcilen = pci->romsize; +	*__rom = rom; -	nr_gops = size / sizeof(void *); -	for (i = 0; i < nr_gops; i++) { -		struct efi_graphics_output_mode_info *info; -		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; -		bool conout_found = false; -		void *dummy; -		void *h = gop_handle[i]; +	status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, +				 PCI_VENDOR_ID, 1, &(rom->vendor)); + +	if (status != EFI_SUCCESS) +		goto free_struct; + +	status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, +				 PCI_DEVICE_ID, 1, &(rom->devid)); + +	if (status != EFI_SUCCESS) +		goto free_struct; + +	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: +	efi_call_early(free_pool, rom); +	return status; + +} + +static efi_status_t +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; + +	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]; + +		status = efi_call_early(handle_protocol, h, +					&pci_proto, (void **)&pci); -		status = efi_call_phys3(sys_table->boottime->handle_protocol, -					h, proto, &gop);  		if (status != EFI_SUCCESS)  			continue; -		status = efi_call_phys3(sys_table->boottime->handle_protocol, -					h, &conout_proto, &dummy); +		if (!pci) +			continue; -		if (status == EFI_SUCCESS) -			conout_found = true; +		status = __setup_efi_pci64(pci, &rom); +		if (status != EFI_SUCCESS) +			continue; -		status = efi_call_phys4(gop->query_mode, gop, -					gop->mode->mode, &size, &info); -		if (status == EFI_SUCCESS && (!first_gop || conout_found)) { -			/* -			 * Systems that use the UEFI Console Splitter may -			 * provide multiple GOP devices, not all of which are -			 * backed by real hardware. The workaround is to search -			 * for a GOP implementing the ConOut protocol, and if -			 * one isn't found, to just fall back to the first GOP. -			 */ -			width = info->horizontal_resolution; -			height = info->vertical_resolution; -			fb_base = gop->mode->frame_buffer_base; -			fb_size = gop->mode->frame_buffer_size; -			pixel_format = info->pixel_format; -			pixel_info = info->pixel_information; -			pixels_per_scan_line = info->pixels_per_scan_line; +		if (data) +			data->next = (unsigned long)rom; +		else +			params->hdr.setup_data = (unsigned long)rom; + +		data = (struct setup_data *)rom; -			/* -			 * Once we've found a GOP supporting ConOut, -			 * don't bother looking any further. -			 */ -			first_gop = gop; -			if (conout_found) -				break; -		}  	} -	/* Did we find any GOPs? */ -	if (!first_gop) +	return status; +} + +static efi_status_t setup_efi_pci(struct boot_params *params) +{ +	efi_status_t status; +	void **pci_handle = NULL; +	efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; +	unsigned long size = 0; + +	status = efi_call_early(locate_handle, +				EFI_LOCATE_BY_PROTOCOL, +				&pci_proto, NULL, &size, pci_handle); + +	if (status == EFI_BUFFER_TOO_SMALL) { +		status = efi_call_early(allocate_pool, +					EFI_LOADER_DATA, +					size, (void **)&pci_handle); + +		if (status != EFI_SUCCESS) +			return status; + +		status = efi_call_early(locate_handle, +					EFI_LOCATE_BY_PROTOCOL, &pci_proto, +					NULL, &size, pci_handle); +	} + +	if (status != EFI_SUCCESS)  		goto free_handle; -	/* EFI framebuffer */ -	si->orig_video_isVGA = VIDEO_TYPE_EFI; +	if (efi_early->is64) +		status = setup_efi_pci64(params, pci_handle, size); +	else +		status = setup_efi_pci32(params, pci_handle, size); -	si->lfb_width = width; -	si->lfb_height = height; -	si->lfb_base = fb_base; -	si->pages = 1; +free_handle: +	efi_call_early(free_pool, pci_handle); +	return status; +} +static void +setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, +		 struct efi_pixel_bitmask pixel_info, int pixel_format) +{  	if (pixel_format == PIXEL_RGB_RESERVED_8BIT_PER_COLOR) {  		si->lfb_depth = 32;  		si->lfb_linelength = pixels_per_scan_line * 4; @@ -501,372 +601,426 @@ static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto,  		si->rsvd_size = 0;  		si->rsvd_pos = 0;  	} +} -	si->lfb_size = si->lfb_linelength * si->lfb_height; +static efi_status_t +__gop_query32(struct efi_graphics_output_protocol_32 *gop32, +	      struct efi_graphics_output_mode_info **info, +	      unsigned long *size, u32 *fb_base) +{ +	struct efi_graphics_output_protocol_mode_32 *mode; +	efi_status_t status; +	unsigned long m; -	si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; +	m = gop32->mode; +	mode = (struct efi_graphics_output_protocol_mode_32 *)m; -free_handle: -	efi_call_phys1(sys_table->boottime->free_pool, gop_handle); +	status = efi_early->call(gop32->query_mode, gop32, +				 mode->mode, size, info); +	if (status != EFI_SUCCESS) +		return status; + +	*fb_base = mode->frame_buffer_base;  	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) +static efi_status_t +setup_gop32(struct screen_info *si, efi_guid_t *proto, +	    unsigned long size, void **gop_handle)  { -	struct efi_uga_draw_protocol *uga, *first_uga; -	unsigned long nr_ugas; +	struct efi_graphics_output_protocol_32 *gop32, *first_gop; +	unsigned long nr_gops; +	u16 width, height; +	u32 pixels_per_scan_line; +	u32 fb_base; +	struct efi_pixel_bitmask pixel_info; +	int pixel_format;  	efi_status_t status; -	u32 width, height; -	void **uga_handle = NULL; +	u32 *handles = (u32 *)(unsigned long)gop_handle;  	int i; -	status = efi_call_phys3(sys_table->boottime->allocate_pool, -				EFI_LOADER_DATA, size, &uga_handle); -	if (status != EFI_SUCCESS) -		return status; - -	status = efi_call_phys5(sys_table->boottime->locate_handle, -				EFI_LOCATE_BY_PROTOCOL, uga_proto, -				NULL, &size, uga_handle); -	if (status != EFI_SUCCESS) -		goto free_handle; - -	first_uga = NULL; +	first_gop = NULL; +	gop32 = NULL; -	nr_ugas = size / sizeof(void *); -	for (i = 0; i < nr_ugas; i++) { -		efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID; -		void *handle = uga_handle[i]; -		u32 w, h, depth, refresh; -		void *pciio; +	nr_gops = size / sizeof(u32); +	for (i = 0; i < nr_gops; i++) { +		struct efi_graphics_output_mode_info *info = NULL; +		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; +		bool conout_found = false; +		void *dummy = NULL; +		u32 h = handles[i]; -		status = efi_call_phys3(sys_table->boottime->handle_protocol, -					handle, uga_proto, &uga); +		status = efi_call_early(handle_protocol, h, +					proto, (void **)&gop32);  		if (status != EFI_SUCCESS)  			continue; -		efi_call_phys3(sys_table->boottime->handle_protocol, -			       handle, &pciio_proto, &pciio); +		status = efi_call_early(handle_protocol, h, +					&conout_proto, &dummy); +		if (status == EFI_SUCCESS) +			conout_found = true; -		status = efi_call_phys5(uga->get_mode, uga, &w, &h, -					&depth, &refresh); -		if (status == EFI_SUCCESS && (!first_uga || pciio)) { -			width = w; -			height = h; +		status = __gop_query32(gop32, &info, &size, &fb_base); +		if (status == EFI_SUCCESS && (!first_gop || conout_found)) { +			/* +			 * Systems that use the UEFI Console Splitter may +			 * provide multiple GOP devices, not all of which are +			 * backed by real hardware. The workaround is to search +			 * for a GOP implementing the ConOut protocol, and if +			 * one isn't found, to just fall back to the first GOP. +			 */ +			width = info->horizontal_resolution; +			height = info->vertical_resolution; +			pixel_format = info->pixel_format; +			pixel_info = info->pixel_information; +			pixels_per_scan_line = info->pixels_per_scan_line;  			/* -			 * Once we've found a UGA supporting PCIIO, +			 * Once we've found a GOP supporting ConOut,  			 * don't bother looking any further.  			 */ -			if (pciio) +			first_gop = gop32; +			if (conout_found)  				break; - -			first_uga = uga;  		}  	} -	if (!first_uga) -		goto free_handle; +	/* Did we find any GOPs? */ +	if (!first_gop) +		goto out;  	/* EFI framebuffer */  	si->orig_video_isVGA = VIDEO_TYPE_EFI; -	si->lfb_depth = 32;  	si->lfb_width = width;  	si->lfb_height = height; +	si->lfb_base = fb_base; +	si->pages = 1; -	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; +	setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format); +	si->lfb_size = si->lfb_linelength * si->lfb_height; -free_handle: -	efi_call_phys1(sys_table->boottime->free_pool, uga_handle); +	si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; +out:  	return status;  } -void setup_graphics(struct boot_params *boot_params) +static efi_status_t +__gop_query64(struct efi_graphics_output_protocol_64 *gop64, +	      struct efi_graphics_output_mode_info **info, +	      unsigned long *size, u32 *fb_base)  { -	efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; -	struct screen_info *si; -	efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID; +	struct efi_graphics_output_protocol_mode_64 *mode;  	efi_status_t status; -	unsigned long size; -	void **gop_handle = NULL; -	void **uga_handle = NULL; +	unsigned long m; -	si = &boot_params->screen_info; -	memset(si, 0, sizeof(*si)); +	m = gop64->mode; +	mode = (struct efi_graphics_output_protocol_mode_64 *)m; -	size = 0; -	status = efi_call_phys5(sys_table->boottime->locate_handle, -				EFI_LOCATE_BY_PROTOCOL, &graphics_proto, -				NULL, &size, gop_handle); -	if (status == EFI_BUFFER_TOO_SMALL) -		status = setup_gop(si, &graphics_proto, size); +	status = efi_early->call(gop64->query_mode, gop64, +				 mode->mode, size, info); +	if (status != EFI_SUCCESS) +		return status; -	if (status != EFI_SUCCESS) { -		size = 0; -		status = efi_call_phys5(sys_table->boottime->locate_handle, -					EFI_LOCATE_BY_PROTOCOL, &uga_proto, -					NULL, &size, uga_handle); -		if (status == EFI_BUFFER_TOO_SMALL) -			setup_uga(si, &uga_proto, size); -	} +	*fb_base = mode->frame_buffer_base; +	return status;  } -struct initrd { -	efi_file_handle_t *handle; -	u64 size; -}; - -/* - * Check the cmdline for a LILO-style initrd= arguments. - * - * We only support loading an initrd from the same filesystem as the - * kernel image. - */ -static efi_status_t handle_ramdisks(efi_loaded_image_t *image, -				    struct setup_header *hdr) +static efi_status_t +setup_gop64(struct screen_info *si, efi_guid_t *proto, +	    unsigned long size, void **gop_handle)  { -	struct initrd *initrds; -	unsigned long initrd_addr; -	efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID; -	u64 initrd_total; -	efi_file_io_interface_t *io; -	efi_file_handle_t *fh; +	struct efi_graphics_output_protocol_64 *gop64, *first_gop; +	unsigned long nr_gops; +	u16 width, height; +	u32 pixels_per_scan_line; +	u32 fb_base; +	struct efi_pixel_bitmask pixel_info; +	int pixel_format;  	efi_status_t status; -	int nr_initrds; -	char *str; -	int i, j, k; +	u64 *handles = (u64 *)(unsigned long)gop_handle; +	int i; -	initrd_addr = 0; -	initrd_total = 0; +	first_gop = NULL; +	gop64 = NULL; -	str = (char *)(unsigned long)hdr->cmd_line_ptr; +	nr_gops = size / sizeof(u64); +	for (i = 0; i < nr_gops; i++) { +		struct efi_graphics_output_mode_info *info = NULL; +		efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; +		bool conout_found = false; +		void *dummy = NULL; +		u64 h = handles[i]; -	j = 0;			/* See close_handles */ +		status = efi_call_early(handle_protocol, h, +					proto, (void **)&gop64); +		if (status != EFI_SUCCESS) +			continue; -	if (!str || !*str) -		return EFI_SUCCESS; +		status = efi_call_early(handle_protocol, h, +					&conout_proto, &dummy); +		if (status == EFI_SUCCESS) +			conout_found = true; -	for (nr_initrds = 0; *str; nr_initrds++) { -		str = strstr(str, "initrd="); -		if (!str) -			break; +		status = __gop_query64(gop64, &info, &size, &fb_base); +		if (status == EFI_SUCCESS && (!first_gop || conout_found)) { +			/* +			 * Systems that use the UEFI Console Splitter may +			 * provide multiple GOP devices, not all of which are +			 * backed by real hardware. The workaround is to search +			 * for a GOP implementing the ConOut protocol, and if +			 * one isn't found, to just fall back to the first GOP. +			 */ +			width = info->horizontal_resolution; +			height = info->vertical_resolution; +			pixel_format = info->pixel_format; +			pixel_info = info->pixel_information; +			pixels_per_scan_line = info->pixels_per_scan_line; -		str += 7; +			/* +			 * Once we've found a GOP supporting ConOut, +			 * don't bother looking any further. +			 */ +			first_gop = gop64; +			if (conout_found) +				break; +		} +	} -		/* Skip any leading slashes */ -		while (*str == '/' || *str == '\\') -			str++; +	/* Did we find any GOPs? */ +	if (!first_gop) +		goto out; -		while (*str && *str != ' ' && *str != '\n') -			str++; -	} +	/* EFI framebuffer */ +	si->orig_video_isVGA = VIDEO_TYPE_EFI; + +	si->lfb_width = width; +	si->lfb_height = height; +	si->lfb_base = fb_base; +	si->pages = 1; -	if (!nr_initrds) -		return EFI_SUCCESS; +	setup_pixel_info(si, pixels_per_scan_line, pixel_info, pixel_format); -	status = efi_call_phys3(sys_table->boottime->allocate_pool, -				EFI_LOADER_DATA, -				nr_initrds * sizeof(*initrds), -				&initrds); -	if (status != EFI_SUCCESS) { -		efi_printk("Failed to alloc mem for initrds\n"); -		goto fail; -	} +	si->lfb_size = si->lfb_linelength * si->lfb_height; -	str = (char *)(unsigned long)hdr->cmd_line_ptr; -	for (i = 0; i < nr_initrds; i++) { -		struct initrd *initrd; -		efi_file_handle_t *h; -		efi_file_info_t *info; -		efi_char16_t filename_16[256]; -		unsigned long info_sz; -		efi_guid_t info_guid = EFI_FILE_INFO_ID; -		efi_char16_t *p; -		u64 file_sz; - -		str = strstr(str, "initrd="); -		if (!str) -			break; +	si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; +out: +	return status; +} -		str += 7; +/* + * See if we have Graphics Output Protocol + */ +static efi_status_t setup_gop(struct screen_info *si, efi_guid_t *proto, +			      unsigned long size) +{ +	efi_status_t status; +	void **gop_handle = NULL; + +	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, +				size, (void **)&gop_handle); +	if (status != EFI_SUCCESS) +		return status; -		initrd = &initrds[i]; -		p = filename_16; +	status = efi_call_early(locate_handle, +				EFI_LOCATE_BY_PROTOCOL, +				proto, NULL, &size, gop_handle); +	if (status != EFI_SUCCESS) +		goto free_handle; -		/* Skip any leading slashes */ -		while (*str == '/' || *str == '\\') -			str++; +	if (efi_early->is64) +		status = setup_gop64(si, proto, size, gop_handle); +	else +		status = setup_gop32(si, proto, size, gop_handle); -		while (*str && *str != ' ' && *str != '\n') { -			if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16)) -				break; +free_handle: +	efi_call_early(free_pool, gop_handle); +	return status; +} -			if (*str == '/') { -				*p++ = '\\'; -				*str++; -			} else { -				*p++ = *str++; -			} -		} +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;; +	efi_status_t status; +	int i; -		*p = '\0'; +	first_uga = NULL; +	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]; -		/* Only open the volume once. */ -		if (!i) { -			efi_boot_services_t *boottime; +		status = efi_call_early(handle_protocol, handle, +					&uga_proto, (void **)&uga); +		if (status != EFI_SUCCESS) +			continue; -			boottime = sys_table->boottime; +		efi_call_early(handle_protocol, handle, &pciio_proto, &pciio); -			status = efi_call_phys3(boottime->handle_protocol, -					image->device_handle, &fs_proto, &io); -			if (status != EFI_SUCCESS) { -				efi_printk("Failed to handle fs_proto\n"); -				goto free_initrds; -			} +		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; -			status = efi_call_phys2(io->open_volume, io, &fh); -			if (status != EFI_SUCCESS) { -				efi_printk("Failed to open volume\n"); -				goto free_initrds; -			} -		} +			/* +			 * Once we've found a UGA supporting PCIIO, +			 * don't bother looking any further. +			 */ +			if (pciio) +				break; -		status = efi_call_phys5(fh->open, fh, &h, filename_16, -					EFI_FILE_MODE_READ, (u64)0); -		if (status != EFI_SUCCESS) { -			efi_printk("Failed to open initrd file: "); -			efi_char16_printk(filename_16); -			efi_printk("\n"); -			goto close_handles; +			first_uga = uga;  		} +	} -		initrd->handle = h; +	return status; +} -		info_sz = 0; -		status = efi_call_phys4(h->get_info, h, &info_guid, -					&info_sz, NULL); -		if (status != EFI_BUFFER_TOO_SMALL) { -			efi_printk("Failed to get initrd info size\n"); -			goto close_handles; -		} +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;; +	efi_status_t status; +	int i; -grow: -		status = efi_call_phys3(sys_table->boottime->allocate_pool, -					EFI_LOADER_DATA, info_sz, &info); -		if (status != EFI_SUCCESS) { -			efi_printk("Failed to alloc mem for initrd info\n"); -			goto close_handles; -		} +	first_uga = NULL; +	nr_ugas = size / sizeof(u64); +	for (i = 0; i < nr_ugas; i++) { +		efi_guid_t pciio_proto = EFI_PCI_IO_PROTOCOL_GUID; +		u32 w, h, depth, refresh; +		void *pciio; +		u64 handle = handles[i]; -		status = efi_call_phys4(h->get_info, h, &info_guid, -					&info_sz, info); -		if (status == EFI_BUFFER_TOO_SMALL) { -			efi_call_phys1(sys_table->boottime->free_pool, info); -			goto grow; -		} +		status = efi_call_early(handle_protocol, handle, +					&uga_proto, (void **)&uga); +		if (status != EFI_SUCCESS) +			continue; -		file_sz = info->file_size; -		efi_call_phys1(sys_table->boottime->free_pool, info); +		efi_call_early(handle_protocol, handle, &pciio_proto, &pciio); -		if (status != EFI_SUCCESS) { -			efi_printk("Failed to get initrd info\n"); -			goto close_handles; -		} +		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; -		initrd->size = file_sz; -		initrd_total += file_sz; +			/* +			 * Once we've found a UGA supporting PCIIO, +			 * don't bother looking any further. +			 */ +			if (pciio) +				break; + +			first_uga = uga; +		}  	} -	if (initrd_total) { -		unsigned long addr; +	return status; +} -		/* -		 * Multiple initrd's need to be at consecutive -		 * addresses in memory, so allocate enough memory for -		 * all the initrd's. -		 */ -		status = high_alloc(initrd_total, 0x1000, -				   &initrd_addr, hdr->initrd_addr_max); -		if (status != EFI_SUCCESS) { -			efi_printk("Failed to alloc highmem for initrds\n"); -			goto close_handles; -		} +/* + * 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; -		/* We've run out of free low memory. */ -		if (initrd_addr > hdr->initrd_addr_max) { -			efi_printk("We've run out of free low memory\n"); -			status = EFI_INVALID_PARAMETER; -			goto free_initrd_total; -		} +	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, +				size, (void **)&uga_handle); +	if (status != EFI_SUCCESS) +		return status; -		addr = initrd_addr; -		for (j = 0; j < nr_initrds; j++) { -			u64 size; - -			size = initrds[j].size; -			while (size) { -				u64 chunksize; -				if (size > EFI_READ_CHUNK_SIZE) -					chunksize = EFI_READ_CHUNK_SIZE; -				else -					chunksize = size; -				status = efi_call_phys3(fh->read, -							initrds[j].handle, -							&chunksize, addr); -				if (status != EFI_SUCCESS) { -					efi_printk("Failed to read initrd\n"); -					goto free_initrd_total; -				} -				addr += chunksize; -				size -= chunksize; -			} - -			efi_call_phys1(fh->close, initrds[j].handle); -		} +	status = efi_call_early(locate_handle, +				EFI_LOCATE_BY_PROTOCOL, +				uga_proto, NULL, &size, uga_handle); +	if (status != EFI_SUCCESS) +		goto free_handle; -	} +	height = 0; +	width = 0; -	efi_call_phys1(sys_table->boottime->free_pool, initrds); +	if (efi_early->is64) +		status = setup_uga64(uga_handle, size, &width, &height); +	else +		status = setup_uga32(uga_handle, size, &width, &height); -	hdr->ramdisk_image = initrd_addr; -	hdr->ramdisk_size = initrd_total; +	if (!width && !height) +		goto free_handle; -	return status; +	/* EFI framebuffer */ +	si->orig_video_isVGA = VIDEO_TYPE_EFI; -free_initrd_total: -	low_free(initrd_total, initrd_addr); +	si->lfb_depth = 32; +	si->lfb_width = width; +	si->lfb_height = height; -close_handles: -	for (k = j; k < i; k++) -		efi_call_phys1(fh->close, initrds[k].handle); -free_initrds: -	efi_call_phys1(sys_table->boottime->free_pool, initrds); -fail: -	hdr->ramdisk_image = 0; -	hdr->ramdisk_size = 0; +	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: +	efi_call_early(free_pool, uga_handle);  	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; +	status = efi_call_early(locate_handle, +				EFI_LOCATE_BY_PROTOCOL, +				&graphics_proto, NULL, &size, gop_handle); +	if (status == EFI_BUFFER_TOO_SMALL) +		status = setup_gop(si, &graphics_proto, size); + +	if (status != EFI_SUCCESS) { +		size = 0; +		status = efi_call_early(locate_handle, +					EFI_LOCATE_BY_PROTOCOL, +					&uga_proto, NULL, &size, uga_handle); +		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). + * + * The caller is responsible for filling out ->code32_start in the + * returned boot_params.   */ -struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table) +struct boot_params *make_boot_params(struct efi_config *c)  {  	struct boot_params *boot_params;  	struct sys_desc_table *sdt; @@ -874,32 +1028,41 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)  	struct setup_header *hdr;  	struct efi_info *efi;  	efi_loaded_image_t *image; -	void *options; -	u32 load_options_size; +	void *options, *handle;  	efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;  	int options_size = 0;  	efi_status_t status; -	unsigned long cmdline; +	char *cmdline_ptr;  	u16 *s2;  	u8 *s1;  	int i; +	unsigned long ramdisk_addr; +	unsigned long ramdisk_size; -	sys_table = _table; +	efi_early = c; +	sys_table = (efi_system_table_t *)(unsigned long)efi_early->table; +	handle = (void *)(unsigned long)efi_early->image_handle;  	/* Check if we were booted by the EFI firmware */  	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)  		return NULL; -	status = efi_call_phys3(sys_table->boottime->handle_protocol, -				handle, &proto, (void *)&image); +	if (efi_early->is64) +		setup_boot_services64(efi_early); +	else +		setup_boot_services32(efi_early); + +	status = efi_call_early(handle_protocol, handle, +				&proto, (void *)&image);  	if (status != EFI_SUCCESS) { -		efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); +		efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");  		return NULL;  	} -	status = low_alloc(0x4000, 1, (unsigned long *)&boot_params); +	status = efi_low_alloc(sys_table, 0x4000, 1, +			       (unsigned long *)&boot_params);  	if (status != EFI_SUCCESS) { -		efi_printk("Failed to alloc lowmem for boot params\n"); +		efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");  		return NULL;  	} @@ -921,45 +1084,13 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)  	hdr->vid_mode = 0xffff;  	hdr->boot_flag = 0xAA55; -	hdr->code32_start = (__u64)(unsigned long)image->image_base; -  	hdr->type_of_loader = 0x21;  	/* Convert unicode cmdline to ascii */ -	options = image->load_options; -	load_options_size = image->load_options_size / 2; /* ASCII */ -	cmdline = 0; -	s2 = (u16 *)options; - -	if (s2) { -		while (*s2 && *s2 != '\n' && options_size < load_options_size) { -			s2++; -			options_size++; -		} - -		if (options_size) { -			if (options_size > hdr->cmdline_size) -				options_size = hdr->cmdline_size; - -			options_size++;	/* NUL termination */ - -			status = low_alloc(options_size, 1, &cmdline); -			if (status != EFI_SUCCESS) { -				efi_printk("Failed to alloc mem for cmdline\n"); -				goto fail; -			} - -			s1 = (u8 *)(unsigned long)cmdline; -			s2 = (u16 *)options; - -			for (i = 0; i < options_size - 1; i++) -				*s1++ = *s2++; - -			*s1 = '\0'; -		} -	} - -	hdr->cmd_line_ptr = cmdline; +	cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size); +	if (!cmdline_ptr) +		goto fail; +	hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;  	hdr->ramdisk_image = 0;  	hdr->ramdisk_size = 0; @@ -969,96 +1100,64 @@ struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)  	memset(sdt, 0, sizeof(*sdt)); -	status = handle_ramdisks(image, hdr); +	status = handle_cmdline_files(sys_table, image, +				      (char *)(unsigned long)hdr->cmd_line_ptr, +				      "initrd=", hdr->initrd_addr_max, +				      &ramdisk_addr, &ramdisk_size);  	if (status != EFI_SUCCESS)  		goto fail2; +	hdr->ramdisk_image = ramdisk_addr; +	hdr->ramdisk_size = ramdisk_size;  	return boot_params;  fail2: -	if (options_size) -		low_free(options_size, hdr->cmd_line_ptr); +	efi_free(sys_table, options_size, hdr->cmd_line_ptr);  fail: -	low_free(0x4000, (unsigned long)boot_params); +	efi_free(sys_table, 0x4000, (unsigned long)boot_params);  	return NULL;  } -static efi_status_t exit_boot(struct boot_params *boot_params, -			      void *handle) +static void add_e820ext(struct boot_params *params, +			struct setup_data *e820ext, u32 nr_entries)  { -	struct efi_info *efi = &boot_params->efi_info; -	struct e820entry *e820_map = &boot_params->e820_map[0]; -	struct e820entry *prev = NULL; -	unsigned long size, key, desc_size, _size; -	efi_memory_desc_t *mem_map; +	struct setup_data *data;  	efi_status_t status; -	__u32 desc_version; -	bool called_exit = false; -	u8 nr_entries; -	int i; - -	size = sizeof(*mem_map) * 32; - -again: -	size += sizeof(*mem_map) * 2; -	_size = size; -	status = low_alloc(size, 1, (unsigned long *)&mem_map); -	if (status != EFI_SUCCESS) -		return status; - -get_map: -	status = efi_call_phys5(sys_table->boottime->get_memory_map, &size, -				mem_map, &key, &desc_size, &desc_version); -	if (status == EFI_BUFFER_TOO_SMALL) { -		low_free(_size, (unsigned long)mem_map); -		goto again; -	} - -	if (status != EFI_SUCCESS) -		goto free_mem_map; +	unsigned long size; -	memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32)); -	efi->efi_systab = (unsigned long)sys_table; -	efi->efi_memdesc_size = desc_size; -	efi->efi_memdesc_version = desc_version; -	efi->efi_memmap = (unsigned long)mem_map; -	efi->efi_memmap_size = size; +	e820ext->type = SETUP_E820_EXT; +	e820ext->len = nr_entries * sizeof(struct e820entry); +	e820ext->next = 0; -#ifdef CONFIG_X86_64 -	efi->efi_systab_hi = (unsigned long)sys_table >> 32; -	efi->efi_memmap_hi = (unsigned long)mem_map >> 32; -#endif +	data = (struct setup_data *)(unsigned long)params->hdr.setup_data; -	/* Might as well exit boot services now */ -	status = efi_call_phys2(sys_table->boottime->exit_boot_services, -				handle, key); -	if (status != EFI_SUCCESS) { -		/* -		 * ExitBootServices() will fail if any of the event -		 * handlers change the memory map. In which case, we -		 * must be prepared to retry, but only once so that -		 * we're guaranteed to exit on repeated failures instead -		 * of spinning forever. -		 */ -		if (called_exit) -			goto free_mem_map; +	while (data && data->next) +		data = (struct setup_data *)(unsigned long)data->next; -		called_exit = true; -		goto get_map; -	} +	if (data) +		data->next = (unsigned long)e820ext; +	else +		params->hdr.setup_data = (unsigned long)e820ext; +} -	/* Historic? */ -	boot_params->alt_mem_k = 32 * 1024; +static efi_status_t setup_e820(struct boot_params *params, +			       struct setup_data *e820ext, u32 e820ext_size) +{ +	struct e820entry *e820_map = ¶ms->e820_map[0]; +	struct efi_info *efi = ¶ms->efi_info; +	struct e820entry *prev = NULL; +	u32 nr_entries; +	u32 nr_desc; +	int i; -	/* -	 * Convert the EFI memory map to E820. -	 */  	nr_entries = 0; -	for (i = 0; i < size / desc_size; i++) { +	nr_desc = efi->efi_memmap_size / efi->efi_memdesc_size; + +	for (i = 0; i < nr_desc; i++) {  		efi_memory_desc_t *d;  		unsigned int e820_type = 0; -		unsigned long m = (unsigned long)mem_map; +		unsigned long m = efi->efi_memmap; -		d = (efi_memory_desc_t *)(m + (i * desc_size)); +		d = (efi_memory_desc_t *)(m + (i * efi->efi_memdesc_size));  		switch (d->type) {  		case EFI_RESERVED_TYPE:  		case EFI_RUNTIME_SERVICES_CODE: @@ -1095,58 +1194,148 @@ get_map:  		/* Merge adjacent mappings */  		if (prev && prev->type == e820_type && -		    (prev->addr + prev->size) == d->phys_addr) +		    (prev->addr + prev->size) == d->phys_addr) {  			prev->size += d->num_pages << 12; -		else { -			e820_map->addr = d->phys_addr; -			e820_map->size = d->num_pages << 12; -			e820_map->type = e820_type; -			prev = e820_map++; -			nr_entries++; +			continue; +		} + +		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++; +	} + +	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;  	} -	boot_params->e820_entries = nr_entries; +	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) { +		efi_call_early(free_pool, *e820ext); +		*e820ext = NULL; +		*e820ext_size = 0; +	} + +	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, +				size, (void **)e820ext); +	if (status == EFI_SUCCESS) +		*e820ext_size = size; -free_mem_map: -	low_free(_size, (unsigned long)mem_map);  	return status;  } -static efi_status_t relocate_kernel(struct setup_header *hdr) +static efi_status_t exit_boot(struct boot_params *boot_params, +			      void *handle, bool is64)  { -	unsigned long start, nr_pages; +	struct efi_info *efi = &boot_params->efi_info; +	unsigned long map_sz, key, desc_size; +	efi_memory_desc_t *mem_map; +	struct setup_data *e820ext; +	const char *signature; +	__u32 e820ext_size; +	__u32 nr_desc, prev_nr_desc;  	efi_status_t status; +	__u32 desc_version; +	bool called_exit = false; +	u8 nr_entries; +	int i; -	/* -	 * The EFI firmware loader could have placed the kernel image -	 * anywhere in memory, but the kernel has various restrictions -	 * on the max physical address it can run at. Attempt to move -	 * the kernel to boot_params.pref_address, or as low as -	 * possible. -	 */ -	start = hdr->pref_address; -	nr_pages = round_up(hdr->init_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; +	nr_desc = 0; +	e820ext = NULL; +	e820ext_size = 0; -	status = efi_call_phys4(sys_table->boottime->allocate_pages, -				EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, -				nr_pages, &start); -	if (status != EFI_SUCCESS) { -		status = low_alloc(hdr->init_size, hdr->kernel_alignment, -				   &start); +get_map: +	status = efi_get_memory_map(sys_table, &mem_map, &map_sz, &desc_size, +				    &desc_version, &key); + +	if (status != EFI_SUCCESS) +		return status; + +	prev_nr_desc = nr_desc; +	nr_desc = map_sz / desc_size; +	if (nr_desc > prev_nr_desc && +	    nr_desc > ARRAY_SIZE(boot_params->e820_map)) { +		u32 nr_e820ext = nr_desc - ARRAY_SIZE(boot_params->e820_map); + +		status = alloc_e820ext(nr_e820ext, &e820ext, &e820ext_size);  		if (status != EFI_SUCCESS) -			efi_printk("Failed to alloc mem for kernel\n"); +			goto free_mem_map; + +		efi_call_early(free_pool, mem_map); +		goto get_map; /* Allocated memory, get map again */  	} -	if (status == EFI_SUCCESS) -		memcpy((void *)start, (void *)(unsigned long)hdr->code32_start, -		       hdr->init_size); +	signature = is64 ? EFI64_LOADER_SIGNATURE : EFI32_LOADER_SIGNATURE; +	memcpy(&efi->efi_loader_signature, signature, sizeof(__u32)); -	hdr->pref_address = hdr->code32_start; -	hdr->code32_start = (__u32)start; +	efi->efi_systab = (unsigned long)sys_table; +	efi->efi_memdesc_size = desc_size; +	efi->efi_memdesc_version = desc_version; +	efi->efi_memmap = (unsigned long)mem_map; +	efi->efi_memmap_size = map_sz; + +#ifdef CONFIG_X86_64 +	efi->efi_systab_hi = (unsigned long)sys_table >> 32; +	efi->efi_memmap_hi = (unsigned long)mem_map >> 32; +#endif + +	/* Might as well exit boot services now */ +	status = efi_call_early(exit_boot_services, handle, key); +	if (status != EFI_SUCCESS) { +		/* +		 * ExitBootServices() will fail if any of the event +		 * handlers change the memory map. In which case, we +		 * must be prepared to retry, but only once so that +		 * we're guaranteed to exit on repeated failures instead +		 * of spinning forever. +		 */ +		if (called_exit) +			goto free_mem_map; + +		called_exit = true; +		efi_call_early(free_pool, mem_map); +		goto get_map; +	} +	/* Historic? */ +	boot_params->alt_mem_k = 32 * 1024; + +	status = setup_e820(boot_params, e820ext, e820ext_size); +	if (status != EFI_SUCCESS) +		return status; + +	return EFI_SUCCESS; + +free_mem_map: +	efi_call_early(free_pool, mem_map);  	return status;  } @@ -1154,14 +1343,23 @@ static efi_status_t relocate_kernel(struct setup_header *hdr)   * On success we return a pointer to a boot_params structure, and NULL   * on failure.   */ -struct boot_params *efi_main(void *handle, efi_system_table_t *_table, +struct boot_params *efi_main(struct efi_config *c,  			     struct boot_params *boot_params)  { -	struct desc_ptr *gdt, *idt; +	struct desc_ptr *gdt = NULL;  	efi_loaded_image_t *image;  	struct setup_header *hdr = &boot_params->hdr;  	efi_status_t status;  	struct desc_struct *desc; +	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;  	sys_table = _table; @@ -1169,48 +1367,48 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,  	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)  		goto fail; +	if (is64) +		setup_boot_services64(efi_early); +	else +		setup_boot_services32(efi_early); +  	setup_graphics(boot_params);  	setup_efi_pci(boot_params); -	status = efi_call_phys3(sys_table->boottime->allocate_pool, -				EFI_LOADER_DATA, sizeof(*gdt), -				(void **)&gdt); +	status = efi_call_early(allocate_pool, EFI_LOADER_DATA, +				sizeof(*gdt), (void **)&gdt);  	if (status != EFI_SUCCESS) { -		efi_printk("Failed to alloc mem for gdt structure\n"); +		efi_printk(sys_table, "Failed to alloc mem for gdt structure\n");  		goto fail;  	}  	gdt->size = 0x800; -	status = low_alloc(gdt->size, 8, (unsigned long *)&gdt->address); -	if (status != EFI_SUCCESS) { -		efi_printk("Failed to alloc mem for gdt\n"); -		goto fail; -	} - -	status = efi_call_phys3(sys_table->boottime->allocate_pool, -				EFI_LOADER_DATA, sizeof(*idt), -				(void **)&idt); +	status = efi_low_alloc(sys_table, gdt->size, 8, +			   (unsigned long *)&gdt->address);  	if (status != EFI_SUCCESS) { -		efi_printk("Failed to alloc mem for idt structure\n"); +		efi_printk(sys_table, "Failed to alloc mem for gdt\n");  		goto fail;  	} -	idt->size = 0; -	idt->address = 0; -  	/*  	 * If the kernel isn't already loaded at the preferred load  	 * address, relocate it.  	 */  	if (hdr->pref_address != hdr->code32_start) { -		status = relocate_kernel(hdr); - +		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);  		if (status != EFI_SUCCESS)  			goto fail; + +		hdr->pref_address = hdr->code32_start; +		hdr->code32_start = bzimage_addr;  	} -	status = exit_boot(boot_params, handle); +	status = exit_boot(boot_params, handle, is64);  	if (status != EFI_SUCCESS)  		goto fail; @@ -1267,10 +1465,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,  	desc->base2 = 0x00;  #endif /* CONFIG_X86_64 */ -	asm volatile ("lidt %0" : : "m" (*idt)); -	asm volatile ("lgdt %0" : : "m" (*gdt)); -  	asm volatile("cli"); +	asm volatile ("lgdt %0" : : "m" (*gdt));  	return boot_params;  fail:  | 
