Browse Source

[romprefix] Split PMM allocations for image source and decompression area

Some BIOSes (at least some AMI BIOSes) tend to refuse to allocate a
single area large enough to hold both the iPXE image source and the
temporary decompression area, despite promising a largest available
PMM memory block of several megabytes.  This causes ROM image
shrinking to fail on these BIOSes, with undesirable consequences:
other option ROMs may be disabled due to shortage of option ROM space,
and the iPXE ROM may itself be corrupted by a further BIOS bug (again,
observed on an AMI BIOS) which causes large ROMs to end up overlapping
reserved areas of memory.  This can potentially render a system
unbootable via any means.

Increase the chances of a successful PMM allocation by dropping the
alignment requirement (which is redundant now that we can enable A20
from within the prefix); this allows us to reduce the allocation size
from 2MB down to only the required size.

Increase the chances still further by using two separate allocations:
one to hold the image source (i.e. the copy of the ROM before being
shrunk) and the other to act as the decompression area.  This allows
ROM image shrinking to take place even on systems that fail to
allocate enough memory for the temporary decompression area.

Improve the behaviour of iPXE in systems with multiple iPXE ROMs by
sharing PMM allocations where possible.  Image source areas can be
shared with any iPXE ROMs with a matching build identifier, and the
temporary decompression area can be shared with any iPXE ROMs with the
same uncompressed size (rounded up to the nearest 128kB).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
c97079710f
1 changed files with 119 additions and 51 deletions
  1. 119
    51
      src/arch/i386/prefix/romprefix.S

+ 119
- 51
src/arch/i386/prefix/romprefix.S View File

@@ -16,7 +16,14 @@ FILE_LICENCE ( GPL2_OR_LATER )
16 16
 #define STACK_MAGIC ( 'L' + ( 'R' << 8 ) + ( 'E' << 16 ) + ( 'T' << 24 ) )
17 17
 #define PNP_GET_BBS_VERSION 0x60
18 18
 #define PMM_ALLOCATE 0x0000
19
-#define PMM_DEALLOCATE 0x0002
19
+#define PMM_FIND 0x0001
20
+#define PMM_HANDLE_BASE ( ( ( 'F' - 'A' + 1 ) << 26 ) + \
21
+			  ( ( 'E' - 'A' + 1 ) << 21 ) + \
22
+			  ( ( 'N' - 'A' + 1 ) << 16 ) )
23
+#define PMM_HANDLE_BASE_IMAGE_SOURCE \
24
+	( PMM_HANDLE_BASE | 0x00001000 )
25
+#define PMM_HANDLE_BASE_DECOMPRESS_TO \
26
+	( PMM_HANDLE_BASE | 0x00002000 )
20 27
 
21 28
 /* ROM banner timeout.  Based on the configurable BANNER_TIMEOUT in
22 29
  * config.h, but converted to a number of (18Hz) timer ticks, and
@@ -310,65 +317,44 @@ pmm_scan:
310 317
 	movw	$init_message_pmm, %si
311 318
 	xorw	%di, %di
312 319
 	call	print_message
313
-	/* We have PMM and so a 1kB stack: preserve upper register halves */
320
+	/* We have PMM and so a 1kB stack: preserve whole registers */
314 321
 	pushal
315
-	/* Calculate required allocation size in %esi */
316
-	movzbl	romheader_size, %eax
317
-	shll	$9, %eax
318
-	addl	$_textdata_memsz, %eax
319
-	orw	$0xffff, %ax	/* Ensure allocation size is at least 64kB */
320
-	bsrl	%eax, %ecx
321
-	subw	$15, %cx	/* Round up and convert to 64kB count */
322
-	movw	$1, %si
323
-	shlw	%cl, %si
324
-pmm_loop:
325
-	/* Try to allocate block via PMM */
326
-	pushw	$0x0006		/* Aligned, extended memory */
327
-	pushl	$0xffffffff	/* No handle */
328
-	movzwl	%si, %eax
329
-	shll	$12, %eax
330
-	pushl	%eax		/* Allocation size in paragraphs */
331
-	pushw	$PMM_ALLOCATE
332
-	lcall	*%es:7
333
-	addw	$12, %sp
334
-	/* Abort if allocation fails */
335
-	testw	%dx, %dx	/* %ax==0 even on success, since align>=64kB */
336
-	jz	pmm_fail
337
-	/* If block has A20==1, free block and try again with twice
338
-	 * the allocation size (and hence alignment).
339
-	 */
340
-	testw	$0x0010, %dx
341
-	jz	got_pmm
342
-	pushw	%dx
343
-	pushw	$0
344
-	pushw	$PMM_DEALLOCATE
345
-	lcall	*%es:7
346
-	addw	$6, %sp
347
-	addw	%si, %si
348
-	jmp	pmm_loop
349
-got_pmm: /* PMM allocation succeeded */
350
-	movw	%dx, ( image_source + 2 )
351
-	movw	%dx, %ax
352
-	xorw	%di, %di
353
-	call	print_hex_word
354
-	movb	$( '@' ), %al
355
-	call	print_character
356
-	movw	%si, %ax
357
-	call	print_hex_byte
358
-	/* Copy ROM to PMM block */
322
+	/* Allocate image source PMM block */
323
+	movzbl	romheader_size, %ecx
324
+	shll	$5, %ecx
325
+	movl	$PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx
326
+	movw	$get_pmm_image_source, %bp
327
+	call	get_pmm
328
+	movl	%esi, image_source
329
+	jc	1f
330
+	/* Copy ROM to image source PMM block */
331
+	pushw	%es
359 332
 	xorw	%ax, %ax
