VirtualBox

source: vbox/trunk/src/VBox/Devices/PC/Etherboot-src/util/makerom.c@ 42793

Last change on this file since 42793 was 3912, checked in by vboxsync, 17 years ago

SOLARIS -> RT_OS_SOLARIS

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.8 KB
Line 
1/************************************************************************
2
3Calculate ROM size for 3rd byte and ROM checksum for 6th byte in ROM image.
4
5-3 option makes the last two bytes of an 8k ROM 0x80. The 3c503 ASIC will
6report this value regardless of the ROM contents, so we need to make
7the checksum work properly. A 3Com EtherStart ROM I have handy sets
8these to 0x80, so we'll use that for now. 0x04 has also been reported.
9Any more offers?
10
11Added capability to handle PCI and PnP headers. Detection is automatic.
12
13************************************************************************/
14
15#include <stdio.h>
16#include <fcntl.h>
17#include <stdlib.h>
18#include <string.h>
19#ifdef _MSC_VER
20#include <sys/types.h>
21#endif
22
23#if defined(__TURBOC__) || defined(__BORLANDC__)
24typedef long off_t;
25#endif
26
27/* should be powers of 2 and MAX a multiple of MIN */
28#define MINROMSIZE 8192L
29#define MAXROMSIZE 262144L
30
31#define MAGIC_3C503 0x80
32
33#define PCI_PTR_LOC 0x18 /* from beginning of ROM */
34#define PCI_HDR_SIZE 0x18
35#define PNP_PTR_LOC 0x1a /* from beginning of ROM */
36#define PNP_HDR_SIZE 0x20
37#define PNP_CHKSUM_OFF 0x9 /* bytes from beginning of PnP header */
38#define PNP_DEVICE_OFF 0x10 /* bytes from beginning of PnP header */
39#define PCI_VEND_ID_OFF 0x4 /* bytes from beginning of PCI header */
40#define PCI_DEV_ID_OFF 0x6 /* bytes from beginning of PCI header */
41#define PCI_SIZE_OFF 0x10 /* bytes from beginning of PCI header */
42#define UNDI_PTR_LOC 0x16 /* from beginning of ROM */
43#define UNDI_HDR_SIZE 0x16
44#define UNDI_CHKSUM_OFF 0x5 /* bytes from beginning of UNDI header */
45
46unsigned char *rom;
47long romsize = 0L; /* for autosizing */
48char *identstring = 0;
49int verbose = 0;
50int pci_vendor_id = 0, pci_device_id = 0;
51int ispxe = 0;
52
53#if !defined(VBOX) || !defined(RT_OS_SOLARIS)
54extern int getopt(int argc, char *argv[], char *options);
55#endif
56
57/* read the first three bytes to get the ROM size */
58static long getromsize(FILE *fd)
59{
60 unsigned char buffer[3];
61 long size, i;
62
63 if (fread(buffer, sizeof(char), 3, fd) != 3) {
64 fprintf(stderr, "Cannot get first 3 bytes of file\n");
65 exit(1);
66 }
67 /* reset pointer to beginning of file */
68 if (fseek(fd, (off_t)0, SEEK_SET) < 0) {
69 perror("fseek");
70 exit(1);
71 }
72 /* warn if preamble is not 0x55 0xAA */
73 if (buffer[0] != 0x55 || buffer[1] != 0xAA)
74 fprintf(stderr, "BIOS extension ROM Image did not start with 0x55 0xAA\n");
75 size = buffer[2] * 512L;
76 /* sizes are usually powers of two, warn if not */
77 for (i = MINROMSIZE; i < MAXROMSIZE && i < size; i *= 2)
78 ;
79 if (size > 0 && i > size)
80 fprintf(stderr, "%ld is a strange size for a boot ROM\n",
81 size);
82 return (size);
83}
84
85static unsigned int addident(void)
86{
87 /* include the terminating NUL byte too */
88 int len = strlen(identstring) + 1;
89
90 /* Put the identifier in only if the space is blank */
91 if (strspn((char *)&rom[romsize-len-2], "\377") >= len) {
92 memcpy(&rom[romsize-len-2], identstring, len);
93 return (romsize-len-2); /* return offset */
94 }
95 return (0); /* otherwise return 0 */
96}
97
98/* Accepts a spec of the form vendorid,deviceid where the ids are
99 numeric strings accepted by strtoul */
100static void getpciids(char *spec)
101{
102 char *vendor, *device;
103 unsigned long value;
104 char *endptr;
105
106 vendor = spec;
107 device = strchr(spec, ',');
108 if (device != 0)
109 *device++ = '\0';
110 value = strtoul(vendor, &endptr, 0);
111 if (*vendor != '\0' && endptr != vendor && *endptr == '\0')
112 pci_vendor_id = value;
113 if (device == 0)
114 return;
115 value = strtoul(device, &endptr, 0);
116 if (*device != '\0' && endptr != device && *endptr == '\0')
117 pci_device_id = value;
118}
119
120static void pcipnpheaders(unsigned int identoffset)
121{
122 int pnp_hdr_offset, pci_hdr_offset;
123 int i;
124 unsigned int sum;
125
126 pci_hdr_offset = rom[PCI_PTR_LOC] + (rom[PCI_PTR_LOC+1] << 8);
127 pnp_hdr_offset = rom[PNP_PTR_LOC] + (rom[PNP_PTR_LOC+1] << 8);
128 /* sanity checks */
129 if (pci_hdr_offset < PCI_PTR_LOC + 2
130 || pci_hdr_offset > romsize - PCI_HDR_SIZE
131 || pnp_hdr_offset <= PCI_PTR_LOC + 2
132 || pnp_hdr_offset > romsize - PNP_HDR_SIZE)
133 pci_hdr_offset = pnp_hdr_offset = 0;
134 else if (memcmp(&rom[pci_hdr_offset], "PCIR", sizeof("PCIR")-1) != 0
135 || memcmp(&rom[pnp_hdr_offset], "$PnP", sizeof("$PnP")-1) != 0)
136 pci_hdr_offset = pnp_hdr_offset = 0;
137 else
138 printf("PCI header at 0x%x and PnP header at 0x%x\n",
139 pci_hdr_offset, pnp_hdr_offset);
140 if (pci_hdr_offset)
141 {
142 /* we only fill in the low byte, this limits us to ROMs of
143 255 * 512 bytes = 127.5kB or so */
144 rom[pci_hdr_offset+PCI_SIZE_OFF] = (romsize / 512) & 0xff;
145 rom[pci_hdr_offset+PCI_SIZE_OFF+1] = (romsize / 512) >> 8;
146 if (pci_vendor_id != 0)
147 {
148 rom[pci_hdr_offset+PCI_VEND_ID_OFF] = pci_vendor_id & 0xff;
149 rom[pci_hdr_offset+PCI_VEND_ID_OFF+1] = pci_vendor_id >> 8;
150 }
151 if (pci_device_id != 0)
152 {
153 rom[pci_hdr_offset+PCI_DEV_ID_OFF] = pci_device_id & 0xff;
154 rom[pci_hdr_offset+PCI_DEV_ID_OFF+1] = pci_device_id >> 8;
155 }
156 }
157 if (pnp_hdr_offset)
158 {
159 /* Point to device id string at end of ROM image */
160 rom[pnp_hdr_offset+PNP_DEVICE_OFF] = identoffset & 0xff;
161 rom[pnp_hdr_offset+PNP_DEVICE_OFF+1] = identoffset >> 8;
162 rom[pnp_hdr_offset+PNP_CHKSUM_OFF] = '\0';
163 for (i = pnp_hdr_offset, sum = 0; i < pnp_hdr_offset + PNP_HDR_SIZE; ++i)
164 sum += rom[i];
165 rom[pnp_hdr_offset+PNP_CHKSUM_OFF] = -sum;
166 }
167}
168
169static void undiheaders(void)
170{
171 int undi_hdr_offset;
172 int i;
173 unsigned int sum;
174
175 undi_hdr_offset = rom[UNDI_PTR_LOC] + (rom[UNDI_PTR_LOC+1] << 8);
176 /* sanity checks */
177 if (undi_hdr_offset < UNDI_PTR_LOC + 2
178 || undi_hdr_offset > romsize - UNDI_HDR_SIZE
179 || rom[undi_hdr_offset] != 'U'
180 || rom[undi_hdr_offset+1] != 'N'
181 || rom[undi_hdr_offset+2] != 'D'
182 || rom[undi_hdr_offset+3] != 'I')
183 undi_hdr_offset = 0;
184 else
185 printf("UNDI header at %#x\n", undi_hdr_offset);
186 if (undi_hdr_offset) {
187 rom[undi_hdr_offset+UNDI_CHKSUM_OFF] = '\0';
188 for (i = undi_hdr_offset, sum = 0; i < undi_hdr_offset + UNDI_HDR_SIZE; ++i)
189 sum += rom[i];
190 rom[undi_hdr_offset+UNDI_CHKSUM_OFF] = -sum;
191 }
192}
193
194static void checksum(void)
195{
196 int i;
197 unsigned int sum;
198
199 rom[5] = '\0';
200 for (i = 0, sum = 0; i < romsize; i++)
201 sum += rom[i];
202 rom[5] = -sum;
203 /* double check */
204 for (i = 0, sum = 0; i < romsize; i++)
205 sum += rom[i];
206 if (sum & 0xFF)
207 printf("Checksum fails.\n");
208 else if (verbose)
209 printf("Checksum ok\n");
210}
211
212int main(int argc, char **argv)
213{
214 int i;
215 long fs;
216 FILE *fd;
217 unsigned int identoffset;
218 char *progname;
219 int is3c503;
220 extern int optind;
221 extern char *optarg;
222
223 progname = argv[0];
224 is3c503 = 0;
225 while ((i = getopt(argc, argv, "3xi:p:s:v")) >= 0) {
226 switch (i) {
227 case '3':
228 is3c503 = 1;
229 break;
230 case 'x':
231 ispxe = 1;
232 break;
233 case 'i':
234 identstring = optarg;
235 break;
236 case 'p':
237 getpciids(optarg);
238 break;
239 case 's':
240 romsize = atol(optarg);
241 if (romsize <= 0)
242 romsize = 32768L;
243 break;
244 case 'v':
245 ++verbose;
246 break;
247 }
248 }
249 argc -= optind;
250 argv += optind;
251 if (argc < 1) {
252#if defined(__TURBOC__) || defined(__BORLANDC__)
253 fprintf(stderr, "Usage: %s [/s romsize] [/i ident] [/p vendorid,deviceid] [/3] rom-file\n", progname);
254#else
255 fprintf(stderr, "Usage: %s [-s romsize] [-i ident] [-p vendorid,deviceid] [-3] rom-file\n", progname);
256#endif
257 exit(1);
258 }
259 if ((fd = fopen(argv[0], "rb+")) == NULL) {
260 perror(argv[0]);
261 exit(1);
262 }
263 /* If size not specified, infer it from 3rd byte */
264 if (romsize == 0 && !ispxe )
265 romsize = getromsize(fd);
266 /* If that is 0, choose the right size */
267 if (romsize == 0)
268 romsize = MAXROMSIZE;
269 if ((rom = malloc(romsize+1)) == 0) {
270 fprintf(stderr, "Cannot malloc memory for ROM buffer\n");
271 exit(1);
272 }
273 /* fill with FFs, slightly less work for PROM burner
274 and allows limited patching */
275 memset(rom, 0xFF, romsize);
276 rom[romsize]=0;
277 if ((fs = fread(rom, sizeof(char), romsize, fd)) < 0) {
278 perror("fread");
279 exit(1);
280 }
281 if (verbose)
282 printf("%ld bytes read\n", fs);
283 if (ispxe) {
284 romsize=fs;
285 rom[2] = (romsize + 511L) / 512L;
286 goto writerom ;
287 }
288
289 if (fs == romsize && fgetc(fd) != EOF) {
290 fprintf(stderr, "ROM size of %ld not big enough for data\n", romsize);
291 exit(1);
292 }
293 /* shrink it down to the smallest size that will do */
294#ifndef VBOX
295 for (romsize = MAXROMSIZE; romsize > MINROMSIZE && romsize >= 2*fs; )
296 romsize /= 2L;
297#else
298 /* VBox can handle ROM BIOS at page boundaries */
299 romsize = (fs + 4095) & ~0xfff;
300#endif
301 rom[2] = romsize / 512L;
302 rom[5] = 0;
303 if (verbose)
304 printf("ROM size is %ld\n", romsize);
305 if (identstring != 0)
306 identoffset = addident();
307 else
308 identoffset = 0;
309 pcipnpheaders(identoffset);
310 undiheaders();
311 /* 3c503 requires last two bytes to be MAGIC_3C503 */
312 if (is3c503 && romsize == MINROMSIZE) {
313 rom[MINROMSIZE - 1] = rom[MINROMSIZE - 2] = MAGIC_3C503;
314 }
315 checksum();
316 writerom:
317 if (fseek(fd, (off_t)0, SEEK_SET) < 0) {
318 perror("fseek");
319 exit(1);
320 }
321 if (fwrite(rom, sizeof(char), romsize, fd) != romsize) {
322 perror(argv[0]);
323 exit(1);
324 }
325 fclose(fd);
326 exit(0);
327}
328/*
329 * Local variables:
330 * c-basic-offset: 8
331 * End:
332 */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette