Browse Source

[prefix] Add .xrom prefix for a ROM that loads itself by PCI accesses

The standard option ROM format provides a header indicating the size
of the entire ROM, which the BIOS will reserve space for, load, and
call as necessary. However, this space is strictly limited to 128k for
all ROMs. gPXE ameliorates this somewhat by reserving space for itself
in high memory and relocating the majority of its code there, but on
systems prior to PCI3 enough space must still be present to load the
ROM in the first place. Even on PCI3 systems, the BIOS often limits the
size of ROM it will load to a bit over 64kB.

These space problems can be solved by providing an artificially small
size in the ROM header: just enough to let the prefix code (at the
beginning of the ROM image) be loaded by the BIOS. To the BIOS, the
gPXE ROM will appear to be only a few kilobytes; it can then load
the rest of itself by accessing the ROM directly using the PCI
interface reserved for that task.

There are a few problems with this approach. First, gPXE needs to find
an unmapped region in memory to map the ROM so it can read from it;
this is done using the crude but effective approach of scanning high
memory (over 0xF0000000) for a sufficiently large region of all-ones
(0xFF) reads. (In x86 architecture, all-ones is returned for accesses
to memory regions that no mapped device can satisfy.) This is not
provably valid in all situations, but has worked well in practice.
More importantly, this type of ROM access can only work if the PCI ROM
BAR exists at all. NICs on physical add-in PCI cards generally must
have the BAR in order for the BIOS to be able to load their ROM, but
ISA cards and LAN-on-Motherboard cards will both fail to load gPXE
using this scheme.

Due to these uncertainties, it is recommended that .xrom only be used
when a regular .rom image is infeasible due to crowded option ROM
space. However, when it works it could allow loading gPXE images
as large as a flash chip one could find - 128kB or even higher.

Signed-off-by: Marty Connor <mdc@etherboot.org>
tags/v1.0.0-rc1
Joshua Oreman 15 years ago
parent
commit
06a8398422

+ 2
- 0
src/Makefile.housekeeping View File

@@ -831,6 +831,8 @@ endif # defined(BIN)
831 831
 FINALISE_rom	= $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \
832 832
 		  -i$(IDENT) -s 0 $@
833 833
 FINALISE_hrom	= $(FINALISE_rom)
834
+FINALISE_xrom	= $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \
835
+		  -i$(IDENT) -n -s 0 $@
834 836
 
835 837
 # Some ROMs require specific flags to be passed to makerom.pl
836 838
 #

+ 2
- 0
src/arch/i386/Makefile.pcbios View File

@@ -12,6 +12,7 @@ LDFLAGS		+= -N --no-check-sections
12 12
 #
13 13
 MEDIA		+= rom
14 14
 MEDIA		+= hrom
15
+MEDIA		+= xrom
15 16
 MEDIA		+= pxe
16 17
 MEDIA		+= kpxe
17 18
 MEDIA		+= kkpxe
@@ -32,6 +33,7 @@ MEDIA		+= exe
32 33
 #
33 34
 PAD_rom		= $(PADIMG) --blksize=512 --byte=0xff $@
34 35
 PAD_hrom	= $(PAD_rom)
36
+PAD_xrom	= $(PAD_rom)
35 37
 PAD_dsk		= $(PADIMG) --blksize=512 $@
36 38
 PAD_hd		= $(PADIMG) --blksize=32768 $@
37 39
 

+ 377
- 10
src/arch/i386/prefix/romprefix.S View File

@@ -25,6 +25,19 @@ FILE_LICENCE ( GPL2_OR_LATER )
25 25
  */
26 26
 #define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
27 27
 
28
+/* We can load a ROM in two ways: have the BIOS load all of it (.rom prefix)
29
+ * or have the BIOS load a stub that loads the rest using PCI (.xrom prefix).
30
+ * The latter is not as widely supported, but allows the use of large ROMs
31
+ * on some systems with crowded option ROM space.
32
+ */
33
+
34
+#ifdef LOAD_ROM_FROM_PCI
35
+#define ROM_SIZE_VALUE	_prefix_filesz_sect /* Amount to load in BIOS */
36
+#else
37
+#define ROM_SIZE_VALUE	0		/* Load amount (before compr. fixup) */
38
+#endif
39
+
40
+
28 41
 	.text
29 42
 	.code16
