|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2009 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: #include <stdint.h> ! 20: #include <stddef.h> ! 21: #include <stdlib.h> ! 22: #include <stdio.h> ! 23: #include <string.h> ! 24: #include <sys/stat.h> ! 25: #include <unistd.h> ! 26: #include <errno.h> ! 27: #include <assert.h> ! 28: #include <getopt.h> ! 29: #include <ipxe/efi/efi.h> ! 30: #include <ipxe/efi/IndustryStandard/PeImage.h> ! 31: #include <ipxe/efi/IndustryStandard/Pci22.h> ! 32: ! 33: #define eprintf(...) fprintf ( stderr, __VA_ARGS__ ) ! 34: ! 35: /** Command-line options */ ! 36: struct options { ! 37: uint16_t vendor; ! 38: uint16_t device; ! 39: }; ! 40: ! 41: /** ! 42: * Allocate memory ! 43: * ! 44: * @v len Length of memory to allocate ! 45: * @ret ptr Pointer to allocated memory ! 46: */ ! 47: static void * xmalloc ( size_t len ) { ! 48: void *ptr; ! 49: ! 50: ptr = malloc ( len ); ! 51: if ( ! ptr ) { ! 52: eprintf ( "Could not allocate %zd bytes\n", len ); ! 53: exit ( 1 ); ! 54: } ! 55: ! 56: return ptr; ! 57: } ! 58: ! 59: /** ! 60: * Get file size ! 61: * ! 62: * @v file File ! 63: * @v len File size ! 64: */ ! 65: static size_t file_size ( FILE *file ) { ! 66: ssize_t len; ! 67: ! 68: return len; ! 69: } ! 70: ! 71: /** ! 72: * Read information from PE headers ! 73: * ! 74: * @v pe PE file ! 75: * @ret machine Machine type ! 76: * @ret subsystem EFI subsystem ! 77: */ ! 78: static void read_pe_info ( void *pe, uint16_t *machine, ! 79: uint16_t *subsystem ) { ! 80: EFI_IMAGE_DOS_HEADER *dos; ! 81: union { ! 82: EFI_IMAGE_NT_HEADERS32 nt32; ! 83: EFI_IMAGE_NT_HEADERS64 nt64; ! 84: } *nt; ! 85: ! 86: /* Locate NT header */ ! 87: dos = pe; ! 88: nt = ( pe + dos->e_lfanew ); ! 89: ! 90: /* Parse out PE information */ ! 91: *machine = nt->nt32.FileHeader.Machine; ! 92: switch ( *machine ) { ! 93: case EFI_IMAGE_MACHINE_IA32: ! 94: *subsystem = nt->nt32.OptionalHeader.Subsystem; ! 95: break; ! 96: case EFI_IMAGE_MACHINE_X64: ! 97: *subsystem = nt->nt64.OptionalHeader.Subsystem; ! 98: break; ! 99: default: ! 100: eprintf ( "Unrecognised machine type %04x\n", *machine ); ! 101: exit ( 1 ); ! 102: } ! 103: } ! 104: ! 105: /** ! 106: * Convert EFI image to ROM image ! 107: * ! 108: * @v pe EFI file ! 109: * @v rom ROM file ! 110: */ ! 111: static void make_efi_rom ( FILE *pe, FILE *rom, struct options *opts ) { ! 112: struct { ! 113: EFI_PCI_EXPANSION_ROM_HEADER rom; ! 114: PCI_DATA_STRUCTURE pci __attribute__ (( aligned ( 4 ) )); ! 115: uint8_t checksum; ! 116: } *headers; ! 117: struct stat pe_stat; ! 118: size_t pe_size; ! 119: size_t rom_size; ! 120: void *buf; ! 121: void *payload; ! 122: unsigned int i; ! 123: uint8_t checksum; ! 124: ! 125: /* Determine PE file size */ ! 126: if ( fstat ( fileno ( pe ), &pe_stat ) != 0 ) { ! 127: eprintf ( "Could not stat PE file: %s\n", ! 128: strerror ( errno ) ); ! 129: exit ( 1 ); ! 130: } ! 131: pe_size = pe_stat.st_size; ! 132: ! 133: /* Determine ROM file size */ ! 134: rom_size = ( ( pe_size + sizeof ( *headers ) + 511 ) & ~511 ); ! 135: ! 136: /* Allocate ROM buffer and read in PE file */ ! 137: buf = xmalloc ( rom_size ); ! 138: memset ( buf, 0, rom_size ); ! 139: headers = buf; ! 140: payload = ( buf + sizeof ( *headers ) ); ! 141: if ( fread ( payload, pe_size, 1, pe ) != 1 ) { ! 142: eprintf ( "Could not read PE file: %s\n", ! 143: strerror ( errno ) ); ! 144: exit ( 1 ); ! 145: } ! 146: ! 147: /* Construct ROM header */ ! 148: headers->rom.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE; ! 149: headers->rom.InitializationSize = ( rom_size / 512 ); ! 150: headers->rom.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE; ! 151: read_pe_info ( payload, &headers->rom.EfiMachineType, ! 152: &headers->rom.EfiSubsystem ); ! 153: headers->rom.EfiImageHeaderOffset = sizeof ( *headers ); ! 154: headers->rom.PcirOffset = ! 155: offsetof ( typeof ( *headers ), pci ); ! 156: headers->pci.Signature = PCI_DATA_STRUCTURE_SIGNATURE; ! 157: headers->pci.VendorId = opts->vendor; ! 158: headers->pci.DeviceId = opts->device; ! 159: headers->pci.Length = sizeof ( headers->pci ); ! 160: headers->pci.ClassCode[0] = PCI_CLASS_NETWORK; ! 161: headers->pci.ImageLength = ( rom_size / 512 ); ! 162: headers->pci.CodeType = 0x03; /* No constant in EFI headers? */ ! 163: headers->pci.Indicator = 0x80; /* No constant in EFI headers? */ ! 164: ! 165: /* Fix image checksum */ ! 166: for ( i = 0, checksum = 0 ; i < rom_size ; i++ ) ! 167: checksum += *( ( uint8_t * ) buf + i ); ! 168: headers->checksum -= checksum; ! 169: ! 170: /* Write out ROM */ ! 171: if ( fwrite ( buf, rom_size, 1, rom ) != 1 ) { ! 172: eprintf ( "Could not write ROM file: %s\n", ! 173: strerror ( errno ) ); ! 174: exit ( 1 ); ! 175: } ! 176: } ! 177: ! 178: /** ! 179: * Print help ! 180: * ! 181: * @v program_name Program name ! 182: */ ! 183: static void print_help ( const char *program_name ) { ! 184: eprintf ( "Syntax: %s [--vendor=VVVV] [--device=DDDD] " ! 185: "infile outfile\n", program_name ); ! 186: } ! 187: ! 188: /** ! 189: * Parse command-line options ! 190: * ! 191: * @v argc Argument count ! 192: * @v argv Argument list ! 193: * @v opts Options structure to populate ! 194: */ ! 195: static int parse_options ( const int argc, char **argv, ! 196: struct options *opts ) { ! 197: char *end; ! 198: int c; ! 199: ! 200: while (1) { ! 201: int option_index = 0; ! 202: static struct option long_options[] = { ! 203: { "vendor", required_argument, NULL, 'v' }, ! 204: { "device", required_argument, NULL, 'd' }, ! 205: { "help", 0, NULL, 'h' }, ! 206: { 0, 0, 0, 0 } ! 207: }; ! 208: ! 209: if ( ( c = getopt_long ( argc, argv, "v:d:h", ! 210: long_options, ! 211: &option_index ) ) == -1 ) { ! 212: break; ! 213: } ! 214: ! 215: switch ( c ) { ! 216: case 'v': ! 217: opts->vendor = strtoul ( optarg, &end, 16 ); ! 218: if ( *end ) { ! 219: eprintf ( "Invalid vendor \"%s\"\n", optarg ); ! 220: exit ( 2 ); ! 221: } ! 222: break; ! 223: case 'd': ! 224: opts->device = strtoul ( optarg, &end, 16 ); ! 225: if ( *end ) { ! 226: eprintf ( "Invalid device \"%s\"\n", optarg ); ! 227: exit ( 2 ); ! 228: } ! 229: break; ! 230: case 'h': ! 231: print_help ( argv[0] ); ! 232: exit ( 0 ); ! 233: case '?': ! 234: default: ! 235: exit ( 2 ); ! 236: } ! 237: } ! 238: return optind; ! 239: } ! 240: ! 241: int main ( int argc, char **argv ) { ! 242: struct options opts = { ! 243: }; ! 244: unsigned int infile_index; ! 245: const char *infile_name; ! 246: const char *outfile_name; ! 247: FILE *infile; ! 248: FILE *outfile; ! 249: ! 250: /* Parse command-line arguments */ ! 251: infile_index = parse_options ( argc, argv, &opts ); ! 252: if ( argc != ( infile_index + 2 ) ) { ! 253: print_help ( argv[0] ); ! 254: exit ( 2 ); ! 255: } ! 256: infile_name = argv[infile_index]; ! 257: outfile_name = argv[infile_index + 1]; ! 258: ! 259: /* Open input and output files */ ! 260: infile = fopen ( infile_name, "r" ); ! 261: if ( ! infile ) { ! 262: eprintf ( "Could not open %s for reading: %s\n", ! 263: infile_name, strerror ( errno ) ); ! 264: exit ( 1 ); ! 265: } ! 266: outfile = fopen ( outfile_name, "w" ); ! 267: if ( ! outfile ) { ! 268: eprintf ( "Could not open %s for writing: %s\n", ! 269: outfile_name, strerror ( errno ) ); ! 270: exit ( 1 ); ! 271: } ! 272: ! 273: /* Convert file */ ! 274: make_efi_rom ( infile, outfile, &opts ); ! 275: ! 276: fclose ( outfile ); ! 277: fclose ( infile ); ! 278: ! 279: return 0; ! 280: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.