Exemplo n.º 1
0
/**
 * Deallocate space on the real-mode stack, optionally copying back
 * data to a user buffer.
 *
 * @v data		User buffer
 * @v size		Size of stack data
 */
void remove_user_from_rm_stack ( userptr_t data, size_t size ) {
	if ( data ) {
		userptr_t rm_stack = real_to_user ( rm_ss, rm_sp );
		memcpy_user ( rm_stack, 0, data, 0, size );
	}
	rm_sp += size;
};
Exemplo n.º 2
0
/**
 * Allocate space on the real-mode stack and copy data there from a
 * user buffer
 *
 * @v data		User buffer
 * @v size		Size of stack data
 * @ret sp		New value of real-mode stack pointer
 */
uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) {
	userptr_t rm_stack;
	rm_sp -= size;
	rm_stack = real_to_user ( rm_ss, rm_sp );
	memcpy_user ( rm_stack, 0, data, 0, size );
	return rm_sp;
};
Exemplo n.º 3
0
/**
 * Initialise initrd
 *
 * @ret rc		Return status code
 */
static int initrd_init ( void ) {
	struct image *image;
	int rc;

	/* Do nothing if no initrd was specified */
	if ( ! initrd_phys ) {
		DBGC ( colour, "RUNTIME found no initrd\n" );
		return 0;
	}
	if ( ! initrd_len ) {
		DBGC ( colour, "RUNTIME found empty initrd\n" );
		return 0;
	}
	DBGC ( colour, "RUNTIME found initrd at [%x,%x)\n",
	       initrd_phys, ( initrd_phys + initrd_len ) );

	/* Allocate image */
	image = alloc_image();
	if ( ! image ) {
		DBGC ( colour, "RUNTIME could not allocate image for "
		       "initrd\n" );
		rc = -ENOMEM;
		goto err_alloc_image;
	}
	image_set_name ( image, "<INITRD>" );

	/* Allocate and copy initrd content */
	image->data = umalloc ( initrd_len );
	if ( ! image->data ) {
		DBGC ( colour, "RUNTIME could not allocate %zd bytes for "
		       "initrd\n", initrd_len );
		rc = -ENOMEM;
		goto err_umalloc;
	}
	image->len = initrd_len;
	memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0,
		      initrd_len );

	/* Mark initrd as consumed */
	initrd_phys = 0;

	/* Register image */
	if ( ( rc = register_image ( image ) ) != 0 ) {
		DBGC ( colour, "RUNTIME could not register initrd: %s\n",
		       strerror ( rc ) );
		goto err_register_image;
	}

	/* Drop our reference to the image */
	image_put ( image );

	return 0;

 err_register_image:
 err_umalloc:
	image_put ( image );
 err_alloc_image:
	return rc;
}
Exemplo n.º 4
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;
	int rc;

	/* 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 ) {
			rc = -EEFI ( efirc );
			DBG ( "EFI could not allocate %d pages: %s\n",
			      new_pages, strerror ( rc ) );
			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 ){
			rc = -EEFI ( efirc );
			DBG ( "EFI could not free %d pages at %llx: %s\n",
			      old_pages, phys_addr, strerror ( rc ) );
			/* 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.º 5
0
/**
 * Execute PXE image
 *
 * @v image		PXE image
 * @ret rc		Return status code
 */
static int pxe_exec ( struct image *image ) {
	userptr_t buffer = real_to_user ( 0, 0x7c00 );
	struct net_device *netdev;
	int rc;

	/* Verify and prepare segment */
	if ( ( rc = prep_segment ( buffer, image->len, image->len ) ) != 0 ) {
		DBGC ( image, "IMAGE %p could not prepare segment: %s\n",
		       image, strerror ( rc ) );
		return rc;
	}

	/* Copy image to segment */
	memcpy_user ( buffer, 0, image->data, 0, image->len );

	/* Arbitrarily pick the most recently opened network device */
	if ( ( netdev = last_opened_netdev() ) == NULL ) {
		DBGC ( image, "IMAGE %p could not locate PXE net device\n",
		       image );
		return -ENODEV;
	}
	netdev_get ( netdev );

	/* Activate PXE */
	pxe_activate ( netdev );

	/* Construct fake DHCP packets */
	pxe_fake_cached_info();

	/* Set PXE command line */
	pxe_cmdline = image->cmdline;

	/* Reset console since PXE NBP will probably use it */
	console_reset();

	/* Disable IRQ, if applicable */
	if ( netdev_irq_supported ( netdev ) && netdev->dev->desc.irq )
		disable_irq ( netdev->dev->desc.irq );

	/* Start PXE NBP */
	rc = pxe_start_nbp();

	/* Clear PXE command line */
	pxe_cmdline = NULL;

	/* Deactivate PXE */
	pxe_deactivate();

	/* Try to reopen network device.  Ignore errors, since the NBP
	 * may have called PXENV_STOP_UNDI.
	 */
	netdev_open ( netdev );
	netdev_put ( netdev );

	return rc;
}
Exemplo n.º 6
0
/**
 * Load ELF segment into memory
 *
 * @v image		ELF file
 * @v phdr		ELF program header
 * @ret rc		Return status code
 */