30 43
 	.arch i386
@@ -33,10 +46,12 @@ FILE_LICENCE ( GPL2_OR_LATER )
33 46
 	.org	0x00
34 47
 romheader:
35 48
 	.word	0xAA55			/* BIOS extension signature */
36
-romheader_size:	.byte 0			/* Size in 512-byte blocks */
49
+romheader_size:	.byte ROM_SIZE_VALUE	/* Size in 512-byte blocks */
37 50
 	jmp	init			/* Initialisation vector */
38 51
 checksum:
39
-	.byte	0
52
+	.byte	0, 0
53
+real_size:
54
+	.word	0
40 55
 	.org	0x16
41 56
 	.word	undiheader
42 57
 	.org	0x18
@@ -44,12 +59,18 @@ checksum:
44 59
 	.org	0x1a
45 60
 	.word	pnpheader
46 61
 	.size romheader, . - romheader
47
-	
62
+
48 63
 	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
64
+#ifndef LOAD_ROM_FROM_PCI
49 65
 	.ascii	"ADDB"
50 66
 	.long	romheader_size
51 67
 	.long	512
52 68
 	.long	0
69
+#endif
70
+	.ascii	"ADDB"
71
+	.long	real_size
72
+	.long	512
73
+	.long	0
53 74
 	.previous
54 75
 
55 76
 pciheader:
@@ -61,17 +82,18 @@ pciheader:
61 82
 	.byte	0x03			/* PCI data structure revision */
62 83
 	.byte	0x02, 0x00, 0x00	/* Class code */
63 84
 pciheader_image_length:
64
-	.word	0			/* Image length */
85
+	.word	ROM_SIZE_VALUE		/* Image length */
65 86
 	.word	0x0001			/* Revision level */
66 87
 	.byte	0x00			/* Code type */
67 88
 	.byte	0x80			/* Last image indicator */
68 89
 pciheader_runtime_length:
69
-	.word	0			/* Maximum run-time image length */
90
+	.word	ROM_SIZE_VALUE		/* Maximum run-time image length */
70 91
 	.word	0x0000			/* Configuration utility code header */
71 92
 	.word	0x0000			/* DMTF CLP entry point */
72 93
 	.equ pciheader_len, . - pciheader
73 94
 	.size pciheader, . - pciheader
74
-	
95
+
96
+#ifndef LOAD_ROM_FROM_PCI
75 97
 	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
76 98
 	.ascii	"ADDW"
77 99
 	.long	pciheader_image_length
@@ -82,6 +104,7 @@ pciheader_runtime_length:
82 104
 	.long	512
83 105
 	.long	0
84 106
 	.previous
107
+#endif
85 108
 
86 109
 pnpheader:
87 110
 	.ascii	"$PnP"			/* Signature */
@@ -175,6 +198,11 @@ init:
175 198
 	call	print_message
176 199
 	call	print_pci_busdevfn
177 200
 
201
+#ifdef LOAD_ROM_FROM_PCI
202
+	/* Save PCI bus:dev.fn for later use */
203
+	movw	%ax, pci_busdevfn
204
+#endif
205
+
178 206
 	/* Fill in product name string, if possible */
179 207
 	movw	$prodstr_pci_id, %di
180 208
 	call	print_pci_busdevfn
@@ -199,6 +227,9 @@ init:
199 227
 	jne	no_pci3
200 228
 	testb	%ah, %ah
201 229
 	jnz	no_pci3
230
+#ifdef LOAD_ROM_FROM_PCI
231
+	incb	pcibios_present
232
+#endif
202 233
 	movw	$init_message_pci, %si
203 234
 	xorw	%di, %di
204 235
 	call	print_message
@@ -310,7 +341,7 @@ pmm_scan:
310 341
 	/* We have PMM and so a 1kB stack: preserve upper register halves */
311 342
 	pushal
312 343
 	/* Calculate required allocation size in %esi */
313
-	movzbl	romheader_size, %eax
344
+	movzwl	real_size, %eax
314 345
 	shll	$9, %eax
315 346
 	addl	$_textdata_memsz, %eax
316 347
 	orw	$0xffff, %ax	/* Ensure allocation size is at least 64kB */
@@ -364,7 +395,7 @@ pmm_copy:
364 395
 	movl	%edi, decompress_to
365 396
 	/* Shrink ROM */
