mirror of https://github.com/ipxe/ipxe.git
[image] Simplify image management
Refactor the {load,exec} image operations as {probe,exec}. This makes the probe mechanism cleaner, eliminates some forward declarations, avoids holding magic state in image->priv, eliminates the possibility of screwing up between the "load" and "exec" stages, and makes the documentation simpler since the concept of "loading" (as distinct from "executing") no longer needs to be explained. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/1/head
parent
530a01eff0
commit
34b6ecb2f1
|
@ -41,8 +41,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
FEATURE ( FEATURE_IMAGE, "bzImage", DHCP_EB_FEATURE_BZIMAGE, 1 );
|
FEATURE ( FEATURE_IMAGE, "bzImage", DHCP_EB_FEATURE_BZIMAGE, 1 );
|
||||||
|
|
||||||
struct image_type bzimage_image_type __image_type ( PROBE_NORMAL );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bzImage context
|
* bzImage context
|
||||||
*/
|
*/
|
||||||
|
@ -111,8 +109,8 @@ static int bzimage_parse_header ( struct image *image,
|
||||||
sizeof ( bzimg->bzhdr ) );
|
sizeof ( bzimg->bzhdr ) );
|
||||||
|
|
||||||
/* Calculate size of real-mode portion */
|
/* Calculate size of real-mode portion */
|
||||||
bzimg->rm_filesz =
|
bzimg->rm_filesz = ( ( ( bzimg->bzhdr.setup_sects ?
|
||||||
( ( bzimg->bzhdr.setup_sects ? bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9;
|
bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9 );
|
||||||
if ( bzimg->rm_filesz > image->len ) {
|
if ( bzimg->rm_filesz > image->len ) {
|
||||||
DBGC ( image, "bzImage %p too short for %zd byte of setup\n",
|
DBGC ( image, "bzImage %p too short for %zd byte of setup\n",
|
||||||
image, bzimg->rm_filesz );
|
image, bzimg->rm_filesz );
|
||||||
|
@ -455,11 +453,33 @@ static int bzimage_exec ( struct image *image ) {
|
||||||
const char *cmdline = ( image->cmdline ? image->cmdline : "" );
|
const char *cmdline = ( image->cmdline ? image->cmdline : "" );
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Read and parse header from loaded kernel */
|
/* Read and parse header from image */
|
||||||
if ( ( rc = bzimage_parse_header ( image, &bzimg,
|
if ( ( rc = bzimage_parse_header ( image, &bzimg,
|
||||||
image->priv.user ) ) != 0 )
|
image->data ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
assert ( bzimg.rm_kernel == image->priv.user );
|
|
||||||
|
/* Prepare segments */
|
||||||
|
if ( ( rc = prep_segment ( bzimg.rm_kernel, bzimg.rm_filesz,
|
||||||
|
bzimg.rm_memsz ) ) != 0 ) {
|
||||||
|
DBGC ( image, "bzImage %p could not prepare RM segment: %s\n",
|
||||||
|
image, strerror ( rc ) );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
if ( ( rc = prep_segment ( bzimg.pm_kernel, bzimg.pm_sz,
|
||||||
|
bzimg.pm_sz ) ) != 0 ) {
|
||||||
|
DBGC ( image, "bzImage %p could not prepare PM segment: %s\n",
|
||||||
|
image, strerror ( rc ) );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load segments */
|
||||||
|
memcpy_user ( bzimg.rm_kernel, 0, image->data,
|
||||||
|
0, bzimg.rm_filesz );
|
||||||
|
memcpy_user ( bzimg.pm_kernel, 0, image->data,
|
||||||
|
bzimg.rm_filesz, bzimg.pm_sz );
|
||||||
|
|
||||||
|
/* Update and write out header */
|
||||||
|
bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
|
||||||
|
|
||||||
/* Parse command line for bootloader parameters */
|
/* Parse command line for bootloader parameters */
|
||||||
if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
|
if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
|
||||||
|
@ -506,12 +526,12 @@ static int bzimage_exec ( struct image *image ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load bzImage image into memory
|
* Probe bzImage image
|
||||||
*
|
*
|
||||||
* @v image bzImage file
|
* @v image bzImage file
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int bzimage_load ( struct image *image ) {
|
int bzimage_probe ( struct image *image ) {
|
||||||
struct bzimage_context bzimg;
|
struct bzimage_context bzimg;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -520,42 +540,12 @@ int bzimage_load ( struct image *image ) {
|
||||||
image->data ) ) != 0 )
|
image->data ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* This is a bzImage image, valid or otherwise */
|
|
||||||
if ( ! image->type )
|
|
||||||
image->type = &bzimage_image_type;
|
|
||||||
|
|
||||||
/* Prepare segments */
|
|
||||||
if ( ( rc = prep_segment ( bzimg.rm_kernel, bzimg.rm_filesz,
|
|
||||||
bzimg.rm_memsz ) ) != 0 ) {
|
|
||||||
DBGC ( image, "bzImage %p could not prepare RM segment: %s\n",
|
|
||||||
image, strerror ( rc ) );
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if ( ( rc = prep_segment ( bzimg.pm_kernel, bzimg.pm_sz,
|
|
||||||
bzimg.pm_sz ) ) != 0 ) {
|
|
||||||
DBGC ( image, "bzImage %p could not prepare PM segment: %s\n",
|
|
||||||
image, strerror ( rc ) );
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load segments */
|
|
||||||
memcpy_user ( bzimg.rm_kernel, 0, image->data,
|
|
||||||
0, bzimg.rm_filesz );
|
|
||||||
memcpy_user ( bzimg.pm_kernel, 0, image->data,
|
|
||||||
bzimg.rm_filesz, bzimg.pm_sz );
|
|
||||||
|
|
||||||
/* Update and write out header */
|
|
||||||
bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
|
|
||||||
|
|
||||||
/* Record real-mode segment in image private data field */
|
|
||||||
image->priv.user = bzimg.rm_kernel;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Linux bzImage image type */
|
/** Linux bzImage image type */
|
||||||
struct image_type bzimage_image_type __image_type ( PROBE_NORMAL ) = {
|
struct image_type bzimage_image_type __image_type ( PROBE_NORMAL ) = {
|
||||||
.name = "bzImage",
|
.name = "bzImage",
|
||||||
.load = bzimage_load,
|
.probe = bzimage_probe,
|
||||||
.exec = bzimage_exec,
|
.exec = bzimage_exec,
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,8 +40,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
#include <ipxe/init.h>
|
#include <ipxe/init.h>
|
||||||
#include <ipxe/io.h>
|
#include <ipxe/io.h>
|
||||||
|
|
||||||
struct image_type com32_image_type __image_type ( PROBE_NORMAL );
|
|
||||||
|
|
||||||
struct idt_register com32_external_idtr = {
|
struct idt_register com32_external_idtr = {
|
||||||
.limit = COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) - 1,
|
.limit = COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) - 1,
|
||||||
.base = COM32_IDT
|
.base = COM32_IDT
|
||||||
|
@ -55,7 +53,7 @@ struct idt_register com32_internal_idtr;
|
||||||
* @v image COM32 image
|
* @v image COM32 image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int com32_exec ( struct image *image ) {
|
static int com32_exec_loop ( struct image *image ) {
|
||||||
struct memory_map memmap;
|
struct memory_map memmap;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int state;
|
int state;
|
||||||
|
@ -137,7 +135,6 @@ static int com32_exec ( struct image *image ) {
|
||||||
image, comboot_replacement_image );
|
image, comboot_replacement_image );
|
||||||
image->replacement = comboot_replacement_image;
|
image->replacement = comboot_replacement_image;
|
||||||
comboot_replacement_image = NULL;
|
comboot_replacement_image = NULL;
|
||||||
image_autoload ( image->replacement );
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMBOOT_EXIT_COMMAND:
|
case COMBOOT_EXIT_COMMAND:
|
||||||
|
@ -207,7 +204,7 @@ static int com32_identify ( struct image *image ) {
|
||||||
* @v image COM32 image
|
* @v image COM32 image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int comboot_load_image ( struct image *image ) {
|
static int com32_load_image ( struct image *image ) {
|
||||||
physaddr_t com32_irq_wrapper_phys;
|
physaddr_t com32_irq_wrapper_phys;
|
||||||
struct idt_descriptor *idt;
|
struct idt_descriptor *idt;
|
||||||
struct ijb_entry *ijb;
|
struct ijb_entry *ijb;
|
||||||
|
@ -262,7 +259,7 @@ static int comboot_load_image ( struct image *image ) {
|
||||||
* @v image COM32 image
|
* @v image COM32 image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int comboot_prepare_bounce_buffer ( struct image * image ) {
|
static int com32_prepare_bounce_buffer ( struct image * image ) {
|
||||||
unsigned int seg;
|
unsigned int seg;
|
||||||
userptr_t seg_userptr;
|
userptr_t seg_userptr;
|
||||||
size_t filesz, memsz;
|
size_t filesz, memsz;
|
||||||
|
@ -286,12 +283,12 @@ static int comboot_prepare_bounce_buffer ( struct image * image ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load COM32 image into memory
|
* Probe COM32 image
|
||||||
*
|
*
|
||||||
* @v image COM32 image
|
* @v image COM32 image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int com32_load ( struct image *image ) {
|
static int com32_probe ( struct image *image ) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
DBGC ( image, "COM32 %p: name '%s', cmdline '%s'\n",
|
DBGC ( image, "COM32 %p: name '%s', cmdline '%s'\n",
|
||||||
|
@ -302,26 +299,34 @@ static int com32_load ( struct image *image ) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a COM32 image, valid or otherwise */
|
return 0;
|
||||||
if ( ! image->type )
|
}
|
||||||
image->type = &com32_image_type;
|
|
||||||
|
/**
|
||||||
|
* Execute COMBOOT image
|
||||||
|
*
|
||||||
|
* @v image COM32 image
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int com32_exec ( struct image *image ) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* Load image */
|
/* Load image */
|
||||||
if ( ( rc = comboot_load_image ( image ) ) != 0 ) {
|
if ( ( rc = com32_load_image ( image ) ) != 0 ) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare bounce buffer segment */
|
/* Prepare bounce buffer segment */
|
||||||
if ( ( rc = comboot_prepare_bounce_buffer ( image ) ) != 0 ) {
|
if ( ( rc = com32_prepare_bounce_buffer ( image ) ) != 0 ) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return com32_exec_loop ( image );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** SYSLINUX COM32 image type */
|
/** SYSLINUX COM32 image type */
|
||||||
struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {
|
struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {
|
||||||
.name = "COM32",
|
.name = "COM32",
|
||||||
.load = com32_load,
|
.probe = com32_probe,
|
||||||
.exec = com32_exec,
|
.exec = com32_exec,
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,8 +42,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
FEATURE ( FEATURE_IMAGE, "COMBOOT", DHCP_EB_FEATURE_COMBOOT, 1 );
|
FEATURE ( FEATURE_IMAGE, "COMBOOT", DHCP_EB_FEATURE_COMBOOT, 1 );
|
||||||
|
|
||||||
struct image_type comboot_image_type __image_type ( PROBE_NORMAL );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* COMBOOT PSP, copied to offset 0 of code segment
|
* COMBOOT PSP, copied to offset 0 of code segment
|
||||||
*/
|
*/
|
||||||
|
@ -131,7 +129,7 @@ static void comboot_init_psp ( struct image * image, userptr_t seg_userptr ) {
|
||||||
* @v image COMBOOT image
|
* @v image COMBOOT image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int comboot_exec ( struct image *image ) {
|
static int comboot_exec_loop ( struct image *image ) {
|
||||||
userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
|
userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
|
||||||
int state;
|
int state;
|
||||||
|
|
||||||
|
@ -194,7 +192,6 @@ static int comboot_exec ( struct image *image ) {
|
||||||
image, comboot_replacement_image );
|
image, comboot_replacement_image );
|
||||||
image->replacement = comboot_replacement_image;
|
image->replacement = comboot_replacement_image;
|
||||||
comboot_replacement_image = NULL;
|
comboot_replacement_image = NULL;
|
||||||
image_autoload ( image->replacement );
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMBOOT_EXIT_COMMAND:
|
case COMBOOT_EXIT_COMMAND:
|
||||||
|
@ -278,12 +275,12 @@ static int comboot_prepare_segment ( struct image *image )
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load COMBOOT image into memory
|
* Probe COMBOOT image
|
||||||
*
|
*
|
||||||
* @v image COMBOOT image
|
* @v image COMBOOT image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int comboot_load ( struct image *image ) {
|
static int comboot_probe ( struct image *image ) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
DBGC ( image, "COMBOOT %p: name '%s'\n",
|
DBGC ( image, "COMBOOT %p: name '%s'\n",
|
||||||
|
@ -295,9 +292,17 @@ static int comboot_load ( struct image *image ) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a 16-bit COMBOOT image, valid or otherwise */
|
return 0;
|
||||||
if ( ! image->type )
|
}
|
||||||
image->type = &comboot_image_type;
|
|
||||||
|
/**
|
||||||
|
* Execute COMBOOT image
|
||||||
|
*
|
||||||
|
* @v image COMBOOT image
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int comboot_exec ( struct image *image ) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* Sanity check for filesize */
|
/* Sanity check for filesize */
|
||||||
if( image->len >= 0xFF00 ) {
|
if( image->len >= 0xFF00 ) {
|
||||||
|
@ -311,12 +316,12 @@ static int comboot_load ( struct image *image ) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return comboot_exec_loop ( image );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** SYSLINUX COMBOOT (16-bit) image type */
|
/** SYSLINUX COMBOOT (16-bit) image type */
|
||||||
struct image_type comboot_image_type __image_type ( PROBE_NORMAL ) = {
|
struct image_type comboot_image_type __image_type ( PROBE_NORMAL ) = {
|
||||||
.name = "COMBOOT",
|
.name = "COMBOOT",
|
||||||
.load = comboot_load,
|
.probe = comboot_probe,
|
||||||
.exec = comboot_exec,
|
.exec = comboot_exec,
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,8 +34,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 );
|
FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 );
|
||||||
|
|
||||||
struct image_type elfboot_image_type __image_type ( PROBE_NORMAL );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute ELF image
|
* Execute ELF image
|
||||||
*
|
*
|
||||||
|
@ -43,7 +41,15 @@ struct image_type elfboot_image_type __image_type ( PROBE_NORMAL );
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int elfboot_exec ( struct image *image ) {
|
static int elfboot_exec ( struct image *image ) {
|
||||||
physaddr_t entry = image->priv.phys;
|
physaddr_t entry;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Load the image using core ELF support */
|
||||||
|
if ( ( rc = elf_load ( image, &entry ) ) != 0 ) {
|
||||||
|
DBGC ( image, "ELF %p could not load: %s\n",
|
||||||
|
image, strerror ( rc ) );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* An ELF image has no callback interface, so we need to shut
|
/* An ELF image has no callback interface, so we need to shut
|
||||||
* down before invoking it.
|
* down before invoking it.
|
||||||
|
@ -66,12 +72,12 @@ static int elfboot_exec ( struct image *image ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load ELF image into memory
|
* Probe ELF image
|
||||||
*
|
*
|
||||||
* @v image ELF file
|
* @v image ELF file
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int elfboot_load ( struct image *image ) {
|
static int elfboot_probe ( struct image *image ) {
|
||||||
Elf32_Ehdr ehdr;
|
Elf32_Ehdr ehdr;
|
||||||
static const uint8_t e_ident[] = {
|
static const uint8_t e_ident[] = {
|
||||||
[EI_MAG0] = ELFMAG0,
|
[EI_MAG0] = ELFMAG0,
|
||||||
|
@ -82,7 +88,6 @@ static int elfboot_load ( struct image *image ) {
|
||||||
[EI_DATA] = ELFDATA2LSB,
|
[EI_DATA] = ELFDATA2LSB,
|
||||||
[EI_VERSION] = EV_CURRENT,
|
[EI_VERSION] = EV_CURRENT,
|
||||||
};
|
};
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* Read ELF header */
|
/* Read ELF header */
|
||||||
copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
|
copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
|
||||||
|
@ -91,23 +96,12 @@ static int elfboot_load ( struct image *image ) {
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is an ELF image, valid or otherwise */
|
|
||||||
if ( ! image->type )
|
|
||||||
image->type = &elfboot_image_type;
|
|
||||||
|
|
||||||
/* Load the image using core ELF support */
|
|
||||||
if ( ( rc = elf_load ( image ) ) != 0 ) {
|
|
||||||
DBGC ( image, "ELF %p could not load: %s\n",
|
|
||||||
image, strerror ( rc ) );
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ELF image type */
|
/** ELF image type */
|
||||||
struct image_type elfboot_image_type __image_type ( PROBE_NORMAL ) = {
|
struct image_type elfboot_image_type __image_type ( PROBE_NORMAL ) = {
|
||||||
.name = "ELF",
|
.name = "ELF",
|
||||||
.load = elfboot_load,
|
.probe = elfboot_probe,
|
||||||
.exec = elfboot_exec,
|
.exec = elfboot_exec,
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,8 +40,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 );
|
FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 );
|
||||||
|
|
||||||
struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum number of modules we will allow for
|
* Maximum number of modules we will allow for
|
||||||
*
|
*
|
||||||
|
@ -254,57 +252,6 @@ static struct multiboot_memory_map
|
||||||
static struct multiboot_module __bss16_array ( mbmodules, [MAX_MODULES] );
|
static struct multiboot_module __bss16_array ( mbmodules, [MAX_MODULES] );
|
||||||
#define mbmodules __use_data16 ( mbmodules )
|
#define mbmodules __use_data16 ( mbmodules )
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute multiboot image
|
|
||||||
*
|
|
||||||
* @v image Multiboot image
|
|
||||||
* @ret rc Return status code
|
|
||||||
*/
|
|
||||||
static int multiboot_exec ( struct image *image ) {
|
|
||||||
physaddr_t entry = image->priv.phys;
|
|
||||||
|
|
||||||
/* Populate multiboot information structure */
|
|
||||||
memset ( &mbinfo, 0, sizeof ( mbinfo ) );
|
|
||||||
mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
|
|
||||||
MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
|
|
||||||
mb_cmdline_offset = 0;
|
|
||||||
mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline );
|
|
||||||
mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
|
|
||||||
( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
|
|
||||||
mbinfo.mods_addr = virt_to_phys ( mbmodules );
|
|
||||||
mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
|
|
||||||
mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
|
|
||||||
|
|
||||||
/* Multiboot images may not return and have no callback
|
|
||||||
* interface, so shut everything down prior to booting the OS.
|
|
||||||
*/
|
|
||||||
shutdown_boot();
|
|
||||||
|
|
||||||
/* Build memory map after unhiding bootloader memory regions as part of
|
|
||||||
* shutting everything down.
|
|
||||||
*/
|
|
||||||
multiboot_build_memmap ( image, &mbinfo, mbmemmap,
|
|
||||||
( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) );
|
|
||||||
|
|
||||||
/* Jump to OS with flat physical addressing */
|
|
||||||
DBGC ( image, "MULTIBOOT %p starting execution at %lx\n",
|
|
||||||
image, entry );
|
|
||||||
__asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t"
|
|
||||||
"call *%%edi\n\t"
|
|
||||||
"popl %%ebp\n\t" )
|
|
||||||
: : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
|
|
||||||
"b" ( virt_to_phys ( &mbinfo ) ),
|
|
||||||
"D" ( entry )
|
|
||||||
: "ecx", "edx", "esi", "memory" );
|
|
||||||
|
|
||||||
DBGC ( image, "MULTIBOOT %p returned\n", image );
|
|
||||||
|
|
||||||
/* It isn't safe to continue after calling shutdown() */
|
|
||||||
while ( 1 ) {}
|
|
||||||
|
|
||||||
return -ECANCELED; /* -EIMPOSSIBLE, anyone? */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find multiboot header
|
* Find multiboot header
|
||||||
*
|
*
|
||||||
|
@ -357,10 +304,12 @@ static int multiboot_find_header ( struct image *image,
|
||||||
*
|
*
|
||||||
* @v image Multiboot file
|
* @v image Multiboot file
|
||||||
* @v hdr Multiboot header descriptor
|
* @v hdr Multiboot header descriptor
|
||||||
|
* @ret entry Entry point
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int multiboot_load_raw ( struct image *image,
|
static int multiboot_load_raw ( struct image *image,
|
||||||
struct multiboot_header_info *hdr ) {
|
struct multiboot_header_info *hdr,
|
||||||
|
physaddr_t *entry ) {
|
||||||
size_t offset;
|
size_t offset;
|
||||||
size_t filesz;
|
size_t filesz;
|
||||||
size_t memsz;
|
size_t memsz;
|
||||||
|
@ -391,8 +340,8 @@ static int multiboot_load_raw ( struct image *image,
|
||||||
/* Copy image to segment */
|
/* Copy image to segment */
|
||||||
memcpy_user ( buffer, 0, image->data, offset, filesz );
|
memcpy_user ( buffer, 0, image->data, offset, filesz );
|
||||||
|
|
||||||
/* Record execution entry point in image private data field */
|
/* Record execution entry point */
|
||||||
image->priv.phys = hdr->mb.entry_addr;
|
*entry = hdr->mb.entry_addr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -401,13 +350,14 @@ static int multiboot_load_raw ( struct image *image,
|
||||||
* Load ELF multiboot image into memory
|
* Load ELF multiboot image into memory
|
||||||
*
|
*
|
||||||
* @v image Multiboot file
|
* @v image Multiboot file
|
||||||
|
* @ret entry Entry point
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int multiboot_load_elf ( struct image *image ) {
|
static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Load ELF image*/
|
/* Load ELF image*/
|
||||||
if ( ( rc = elf_load ( image ) ) != 0 ) {
|
if ( ( rc = elf_load ( image, entry ) ) != 0 ) {
|
||||||
DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
|
DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
|
||||||
image, strerror ( rc ) );
|
image, strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -417,13 +367,14 @@ static int multiboot_load_elf ( struct image *image ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load multiboot image into memory
|
* Execute multiboot image
|
||||||
*
|
*
|
||||||
* @v image Multiboot file
|
* @v image Multiboot image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int multiboot_load ( struct image *image ) {
|
static int multiboot_exec ( struct image *image ) {
|
||||||
struct multiboot_header_info hdr;
|
struct multiboot_header_info hdr;
|
||||||
|
physaddr_t entry;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Locate multiboot header, if present */
|
/* Locate multiboot header, if present */
|
||||||
|
@ -432,12 +383,6 @@ static int multiboot_load ( struct image *image ) {
|
||||||
image );
|
image );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
DBGC ( image, "MULTIBOOT %p found header with flags %08x\n",
|
|
||||||
image, hdr.mb.flags );
|
|
||||||
|
|
||||||
/* This is a multiboot image, valid or otherwise */
|
|
||||||
if ( ! image->type )
|
|
||||||
image->type = &multiboot_image_type;
|
|
||||||
|
|
||||||
/* Abort if we detect flags that we cannot support */
|
/* Abort if we detect flags that we cannot support */
|
||||||
if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) {
|
if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) {
|
||||||
|
@ -451,16 +396,77 @@ static int multiboot_load ( struct image *image ) {
|
||||||
* the ELF header if present, and Solaris relies on this
|
* the ELF header if present, and Solaris relies on this
|
||||||
* behaviour.
|
* behaviour.
|
||||||
*/
|
*/
|
||||||
if ( ( ( rc = multiboot_load_elf ( image ) ) != 0 ) &&
|
if ( ( ( rc = multiboot_load_elf ( image, &entry ) ) != 0 ) &&
|
||||||
( ( rc = multiboot_load_raw ( image, &hdr ) ) != 0 ) )
|
( ( rc = multiboot_load_raw ( image, &hdr, &entry ) ) != 0 ) )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
/* Populate multiboot information structure */
|
||||||
|
memset ( &mbinfo, 0, sizeof ( mbinfo ) );
|
||||||
|
mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
|
||||||
|
MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
|
||||||
|
mb_cmdline_offset = 0;
|
||||||
|
mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline );
|
||||||
|
mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
|
||||||
|
( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
|
||||||
|
mbinfo.mods_addr = virt_to_phys ( mbmodules );
|
||||||
|
mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
|
||||||
|
mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
|
||||||
|
|
||||||
|
/* Multiboot images may not return and have no callback
|
||||||
|
* interface, so shut everything down prior to booting the OS.
|
||||||
|
*/
|
||||||
|
shutdown_boot();
|
||||||
|
|
||||||
|
/* Build memory map after unhiding bootloader memory regions as part of
|
||||||
|
* shutting everything down.
|
||||||
|
*/
|
||||||
|
multiboot_build_memmap ( image, &mbinfo, mbmemmap,
|
||||||
|
( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) );
|
||||||
|
|
||||||
|
/* Jump to OS with flat physical addressing */
|
||||||
|
DBGC ( image, "MULTIBOOT %p starting execution at %lx\n",
|
||||||
|
image, entry );
|
||||||
|
__asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t"
|
||||||
|
"call *%%edi\n\t"
|
||||||
|
"popl %%ebp\n\t" )
|
||||||
|
: : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
|
||||||
|
"b" ( virt_to_phys ( &mbinfo ) ),
|
||||||
|
"D" ( entry )
|
||||||
|
: "ecx", "edx", "esi", "memory" );
|
||||||
|
|
||||||
|
DBGC ( image, "MULTIBOOT %p returned\n", image );
|
||||||
|
|
||||||
|
/* It isn't safe to continue after calling shutdown() */
|
||||||
|
while ( 1 ) {}
|
||||||
|
|
||||||
|
return -ECANCELED; /* -EIMPOSSIBLE, anyone? */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Probe multiboot image
|
||||||
|
*
|
||||||
|
* @v image Multiboot file
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int multiboot_probe ( struct image *image ) {
|
||||||
|
struct multiboot_header_info hdr;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Locate multiboot header, if present */
|
||||||
|
if ( ( rc = multiboot_find_header ( image, &hdr ) ) != 0 ) {
|
||||||
|
DBGC ( image, "MULTIBOOT %p has no multiboot header\n",
|
||||||
|
image );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
DBGC ( image, "MULTIBOOT %p found header with flags %08x\n",
|
||||||
|
image, hdr.mb.flags );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Multiboot image type */
|
/** Multiboot image type */
|
||||||
struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT ) = {
|
struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT ) = {
|
||||||
.name = "Multiboot",
|
.name = "Multiboot",
|
||||||
.load = multiboot_load,
|
.probe = multiboot_probe,
|
||||||
.exec = multiboot_exec,
|
.exec = multiboot_exec,
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,8 +28,6 @@
|
||||||
|
|
||||||
FEATURE ( FEATURE_IMAGE, "NBI", DHCP_EB_FEATURE_NBI, 1 );
|
FEATURE ( FEATURE_IMAGE, "NBI", DHCP_EB_FEATURE_NBI, 1 );
|
||||||
|
|
||||||
struct image_type nbi_image_type __image_type ( PROBE_NORMAL );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An NBI image header
|
* An NBI image header
|
||||||
*
|
*
|
||||||
|
@ -240,57 +238,6 @@ static int nbi_process_segments ( struct image *image,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load an NBI image into memory
|
|
||||||
*
|
|
||||||
* @v image NBI image
|
|
||||||
* @ret rc Return status code
|
|
||||||
*/
|
|
||||||
static int nbi_load ( struct image *image ) {
|
|
||||||
struct imgheader imgheader;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* If we don't have enough data give up */
|
|
||||||
if ( image->len < NBI_HEADER_LENGTH ) {
|
|
||||||
DBGC ( image, "NBI %p too short for an NBI image\n", image );
|
|
||||||
return -ENOEXEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check image header */
|
|
||||||
copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
|
|
||||||
if ( imgheader.magic != NBI_MAGIC ) {
|
|
||||||
DBGC ( image, "NBI %p has no NBI signature\n", image );
|
|
||||||
return -ENOEXEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is an NBI image, valid or otherwise */
|
|
||||||
if ( ! image->type )
|
|
||||||
image->type = &nbi_image_type;
|
|
||||||
|
|
||||||
DBGC ( image, "NBI %p placing header at %hx:%hx\n", image,
|
|
||||||
imgheader.location.segment, imgheader.location.offset );
|
|
||||||
|
|
||||||
/* NBI files can have overlaps between segments; the bss of
|
|
||||||
* one segment may overlap the initialised data of another. I
|
|
||||||
* assume this is a design flaw, but there are images out
|
|
||||||
* there that we need to work with. We therefore do two
|
|
||||||
* passes: first to initialise the segments, then to copy the
|
|
||||||
* data. This avoids zeroing out already-copied data.
|
|
||||||
*/
|
|
||||||
if ( ( rc = nbi_process_segments ( image, &imgheader,
|
|
||||||
nbi_prepare_segment ) ) != 0 )
|
|
||||||
return rc;
|
|
||||||
if ( ( rc = nbi_process_segments ( image, &imgheader,
|
|
||||||
nbi_load_segment ) ) != 0 )
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
/* Record header address in image private data field */
|
|
||||||
image->priv.user = real_to_user ( imgheader.location.segment,
|
|
||||||
imgheader.location.offset );
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Boot a 16-bit NBI image
|
* Boot a 16-bit NBI image
|
||||||
*
|
*
|
||||||
|
@ -396,8 +343,25 @@ static int nbi_exec ( struct image *image ) {
|
||||||
int may_return;
|
int may_return;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
copy_from_user ( &imgheader, image->priv.user, 0,
|
/* Retrieve image header */
|
||||||
sizeof ( imgheader ) );
|
copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
|
||||||
|
|
||||||
|
DBGC ( image, "NBI %p placing header at %hx:%hx\n", image,
|
||||||
|
imgheader.location.segment, imgheader.location.offset );
|
||||||
|
|
||||||
|
/* NBI files can have overlaps between segments; the bss of
|
||||||
|
* one segment may overlap the initialised data of another. I
|
||||||
|
* assume this is a design flaw, but there are images out
|
||||||
|
* there that we need to work with. We therefore do two
|
||||||
|
* passes: first to initialise the segments, then to copy the
|
||||||
|
* data. This avoids zeroing out already-copied data.
|
||||||
|
*/
|
||||||
|
if ( ( rc = nbi_process_segments ( image, &imgheader,
|
||||||
|
nbi_prepare_segment ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
if ( ( rc = nbi_process_segments ( image, &imgheader,
|
||||||
|
nbi_load_segment ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
|
||||||
/* Prepare DHCP option block */
|
/* Prepare DHCP option block */
|
||||||
if ( ( rc = nbi_prepare_dhcp ( image ) ) != 0 )
|
if ( ( rc = nbi_prepare_dhcp ( image ) ) != 0 )
|
||||||
|
@ -427,9 +391,34 @@ static int nbi_exec ( struct image *image ) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Probe NBI image
|
||||||
|
*
|
||||||
|
* @v image NBI image
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int nbi_probe ( struct image *image ) {
|
||||||
|
struct imgheader imgheader;
|
||||||
|
|
||||||
|
/* If we don't have enough data give up */
|
||||||
|
if ( image->len < NBI_HEADER_LENGTH ) {
|
||||||
|
DBGC ( image, "NBI %p too short for an NBI image\n", image );
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check image header */
|
||||||
|
copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
|
||||||
|
if ( imgheader.magic != NBI_MAGIC ) {
|
||||||
|
DBGC ( image, "NBI %p has no NBI signature\n", image );
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** NBI image type */
|
/** NBI image type */
|
||||||
struct image_type nbi_image_type __image_type ( PROBE_NORMAL ) = {
|
struct image_type nbi_image_type __image_type ( PROBE_NORMAL ) = {
|
||||||
.name = "NBI",
|
.name = "NBI",
|
||||||
.load = nbi_load,
|
.probe = nbi_probe,
|
||||||
.exec = nbi_exec,
|
.exec = nbi_exec,
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,8 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
|
FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
|
||||||
|
|
||||||
struct image_type pxe_image_type __image_type ( PROBE_PXE );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute PXE image
|
* Execute PXE image
|
||||||
*
|
*
|
||||||
|
@ -44,9 +42,20 @@ struct image_type pxe_image_type __image_type ( PROBE_PXE );
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int pxe_exec ( struct image *image ) {
|
static int pxe_exec ( struct image *image ) {
|
||||||
|
userptr_t buffer = real_to_user ( 0, 0x7c00 );
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
int rc;
|
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 */
|
/* Arbitrarily pick the most recently opened network device */
|
||||||
if ( ( netdev = last_opened_netdev() ) == NULL ) {
|
if ( ( netdev = last_opened_netdev() ) == NULL ) {
|
||||||
DBGC ( image, "IMAGE %p could not locate PXE net device\n",
|
DBGC ( image, "IMAGE %p could not locate PXE net device\n",
|
||||||
|
@ -67,51 +76,33 @@ static int pxe_exec ( struct image *image ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load PXE image into memory
|
* Probe PXE image
|
||||||
*
|
*
|
||||||
* @v image PXE file
|
* @v image PXE file
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int pxe_load ( struct image *image ) {
|
int pxe_probe ( 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 too large to fit in base memory cannot be PXE
|
||||||
* images. We include this check to help prevent unrecognised
|
* images. We include this check to help prevent unrecognised
|
||||||
* images from being marked as PXE images, since PXE images
|
* images from being marked as PXE images, since PXE images
|
||||||
* have no signature we can check against.
|
* have no signature we can check against.
|
||||||
*/
|
*/
|
||||||
if ( filesz > ( 0xa0000 - 0x7c00 ) )
|
if ( image->len > ( 0xa0000 - 0x7c00 ) )
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
|
|
||||||
/* Rejecting zero-length images is also useful, since these
|
/* Rejecting zero-length images is also useful, since these
|
||||||
* end up looking to the user like bugs in iPXE.
|
* end up looking to the user like bugs in iPXE.
|
||||||
*/
|
*/
|
||||||
if ( ! filesz )
|
if ( ! image->len )
|
||||||
return -ENOEXEC;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** PXE image type */
|
/** PXE image type */
|
||||||
struct image_type pxe_image_type __image_type ( PROBE_PXE ) = {
|
struct image_type pxe_image_type __image_type ( PROBE_PXE ) = {
|
||||||
.name = "PXE",
|
.name = "PXE",
|
||||||
.load = pxe_load,
|
.probe = pxe_probe,
|
||||||
.exec = pxe_exec,
|
.exec = pxe_exec,
|
||||||
};
|
};
|
||||||
|
|
|
@ -217,7 +217,7 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ( ( rc = imgfetch ( kernel, kernel_file,
|
if ( ( rc = imgfetch ( kernel, kernel_file,
|
||||||
register_image ) ) != 0 ) {
|
register_and_select_image ) ) != 0 ) {
|
||||||
DBG ( "COMBOOT: could not fetch kernel: %s\n",
|
DBG ( "COMBOOT: could not fetch kernel: %s\n",
|
||||||
strerror ( rc ) );
|
strerror ( rc ) );
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -218,8 +218,7 @@ static struct interface_descriptor downloader_job_desc =
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*
|
*
|
||||||
* Instantiates a downloader object to download the specified URI into
|
* Instantiates a downloader object to download the specified URI into
|
||||||
* the specified image object. If the download is successful, the
|
* the specified image object.
|
||||||
* image registration routine @c register_image() will be called.
|
|
||||||
*/
|
*/
|
||||||
int create_downloader ( struct interface *job, struct image *image,
|
int create_downloader ( struct interface *job, struct image *image,
|
||||||
int type, ... ) {
|
int type, ... ) {
|
||||||
|
|
182
src/core/image.c
182
src/core/image.c
|
@ -32,7 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
*
|
*
|
||||||
* Executable/loadable images
|
* Executable images
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
struct list_head images = LIST_HEAD_INIT ( images );
|
struct list_head images = LIST_HEAD_INIT ( images );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free executable/loadable image
|
* Free executable image
|
||||||
*
|
*
|
||||||
* @v refcnt Reference counter
|
* @v refcnt Reference counter
|
||||||
*/
|
*/
|
||||||
|
@ -52,13 +52,13 @@ static void free_image ( struct refcnt *refcnt ) {
|
||||||
ufree ( image->data );
|
ufree ( image->data );
|
||||||
image_put ( image->replacement );
|
image_put ( image->replacement );
|
||||||
free ( image );
|
free ( image );
|
||||||
DBGC ( image, "IMAGE %p freed\n", image );
|
DBGC ( image, "IMAGE %s freed\n", image->name );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate executable/loadable image
|
* Allocate executable image
|
||||||
*
|
*
|
||||||
* @ret image Executable/loadable image
|
* @ret image Executable image
|
||||||
*/
|
*/
|
||||||
struct image * alloc_image ( void ) {
|
struct image * alloc_image ( void ) {
|
||||||
struct image *image;
|
struct image *image;
|
||||||
|
@ -75,12 +75,11 @@ struct image * alloc_image ( void ) {
|
||||||
*
|
*
|
||||||
* @v image Image
|
* @v image Image
|
||||||
* @v URI New image URI
|
* @v URI New image URI
|
||||||
* @ret rc Return status code
|
|
||||||
*
|
*
|
||||||
* If no name is set, the name will be updated to the base name of the
|
* If no name is set, the name will be updated to the base name of the
|
||||||
* URI path (if any).
|
* URI path (if any).
|
||||||
*/
|
*/
|
||||||
int image_set_uri ( struct image *image, struct uri *uri ) {
|
void image_set_uri ( struct image *image, struct uri *uri ) {
|
||||||
const char *path = uri->path;
|
const char *path = uri->path;
|
||||||
|
|
||||||
/* Replace URI reference */
|
/* Replace URI reference */
|
||||||
|
@ -90,8 +89,6 @@ int image_set_uri ( struct image *image, struct uri *uri ) {
|
||||||
/* Set name if none already specified */
|
/* Set name if none already specified */
|
||||||
if ( path && ( ! image->name[0] ) )
|
if ( path && ( ! image->name[0] ) )
|
||||||
image_set_name ( image, basename ( ( char * ) path ) );
|
image_set_name ( image, basename ( ( char * ) path ) );
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,9 +107,9 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register executable/loadable image
|
* Register executable image
|
||||||
*
|
*
|
||||||
* @v image Executable/loadable image
|
* @v image Executable image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int register_image ( struct image *image ) {
|
int register_image ( struct image *image ) {
|
||||||
|
@ -127,20 +124,20 @@ int register_image ( struct image *image ) {
|
||||||
/* Add to image list */
|
/* Add to image list */
|
||||||
image_get ( image );
|
image_get ( image );
|
||||||
list_add_tail ( &image->list, &images );
|
list_add_tail ( &image->list, &images );
|
||||||
DBGC ( image, "IMAGE %p at [%lx,%lx) registered as %s\n",
|
DBGC ( image, "IMAGE %s at [%lx,%lx) registered\n",
|
||||||
image, user_to_phys ( image->data, 0 ),
|
image->name, user_to_phys ( image->data, 0 ),
|
||||||
user_to_phys ( image->data, image->len ), image->name );
|
user_to_phys ( image->data, image->len ) );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregister executable/loadable image
|
* Unregister executable image
|
||||||
*
|
*
|
||||||
* @v image Executable/loadable image
|
* @v image Executable image
|
||||||
*/
|
*/
|
||||||
void unregister_image ( struct image *image ) {
|
void unregister_image ( struct image *image ) {
|
||||||
DBGC ( image, "IMAGE %p unregistered\n", image );
|
DBGC ( image, "IMAGE %s unregistered\n", image->name );
|
||||||
list_del ( &image->list );
|
list_del ( &image->list );
|
||||||
image_put ( image );
|
image_put ( image );
|
||||||
}
|
}
|
||||||
|
@ -149,7 +146,7 @@ void unregister_image ( struct image *image ) {
|
||||||
* Find image by name
|
* Find image by name
|
||||||
*
|
*
|
||||||
* @v name Image name
|
* @v name Image name
|
||||||
* @ret image Executable/loadable image, or NULL
|
* @ret image Executable image, or NULL
|
||||||
*/
|
*/
|
||||||
struct image * find_image ( const char *name ) {
|
struct image * find_image ( const char *name ) {
|
||||||
struct image *image;
|
struct image *image;
|
||||||
|
@ -163,75 +160,39 @@ struct image * find_image ( const char *name ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load executable/loadable image into memory
|
* Determine image type
|
||||||
*
|
*
|
||||||
* @v image Executable/loadable image
|
* @v image Executable image
|
||||||
* @v type Executable/loadable image type
|
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int image_load_type ( struct image *image, struct image_type *type ) {
|
int image_probe ( struct image *image ) {
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* Check image is actually loadable */
|
|
||||||
if ( ! type->load )
|
|
||||||
return -ENOEXEC;
|
|
||||||
|
|
||||||
/* Try the image loader */
|
|
||||||
if ( ( rc = type->load ( image ) ) != 0 ) {
|
|
||||||
DBGC ( image, "IMAGE %p could not load as %s: %s\n",
|
|
||||||
image, type->name, strerror ( rc ) );
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Flag as loaded */
|
|
||||||
image->flags |= IMAGE_LOADED;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load executable/loadable image into memory
|
|
||||||
*
|
|
||||||
* @v image Executable/loadable image
|
|
||||||
* @ret rc Return status code
|
|
||||||
*/
|
|
||||||
int image_load ( struct image *image ) {
|
|
||||||
|
|
||||||
assert ( image->type != NULL );
|
|
||||||
|
|
||||||
return image_load_type ( image, image->type );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Autodetect image type and load executable/loadable image into memory
|
|
||||||
*
|
|
||||||
* @v image Executable/loadable image
|
|
||||||
* @ret rc Return status code
|
|
||||||
*/
|
|
||||||
int image_autoload ( struct image *image ) {
|
|
||||||
struct image_type *type;
|
struct image_type *type;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* If image already has a type, use it */
|
/* Succeed if we already have a type */
|
||||||
if ( image->type )
|
if ( image->type )
|
||||||
return image_load ( image );
|
return 0;
|
||||||
|
|
||||||
/* Otherwise probe for a suitable type */
|
/* Try each type in turn */
|
||||||
for_each_table_entry ( type, IMAGE_TYPES ) {
|
for_each_table_entry ( type, IMAGE_TYPES ) {
|
||||||
DBGC ( image, "IMAGE %p trying type %s\n", image, type->name );
|
if ( ( rc = type->probe ( image ) ) == 0 ) {
|
||||||
rc = image_load_type ( image, type );
|
image->type = type;
|
||||||
if ( image->type == NULL )
|
DBGC ( image, "IMAGE %s is %s\n",
|
||||||
continue;
|
image->name, type->name );
|
||||||
return rc;
|
return 0;
|
||||||
|
}
|
||||||
|
DBGC ( image, "IMAGE %s is not %s: %s\n", image->name,
|
||||||
|
type->name, strerror ( rc ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
DBGC ( image, "IMAGE %p format not recognised\n", image );
|
DBGC ( image, "IMAGE %s format not recognised\n", image->name );
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute loaded image
|
* Execute image
|
||||||
*
|
*
|
||||||
* @v image Loaded image
|
* @v image Executable image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int image_exec ( struct image *image ) {
|
int image_exec ( struct image *image ) {
|
||||||
|
@ -239,18 +200,9 @@ int image_exec ( struct image *image ) {
|
||||||
struct uri *old_cwuri;
|
struct uri *old_cwuri;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Image must be loaded first */
|
/* Check that this image can be executed */
|
||||||
if ( ! ( image->flags & IMAGE_LOADED ) ) {
|
if ( ( rc = image_probe ( image ) ) != 0 )
|
||||||
DBGC ( image, "IMAGE %p could not execute: not loaded\n",
|
return rc;
|
||||||
image );
|
|
||||||
return -ENOTTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert ( image->type != NULL );
|
|
||||||
|
|
||||||
/* Check that image is actually executable */
|
|
||||||
if ( ! image->type->exec )
|
|
||||||
return -ENOEXEC;
|
|
||||||
|
|
||||||
/* Switch current working directory to be that of the image itself */
|
/* Switch current working directory to be that of the image itself */
|
||||||
old_cwuri = uri_get ( cwuri );
|
old_cwuri = uri_get ( cwuri );
|
||||||
|
@ -264,8 +216,8 @@ int image_exec ( struct image *image ) {
|
||||||
|
|
||||||
/* Try executing the image */
|
/* Try executing the image */
|
||||||
if ( ( rc = image->type->exec ( image ) ) != 0 ) {
|
if ( ( rc = image->type->exec ( image ) ) != 0 ) {
|
||||||
DBGC ( image, "IMAGE %p could not execute: %s\n",
|
DBGC ( image, "IMAGE %s could not execute: %s\n",
|
||||||
image, strerror ( rc ) );
|
image->name, strerror ( rc ) );
|
||||||
/* Do not return yet; we still have clean-up to do */
|
/* Do not return yet; we still have clean-up to do */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,8 +235,8 @@ int image_exec ( struct image *image ) {
|
||||||
|
|
||||||
/* Tail-recurse into replacement image, if one exists */
|
/* Tail-recurse into replacement image, if one exists */
|
||||||
if ( replacement ) {
|
if ( replacement ) {
|
||||||
DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
|
DBGC ( image, "IMAGE %s replacing self with IMAGE %s\n",
|
||||||
image, replacement );
|
image->name, replacement->name );
|
||||||
if ( ( rc = image_exec ( replacement ) ) != 0 )
|
if ( ( rc = image_exec ( replacement ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -293,33 +245,75 @@ int image_exec ( struct image *image ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register and autoload an image
|
* Select image for execution
|
||||||
*
|
*
|
||||||
* @v image Image
|
* @v image Executable image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int register_and_autoload_image ( struct image *image ) {
|
int image_select ( struct image *image ) {
|
||||||
|
struct image *tmp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Unselect all other images */
|
||||||
|
for_each_image ( tmp )
|
||||||
|
tmp->flags &= ~IMAGE_SELECTED;
|
||||||
|
|
||||||
|
/* Check that this image can be executed */
|
||||||
|
if ( ( rc = image_probe ( image ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Mark image as selected */
|
||||||
|
image->flags |= IMAGE_SELECTED;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find selected image
|
||||||
|
*
|
||||||
|
* @ret image Executable image, or NULL
|
||||||
|
*/
|
||||||
|
struct image * image_find_selected ( void ) {
|
||||||
|
struct image *image;
|
||||||
|
|
||||||
|
for_each_image ( image ) {
|
||||||
|
if ( image->flags & IMAGE_SELECTED )
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register and select an image
|
||||||
|
*
|
||||||
|
* @v image Executable image
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int register_and_select_image ( struct image *image ) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if ( ( rc = register_image ( image ) ) != 0 )
|
if ( ( rc = register_image ( image ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if ( ( rc = image_autoload ( image ) ) != 0 )
|
if ( ( rc = image_probe ( image ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if ( ( rc = image_select ( image ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register and autoexec an image
|
* Register and boot an image
|
||||||
*
|
*
|
||||||
* @v image Image
|
* @v image Image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int register_and_autoexec_image ( struct image *image ) {
|
int register_and_boot_image ( struct image *image ) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if ( ( rc = register_and_autoload_image ( image ) ) != 0 )
|
if ( ( rc = register_and_select_image ( image ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if ( ( rc = image_exec ( image ) ) != 0 )
|
if ( ( rc = image_exec ( image ) ) != 0 )
|
||||||
|
|
|
@ -86,28 +86,18 @@ static struct command_descriptor imgfetch_cmd =
|
||||||
COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
|
COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
|
||||||
"[--name <name>] <uri> [<arguments>...]" );
|
"[--name <name>] <uri> [<arguments>...]" );
|
||||||
|
|
||||||
/** "kernel" command descriptor */
|
|
||||||
static struct command_descriptor kernel_cmd =
|
|
||||||
COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
|
|
||||||
"[--name <name>] <uri> [<arguments>...]" );
|
|
||||||
|
|
||||||
/** "chain" command descriptor */
|
|
||||||
static struct command_descriptor chain_cmd =
|
|
||||||
COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
|
|
||||||
"[--name <name>] <uri> [<arguments>...]" );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "imgfetch" and friends command body
|
* The "imgfetch" and friends command body
|
||||||
*
|
*
|
||||||
* @v argc Argument count
|
* @v argc Argument count
|
||||||
* @v argv Argument list
|
* @v argv Argument list
|
||||||
* @v cmd Command descriptor
|
* @v cmd Command descriptor
|
||||||
* @v image_register Image registration action
|
* @v action Action to take upon a successful download
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int imgfetch_core_exec ( int argc, char **argv,
|
static int imgfetch_core_exec ( int argc, char **argv,
|
||||||
struct command_descriptor *cmd,
|
struct command_descriptor *cmd,
|
||||||
int ( * image_register ) ( struct image * ) ) {
|
int ( * action ) ( struct image *image ) ) {
|
||||||
struct imgfetch_options opts;
|
struct imgfetch_options opts;
|
||||||
struct image *image;
|
struct image *image;
|
||||||
char *uri_string;
|
char *uri_string;
|
||||||
|
@ -139,7 +129,7 @@ static int imgfetch_core_exec ( int argc, char **argv,
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* Fetch the image */
|
/* Fetch the image */
|
||||||
if ( ( rc = imgfetch ( image, uri_string, image_register ) ) != 0 ) {
|
if ( ( rc = imgfetch ( image, uri_string, action ) ) != 0 ) {
|
||||||
printf ( "Could not fetch %s: %s\n",
|
printf ( "Could not fetch %s: %s\n",
|
||||||
uri_string, strerror ( rc ) );
|
uri_string, strerror ( rc ) );
|
||||||
image_put ( image );
|
image_put ( image );
|
||||||
|
@ -172,8 +162,8 @@ static int imgfetch_exec ( int argc, char **argv ) {
|
||||||
*/
|
*/
|
||||||
static int kernel_exec ( int argc, char **argv ) {
|
static int kernel_exec ( int argc, char **argv ) {
|
||||||
|
|
||||||
return imgfetch_core_exec ( argc, argv, &kernel_cmd,
|
return imgfetch_core_exec ( argc, argv, &imgfetch_cmd,
|
||||||
register_and_autoload_image );
|
register_and_select_image );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -185,34 +175,35 @@ static int kernel_exec ( int argc, char **argv ) {
|
||||||
*/
|
*/
|
||||||
static int chain_exec ( int argc, char **argv) {
|
static int chain_exec ( int argc, char **argv) {
|
||||||
|
|
||||||
return imgfetch_core_exec ( argc, argv, &chain_cmd,
|
return imgfetch_core_exec ( argc, argv, &imgfetch_cmd,
|
||||||
register_and_autoexec_image );
|
register_and_boot_image );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** "imgload" options */
|
/** "imgselect" options */
|
||||||
struct imgload_options {};
|
struct imgselect_options {};
|
||||||
|
|
||||||
/** "imgload" option list */
|
/** "imgselect" option list */
|
||||||
static struct option_descriptor imgload_opts[] = {};
|
static struct option_descriptor imgselect_opts[] = {};
|
||||||
|
|
||||||
/** "imgload" command descriptor */
|
/** "imgselect" command descriptor */
|
||||||
static struct command_descriptor imgload_cmd =
|
static struct command_descriptor imgselect_cmd =
|
||||||
COMMAND_DESC ( struct imgload_options, imgload_opts, 1, 1, "<image>" );
|
COMMAND_DESC ( struct imgselect_options, imgselect_opts, 1, 1,
|
||||||
|
"<image>" );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "imgload" command
|
* The "imgselect" command
|
||||||
*
|
*
|
||||||
* @v argc Argument count
|
* @v argc Argument count
|
||||||
* @v argv Argument list
|
* @v argv Argument list
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int imgload_exec ( int argc, char **argv ) {
|
static int imgselect_exec ( int argc, char **argv ) {
|
||||||
struct imgload_options opts;
|
struct imgselect_options opts;
|
||||||
struct image *image;
|
struct image *image;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Parse options */
|
/* Parse options */
|
||||||
if ( ( rc = parse_options ( argc, argv, &imgload_cmd, &opts ) ) != 0 )
|
if ( ( rc = parse_options ( argc, argv, &imgselect_cmd, &opts ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* Parse image name */
|
/* Parse image name */
|
||||||
|
@ -220,8 +211,8 @@ static int imgload_exec ( int argc, char **argv ) {
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* Load image */
|
/* Load image */
|
||||||
if ( ( rc = imgload ( image ) ) != 0 ) {
|
if ( ( rc = imgselect ( image ) ) != 0 ) {
|
||||||
printf ( "Could not load %s: %s\n",
|
printf ( "Could not select %s: %s\n",
|
||||||
image->name, strerror ( rc ) );
|
image->name, strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -302,8 +293,9 @@ static int imgexec_exec ( int argc, char **argv ) {
|
||||||
} else {
|
} else {
|
||||||
image = imgautoselect();
|
image = imgautoselect();
|
||||||
if ( ! image ) {
|
if ( ! image ) {
|
||||||
printf ( "No (unique) loaded image\n" );
|
rc = -ENOTTY;
|
||||||
return -ENOTTY;
|
printf ( "No image selected: %s\n", strerror ( rc ) );
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,8 +409,12 @@ struct command image_commands[] __command = {
|
||||||
.exec = chain_exec,
|
.exec = chain_exec,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "imgload",
|
.name = "imgselect",
|
||||||
.exec = imgload_exec,
|
.exec = imgselect_exec,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "imgload", /* synonym for "imgselect" */
|
||||||
|
.exec = imgselect_exec,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "imgargs",
|
.name = "imgargs",
|
||||||
|
|
|
@ -26,8 +26,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
|
FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
|
||||||
|
|
||||||
struct image_type efi_image_type __image_type ( PROBE_NORMAL );
|
|
||||||
|
|
||||||
/** Event used to signal shutdown */
|
/** Event used to signal shutdown */
|
||||||
static EFI_EVENT efi_shutdown_event;
|
static EFI_EVENT efi_shutdown_event;
|
||||||
|
|
||||||
|
@ -99,12 +97,12 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load EFI image into memory
|
* Probe EFI image
|
||||||
*
|
*
|
||||||
* @v image EFI file
|
* @v image EFI file
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int efi_image_load ( struct image *image ) {
|
static int efi_image_probe ( struct image *image ) {
|
||||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||||
EFI_HANDLE handle;
|
EFI_HANDLE handle;
|
||||||
EFI_STATUS efirc;
|
EFI_STATUS efirc;
|
||||||
|
@ -119,10 +117,6 @@ static int efi_image_load ( struct image *image ) {
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is an EFI image */
|
|
||||||
if ( ! image->type )
|
|
||||||
image->type = &efi_image_type;
|
|
||||||
|
|
||||||
/* Unload the image. We can't leave it loaded, because we
|
/* Unload the image. We can't leave it loaded, because we
|
||||||
* have no "unload" operation.
|
* have no "unload" operation.
|
||||||
*/
|
*/
|
||||||
|
@ -134,6 +128,6 @@ static int efi_image_load ( struct image *image ) {
|
||||||
/** EFI image type */
|
/** EFI image type */
|
||||||
struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
|
struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
|
||||||
.name = "EFI",
|
.name = "EFI",
|
||||||
.load = efi_image_load,
|
.probe = efi_image_probe,
|
||||||
.exec = efi_image_exec,
|
.exec = efi_image_exec,
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,10 +45,11 @@ typedef Elf32_Off Elf_Off;
|
||||||
* @v image ELF file
|
* @v image ELF file
|
||||||
* @v phdr ELF program header
|
* @v phdr ELF program header
|
||||||
* @v ehdr ELF executable header
|
* @v ehdr ELF executable header
|
||||||
|
* @ret entry Entry point, if found
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
|
static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
|
||||||
Elf_Ehdr *ehdr ) {
|
Elf_Ehdr *ehdr, physaddr_t *entry ) {
|
||||||
physaddr_t dest;
|
physaddr_t dest;
|
||||||
userptr_t buffer;
|
userptr_t buffer;
|
||||||
unsigned long e_offset;
|
unsigned long e_offset;
|
||||||
|
@ -96,15 +97,15 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
|
||||||
|
|
||||||
/* Set execution address, if it lies within this segment */
|
/* Set execution address, if it lies within this segment */
|
||||||
if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
|
if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
|
||||||
image->priv.phys = ehdr->e_entry;
|
*entry = ehdr->e_entry;
|
||||||
DBGC ( image, "ELF %p found physical entry point at %lx\n",
|
DBGC ( image, "ELF %p found physical entry point at %lx\n",
|
||||||
image, image->priv.phys );
|
image, *entry );
|
||||||
} else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) )
|
} else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) )
|
||||||
< phdr->p_filesz ) {
|
< phdr->p_filesz ) {
|
||||||
if ( ! image->priv.phys ) {
|
if ( ! *entry ) {
|
||||||
image->priv.phys = ( dest + e_offset );
|
*entry = ( dest + e_offset );
|
||||||
DBGC ( image, "ELF %p found virtual entry point at %lx"
|
DBGC ( image, "ELF %p found virtual entry point at %lx"
|
||||||
" (virt %lx)\n", image, image->priv.phys,
|
" (virt %lx)\n", image, *entry,
|
||||||
( ( unsigned long ) ehdr->e_entry ) );
|
( ( unsigned long ) ehdr->e_entry ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,18 +117,16 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
|
||||||
* Load ELF image into memory
|
* Load ELF image into memory
|
||||||
*
|
*
|
||||||
* @v image ELF file
|
* @v image ELF file
|
||||||
|
* @ret entry Entry point
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int elf_load ( struct image *image ) {
|
int elf_load ( struct image *image, physaddr_t *entry ) {
|
||||||
Elf_Ehdr ehdr;
|
Elf_Ehdr ehdr;
|
||||||
Elf_Phdr phdr;
|
Elf_Phdr phdr;
|
||||||
Elf_Off phoff;
|
Elf_Off phoff;
|
||||||
unsigned int phnum;
|
unsigned int phnum;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Image type must already have been set by caller */
|
|
||||||
assert ( image->type != NULL );
|
|
||||||
|
|
||||||
/* Read ELF header */
|
/* Read ELF header */
|
||||||
copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
|
copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
|
||||||
if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) {
|
if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) {
|
||||||
|
@ -135,8 +134,8 @@ int elf_load ( struct image *image ) {
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invalidate execution address */
|
/* Invalidate entry point */
|
||||||
image->priv.phys = 0;
|
*entry = 0;
|
||||||
|
|
||||||
/* Read ELF program headers */
|
/* Read ELF program headers */
|
||||||
for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
|
for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
|
||||||
|
@ -147,12 +146,14 @@ int elf_load ( struct image *image ) {
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
|
copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
|
||||||
if ( ( rc = elf_load_segment ( image, &phdr, &ehdr ) ) != 0 )
|
if ( ( rc = elf_load_segment ( image, &phdr, &ehdr,
|
||||||
|
entry ) ) != 0 ) {
|
||||||
return rc;
|
return rc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for a valid execution address */
|
/* Check for a valid execution address */
|
||||||
if ( ! image->priv.phys ) {
|
if ( ! *entry ) {
|
||||||
DBGC ( image, "ELF %p entry point %lx outside image\n",
|
DBGC ( image, "ELF %p entry point %lx outside image\n",
|
||||||
image, ( ( unsigned long ) ehdr.e_entry ) );
|
image, ( ( unsigned long ) ehdr.e_entry ) );
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
|
|
|
@ -76,10 +76,10 @@ static void embedded_init ( void ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load the first image */
|
/* Select the first image */
|
||||||
image = &embedded_images[0];
|
image = &embedded_images[0];
|
||||||
if ( ( rc = image_autoload ( image ) ) != 0 ) {
|
if ( ( rc = image_select ( image ) ) != 0 ) {
|
||||||
DBG ( "Could not load embedded image \"%s\": %s\n",
|
DBG ( "Could not select embedded image \"%s\": %s\n",
|
||||||
image->name, strerror ( rc ) );
|
image->name, strerror ( rc ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
#include <ipxe/image.h>
|
#include <ipxe/image.h>
|
||||||
#include <ipxe/shell.h>
|
#include <ipxe/shell.h>
|
||||||
|
|
||||||
struct image_type script_image_type __image_type ( PROBE_NORMAL );
|
|
||||||
|
|
||||||
/** Currently running script
|
/** Currently running script
|
||||||
*
|
*
|
||||||
* This is a global in order to allow goto_exec() to update the
|
* This is a global in order to allow goto_exec() to update the
|
||||||
|
@ -165,12 +163,12 @@ static int script_exec ( struct image *image ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load script into memory
|
* Probe script image
|
||||||
*
|
*
|
||||||
* @v image Script
|
* @v image Script
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int script_load ( struct image *image ) {
|
static int script_probe ( struct image *image ) {
|
||||||
static const char ipxe_magic[] = "#!ipxe";
|
static const char ipxe_magic[] = "#!ipxe";
|
||||||
static const char gpxe_magic[] = "#!gpxe";
|
static const char gpxe_magic[] = "#!gpxe";
|
||||||
linker_assert ( sizeof ( ipxe_magic ) == sizeof ( gpxe_magic ),
|
linker_assert ( sizeof ( ipxe_magic ) == sizeof ( gpxe_magic ),
|
||||||
|
@ -193,20 +191,13 @@ static int script_load ( struct image *image ) {
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is a script */
|
|
||||||
image->type = &script_image_type;
|
|
||||||
|
|
||||||
/* We don't actually load it anywhere; we will pick the lines
|
|
||||||
* out of the image as we need them.
|
|
||||||
*/
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Script image type */
|
/** Script image type */
|
||||||
struct image_type script_image_type __image_type ( PROBE_NORMAL ) = {
|
struct image_type script_image_type __image_type ( PROBE_NORMAL ) = {
|
||||||
.name = "script",
|
.name = "script",
|
||||||
.load = script_load,
|
.probe = script_probe,
|
||||||
.exec = script_exec,
|
.exec = script_exec,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
|
|
||||||
extern int elf_load ( struct image *image );
|
extern int elf_load ( struct image *image, physaddr_t *entry );
|
||||||
|
|
||||||
#endif /* _IPXE_ELF_H */
|
#endif /* _IPXE_ELF_H */
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
/**
|
/**
|
||||||
* @file
|
* @file
|
||||||
*
|
*
|
||||||
* Executable/loadable images
|
* Executable images
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
struct uri;
|
struct uri;
|
||||||
struct image_type;
|
struct image_type;
|
||||||
|
|
||||||
/** An executable or loadable image */
|
/** An executable image */
|
||||||
struct image {
|
struct image {
|
||||||
/** Reference count */
|
/** Reference count */
|
||||||
struct refcnt refcnt;
|
struct refcnt refcnt;
|
||||||
|
@ -42,20 +42,13 @@ struct image {
|
||||||
|
|
||||||
/** Image type, if known */
|
/** Image type, if known */
|
||||||
struct image_type *type;
|
struct image_type *type;
|
||||||
/** Image type private data */
|
|
||||||
union {
|
|
||||||
physaddr_t phys;
|
|
||||||
userptr_t user;
|
|
||||||
unsigned long ul;
|
|
||||||
} priv;
|
|
||||||
|
|
||||||
/** Replacement image
|
/** Replacement image
|
||||||
*
|
*
|
||||||
* An image wishing to replace itself with another image (in a
|
* An image wishing to replace itself with another image (in a
|
||||||
* style similar to a Unix exec() call) should return from its
|
* style similar to a Unix exec() call) should return from its
|
||||||
* exec() method with the replacement image set to point to
|
* exec() method with the replacement image set to point to
|
||||||
* the new image. The new image must already be in a suitable
|
* the new image.
|
||||||
* state for execution (i.e. loaded).
|
|
||||||
*
|
*
|
||||||
* If an image unregisters itself as a result of being
|
* If an image unregisters itself as a result of being
|
||||||
* executed, it must make sure that its replacement image (if
|
* executed, it must make sure that its replacement image (if
|
||||||
|
@ -65,41 +58,26 @@ struct image {
|
||||||
struct image *replacement;
|
struct image *replacement;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Image is loaded */
|
/** Image is selected for execution */
|
||||||
#define IMAGE_LOADED 0x0001
|
#define IMAGE_SELECTED 0x0001
|
||||||
|
|
||||||
/** An executable or loadable image type */
|
/** An executable image type */
|
||||||
struct image_type {
|
struct image_type {
|
||||||
/** Name of this image type */
|
/** Name of this image type */
|
||||||
char *name;
|
char *name;
|
||||||
/**
|
/** Probe image
|
||||||
* Load image into memory
|
|
||||||
*
|
*
|
||||||
* @v image Executable/loadable image
|
* @v image Executable image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*
|
*
|
||||||
* Load the image into memory at the correct location as
|
* Return success if the image is of this image type.
|
||||||
* determined by the file format.
|
|
||||||
*
|
|
||||||
* If the file image is in the correct format, the method must
|
|
||||||
* update @c image->type to point to its own type (unless @c
|
|
||||||
* image->type is already set). This allows the autoloading
|
|
||||||
* code to disambiguate between "this is not my image format"
|
|
||||||
* and "there is something wrong with this image". In
|
|
||||||
* particular, setting @c image->type and then returning an
|
|
||||||
* error will cause image_autoload() to abort and return an
|
|
||||||
* error, rather than continuing to the next image type.
|
|
||||||
*/
|
*/
|
||||||
int ( * load ) ( struct image *image );
|
int ( * probe ) ( struct image *image );
|
||||||
/**
|
/**
|
||||||
* Execute loaded image
|
* Execute image
|
||||||
*
|
*
|
||||||
* @v image Loaded image
|
* @v image Executable image
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*
|
|
||||||
* Note that the image may be invalidated by the act of
|
|
||||||
* execution, i.e. an image is allowed to choose to unregister
|
|
||||||
* (and so potentially free) itself.
|
|
||||||
*/
|
*/
|
||||||
int ( * exec ) ( struct image *image );
|
int ( * exec ) ( struct image *image );
|
||||||
};
|
};
|
||||||
|
@ -125,10 +103,10 @@ struct image_type {
|
||||||
*/
|
*/
|
||||||
#define PROBE_PXE 03
|
#define PROBE_PXE 03
|
||||||
|
|
||||||
/** Executable or loadable image type table */
|
/** Executable image type table */
|
||||||
#define IMAGE_TYPES __table ( struct image_type, "image_types" )
|
#define IMAGE_TYPES __table ( struct image_type, "image_types" )
|
||||||
|
|
||||||
/** An executable or loadable image type */
|
/** An executable image type */
|
||||||
#define __image_type( probe_order ) __table_entry ( IMAGE_TYPES, probe_order )
|
#define __image_type( probe_order ) __table_entry ( IMAGE_TYPES, probe_order )
|
||||||
|
|
||||||
extern struct list_head images;
|
extern struct list_head images;
|
||||||
|
@ -147,17 +125,17 @@ static inline int have_images ( void ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct image * alloc_image ( void );
|
extern struct image * alloc_image ( void );
|
||||||
extern int image_set_uri ( struct image *image, struct uri *uri );
|
extern void image_set_uri ( struct image *image, struct uri *uri );
|
||||||
extern int image_set_cmdline ( struct image *image, const char *cmdline );
|
extern int image_set_cmdline ( struct image *image, const char *cmdline );
|
||||||
extern int register_image ( struct image *image );
|
extern int register_image ( struct image *image );
|
||||||
extern void unregister_image ( struct image *image );
|
extern void unregister_image ( struct image *image );
|
||||||
extern void promote_image ( struct image *image );
|
|
||||||
struct image * find_image ( const char *name );
|
struct image * find_image ( const char *name );
|
||||||
extern int image_load ( struct image *image );
|
extern int image_probe ( struct image *image );
|
||||||
extern int image_autoload ( struct image *image );
|
|
||||||
extern int image_exec ( struct image *image );
|
extern int image_exec ( struct image *image );
|
||||||
extern int register_and_autoload_image ( struct image *image );
|
extern int image_select ( struct image *image );
|
||||||
extern int register_and_autoexec_image ( struct image *image );
|
extern struct image * image_find_selected ( void );
|
||||||
|
extern int register_and_select_image ( struct image *image );
|
||||||
|
extern int register_and_boot_image ( struct image *image );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment reference count on an image
|
* Increment reference count on an image
|
||||||
|
|
|
@ -9,16 +9,42 @@
|
||||||
|
|
||||||
FILE_LICENCE ( GPL2_OR_LATER );
|
FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
struct image;
|
#include <ipxe/image.h>
|
||||||
|
|
||||||
extern int imgdownload ( struct image *image, struct uri *uri,
|
extern int imgdownload ( struct image *image, struct uri *uri,
|
||||||
int ( * action ) ( struct image *image ) );
|
int ( * action ) ( struct image *image ) );
|
||||||
extern int imgfetch ( struct image *image, const char *uri_string,
|
extern int imgfetch ( struct image *image, const char *uri_string,
|
||||||
int ( * action ) ( struct image *image ) );
|
int ( * action ) ( struct image *image ) );
|
||||||
extern int imgload ( struct image *image );
|
|
||||||
extern int imgexec ( struct image *image );
|
|
||||||
extern struct image * imgautoselect ( void );
|
|
||||||
extern void imgstat ( struct image *image );
|
extern void imgstat ( struct image *image );
|
||||||
extern void imgfree ( struct image *image );
|
extern void imgfree ( struct image *image );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select an image for execution
|
||||||
|
*
|
||||||
|
* @v image Image
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static inline int imgselect ( struct image *image ) {
|
||||||
|
return image_select ( image );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the previously-selected image
|
||||||
|
*
|
||||||
|
* @ret image Image, or NULL
|
||||||
|
*/
|
||||||
|
static inline struct image * imgautoselect ( void ) {
|
||||||
|
return image_find_selected();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute an image
|
||||||
|
*
|
||||||
|
* @v image Image
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static inline int imgexec ( struct image *image ) {
|
||||||
|
return image_exec ( image );
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _USR_IMGMGMT_H */
|
#endif /* _USR_IMGMGMT_H */
|
||||||
|
|
|
@ -184,7 +184,7 @@ int uriboot ( struct uri *filename, struct uri *root_path ) {
|
||||||
/* Attempt filename boot if applicable */
|
/* Attempt filename boot if applicable */
|
||||||
if ( filename ) {
|
if ( filename ) {
|
||||||
if ( ( rc = imgdownload ( image, filename,
|
if ( ( rc = imgdownload ( image, filename,
|
||||||
register_and_autoexec_image ) ) !=0){
|
register_and_boot_image ) ) != 0 ) {
|
||||||
printf ( "\nCould not chain image: %s\n",
|
printf ( "\nCould not chain image: %s\n",
|
||||||
strerror ( rc ) );
|
strerror ( rc ) );
|
||||||
/* Fall through to (possibly) attempt a SAN boot
|
/* Fall through to (possibly) attempt a SAN boot
|
||||||
|
|
|
@ -99,63 +99,17 @@ int imgfetch ( struct image *image, const char *uri_string,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load an image
|
|
||||||
*
|
|
||||||
* @v image Image
|
|
||||||
* @ret rc Return status code
|
|
||||||
*/
|
|
||||||
int imgload ( struct image *image ) {
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* Try to load image */
|
|
||||||
if ( ( rc = image_autoload ( image ) ) != 0 )
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute an image
|
|
||||||
*
|
|
||||||
* @v image Image
|
|
||||||
* @ret rc Return status code
|
|
||||||
*/
|
|
||||||
int imgexec ( struct image *image ) {
|
|
||||||
return image_exec ( image );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Identify the only loaded image
|
|
||||||
*
|
|
||||||
* @ret image Image, or NULL if 0 or >1 images are loaded
|
|
||||||
*/
|
|
||||||
struct image * imgautoselect ( void ) {
|
|
||||||
struct image *image;
|
|
||||||
struct image *selected_image = NULL;
|
|
||||||
int flagged_images = 0;
|
|
||||||
|
|
||||||
for_each_image ( image ) {
|
|
||||||
if ( image->flags & IMAGE_LOADED ) {
|
|
||||||
selected_image = image;
|
|
||||||
flagged_images++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ( ( flagged_images == 1 ) ? selected_image : NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display status of an image
|
* Display status of an image
|
||||||
*
|
*
|
||||||
* @v image Executable/loadable image
|
* @v image Executable/loadable image
|
||||||
*/
|
*/
|
||||||
void imgstat ( struct image *image ) {
|
void imgstat ( struct image *image ) {
|
||||||
printf ( "%s: %zd bytes", image->name, image->len );
|
printf ( "%s : %zd bytes", image->name, image->len );
|
||||||
if ( image->type )
|
if ( image->type )
|
||||||
printf ( " [%s]", image->type->name );
|
printf ( " [%s]", image->type->name );
|
||||||
if ( image->flags & IMAGE_LOADED )
|
if ( image->flags & IMAGE_SELECTED )
|
||||||
printf ( " [LOADED]" );
|
printf ( " [SELECTED]" );
|
||||||
if ( image->cmdline )
|
if ( image->cmdline )
|
||||||
printf ( " \"%s\"", image->cmdline );
|
printf ( " \"%s\"", image->cmdline );
|
||||||
printf ( "\n" );
|
printf ( "\n" );
|
||||||
|
|
Loading…
Reference in New Issue