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
 FINALISE_rom	= $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \
831
 FINALISE_rom	= $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \
832
 		  -i$(IDENT) -s 0 $@
832
 		  -i$(IDENT) -s 0 $@
833
 FINALISE_hrom	= $(FINALISE_rom)
833
 FINALISE_hrom	= $(FINALISE_rom)
834
+FINALISE_xrom	= $(MAKEROM) $(MAKEROM_FLAGS) $(TGT_MAKEROM_FLAGS) \
835
+		  -i$(IDENT) -n -s 0 $@
834
 
836
 
835
 # Some ROMs require specific flags to be passed to makerom.pl
837
 # Some ROMs require specific flags to be passed to makerom.pl
836
 #
838
 #

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

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

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

25
  */
25
  */
26
 #define ROM_BANNER_TIMEOUT ( 2 * ( 18 * BANNER_TIMEOUT ) / 10 )
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
 	.text
41
 	.text
29
 	.code16
42
 	.code16
30
 	.arch i386
43
 	.arch i386
33
 	.org	0x00
46
 	.org	0x00
34
 romheader:
47
 romheader:
35
 	.word	0xAA55			/* BIOS extension signature */
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
 	jmp	init			/* Initialisation vector */
50
 	jmp	init			/* Initialisation vector */
38
 checksum:
51
 checksum:
39
-	.byte	0
52
+	.byte	0, 0
53
+real_size:
54
+	.word	0
40
 	.org	0x16
55
 	.org	0x16
41
 	.word	undiheader
56
 	.word	undiheader
42
 	.org	0x18
57
 	.org	0x18
44
 	.org	0x1a
59
 	.org	0x1a
45
 	.word	pnpheader
60
 	.word	pnpheader
46
 	.size romheader, . - romheader
61
 	.size romheader, . - romheader
47
-	
62
+
48
 	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
63
 	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
64
+#ifndef LOAD_ROM_FROM_PCI
49
 	.ascii	"ADDB"
65
 	.ascii	"ADDB"
50
 	.long	romheader_size
66
 	.long	romheader_size
51
 	.long	512
67
 	.long	512
52
 	.long	0
68
 	.long	0
69
+#endif
70
+	.ascii	"ADDB"
71
+	.long	real_size
72
+	.long	512
73
+	.long	0
53
 	.previous
74
 	.previous
54
 
75
 
55
 pciheader:
76
 pciheader:
61
 	.byte	0x03			/* PCI data structure revision */
82
 	.byte	0x03			/* PCI data structure revision */
62
 	.byte	0x02, 0x00, 0x00	/* Class code */
83
 	.byte	0x02, 0x00, 0x00	/* Class code */
63
 pciheader_image_length:
84
 pciheader_image_length:
64
-	.word	0			/* Image length */
85
+	.word	ROM_SIZE_VALUE		/* Image length */
65
 	.word	0x0001			/* Revision level */
86
 	.word	0x0001			/* Revision level */
66
 	.byte	0x00			/* Code type */
87
 	.byte	0x00			/* Code type */
67
 	.byte	0x80			/* Last image indicator */
88
 	.byte	0x80			/* Last image indicator */
68
 pciheader_runtime_length:
89
 pciheader_runtime_length:
69
-	.word	0			/* Maximum run-time image length */
90
+	.word	ROM_SIZE_VALUE		/* Maximum run-time image length */
70
 	.word	0x0000			/* Configuration utility code header */
91
 	.word	0x0000			/* Configuration utility code header */
71
 	.word	0x0000			/* DMTF CLP entry point */
92
 	.word	0x0000			/* DMTF CLP entry point */
72
 	.equ pciheader_len, . - pciheader
93
 	.equ pciheader_len, . - pciheader
73
 	.size pciheader, . - pciheader
94
 	.size pciheader, . - pciheader
74
-	
95
+
96
+#ifndef LOAD_ROM_FROM_PCI
75
 	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
97
 	.section ".zinfo.fixup", "a", @progbits	/* Compressor fixups */
76
 	.ascii	"ADDW"
98
 	.ascii	"ADDW"
77
 	.long	pciheader_image_length
99
 	.long	pciheader_image_length
82
 	.long	512
104
 	.long	512
83
 	.long	0
105
 	.long	0
84
 	.previous
106
 	.previous
107
+#endif
85
 
108
 
86
 pnpheader:
109
 pnpheader:
87
 	.ascii	"$PnP"			/* Signature */
110
 	.ascii	"$PnP"			/* Signature */
175
 	call	print_message
198
 	call	print_message
176
 	call	print_pci_busdevfn
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
 	/* Fill in product name string, if possible */
206
 	/* Fill in product name string, if possible */
179
 	movw	$prodstr_pci_id, %di
207
 	movw	$prodstr_pci_id, %di
180
 	call	print_pci_busdevfn
