diff options
Diffstat (limited to 'arch/x86/boot/compressed/eboot.c')
| -rw-r--r-- | arch/x86/boot/compressed/eboot.c | 198 | 
1 files changed, 120 insertions, 78 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 4e85f5f8583..b3e0227df2c 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -729,32 +729,68 @@ fail:   * need to create one ourselves (usually the bootloader would create   * one for us).   */ -static efi_status_t make_boot_params(struct boot_params *boot_params, -				     efi_loaded_image_t *image, -				     void *handle) +struct boot_params *make_boot_params(void *handle, efi_system_table_t *_table)  { -	struct efi_info *efi = &boot_params->efi_info; -	struct apm_bios_info *bi = &boot_params->apm_bios_info; -	struct sys_desc_table *sdt = &boot_params->sys_desc_table; -	struct e820entry *e820_map = &boot_params->e820_map[0]; -	struct e820entry *prev = NULL; -	struct setup_header *hdr = &boot_params->hdr; -	unsigned long size, key, desc_size, _size; -	efi_memory_desc_t *mem_map; -	void *options = image->load_options; -	u32 load_options_size = image->load_options_size / 2; /* ASCII */ +	struct boot_params *boot_params; +	struct sys_desc_table *sdt; +	struct apm_bios_info *bi; +	struct setup_header *hdr; +	struct efi_info *efi; +	efi_loaded_image_t *image; +	void *options; +	u32 load_options_size; +	efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;  	int options_size = 0;  	efi_status_t status; -	__u32 desc_version;  	unsigned long cmdline; -	u8 nr_entries;  	u16 *s2;  	u8 *s1;  	int i; +	sys_table = _table; + +	/* 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 (status != EFI_SUCCESS) { +		efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); +		return NULL; +	} + +	status = low_alloc(0x4000, 1, (unsigned long *)&boot_params); +	if (status != EFI_SUCCESS) { +		efi_printk("Failed to alloc lowmem for boot params\n"); +		return NULL; +	} + +	memset(boot_params, 0x0, 0x4000); + +	hdr = &boot_params->hdr; +	efi = &boot_params->efi_info; +	bi = &boot_params->apm_bios_info; +	sdt = &boot_params->sys_desc_table; + +	/* 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; + +	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; @@ -791,18 +827,36 @@ static efi_status_t make_boot_params(struct boot_params *boot_params,  	hdr->ramdisk_image = 0;  	hdr->ramdisk_size = 0; -	status = handle_ramdisks(image, hdr); -	if (status != EFI_SUCCESS) -		goto free_cmdline; - -	setup_graphics(boot_params); -  	/* Clear APM BIOS info */  	memset(bi, 0, sizeof(*bi));  	memset(sdt, 0, sizeof(*sdt)); -	memcpy(&efi->efi_loader_signature, EFI_LOADER_SIGNATURE, sizeof(__u32)); +	status = handle_ramdisks(image, hdr); +	if (status != EFI_SUCCESS) +		goto fail2; + +	return boot_params; +fail2: +	if (options_size) +		low_free(options_size, hdr->cmd_line_ptr); +fail: +	low_free(0x4000, (unsigned long)boot_params); +	return NULL; +} + +static efi_status_t exit_boot(struct boot_params *boot_params, +			      void *handle) +{ +	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; +	efi_status_t status; +	__u32 desc_version; +	u8 nr_entries; +	int i;  	size = sizeof(*mem_map) * 32; @@ -811,7 +865,7 @@ again:  	_size = size;  	status = low_alloc(size, 1, (unsigned long *)&mem_map);  	if (status != EFI_SUCCESS) -		goto free_cmdline; +		return status;  	status = efi_call_phys5(sys_table->boottime->get_memory_map, &size,  				mem_map, &key, &desc_size, &desc_version); @@ -823,6 +877,7 @@ again:  	if (status != EFI_SUCCESS)  		goto free_mem_map; +	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; @@ -906,61 +961,13 @@ again:  free_mem_map:  	low_free(_size, (unsigned long)mem_map); -free_cmdline: -	if (options_size) -		low_free(options_size, hdr->cmd_line_ptr); -fail:  	return status;  } -/* - * 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) +static efi_status_t relocate_kernel(struct setup_header *hdr)  { -	struct boot_params *boot_params;  	unsigned long start, nr_pages; -	struct desc_ptr *gdt, *idt; -	efi_loaded_image_t *image; -	struct setup_header *hdr;  	efi_status_t status; -	efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; -	struct desc_struct *desc; - -	sys_table = _table; - -	/* Check if we were booted by the EFI firmware */ -	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) -		goto fail; - -	status = efi_call_phys3(sys_table->boottime->handle_protocol, -				handle, &proto, (void *)&image); -	if (status != EFI_SUCCESS) { -		efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); -		goto fail; -	} - -	status = low_alloc(0x4000, 1, (unsigned long *)&boot_params); -	if (status != EFI_SUCCESS) { -		efi_printk("Failed to alloc lowmem for boot params\n"); -		goto fail; -	} - -	memset(boot_params, 0x0, 0x4000); - -	hdr = &boot_params->hdr; - -	/* 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;  	/*  	 * The EFI firmware loader could have placed the kernel image @@ -978,16 +985,40 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table)  	if (status != EFI_SUCCESS) {  		status = low_alloc(hdr->init_size, hdr->kernel_alignment,  				   &start); -		if (status != EFI_SUCCESS) { +		if (status != EFI_SUCCESS)  			efi_printk("Failed to alloc mem for kernel\n"); -			goto fail; -		}  	} +	if (status == EFI_SUCCESS) +		memcpy((void *)start, (void *)(unsigned long)hdr->code32_start, +		       hdr->init_size); + +	hdr->pref_address = hdr->code32_start;  	hdr->code32_start = (__u32)start; -	hdr->pref_address = (__u64)(unsigned long)image->image_base; -	memcpy((void *)start, image->image_base, image->image_size); +	return status; +} + +/* + * 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 *boot_params) +{ +	struct desc_ptr *gdt, *idt; +	efi_loaded_image_t *image; +	struct setup_header *hdr = &boot_params->hdr; +	efi_status_t status; +	struct desc_struct *desc; + +	sys_table = _table; + +	/* Check if we were booted by the EFI firmware */ +	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) +		goto fail; + +	setup_graphics(boot_params);  	status = efi_call_phys3(sys_table->boottime->allocate_pool,  				EFI_LOADER_DATA, sizeof(*gdt), @@ -1015,7 +1046,18 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table)  	idt->size = 0;  	idt->address = 0; -	status = make_boot_params(boot_params, image, handle); +	/* +	 * 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); + +		if (status != EFI_SUCCESS) +			goto fail; +	} + +	status = exit_boot(boot_params, handle);  	if (status != EFI_SUCCESS)  		goto fail;  |