Пример #1
0
/*
 * EFI entry point for the arm/arm64 EFI stubs.  This is the entrypoint
 * that is described in the PE/COFF header.  Most of the code is the same
 * for both archictectures, with the arch-specific code provided in the
 * handle_kernel_image() function.
 */
unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
			       unsigned long *image_addr)
{
	efi_loaded_image_t *image;
	efi_status_t status;
	unsigned long image_size = 0;
	unsigned long dram_base;
	/* addr/point and size pairs for memory management*/
	unsigned long initrd_addr;
	u64 initrd_size = 0;
	unsigned long fdt_addr = 0;  /* Original DTB */
	unsigned long fdt_size = 0;
	char *cmdline_ptr = NULL;
	int cmdline_size = 0;
	unsigned long new_fdt_addr;
	efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
	unsigned long reserve_addr = 0;
	unsigned long reserve_size = 0;
	int secure_boot = 0;
	struct screen_info *si;

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

	pr_efi(sys_table, "Booting Linux Kernel...\n");

	status = check_platform_features(sys_table);
	if (status != EFI_SUCCESS)
		goto fail;

	/*
	 * Get a handle to the loaded image protocol.  This is used to get
	 * information about the running image, such as size and the command
	 * line.
	 */
	status = sys_table->boottime->handle_protocol(handle,
					&loaded_image_proto, (void *)&image);
	if (status != EFI_SUCCESS) {
		pr_efi_err(sys_table, "Failed to get loaded image protocol\n");
		goto fail;
	}

	dram_base = get_dram_base(sys_table);
	if (dram_base == EFI_ERROR) {
		pr_efi_err(sys_table, "Failed to find DRAM base\n");
		goto fail;
	}

	/*
	 * Get the command line from EFI, using the LOADED_IMAGE
	 * protocol. We are going to copy the command line into the
	 * device tree, so this can be allocated anywhere.
	 */
	cmdline_ptr = efi_convert_cmdline(sys_table, image, &cmdline_size);
	if (!cmdline_ptr) {
		pr_efi_err(sys_table, "getting command line via LOADED_IMAGE_PROTOCOL\n");
		goto fail;
	}

	/* check whether 'nokaslr' was passed on the command line */
	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
		static const u8 default_cmdline[] = CONFIG_CMDLINE;
		const u8 *str, *cmdline = cmdline_ptr;

		if (IS_ENABLED(CONFIG_CMDLINE_FORCE))
			cmdline = default_cmdline;
		str = strstr(cmdline, "nokaslr");
		if (str == cmdline || (str > cmdline && *(str - 1) == ' '))
			__nokaslr = true;
	}

	si = setup_graphics(sys_table);

	status = handle_kernel_image(sys_table, image_addr, &image_size,
				     &reserve_addr,
				     &reserve_size,
				     dram_base, image);
	if (status != EFI_SUCCESS) {
		pr_efi_err(sys_table, "Failed to relocate kernel\n");
		goto fail_free_cmdline;
	}

	status = efi_parse_options(cmdline_ptr);
	if (status != EFI_SUCCESS)
		pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n");

	secure_boot = efi_get_secureboot(sys_table);
	if (secure_boot > 0)
		pr_efi(sys_table, "UEFI Secure Boot is enabled.\n");

	if (secure_boot < 0) {
		pr_efi_err(sys_table,
			"could not determine UEFI Secure Boot status.\n");
	}

	/*
	 * Unauthenticated device tree data is a security hazard, so
	 * ignore 'dtb=' unless UEFI Secure Boot is disabled.
	 */
	if (secure_boot != 0 && strstr(cmdline_ptr, "dtb=")) {
		pr_efi(sys_table, "Ignoring DTB from command line.\n");
	} else {
		status = handle_cmdline_files(sys_table, image, cmdline_ptr,
					      "dtb=",
					      ~0UL, &fdt_addr, &fdt_size);

		if (status != EFI_SUCCESS) {
			pr_efi_err(sys_table, "Failed to load device tree!\n");
			goto fail_free_image;
		}
	}

	if (fdt_addr) {
		pr_efi(sys_table, "Using DTB from command line\n");
	} else {
		/* Look for a device tree configuration table entry. */
		fdt_addr = (uintptr_t)get_fdt(sys_table, &fdt_size);
		if (fdt_addr)
			pr_efi(sys_table, "Using DTB from configuration table\n");
	}

	if (!fdt_addr)
		pr_efi(sys_table, "Generating empty DTB\n");

	status = handle_cmdline_files(sys_table, image, cmdline_ptr,
				      "initrd=", dram_base + SZ_512M,
				      (unsigned long *)&initrd_addr,
				      (unsigned long *)&initrd_size);
	if (status != EFI_SUCCESS)
		pr_efi_err(sys_table, "Failed initrd from command line!\n");

	efi_random_get_seed(sys_table);

	new_fdt_addr = fdt_addr;
	status = allocate_new_fdt_and_exit_boot(sys_table, handle,
				&new_fdt_addr, dram_base + MAX_FDT_OFFSET,
				initrd_addr, initrd_size, cmdline_ptr,
				fdt_addr, fdt_size);

	/*
	 * If all went well, we need to return the FDT address to the
	 * calling function so it can be passed to kernel as part of
	 * the kernel boot protocol.
	 */
	if (status == EFI_SUCCESS)
		return new_fdt_addr;

	pr_efi_err(sys_table, "Failed to update FDT and exit boot services\n");

	efi_free(sys_table, initrd_size, initrd_addr);
	efi_free(sys_table, fdt_size, fdt_addr);

fail_free_image:
	efi_free(sys_table, image_size, *image_addr);
	efi_free(sys_table, reserve_size, reserve_addr);
fail_free_cmdline:
	free_screen_info(sys_table, si);
	efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
fail:
	return EFI_ERROR;
}
Пример #2
0
/*
 * 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(struct efi_config *c)
{
	struct boot_params *boot_params;
	struct apm_bios_info *bi;
	struct setup_header *hdr;
	efi_loaded_image_t *image;
	void *options, *handle;
	efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
	int options_size = 0;
	efi_status_t status;
	char *cmdline_ptr;
	u16 *s2;
	u8 *s1;
	int i;
	unsigned long ramdisk_addr;
	unsigned long ramdisk_size;

	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;

	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(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
		return NULL;
	}

	status = efi_low_alloc(sys_table, 0x4000, 1,
			       (unsigned long *)&boot_params);
	if (status != EFI_SUCCESS) {
		efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
		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;

	hdr->type_of_loader = 0x21;

	/* Convert unicode cmdline to ascii */
	cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
	if (!cmdline_ptr)
		goto fail;
	hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
	/* Fill in upper bits of command line address, NOP on 32 bit  */
	boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32;

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

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

	status = efi_parse_options(cmdline_ptr);
	if (status != EFI_SUCCESS)
		goto fail2;

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

	if (status != EFI_SUCCESS)
		goto fail2;
	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;

	return boot_params;
fail2:
	efi_free(sys_table, options_size, hdr->cmd_line_ptr);
fail:
	efi_free(sys_table, 0x4000, (unsigned long)boot_params);
	return NULL;
}