208
 	call	print_pci_busdevfn
199
 	jne	no_pci3
227
 	jne	no_pci3
200
 	testb	%ah, %ah
228
 	testb	%ah, %ah
201
 	jnz	no_pci3
229
 	jnz	no_pci3
230
+#ifdef LOAD_ROM_FROM_PCI
231
+	incb	pcibios_present
232
+#endif
202
 	movw	$init_message_pci, %si
233
 	movw	$init_message_pci, %si
203
 	xorw	%di, %di
234
 	xorw	%di, %di
204
 	call	print_message
235
 	call	print_message
310
 	/* We have PMM and so a 1kB stack: preserve upper register halves */
341
 	/* We have PMM and so a 1kB stack: preserve upper register halves */
311
 	pushal
342
 	pushal
312
 	/* Calculate required allocation size in %esi */
343
 	/* Calculate required allocation size in %esi */
313
-	movzbl	romheader_size, %eax
344
+	movzwl	real_size, %eax
314
 	shll	$9, %eax
345
 	shll	$9, %eax
315
 	addl	$_textdata_memsz, %eax
346
 	addl	$_textdata_memsz, %eax
316
 	orw	$0xffff, %ax	/* Ensure allocation size is at least 64kB */
347
 	orw	$0xffff, %ax	/* Ensure allocation size is at least 64kB */
364
 	movl	%edi, decompress_to
395
 	movl	%edi, decompress_to
365
 	/* Shrink ROM */
396
 	/* Shrink ROM */
366
 	movb	$_prefix_memsz_sect, romheader_size
397
 	movb	$_prefix_memsz_sect, romheader_size
367
-#ifdef SHRINK_WITHOUT_PMM
398
+#if defined(SHRINK_WITHOUT_PMM) || defined(LOAD_ROM_FROM_PCI)
368
 	jmp	pmm_done
399
 	jmp	pmm_done
369
 pmm_fail:
400
 pmm_fail:
370
 	/* Print marker and copy ourselves to high memory */
401
 	/* Print marker and copy ourselves to high memory */
379
 #endif
410
 #endif
380
 	/* Restore upper register halves */
411
 	/* Restore upper register halves */
381
 	popal
412
 	popal
413
+#if defined(LOAD_ROM_FROM_PCI)
414
+	call	load_from_pci
415
+	jc	load_err
416
+	jmp	load_ok
382
 no_pmm:
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
 	/* Update checksum */
435
 	/* Update checksum */
385
 	xorw	%bx, %bx
436
 	xorw	%bx, %bx
386
 	xorw	%si, %si
437
 	xorw	%si, %si
425
 	movw	$init_message_done, %si
476
 	movw	$init_message_done, %si
426
 	call	print_message
477
 	call	print_message
427
 	popf
478
 	popf
428
-	jnz	2f
479
+	jnz	out
429
 	/* Ctrl-B was pressed: invoke gPXE.  The keypress will be
480
 	/* Ctrl-B was pressed: invoke gPXE.  The keypress will be
430
 	 * picked up by the initial shell prompt, and we will drop
481
 	 * picked up by the initial shell prompt, and we will drop
431
 	 * into a shell.
482
 	 * into a shell.
432
 	 */
483
 	 */
433
 	pushw	%cs
484
 	pushw	%cs
434
 	call	exec
485
 	call	exec
435
-2:
486
+out:
436
 	/* Restore registers */
487
 	/* Restore registers */
437
 	popw	%gs
488
 	popw	%gs
438
 	popw	%fs
489
 	popw	%fs
479
 init_message_pmm:
530
 init_message_pmm:
480
 	.asciz	" PMM"
531
 	.asciz	" PMM"
481
 	.size	init_message_pmm, . - init_message_pmm
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
 init_message_int19:
538
 init_message_int19:
483
 	.asciz	" INT19"
539
 	.asciz	" INT19"
484
 	.size	init_message_int19, . - init_message_int19
540
 	.size	init_message_int19, . - init_message_int19
504
 /* Temporary decompression area
560
 /* Temporary decompression area
505
  *
561
  *
506
  * May be either at HIGHMEM_LOADPOINT, or within PMM-allocated block.
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
 	.globl	decompress_to
565
 	.globl	decompress_to
509
 decompress_to:
566
 decompress_to:
510
 	.long	HIGHMEM_LOADPOINT
567
 	.long	HIGHMEM_LOADPOINT
511
 	.size	decompress_to, . - decompress_to
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
 /* BBS version
589
 /* BBS version
514
  *
590
  *
515
  * Filled in by BBS BIOS.  We ignore the value.
591
  * Filled in by BBS BIOS.  We ignore the value.
528
 	lret
604
 	lret
529
 	.size	bev_entry, . - bev_entry
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
 /* INT19 entry point
890
 /* INT19 entry point
532
  *
891
  *
533
  * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
892
  * Called via the hooked INT 19 if we detected a non-PnP BIOS.  We
588
 	pushw	%cs
947
 	pushw	%cs
589
 	popw	%ds
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
 	/* Print message as soon as possible */
