nvramtool: 64bit safe CBFS handling
[coreboot.git] / util / vgabios / testbios.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/io.h>
5 #include <sys/mman.h>
6 #include <fcntl.h>
7 #include <getopt.h>
8 #include <string.h>
9
10 #define die(x) { perror(x); exit(1); }
11 #define warn(x) { perror(x);  }
12
13 #include <x86emu/x86emu.h>
14 #include "helper_exec.h"
15 #include "test.h"
16 #include "pci-userspace.h"
17
18 void x86emu_dump_xregs(void);
19 int int15_handler(void);
20 int int16_handler(void);
21 int int1A_handler(void);
22 #ifndef _PC
23 int int42_handler(void);
24 #endif
25 int intE6_handler(void);
26
27 void pushw(u16 val);
28
29 unsigned short get_device(char *arg_val);
30
31 extern int teststart, testend;
32
33 _ptr p;
34 ptr current = 0;
35 unsigned char biosmem[1024 * 1024];
36
37 int verbose = 0;
38
39
40 /* Interrupt multiplexer */
41
42 void do_int(int num)
43 {
44         int ret = 0;
45
46         printf("int%x vector at %x\n", num, getIntVect(num));
47
48         /* This is a pInt leftover */
49         current->num = num;
50
51         switch (num) {
52 #ifndef _PC
53         case 0x10:
54         case 0x42:
55         case 0x6D:
56
57                 if (getIntVect(num) == 0xFF065) {
58                         ret = int42_handler();
59                 }
60                 break;
61 #endif
62         case 0x15:
63                 ret = int15_handler();
64                 break;
65         case 0x16:
66                 ret = int16_handler();
67                 break;
68         case 0x1A:
69                 ret = int1A_handler();
70                 break;
71         case 0xe6:
72                 ret = intE6_handler();
73                 break;
74         default:
75                 break;
76         }
77
78         if (!ret)
79                 ret = run_bios_int(num);
80
81         if (!ret) {
82                 printf("\nint%x: not implemented\n", num);
83                 //x86emu_dump_xregs();
84         }
85 }
86
87 unsigned char *mapitin(char *file, off_t where, size_t size)
88 {
89         void *z;
90
91         int fd = open(file, O_RDWR, 0);
92
93         if (fd < 0)
94                 die(file);
95         z = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, where);
96         if (z == (void *) -1)
97                 die("mmap");
98         close(fd);
99
100         return z;
101
102 }
103
104 u8 x_inb(u16 port);
105 u16 x_inw(u16 port);
106 void x_outb(u16 port, u8 val);
107 void x_outw(u16 port, u16 val);
108 u32 x_inl(u16 port);
109 void x_outl(u16 port, u32 val);
110
111
112 X86EMU_pioFuncs myfuncs = {
113         x_inb, x_inw, x_inl,
114         x_outb, x_outw, x_outl
115 };
116
117
118 void usage(char *name)
119 {
120         printf
121             ("Usage: %s [-c codesegment] [-s size] [-b base] [-i ip] [-t] <filename> ... \n",
122              name);
123 }
124
125 int main(int argc, char **argv)
126 {
127         char *absegname = 0;
128         void *abseg = 0;
129         int i, c, trace = 0;
130         unsigned char *cp;
131         char *filename;
132         size_t size = 0;
133         int base = 0;
134         int have_size = 0, have_base = 0, have_ip = 0, have_cs = 0;
135         int have_devfn = 0;
136         int parse_rom = 0;
137         char *fsegname = 0;
138         unsigned char *fsegptr;
139         unsigned short initialip = 0, initialcs = 0, devfn = 0;
140         X86EMU_intrFuncs intFuncs[256];
141         void X86EMU_setMemBase(void *base, size_t size);
142         void x86emu_dump_xregs(void);
143         int X86EMU_set_debug(int debug);
144         int debugflag = 0;
145
146         const char *optstring = "vh?b:i:c:s:tpd:";
147         while (1) {
148                 int option_index = 0;
149                 static struct option long_options[] = {
150                         {"verbose", 0, 0, 'v'},
151                         {"help", 0, 0, 'h'},
152                         {"trace", 0, 0, 't'},
153                         {"base", 1, 0, 'b'},
154                         {"fseg", 1, 0, 'f'},
155                         {"instructionpointer", 1, 0, 'i'},
156                         {"codesegment", 1, 0, 'c'},
157                         {"absegment", 1, 0, 'a'},
158                         {"size", 1, 0, 's'},
159                         {"parserom", 0, 0, 'p'},
160                         {"device", 1, 0, 'd'},
161                         {"debug", 1, 0, 'D'},
162                         {0, 0, 0, 0}
163                 };
164                 c = getopt_long(argc, argv, optstring, long_options, &option_index);
165                 if (c == -1)
166                         break;
167                 switch (c) {
168                 case 'v':
169                         verbose = 1;
170                         break;
171                 case 'h':
172                 case '?':
173                         usage(argv[0]);
174                         return 0;
175                 case 't':
176                         trace = 1;
177                         break;
178                 case 'b':
179                         base = strtol(optarg, 0, 0);
180                         have_base = 1;
181                         break;
182                 case 'i':
183                         initialip = strtol(optarg, 0, 0);
184                         have_ip = 1;
185                         break;
186                 case 'c':
187                         initialcs = strtol(optarg, 0, 0);
188                         have_cs = 1;
189                         break;
190                 case 's':
191                         size = strtol(optarg, 0, 0);
192                         have_size = 1;
193                         break;
194                 case 'p':
195                         printf("Parsing rom images not implemented.\n");
196                         parse_rom = 1;
197                         break;
198                 case 'f':
199                         fsegname = optarg;
200                         break;
201                 case 'a':
202                         absegname = optarg;
203                         break;
204                 case 'd':
205                         devfn = get_device(optarg);
206                         have_devfn = 1;
207                         break;
208                 case 'D':
209                         debugflag = strtol(optarg, 0, 0);
210                         break;
211                 default:
212                         printf("Unknown option \n");
213                         usage(argv[0]);
214                         return 1;
215                 }
216         }
217
218         if (optind >= argc) {
219                 printf("Filename missing.\n");
220                 usage(argv[0]);
221                 return 1;
222         }
223
224         while (optind < argc) {
225                 printf("running file %s\n", argv[optind]);
226                 filename = argv[optind];
227                 optind++;
228                 /* normally we would do continue, but for
229                  * now only one filename is supported.
230                  */
231                 /* continue; */
232                 break;
233         }
234
235         if (!have_size) {
236                 printf("No size specified. defaulting to 32k\n");
237                 size = 32 * 1024;
238         }
239         if (!have_base) {
240                 printf("No base specified. defaulting to 0xc0000\n");
241                 base = 0xc0000;
242         }
243         if (!have_cs) {
244                 printf("No initial code segment specified. defaulting to 0xc000\n");
245                 initialcs = 0xc000;
246         }
247         if (!have_ip) {
248                 printf
249                     ("No initial instruction pointer specified. defaulting to 0x0003\n");
250                 initialip = 0x0003;
251         }
252
253         //printf("Point 1 int%x vector at %x\n", 0x42, getIntVect(0x42));
254
255         if (initialip == 0x0003) {
256                 if ((devfn == 0) || (have_devfn == 0)) {
257                         printf("WARNING! It appears you are trying to run an option ROM.\n");
258                         printf("  (initial ip = 0x0003)\n");
259                         if (have_devfn) {
260                                 printf("  However, the device you have specified is 0x00\n");
261                                 printf("  It is very unlikely that your device is at this address\n");
262                                 printf("  Please check your -d option\n");
263                         }
264                         else {
265                                 printf("  Please specify a device with -d\n");
266                                 printf("  The default is not likely to work\n");
267                         }
268                 }
269         }
270
271         if (absegname) {
272                 abseg = mapitin(absegname, (off_t) 0xa0000, 0x20000);
273                 if (!abseg)
274                         die(absegname);
275         }
276
277         current = &p;
278         X86EMU_setMemBase(biosmem, sizeof(biosmem));
279         M.abseg = (unsigned long)abseg;
280         X86EMU_setupPioFuncs(&myfuncs);
281         ioperm(0, 0x400, 1);
282
283         if (iopl(3) < 0) {
284                 warn("iopl failed, continuing anyway");
285         }
286
287         /* Emergency sync ;-) */
288         sync();
289         sync();
290
291         /* Setting up interrupt environment.
292          * basically this means initializing PCI and
293          * intXX handlers.
294          */
295         pciInit();
296
297         for (i = 0; i < 256; i++)
298                 intFuncs[i] = do_int;
299         X86EMU_setupIntrFuncs(intFuncs);
300         cp = mapitin(filename, (off_t) 0, size);
301
302         if (devfn) {
303                 printf("Loading ax with BusDevFn = %x\n",devfn);
304         }
305
306         current->ax = devfn   ? devfn : 0xff;
307         current->dx = 0x80;
308         //      current->ip = 0;
309         for (i = 0; i < size; i++)
310                 wrb(base + i, cp[i]);
311
312         if (fsegname) {
313                 fsegptr = mapitin(fsegname, (off_t) 0, 0x10000);
314                 for (i = 0; i < 0x10000; i++)
315                         wrb(0xf0000 + i, fsegptr[i]);
316         } else {
317                 char *date = "01/01/99";
318                 for (i = i; date[i]; i++)
319                         wrb(0xffff5 + i, date[i]);
320                 wrb(0xffff7, '/');
321                 wrb(0xffffa, '/');
322         }
323         /* cpu setup */
324         X86_AX = devfn ? devfn : 0xff;
325         X86_DX = 0x80;
326         X86_EIP = initialip;
327         X86_CS = initialcs;
328
329         /* Initialize stack and data segment */
330         X86_SS = 0x0030;
331         X86_DS = 0x0040;
332         X86_SP = 0xfffe;
333         /* We need a sane way to return from bios
334          * execution. A hlt instruction and a pointer
335          * to it, both kept on the stack, will do.
336          */
337         pushw(0xf4f4);          /* hlt; hlt */
338         pushw(X86_SS);
339         pushw(X86_SP + 2);
340
341         X86_ES = 0x0000;
342
343         if (trace) {
344                 printf("Switching to single step mode.\n");
345                 //X86EMU_trace_on();
346         }
347         if (debugflag) {
348                 //X86EMU_set_debug(debugflag);
349         }
350         X86EMU_exec();
351         /* Cleaning up */
352         pciExit();
353
354         return 0;
355 }
356
357 unsigned short get_device(char *arg_val)
358 {
359         unsigned short devfn=0;
360         long bus=0,dev=0,fn=0,need_pack=0;
361         char *tok;
362
363         tok = strsep(&arg_val,":");
364         if (arg_val != NULL) {
365                 bus = strtol(tok,0,16);
366                 need_pack = 1;
367         }
368         else {
369                 arg_val = tok;
370         }
371
372         tok = strsep(&arg_val,".");
373         if (arg_val != NULL) {
374                 dev = strtol(tok,0,16);
375                 fn  = strtol(arg_val,0,16);
376                 need_pack = 1;
377         }
378         else {
379                 if (need_pack ==1 && (strlen(tok))) {
380                         dev = strtol(tok,0,16);
381                 }
382         }
383
384         if ( need_pack == 1) {
385                 devfn = bus<<8 | (dev<<3) | fn;
386         }
387         else {
388                 devfn = strtol(tok, 0, 0);
389         }
390
391
392         return devfn;
393 }
394