Browse Source

[bzimage] Report exact initrd length via bzImage header

iPXE currently pads initrd images to a multiple of 4kB and inserts
zero padding between images, as required by some versions of the Linux
kernel.  The overall length reported via the ramdisk_size field in the
bzImage header includes this zero padding.

This causes problems when using memdisk to load a gzip-compressed disk
image.  memdisk treats the ramdisk_size field as containing the exact
length of the initrd image, and uses this length to locate the 8-byte
gzip footer.  This will generally cause memdisk to fail to decompress
the disk image.

Fix by reporting the exact length of the initrd image set, including
any padding inserted between images but excluding any padding added at
the end of the final image.

Reported-by: Levente LEVAI <levail@aviatronic.hu>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
0fac055119
1 changed files with 28 additions and 14 deletions
  1. 28
    14
      src/arch/i386/image/bzimage.c

+ 28
- 14
src/arch/i386/image/bzimage.c View File

346
 	}
346
 	}
347
 }
347
 }
348
 
348
 
349
+/**
350
+ * Align initrd length
351
+ *
352
+ * @v len		Length
353
+ * @ret len		Length rounded up to INITRD_ALIGN
354
+ */
355
+static inline size_t bzimage_align ( size_t len ) {
356
+
357
+	return ( ( len + INITRD_ALIGN - 1 ) & ~( INITRD_ALIGN - 1 ) );
358
+}
359
+
349
 /**
360
 /**
350
  * Load initrd
361
  * Load initrd
351
  *
362
  *
352
  * @v image		bzImage image
363
  * @v image		bzImage image
353
  * @v initrd		initrd image
364
  * @v initrd		initrd image
354
  * @v address		Address at which to load, or UNULL
365
  * @v address		Address at which to load, or UNULL
355
- * @ret len		Length of loaded image, rounded up to INITRD_ALIGN
366
+ * @ret len		Length of loaded image, excluding zero-padding
356
  */
367
  */
357
 static size_t bzimage_load_initrd ( struct image *image,
368
 static size_t bzimage_load_initrd ( struct image *image,
358
 				    struct image *initrd,
369
 				    struct image *initrd,
408
 	}
419
 	}
409
 	offset += initrd->len;
420
 	offset += initrd->len;
410
 
421
 
411
-	/* Round up to multiple of INITRD_ALIGN and zero-pad */
422
+	/* Zero-pad to next INITRD_ALIGN boundary */
412
 	pad_len = ( ( -offset ) & ( INITRD_ALIGN - 1 ) );
423
 	pad_len = ( ( -offset ) & ( INITRD_ALIGN - 1 ) );
413
 	if ( address )
424
 	if ( address )
414
 		memset_user ( address, offset, 0, pad_len );
425
 		memset_user ( address, offset, 0, pad_len );
415
-	offset += pad_len;
416
 
426
 
417
 	return offset;
427
 	return offset;
418
 }
428
 }
440
 
450
 
441
 		/* Calculate length */
451
 		/* Calculate length */
442
 		len += bzimage_load_initrd ( image, initrd, UNULL );
452
 		len += bzimage_load_initrd ( image, initrd, UNULL );
453
+		len = bzimage_align ( len );
443
 
454
 
444
 		DBGC ( image, "bzImage %p initrd %p from [%#08lx,%#08lx)%s%s\n",
455
 		DBGC ( image, "bzImage %p initrd %p from [%#08lx,%#08lx)%s%s\n",
445
 		       image, initrd, user_to_phys ( initrd->data, 0 ),
456
 		       image, initrd, user_to_phys ( initrd->data, 0 ),
487
 	struct image *other;
498
 	struct image *other;
488
 	userptr_t top;
499
 	userptr_t top;
489
 	userptr_t dest;
500
 	userptr_t dest;
501
+	size_t offset;
490
 	size_t len;
502
 	size_t len;
491
 
503
 
492
 	/* Reshuffle initrds into desired order */
504
 	/* Reshuffle initrds into desired order */
505
 		return;
517
 		return;
506
 
518
 
507
 	/* Find highest usable address */
519
 	/* Find highest usable address */
508
-	top = userptr_add ( highest->data,
509
-			    ( ( highest->len + INITRD_ALIGN - 1 ) &
510
-			      ~( INITRD_ALIGN - 1 ) ) );
520
+	top = userptr_add ( highest->data, bzimage_align ( highest->len ) );
511
 	if ( user_to_phys ( top, 0 ) > bzimg->mem_limit )
521
 	if ( user_to_phys ( top, 0 ) > bzimg->mem_limit )
512
 		top = phys_to_user ( bzimg->mem_limit );
522
 		top = phys_to_user ( bzimg->mem_limit );
513
 	DBGC ( image, "bzImage %p loading initrds from %#08lx downwards\n",
523
 	DBGC ( image, "bzImage %p loading initrds from %#08lx downwards\n",
519
 		/* Calculate cumulative length of following
529
 		/* Calculate cumulative length of following
520
 		 * initrds (including padding).
530
 		 * initrds (including padding).
521
 		 */
531
 		 */
522
-		len = 0;
532
+		offset = 0;
523
 		for_each_image ( other ) {
533
 		for_each_image ( other ) {
524
 			if ( other == initrd )
534
 			if ( other == initrd )
525
-				len = 0;
526
-			len += bzimage_load_initrd ( image, other, UNULL );
535
+				offset = 0;
536
+			offset += bzimage_load_initrd ( image, other, UNULL );
537
+			offset = bzimage_align ( offset );
527
 		}
538
 		}
528
 
539
 
529
 		/* Load initrd at this address */
540
 		/* Load initrd at this address */
530
-		dest = userptr_add ( top, -len );
531
-		bzimage_load_initrd ( image, initrd, dest );
541
+		dest = userptr_add ( top, -offset );
542
+		len = bzimage_load_initrd ( image, initrd, dest );
532
 
543
 
533
 		/* Record initrd location */
544
 		/* Record initrd location */
534
-		if ( ! bzimg->ramdisk_image ) {
545
+		if ( ! bzimg->ramdisk_image )
535
 			bzimg->ramdisk_image = user_to_phys ( dest, 0 );
546
 			bzimg->ramdisk_image = user_to_phys ( dest, 0 );
536
-			bzimg->ramdisk_size = len;
537
-		}
547
+		bzimg->ramdisk_size = ( user_to_phys ( dest, len ) -
548
+					bzimg->ramdisk_image );
538
 	}
549
 	}
550
+	DBGC ( image, "bzImage %p initrds at [%#08lx,%#08lx)\n",
551
+	       image, bzimg->ramdisk_image,
552
+	       ( bzimg->ramdisk_image + bzimg->ramdisk_size ) );
539
 }
553
 }
540
 
554
 
541
 /**
555
 /**

Loading…
Cancel
Save