static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) {
	physaddr_t dest;
	userptr_t buffer;
	int rc;

	/* Do nothing for non-PT_LOAD segments */
	if ( phdr->p_type != PT_LOAD )
		return 0;

	/* Check segment lies within image */
	if ( ( phdr->p_offset + phdr->p_filesz ) > image->len ) {
		DBG ( "ELF segment outside ELF file\n" );
		return -ENOEXEC;
	}

	/* Find start address: use physical address for preference,
	 * fall back to virtual address if no physical address
	 * supplied.
	 */
	dest = phdr->p_paddr;
	if ( ! dest )
		dest = phdr->p_vaddr;
	if ( ! dest ) {
		DBG ( "ELF segment loads to physical address 0\n" );
		return -ENOEXEC;
	}
	buffer = phys_to_user ( dest );

	DBG ( "ELF loading segment [%x,%x) to [%x,%x,%x)\n",
	      phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
	      phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
	      ( phdr->p_paddr + phdr->p_memsz ) );

	/* Verify and prepare segment */
	if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
				   phdr->p_memsz ) ) != 0 ) {
		DBG ( "ELF could not prepare segment: %s\n", strerror ( rc ) );
		return rc;
	}

	/* Copy image to segment */
	memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );

	return 0;
}
Exemplo n.º 7
0
/**
 * Load PXE image into memory
 *
 * @v image		PXE file
 * @ret rc		Return status code
 */
int pxe_load ( struct image *image ) {
	userptr_t buffer = real_to_user ( 0, 0x7c00 );
	size_t filesz = image->len;
	size_t memsz = image->len;
	int rc;

	/* Images too large to fit in base memory cannot be PXE
	 * images.  We include this check to help prevent unrecognised
	 * images from being marked as PXE images, since PXE images
	 * have no signature we can check against.
	 */
	if ( filesz > ( 0xa0000 - 0x7c00 ) )
		return -ENOEXEC;

	/* Rejecting zero-length images is also useful, since these
	 * end up looking to the user like bugs in gPXE.
	 */
	if ( ! filesz )
		return -ENOEXEC;

	/* There are no signature checks for PXE; we will accept anything */
	if ( ! image->type )
		image->type = &pxe_image_type;

	/* Verify and prepare segment */
	if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
		DBGC ( image, "IMAGE %p could not prepare segment: %s\n",
		       image, strerror ( rc ) );
		return rc;
	}

	/* Copy image to segment */
	memcpy_user ( buffer, 0, image->data, 0, filesz );

	return 0;
}
Exemplo n.º 8
0
/**
 * Load ELF segment into memory
 *
 * @v image		ELF file
 * @v phdr		ELF program header
 * @v ehdr		ELF executable header
 * @ret entry		Entry point, if found
 * @ret max		Maximum used address
 * @ret rc		Return status code
 */
static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
			      Elf_Ehdr *ehdr, physaddr_t *entry,
			      physaddr_t *max ) {
	physaddr_t dest;
	physaddr_t end;
	userptr_t buffer;
	unsigned long e_offset;
	int rc;

	/* Do nothing for non-PT_LOAD segments */
	if ( phdr->p_type != PT_LOAD )
		return 0;

	/* Check segment lies within image */
	if ( ( phdr->p_offset + phdr->p_filesz ) > image->len ) {
		DBGC ( image, "ELF %p segment outside image\n", image );
		return -ENOEXEC;
	}

	/* Find start address: use physical address for preference,
	 * fall back to virtual address if no physical address
	 * supplied.
	 */
	dest = phdr->p_paddr;
	if ( ! dest )
		dest = phdr->p_vaddr;
	if ( ! dest ) {
		DBGC ( image, "ELF %p segment loads to physical address 0\n",
		       image );
		return -ENOEXEC;
	}
	buffer = phys_to_user ( dest );
	end = ( dest + phdr->p_memsz );

	DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
	       phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
	       phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
	       ( phdr->p_paddr + phdr->p_memsz ) );

	/* Verify and prepare segment */
	if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
				   phdr->p_memsz ) ) != 0 ) {
		DBGC ( image, "ELF %p could not prepare segment: %s\n",
		       image, strerror ( rc ) );
		return rc;
	}

	/* Update maximum used address, if applicable */
	if ( end > *max )
		*max = end;

	/* Copy image to segment */
	memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );

	/* Set execution address, if it lies within this segment */
	if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
		*entry = ehdr->e_entry;
		DBGC ( image, "ELF %p found physical entry point at %lx\n",
		       image, *entry );
	} else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) )
		    < phdr->p_filesz ) {
		if ( ! *entry ) {
			*entry = ( dest + e_offset );
			DBGC ( image, "ELF %p found virtual entry point at %lx"
			       " (virt %lx)\n", image, *entry,
			       ( ( unsigned long ) ehdr->e_entry ) );
		}
	}

	return 0;
}
Exemplo n.º 9
0
/**
 * Read and verify El Torito Boot Record Volume Descriptor
 *
 * @v image		El Torito file
 * @ret catalog_offset	Offset of Boot Catalog
 * @ret rc		Return status code
 */
