mirror of
https://github.com/ipxe/ipxe
synced 2025-12-25 00:17:57 +03:00
[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>
This commit is contained in:
@@ -41,8 +41,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "bzImage", DHCP_EB_FEATURE_BZIMAGE, 1 );
|
||||
|
||||
struct image_type bzimage_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
/**
|
||||
* bzImage context
|
||||
*/
|
||||
@@ -111,8 +109,8 @@ static int bzimage_parse_header ( struct image *image,
|
||||
sizeof ( bzimg->bzhdr ) );
|
||||
|
||||
/* Calculate size of real-mode portion */
|
||||
bzimg->rm_filesz =
|
||||
( ( bzimg->bzhdr.setup_sects ? bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9;
|
||||
bzimg->rm_filesz = ( ( ( bzimg->bzhdr.setup_sects ?
|
||||
bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9 );
|
||||
if ( bzimg->rm_filesz > image->len ) {
|
||||
DBGC ( image, "bzImage %p too short for %zd byte of setup\n",
|
||||
image, bzimg->rm_filesz );
|
||||
@@ -455,11 +453,33 @@ static int bzimage_exec ( struct image *image ) {
|
||||
const char *cmdline = ( image->cmdline ? image->cmdline : "" );
|
||||
int rc;
|
||||
|
||||
/* Read and parse header from loaded kernel */
|
||||
/* Read and parse header from image */
|
||||
if ( ( rc = bzimage_parse_header ( image, &bzimg,
|
||||
image->priv.user ) ) != 0 )
|
||||
image->data ) ) != 0 )
|
||||
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 */
|
||||
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
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int bzimage_load ( struct image *image ) {
|
||||
int bzimage_probe ( struct image *image ) {
|
||||
struct bzimage_context bzimg;
|
||||
int rc;
|
||||
|
||||
@@ -520,42 +540,12 @@ int bzimage_load ( struct image *image ) {
|
||||
image->data ) ) != 0 )
|
||||
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;
|
||||
}
|
||||
|
||||
/** Linux bzImage image type */
|
||||
struct image_type bzimage_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "bzImage",
|
||||
.load = bzimage_load,
|
||||
.probe = bzimage_probe,
|
||||
.exec = bzimage_exec,
|
||||
};
|
||||
|
||||
@@ -40,8 +40,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/io.h>
|
||||
|
||||
struct image_type com32_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
struct idt_register com32_external_idtr = {
|
||||
.limit = COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) - 1,
|
||||
.base = COM32_IDT
|
||||
@@ -55,7 +53,7 @@ struct idt_register com32_internal_idtr;
|
||||
* @v image COM32 image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int com32_exec ( struct image *image ) {
|
||||
static int com32_exec_loop ( struct image *image ) {
|
||||
struct memory_map memmap;
|
||||
unsigned int i;
|
||||
int state;
|
||||
@@ -137,7 +135,6 @@ static int com32_exec ( struct image *image ) {
|
||||
image, comboot_replacement_image );
|
||||
image->replacement = comboot_replacement_image;
|
||||
comboot_replacement_image = NULL;
|
||||
image_autoload ( image->replacement );
|
||||
break;
|
||||
|
||||
case COMBOOT_EXIT_COMMAND:
|
||||
@@ -207,7 +204,7 @@ static int com32_identify ( struct image *image ) {
|
||||
* @v image COM32 image
|
||||
* @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;
|
||||
struct idt_descriptor *idt;
|
||||
struct ijb_entry *ijb;
|
||||
@@ -262,7 +259,7 @@ static int comboot_load_image ( struct image *image ) {
|
||||
* @v image COM32 image
|
||||
* @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;
|
||||
userptr_t seg_userptr;
|
||||
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
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int com32_load ( struct image *image ) {
|
||||
static int com32_probe ( struct image *image ) {
|
||||
int rc;
|
||||
|
||||
DBGC ( image, "COM32 %p: name '%s', cmdline '%s'\n",
|
||||
@@ -302,26 +299,34 @@ static int com32_load ( struct image *image ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* This is a COM32 image, valid or otherwise */
|
||||
if ( ! image->type )
|
||||
image->type = &com32_image_type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute COMBOOT image
|
||||
*
|
||||
* @v image COM32 image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int com32_exec ( struct image *image ) {
|
||||
int rc;
|
||||
|
||||
/* Load image */
|
||||
if ( ( rc = comboot_load_image ( image ) ) != 0 ) {
|
||||
if ( ( rc = com32_load_image ( image ) ) != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Prepare bounce buffer segment */
|
||||
if ( ( rc = comboot_prepare_bounce_buffer ( image ) ) != 0 ) {
|
||||
if ( ( rc = com32_prepare_bounce_buffer ( image ) ) != 0 ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return com32_exec_loop ( image );
|
||||
}
|
||||
|
||||
/** SYSLINUX COM32 image type */
|
||||
struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "COM32",
|
||||
.load = com32_load,
|
||||
.probe = com32_probe,
|
||||
.exec = com32_exec,
|
||||
};
|
||||
|
||||
@@ -42,8 +42,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
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
|
||||
*/
|
||||
@@ -131,7 +129,7 @@ static void comboot_init_psp ( struct image * image, userptr_t seg_userptr ) {
|
||||
* @v image COMBOOT image
|
||||
* @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 );
|
||||
int state;
|
||||
|
||||
@@ -194,7 +192,6 @@ static int comboot_exec ( struct image *image ) {
|
||||
image, comboot_replacement_image );
|
||||
image->replacement = comboot_replacement_image;
|
||||
comboot_replacement_image = NULL;
|
||||
image_autoload ( image->replacement );
|
||||
break;
|
||||
|
||||
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
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int comboot_load ( struct image *image ) {
|
||||
static int comboot_probe ( struct image *image ) {
|
||||
int rc;
|
||||
|
||||
DBGC ( image, "COMBOOT %p: name '%s'\n",
|
||||
@@ -295,9 +292,17 @@ static int comboot_load ( struct image *image ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* This is a 16-bit COMBOOT image, valid or otherwise */
|
||||
if ( ! image->type )
|
||||
image->type = &comboot_image_type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
if( image->len >= 0xFF00 ) {
|
||||
@@ -311,12 +316,12 @@ static int comboot_load ( struct image *image ) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return comboot_exec_loop ( image );
|
||||
}
|
||||
|
||||
/** SYSLINUX COMBOOT (16-bit) image type */
|
||||
struct image_type comboot_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "COMBOOT",
|
||||
.load = comboot_load,
|
||||
.probe = comboot_probe,
|
||||
.exec = comboot_exec,
|
||||
};
|
||||
|
||||
@@ -34,8 +34,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 );
|
||||
|
||||
struct image_type elfboot_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
/**
|
||||
* Execute ELF image
|
||||
*
|
||||
@@ -43,7 +41,15 @@ struct image_type elfboot_image_type __image_type ( PROBE_NORMAL );
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
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
|
||||
* 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
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int elfboot_load ( struct image *image ) {
|
||||
static int elfboot_probe ( struct image *image ) {
|
||||
Elf32_Ehdr ehdr;
|
||||
static const uint8_t e_ident[] = {
|
||||
[EI_MAG0] = ELFMAG0,
|
||||
@@ -82,7 +88,6 @@ static int elfboot_load ( struct image *image ) {
|
||||
[EI_DATA] = ELFDATA2LSB,
|
||||
[EI_VERSION] = EV_CURRENT,
|
||||
};
|
||||
int rc;
|
||||
|
||||
/* Read ELF header */
|
||||
copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
|
||||
@@ -91,23 +96,12 @@ static int elfboot_load ( struct image *image ) {
|
||||
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;
|
||||
}
|
||||
|
||||
/** ELF image type */
|
||||
struct image_type elfboot_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "ELF",
|
||||
.load = elfboot_load,
|
||||
.probe = elfboot_probe,
|
||||
.exec = elfboot_exec,
|
||||
};
|
||||
|
||||
@@ -40,8 +40,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
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
|
||||
*
|
||||
@@ -254,57 +252,6 @@ static struct multiboot_memory_map
|
||||
static struct multiboot_module __bss16_array ( mbmodules, [MAX_MODULES] );
|
||||
#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
|
||||
*
|
||||
@@ -357,10 +304,12 @@ static int multiboot_find_header ( struct image *image,
|
||||
*
|
||||
* @v image Multiboot file
|
||||
* @v hdr Multiboot header descriptor
|
||||
* @ret entry Entry point
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
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 filesz;
|
||||
size_t memsz;
|
||||
@@ -391,8 +340,8 @@ static int multiboot_load_raw ( struct image *image,
|
||||
/* Copy image to segment */
|
||||
memcpy_user ( buffer, 0, image->data, offset, filesz );
|
||||
|
||||
/* Record execution entry point in image private data field */
|
||||
image->priv.phys = hdr->mb.entry_addr;
|
||||
/* Record execution entry point */
|
||||
*entry = hdr->mb.entry_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -401,13 +350,14 @@ static int multiboot_load_raw ( struct image *image,
|
||||
* Load ELF multiboot image into memory
|
||||
*
|
||||
* @v image Multiboot file
|
||||
* @ret entry Entry point
|
||||
* @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;
|
||||
|
||||
/* 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",
|
||||
image, strerror ( 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
|
||||
*/
|
||||
static int multiboot_load ( struct image *image ) {
|
||||
static int multiboot_exec ( struct image *image ) {
|
||||
struct multiboot_header_info hdr;
|
||||
physaddr_t entry;
|
||||
int rc;
|
||||
|
||||
/* Locate multiboot header, if present */
|
||||
@@ -432,12 +383,6 @@ static int multiboot_load ( struct image *image ) {
|
||||
image );
|
||||
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 */
|
||||
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
|
||||
* behaviour.
|
||||
*/
|
||||
if ( ( ( rc = multiboot_load_elf ( image ) ) != 0 ) &&
|
||||
( ( rc = multiboot_load_raw ( image, &hdr ) ) != 0 ) )
|
||||
if ( ( ( rc = multiboot_load_elf ( image, &entry ) ) != 0 ) &&
|
||||
( ( rc = multiboot_load_raw ( image, &hdr, &entry ) ) != 0 ) )
|
||||
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;
|
||||
}
|
||||
|
||||
/** Multiboot image type */
|
||||
struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT ) = {
|
||||
.name = "Multiboot",
|
||||
.load = multiboot_load,
|
||||
.probe = multiboot_probe,
|
||||
.exec = multiboot_exec,
|
||||
};
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "NBI", DHCP_EB_FEATURE_NBI, 1 );
|
||||
|
||||
struct image_type nbi_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
/**
|
||||
* An NBI image header
|
||||
*
|
||||
@@ -240,57 +238,6 @@ static int nbi_process_segments ( struct image *image,
|
||||
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
|
||||
*
|
||||
@@ -396,8 +343,25 @@ static int nbi_exec ( struct image *image ) {
|
||||
int may_return;
|
||||
int rc;
|
||||
|
||||
copy_from_user ( &imgheader, image->priv.user, 0,
|
||||
sizeof ( imgheader ) );
|
||||
/* Retrieve image header */
|
||||
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 */
|
||||
if ( ( rc = nbi_prepare_dhcp ( image ) ) != 0 )
|
||||
@@ -427,9 +391,34 @@ static int nbi_exec ( struct image *image ) {
|
||||
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 */
|
||||
struct image_type nbi_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "NBI",
|
||||
.load = nbi_load,
|
||||
.probe = nbi_probe,
|
||||
.exec = nbi_exec,
|
||||
};
|
||||
|
||||
@@ -35,8 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
|
||||
|
||||
struct image_type pxe_image_type __image_type ( PROBE_PXE );
|
||||
|
||||
/**
|
||||
* Execute PXE image
|
||||
*
|
||||
@@ -44,9 +42,20 @@ struct image_type pxe_image_type __image_type ( PROBE_PXE );
|
||||
* @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",
|
||||
@@ -67,51 +76,33 @@ static int pxe_exec ( struct image *image ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load PXE image into memory
|
||||
* Probe PXE image
|
||||
*
|
||||
* @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;
|
||||
int pxe_probe ( struct image *image ) {
|
||||
|
||||
/* 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 ) )
|
||||
if ( image->len > ( 0xa0000 - 0x7c00 ) )
|
||||
return -ENOEXEC;
|
||||
|
||||
/* Rejecting zero-length images is also useful, since these
|
||||
* end up looking to the user like bugs in iPXE.
|
||||
*/
|
||||
if ( ! filesz )
|
||||
if ( ! image->len )
|
||||
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;
|
||||
}
|
||||
|
||||
/** PXE image type */
|
||||
struct image_type pxe_image_type __image_type ( PROBE_PXE ) = {
|
||||
.name = "PXE",
|
||||
.load = pxe_load,
|
||||
.probe = pxe_probe,
|
||||
.exec = pxe_exec,
|
||||
};
|
||||
|
||||
@@ -217,7 +217,7 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
|
||||
goto out;
|
||||
}
|
||||
if ( ( rc = imgfetch ( kernel, kernel_file,
|
||||
register_image ) ) != 0 ) {
|
||||
register_and_select_image ) ) != 0 ) {
|
||||
DBG ( "COMBOOT: could not fetch kernel: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto out;
|
||||
|
||||
Reference in New Issue
Block a user