Exemplo n.º 1
0
int efi_load_image(const char *file, efi_loaded_image_t **loaded_image,
		efi_handle_t *h)
{
	void *exe;
	size_t size;
	efi_handle_t handle;
	efi_status_t efiret = EFI_SUCCESS;

	exe = read_file(file, &size);
	if (!exe)
		return -EINVAL;

	efiret = BS->load_image(false, efi_parent_image, efi_device_path, exe, size,
			&handle);
	if (EFI_ERROR(efiret)) {
		pr_err("failed to LoadImage: %s\n", efi_strerror(efiret));
		goto out;
	};

	efiret = BS->open_protocol(handle, &efi_loaded_image_protocol_guid,
			(void **)loaded_image,
			efi_parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
	if (EFI_ERROR(efiret)) {
		pr_err("failed to OpenProtocol: %s\n", efi_strerror(efiret));
		BS->unload_image(handle);
		goto out;
	}

	*h = handle;
out:
	memset(exe, 0, size);
	free(exe);
	return -efi_errno(efiret);
}
Exemplo n.º 2
0
/**
 * Reallocate external memory
 *
 * @v old_ptr		Memory previously allocated by umalloc(), or UNULL
 * @v new_size		Requested size
 * @ret new_ptr		Allocated memory, or UNULL
 *
 * Calling realloc() with a new size of zero is a valid way to free a
 * memory block.
 */
static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
	EFI_PHYSICAL_ADDRESS phys_addr;
	unsigned int new_pages, old_pages;
	userptr_t new_ptr = UNOWHERE;
	size_t old_size;
	EFI_STATUS efirc;

	/* Allocate new memory if necessary.  If allocation fails,
	 * return without touching the old block.
	 */
	if ( new_size ) {
		new_pages = ( EFI_SIZE_TO_PAGES ( new_size ) + 1 );
		if ( ( efirc = bs->AllocatePages ( AllocateAnyPages,
						   EfiBootServicesData,
						   new_pages,
						   &phys_addr ) ) != 0 ) {
			DBG ( "EFI could not allocate %d pages: %s\n",
			      new_pages, efi_strerror ( efirc ) );
			return UNULL;
		}
		assert ( phys_addr != 0 );
		new_ptr = phys_to_user ( phys_addr + EFI_PAGE_SIZE );
		copy_to_user ( new_ptr, -EFI_PAGE_SIZE,
			       &new_size, sizeof ( new_size ) );
		DBG ( "EFI allocated %d pages at %llx\n",
		      new_pages, phys_addr );
	}

	/* Copy across relevant part of the old data region (if any),
	 * then free it.  Note that at this point either (a) new_ptr
	 * is valid, or (b) new_size is 0; either way, the memcpy() is
	 * valid.
	 */
	if ( old_ptr && ( old_ptr != UNOWHERE ) ) {
		copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE,
				 sizeof ( old_size ) );
		memcpy_user ( new_ptr, 0, old_ptr, 0,
			      ( (old_size < new_size) ? old_size : new_size ));
		old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 );
		phys_addr = user_to_phys ( old_ptr, -EFI_PAGE_SIZE );
		if ( ( efirc = bs->FreePages ( phys_addr, old_pages ) ) != 0 ){
			DBG ( "EFI could not free %d pages at %llx: %s\n",
			      old_pages, phys_addr, efi_strerror ( efirc ) );
			/* Not fatal; we have leaked memory but successfully
			 * allocated (if asked to do so).
			 */
		}
		DBG ( "EFI freed %d pages at %llx\n", old_pages, phys_addr );
	}

	return new_ptr;
}
Exemplo n.º 3
0
static int efi_execute_image(const char *file)
{
	efi_handle_t handle;
	efi_loaded_image_t *loaded_image;
	efi_status_t efiret;
	struct linux_kernel_header *image_header;
	const char *options;
	int ret;

	ret = efi_load_image(file, &loaded_image, &handle);
	if (ret)
		return ret;

	image_header = (struct linux_kernel_header *)loaded_image->image_base;
	if (image_header->boot_flag == 0xAA55 &&
	    image_header->header == 0x53726448) {
		pr_debug("Linux kernel detected. Adding bootargs.");
		options = linux_bootargs_get();
		pr_err("add linux options '%s'\n", options);
		loaded_image->load_options = xstrdup_char_to_wchar(options);
		loaded_image->load_options_size =
			(strlen(options) + 1) * sizeof(wchar_t);
	}

	efiret = BS->start_image(handle, NULL, NULL);
	if (EFI_ERROR(efiret))
		pr_err("failed to StartImage: %s\n", efi_strerror(efiret));

	BS->unload_image(handle);

	efi_connect_all();
	efi_register_devices();

	return -efi_errno(efiret);
}
Exemplo n.º 4
0
/**
 * Delay for a fixed number of microseconds
 *
 * @v usecs		Number of microseconds for which to delay
 */