366 397
 	movb	$_prefix_memsz_sect, romheader_size
367
-#ifdef SHRINK_WITHOUT_PMM
398
+#if defined(SHRINK_WITHOUT_PMM) || defined(LOAD_ROM_FROM_PCI)
368 399
 	jmp	pmm_done
369 400
 pmm_fail:
370 401
 	/* Print marker and copy ourselves to high memory */
@@ -379,8 +410,28 @@ pmm_fail:
379 410
 #endif
380 411
 	/* Restore upper register halves */
381 412
 	popal
413
+#if defined(LOAD_ROM_FROM_PCI)
414
+	call	load_from_pci
415
+	jc	load_err
416
+	jmp	load_ok
382 417
 no_pmm:
418
+	/* Cannot continue without PMM - print error message */
419
+	xorw	%di, %di
420
+	movw	$init_message_no_pmm, %si
421
+	call	print_message
422
+load_err:
423
+	/* Wait for five seconds to let user see message */
424
+	movw	$90, %cx
425
+1:	call	wait_for_tick
426
+	loop	1b
427
+	/* Mark environment as invalid and return */
428
+	movl	$0, decompress_to
429
+	jmp	out
383 430
 
431
+load_ok:
432
+#else
433
+no_pmm:
434
+#endif
384 435
 	/* Update checksum */
385 436
 	xorw	%bx, %bx
386 437
 	xorw	%si, %si
@@ -425,14 +476,14 @@ no_pmm:
425 476
 	movw	$init_message_done, %si
426 477
 	call	print_message
427 478
 	popf
428
-	jnz	2f
479
+	jnz	out
429 480
 	/* Ctrl-B was pressed: invoke gPXE.  The keypress will be
430 481
 	 * picked up by the initial shell prompt, and we will drop
431 482
 	 * into a shell.
432 483
 	 */
433 484
 	pushw	%cs
434 485
 	call	exec
435
-2:
486
+out:
436 487
 	/* Restore registers */
437 488
 	popw	%gs
438 489
 	popw	%fs
@@ -479,6 +530,11 @@ init_message_bbs:
479 530
 init_message_pmm:
480 531
 	.asciz	" PMM"
481 532
 	.size	init_message_pmm, . - init_message_pmm
533
+#ifdef LOAD_ROM_FROM_PCI
534
+init_message_no_pmm:
535
+	.asciz	"\nPMM required but not present!\n"
536
+	.size	init_message_no_pmm, . - init_message_no_pmm
537
+#endif
482 538
 init_message_int19:
483 539
 	.asciz	" INT19"
484 540
 	.size	init_message_int19, . - init_message_int19
@@ -504,12 +560,32 @@ image_source:
504 560
 /* Temporary decompression area
505 561
  *
506 562
  * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
563
+ * If a PCI ROM load fails, this will be set to zero.
507 564
  */
508 565
 	.globl	decompress_to
509 566
 decompress_to:
510 567
 	.long	HIGHMEM_LOADPOINT
511 568
 	.size	decompress_to, . - decompress_to
512 569
 