360 333
 	movw	%ax, %es
361
-	movl	image_source, %edi
334
+	movl	%esi, %edi
362 335
 	xorl	%esi, %esi
363 336
 	movzbl	romheader_size, %ecx
364 337
 	shll	$9, %ecx
365 338
 	addr32 rep movsb	/* PMM presence implies flat real mode */
366
-	movl	%edi, decompress_to
339
+	popw	%es
367 340
 	/* Shrink ROM */
368 341
 	movb	shrunk_rom_size, %al
369 342
 	movb	%al, romheader_size
370
-pmm_fail:
371
-	/* Restore upper register halves */
343
+1:	/* Allocate decompression PMM block.  Round up the size to the
344
+	 * nearest 128kB and use the size within the PMM handle; this
345
+	 * allows the same decompression area to be shared between
346
+	 * multiple iPXE ROMs even with differing build IDs
347
+	 */
348
+	movl	$_textdata_memsz_pgh, %ecx
349
+	addl	$0x00001fff, %ecx
350
+	andl	$0xffffe000, %ecx
351
+	movl	%ecx, %ebx
352
+	shrw	$12, %bx
353
+	orl	$PMM_HANDLE_BASE_DECOMPRESS_TO, %ebx
354
+	movw	$get_pmm_decompress_to, %bp
355
+	call	get_pmm
356
+	movl	%esi, decompress_to
357
+	/* Restore registers */
372 358
 	popal
373 359
 no_pmm:
374 360
 
@@ -436,6 +422,88 @@ no_pmm:
436 422
 	lret
437 423
 	.size init, . - init
438 424
 
425
+/* Attempt to find or allocate PMM block
426
+ *
427
+ * Parameters:
428
+ *  %ecx : size of block to allocate, in paragraphs
429
+ *  %ebx : PMM handle base
430
+ *  %bp : routine to check acceptability of found blocks
431
+ *  %es:0000 : PMM structure
432
+ * Returns:
433
+ *  %ebx : PMM handle
434
+ *  %esi : allocated block address, or zero (with CF set) if allocation failed
435
+ */
436
+get_pmm:
437
+	/* Preserve registers */
438
+	pushl	%eax
439
+	pushw	%di
440
+	movw	$' ', %di
441
+get_pmm_find:
442
+	/* Try to find existing block */
443
+	pushl	%ebx		/* PMM handle */
444
+	pushw	$PMM_FIND
445
+	lcall	*%es:7
446
+	addw	$6, %sp
447
+	pushw	%dx
448
+	pushw	%ax
449
+	popl	%esi
450
+	testl	%esi, %esi
451
+	jz	get_pmm_allocate
452
+	/* Block found - check acceptability */
453
+	call	*%bp
454
+	jnc	get_pmm_done
455
+	/* Block not acceptable - increment handle and retry */
456
+	incl	%ebx
457
+	jmp	get_pmm_find
458
+get_pmm_allocate:
459
+	/* Block not found - try to allocate new block */
460
+	pushw	$0x0002		/* Extended memory */
461
+	pushl	%ebx		/* PMM handle */
462
+	pushl	%ecx		/* Length */
463
+	pushw	$PMM_ALLOCATE
464
+	lcall	*%es:7
465
+	addw	$12, %sp
466
+	pushw	%dx
467
+	pushw	%ax
468
+	popl	%esi
469
+	movw	$'+', %di	/* Indicate allocation attempt */
470
+	testl	%esi, %esi
471
+	jnz	get_pmm_done
472
+	stc
473
+get_pmm_done:
474
+	/* Print block address */
475
+	pushfw
476
+	movw	%di, %ax
477
+	xorw	%di, %di
478
+	call	print_character
479
+	movl	%esi, %eax
480
+	call	print_hex_dword
481
+	popfw
482
+	/* Restore registers and return */
483
+	popw	%di
484
+	popl	%eax
485
+	ret
486
+	.size	get_pmm, . - get_pmm
487
+
488
+	/* Check acceptability of image source block */
489
+get_pmm_image_source:
490
+	pushw	%es
491
+	xorw	%ax, %ax
492
+	movw	%ax, %es
493
+	movl	build_id, %eax
494
+	cmpl	%es:build_id(%esi), %eax
495
+	je	1f
496
+	stc
497
+1:	popw	%es
498
+	ret
499
+	.size	get_pmm_image_source, . - get_pmm_image_source
500
+
501
+	/* Check acceptability of decompression block */
502
+get_pmm_decompress_to:
503
+	clc
504
+	ret
505
+	.size	get_pmm_decompress_to, . - get_pmm_decompress_to
506
+
439 507
 /*
440 508
  * Note to hardware vendors:
441 509
  *
@@ -456,7 +524,7 @@ init_message:
456 524
 	.ascii	"\n"
457 525
 	.ascii	PRODUCT_NAME
458 526
 	.ascii	"\n"
459
-	.asciz	"iPXE (http://ipxe.org) - "
527
+	.asciz	"iPXE (http://ipxe.org) "
460 528
 	.size	init_message, . - init_message
461 529
 init_message_pci:
462 530
 	.asciz	" PCI"

Loading…
Cancel
Save