static void efi_udelay ( unsigned long usecs ) {
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
	EFI_STATUS efirc;

	if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
		DBG ( "EFI could not delay for %ldus: %s\n",
		      usecs, efi_strerror ( efirc ) );
		/* Probably screwed */
	}
}
Exemplo n.º 5
0
/**
 * String write to device
 *
 * @v io_addr		I/O address
 * @v data		Data buffer
 * @v size		Size of values
 * @v count		Number of values to write
 */
void efi_iowrites ( volatile void *io_addr, const void *data,
		    size_t size, unsigned int count ) {
	EFI_CPU_IO_PROTOCOL_IO_MEM write;
	EFI_STATUS efirc;

	write = ( IS_PORT_ADDRESS ( io_addr ) ?
		 cpu_io->Io.Write : cpu_io->Mem.Write );

	if ( ( efirc = write ( cpu_io, efi_width ( size ),
			       ( intptr_t ) io_addr, count,
			       ( void * ) data ) ) != 0 ) {
		DBG ( "EFI I/O write at %p failed: %s\n",
		      io_addr, efi_strerror ( efirc ) );
	}
}
Exemplo n.º 6
0
/**
 * String read from device
 *
 * @v io_addr		I/O address
 * @v data		Data buffer
 * @v size		Size of values
 * @v count		Number of values to read
 */
void efi_ioreads ( volatile void *io_addr, void *data,
		   size_t size, unsigned int count ) {
	EFI_CPU_IO_PROTOCOL_IO_MEM read;
	EFI_STATUS efirc;

	read = ( IS_PORT_ADDRESS ( io_addr ) ?
		 cpu_io->Io.Read : cpu_io->Mem.Read );

	if ( ( efirc = read ( cpu_io, efi_width ( size ),
			      ( intptr_t ) io_addr, count,
			      ( void * ) data ) ) != 0 ) {
		DBG ( "EFI I/O string read at %p failed: %s\n",
		      io_addr, efi_strerror ( efirc ) );
	}
}
Exemplo n.º 7
0
/**
 * Get current system time in ticks
 *
 * @ret ticks		Current time, in ticks
 */
static unsigned long efi_currticks ( void ) {
	UINT64 time;
	EFI_STATUS efirc;

	/* Read CPU timer 0 (TSC) */
	if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time,
						 NULL ) ) != 0 ) {
		DBG ( "EFI could not read CPU timer: %s\n",
		      efi_strerror ( efirc ) );
		/* Probably screwed */
		return -1UL;
	}

	return ( time >> EFI_TIMER0_SHIFT );
}
Exemplo n.º 8
0
int efipci_write ( struct pci_device *pci, unsigned long location,
		   unsigned long value ) {
	EFI_STATUS efirc;

	if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ),
					   efipci_address ( pci, location ), 1,
					   &value ) ) != 0 ) {
		DBG ( "EFIPCI config write to %02x:%02x.%x offset %02lx "
		      "failed: %s\n", pci->bus, PCI_SLOT ( pci->devfn ),
		      PCI_FUNC ( pci->devfn ), EFIPCI_OFFSET ( location ),
		      efi_strerror ( efirc ) );
		return -EIO;
	}

	return 0;
}
Exemplo n.º 9
0
/**
 * Read from device
 *
 * @v io_addr		I/O address
 * @v size		Size of value
 * @ret data		Value read
 */
unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) {
	EFI_CPU_IO_PROTOCOL_IO_MEM read;
	unsigned long long data = 0;
	EFI_STATUS efirc;

	read = ( IS_PORT_ADDRESS ( io_addr ) ?
		 cpu_io->Io.Read : cpu_io->Mem.Read );

	if ( ( efirc = read ( cpu_io, efi_width ( size ),
			      ( intptr_t ) io_addr, 1,
			      ( void * ) &data ) ) != 0 ) {
		DBG ( "EFI I/O read at %p failed: %s\n",
		      io_addr, efi_strerror ( efirc ) );
		return -1ULL;
	}

	return data;
}
Exemplo n.º 10
0
/**
 * Probe EFI image
 *
 * @v image		EFI file
 * @ret rc		Return status code
 */
