VirtualBox

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

Last change on this file since 31 was 31, checked in by vboxsync, 18 years ago

Move etherboot BIOS from 0xc8000...0xcffff to 0xcb000...0xcffff as it does not need more than 20KB and the VGA BIOS needs more than 32KB in future versions.

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