static int eltorito_read_voldesc ( struct image *image,
				   unsigned long *catalog_offset ) {
	static const struct eltorito_vol_desc vol_desc_signature = {
		.record_indicator = 0,
		.iso9660_id = "CD001",
		.version = 1,
		.system_indicator = "EL TORITO SPECIFICATION",
	};
	struct eltorito_vol_desc vol_desc;

	/* Sanity check */
	if ( image->len < ( ELTORITO_VOL_DESC_OFFSET + ISO9660_BLKSIZE ) ) {
		DBGC ( image, "ElTorito %p too short\n", image );
		return -ENOEXEC;
	}

	/* Read and verify Boot Record Volume Descriptor */
	copy_from_user ( &vol_desc, image->data, ELTORITO_VOL_DESC_OFFSET,
			 sizeof ( vol_desc ) );
	if ( memcmp ( &vol_desc, &vol_desc_signature,
		      offsetof ( typeof ( vol_desc ), sector ) ) != 0 ) {
		DBGC ( image, "ElTorito %p invalid Boot Record Volume "
		       "Descriptor\n", image );
		return -ENOEXEC;
	}
	*catalog_offset = ( vol_desc.sector * ISO9660_BLKSIZE );

	DBGC ( image, "ElTorito %p boot catalog at offset %#lx\n",
	       image, *catalog_offset );

	return 0;
}

/**
 * Read and verify El Torito Boot Catalog
 *
 * @v image		El Torito file
 * @v catalog_offset	Offset of Boot Catalog
 * @ret boot_entry	El Torito boot entry
 * @ret rc		Return status code
 */
static int eltorito_read_catalog ( struct image *image,
				   unsigned long catalog_offset,
				   struct eltorito_boot_entry *boot_entry ) {
	struct eltorito_validation_entry validation_entry;

	/* Sanity check */
	if ( image->len < ( catalog_offset + ISO9660_BLKSIZE ) ) {
		DBGC ( image, "ElTorito %p bad boot catalog offset %#lx\n",
		       image, catalog_offset );
		return -ENOEXEC;
	}

	/* Read and verify the Validation Entry of the Boot Catalog */
	copy_from_user ( &validation_entry, image->data, catalog_offset,
			 sizeof ( validation_entry ) );
	if ( word_checksum ( &validation_entry,
			     sizeof ( validation_entry ) ) != 0 ) {
		DBGC ( image, "ElTorito %p bad Validation Entry checksum\n",
		       image );
		return -ENOEXEC;
	}

	/* Read and verify the Initial/Default entry */
	copy_from_user ( boot_entry, image->data,
			 ( catalog_offset + sizeof ( validation_entry ) ),
			 sizeof ( *boot_entry ) );
	if ( boot_entry->indicator != ELTORITO_BOOTABLE ) {
		DBGC ( image, "ElTorito %p not bootable\n", image );
		return -ENOEXEC;
	}
	if ( boot_entry->media_type != ELTORITO_NO_EMULATION ) {
		DBGC ( image, "ElTorito %p cannot support media type %d\n",
		       image, boot_entry->media_type );
		return -ENOTSUP;
	}

	DBGC ( image, "ElTorito %p media type %d segment %04x\n",
	       image, boot_entry->media_type, boot_entry->load_segment );

	return 0;
}

/**
 * Load El Torito virtual disk image into memory
 *
 * @v image		El Torito file
 * @v boot_entry	El Torito boot entry
 * @ret rc		Return status code
 */
static int eltorito_load_disk ( struct image *image,
				struct eltorito_boot_entry *boot_entry ) {
	unsigned long start = ( boot_entry->start * ISO9660_BLKSIZE );
	unsigned long length = ( boot_entry->length * ISO9660_BLKSIZE );
	unsigned int load_segment;
	userptr_t buffer;
	int rc;

	/* Sanity check */
	if ( image->len < ( start + length ) ) {
		DBGC ( image, "ElTorito %p virtual disk lies outside image\n",
		       image );
		return -ENOEXEC;
	}
	DBGC ( image, "ElTorito %p virtual disk at %#lx+%#lx\n",
	       image, start, length );

	/* Calculate load address */
	load_segment = boot_entry->load_segment;
	buffer = real_to_user ( load_segment, ( load_segment ? 0 : 0x7c00 ) );

	/* Verify and prepare segment */
	if ( ( rc = prep_segment ( buffer, length, length ) ) != 0 ) {
		DBGC ( image, "ElTorito %p could not prepare segment: %s\n",
		       image, strerror ( rc ) );
		return rc;
	}

	/* Copy image to segment */
	memcpy_user ( buffer, 0, image->data, start, length );

	return 0;
}