diff options
Diffstat (limited to 'src/arch')
| -rw-r--r-- | src/arch/i386/image/bzimage.c | 70 | ||||
| -rw-r--r-- | src/arch/i386/image/com32.c | 35 | ||||
| -rw-r--r-- | src/arch/i386/image/comboot.c | 27 | ||||
| -rw-r--r-- | src/arch/i386/image/elfboot.c | 30 | ||||
| -rw-r--r-- | src/arch/i386/image/multiboot.c | 146 | ||||
| -rw-r--r-- | src/arch/i386/image/nbi.c | 101 | ||||
| -rw-r--r-- | src/arch/i386/image/pxe_image.c | 41 | ||||
| -rw-r--r-- | src/arch/i386/interface/syslinux/comboot_call.c | 2 |
8 files changed, 216 insertions, 236 deletions
diff --git a/src/arch/i386/image/bzimage.c b/src/arch/i386/image/bzimage.c index 45a1e8620..cc7aecab4 100644 --- a/src/arch/i386/image/bzimage.c +++ b/src/arch/i386/image/bzimage.c @@ -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; + + /* 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; - assert ( bzimg.rm_kernel == image->priv.user ); + } + + /* 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, }; diff --git a/src/arch/i386/image/com32.c b/src/arch/i386/image/com32.c index 72e679f16..4d8ce4c45 100644 --- a/src/arch/i386/image/com32.c +++ b/src/arch/i386/image/com32.c @@ -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, }; diff --git a/src/arch/i386/image/comboot.c b/src/arch/i386/image/comboot.c index 253cbb696..26bb1139a 100644 --- a/src/arch/i386/image/comboot.c +++ b/src/arch/i386/image/comboot.c @@ -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, }; diff --git a/src/arch/i386/image/elfboot.c b/src/arch/i386/image/elfboot.c index 331d3764c..89e70a3b8 100644 --- a/src/arch/i386/image/elfboot.c +++ b/src/arch/i386/image/elfboot.c @@ -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, }; diff --git a/src/arch/i386/image/multiboot.c b/src/arch/i386/image/multiboot.c index 3ed4d8407..15e8fd52b 100644 --- a/src/arch/i386/image/multiboot.c +++ b/src/arch/i386/image/multiboot.c @@ -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 * @@ -255,57 +253,6 @@ 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 * * @v image Multiboot file @@ -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, }; diff --git a/src/arch/i386/image/nbi.c b/src/arch/i386/image/nbi.c index 804b23037..c516bb2ec 100644 --- a/src/arch/i386/image/nbi.c +++ b/src/arch/i386/image/nbi.c @@ -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 * @@ -241,57 +239,6 @@ static int nbi_process_segments ( struct image *image, } /** - * 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 * * @v imgheader Image header information @@ -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, }; diff --git a/src/arch/i386/image/pxe_image.c b/src/arch/i386/image/pxe_image.c index ef776d9a2..bdccc93d6 100644 --- a/src/arch/i386/image/pxe_image.c +++ b/src/arch/i386/image/pxe_image.c @@ -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, }; diff --git a/src/arch/i386/interface/syslinux/comboot_call.c b/src/arch/i386/interface/syslinux/comboot_call.c index 950832702..1dbc830fd 100644 --- a/src/arch/i386/interface/syslinux/comboot_call.c +++ b/src/arch/i386/interface/syslinux/comboot_call.c @@ -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; |