958
 	/* Print message as soon as possible */
592
 	movw	$prodstr, %si
959
 	movw	$prodstr, %si
593
 	xorw	%di, %di
960
 	xorw	%di, %di

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

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
      * Values calculated to save code from doing it
194
      * Values calculated to save code from doing it
195
      *
195
      *
196
      */
196
      */
197
+    _prefix_filesz_sect = ( ( _prefix_filesz + 511 ) / 512 );
197
     _prefix_memsz_pgh	= ( ( _prefix_memsz + 15 ) / 16 );
198
     _prefix_memsz_pgh	= ( ( _prefix_memsz + 15 ) / 16 );
198
     _prefix_memsz_sect	= ( ( _prefix_memsz + 511 ) / 512 );
199
     _prefix_memsz_sect	= ( ( _prefix_memsz + 511 ) / 512 );
199
     _text16_memsz_pgh	= ( ( _text16_memsz + 15 ) / 16 );
200
     _text16_memsz_pgh	= ( ( _text16_memsz + 15 ) / 16 );

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

130
 	close(R);
130
 	close(R);
131
 }
131
 }
132
 
132
 
133
-sub checksum ($) {
134
-	my ($romref) = @_;
133
+sub checksum ($$) {
134
+	my ($romref, $romsize) = @_;
135
 
135
 
136
 	substr($$romref, 6, 1) = "\x00";
136
 	substr($$romref, 6, 1) = "\x00";
137
-	my $sum = unpack('%8C*', $$romref);
137
+	my $sum = unpack('%8C*', substr($$romref, 0, $romsize));
138
 	substr($$romref, 6, 1) = chr(256 - $sum);
138
 	substr($$romref, 6, 1) = chr(256 - $sum);
139
 	# Double check
139
 	# Double check
140
-	$sum = unpack('%8C*', $$romref);
140
+	$sum = unpack('%8C*', substr($$romref, 0, $romsize));
141
 	if ($sum != 0) {
141
 	if ($sum != 0) {
142
 		print "Checksum fails\n"
142
 		print "Checksum fails\n"
143
 	} elsif ($opts{'v'}) {
143
 	} elsif ($opts{'v'}) {
146
 }
146
 }
147
 
147
 
148
 sub makerom () {
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
 	open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
153
 	open(R, $ARGV[0]) or die "$ARGV[0]: $!\n";
154
 	# Read in the whole ROM in one gulp
154
 	# Read in the whole ROM in one gulp
155
 	my $filesize = read(R, $rom, MAXROMSIZE+1);
155
 	my $filesize = read(R, $rom, MAXROMSIZE+1);
183
 	}
183
 	}
184
 	# Pad with 0xFF to $romsize
184
 	# Pad with 0xFF to $romsize
185
 	$rom .= "\xFF" x ($romsize - length($rom));
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
 	print "ROM size is $romsize\n" if $opts{'v'};
196
 	print "ROM size is $romsize\n" if $opts{'v'};
191
 	# set the product string only if we don't have one yet
197
 	# set the product string only if we don't have one yet
192
 	my $pnp_hdr_offset = unpack('v', substr($rom, PNP_PTR_LOC, 2));
198
 	my $pnp_hdr_offset = unpack('v', substr($rom, PNP_PTR_LOC, 2));
196
 	# 3c503 requires last two bytes to be 0x80
202
 	# 3c503 requires last two bytes to be 0x80
197
 	substr($rom, MINROMSIZE-2, 2) = "\x80\x80"
203
 	substr($rom, MINROMSIZE-2, 2) = "\x80\x80"
198
 		if ($opts{'3'} and $romsize == MINROMSIZE);
204
 		if ($opts{'3'} and $romsize == MINROMSIZE);
199
-	checksum(\$rom);
205
+	checksum(\$rom, $opts{'n'} ? $stubsize : $romsize);
200
 	writerom($ARGV[0], \$rom);
206
 	writerom($ARGV[0], \$rom);
201
 }
207
 }
202
 
208
 
213
 	print "$filesize bytes read\n" if $opts{'v'};
219
 	print "$filesize bytes read\n" if $opts{'v'};
214
 	pcipnpheaders(\$rom, undef);
220
 	pcipnpheaders(\$rom, undef);
215
 	undiheaders(\$rom);
221
 	undiheaders(\$rom);
216
-	checksum(\$rom);
222
+	checksum(\$rom, ord(substr($rom, 2, 1)) * 512);
217
 	writerom($ARGV[0], \$rom);
223
 	writerom($ARGV[0], \$rom);
218
 }
224
 }
219
 
225
 

Loading…
Cancel
Save