static int efi_image_probe ( struct image *image ) {
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
	EFI_HANDLE handle;
	EFI_STATUS efirc;

	/* Attempt loading image */
	if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
				       user_to_virt ( image->data, 0 ),
				       image->len, &handle ) ) != 0 ) {
		/* Not an EFI image */
		DBGC ( image, "EFIIMAGE %p could not load: %s\n",
		       image, efi_strerror ( efirc ) );
		return -ENOEXEC;
	}

	/* Unload the image.  We can't leave it loaded, because we
	 * have no "unload" operation.
	 */
	bs->UnloadImage ( handle );

	return 0;
}
Exemplo n.º 11
0
static int efi_execute_image(const char *file)
{
	void *exe;
	size_t size;
	efi_handle_t handle;
	efi_status_t efiret;
	const char *options;
	efi_loaded_image_t *loaded_image;

	exe = read_file(file, &size);
	if (!exe)
		return -EINVAL;

	efiret = BS->load_image(false, efi_parent_image, efi_device_path, exe, size,
			&handle);
	if (EFI_ERROR(efiret)) {
		pr_err("failed to LoadImage: %s\n", efi_strerror(efiret));
		return -efi_errno(efiret);;
	};

	efiret = BS->open_protocol(handle, &efi_loaded_image_protocol_guid,
			(void **)&loaded_image,
			efi_parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
	if (EFI_ERROR(efiret))
		return -efi_errno(efiret);

	options = linux_bootargs_get();
	loaded_image->load_options = strdup_char_to_wchar(options);
	loaded_image->load_options_size = (strlen(options) + 1) * sizeof(wchar_t);

	efiret = BS->start_image(handle, NULL, NULL);

	efi_connect_all();
	efi_register_devices();

	return 0;
}
Exemplo n.º 12
0
/**
 * Execute EFI image
 *
 * @v image		EFI image
 * @ret rc		Return status code
 */
static int efi_image_exec ( struct image *image ) {
	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
	struct efi_snp_device *snpdev;
	EFI_DEVICE_PATH_PROTOCOL *path;
	union {
		EFI_LOADED_IMAGE_PROTOCOL *image;
		void *interface;
	} loaded;
	EFI_HANDLE handle;
	wchar_t *cmdline;
	EFI_STATUS efirc;
	int rc;

	/* Find an appropriate device handle to use */
	snpdev = last_opened_snpdev();
	if ( ! snpdev ) {
		DBGC ( image, "EFIIMAGE %p could not identify SNP device\n",
		       image );
		rc = -ENODEV;
		goto err_no_snpdev;
	}

	/* Install file I/O protocols */
	if ( ( rc = efi_file_install ( &snpdev->handle ) ) != 0 ) {
		DBGC ( image, "EFIIMAGE %p could not install file protocol: "
		       "%s\n", image, strerror ( rc ) );
		goto err_file_install;
	}

	/* Install iPXE download protocol */
	if ( ( rc = efi_download_install ( &snpdev->handle ) ) != 0 ) {
		DBGC ( image, "EFIIMAGE %p could not install iPXE download "
		       "protocol: %s\n", image, strerror ( rc ) );
		goto err_download_install;
	}

	/* Create device path for image */
	path = efi_image_path ( image, &snpdev->path );
	if ( ! path ) {
		DBGC ( image, "EFIIMAGE %p could not create device path\n",
		       image );
		rc = -ENOMEM;
		goto err_image_path;
	}

	/* Create command line for image */
	cmdline = efi_image_cmdline ( image );
	if ( ! cmdline ) {
		DBGC ( image, "EFIIMAGE %p could not create command line\n",
		       image );
		rc = -ENOMEM;
		goto err_cmdline;
	}

	/* Attempt loading image */
	if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path,
				       user_to_virt ( image->data, 0 ),
				       image->len, &handle ) ) != 0 ) {
		/* Not an EFI image */
		DBGC ( image, "EFIIMAGE %p could not load: %s\n",
		       image, efi_strerror ( efirc ) );
		rc = -ENOEXEC;
		goto err_load_image;
	}

	/* Get the loaded image protocol for the newly loaded image */
	efirc = bs->OpenProtocol ( handle, &efi_loaded_image_protocol_guid,
				   &loaded.interface, efi_image_handle,
				   NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL );
	if ( efirc ) {
		/* Should never happen */
		rc = EFIRC_TO_RC ( efirc );
		goto err_open_protocol;
	}

	/* Sanity checks */
	assert ( loaded.image->ParentHandle == efi_image_handle );
	assert ( loaded.image->DeviceHandle == snpdev->handle );
	assert ( loaded.image->LoadOptionsSize == 0 );
	assert ( loaded.image->LoadOptions == NULL );

	/* Set command line */
	loaded.image->LoadOptions = cmdline;
	loaded.image->LoadOptionsSize =
		( ( wcslen ( cmdline ) + 1 /* NUL */ ) * sizeof ( wchar_t ) );

	/* Start the image */
	if ( ( efirc = bs->StartImage ( handle, NULL, NULL ) ) != 0 ) {
		DBGC ( image, "EFIIMAGE %p returned with status %s\n",
		       image, efi_strerror ( efirc ) );
		rc = EFIRC_TO_RC ( efirc );
		goto err_start_image;
	}

	/* Success */
	rc = 0;

 err_start_image:
 err_open_protocol:
	/* Unload the image.  We can't leave it loaded, because we
	 * have no "unload" operation.
	 */
	if ( ( efirc = bs->UnloadImage ( handle ) ) != 0 ) {
		DBGC ( image, "EFIIMAGE %p could not unload: %s\n",
		       image, efi_strerror ( efirc ) );
	}
 err_load_image:
	free ( cmdline );
 err_cmdline:
	free ( path );
 err_image_path:
	efi_download_uninstall ( snpdev->handle );
 err_download_install:
	efi_file_uninstall ( snpdev->handle );
 err_file_install:
 err_no_snpdev:
	return rc;
}