summaryrefslogtreecommitdiffstats
path: root/src/arch
diff options
context:
space:
mode:
authorMichael Brown2007-07-31 19:09:18 +0200
committerMichael Brown2007-07-31 19:09:18 +0200
commitc5d911406460467f2242ee7bcbffe063038fea64 (patch)
treeb85da032eb759f0b0e41479eba16869c5ff007a3 /src/arch
parentAdded support for draft version of the AoE Boot Firmware Table. (diff)
downloadipxe-c5d911406460467f2242ee7bcbffe063038fea64.tar.gz
ipxe-c5d911406460467f2242ee7bcbffe063038fea64.tar.xz
ipxe-c5d911406460467f2242ee7bcbffe063038fea64.zip
Allow loading of multiple initramfs images.
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/i386/image/bzimage.c111
1 files changed, 61 insertions, 50 deletions
diff --git a/src/arch/i386/image/bzimage.c b/src/arch/i386/image/bzimage.c
index 3a3e82ef..161d2675 100644
--- a/src/arch/i386/image/bzimage.c
+++ b/src/arch/i386/image/bzimage.c
@@ -33,7 +33,6 @@
#include <gpxe/uaccess.h>
#include <gpxe/image.h>
#include <gpxe/segment.h>
-#include <gpxe/memmap.h>
#include <gpxe/init.h>
#include <gpxe/initrd.h>
@@ -168,58 +167,77 @@ static int bzimage_set_cmdline ( struct image *image,
}
/**
- * Load initrd, if any
+ * Load initrds, if any
*
* @v image bzImage image
* @v exec_ctx Execution context
* @ret rc Return status code
*/
static int bzimage_load_initrd ( struct image *image,
- struct bzimage_exec_context *exec_ctx,
- struct image *initrd ) {
- physaddr_t start = user_to_phys ( initrd->data, 0 );
+ struct bzimage_exec_context *exec_ctx ) {
+ struct image *initrd;
+ size_t initrd_len;
+ size_t total_len = 0;
+ size_t offset = 0;
+ physaddr_t start;
int rc;
- DBGC ( image, "bzImage %p loading initrd %p (%s)\n",
- image, initrd, initrd->name );
-
- /* Find a suitable start address */
- if ( ( start + initrd->len ) <= exec_ctx->mem_limit ) {
- /* Just use initrd in situ */
- DBGC ( image, "bzImage %p using initrd as [%lx,%lx)\n",
- image, start, ( start + initrd->len ) );
- } else {
- for ( ; ; start -= 0x100000 ) {
- /* Check that we're not going to overwrite the
- * kernel itself. This check isn't totally
- * accurate, but errs on the side of caution.
- */
- if ( start <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
- DBGC ( image, "bzImage %p could not find a "
- "location for initrd\n", image );
- return -ENOBUFS;
- }
- /* Check that we are within the kernel's range */
- if ( ( start + initrd->len ) > exec_ctx->mem_limit )
- continue;
- /* Prepare and verify segment */
- if ( ( rc = prep_segment ( phys_to_user ( start ),
- initrd->len,
- initrd->len ) ) != 0 )
- continue;
- /* Copy to segment */
- DBGC ( image, "bzImage %p relocating initrd to "
- "[%lx,%lx)\n", image, start,
- ( start + initrd->len ) );
- memcpy_user ( phys_to_user ( start ), 0,
- initrd->data, 0, initrd->len );
- break;
+ /* Add up length of all initrd images */
+ for_each_image ( initrd ) {
+ if ( initrd->type != &initrd_image_type )
+ continue;
+ initrd_len = ( ( image->len + 0x0f ) & ~0x0f );
+ total_len += initrd_len;
+ }
+
+ if ( ! total_len )
+ return 0;
+
+ /* Find a suitable start address. Try 1MB boundaries,
+ * starting from the downloaded kernel image itself and
+ * working downwards until we hit an available region.
+ */
+ for ( start = ( user_to_phys ( image->data, 0 ) & ~0xfffff ) ; ;
+ start -= 0x100000 ) {
+ /* Check that we're not going to overwrite the
+ * kernel itself. This check isn't totally
+ * accurate, but errs on the side of caution.
+ */
+ if ( start <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
+ DBGC ( image, "bzImage %p could not find a location "
+ "for initrd\n", image );
+ return -ENOBUFS;
}
+ /* Check that we are within the kernel's range */
+ if ( ( start + total_len ) > exec_ctx->mem_limit )
+ continue;
+ /* Prepare and verify segment */
+ if ( ( rc = prep_segment ( phys_to_user ( start ), 0,
+ total_len ) ) != 0 )
+ continue;
+ /* Use this address */
+ break;
}
+ /* Construct initrd */
+ DBGC ( image, "bzImage %p constructing initrd at [%lx,%lx)\n",
+ image, start, ( start + total_len ) );
+ for_each_image ( initrd ) {
+ if ( initrd->type != &initrd_image_type )
+ continue;
+ initrd_len = ( ( image->len + 0x0f ) & ~0x0f );
+ DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
+ image, initrd, ( start + offset ),
+ ( start + offset + initrd->len ) );
+ memcpy_user ( phys_to_user ( start ), offset,
+ initrd->data, 0, initrd->len );
+ offset += initrd_len;
+ }
+ assert ( offset == total_len );
+
/* Record initrd location */
exec_ctx->ramdisk_image = start;
- exec_ctx->ramdisk_size = initrd->len;
+ exec_ctx->ramdisk_size = total_len;
return 0;
}
@@ -234,7 +252,6 @@ static int bzimage_exec ( struct image *image ) {
struct bzimage_exec_context exec_ctx;
struct bzimage_header bzhdr;
const char *cmdline = ( image->cmdline ? image->cmdline : "" );
- struct image *initrd;
int rc;
/* Initialise context */
@@ -262,15 +279,9 @@ static int bzimage_exec ( struct image *image ) {
if ( ( rc = bzimage_set_cmdline ( image, &exec_ctx, cmdline ) ) != 0 )
return rc;
- /* Load an initrd, if one exists */
- for_each_image ( initrd ) {
- if ( initrd->type == &initrd_image_type ) {
- if ( ( rc = bzimage_load_initrd ( image, &exec_ctx,
- initrd ) ) != 0 )
- return rc;
- break;
- }
- }
+ /* Load any initrds */
+ if ( ( rc = bzimage_load_initrd ( image, &exec_ctx ) ) != 0 )
+ return rc;
/* Update and store kernel header */
bzhdr.vid_mode = exec_ctx.vid_mode;