diff options
Diffstat (limited to 'src/arch/x86/image')
| -rw-r--r-- | src/arch/x86/image/bzimage.c | 360 | ||||
| -rw-r--r-- | src/arch/x86/image/com32.c | 90 | ||||
| -rw-r--r-- | src/arch/x86/image/comboot.c | 93 | ||||
| -rw-r--r-- | src/arch/x86/image/elfboot.c | 35 | ||||
| -rw-r--r-- | src/arch/x86/image/initrd.c | 306 | ||||
| -rw-r--r-- | src/arch/x86/image/multiboot.c | 234 | ||||
| -rw-r--r-- | src/arch/x86/image/nbi.c | 117 | ||||
| -rw-r--r-- | src/arch/x86/image/pxe_image.c | 26 | ||||
| -rw-r--r-- | src/arch/x86/image/sdi.c | 75 | ||||
| -rw-r--r-- | src/arch/x86/image/ucode.c | 231 |
10 files changed, 561 insertions, 1006 deletions
diff --git a/src/arch/x86/image/bzimage.c b/src/arch/x86/image/bzimage.c index 2c776147d..16a47fc57 100644 --- a/src/arch/x86/image/bzimage.c +++ b/src/arch/x86/image/bzimage.c @@ -32,12 +32,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdint.h> #include <stdlib.h> +#include <stdio.h> #include <string.h> #include <errno.h> #include <assert.h> #include <realmode.h> #include <bzimage.h> -#include <initrd.h> +#include <ipxe/initrd.h> #include <ipxe/uaccess.h> #include <ipxe/image.h> #include <ipxe/segment.h> @@ -56,7 +57,7 @@ struct bzimage_context { /** Real-mode kernel portion load segment address */ unsigned int rm_kernel_seg; /** Real-mode kernel portion load address */ - userptr_t rm_kernel; + void *rm_kernel; /** Real-mode kernel portion file size */ size_t rm_filesz; /** Real-mode heap top (offset from rm_kernel) */ @@ -68,7 +69,7 @@ struct bzimage_context { /** Real-mode kernel portion total memory size */ size_t rm_memsz; /** Non-real-mode kernel portion load address */ - userptr_t pm_kernel; + void *pm_kernel; /** Non-real-mode kernel portion file and memory size */ size_t pm_sz; /** Video mode */ @@ -76,14 +77,9 @@ struct bzimage_context { /** Memory limit */ uint64_t mem_limit; /** Initrd address */ - physaddr_t ramdisk_image; + void *initrd; /** Initrd size */ - physaddr_t ramdisk_size; - - /** Command line magic block */ - struct bzimage_cmdline cmdline_magic; - /** bzImage header */ - struct bzimage_header bzhdr; + physaddr_t initrd_size; }; /** @@ -91,35 +87,31 @@ struct bzimage_context { * * @v image bzImage file * @v bzimg bzImage context - * @v src bzImage to parse * @ret rc Return status code */ static int bzimage_parse_header ( struct image *image, - struct bzimage_context *bzimg, - userptr_t src ) { + struct bzimage_context *bzimg ) { + const struct bzimage_header *bzhdr; unsigned int syssize; int is_bzimage; + /* Initialise context */ + memset ( bzimg, 0, sizeof ( *bzimg ) ); + /* Sanity check */ - if ( image->len < ( BZI_HDR_OFFSET + sizeof ( bzimg->bzhdr ) ) ) { - DBGC ( image, "bzImage %p too short for kernel header\n", - image ); + if ( image->len < ( BZI_HDR_OFFSET + sizeof ( *bzhdr ) ) ) { + DBGC ( image, "bzImage %s too short for kernel header\n", + image->name ); return -ENOEXEC; } - - /* Read in header structures */ - memset ( bzimg, 0, sizeof ( *bzimg ) ); - copy_from_user ( &bzimg->cmdline_magic, src, BZI_CMDLINE_OFFSET, - sizeof ( bzimg->cmdline_magic ) ); - copy_from_user ( &bzimg->bzhdr, src, BZI_HDR_OFFSET, - sizeof ( bzimg->bzhdr ) ); + bzhdr = ( image->data + BZI_HDR_OFFSET ); /* Calculate size of real-mode portion */ - bzimg->rm_filesz = ( ( ( bzimg->bzhdr.setup_sects ? - bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9 ); + bzimg->rm_filesz = ( ( ( bzhdr->setup_sects ? + 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 ); + DBGC ( image, "bzImage %s too short for %zd byte of setup\n", + image->name, bzimg->rm_filesz ); return -ENOEXEC; } bzimg->rm_memsz = BZI_ASSUMED_RM_SIZE; @@ -129,13 +121,14 @@ static int bzimage_parse_header ( struct image *image, syssize = ( ( bzimg->pm_sz + 15 ) / 16 ); /* Check for signatures and determine version */ - if ( bzimg->bzhdr.boot_flag != BZI_BOOT_FLAG ) { - DBGC ( image, "bzImage %p missing 55AA signature\n", image ); + if ( bzhdr->boot_flag != BZI_BOOT_FLAG ) { + DBGC ( image, "bzImage %s missing 55AA signature\n", + image->name ); return -ENOEXEC; } - if ( bzimg->bzhdr.header == BZI_SIGNATURE ) { + if ( bzhdr->header == BZI_SIGNATURE ) { /* 2.00+ */ - bzimg->version = bzimg->bzhdr.version; + bzimg->version = bzhdr->version; } else { /* Pre-2.00. Check that the syssize field is correct, * as a guard against accepting arbitrary binary data, @@ -145,20 +138,21 @@ static int bzimage_parse_header ( struct image *image, * check this field. */ bzimg->version = 0x0100; - if ( bzimg->bzhdr.syssize != syssize ) { - DBGC ( image, "bzImage %p bad syssize %x (expected " - "%x)\n", image, bzimg->bzhdr.syssize, syssize ); + if ( bzhdr->syssize != syssize ) { + DBGC ( image, "bzImage %s bad syssize %x (expected " + "%x)\n", image->name, bzhdr->syssize, + syssize ); return -ENOEXEC; } } /* Determine image type */ is_bzimage = ( ( bzimg->version >= 0x0200 ) ? - ( bzimg->bzhdr.loadflags & BZI_LOAD_HIGH ) : 0 ); + ( bzhdr->loadflags & BZI_LOAD_HIGH ) : 0 ); /* Calculate load address of real-mode portion */ bzimg->rm_kernel_seg = ( is_bzimage ? 0x1000 : 0x9000 ); - bzimg->rm_kernel = real_to_user ( bzimg->rm_kernel_seg, 0 ); + bzimg->rm_kernel = real_to_virt ( bzimg->rm_kernel_seg, 0 ); /* Allow space for the stack and heap */ bzimg->rm_memsz += BZI_STACK_SIZE; @@ -169,24 +163,24 @@ static int bzimage_parse_header ( struct image *image, bzimg->rm_memsz += BZI_CMDLINE_SIZE; /* Calculate load address of protected-mode portion */ - bzimg->pm_kernel = phys_to_user ( is_bzimage ? BZI_LOAD_HIGH_ADDR + bzimg->pm_kernel = phys_to_virt ( is_bzimage ? BZI_LOAD_HIGH_ADDR : BZI_LOAD_LOW_ADDR ); /* Extract video mode */ - bzimg->vid_mode = bzimg->bzhdr.vid_mode; + bzimg->vid_mode = bzhdr->vid_mode; /* Extract memory limit */ bzimg->mem_limit = ( ( bzimg->version >= 0x0203 ) ? - bzimg->bzhdr.initrd_addr_max : BZI_INITRD_MAX ); + bzhdr->initrd_addr_max : BZI_INITRD_MAX ); /* Extract command line size */ bzimg->cmdline_size = ( ( bzimg->version >= 0x0206 ) ? - bzimg->bzhdr.cmdline_size : BZI_CMDLINE_SIZE ); + bzhdr->cmdline_size : BZI_CMDLINE_SIZE ); - DBGC ( image, "bzImage %p version %04x RM %#lx+%#zx PM %#lx+%#zx " - "cmdlen %zd\n", image, bzimg->version, - user_to_phys ( bzimg->rm_kernel, 0 ), bzimg->rm_filesz, - user_to_phys ( bzimg->pm_kernel, 0 ), bzimg->pm_sz, + DBGC ( image, "bzImage %s version %04x RM %#lx+%#zx PM %#lx+%#zx " + "cmdlen %zd\n", image->name, bzimg->version, + virt_to_phys ( bzimg->rm_kernel ), bzimg->rm_filesz, + virt_to_phys ( bzimg->pm_kernel ), bzimg->pm_sz, bzimg->cmdline_size ); return 0; @@ -197,49 +191,44 @@ static int bzimage_parse_header ( struct image *image, * * @v image bzImage file * @v bzimg bzImage context - * @v dst bzImage to update */ static void bzimage_update_header ( struct image *image, - struct bzimage_context *bzimg, - userptr_t dst ) { + struct bzimage_context *bzimg ) { + struct bzimage_header *bzhdr = ( bzimg->rm_kernel + BZI_HDR_OFFSET ); + struct bzimage_cmdline *cmdline; /* Set loader type */ if ( bzimg->version >= 0x0200 ) - bzimg->bzhdr.type_of_loader = BZI_LOADER_TYPE_IPXE; + bzhdr->type_of_loader = BZI_LOADER_TYPE_IPXE; /* Set heap end pointer */ if ( bzimg->version >= 0x0201 ) { - bzimg->bzhdr.heap_end_ptr = ( bzimg->rm_heap - 0x200 ); - bzimg->bzhdr.loadflags |= BZI_CAN_USE_HEAP; + bzhdr->heap_end_ptr = ( bzimg->rm_heap - 0x200 ); + bzhdr->loadflags |= BZI_CAN_USE_HEAP; } /* Set command line */ if ( bzimg->version >= 0x0202 ) { - bzimg->bzhdr.cmd_line_ptr = user_to_phys ( bzimg->rm_kernel, - bzimg->rm_cmdline ); + bzhdr->cmd_line_ptr = ( virt_to_phys ( bzimg->rm_kernel ) + + bzimg->rm_cmdline ); } else { - bzimg->cmdline_magic.magic = BZI_CMDLINE_MAGIC; - bzimg->cmdline_magic.offset = bzimg->rm_cmdline; + cmdline = ( bzimg->rm_kernel + BZI_CMDLINE_OFFSET ); + cmdline->magic = BZI_CMDLINE_MAGIC; + cmdline->offset = bzimg->rm_cmdline; if ( bzimg->version >= 0x0200 ) - bzimg->bzhdr.setup_move_size = bzimg->rm_memsz; + bzhdr->setup_move_size = bzimg->rm_memsz; } /* Set video mode */ - bzimg->bzhdr.vid_mode = bzimg->vid_mode; + bzhdr->vid_mode = bzimg->vid_mode; + DBGC ( image, "bzImage %s vidmode %d\n", + image->name, bzhdr->vid_mode ); /* Set initrd address */ if ( bzimg->version >= 0x0200 ) { - bzimg->bzhdr.ramdisk_image = bzimg->ramdisk_image; - bzimg->bzhdr.ramdisk_size = bzimg->ramdisk_size; + bzhdr->ramdisk_image = virt_to_phys ( bzimg->initrd ); + bzhdr->ramdisk_size = bzimg->initrd_size; } - - /* Write out header structures */ - copy_to_user ( dst, BZI_CMDLINE_OFFSET, &bzimg->cmdline_magic, - sizeof ( bzimg->cmdline_magic ) ); - copy_to_user ( dst, BZI_HDR_OFFSET, &bzimg->bzhdr, - sizeof ( bzimg->bzhdr ) ); - - DBGC ( image, "bzImage %p vidmode %d\n", image, bzimg->vid_mode ); } /** @@ -270,8 +259,9 @@ static int bzimage_parse_cmdline ( struct image *image, } else { bzimg->vid_mode = strtoul ( vga, &end, 0 ); if ( *end ) { - DBGC ( image, "bzImage %p strange \"vga=\" " - "terminator '%c'\n", image, *end ); + DBGC ( image, "bzImage %s strange \"vga=\" " + "terminator '%c'\n", + image->name, *end ); } } if ( sep ) @@ -298,8 +288,8 @@ static int bzimage_parse_cmdline ( struct image *image, case ' ': break; default: - DBGC ( image, "bzImage %p strange \"mem=\" " - "terminator '%c'\n", image, *end ); + DBGC ( image, "bzImage %s strange \"mem=\" " + "terminator '%c'\n", image->name, *end ); break; } bzimg->mem_limit -= 1; @@ -317,76 +307,13 @@ static int bzimage_parse_cmdline ( struct image *image, static void bzimage_set_cmdline ( struct image *image, struct bzimage_context *bzimg ) { const char *cmdline = ( image->cmdline ? image->cmdline : "" ); - size_t cmdline_len; + char *rm_cmdline; /* Copy command line down to real-mode portion */ - cmdline_len = ( strlen ( cmdline ) + 1 ); - if ( cmdline_len > bzimg->cmdline_size ) - cmdline_len = bzimg->cmdline_size; - copy_to_user ( bzimg->rm_kernel, bzimg->rm_cmdline, - cmdline, cmdline_len ); - DBGC ( image, "bzImage %p command line \"%s\"\n", image, cmdline ); -} - -/** - * Align initrd length - * - * @v len Length - * @ret len Length rounded up to INITRD_ALIGN - */ -static inline size_t bzimage_align ( size_t len ) { - - return ( ( len + INITRD_ALIGN - 1 ) & ~( INITRD_ALIGN - 1 ) ); -} - -/** - * Load initrd - * - * @v image bzImage image - * @v initrd initrd image - * @v address Address at which to load, or UNULL - * @ret len Length of loaded image, excluding zero-padding - */ -static size_t bzimage_load_initrd ( struct image *image, - struct image *initrd, - userptr_t address ) { - const char *filename = cpio_name ( initrd ); - struct cpio_header cpio; - size_t offset; - size_t pad_len; - - /* Skip hidden images */ - if ( initrd->flags & IMAGE_HIDDEN ) - return 0; - - /* Create cpio header for non-prebuilt images */ - offset = cpio_header ( initrd, &cpio ); - - /* Copy in initrd image body (and cpio header if applicable) */ - if ( address ) { - memmove_user ( address, offset, initrd->data, 0, initrd->len ); - if ( offset ) { - memset_user ( address, 0, 0, offset ); - copy_to_user ( address, 0, &cpio, sizeof ( cpio ) ); - copy_to_user ( address, sizeof ( cpio ), filename, - cpio_name_len ( initrd ) ); - } - DBGC ( image, "bzImage %p initrd %p [%#08lx,%#08lx,%#08lx)" - "%s%s\n", image, initrd, user_to_phys ( address, 0 ), - user_to_phys ( address, offset ), - user_to_phys ( address, ( offset + initrd->len ) ), - ( filename ? " " : "" ), ( filename ? filename : "" ) ); - DBGC2_MD5A ( image, user_to_phys ( address, offset ), - user_to_virt ( address, offset ), initrd->len ); - } - offset += initrd->len; - - /* Zero-pad to next INITRD_ALIGN boundary */ - pad_len = ( ( -offset ) & ( INITRD_ALIGN - 1 ) ); - if ( address ) - memset_user ( address, offset, 0, pad_len ); - - return offset; + rm_cmdline = ( bzimg->rm_kernel + bzimg->rm_cmdline ); + snprintf ( rm_cmdline, bzimg->cmdline_size, "%s", cmdline ); + DBGC ( image, "bzImage %s command line \"%s\"\n", + image->name, rm_cmdline ); } /** @@ -398,48 +325,52 @@ static size_t bzimage_load_initrd ( struct image *image, */ static int bzimage_check_initrds ( struct image *image, struct bzimage_context *bzimg ) { - struct image *initrd; - userptr_t bottom; - size_t len = 0; + struct memmap_region region; + physaddr_t min; + physaddr_t max; + physaddr_t dest; int rc; /* Calculate total loaded length of initrds */ - for_each_image ( initrd ) { - - /* Calculate length */ - len += bzimage_load_initrd ( image, initrd, UNULL ); - len = bzimage_align ( len ); - - DBGC ( image, "bzImage %p initrd %p from [%#08lx,%#08lx)%s%s\n", - image, initrd, user_to_phys ( initrd->data, 0 ), - user_to_phys ( initrd->data, initrd->len ), - ( initrd->cmdline ? " " : "" ), - ( initrd->cmdline ? initrd->cmdline : "" ) ); - DBGC2_MD5A ( image, user_to_phys ( initrd->data, 0 ), - user_to_virt ( initrd->data, 0 ), initrd->len ); - } + bzimg->initrd_size = initrd_len(); - /* Calculate lowest usable address */ - bottom = userptr_add ( bzimg->pm_kernel, bzimg->pm_sz ); + /* Succeed if there are no initrds */ + if ( ! bzimg->initrd_size ) + return 0; - /* Check that total length fits within space available for - * reshuffling. This is a conservative check, since CPIO - * headers are not present during reshuffling, but this - * doesn't hurt and keeps the code simple. - */ - if ( ( rc = initrd_reshuffle_check ( len, bottom ) ) != 0 ) { - DBGC ( image, "bzImage %p failed reshuffle check: %s\n", - image, strerror ( rc ) ); + /* Calculate available load region after reshuffling */ + if ( ( rc = initrd_region ( bzimg->initrd_size, ®ion ) ) != 0 ) { + DBGC ( image, "bzImage %s no region for initrds: %s\n", + image->name, strerror ( rc ) ); return rc; } - /* Check that total length fits within kernel's memory limit */ - if ( user_to_phys ( bottom, len ) > bzimg->mem_limit ) { - DBGC ( image, "bzImage %p not enough space for initrds\n", - image ); + /* Limit region to avoiding kernel itself */ + min = virt_to_phys ( bzimg->pm_kernel + bzimg->pm_sz ); + if ( min < region.min ) + min = region.min; + + /* Limit region to kernel's memory limit */ + max = region.max; + if ( max > bzimg->mem_limit ) + max = bzimg->mem_limit; + + /* Calculate installation address */ + if ( max < ( bzimg->initrd_size - 1 ) ) { + DBGC ( image, "bzImage %s not enough space for initrds\n", + image->name ); + return -ENOBUFS; + } + dest = ( ( max + 1 - bzimg->initrd_size ) & ~( INITRD_ALIGN - 1 ) ); + if ( dest < min ) { + DBGC ( image, "bzImage %s not enough space for initrds\n", + image->name ); return -ENOBUFS; } + bzimg->initrd = phys_to_virt ( dest ); + DBGC ( image, "bzImage %s loading initrds from %#08lx downwards\n", + image->name, max ); return 0; } @@ -451,65 +382,21 @@ static int bzimage_check_initrds ( struct image *image, */ static void bzimage_load_initrds ( struct image *image, struct bzimage_context *bzimg ) { - struct image *initrd; - struct image *highest = NULL; - struct image *other; - userptr_t top; - userptr_t dest; - size_t offset; size_t len; - /* Reshuffle initrds into desired order */ - initrd_reshuffle ( userptr_add ( bzimg->pm_kernel, bzimg->pm_sz ) ); - - /* Find highest initrd */ - for_each_image ( initrd ) { - if ( ( highest == NULL ) || - ( userptr_sub ( initrd->data, highest->data ) > 0 ) ) { - highest = initrd; - } - } - /* Do nothing if there are no initrds */ - if ( ! highest ) + if ( ! bzimg->initrd ) return; - /* Find highest usable address */ - top = userptr_add ( highest->data, bzimage_align ( highest->len ) ); - if ( user_to_phys ( top, -1 ) > bzimg->mem_limit ) { - top = phys_to_user ( ( bzimg->mem_limit + 1 ) & - ~( INITRD_ALIGN - 1 ) ); - } - DBGC ( image, "bzImage %p loading initrds from %#08lx downwards\n", - image, user_to_phys ( top, -1 ) ); - - /* Load initrds in order */ - for_each_image ( initrd ) { - - /* Calculate cumulative length of following - * initrds (including padding). - */ - offset = 0; - for_each_image ( other ) { - if ( other == initrd ) - offset = 0; - offset += bzimage_load_initrd ( image, other, UNULL ); - offset = bzimage_align ( offset ); - } - - /* Load initrd at this address */ - dest = userptr_add ( top, -offset ); - len = bzimage_load_initrd ( image, initrd, dest ); - - /* Record initrd location */ - if ( ! bzimg->ramdisk_image ) - bzimg->ramdisk_image = user_to_phys ( dest, 0 ); - bzimg->ramdisk_size = ( user_to_phys ( dest, len ) - - bzimg->ramdisk_image ); - } - DBGC ( image, "bzImage %p initrds at [%#08lx,%#08lx)\n", - image, bzimg->ramdisk_image, - ( bzimg->ramdisk_image + bzimg->ramdisk_size ) ); + /* Reshuffle initrds into desired order */ + initrd_reshuffle(); + + /* Load initrds */ + DBGC ( image, "bzImage %s initrds at [%#08lx,%#08lx)\n", + image->name, virt_to_phys ( bzimg->initrd ), + ( virt_to_phys ( bzimg->initrd ) + bzimg->initrd_size ) ); + len = initrd_load_all ( bzimg->initrd ); + assert ( len == bzimg->initrd_size ); } /** @@ -523,21 +410,20 @@ static int bzimage_exec ( struct image *image ) { int rc; /* Read and parse header from image */ - if ( ( rc = bzimage_parse_header ( image, &bzimg, - image->data ) ) != 0 ) + if ( ( rc = bzimage_parse_header ( image, &bzimg ) ) != 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 ) ); + DBGC ( image, "bzImage %s could not prepare RM segment: %s\n", + image->name, 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 ) ); + DBGC ( image, "bzImage %s could not prepare PM segment: %s\n", + image->name, strerror ( rc ) ); return rc; } @@ -553,10 +439,9 @@ static int bzimage_exec ( struct image *image ) { unregister_image ( image_get ( image ) ); /* 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 ); + memcpy ( bzimg.rm_kernel, image->data, bzimg.rm_filesz ); + memcpy ( bzimg.pm_kernel, ( image->data + bzimg.rm_filesz ), + bzimg.pm_sz ); /* Store command line */ bzimage_set_cmdline ( image, &bzimg ); @@ -570,10 +455,10 @@ static int bzimage_exec ( struct image *image ) { bzimage_load_initrds ( image, &bzimg ); /* Update kernel header */ - bzimage_update_header ( image, &bzimg, bzimg.rm_kernel ); + bzimage_update_header ( image, &bzimg ); - DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 " - "(stack %04x:%04zx)\n", image, ( bzimg.rm_kernel_seg + 0x20 ), + DBGC ( image, "bzImage %s jumping to RM kernel at %04x:0000 (stack " + "%04x:%04zx)\n", image->name, ( bzimg.rm_kernel_seg + 0x20 ), bzimg.rm_kernel_seg, bzimg.rm_heap ); /* Jump to the kernel */ @@ -609,8 +494,7 @@ int bzimage_probe ( struct image *image ) { int rc; /* Read and parse header from image */ - if ( ( rc = bzimage_parse_header ( image, &bzimg, - image->data ) ) != 0 ) + if ( ( rc = bzimage_parse_header ( image, &bzimg ) ) != 0 ) return rc; return 0; diff --git a/src/arch/x86/image/com32.c b/src/arch/x86/image/com32.c index 6f0e66041..2b31fb2e5 100644 --- a/src/arch/x86/image/com32.c +++ b/src/arch/x86/image/com32.c @@ -39,7 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/image.h> #include <ipxe/segment.h> #include <ipxe/init.h> -#include <ipxe/io.h> +#include <ipxe/memmap.h> #include <ipxe/console.h> /** @@ -49,8 +49,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @ret rc Return status code */ static int com32_exec_loop ( struct image *image ) { - struct memory_map memmap; - unsigned int i; + struct memmap_region region; int state; uint32_t avail_mem_top; @@ -59,21 +58,12 @@ static int com32_exec_loop ( struct image *image ) { switch ( state ) { case 0: /* First time through; invoke COM32 program */ - /* Get memory map */ - get_memmap ( &memmap ); - /* Find end of block covering COM32 image loading area */ - for ( i = 0, avail_mem_top = 0 ; i < memmap.count ; i++ ) { - if ( (memmap.regions[i].start <= COM32_START_PHYS) && - (memmap.regions[i].end > COM32_START_PHYS + image->len) ) { - avail_mem_top = memmap.regions[i].end; - break; - } - } - - DBGC ( image, "COM32 %p: available memory top = 0x%x\n", - image, avail_mem_top ); - + memmap_describe ( COM32_START_PHYS, 1, ®ion ); + assert ( memmap_is_usable ( ®ion ) ); + avail_mem_top = ( COM32_START_PHYS + memmap_size ( ®ion ) ); + DBGC ( image, "COM32 %s: available memory top = 0x%x\n", + image->name, avail_mem_top ); assert ( avail_mem_top != 0 ); /* Hook COMBOOT API interrupts */ @@ -114,32 +104,32 @@ static int com32_exec_loop ( struct image *image ) { /* Restore registers */ "popal\n\t" ) : - : "r" ( avail_mem_top ), - "r" ( virt_to_phys ( com32_cfarcall_wrapper ) ), - "r" ( virt_to_phys ( com32_farcall_wrapper ) ), - "r" ( get_fbms() * 1024 - ( COM32_BOUNCE_SEG << 4 ) ), + : "R" ( avail_mem_top ), + "R" ( virt_to_phys ( com32_cfarcall_wrapper ) ), + "R" ( virt_to_phys ( com32_farcall_wrapper ) ), + "R" ( get_fbms() * 1024 - ( COM32_BOUNCE_SEG << 4 ) ), "i" ( COM32_BOUNCE_SEG << 4 ), - "r" ( virt_to_phys ( com32_intcall_wrapper ) ), - "r" ( virt_to_phys ( image->cmdline ? + "R" ( virt_to_phys ( com32_intcall_wrapper ) ), + "R" ( virt_to_phys ( image->cmdline ? image->cmdline : "" ) ), "i" ( COM32_START_PHYS ) : "memory" ); - DBGC ( image, "COM32 %p: returned\n", image ); + DBGC ( image, "COM32 %s: returned\n", image->name ); break; case COMBOOT_EXIT: - DBGC ( image, "COM32 %p: exited\n", image ); + DBGC ( image, "COM32 %s: exited\n", image->name ); break; case COMBOOT_EXIT_RUN_KERNEL: assert ( image->replacement ); - DBGC ( image, "COM32 %p: exited to run kernel %s\n", - image, image->replacement->name ); + DBGC ( image, "COM32 %s: exited to run kernel %s\n", + image->name, image->replacement->name ); break; case COMBOOT_EXIT_COMMAND: - DBGC ( image, "COM32 %p: exited after executing command\n", - image ); + DBGC ( image, "COM32 %s: exited after executing command\n", + image->name ); break; default: @@ -162,17 +152,15 @@ static int com32_exec_loop ( struct image *image ) { static int com32_identify ( struct image *image ) { const char *ext; static const uint8_t magic[] = { 0xB8, 0xFF, 0x4C, 0xCD, 0x21 }; - uint8_t buf[5]; - if ( image->len >= 5 ) { + if ( image->len >= sizeof ( magic ) ) { /* Check for magic number * mov eax,21cd4cffh * B8 FF 4C CD 21 */ - copy_from_user ( buf, image->data, 0, sizeof(buf) ); - if ( ! memcmp ( buf, magic, sizeof(buf) ) ) { - DBGC ( image, "COM32 %p: found magic number\n", - image ); + if ( memcmp ( image->data, magic, sizeof ( magic) ) == 0 ) { + DBGC ( image, "COM32 %s: found magic number\n", + image->name ); return 0; } } @@ -182,16 +170,16 @@ static int com32_identify ( struct image *image ) { ext = strrchr( image->name, '.' ); if ( ! ext ) { - DBGC ( image, "COM32 %p: no extension\n", - image ); + DBGC ( image, "COM32 %s: no extension\n", + image->name ); return -ENOEXEC; } ++ext; if ( strcasecmp( ext, "c32" ) ) { - DBGC ( image, "COM32 %p: unrecognized extension %s\n", - image, ext ); + DBGC ( image, "COM32 %s: unrecognized extension %s\n", + image->name, ext ); return -ENOEXEC; } @@ -206,20 +194,20 @@ static int com32_identify ( struct image *image ) { */ static int com32_load_image ( struct image *image ) { size_t filesz, memsz; - userptr_t buffer; + void *buffer; int rc; filesz = image->len; memsz = filesz; - buffer = phys_to_user ( COM32_START_PHYS ); + buffer = phys_to_virt ( COM32_START_PHYS ); if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) { - DBGC ( image, "COM32 %p: could not prepare segment: %s\n", - image, strerror ( rc ) ); + DBGC ( image, "COM32 %s: could not prepare segment: %s\n", + image->name, strerror ( rc ) ); return rc; } /* Copy image to segment */ - memcpy_user ( buffer, 0, image->data, 0, filesz ); + memcpy ( buffer, image->data, filesz ); return 0; } @@ -230,22 +218,20 @@ static int com32_load_image ( struct image *image ) { * @ret rc Return status code */ static int com32_prepare_bounce_buffer ( struct image * image ) { - unsigned int seg; - userptr_t seg_userptr; + void *seg; size_t filesz, memsz; int rc; - seg = COM32_BOUNCE_SEG; - seg_userptr = real_to_user ( seg, 0 ); + seg = real_to_virt ( COM32_BOUNCE_SEG, 0 ); /* Ensure the entire 64k segment is free */ memsz = 0xFFFF; filesz = 0; /* Prepare, verify, and load the real-mode segment */ - if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) { - DBGC ( image, "COM32 %p: could not prepare bounce buffer segment: %s\n", - image, strerror ( rc ) ); + if ( ( rc = prep_segment ( seg, filesz, memsz ) ) != 0 ) { + DBGC ( image, "COM32 %s: could not prepare bounce buffer segment: %s\n", + image->name, strerror ( rc ) ); return rc; } @@ -261,8 +247,6 @@ static int com32_prepare_bounce_buffer ( struct image * image ) { static int com32_probe ( struct image *image ) { int rc; - DBGC ( image, "COM32 %p: name '%s'\n", image, image->name ); - /* Check if this is a COMBOOT image */ if ( ( rc = com32_identify ( image ) ) != 0 ) { return rc; diff --git a/src/arch/x86/image/comboot.c b/src/arch/x86/image/comboot.c index 9a847f0ff..6eba027c6 100644 --- a/src/arch/x86/image/comboot.c +++ b/src/arch/x86/image/comboot.c @@ -35,7 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <realmode.h> #include <basemem.h> #include <comboot.h> -#include <ipxe/uaccess.h> #include <ipxe/image.h> #include <ipxe/segment.h> #include <ipxe/init.h> @@ -67,62 +66,53 @@ struct comboot_psp { * * @v image COMBOOT image */ -static void comboot_copy_cmdline ( struct image * image, userptr_t seg_userptr ) { +static void comboot_copy_cmdline ( struct image * image, void *seg ) { const char *cmdline = ( image->cmdline ? image->cmdline : "" ); int cmdline_len = strlen ( cmdline ); + uint8_t *psp_cmdline; + + /* Limit length of command line */ if( cmdline_len > COMBOOT_MAX_CMDLINE_LEN ) cmdline_len = COMBOOT_MAX_CMDLINE_LEN; - uint8_t len_byte = cmdline_len; - char spc = ' ', cr = '\r'; /* Copy length to byte before command line */ - copy_to_user ( seg_userptr, COMBOOT_PSP_CMDLINE_OFFSET - 1, - &len_byte, 1 ); + psp_cmdline = ( seg + COMBOOT_PSP_CMDLINE_OFFSET ); + psp_cmdline[-1] = cmdline_len; /* Command line starts with space */ - copy_to_user ( seg_userptr, - COMBOOT_PSP_CMDLINE_OFFSET, - &spc, 1 ); + psp_cmdline[0] = ' '; /* Copy command line */ - copy_to_user ( seg_userptr, - COMBOOT_PSP_CMDLINE_OFFSET + 1, - cmdline, cmdline_len ); + memcpy ( &psp_cmdline[1], cmdline, cmdline_len ); /* Command line ends with CR */ - copy_to_user ( seg_userptr, - COMBOOT_PSP_CMDLINE_OFFSET + cmdline_len + 1, - &cr, 1 ); + psp_cmdline[ 1 + cmdline_len ] = '\r'; } /** * Initialize PSP * * @v image COMBOOT image - * @v seg_userptr segment to initialize + * @v seg segment to initialize */ -static void comboot_init_psp ( struct image * image, userptr_t seg_userptr ) { - struct comboot_psp psp; +static void comboot_init_psp ( struct image * image, void *seg ) { + struct comboot_psp *psp; /* Fill PSP */ + psp = seg; /* INT 20h instruction, byte order reversed */ - psp.int20 = 0x20CD; + psp->int20 = 0x20CD; /* get_fbms() returns BIOS free base memory counter, which is in * kilobytes; x * 1024 / 16 == x * 64 == x << 6 */ - psp.first_non_free_para = get_fbms() << 6; - - DBGC ( image, "COMBOOT %p: first non-free paragraph = 0x%x\n", - image, psp.first_non_free_para ); + psp->first_non_free_para = get_fbms() << 6; - /* Copy the PSP to offset 0 of segment. - * The rest of the PSP was already zeroed by - * comboot_prepare_segment. */ - copy_to_user ( seg_userptr, 0, &psp, sizeof( psp ) ); + DBGC ( image, "COMBOOT %s: first non-free paragraph = 0x%x\n", + image->name, psp->first_non_free_para ); /* Copy the command line to the PSP */ - comboot_copy_cmdline ( image, seg_userptr ); + comboot_copy_cmdline ( image, seg ); } /** @@ -132,7 +122,7 @@ static void comboot_init_psp ( struct image * image, userptr_t seg_userptr ) { * @ret rc Return status code */ static int comboot_exec_loop ( struct image *image ) { - userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 ); + void *seg = real_to_virt ( COMBOOT_PSP_SEG, 0 ); int state; state = rmsetjmp ( comboot_return ); @@ -141,7 +131,7 @@ static int comboot_exec_loop ( struct image *image ) { case 0: /* First time through; invoke COMBOOT program */ /* Initialize PSP */ - comboot_init_psp ( image, seg_userptr ); + comboot_init_psp ( image, seg ); /* Hook COMBOOT API interrupts */ hook_comboot_interrupts(); @@ -181,23 +171,23 @@ static int comboot_exec_loop ( struct image *image ) { "xorw %%di, %%di\n\t" "xorw %%bp, %%bp\n\t" "lret\n\t" ) - : : "r" ( COMBOOT_PSP_SEG ) : "eax" ); - DBGC ( image, "COMBOOT %p: returned\n", image ); + : : "R" ( COMBOOT_PSP_SEG ) : "eax" ); + DBGC ( image, "COMBOOT %s: returned\n", image->name ); break; case COMBOOT_EXIT: - DBGC ( image, "COMBOOT %p: exited\n", image ); + DBGC ( image, "COMBOOT %s: exited\n", image->name ); break; case COMBOOT_EXIT_RUN_KERNEL: assert ( image->replacement ); - DBGC ( image, "COMBOOT %p: exited to run kernel %s\n", - image, image->replacement->name ); + DBGC ( image, "COMBOOT %s: exited to run kernel %s\n", + image->name, image->replacement->name ); break; case COMBOOT_EXIT_COMMAND: - DBGC ( image, "COMBOOT %p: exited after executing command\n", - image ); + DBGC ( image, "COMBOOT %s: exited after executing command\n", + image->name ); break; default: @@ -223,16 +213,16 @@ static int comboot_identify ( struct image *image ) { ext = strrchr( image->name, '.' ); if ( ! ext ) { - DBGC ( image, "COMBOOT %p: no extension\n", - image ); + DBGC ( image, "COMBOOT %s: no extension\n", + image->name ); return -ENOEXEC; } ++ext; if ( strcasecmp( ext, "cbt" ) ) { - DBGC ( image, "COMBOOT %p: unrecognized extension %s\n", - image, ext ); + DBGC ( image, "COMBOOT %s: unrecognized extension %s\n", + image->name, ext ); return -ENOEXEC; } @@ -246,12 +236,12 @@ static int comboot_identify ( struct image *image ) { */ static int comboot_prepare_segment ( struct image *image ) { - userptr_t seg_userptr; + void *seg; size_t filesz, memsz; int rc; /* Load image in segment */ - seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 ); + seg = real_to_virt ( COMBOOT_PSP_SEG, 0 ); /* Allow etra 0x100 bytes before image for PSP */ filesz = image->len + 0x100; @@ -260,17 +250,17 @@ static int comboot_prepare_segment ( struct image *image ) memsz = 0xFFFF; /* Prepare, verify, and load the real-mode segment */ - if ( ( rc = prep_segment ( seg_userptr, filesz, memsz ) ) != 0 ) { - DBGC ( image, "COMBOOT %p: could not prepare segment: %s\n", - image, strerror ( rc ) ); + if ( ( rc = prep_segment ( seg, filesz, memsz ) ) != 0 ) { + DBGC ( image, "COMBOOT %s: could not prepare segment: %s\n", + image->name, strerror ( rc ) ); return rc; } /* Zero PSP */ - memset_user ( seg_userptr, 0, 0, 0x100 ); + memset ( seg, 0, 0x100 ); /* Copy image to segment:0100 */ - memcpy_user ( seg_userptr, 0x100, image->data, 0, image->len ); + memcpy ( ( seg + 0x100 ), image->data, image->len ); return 0; } @@ -284,9 +274,6 @@ static int comboot_prepare_segment ( struct image *image ) static int comboot_probe ( struct image *image ) { int rc; - DBGC ( image, "COMBOOT %p: name '%s'\n", - image, image->name ); - /* Check if this is a COMBOOT image */ if ( ( rc = comboot_identify ( image ) ) != 0 ) { @@ -307,8 +294,8 @@ static int comboot_exec ( struct image *image ) { /* Sanity check for filesize */ if( image->len >= 0xFF00 ) { - DBGC( image, "COMBOOT %p: image too large\n", - image ); + DBGC( image, "COMBOOT %s: image too large\n", + image->name ); return -ENOEXEC; } diff --git a/src/arch/x86/image/elfboot.c b/src/arch/x86/image/elfboot.c index dc3568929..d0f91d1c0 100644 --- a/src/arch/x86/image/elfboot.c +++ b/src/arch/x86/image/elfboot.c @@ -23,8 +23,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include <string.h> #include <errno.h> #include <elf.h> +#include <librm.h> #include <ipxe/image.h> #include <ipxe/elf.h> #include <ipxe/features.h> @@ -52,8 +54,8 @@ static int elfboot_exec ( struct image *image ) { /* Load the image using core ELF support */ if ( ( rc = elf_load ( image, &entry, &max ) ) != 0 ) { - DBGC ( image, "ELF %p could not load: %s\n", - image, strerror ( rc ) ); + DBGC ( image, "ELF %s could not load: %s\n", + image->name, strerror ( rc ) ); return rc; } @@ -63,14 +65,15 @@ static int elfboot_exec ( struct image *image ) { shutdown_boot(); /* Jump to OS with flat physical addressing */ - DBGC ( image, "ELF %p starting execution at %lx\n", image, entry ); + DBGC ( image, "ELF %s starting execution at %lx\n", + image->name, entry ); __asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t" /* gcc bug */ "call *%%edi\n\t" "popl %%ebp\n\t" /* gcc bug */ ) : : "D" ( entry ) : "eax", "ebx", "ecx", "edx", "esi", "memory" ); - DBGC ( image, "ELF %p returned\n", image ); + DBGC ( image, "ELF %s returned\n", image->name ); /* It isn't safe to continue after calling shutdown() */ while ( 1 ) {} @@ -86,13 +89,13 @@ static int elfboot_exec ( struct image *image ) { * @v dest Destination address * @ret rc Return status code */ -static int elfboot_check_segment ( struct image *image, Elf_Phdr *phdr, +static int elfboot_check_segment ( struct image *image, const Elf_Phdr *phdr, physaddr_t dest ) { /* Check that ELF segment uses flat physical addressing */ if ( phdr->p_vaddr != dest ) { - DBGC ( image, "ELF %p uses virtual addressing (phys %x, " - "virt %x)\n", image, phdr->p_paddr, phdr->p_vaddr ); + DBGC ( image, "ELF %s uses virtual addressing (phys %x, virt " + "%x)\n", image->name, phdr->p_paddr, phdr->p_vaddr ); return -ENOEXEC; } @@ -106,7 +109,7 @@ static int elfboot_check_segment ( struct image *image, Elf_Phdr *phdr, * @ret rc Return status code */ static int elfboot_probe ( struct image *image ) { - Elf32_Ehdr ehdr; + const Elf32_Ehdr *ehdr; static const uint8_t e_ident[] = { [EI_MAG0] = ELFMAG0, [EI_MAG1] = ELFMAG1, @@ -121,16 +124,22 @@ static int elfboot_probe ( struct image *image ) { int rc; /* Read ELF header */ - copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) ); - if ( memcmp ( ehdr.e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) { - DBGC ( image, "Invalid ELF identifier\n" ); + if ( image->len < sizeof ( *ehdr ) ) { + DBGC ( image, "ELF %s too short for ELF header\n", + image->name ); + return -ENOEXEC; + } + ehdr = image->data; + if ( memcmp ( ehdr->e_ident, e_ident, sizeof ( e_ident ) ) != 0 ) { + DBGC ( image, "ELF %s invalid identifier\n", image->name ); return -ENOEXEC; } /* Check that this image uses flat physical addressing */ - if ( ( rc = elf_segments ( image, &ehdr, elfboot_check_segment, + if ( ( rc = elf_segments ( image, ehdr, elfboot_check_segment, &entry, &max ) ) != 0 ) { - DBGC ( image, "Unloadable ELF image\n" ); + DBGC ( image, "ELF %s is not loadable: %s\n", + image->name, strerror ( rc ) ); return rc; } diff --git a/src/arch/x86/image/initrd.c b/src/arch/x86/image/initrd.c deleted file mode 100644 index d7b1f5773..000000000 --- a/src/arch/x86/image/initrd.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * You can also choose to distribute this program under the terms of - * the Unmodified Binary Distribution Licence (as given in the file - * COPYING.UBDL), provided that you have satisfied its requirements. - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include <errno.h> -#include <initrd.h> -#include <ipxe/image.h> -#include <ipxe/uaccess.h> -#include <ipxe/init.h> -#include <ipxe/memblock.h> -#include <ipxe/cpio.h> - -/** @file - * - * Initial ramdisk (initrd) reshuffling - * - */ - -/** Maximum address available for initrd */ -userptr_t initrd_top; - -/** Minimum address available for initrd */ -userptr_t initrd_bottom; - -/** - * Squash initrds as high as possible in memory - * - * @v top Highest possible address - * @ret used Lowest address used by initrds - */ -static userptr_t initrd_squash_high ( userptr_t top ) { - userptr_t current = top; - struct image *initrd; - struct image *highest; - size_t len; - - /* Squash up any initrds already within or below the region */ - while ( 1 ) { - - /* Find the highest image not yet in its final position */ - highest = NULL; - for_each_image ( initrd ) { - if ( ( userptr_sub ( initrd->data, current ) < 0 ) && - ( ( highest == NULL ) || - ( userptr_sub ( initrd->data, - highest->data ) > 0 ) ) ) { - highest = initrd; - } - } - if ( ! highest ) - break; - - /* Move this image to its final position */ - len = ( ( highest->len + INITRD_ALIGN - 1 ) & - ~( INITRD_ALIGN - 1 ) ); - current = userptr_sub ( current, len ); - DBGC ( &images, "INITRD squashing %s [%#08lx,%#08lx)->" - "[%#08lx,%#08lx)\n", highest->name, - user_to_phys ( highest->data, 0 ), - user_to_phys ( highest->data, highest->len ), - user_to_phys ( current, 0 ), - user_to_phys ( current, highest->len ) ); - memmove_user ( current, 0, highest->data, 0, highest->len ); - highest->data = current; - } - - /* Copy any remaining initrds (e.g. embedded images) to the region */ - for_each_image ( initrd ) { - if ( userptr_sub ( initrd->data, top ) >= 0 ) { - len = ( ( initrd->len + INITRD_ALIGN - 1 ) & - ~( INITRD_ALIGN - 1 ) ); - current = userptr_sub ( current, len ); - DBGC ( &images, "INITRD copying %s [%#08lx,%#08lx)->" - "[%#08lx,%#08lx)\n", initrd->name, - user_to_phys ( initrd->data, 0 ), - user_to_phys ( initrd->data, initrd->len ), - user_to_phys ( current, 0 ), - user_to_phys ( current, initrd->len ) ); - memcpy_user ( current, 0, initrd->data, 0, - initrd->len ); - initrd->data = current; - } - } - - return current; -} - -/** - * Swap position of two adjacent initrds - * - * @v low Lower initrd - * @v high Higher initrd - * @v free Free space - * @v free_len Length of free space - */ -static void initrd_swap ( struct image *low, struct image *high, - userptr_t free, size_t free_len ) { - size_t len = 0; - size_t frag_len; - size_t new_len; - - DBGC ( &images, "INITRD swapping %s [%#08lx,%#08lx)<->[%#08lx,%#08lx) " - "%s\n", low->name, user_to_phys ( low->data, 0 ), - user_to_phys ( low->data, low->len ), - user_to_phys ( high->data, 0 ), - user_to_phys ( high->data, high->len ), high->name ); - - /* Round down length of free space */ - free_len &= ~( INITRD_ALIGN - 1 ); - assert ( free_len > 0 ); - - /* Swap image data */ - while ( len < high->len ) { - - /* Calculate maximum fragment length */ - frag_len = ( high->len - len ); - if ( frag_len > free_len ) - frag_len = free_len; - new_len = ( ( len + frag_len + INITRD_ALIGN - 1 ) & - ~( INITRD_ALIGN - 1 ) ); - - /* Swap fragments */ - memcpy_user ( free, 0, high->data, len, frag_len ); - memmove_user ( low->data, new_len, low->data, len, low->len ); - memcpy_user ( low->data, len, free, 0, frag_len ); - len = new_len; - } - - /* Adjust data pointers */ - high->data = low->data; - low->data = userptr_add ( low->data, len ); -} - -/** - * Swap position of any two adjacent initrds not currently in the correct order - * - * @v free Free space - * @v free_len Length of free space - * @ret swapped A pair of initrds was swapped - */ -static int initrd_swap_any ( userptr_t free, size_t free_len ) { - struct image *low; - struct image *high; - size_t padded_len; - userptr_t adjacent; - - /* Find any pair of initrds that can be swapped */ - for_each_image ( low ) { - - /* Calculate location of adjacent image (if any) */ - padded_len = ( ( low->len + INITRD_ALIGN - 1 ) & - ~( INITRD_ALIGN - 1 ) ); - adjacent = userptr_add ( low->data, padded_len ); - - /* Search for adjacent image */ - for_each_image ( high ) { - - /* Stop search if all remaining potential - * adjacent images are already in the correct - * order. - */ - if ( high == low ) - break; - - /* If we have found the adjacent image, swap and exit */ - if ( high->data == adjacent ) { - initrd_swap ( low, high, free, free_len ); - return 1; - } - } - } - - /* Nothing swapped */ - return 0; -} - -/** - * Dump initrd locations (for debug) - * - */ -static void initrd_dump ( void ) { - struct image *initrd; - - /* Do nothing unless debugging is enabled */ - if ( ! DBG_LOG ) - return; - - /* Dump initrd locations */ - for_each_image ( initrd ) { - DBGC ( &images, "INITRD %s at [%#08lx,%#08lx)\n", - initrd->name, user_to_phys ( initrd->data, 0 ), - user_to_phys ( initrd->data, initrd->len ) ); - DBGC2_MD5A ( &images, user_to_phys ( initrd->data, 0 ), - user_to_virt ( initrd->data, 0 ), initrd->len ); - } -} - -/** - * Reshuffle initrds into desired order at top of memory - * - * @v bottom Lowest address available for initrds - * - * After this function returns, the initrds have been rearranged in - * memory and the external heap structures will have been corrupted. - * Reshuffling must therefore take place immediately prior to jumping - * to the loaded OS kernel; no further execution within iPXE is - * permitted. - */ -void initrd_reshuffle ( userptr_t bottom ) { - userptr_t top; - userptr_t used; - userptr_t free; - size_t free_len; - - /* Calculate limits of available space for initrds */ - top = initrd_top; - if ( userptr_sub ( initrd_bottom, bottom ) > 0 ) - bottom = initrd_bottom; - - /* Debug */ - DBGC ( &images, "INITRD region [%#08lx,%#08lx)\n", - user_to_phys ( bottom, 0 ), user_to_phys ( top, 0 ) ); - initrd_dump(); - - /* Squash initrds as high as possible in memory */ - used = initrd_squash_high ( top ); - - /* Calculate available free space */ - free = bottom; - free_len = userptr_sub ( used, free ); - - /* Bubble-sort initrds into desired order */ - while ( initrd_swap_any ( free, free_len ) ) {} - - /* Debug */ - initrd_dump(); -} - -/** - * Check that there is enough space to reshuffle initrds - * - * @v len Total length of initrds (including padding) - * @v bottom Lowest address available for initrds - * @ret rc Return status code - */ -int initrd_reshuffle_check ( size_t len, userptr_t bottom ) { - userptr_t top; - size_t available; - - /* Calculate limits of available space for initrds */ - top = initrd_top; - if ( userptr_sub ( initrd_bottom, bottom ) > 0 ) - bottom = initrd_bottom; - available = userptr_sub ( top, bottom ); - - /* Allow for a sensible minimum amount of free space */ - len += INITRD_MIN_FREE_LEN; - - /* Check for available space */ - return ( ( len < available ) ? 0 : -ENOBUFS ); -} - -/** - * initrd startup function - * - */ -static void initrd_startup ( void ) { - size_t len; - - /* Record largest memory block available. Do this after any - * allocations made during driver startup (e.g. large host - * memory blocks for Infiniband devices, which may still be in - * use at the time of rearranging if a SAN device is hooked) - * but before any allocations for downloaded images (which we - * can safely reuse when rearranging). - */ - len = largest_memblock ( &initrd_bottom ); - initrd_top = userptr_add ( initrd_bottom, len ); -} - -/** initrd startup function */ -struct startup_fn startup_initrd __startup_fn ( STARTUP_LATE ) = { - .name = "initrd", - .startup = initrd_startup, -}; diff --git a/src/arch/x86/image/multiboot.c b/src/arch/x86/image/multiboot.c index cada021ab..40d6941da 100644 --- a/src/arch/x86/image/multiboot.c +++ b/src/arch/x86/image/multiboot.c @@ -31,14 +31,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include <stdio.h> +#include <string.h> #include <errno.h> #include <assert.h> #include <realmode.h> #include <multiboot.h> -#include <ipxe/uaccess.h> #include <ipxe/image.h> #include <ipxe/segment.h> -#include <ipxe/io.h> +#include <ipxe/memmap.h> #include <ipxe/elf.h> #include <ipxe/init.h> #include <ipxe/features.h> @@ -59,6 +59,9 @@ FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 ); */ #define MAX_MODULES 8 +/** Maximum number of memory map entries */ +#define MAX_MEMMAP 8 + /** * Maximum combined length of command lines * @@ -87,14 +90,6 @@ FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 ); */ #define MB_UNSUPPORTED_FLAGS ( MB_COMPULSORY_FLAGS & ~MB_SUPPORTED_FLAGS ) -/** A multiboot header descriptor */ -struct multiboot_header_info { - /** The actual multiboot header */ - struct multiboot_header mb; - /** Offset of header within the multiboot image */ - size_t offset; -}; - /** Multiboot module command lines */ static char __bss16_array ( mb_cmdlines, [MB_MAX_CMDLINE] ); #define mb_cmdlines __use_data16 ( mb_cmdlines ) @@ -114,32 +109,43 @@ static void multiboot_build_memmap ( struct image *image, struct multiboot_info *mbinfo, struct multiboot_memory_map *mbmemmap, unsigned int limit ) { - struct memory_map memmap; - unsigned int i; - - /* Get memory map */ - get_memmap ( &memmap ); + struct memmap_region region; + unsigned int remaining; /* Translate into multiboot format */ memset ( mbmemmap, 0, sizeof ( *mbmemmap ) ); - for ( i = 0 ; i < memmap.count ; i++ ) { - if ( i >= limit ) { - DBGC ( image, "MULTIBOOT %p limit of %d memmap " - "entries reached\n", image, limit ); + remaining = limit; + for_each_memmap ( ®ion, 0 ) { + + /* Ignore any non-memory regions */ + if ( ! ( region.flags & MEMMAP_FL_MEMORY ) ) + continue; + DBGC_MEMMAP ( image, ®ion ); + + /* Check Multiboot memory map limit */ + if ( ! remaining ) { + DBGC ( image, "MULTIBOOT %s limit of %d memmap " + "entries reached\n", image->name, limit ); break; } - mbmemmap[i].size = ( sizeof ( mbmemmap[i] ) - - sizeof ( mbmemmap[i].size ) ); - mbmemmap[i].base_addr = memmap.regions[i].start; - mbmemmap[i].length = ( memmap.regions[i].end - - memmap.regions[i].start ); - mbmemmap[i].type = MBMEM_RAM; - mbinfo->mmap_length += sizeof ( mbmemmap[i] ); - if ( memmap.regions[i].start == 0 ) - mbinfo->mem_lower = ( memmap.regions[i].end / 1024 ); - if ( memmap.regions[i].start == 0x100000 ) - mbinfo->mem_upper = ( ( memmap.regions[i].end - - 0x100000 ) / 1024 ); + + /* Populate Multiboot memory map entry */ + mbmemmap->size = ( sizeof ( *mbmemmap ) - + sizeof ( mbmemmap->size ) ); + mbmemmap->base_addr = region.min; + mbmemmap->length = memmap_size ( ®ion ); + mbmemmap->type = MBMEM_RAM; + + /* Update Multiboot information */ + mbinfo->mmap_length += sizeof ( *mbmemmap ); + if ( mbmemmap->base_addr == 0 ) + mbinfo->mem_lower = ( mbmemmap->length / 1024 ); + if ( mbmemmap->base_addr == 0x100000 ) + mbinfo->mem_upper = ( mbmemmap->length / 1024 ); + + /* Move to next Multiboot memory map entry */ + mbmemmap++; + remaining--; } } @@ -199,8 +205,8 @@ static int multiboot_add_modules ( struct image *image, physaddr_t start, for_each_image ( module_image ) { if ( mbinfo->mods_count >= limit ) { - DBGC ( image, "MULTIBOOT %p limit of %d modules " - "reached\n", image, limit ); + DBGC ( image, "MULTIBOOT %s limit of %d modules " + "reached\n", image->name, limit ); break; } @@ -212,18 +218,18 @@ static int multiboot_add_modules ( struct image *image, physaddr_t start, start = ( ( start + 0xfff ) & ~0xfff ); /* Prepare segment */ - if ( ( rc = prep_segment ( phys_to_user ( start ), + if ( ( rc = prep_segment ( phys_to_virt ( start ), module_image->len, module_image->len ) ) != 0 ) { - DBGC ( image, "MULTIBOOT %p could not prepare module " - "%s: %s\n", image, module_image->name, + DBGC ( image, "MULTIBOOT %s could not prepare module " + "%s: %s\n", image->name, module_image->name, strerror ( rc ) ); return rc; } /* Copy module */ - memcpy_user ( phys_to_user ( start ), 0, - module_image->data, 0, module_image->len ); + memcpy ( phys_to_virt ( start ), module_image->data, + module_image->len ); /* Add module to list */ module = &modules[mbinfo->mods_count++]; @@ -231,8 +237,8 @@ static int multiboot_add_modules ( struct image *image, physaddr_t start, module->mod_end = ( start + module_image->len ); module->string = multiboot_add_cmdline ( module_image ); module->reserved = 0; - DBGC ( image, "MULTIBOOT %p module %s is [%x,%x)\n", - image, module_image->name, module->mod_start, + DBGC ( image, "MULTIBOOT %s module %s is [%x,%x)\n", + image->name, module_image->name, module->mod_start, module->mod_end ); start += module_image->len; } @@ -255,8 +261,7 @@ static char __bss16_array ( mb_bootloader_name, [32] ); #define mb_bootloader_name __use_data16 ( mb_bootloader_name ) /** The multiboot memory map */ -static struct multiboot_memory_map - __bss16_array ( mbmemmap, [MAX_MEMORY_REGIONS] ); +static struct multiboot_memory_map __bss16_array ( mbmemmap, [MAX_MEMMAP] ); #define mbmemmap __use_data16 ( mbmemmap ) /** The multiboot module list */ @@ -267,94 +272,101 @@ static struct multiboot_module __bss16_array ( mbmodules, [MAX_MODULES] ); * Find multiboot header * * @v image Multiboot file - * @v hdr Multiboot header descriptor to fill in - * @ret rc Return status code + * @ret offset Offset to Multiboot header, or negative error */ -static int multiboot_find_header ( struct image *image, - struct multiboot_header_info *hdr ) { - uint32_t buf[64]; +static int multiboot_find_header ( struct image *image ) { + const struct multiboot_header *mb; size_t offset; - unsigned int buf_idx; uint32_t checksum; - /* Scan through first 8kB of image file 256 bytes at a time. - * (Use the buffering to avoid the overhead of a - * copy_from_user() for every dword.) - */ - for ( offset = 0 ; offset < 8192 ; offset += sizeof ( buf[0] ) ) { + /* Scan through first 8kB of image file */ + for ( offset = 0 ; offset < 8192 ; offset += 4 ) { /* Check for end of image */ - if ( offset > image->len ) + if ( ( offset + sizeof ( *mb ) ) > image->len ) break; - /* Refill buffer if applicable */ - buf_idx = ( ( offset % sizeof ( buf ) ) / sizeof ( buf[0] ) ); - if ( buf_idx == 0 ) { - copy_from_user ( buf, image->data, offset, - sizeof ( buf ) ); - } + mb = ( image->data + offset ); /* Check signature */ - if ( buf[buf_idx] != MULTIBOOT_HEADER_MAGIC ) + if ( mb->magic != MULTIBOOT_HEADER_MAGIC ) continue; /* Copy header and verify checksum */ - copy_from_user ( &hdr->mb, image->data, offset, - sizeof ( hdr->mb ) ); - checksum = ( hdr->mb.magic + hdr->mb.flags + - hdr->mb.checksum ); + checksum = ( mb->magic + mb->flags + mb->checksum ); if ( checksum != 0 ) continue; - /* Record offset of multiboot header and return */ - hdr->offset = offset; - return 0; + /* Return header */ + return offset; } /* No multiboot header found */ + DBGC ( image, "MULTIBOOT %s has no multiboot header\n", + image->name ); return -ENOEXEC; } /** * Load raw multiboot image into memory * - * @v image Multiboot file - * @v hdr Multiboot header descriptor + * @v image Multiboot image + * @v offset Offset to Multiboot header * @ret entry Entry point * @ret max Maximum used address * @ret rc Return status code */ -static int multiboot_load_raw ( struct image *image, - struct multiboot_header_info *hdr, +static int multiboot_load_raw ( struct image *image, size_t offset, physaddr_t *entry, physaddr_t *max ) { - size_t offset; + const struct multiboot_header *mb = ( image->data + offset ); size_t filesz; size_t memsz; - userptr_t buffer; + void *buffer; int rc; /* Sanity check */ - if ( ! ( hdr->mb.flags & MB_FLAG_RAW ) ) { - DBGC ( image, "MULTIBOOT %p is not flagged as a raw image\n", - image ); + if ( ! ( mb->flags & MB_FLAG_RAW ) ) { + DBGC ( image, "MULTIBOOT %s is not flagged as a raw image\n", + image->name ); return -EINVAL; } - /* Verify and prepare segment */ - offset = ( hdr->offset - hdr->mb.header_addr + hdr->mb.load_addr ); - filesz = ( hdr->mb.load_end_addr ? - ( hdr->mb.load_end_addr - hdr->mb.load_addr ) : + /* Calculate starting offset within file */ + if ( ( mb->load_addr > mb->header_addr ) || + ( ( mb->header_addr - mb->load_addr ) > offset ) ) { + DBGC ( image, "MULTIBOOT %s has misplaced header\n", + image->name ); + return -EINVAL; + } + offset -= ( mb->header_addr - mb->load_addr ); + assert ( offset < image->len ); + + /* Calculate length of initialized data */ + filesz = ( mb->load_end_addr ? + ( mb->load_end_addr - mb->load_addr ) : ( image->len - offset ) ); - memsz = ( hdr->mb.bss_end_addr ? - ( hdr->mb.bss_end_addr - hdr->mb.load_addr ) : filesz ); - buffer = phys_to_user ( hdr->mb.load_addr ); + if ( filesz > image->len ) { + DBGC ( image, "MULTIBOOT %s has overlength data\n", + image->name ); + return -EINVAL; + } + + /* Calculate length of uninitialised data */ + memsz = ( mb->bss_end_addr ? + ( mb->bss_end_addr - mb->load_addr ) : filesz ); + DBGC ( image, "MULTIBOOT %s loading [%zx,%zx) to [%x,%zx,%zx)\n", + image->name, offset, ( offset + filesz ), mb->load_addr, + ( mb->load_addr + filesz ), ( mb->load_addr + memsz ) ); + + /* Verify and prepare segment */ + buffer = phys_to_virt ( mb->load_addr ); if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) { - DBGC ( image, "MULTIBOOT %p could not prepare segment: %s\n", - image, strerror ( rc ) ); + DBGC ( image, "MULTIBOOT %s could not prepare segment: %s\n", + image->name, strerror ( rc ) ); return rc; } /* Copy image to segment */ - memcpy_user ( buffer, 0, image->data, offset, filesz ); + memcpy ( buffer, ( image->data + offset ), filesz ); /* Record execution entry point and maximum used address */ - *entry = hdr->mb.entry_addr; - *max = ( hdr->mb.load_addr + memsz ); + *entry = mb->entry_addr; + *max = ( mb->load_addr + memsz ); return 0; } @@ -373,8 +385,8 @@ static int multiboot_load_elf ( struct image *image, physaddr_t *entry, /* Load ELF image*/ if ( ( rc = elf_load ( image, entry, max ) ) != 0 ) { - DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n", - image, strerror ( rc ) ); + DBGC ( image, "MULTIBOOT %s ELF image failed to load: %s\n", + image->name, strerror ( rc ) ); return rc; } @@ -388,22 +400,24 @@ static int multiboot_load_elf ( struct image *image, physaddr_t *entry, * @ret rc Return status code */ static int multiboot_exec ( struct image *image ) { - struct multiboot_header_info hdr; + const struct multiboot_header *mb; physaddr_t entry; physaddr_t max; + int offset; 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 ); + offset = multiboot_find_header ( image ); + if ( offset < 0 ) { + rc = offset; return rc; } + mb = ( image->data + offset ); /* Abort if we detect flags that we cannot support */ - if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) { - DBGC ( image, "MULTIBOOT %p flags %08x not supported\n", - image, ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) ); + if ( mb->flags & MB_UNSUPPORTED_FLAGS ) { + DBGC ( image, "MULTIBOOT %s flags %#08x not supported\n", + image->name, ( mb->flags & MB_UNSUPPORTED_FLAGS ) ); return -ENOTSUP; } @@ -413,8 +427,10 @@ static int multiboot_exec ( struct image *image ) { * behaviour. */ if ( ( ( rc = multiboot_load_elf ( image, &entry, &max ) ) != 0 ) && - ( ( rc = multiboot_load_raw ( image, &hdr, &entry, &max ) ) != 0 )) + ( ( rc = multiboot_load_raw ( image, offset, &entry, + &max ) ) != 0 ) ) { return rc; + } /* Populate multiboot information structure */ memset ( &mbinfo, 0, sizeof ( mbinfo ) ); @@ -444,8 +460,8 @@ static int multiboot_exec ( struct image *image ) { ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) ); /* Jump to OS with flat physical addressing */ - DBGC ( image, "MULTIBOOT %p starting execution at %lx\n", - image, entry ); + DBGC ( image, "MULTIBOOT %s starting execution at %lx\n", + image->name, entry ); __asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t" "call *%%edi\n\t" "popl %%ebp\n\t" ) @@ -454,7 +470,7 @@ static int multiboot_exec ( struct image *image ) { "D" ( entry ) : "ecx", "edx", "esi", "memory" ); - DBGC ( image, "MULTIBOOT %p returned\n", image ); + DBGC ( image, "MULTIBOOT %s returned\n", image->name ); /* It isn't safe to continue after calling shutdown() */ while ( 1 ) {} @@ -469,17 +485,19 @@ static int multiboot_exec ( struct image *image ) { * @ret rc Return status code */ static int multiboot_probe ( struct image *image ) { - struct multiboot_header_info hdr; + const struct multiboot_header *mb; + int offset; 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 ); + offset = multiboot_find_header ( image ); + if ( offset < 0 ) { + rc = offset; return rc; } - DBGC ( image, "MULTIBOOT %p found header with flags %08x\n", - image, hdr.mb.flags ); + mb = ( image->data + offset ); + DBGC ( image, "MULTIBOOT %s found header at +%#x with flags %#08x\n", + image->name, offset, mb->flags ); return 0; } diff --git a/src/arch/x86/image/nbi.c b/src/arch/x86/image/nbi.c index b691bee20..e0a46758e 100644 --- a/src/arch/x86/image/nbi.c +++ b/src/arch/x86/image/nbi.c @@ -1,3 +1,4 @@ +#include <string.h> #include <errno.h> #include <assert.h> #include <realmode.h> @@ -106,12 +107,12 @@ struct ebinfo { * @ret rc Return status code */ static int nbi_prepare_segment ( struct image *image, size_t offset __unused, - userptr_t dest, size_t filesz, size_t memsz ){ + void *dest, size_t filesz, size_t memsz ) { int rc; if ( ( rc = prep_segment ( dest, filesz, memsz ) ) != 0 ) { - DBGC ( image, "NBI %p could not prepare segment: %s\n", - image, strerror ( rc ) ); + DBGC ( image, "NBI %s could not prepare segment: %s\n", + image->name, strerror ( rc ) ); return rc; } @@ -129,9 +130,9 @@ static int nbi_prepare_segment ( struct image *image, size_t offset __unused, * @ret rc Return status code */ static int nbi_load_segment ( struct image *image, size_t offset, - userptr_t dest, size_t filesz, + void *dest, size_t filesz, size_t memsz __unused ) { - memcpy_user ( dest, 0, image->data, offset, filesz ); + memcpy ( dest, ( image->data + offset ), filesz ); return 0; } @@ -144,22 +145,22 @@ static int nbi_load_segment ( struct image *image, size_t offset, * @ret rc Return status code */ static int nbi_process_segments ( struct image *image, - struct imgheader *imgheader, + const struct imgheader *imgheader, int ( * process ) ( struct image *image, size_t offset, - userptr_t dest, + void *dest, size_t filesz, size_t memsz ) ) { - struct segheader sh; + const struct segheader *sh; size_t offset = 0; size_t sh_off; - userptr_t dest; + void *dest; size_t filesz; size_t memsz; int rc; /* Copy image header to target location */ - dest = real_to_user ( imgheader->location.segment, + dest = real_to_virt ( imgheader->location.segment, imgheader->location.offset ); filesz = memsz = NBI_HEADER_LENGTH; if ( ( rc = process ( image, offset, dest, filesz, memsz ) ) != 0 ) @@ -170,32 +171,32 @@ static int nbi_process_segments ( struct image *image, sh_off = NBI_LENGTH ( imgheader->length ); do { /* Read segment header */ - copy_from_user ( &sh, image->data, sh_off, sizeof ( sh ) ); - if ( sh.length == 0 ) { + sh = ( image->data + sh_off ); + if ( sh->length == 0 ) { /* Avoid infinite loop? */ - DBGC ( image, "NBI %p invalid segheader length 0\n", - image ); + DBGC ( image, "NBI %s invalid segheader length 0\n", + image->name ); return -ENOEXEC; } /* Calculate segment load address */ - switch ( NBI_LOADADDR_FLAGS ( sh.flags ) ) { + switch ( NBI_LOADADDR_FLAGS ( sh->flags ) ) { case NBI_LOADADDR_ABS: - dest = phys_to_user ( sh.loadaddr ); + dest = phys_to_virt ( sh->loadaddr ); break; case NBI_LOADADDR_AFTER: - dest = userptr_add ( dest, memsz + sh.loadaddr ); + dest = ( dest + memsz + sh->loadaddr ); break; case NBI_LOADADDR_BEFORE: - dest = userptr_add ( dest, -sh.loadaddr ); + dest = ( dest - sh->loadaddr ); break; case NBI_LOADADDR_END: /* Not correct according to the spec, but * maintains backwards compatibility with * previous versions of Etherboot. */ - dest = phys_to_user ( ( extmemsize() + 1024 ) * 1024 - - sh.loadaddr ); + dest = phys_to_virt ( ( extmemsize() + 1024 ) * 1024 + - sh->loadaddr ); break; default: /* Cannot be reached */ @@ -203,10 +204,11 @@ static int nbi_process_segments ( struct image *image, } /* Process this segment */ - filesz = sh.imglength; - memsz = sh.memlength; + filesz = sh->imglength; + memsz = sh->memlength; if ( ( offset + filesz ) > image->len ) { - DBGC ( image, "NBI %p segment outside file\n", image ); + DBGC ( image, "NBI %s segment outside file\n", + image->name ); return -ENOEXEC; } if ( ( rc = process ( image, offset, dest, @@ -216,17 +218,18 @@ static int nbi_process_segments ( struct image *image, offset += filesz; /* Next segheader */ - sh_off += NBI_LENGTH ( sh.length ); + sh_off += NBI_LENGTH ( sh->length ); if ( sh_off >= NBI_HEADER_LENGTH ) { - DBGC ( image, "NBI %p header overflow\n", image ); + DBGC ( image, "NBI %s header overflow\n", + image->name ); return -ENOEXEC; } - } while ( ! NBI_LAST_SEGHEADER ( sh.flags ) ); + } while ( ! NBI_LAST_SEGHEADER ( sh->flags ) ); if ( offset != image->len ) { - DBGC ( image, "NBI %p length wrong (file %zd, metadata %zd)\n", - image, image->len, offset ); + DBGC ( image, "NBI %s length wrong (file %zd, metadata %zd)\n", + image->name, image->len, offset ); return -ENOEXEC; } @@ -239,12 +242,13 @@ static int nbi_process_segments ( struct image *image, * @v imgheader Image header information * @ret rc Return status code, if image returns */ -static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) { +static int nbi_boot16 ( struct image *image, + const struct imgheader *imgheader ) { int discard_D, discard_S, discard_b; int32_t rc; - DBGC ( image, "NBI %p executing 16-bit image at %04x:%04x\n", image, - imgheader->execaddr.segoff.segment, + DBGC ( image, "NBI %s executing 16-bit image at %04x:%04x\n", + image->name, imgheader->execaddr.segoff.segment, imgheader->execaddr.segoff.offset ); __asm__ __volatile__ ( @@ -277,7 +281,8 @@ static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) { * @v imgheader Image header information * @ret rc Return status code, if image returns */ -static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) { +static int nbi_boot32 ( struct image *image, + const struct imgheader *imgheader ) { struct ebinfo loaderinfo = { product_major_version, product_minor_version, 0 @@ -285,8 +290,8 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) { int discard_D, discard_S, discard_b; int32_t rc; - DBGC ( image, "NBI %p executing 32-bit image at %lx\n", - image, imgheader->execaddr.linear ); + DBGC ( image, "NBI %s executing 32-bit image at %lx\n", + image->name, imgheader->execaddr.linear ); /* Jump to OS with flat physical addressing */ __asm__ __volatile__ ( @@ -321,14 +326,15 @@ static int nbi_prepare_dhcp ( struct image *image ) { boot_netdev = last_opened_netdev(); if ( ! boot_netdev ) { - DBGC ( image, "NBI %p could not identify a network device\n", - image ); + DBGC ( image, "NBI %s could not identify a network device\n", + image->name ); return -ENODEV; } if ( ( rc = create_fakedhcpack ( boot_netdev, basemem_packet, sizeof ( basemem_packet ) ) ) != 0 ) { - DBGC ( image, "NBI %p failed to build DHCP packet\n", image ); + DBGC ( image, "NBI %s failed to build DHCP packet\n", + image->name ); return rc; } @@ -342,15 +348,15 @@ static int nbi_prepare_dhcp ( struct image *image ) { * @ret rc Return status code */ static int nbi_exec ( struct image *image ) { - struct imgheader imgheader; + const struct imgheader *imgheader; int may_return; int rc; /* Retrieve image header */ - copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) ); + imgheader = image->data; - DBGC ( image, "NBI %p placing header at %hx:%hx\n", image, - imgheader.location.segment, imgheader.location.offset ); + DBGC ( image, "NBI %s placing header at %hx:%hx\n", image->name, + 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 @@ -359,10 +365,10 @@ static int nbi_exec ( struct image *image ) { * 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, + if ( ( rc = nbi_process_segments ( image, imgheader, nbi_prepare_segment ) ) != 0 ) return rc; - if ( ( rc = nbi_process_segments ( image, &imgheader, + if ( ( rc = nbi_process_segments ( image, imgheader, nbi_load_segment ) ) != 0 ) return rc; @@ -371,25 +377,25 @@ static int nbi_exec ( struct image *image ) { return rc; /* Shut down now if NBI image will not return */ - may_return = NBI_PROGRAM_RETURNS ( imgheader.flags ); + may_return = NBI_PROGRAM_RETURNS ( imgheader->flags ); if ( ! may_return ) shutdown_boot(); /* Execute NBI image */ - if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) { - rc = nbi_boot32 ( image, &imgheader ); + if ( NBI_LINEAR_EXEC_ADDR ( imgheader->flags ) ) { + rc = nbi_boot32 ( image, imgheader ); } else { - rc = nbi_boot16 ( image, &imgheader ); + rc = nbi_boot16 ( image, imgheader ); } if ( ! may_return ) { /* Cannot continue after shutdown() called */ - DBGC ( image, "NBI %p returned %d from non-returnable image\n", - image, rc ); + DBGC ( image, "NBI %s returned %d from non-returnable image\n", + image->name, rc ); while ( 1 ) {} } - DBGC ( image, "NBI %p returned %d\n", image, rc ); + DBGC ( image, "NBI %s returned %d\n", image->name, rc ); return rc; } @@ -401,18 +407,19 @@ static int nbi_exec ( struct image *image ) { * @ret rc Return status code */ static int nbi_probe ( struct image *image ) { - struct imgheader imgheader; + const 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 ); + DBGC ( image, "NBI %s too short for an NBI image\n", + image->name ); return -ENOEXEC; } + imgheader = image->data; /* 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 ); + if ( imgheader->magic != NBI_MAGIC ) { + DBGC ( image, "NBI %s has no NBI signature\n", image->name ); return -ENOEXEC; } diff --git a/src/arch/x86/image/pxe_image.c b/src/arch/x86/image/pxe_image.c index b6bcb18b4..f88eadc09 100644 --- a/src/arch/x86/image/pxe_image.c +++ b/src/arch/x86/image/pxe_image.c @@ -30,10 +30,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +#include <string.h> #include <pxe.h> #include <pxe_call.h> #include <pic8259.h> -#include <ipxe/uaccess.h> #include <ipxe/image.h> #include <ipxe/segment.h> #include <ipxe/netdevice.h> @@ -54,24 +54,24 @@ const char *pxe_cmdline; * @ret rc Return status code */ static int pxe_exec ( struct image *image ) { - userptr_t buffer = real_to_user ( 0, 0x7c00 ); + void *buffer = real_to_virt ( 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 ) ); + DBGC ( image, "IMAGE %s could not prepare segment: %s\n", + image->name, strerror ( rc ) ); return rc; } /* Copy image to segment */ - memcpy_user ( buffer, 0, image->data, 0, image->len ); + memcpy ( buffer, image->data, image->len ); /* Arbitrarily pick the most recently opened network device */ if ( ( netdev = last_opened_netdev() ) == NULL ) { - DBGC ( image, "IMAGE %p could not locate PXE net device\n", - image ); + DBGC ( image, "IMAGE %s could not locate PXE net device\n", + image->name ); return -ENODEV; } netdev_get ( netdev ); @@ -142,7 +142,7 @@ int pxe_probe ( struct image *image ) { * @ret rc Return status code */ int pxe_probe_no_mz ( struct image *image ) { - uint16_t magic; + const uint16_t *magic; int rc; /* Probe PXE image */ @@ -152,11 +152,11 @@ int pxe_probe_no_mz ( struct image *image ) { /* Reject image with an "MZ" signature which may indicate an * EFI image incorrectly handed out to a BIOS system. */ - if ( image->len >= sizeof ( magic ) ) { - copy_from_user ( &magic, image->data, 0, sizeof ( magic ) ); - if ( magic == cpu_to_le16 ( EFI_IMAGE_DOS_SIGNATURE ) ) { - DBGC ( image, "IMAGE %p may be an EFI image\n", - image ); + if ( image->len >= sizeof ( *magic ) ) { + magic = image->data; + if ( *magic == cpu_to_le16 ( EFI_IMAGE_DOS_SIGNATURE ) ) { + DBGC ( image, "IMAGE %s may be an EFI image\n", + image->name ); return -ENOTTY; } } diff --git a/src/arch/x86/image/sdi.c b/src/arch/x86/image/sdi.c index fa2d0b73f..c0cded239 100644 --- a/src/arch/x86/image/sdi.c +++ b/src/arch/x86/image/sdi.c @@ -45,63 +45,36 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); FEATURE ( FEATURE_IMAGE, "SDI", DHCP_EB_FEATURE_SDI, 1 ); /** - * Parse SDI image header - * - * @v image SDI file - * @v sdi SDI header to fill in - * @ret rc Return status code - */ -static int sdi_parse_header ( struct image *image, struct sdi_header *sdi ) { - - /* Sanity check */ - if ( image->len < sizeof ( *sdi ) ) { - DBGC ( image, "SDI %p too short for SDI header\n", image ); - return -ENOEXEC; - } - - /* Read in header */ - copy_from_user ( sdi, image->data, 0, sizeof ( *sdi ) ); - - /* Check signature */ - if ( sdi->magic != SDI_MAGIC ) { - DBGC ( image, "SDI %p is not an SDI image\n", image ); - return -ENOEXEC; - } - - return 0; -} - -/** * Execute SDI image * * @v image SDI file * @ret rc Return status code */ static int sdi_exec ( struct image *image ) { - struct sdi_header sdi; + const struct sdi_header *sdi; uint32_t sdiptr; - int rc; - /* Parse image header */ - if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 ) - return rc; + /* Sanity check */ + assert ( image->len >= sizeof ( *sdi ) ); + sdi = image->data; /* Check that image is bootable */ - if ( sdi.boot_size == 0 ) { - DBGC ( image, "SDI %p is not bootable\n", image ); + if ( sdi->boot_size == 0 ) { + DBGC ( image, "SDI %s is not bootable\n", image->name ); return -ENOTTY; } - DBGC ( image, "SDI %p image at %08lx+%08zx\n", - image, user_to_phys ( image->data, 0 ), image->len ); - DBGC ( image, "SDI %p boot code at %08lx+%llx\n", image, - user_to_phys ( image->data, sdi.boot_offset ), sdi.boot_size ); + DBGC ( image, "SDI %s image at %08lx+%08zx\n", + image->name, virt_to_phys ( image->data ), image->len ); + DBGC ( image, "SDI %s boot code at %08llx+%llx\n", image->name, + ( virt_to_phys ( image->data ) + sdi->boot_offset ), + sdi->boot_size ); /* Copy boot code */ - memcpy_user ( real_to_user ( SDI_BOOT_SEG, SDI_BOOT_OFF ), 0, - image->data, sdi.boot_offset, sdi.boot_size ); + memcpy ( real_to_virt ( SDI_BOOT_SEG, SDI_BOOT_OFF ), + ( image->data + sdi->boot_offset ), sdi->boot_size ); /* Jump to boot code */ - sdiptr = ( user_to_phys ( image->data, 0 ) | SDI_WTF ); + sdiptr = ( virt_to_phys ( image->data ) | SDI_WTF ); __asm__ __volatile__ ( REAL_CODE ( "ljmp %0, %1\n\t" ) : : "i" ( SDI_BOOT_SEG ), "i" ( SDI_BOOT_OFF ), @@ -122,12 +95,22 @@ static int sdi_exec ( struct image *image ) { * @ret rc Return status code */ static int sdi_probe ( struct image *image ) { - struct sdi_header sdi; - int rc; + const struct sdi_header *sdi; - /* Parse image */ - if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 ) - return rc; + /* Sanity check */ + if ( image->len < sizeof ( *sdi ) ) { + DBGC ( image, "SDI %s too short for SDI header\n", + image->name ); + return -ENOEXEC; + } + sdi = image->data; + + /* Check signature */ + if ( sdi->magic != SDI_MAGIC ) { + DBGC ( image, "SDI %s is not an SDI image\n", + image->name ); + return -ENOEXEC; + } return 0; } diff --git a/src/arch/x86/image/ucode.c b/src/arch/x86/image/ucode.c index 499c0a940..fd4689e00 100644 --- a/src/arch/x86/image/ucode.c +++ b/src/arch/x86/image/ucode.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <stdlib.h> #include <stdio.h> +#include <string.h> #include <assert.h> #include <errno.h> #include <ipxe/uaccess.h> @@ -149,41 +150,38 @@ static const char * ucode_vendor_name ( const union ucode_vendor_id *vendor ) { * * @v update Microcode update * @v control Microcode update control + * @v status Microcode update status * @v summary Microcode update summary * @v id APIC ID * @v optional Status report is optional * @ret rc Return status code */ -static int ucode_status ( struct ucode_update *update, - struct ucode_control *control, +static int ucode_status ( const struct ucode_update *update, + const struct ucode_control *control, + const struct ucode_status *status, struct ucode_summary *summary, unsigned int id, int optional ) { - struct ucode_status status; struct ucode_descriptor *desc; /* Sanity check */ assert ( id <= control->apic_max ); - /* Read status report */ - copy_from_user ( &status, phys_to_user ( control->status ), - ( id * sizeof ( status ) ), sizeof ( status ) ); - /* Ignore empty optional status reports */ - if ( optional && ( ! status.signature ) ) + if ( optional && ( ! status->signature ) ) return 0; DBGC ( update, "UCODE %#08x signature %#08x ucode %#08x->%#08x\n", - id, status.signature, status.before, status.after ); + id, status->signature, status->before, status->after ); /* Check CPU signature */ - if ( ! status.signature ) { + if ( ! status->signature ) { DBGC2 ( update, "UCODE %#08x has no signature\n", id ); return -ENOENT; } /* Check APIC ID is correct */ - if ( status.id != id ) { + if ( status->id != id ) { DBGC ( update, "UCODE %#08x wrong APIC ID %#08x\n", - id, status.id ); + id, status->id ); return -EINVAL; } @@ -195,29 +193,29 @@ static int ucode_status ( struct ucode_update *update, } /* Check microcode was not downgraded */ - if ( status.after < status.before ) { + if ( status->after < status->before ) { DBGC ( update, "UCODE %#08x was downgraded %#08x->%#08x\n", - id, status.before, status.after ); + id, status->before, status->after ); return -ENOTTY; } /* Check that expected updates (if any) were applied */ for ( desc = update->desc ; desc->signature ; desc++ ) { - if ( ( desc->signature == status.signature ) && - ( status.after < desc->version ) ) { + if ( ( desc->signature == status->signature ) && + ( status->after < desc->version ) ) { DBGC ( update, "UCODE %#08x failed update %#08x->%#08x " - "(wanted %#08x)\n", id, status.before, - status.after, desc->version ); + "(wanted %#08x)\n", id, status->before, + status->after, desc->version ); return -EIO; } } /* Update summary */ summary->count++; - if ( status.before < summary->low ) - summary->low = status.before; - if ( status.after > summary->high ) - summary->high = status.after; + if ( status->before < summary->low ) + summary->low = status->before; + if ( status->after > summary->high ) + summary->high = status->after; return 0; } @@ -231,13 +229,13 @@ static int ucode_status ( struct ucode_update *update, * @ret rc Return status code */ static int ucode_update_all ( struct image *image, - struct ucode_update *update, + const struct ucode_update *update, struct ucode_summary *summary ) { struct ucode_control control; struct ucode_vendor *vendor; - userptr_t status; + struct ucode_status *status; unsigned int max; - unsigned int i; + unsigned int id; size_t len; int rc; @@ -248,7 +246,7 @@ static int ucode_update_all ( struct image *image, /* Allocate status reports */ max = mp_max_cpuid(); - len = ( ( max + 1 ) * sizeof ( struct ucode_status ) ); + len = ( ( max + 1 ) * sizeof ( *status ) ); status = umalloc ( len ); if ( ! status ) { DBGC ( image, "UCODE %s could not allocate %d status reports\n", @@ -256,12 +254,12 @@ static int ucode_update_all ( struct image *image, rc = -ENOMEM; goto err_alloc; } - memset_user ( status, 0, 0, len ); + memset ( status, 0, len ); /* Construct control structure */ memset ( &control, 0, sizeof ( control ) ); control.desc = virt_to_phys ( update->desc ); - control.status = user_to_phys ( status, 0 ); + control.status = virt_to_phys ( status ); vendor = update->vendor; if ( vendor ) { control.ver_clear = vendor->ver_clear; @@ -274,8 +272,9 @@ static int ucode_update_all ( struct image *image, /* Update microcode on boot processor */ mp_exec_boot ( ucode_update, &control ); - if ( ( rc = ucode_status ( update, &control, summary, - mp_boot_cpuid(), 0 ) ) != 0 ) { + id = mp_boot_cpuid(); + if ( ( rc = ucode_status ( update, &control, &status[id], + summary, id, 0 ) ) != 0 ) { DBGC ( image, "UCODE %s failed on boot processor: %s\n", image->name, strerror ( rc ) ); goto err_boot; @@ -293,9 +292,9 @@ static int ucode_update_all ( struct image *image, /* Check status reports */ summary->count = 0; - for ( i = 0 ; i <= max ; i++ ) { - if ( ( rc = ucode_status ( update, &control, summary, - i, 1 ) ) != 0 ) { + for ( id = 0 ; id <= max ; id++ ) { + if ( ( rc = ucode_status ( update, &control, &status[id], + summary, id, 1 ) ) != 0 ) { goto err_status; } } @@ -359,24 +358,22 @@ static void ucode_describe ( struct image *image, size_t start, * @ret rc Return status code */ static int ucode_verify ( struct image *image, size_t start, size_t len ) { - uint32_t checksum = 0; - uint32_t dword; - size_t offset; + const uint32_t *dword; + uint32_t checksum; + unsigned int count; /* Check length is a multiple of dwords */ - if ( ( len % sizeof ( dword ) ) != 0 ) { + if ( ( len % sizeof ( *dword ) ) != 0 ) { DBGC ( image, "UCODE %s+%#04zx invalid length %#zx\n", image->name, start, len ); return -EINVAL; } + dword = ( image->data + start ); /* Calculate checksum */ - for ( offset = start ; len ; - offset += sizeof ( dword ), len -= sizeof ( dword ) ) { - copy_from_user ( &dword, image->data, offset, - sizeof ( dword ) ); - checksum += dword; - } + count = ( len / sizeof ( *dword ) ); + for ( checksum = 0 ; count ; count-- ) + checksum += *(dword++); if ( checksum != 0 ) { DBGC ( image, "UCODE %s+%#04zx bad checksum %#08x\n", image->name, start, checksum ); @@ -396,9 +393,9 @@ static int ucode_verify ( struct image *image, size_t start, size_t len ) { */ static int ucode_parse_intel ( struct image *image, size_t start, struct ucode_update *update ) { - struct intel_ucode_header hdr; - struct intel_ucode_ext_header exthdr; - struct intel_ucode_ext ext; + const struct intel_ucode_header *hdr; + const struct intel_ucode_ext_header *exthdr; + const struct intel_ucode_ext *ext; struct ucode_descriptor desc; size_t remaining; size_t offset; @@ -409,27 +406,27 @@ static int ucode_parse_intel ( struct image *image, size_t start, /* Read header */ remaining = ( image->len - start ); - if ( remaining < sizeof ( hdr ) ) { + if ( remaining < sizeof ( *hdr ) ) { DBGC ( image, "UCODE %s+%#04zx too small for Intel header\n", image->name, start ); return -ENOEXEC; } - copy_from_user ( &hdr, image->data, start, sizeof ( hdr ) ); + hdr = ( image->data + start ); /* Determine lengths */ - data_len = hdr.data_len; + data_len = hdr->data_len; if ( ! data_len ) data_len = INTEL_UCODE_DATA_LEN; - len = hdr.len; + len = hdr->len; if ( ! len ) - len = ( sizeof ( hdr ) + data_len ); + len = ( sizeof ( *hdr ) + data_len ); /* Verify a selection of fields */ - if ( ( hdr.hver != INTEL_UCODE_HVER ) || - ( hdr.lver != INTEL_UCODE_LVER ) || - ( len < sizeof ( hdr ) ) || + if ( ( hdr->hver != INTEL_UCODE_HVER ) || + ( hdr->lver != INTEL_UCODE_LVER ) || + ( len < sizeof ( *hdr ) ) || ( len > remaining ) || - ( data_len > ( len - sizeof ( hdr ) ) ) || + ( data_len > ( len - sizeof ( *hdr ) ) ) || ( ( data_len % sizeof ( uint32_t ) ) != 0 ) || ( ( len % INTEL_UCODE_ALIGN ) != 0 ) ) { DBGC2 ( image, "UCODE %s+%#04zx is not an Intel update\n", @@ -444,48 +441,46 @@ static int ucode_parse_intel ( struct image *image, size_t start, return rc; /* Populate descriptor */ - desc.signature = hdr.signature; - desc.version = hdr.version; - desc.address = user_to_phys ( image->data, - ( start + sizeof ( hdr ) ) ); + desc.signature = hdr->signature; + desc.version = hdr->version; + desc.address = ( virt_to_phys ( image->data ) + start + + sizeof ( *hdr ) ); /* Add non-extended descriptor, if applicable */ - ucode_describe ( image, start, &ucode_intel, &desc, hdr.platforms, + ucode_describe ( image, start, &ucode_intel, &desc, hdr->platforms, update ); /* Construct extended descriptors, if applicable */ - offset = ( sizeof ( hdr ) + data_len ); - if ( offset <= ( len - sizeof ( exthdr ) ) ) { + offset = ( sizeof ( *hdr ) + data_len ); + if ( offset <= ( len - sizeof ( *exthdr ) ) ) { /* Read extended header */ - copy_from_user ( &exthdr, image->data, ( start + offset ), - sizeof ( exthdr ) ); - offset += sizeof ( exthdr ); + exthdr = ( image->data + start + offset ); + offset += sizeof ( *exthdr ); /* Read extended signatures */ - for ( i = 0 ; i < exthdr.count ; i++ ) { + for ( i = 0 ; i < exthdr->count ; i++ ) { /* Read extended signature */ - if ( offset > ( len - sizeof ( ext ) ) ) { + if ( offset > ( len - sizeof ( *ext ) ) ) { DBGC ( image, "UCODE %s+%#04zx extended " "signature overrun\n", image->name, start ); return -EINVAL; } - copy_from_user ( &ext, image->data, ( start + offset ), - sizeof ( ext ) ); - offset += sizeof ( ext ); + ext = ( image->data + start + offset ); + offset += sizeof ( *ext ); /* Avoid duplicating non-extended descriptor */ - if ( ( ext.signature == hdr.signature ) && - ( ext.platforms == hdr.platforms ) ) { + if ( ( ext->signature == hdr->signature ) && + ( ext->platforms == hdr->platforms ) ) { continue; } /* Construct descriptor, if applicable */ - desc.signature = ext.signature; + desc.signature = ext->signature; ucode_describe ( image, start, &ucode_intel, &desc, - ext.platforms, update ); + ext->platforms, update ); } } @@ -502,10 +497,10 @@ static int ucode_parse_intel ( struct image *image, size_t start, */ static int ucode_parse_amd ( struct image *image, size_t start, struct ucode_update *update ) { - struct amd_ucode_header hdr; - struct amd_ucode_equivalence equiv; - struct amd_ucode_patch_header phdr; - struct amd_ucode_patch patch; + const struct amd_ucode_header *hdr; + const struct amd_ucode_equivalence *equiv; + const struct amd_ucode_patch_header *phdr; + const struct amd_ucode_patch *patch; struct ucode_descriptor desc; size_t remaining; size_t offset; @@ -515,91 +510,85 @@ static int ucode_parse_amd ( struct image *image, size_t start, /* Read header */ remaining = ( image->len - start ); - if ( remaining < sizeof ( hdr ) ) { + if ( remaining < sizeof ( *hdr ) ) { DBGC ( image, "UCODE %s+%#04zx too small for AMD header\n", image->name, start ); return -ENOEXEC; } - copy_from_user ( &hdr, image->data, start, sizeof ( hdr ) ); + hdr = ( image->data + start ); /* Check header */ - if ( hdr.magic != AMD_UCODE_MAGIC ) { + if ( hdr->magic != AMD_UCODE_MAGIC ) { DBGC2 ( image, "UCODE %s+%#04zx is not an AMD update\n", image->name, start ); return -ENOEXEC; } DBGC2 ( image, "UCODE %s+%#04zx is an AMD update\n", image->name, start ); - if ( hdr.type != AMD_UCODE_EQUIV_TYPE ) { + if ( hdr->type != AMD_UCODE_EQUIV_TYPE ) { DBGC ( image, "UCODE %s+%#04zx unsupported equivalence table " - "type %d\n", image->name, start, hdr.type ); + "type %d\n", image->name, start, hdr->type ); return -ENOTSUP; } - if ( hdr.len > ( remaining - sizeof ( hdr ) ) ) { + if ( hdr->len > ( remaining - sizeof ( *hdr ) ) ) { DBGC ( image, "UCODE %s+%#04zx truncated equivalence table\n", image->name, start ); return -EINVAL; } /* Count number of equivalence table entries */ - offset = sizeof ( hdr ); - for ( count = 0 ; offset < ( sizeof ( hdr ) + hdr.len ) ; - count++, offset += sizeof ( equiv ) ) { - copy_from_user ( &equiv, image->data, ( start + offset ), - sizeof ( equiv ) ); - if ( ! equiv.signature ) + offset = sizeof ( *hdr ); + equiv = ( image->data + start + offset ); + for ( count = 0 ; offset < ( sizeof ( *hdr ) + hdr->len ) ; + count++, offset += sizeof ( *equiv ) ) { + if ( ! equiv[count].signature ) break; } DBGC2 ( image, "UCODE %s+%#04zx has %d equivalence table entries\n", image->name, start, count ); /* Parse available updates */ - offset = ( sizeof ( hdr ) + hdr.len ); + offset = ( sizeof ( *hdr ) + hdr->len ); used = 0; while ( used < count ) { /* Read patch header */ - if ( ( offset + sizeof ( phdr ) ) > remaining ) { + if ( ( offset + sizeof ( *phdr ) ) > remaining ) { DBGC ( image, "UCODE %s+%#04zx truncated patch " "header\n", image->name, start ); return -EINVAL; } - copy_from_user ( &phdr, image->data, ( start + offset ), - sizeof ( phdr ) ); - offset += sizeof ( phdr ); + phdr = ( image->data + start + offset ); + offset += sizeof ( *phdr ); /* Validate patch header */ - if ( phdr.type != AMD_UCODE_PATCH_TYPE ) { + if ( phdr->type != AMD_UCODE_PATCH_TYPE ) { DBGC ( image, "UCODE %s+%#04zx unsupported patch type " - "%d\n", image->name, start, phdr.type ); + "%d\n", image->name, start, phdr->type ); return -ENOTSUP; } - if ( phdr.len < sizeof ( patch ) ) { + if ( phdr->len < sizeof ( *patch ) ) { DBGC ( image, "UCODE %s+%#04zx underlength patch\n", image->name, start ); return -EINVAL; } - if ( phdr.len > ( remaining - offset ) ) { + if ( phdr->len > ( remaining - offset ) ) { DBGC ( image, "UCODE %s+%#04zx truncated patch\n", image->name, start ); return -EINVAL; } /* Read patch and construct descriptor */ - copy_from_user ( &patch, image->data, ( start + offset ), - sizeof ( patch ) ); - desc.version = patch.version; - desc.address = user_to_phys ( image->data, ( start + offset ) ); - offset += phdr.len; + patch = ( image->data + start + offset ); + desc.version = patch->version; + desc.address = ( virt_to_phys ( image->data ) + + start + offset ); + offset += phdr->len; /* Parse equivalence table to find matching signatures */ for ( i = 0 ; i < count ; i++ ) { - copy_from_user ( &equiv, image->data, - ( start + sizeof ( hdr ) + - ( i * ( sizeof ( equiv ) ) ) ), - sizeof ( equiv ) ); - if ( patch.id == equiv.id ) { - desc.signature = equiv.signature; + if ( patch->id == equiv[i].id ) { + desc.signature = equiv[i].signature; ucode_describe ( image, start, &ucode_amd, &desc, 0, update ); used++; @@ -744,19 +733,19 @@ static int ucode_exec ( struct image *image ) { * @ret rc Return status code */ static int ucode_probe ( struct image *image ) { - union { + const union { struct intel_ucode_header intel; struct amd_ucode_header amd; - } header; + } *header; /* Sanity check */ - if ( image->len < sizeof ( header ) ) { + if ( image->len < sizeof ( *header ) ) { DBGC ( image, "UCODE %s too short\n", image->name ); return -ENOEXEC; } /* Read first microcode image header */ - copy_from_user ( &header, image->data, 0, sizeof ( header ) ); + header = image->data; /* Check for something that looks like an Intel update * @@ -769,19 +758,19 @@ static int ucode_probe ( struct image *image ) { * the image, and do not want to have a microcode image * erroneously treated as a PXE boot executable. */ - if ( ( header.intel.hver == INTEL_UCODE_HVER ) && - ( header.intel.lver == INTEL_UCODE_LVER ) && - ( ( header.intel.date.century == 0x19 ) || - ( ( header.intel.date.century >= 0x20 ) && - ( header.intel.date.century <= 0x29 ) ) ) ) { + if ( ( header->intel.hver == INTEL_UCODE_HVER ) && + ( header->intel.lver == INTEL_UCODE_LVER ) && + ( ( header->intel.date.century == 0x19 ) || + ( ( header->intel.date.century >= 0x20 ) && + ( header->intel.date.century <= 0x29 ) ) ) ) { DBGC ( image, "UCODE %s+%#04zx looks like an Intel update\n", image->name, ( ( size_t ) 0 ) ); return 0; } /* Check for AMD update signature */ - if ( ( header.amd.magic == AMD_UCODE_MAGIC ) && - ( header.amd.type == AMD_UCODE_EQUIV_TYPE ) ) { + if ( ( header->amd.magic == AMD_UCODE_MAGIC ) && + ( header->amd.type == AMD_UCODE_EQUIV_TYPE ) ) { DBGC ( image, "UCODE %s+%#04zx looks like an AMD update\n", image->name, ( ( size_t ) 0 ) ); return 0; |