570
+#ifdef LOAD_ROM_FROM_PCI
571
+
572
+/* Set if the PCI BIOS is present, even <3.0 */
573
+pcibios_present:
574
+	.byte	0
575
+	.byte	0		/* for alignment */
576
+	.size	pcibios_present, . - pcibios_present
577
+
578
+/* PCI bus:device.function word
579
+ *
580
+ * Filled in by init in the .xrom case, so the remainder of the ROM
581
+ * can be located.
582
+ */
583
+pci_busdevfn:
584
+	.word	0
585
+	.size	pci_busdevfn, . - pci_busdevfn
586
+
587
+#endif
588
+
513 589
 /* BBS version
514 590
  *
515 591
  * Filled in by BBS BIOS.  We ignore the value.
@@ -528,6 +604,289 @@ bev_entry:
528 604
 	lret
529 605
 	.size	bev_entry, . - bev_entry
530 606
 
607
+
608
+#ifdef LOAD_ROM_FROM_PCI
609
+
610
+#define PCI_ROM_ADDRESS		0x30	/* Bits 31:11 address, 10:1 reserved */
611
+#define PCI_ROM_ADDRESS_ENABLE	 0x00000001
612
+#define PCI_ROM_ADDRESS_MASK	 0xfffff800
613
+
614
+#define PCIBIOS_READ_WORD	0xb109
615
+#define PCIBIOS_READ_DWORD	0xb10a
616
+#define PCIBIOS_WRITE_WORD	0xb10c
617
+#define PCIBIOS_WRITE_DWORD	0xb10d
618
+
619
+/* Determine size of PCI BAR
620
+ *
621
+ *  %bx : PCI bus:dev.fn to probe
622
+ *  %di : Address of BAR to find size of
623
+ * %edx : Mask of address bits within BAR
624
+ *
625
+ * %ecx : Size for a memory resource,
626
+ *	  1 for an I/O resource (bit 0 set).
627
+ *   CF : Set on error or nonexistent device (all-ones read)
628
+ *
629
+ * All other registers saved.
630
+ */
631
+pci_bar_size:
632
+	/* Save registers */
633
+	pushw	%ax
634
+	pushl	%esi
635
+	pushl	%edx
636
+
637
+	/* Read current BAR value */
638
+	movw	$PCIBIOS_READ_DWORD, %ax
639
+	int	$0x1a
640
+
641
+	/* Check for device existence and save it */
642
+	testb	$1, %cl		/* I/O bit? */
643
+	jz	1f
644
+	andl	$1, %ecx	/* If so, exit with %ecx = 1 */
645
+	jmp	99f
646
+1:	notl	%ecx
647
+	testl	%ecx, %ecx	/* Set ZF iff %ecx was all-ones */
648
+	notl	%ecx
649
+	jnz	1f
650
+	stc			/* All ones - exit with CF set */
651
+	jmp	99f
652
+1:	movl	%ecx, %esi	/* Save in %esi */
653
+
654
+	/* Write all ones to BAR */
655
+	movl	%edx, %ecx
656
+	movw	$PCIBIOS_WRITE_DWORD, %ax
657
+	int	$0x1a
658
+
659
+	/* Read back BAR */
660
+	movw	$PCIBIOS_READ_DWORD, %ax
661
+	int	$0x1a
662
+
663
+	/* Find decode size from least set bit in mask BAR */
664
+	bsfl	%ecx, %ecx	/* Find least set bit, log2(decode size) */
665
+	jz	1f		/* Mask BAR should not be zero */
666
+	xorl	%edx, %edx
667
+	incl	%edx
668
+	shll	%cl, %edx	/* %edx = decode size */
669
+	jmp	2f
670
+1:	xorl	%edx, %edx	/* Return zero size for mask BAR zero */
671
+
672
+	/* Restore old BAR value */
673
+2:	movl	%esi, %ecx
674
+	movw	$PCIBIOS_WRITE_DWORD, %ax
675
+	int	$0x1a
676
+
677
+	movl	%edx, %ecx	/* Return size in %ecx */
678
+
679
+	/* Restore registers and return */
680
+99:	popl	%edx
681
+	popl	%esi
682
+	popw	%ax
683
+	ret
684
+
685
+	.size	pci_bar_size, . - pci_bar_size
686
+
687
+/* PCI ROM loader
688
+ *
689
+ * Called from init in the .xrom case to load the non-prefix code
690
+ * using the PCI ROM BAR.
691
+ *
692
+ * Returns with carry flag set on error. All registers saved.
693
+ */
694
+load_from_pci:
695
+	/*
696
+	 * Use PCI BIOS access to config space. The calls take
697
+	 *
698
+	 *   %ah : 0xb1		%al : function
699
+	 *   %bx : bus/dev/fn
700
+	 *   %di : config space address
701
+	 *  %ecx : value to write (for writes)
702
+	 *
703
+	 *  %ecx : value read (for reads)
704
+	 *   %ah : return code
705
+	 *    CF : error indication
706
+	 *
707
+	 * All registers not used for return are preserved.
708
+	 */
709
+
710
+	/* Save registers and set up %es for big real mode */
711
+	pushal
712
+	pushw	%es
713
+	xorw	%ax, %ax
714
+	movw	%ax, %es
715
+
716
+	/* Check PCI BIOS presence */
717
+	cmpb	$0, pcibios_present
718
+	jz	err_pcibios
719
+
720
+	/* Load existing PCI ROM BAR */
721
+	movw	$PCIBIOS_READ_DWORD, %ax
722
+	movw	pci_busdevfn, %bx
723
+	movw	$PCI_ROM_ADDRESS, %di
724
+	int	$0x1a
725
+
726
+	/* Maybe it's already enabled? */
727
+	testb	$PCI_ROM_ADDRESS_ENABLE, %cl
728
+	jz	1f
729
+	movb	$1, %dl		/* Flag indicating no deinit required */
730
+	movl	%ecx, %ebp
731
+	jmp	check_rom
732
+
733
+	/* Determine PCI BAR decode size */
734
+1:	movl	$PCI_ROM_ADDRESS_MASK, %edx
735
+	call	pci_bar_size	/* Returns decode size in %ecx */
736
+	jc	err_size_insane	/* CF => no ROM BAR, %ecx == ffffffff */
737
+
738
+	/* Check sanity of decode size */
739
+	xorl	%eax, %eax
740
+	movw	real_size, %ax
741
+	shll	$9, %eax	/* %eax = ROM size */
742
+	cmpl	%ecx, %eax
743
+	ja	err_size_insane	/* Insane if decode size < ROM size */
744
+	cmpl	$0x100000, %ecx
745
+	jae	err_size_insane	/* Insane if decode size >= 1MB */
746
+
747
+	/* Find a place to map the BAR
748
+	 * In theory we should examine e820 and all PCI BARs to find a
749
+	 * free region. However, we run at POST when e820 may not be
750
+	 * available, and memory reads of an unmapped location are
751
+	 * de facto standardized to return all-ones. Thus, we can get
752
+	 * away with searching high memory (0xf0000000 and up) on
753
+	 * multiples of the ROM BAR decode size for a sufficiently
754
+	 * large all-ones region.
755
+	 */
756
+	movl	%ecx, %edx	/* Save ROM BAR size in %edx */
757
+	movl	$0xf0000000, %ebp
758
+	xorl	%eax, %eax
759
+	notl	%eax		/* %eax = all ones */
760
+bar_search:
761
+	movl	%ebp, %edi
762
+	movl	%edx, %ecx
763
+	shrl	$2, %ecx
764
+	addr32 repe scasl	/* Scan %es:edi for anything not all-ones */
765
+	jz	bar_found
766
+	addl	%edx, %ebp
767
+	testl	$0x80000000, %ebp
768
+	jz	err_no_bar
769
+	jmp	bar_search
770
+
771
+bar_found:
772
+	movl	%edi, %ebp
773
+	/* Save current BAR value on stack to restore later */
774
+	movw	$PCIBIOS_READ_DWORD, %ax
775
+	movw	$PCI_ROM_ADDRESS, %di
776
+	int	$0x1a
777
+	pushl	%ecx
778
+
779
+	/* Map the ROM */
780
+	movw	$PCIBIOS_WRITE_DWORD, %ax
781
+	movl	%ebp, %ecx
782
+	orb	$PCI_ROM_ADDRESS_ENABLE, %cl
783
+	int	$0x1a
784
+
785
+	xorb	%dl, %dl	/* %dl = 0 : ROM was not already mapped */
786
+check_rom:
787
+	/* Check and copy ROM - enter with %dl set to skip unmapping,
788
+	 * %ebp set to mapped ROM BAR address.
789
+	 * We check up to prodstr_separator for equality, since anything past
790
+	 * that may have been modified. Since our check includes the checksum
791
+	 * byte over the whole ROM stub, that should be sufficient.
792
+	 */
793
+	xorb	%dh, %dh	/* %dh = 0 : ROM did not fail integrity check */
794
+
795
+	/* Verify ROM integrity */
796
+	xorl	%esi, %esi
797
+	movl	%ebp, %edi
798
+	movl	$prodstr_separator, %ecx
799
+	addr32 repe cmpsb
800
+	jz	copy_rom
801
+	incb	%dh		/* ROM failed integrity check */
802
+	movl	%ecx, %ebp	/* Save number of bytes left */
803
+	jmp	skip_load
804
+
805
+copy_rom:
806
+	/* Print BAR address and indicate whether we mapped it ourselves */
807
+	movb	$( ' ' ), %al
808
+	xorw	%di, %di
809
+	call	print_character
810
+	movl	%ebp, %eax
811
+	call	print_hex_dword
812
+	movb	$( '-' ), %al	/* '-' for self-mapped */
813
+	subb	%dl, %al
814
+	subb	%dl, %al	/* '+' = '-' - 2 for BIOS-mapped */
815
+	call	print_character
816
+
817
+	/* Copy ROM at %ebp to PMM or highmem block */
818
+	movl	%ebp, %esi
819
+	movl	image_source, %edi
820
+	movzwl	real_size, %ecx
821
+	shll	$9, %ecx
822
+	addr32 es rep movsb
823
+	movl	%edi, decompress_to
824
+skip_load:
825
+	testb	%dl, %dl	/* Was ROM already mapped? */
826
+	jnz	skip_unmap
827
+
828
+	/* Unmap the ROM by restoring old ROM BAR */
829
+	movw	$PCIBIOS_WRITE_DWORD, %ax
830
+	movw	$PCI_ROM_ADDRESS, %di
831
+	popl	%ecx
832
+	int	$0x1a
833
+
834
+skip_unmap:
835
+	/* Error handling */
836
+	testb	%dh, %dh
837
+	jnz	err_rom_invalid
838
+	clc
839
+	jmp	99f
840
+
841
+err_pcibios:			/* No PCI BIOS available */
842
+	movw	$load_message_no_pcibios, %si
843
+	xorl	%eax, %eax	/* "error code" is zero */
844
+	jmp	1f
845
+err_size_insane:		/* BAR has size (%ecx) that is insane */
846
+	movw	$load_message_size_insane, %si
847
+	movl	%ecx, %eax
848
+	jmp	1f
849
+err_no_bar:			/* No space of sufficient size (%edx) found */
850
+	movw	$load_message_no_bar, %si
851
+	movl	%edx, %eax
852
+	jmp	1f
853
+err_rom_invalid:		/* Loaded ROM does not match (%ebp bytes left) */
854
+	movw	$load_message_rom_invalid, %si
855
+	movzbl	romheader_size, %eax
856
+	shll	$9, %eax
857
+	subl	%ebp, %eax
858
+	decl	%eax		/* %eax is now byte index of failure */
859
+
860
+1:	/* Error handler - print message at %si and dword in %eax */
861
+	xorw	%di, %di
862
+	call	print_message
863
+	call	print_hex_dword
864
+	stc
865
+99:	popw	%es
866
+	popal
867
+	ret
868
+
869
+	.size	load_from_pci, . - load_from_pci
870
+
871
+load_message_no_pcibios:
872
+	.asciz	"\nNo PCI BIOS found! "
873
+	.size	load_message_no_pcibios, . - load_message_no_pcibios
874
+
875
+load_message_size_insane:
876
+	.asciz	"\nROM resource has invalid size "
877
+	.size	load_message_size_insane, . - load_message_size_insane
878
+
879
+load_message_no_bar:
880
+	.asciz	"\nNo memory hole of sufficient size "
881
+	.size	load_message_no_bar, . - load_message_no_bar
882
+
883
+load_message_rom_invalid:
884
+	.asciz	"\nLoaded ROM is invalid at "
885
+	.size	load_message_rom_invalid, . - load_message_rom_invalid
886
+
887
+#endif /* LOAD_ROM_FROM_PCI */
888
+
889
+
531 890
 /* INT19 entry point
532 891
  *
533 892
  * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
@@ -588,6 +947,14 @@ exec:	/* Set %ds = %cs */
588 947
 	pushw	%cs
