|
|
1.1 ! root 1: #!/usr/bin/perl -w ! 2: ! 3: use Getopt::Std; ! 4: ! 5: use constant MINROMSIZE => 8192; ! 6: use constant MAXROMSIZE => 262144; ! 7: ! 8: use constant PCI_PTR_LOC => 0x18; # from beginning of ROM ! 9: use constant PCI_HDR_SIZE => 0x18; ! 10: use constant PNP_PTR_LOC => 0x1a; # from beginning of ROM ! 11: use constant PNP_HDR_SIZE => 0x20; ! 12: use constant PNP_CHKSUM_OFF => 0x9; # bytes from beginning of PnP header ! 13: use constant PNP_DEVICE_OFF => 0x10; # bytes from beginning of PnP header ! 14: use constant PCI_VEND_ID_OFF => 0x4; # bytes from beginning of PCI header ! 15: use constant PCI_DEV_ID_OFF => 0x6; # bytes from beginning of PCI header ! 16: use constant PCI_SIZE_OFF => 0x10; # bytes from beginning of PCI header ! 17: ! 18: use constant UNDI_PTR_LOC => 0x16; # from beginning of ROM ! 19: use constant UNDI_HDR_SIZE => 0x16; ! 20: use constant UNDI_CHKSUM_OFF => 0x05; ! 21: ! 22: use strict; ! 23: ! 24: use vars qw(%opts); ! 25: ! 26: use bytes; ! 27: ! 28: sub getromsize ($) { ! 29: my ($romref) = @_; ! 30: my $i; ! 31: ! 32: print STDERR "BIOS extension ROM Image did not start with 0x55 0xAA\n" ! 33: if (substr($$romref, 0, 2) ne "\x55\xaa"); ! 34: my $size = ord(substr($$romref, 2, 1)) * 512; ! 35: for ($i = MINROMSIZE; $i < MAXROMSIZE and $i < $size; $i *= 2) { } ! 36: print STDERR "$size is a strange size for a boot ROM\n" ! 37: if ($size > 0 and $i > $size); ! 38: return ($size); ! 39: } ! 40: ! 41: sub addident ($) { ! 42: my ($romref) = @_; ! 43: ! 44: return (0) unless (my $s = $opts{'i'}); ! 45: # include the terminating NUL byte too ! 46: $s .= "\x00"; ! 47: my $len = length($s); ! 48: # Put the identifier in only if the space is blank ! 49: my $pos = length($$romref) - $len - 2; ! 50: return (0) if (substr($$romref, $pos, $len) ne ("\xFF" x $len)); ! 51: substr($$romref, $pos, $len) = $s; ! 52: return ($pos); ! 53: } ! 54: ! 55: sub pcipnpheaders ($$) { ! 56: my ($romref, $identoffset) = @_; ! 57: my ($pci_hdr_offset, $pnp_hdr_offset); ! 58: ! 59: $pci_hdr_offset = unpack('v', substr($$romref, PCI_PTR_LOC, 2)); ! 60: $pnp_hdr_offset = unpack('v', substr($$romref, PNP_PTR_LOC, 2)); ! 61: # Sanity checks ! 62: if ($pci_hdr_offset < PCI_PTR_LOC + 2 ! 63: or $pci_hdr_offset > length($$romref) - PCI_HDR_SIZE ! 64: or $pnp_hdr_offset < PNP_PTR_LOC + 2 ! 65: or $pnp_hdr_offset > length($$romref) - PNP_HDR_SIZE ! 66: or substr($$romref, $pci_hdr_offset, 4) ne 'PCIR' ! 67: or substr($$romref, $pnp_hdr_offset, 4) ne '$PnP') { ! 68: $pci_hdr_offset = $pnp_hdr_offset = 0; ! 69: } else { ! 70: printf "PCI header at %#x and PnP header at %#x\n", ! 71: $pci_hdr_offset, $pnp_hdr_offset; ! 72: } ! 73: if ($pci_hdr_offset > 0) { ! 74: my ($pci_vendor_id, $pci_device_id); ! 75: # if no -p option, just report what's there ! 76: if (!defined($opts{'p'})) { ! 77: $pci_vendor_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2)); ! 78: $pci_device_id = unpack('v', substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2)); ! 79: printf "PCI Vendor ID %#x Device ID %#x\n", ! 80: $pci_vendor_id, $pci_device_id; ! 81: } else { ! 82: substr($$romref, $pci_hdr_offset + PCI_SIZE_OFF, 2) ! 83: = pack('v', length($$romref) / 512); ! 84: ($pci_vendor_id, $pci_device_id) = split(/,/, $opts{'p'}); ! 85: substr($$romref, $pci_hdr_offset+PCI_VEND_ID_OFF, 2) ! 86: = pack('v', oct($pci_vendor_id)) if ($pci_vendor_id); ! 87: substr($$romref, $pci_hdr_offset+PCI_DEV_ID_OFF, 2) ! 88: = pack('v', oct($pci_device_id)) if ($pci_device_id); ! 89: } ! 90: } ! 91: if ($pnp_hdr_offset > 0 and defined($identoffset)) { ! 92: # Point to device id string at end of ROM image ! 93: substr($$romref, $pnp_hdr_offset+PNP_DEVICE_OFF, 2) ! 94: = pack('v', $identoffset); ! 95: substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = "\x00"; ! 96: my $sum = unpack('%8C*', substr($$romref, $pnp_hdr_offset, ! 97: PNP_HDR_SIZE)); ! 98: substr($$romref, $pnp_hdr_offset+PNP_CHKSUM_OFF, 1) = chr(256 - $sum); ! 99: } ! 100: } ! 101: ! 102: sub undiheaders ($) { ! 103: my ($romref) = @_; ! 104: my ($undi_hdr_offset); ! 105: ! 106: $undi_hdr_offset = unpack('v', substr($$romref, UNDI_PTR_LOC, 2)); ! 107: # Sanity checks ! 108: if ($undi_hdr_offset < UNDI_PTR_LOC + 2 ! 109: or $undi_hdr_offset > length($$romref) - UNDI_HDR_SIZE ! 110: or substr($$romref, $undi_hdr_offset, 4) ne 'UNDI') { ! 111: $undi_hdr_offset = 0; ! 112: } else { ! 113: printf "UNDI header at %#x\n", $undi_hdr_offset; ! 114: } ! 115: if ($undi_hdr_offset > 0) { ! 116: substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = "\x00"; ! 117: my $sum = unpack('%8C*', substr($$romref, $undi_hdr_offset, ! 118: UNDI_HDR_SIZE)); ! 119: substr($$romref, $undi_hdr_offset+UNDI_CHKSUM_OFF, 1) = chr(256 - $sum); ! 120: } ! 121: } ! 122: ! 123: sub writerom ($$) { ! 124: my ($filename, $romref) = @_; ! 125: ! 126: open(R, ">$filename") or die "$filename: $!\n"; ! 127: print R $$romref; ! 128: close(R); ! 129: } ! 130: ! 131: sub checksum ($) { ! 132: my ($romref) = @_; ! 133: ! 134: substr($$romref, 6, 1) = "\x00"; ! 135: my $sum = unpack('%8C*', $$romref); ! 136: substr($$romref, 6, 1) = chr(256 - $sum); ! 137: # Double check ! 138: $sum = unpack('%8C*', $$romref); ! 139: if ($sum != 0) { ! 140: print "Checksum fails\n" ! 141: } elsif ($opts{'v'}) { ! 142: print "Checksum ok\n"; ! 143: } ! 144: } ! 145: ! 146: sub makerom () { ! 147: my ($rom, $romsize); ! 148: ! 149: getopts('3xi:p:s:v', \%opts); ! 150: $ARGV[0] or die "Usage: $0 [-s romsize] [-i ident] [-p vendorid,deviceid] [-x] [-3] rom-file\n"; ! 151: open(R, $ARGV[0]) or die "$ARGV[0]: $!\n"; ! 152: # Read in the whole ROM in one gulp ! 153: my $filesize = read(R, $rom, MAXROMSIZE+1); ! 154: close(R); ! 155: defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n"; ! 156: print "$filesize bytes read\n" if $opts{'v'}; ! 157: # If PXE image, just fill the length field and write it out ! 158: if ($opts{'x'}) { ! 159: substr($rom, 2, 1) = chr((length($rom) + 511) / 512); ! 160: &writerom($ARGV[0], \$rom); ! 161: return; ! 162: } ! 163: # Size specified with -s overrides value in 3rd byte in image ! 164: # -s 0 means round up to next 512 byte block ! 165: if (defined($opts{'s'})) { ! 166: if (($romsize = oct($opts{'s'})) <= 0) { ! 167: # NB: This roundup trick only works on powers of 2 ! 168: $romsize = ($filesize + 511) & ~511 ! 169: } ! 170: } else { ! 171: $romsize = &getromsize(\$rom); ! 172: # 0 put there by *loader.S means makerom should pick the size ! 173: if ($romsize == 0) { ! 174: # Shrink romsize down to the smallest power of two that will do ! 175: for ($romsize = MAXROMSIZE; ! 176: $romsize > MINROMSIZE and $romsize >= 2*$filesize; ! 177: $romsize /= 2) { } ! 178: } ! 179: } ! 180: if ($filesize > $romsize) { ! 181: print STDERR "ROM size of $romsize not big enough for data, "; ! 182: # NB: This roundup trick only works on powers of 2 ! 183: $romsize = ($filesize + 511) & ~511; ! 184: print "will use $romsize instead\n" ! 185: } ! 186: # Pad with 0xFF to $romsize ! 187: $rom .= "\xFF" x ($romsize - length($rom)); ! 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: print "ROM size is $romsize\n" if $opts{'v'}; ! 193: my $identoffset = &addident(\$rom); ! 194: &pcipnpheaders(\$rom, $identoffset); ! 195: &undiheaders(\$rom); ! 196: # 3c503 requires last two bytes to be 0x80 ! 197: substr($rom, MINROMSIZE-2, 2) = "\x80\x80" ! 198: if ($opts{'3'} and $romsize == MINROMSIZE); ! 199: &checksum(\$rom); ! 200: &writerom($ARGV[0], \$rom); ! 201: } ! 202: ! 203: sub modrom () { ! 204: my ($rom); ! 205: ! 206: getopts('p:v', \%opts); ! 207: $ARGV[0] or die "Usage: $0 [-p vendorid,deviceid] rom-file\n"; ! 208: open(R, $ARGV[0]) or die "$ARGV[0]: $!\n"; ! 209: # Read in the whole ROM in one gulp ! 210: my $filesize = read(R, $rom, MAXROMSIZE+1); ! 211: close(R); ! 212: defined($filesize) and $filesize >= 3 or die "Cannot get first 3 bytes of file\n"; ! 213: print "$filesize bytes read\n" if $opts{'v'}; ! 214: &pcipnpheaders(\$rom); ! 215: &undiheaders(\$rom); ! 216: &checksum(\$rom); ! 217: &writerom($ARGV[0], \$rom); ! 218: } ! 219: ! 220: # Main routine. See how we were called and behave accordingly ! 221: if ($0 =~ m:modrom(\.pl)?$:) { ! 222: &modrom(); ! 223: } else { ! 224: &makerom(); ! 225: } ! 226: exit(0);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.