|
|
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.