589 948
 	popw	%ds
590 949
 
950
+#ifdef LOAD_ROM_FROM_PCI
951
+	/* Don't execute if load was invalid */
952
+	cmpl	$0, decompress_to
953
+	jne	1f
954
+	lret
955
+1:
956
+#endif
957
+
591 958
 	/* Print message as soon as possible */
592 959
 	movw	$prodstr, %si
593 960
 	xorw	%di, %di

+ 9
- 0
src/arch/i386/prefix/xromprefix.S View File

@@ -0,0 +1,9 @@
1
+/*
2
+ * ROM prefix that loads the bulk of the ROM using direct PCI accesses,
3
+ * so as not to take up much option ROM space on PCI <3.0 systems.
4
+ */
5
+
6
+FILE_LICENCE ( GPL2_OR_LATER )
7
+
8
+#define LOAD_ROM_FROM_PCI
9
+#include "romprefix.S"

+ 1
- 0
src/arch/i386/scripts/i386.lds View File

@@ -194,6 +194,7 @@ SECTIONS {
194 194
      * Values calculated to save code from doing it
195 195
      *
196 196
      */
197
+    _prefix_filesz_sect = ( ( _prefix_filesz + 511 ) / 512 );
197 198
     _prefix_memsz_pgh	= ( ( _prefix_memsz + 15 ) / 16 );
198 199
     _prefix_memsz_sect	= ( ( _prefix_memsz + 511 ) / 512 );
199 200
     _text16_memsz_pgh	= ( ( _text16_memsz + 15 ) / 16 );

+ 18
- 12
src/util/makerom.pl View File

@@ -130,14 +130,14 @@ sub writerom ($$) {
130 130
 	close(R);
131 131
 }
132 132
 
133
-sub checksum ($) {
134
-	my ($romref) = @_;
133
+sub checksum ($$) {
134
+	my ($romref, $romsize) = @_;
135 135
 
136 136
 	substr($$romref, 6, 1) = "\x00";
137
-	my $sum = unpack('%8C*', $$romref);
137
+	my $sum = unpack('%8C*', substr($$romref, 0, $romsize));
138 138
 	substr($$romref, 6, 1) = chr(256 - $sum);
139 139
 	# Double check
140
-	$sum = unpack('%8C*', $$romref);
140
+	$sum = unpack('%8C*', substr($$romref, 0, $romsize));
141 141
 	if ($sum != 0) {
142 142
 		print "Checksum fails\n"
143 143
 	} elsif ($opts{'v'}) {
@@ -146,10 +146,10 @@ sub checksum ($) {
146 146
 }
147 147
 
148 148
 sub makerom () {
149
-	my ($rom, $romsize);
149
+	my ($rom, $romsize, $stubsize);
150 150
 
151
-	getopts('3xi:p:s:v', \%opts);
152
-	$ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-x] [-3] rom-file\n";
151
+	getopts('3xni:p:s:v', \%opts);
152
+	$ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-n] [-x] [-3] rom-file\n";
153 153
 	open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
154 154
 	# Read in the whole ROM in one gulp
155 155
 	my $filesize = read(R, $rom, MAXROMSIZE+1);
@@ -183,10 +183,16 @@ sub makerom () {
183 183
 	}
184 184
 	# Pad with 0xFF to $romsize
185 185
 	$rom .= "\xFF" x ($romsize - length($rom));
186
-	if ($romsize >= 128 * 1024) {
187
-		print "Warning: ROM size exceeds extension BIOS limit\n";
186
+	# If this is a stub ROM, don't force header size to the full amount
187
+	if (!$opts{'n'}) {
188
+		if ($romsize >= 128 * 1024) {
189
+			print "Warning: ROM size exceeds extension BIOS limit\n";
190
+		}
191
+		substr($rom, 2, 1) = chr(($romsize / 512) % 256);
192
+	} else {
193
+		$stubsize = ord(substr($rom, 2, 1)) * 512;
194
+		print "Stub size is $stubsize\n" if $opts{'v'};
188 195
 	}
189
-	substr($rom, 2, 1) = chr(($romsize / 512) % 256);
190 196
 	print "ROM size is $romsize\n" if $opts{'v'};
191 197
 	# set the product string only if we don't have one yet
192 198
 	my $pnp_hdr_offset = unpack('v', substr($rom, PNP_PTR_LOC, 2));
@@ -196,7 +202,7 @@ sub makerom () {
196 202
 	# 3c503 requires last two bytes to be 0x80
197 203
 	substr($rom, MINROMSIZE-2, 2) = "\x80\x80"
198 204
 		if ($opts{'3'} and $romsize == MINROMSIZE);
199
-	checksum(\$rom);
205
+	checksum(\$rom, $opts{'n'} ? $stubsize : $romsize);
200 206
 	writerom($ARGV[0], \$rom);
201 207
 }
202 208
 
@@ -213,7 +219,7 @@ sub modrom () {
213 219
 	print "$filesize bytes read\n" if $opts{'v'};
214 220
 	pcipnpheaders(\$rom, undef);
215 221
 	undiheaders(\$rom);
216
-	checksum(\$rom);
222
+	checksum(\$rom, ord(substr($rom, 2, 1)) * 512);
217 223
 	writerom($ARGV[0], \$rom);
218 224
 }
219 225
 

Loading…
Cancel
Save