]>
Commit | Line | Data |
---|---|---|
c7de829c WD |
1 | /* |
2 | * Copyright 1999 Egbert Eich | |
3 | * | |
4 | * Permission to use, copy, modify, distribute, and sell this software and its | |
5 | * documentation for any purpose is hereby granted without fee, provided that | |
6 | * the above copyright notice appear in all copies and that both that | |
7 | * copyright notice and this permission notice appear in supporting | |
8 | * documentation, and that the name of the authors not be used in | |
9 | * advertising or publicity pertaining to distribution of the software without | |
10 | * specific, written prior permission. The authors makes no representations | |
11 | * about the suitability of this software for any purpose. It is provided | |
12 | * "as is" without express or implied warranty. | |
13 | * | |
14 | * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |
16 | * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |
20 | * PERFORMANCE OF THIS SOFTWARE. | |
21 | */ | |
22 | #define DELETE | |
23 | #include <unistd.h> | |
24 | #include <fcntl.h> | |
25 | #include <stdio.h> | |
26 | #include <sys/mman.h> | |
27 | #include <sys/types.h> | |
28 | #include <string.h> | |
29 | #include <stdlib.h> | |
30 | #include <signal.h> | |
31 | #include <sys/stat.h> | |
32 | #include <readline/readline.h> | |
33 | #include <readline/history.h> | |
34 | #if defined(__alpha__) || defined (__ia64__) | |
35 | #include <sys/io.h> | |
36 | #elif defined(HAVE_SYS_PERM) | |
37 | #include <sys/perm.h> | |
38 | #endif | |
39 | #include "debug.h" | |
40 | #include "v86bios.h" | |
41 | #include "pci.h" | |
42 | #include "AsmMacros.h" | |
43 | ||
44 | #define SIZE 0x100000 | |
45 | #define VRAM_START 0xA0000 | |
46 | #define VRAM_SIZE 0x1FFFF | |
47 | #define V_BIOS_SIZE 0x1FFFF | |
48 | #define BIOS_START 0x7C00 /* default BIOS entry */ | |
49 | #define BIOS_MEM 0x600 | |
50 | ||
8bde7f77 | 51 | /*CARD8 code[] = { 0xb8 , 0xf0 , 0xf0, 0xf4 }; */ |
c7de829c WD |
52 | #define VB_X(x) (V_BIOS >> x) & 0xFF |
53 | CARD8 code[] = { 6, 0x9a, 0x03, 0x00, 0x00, VB_X(12), 0xf4 }; | |
8bde7f77 WD |
54 | /*CARD8 code[] = { 0x9a, 0x03, 0x00, 0x00, VB_X(12), 0xb8, 0x03, 0x00, */ |
55 | /*0xcd, 0x10, 0xf4 }; */ | |
56 | /*CARD8 code[] = { 0xb8 , 0xf0 , 0xf0 ,0xf4 }; */ | |
c7de829c WD |
57 | |
58 | int ioperm_list[IOPERM_BITS] = {0,}; | |
59 | ||
60 | static void sig_handler(int); | |
61 | static int map(void); | |
62 | static void unmap(void); | |
63 | static void bootBIOS(CARD16 ax); | |
64 | static int map_vram(void); | |
65 | static void unmap_vram(void); | |
66 | static int copy_vbios(memType v_base); | |
67 | static int copy_sys_bios(void); | |
68 | static void save_bios_to_file(void); | |
69 | static int setup_system_bios(void); | |
70 | static CARD32 setup_int_vect(void); | |
71 | #ifdef __ia32__ | |
72 | static CARD32 setup_primary_int_vect(void); | |
73 | #endif | |
74 | static int chksum(CARD8 *start); | |
75 | static void setup_bios_regs(i86biosRegsPtr regs, CARD32 ax); | |
76 | static void print_regs(i86biosRegsPtr regs); | |
77 | static void print_usage(void); | |
78 | static void set_hlt(Bool set); | |
79 | static void set_ioperm(void); | |
80 | ||
81 | extern void yyparse(); | |
82 | ||
83 | void loadCodeToMem(unsigned char *ptr, CARD8 *code); | |
84 | void dprint(unsigned long start, unsigned long size); | |
85 | ||
86 | static int vram_mapped = 0; | |
87 | static char* bios_var = NULL; | |
88 | static CARD8 save_msr; | |
89 | static CARD8 save_pos102; | |
90 | static CARD8 save_vse; | |
91 | static CARD8 save_46e8; | |
92 | static haltpoints hltp[20] = { {0, 0}, }; | |
93 | ||
94 | console Console = {-1,-1}; | |
95 | struct config Config; | |
96 | ||
97 | int main(int argc,char **argv) | |
98 | { | |
99 | int c; | |
8bde7f77 | 100 | |
c7de829c WD |
101 | Config.PrintPort = PRINT_PORT; |
102 | Config.IoStatistics = IO_STATISTICS; | |
103 | Config.PrintIrq = PRINT_IRQ; | |
104 | Config.PrintPci = PRINT_PCI; | |
8bde7f77 WD |
105 | Config.ShowAllDev = SHOW_ALL_DEV; |
106 | Config.PrintIp = PRINT_IP; | |
107 | Config.SaveBios = SAVE_BIOS; | |
108 | Config.Trace = TRACE; | |
c7de829c WD |
109 | Config.ConfigActiveOnly = CONFIG_ACTIVE_ONLY; /* boot */ |
110 | Config.ConfigActiveDevice = CONFIG_ACTIVE_DEVICE; /* boot */ | |
8bde7f77 WD |
111 | Config.MapSysBios = MAP_SYS_BIOS; |
112 | Config.Resort = RESORT; /* boot */ | |
113 | Config.FixRom = FIX_ROM; | |
c7de829c WD |
114 | Config.NoConsole = NO_CONSOLE; |
115 | Config.BootOnly = FALSE; | |
116 | Config.Verbose = VERBOSE; | |
8bde7f77 WD |
117 | |
118 | opterr = 0; | |
c7de829c WD |
119 | while ((c = getopt(argc,argv,"psicaPStAdbrfnv:?")) != EOF) { |
120 | switch(c) { | |
121 | case 'p': | |
8bde7f77 WD |
122 | Config.PrintPort = TRUE; |
123 | break; | |
c7de829c | 124 | case 's': |
8bde7f77 WD |
125 | Config.IoStatistics = TRUE; |
126 | break; | |
c7de829c | 127 | case 'i': |
8bde7f77 WD |
128 | Config.PrintIrq = TRUE; |
129 | break; | |
c7de829c | 130 | case 'c': |
8bde7f77 WD |
131 | Config.PrintPci = TRUE; |
132 | break; | |
c7de829c | 133 | case 'a': |
8bde7f77 WD |
134 | Config.ShowAllDev = TRUE; |
135 | break; | |
c7de829c | 136 | case 'P': |
8bde7f77 WD |
137 | Config.PrintIp = TRUE; |
138 | break; | |
c7de829c | 139 | case 'S': |
8bde7f77 WD |
140 | Config.SaveBios = TRUE; |
141 | break; | |
c7de829c | 142 | case 't': |
8bde7f77 WD |
143 | Config.Trace = TRUE; |
144 | break; | |
c7de829c | 145 | case 'A': |
8bde7f77 WD |
146 | Config.ConfigActiveOnly = TRUE; |
147 | break; | |
c7de829c | 148 | case 'd': |
8bde7f77 WD |
149 | Config.ConfigActiveDevice = TRUE; |
150 | break; | |
c7de829c | 151 | case 'b': |
8bde7f77 WD |
152 | Config.MapSysBios = TRUE; |
153 | break; | |
c7de829c | 154 | case 'r': |
8bde7f77 WD |
155 | Config.Resort = TRUE; |
156 | break; | |
c7de829c | 157 | case 'f': |
8bde7f77 WD |
158 | Config.FixRom = TRUE; |
159 | break; | |
c7de829c | 160 | case 'n': |
8bde7f77 WD |
161 | Config.NoConsole = TRUE; |
162 | break; | |
c7de829c | 163 | case 'v': |
8bde7f77 WD |
164 | Config.Verbose = strtol(optarg,NULL,0); |
165 | break; | |
c7de829c | 166 | case '?': |
8bde7f77 WD |
167 | print_usage(); |
168 | break; | |
c7de829c | 169 | default: |
8bde7f77 | 170 | break; |
c7de829c WD |
171 | } |
172 | } | |
8bde7f77 WD |
173 | |
174 | ||
c7de829c WD |
175 | if (!map()) |
176 | exit(1); | |
8bde7f77 | 177 | |
c7de829c WD |
178 | if (!setup_system_bios()) |
179 | exit(1); | |
8bde7f77 | 180 | |
c7de829c WD |
181 | iopl(3); |
182 | ||
183 | scan_pci(); | |
184 | ||
185 | save_msr = inb(0x3CC); | |
186 | save_vse = inb(0x3C3); | |
187 | save_46e8 = inb(0x46e8); | |
188 | save_pos102 = inb(0x102); | |
189 | ||
190 | if (Config.BootOnly) { | |
8bde7f77 | 191 | |
c7de829c | 192 | if (!CurrentPci && !Config.ConfigActiveDevice |
8bde7f77 WD |
193 | && !Config.ConfigActiveOnly) { |
194 | iopl(0); | |
195 | unmap(); | |
196 | exit (1); | |
c7de829c WD |
197 | } |
198 | call_boot(NULL); | |
199 | } else { | |
200 | using_history(); | |
201 | yyparse(); | |
202 | } | |
8bde7f77 | 203 | |
c7de829c WD |
204 | unmap(); |
205 | ||
206 | pciVideoRestore(); | |
8bde7f77 | 207 | |
c7de829c WD |
208 | outb(0x102, save_pos102); |
209 | outb(0x46e8, save_46e8); | |
210 | outb(0x3C3, save_vse); | |
211 | outb(0x3C2, save_msr); | |
212 | ||
213 | iopl(0); | |
214 | ||
215 | close_console(Console); | |
216 | ||
217 | exit(0); | |
218 | } | |
219 | ||
220 | ||
221 | void | |
222 | call_boot(struct device *dev) | |
223 | { | |
224 | int Active_is_Pci = 0; | |
225 | CARD32 vbios_base; | |
8bde7f77 | 226 | |
c7de829c WD |
227 | CurrentPci = PciList; |
228 | Console = open_console(); | |
8bde7f77 | 229 | |
c7de829c WD |
230 | set_ioperm(); |
231 | ||
8bde7f77 | 232 | |
c7de829c WD |
233 | signal(2,sig_handler); |
234 | signal(11,sig_handler); | |
8bde7f77 | 235 | |
c7de829c WD |
236 | /* disable primary card */ |
237 | pciVideoRestore(); /* reset PCI state to see primary card */ | |
238 | outb(0x3C2,~(CARD8)0x03 & save_msr); | |
239 | outb(0x3C3,~(CARD8)0x01 & save_vse); | |
240 | outb(0x46e8, ~(CARD8)0x08 & save_46e8); | |
241 | outb(0x102, ~(CARD8)0x01 & save_pos102); | |
8bde7f77 | 242 | |
c7de829c | 243 | pciVideoDisable(); |
8bde7f77 | 244 | |
c7de829c WD |
245 | while (CurrentPci) { |
246 | CARD16 ax; | |
8bde7f77 | 247 | |
c7de829c | 248 | if (CurrentPci->active) { |
8bde7f77 WD |
249 | Active_is_Pci = 1; |
250 | if (!Config.ConfigActiveDevice && !dev) { | |
251 | CurrentPci = CurrentPci->next; | |
252 | continue; | |
253 | } | |
c7de829c | 254 | } else if (Config.ConfigActiveOnly && !dev) { |
8bde7f77 WD |
255 | CurrentPci = CurrentPci->next; |
256 | continue; | |
c7de829c WD |
257 | } |
258 | if (dev && ((dev->type != PCI) | |
8bde7f77 WD |
259 | || (dev->type == PCI |
260 | && (dev->loc.pci.dev != CurrentPci->dev | |
261 | || dev->loc.pci.bus != CurrentPci->bus | |
262 | || dev->loc.pci.func != CurrentPci->func)))) { | |
263 | CurrentPci = CurrentPci->next; | |
264 | continue; | |
265 | } | |
266 | ||
c7de829c | 267 | EnableCurrent(); |
8bde7f77 | 268 | |
c7de829c | 269 | if (CurrentPci->active) { |
8bde7f77 WD |
270 | outb(0x102, save_pos102); |
271 | outb(0x46e8, save_46e8); | |
272 | outb(0x3C3, save_vse); | |
273 | outb(0x3C2, save_msr); | |
c7de829c | 274 | } |
8bde7f77 | 275 | |
c7de829c WD |
276 | /* clear interrupt vectors */ |
277 | #ifdef __ia32__ | |
278 | vbios_base = CurrentPci->active ? setup_primary_int_vect() | |
8bde7f77 | 279 | : setup_int_vect(); |
c7de829c WD |
280 | #else |
281 | vbios_base = setup_int_vect(); | |
282 | #endif | |
283 | ax = ((CARD16)(CurrentPci->bus) << 8) | |
8bde7f77 | 284 | | (CurrentPci->dev << 3) | (CurrentPci->func & 0x7); |
c7de829c | 285 | if (Config.Verbose > 1) P_printf("ax: 0x%x\n",ax); |
8bde7f77 | 286 | |
c7de829c | 287 | BootBios = findPciByIDs(CurrentPci->bus,CurrentPci->dev, |
8bde7f77 | 288 | CurrentPci->func); |
c7de829c | 289 | if (!((mapPciRom(BootBios) && chksum((CARD8*)V_BIOS)) |
8bde7f77 WD |
290 | || (CurrentPci->active && copy_vbios(vbios_base)))) { |
291 | CurrentPci = CurrentPci->next; | |
292 | continue; | |
c7de829c WD |
293 | } |
294 | if (!map_vram()) { | |
8bde7f77 WD |
295 | CurrentPci = CurrentPci->next; |
296 | continue; | |
c7de829c WD |
297 | } |
298 | if (Config.SaveBios) save_bios_to_file(); | |
299 | printf("initializing PCI bus: %i dev: %i func: %i\n",CurrentPci->bus, | |
8bde7f77 | 300 | CurrentPci->dev,CurrentPci->func); |
c7de829c WD |
301 | bootBIOS(ax); |
302 | unmap_vram(); | |
303 | ||
304 | if (CurrentPci->active) | |
8bde7f77 | 305 | close_console(Console); |
c7de829c WD |
306 | |
307 | if (dev) return; | |
8bde7f77 | 308 | |
c7de829c WD |
309 | CurrentPci = CurrentPci->next; |
310 | } | |
8bde7f77 | 311 | |
c7de829c WD |
312 | /* We have an ISA device - configure if requested */ |
313 | if (!Active_is_Pci /* no isa card in system! */ | |
314 | && ((!dev && (Config.ConfigActiveDevice || Config.ConfigActiveOnly)) | |
8bde7f77 | 315 | || (dev && dev->type == ISA))) { |
c7de829c WD |
316 | |
317 | pciVideoDisable(); | |
318 | ||
319 | if (!dev || dev->type == ISA) { | |
8bde7f77 WD |
320 | outb(0x102, save_pos102); |
321 | outb(0x46e8, save_46e8); | |
322 | outb(0x3C3, save_vse); | |
323 | outb(0x3C2, save_msr); | |
324 | ||
c7de829c | 325 | #ifdef __ia32__ |
8bde7f77 | 326 | vbios_base = setup_primary_int_vect(); |
c7de829c | 327 | #else |
8bde7f77 | 328 | vbios_base = setup_int_vect(); |
c7de829c | 329 | #endif |
8bde7f77 WD |
330 | if (copy_vbios(vbios_base)) { |
331 | ||
332 | if (Config.SaveBios) save_bios_to_file(); | |
333 | if (map_vram()) { | |
334 | printf("initializing ISA bus\n"); | |
335 | bootBIOS(0); | |
336 | } | |
337 | } | |
338 | ||
339 | unmap_vram(); | |
340 | sleep(1); | |
341 | close_console(Console); | |
342 | } | |
343 | } | |
344 | ||
345 | ||
c7de829c WD |
346 | } |
347 | ||
8bde7f77 | 348 | int |
c7de829c WD |
349 | map(void) |
350 | { | |
351 | void* mem; | |
352 | mem = mmap(0, (size_t)SIZE, | |
8bde7f77 WD |
353 | PROT_EXEC | PROT_READ | PROT_WRITE, |
354 | MAP_FIXED | MAP_PRIVATE | MAP_ANON, | |
355 | -1, 0 ); | |
c7de829c | 356 | if (mem != 0) { |
8bde7f77 WD |
357 | perror("anonymous map"); |
358 | return (0); | |
c7de829c WD |
359 | } |
360 | memset(mem,0,SIZE); | |
361 | ||
362 | return (1); | |
363 | } | |
364 | ||
365 | static void | |
366 | unmap(void) | |
367 | { | |
368 | munmap(0,SIZE); | |
369 | } | |
370 | ||
371 | static void | |
372 | bootBIOS(CARD16 ax) | |
373 | { | |
374 | i86biosRegs bRegs; | |
375 | #ifdef V86BIOS_DEBUG | |
376 | printf("starting BIOS\n"); | |
377 | #endif | |
378 | setup_io(); | |
379 | setup_bios_regs(&bRegs, ax); | |
380 | loadCodeToMem((unsigned char *) BIOS_START, code); | |
381 | do_x86(BIOS_START,&bRegs); | |
382 | #ifdef V86BIOS_DEBUG | |
383 | printf("done\n"); | |
384 | #endif | |
385 | } | |
386 | ||
387 | static int | |
388 | map_vram(void) | |
389 | { | |
390 | int mem_fd; | |
391 | ||
392 | #ifdef __ia64__ | |
8bde7f77 | 393 | if ((mem_fd = open(MEM_FILE,O_RDWR | O_SYNC))<0) |
c7de829c | 394 | #else |
8bde7f77 | 395 | if ((mem_fd = open(MEM_FILE,O_RDWR))<0) |
c7de829c | 396 | #endif |
8bde7f77 WD |
397 | { |
398 | perror("opening memory"); | |
399 | return 0; | |
c7de829c WD |
400 | } |
401 | ||
402 | #ifdef __alpha__ | |
403 | if (!_bus_base()) sparse_shift = 7; /* Uh, oh, JENSEN... */ | |
8bde7f77 WD |
404 | if (!_bus_base_sparse()) sparse_shift = 0; |
405 | if ((vram_map = mmap(0,(size_t) (VRAM_SIZE << sparse_shift), | |
406 | PROT_READ | PROT_WRITE, | |
407 | MAP_SHARED, | |
408 | mem_fd, (VRAM_START << sparse_shift) | |
409 | | _bus_base_sparse())) == (void *) -1) | |
c7de829c WD |
410 | #else |
411 | if (mmap((void *) VRAM_START, (size_t) VRAM_SIZE, | |
8bde7f77 WD |
412 | PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, |
413 | mem_fd, VRAM_START) == (void *) -1) | |
c7de829c WD |
414 | #endif |
415 | { | |
8bde7f77 WD |
416 | perror("mmap error in map_hardware_ram (1)"); |
417 | close(mem_fd); | |
418 | return (0); | |
419 | } | |
c7de829c WD |
420 | vram_mapped = 1; |
421 | close(mem_fd); | |
422 | return (1); | |
423 | } | |
424 | ||
425 | static void | |
426 | unmap_vram(void) | |
427 | { | |
428 | if (!vram_mapped) return; | |
8bde7f77 | 429 | |
c7de829c WD |
430 | munmap((void*)VRAM_START,VRAM_SIZE); |
431 | vram_mapped = 0; | |
432 | } | |
433 | ||
434 | static int | |
435 | copy_vbios(memType v_base) | |
436 | { | |
437 | int mem_fd; | |
438 | unsigned char *tmp; | |
439 | int size; | |
440 | ||
441 | if ((mem_fd = open(MEM_FILE,O_RDONLY))<0) { | |
8bde7f77 WD |
442 | perror("opening memory"); |
443 | return (0); | |
c7de829c WD |
444 | } |
445 | ||
8bde7f77 WD |
446 | if (lseek(mem_fd,(off_t) v_base, SEEK_SET) != (off_t) v_base) { |
447 | fprintf(stderr,"Cannot lseek\n"); | |
448 | goto Error; | |
c7de829c WD |
449 | } |
450 | tmp = (unsigned char *)malloc(3); | |
451 | if (read(mem_fd, (char *)tmp, (size_t) 3) != (size_t) 3) { | |
8bde7f77 WD |
452 | fprintf(stderr,"Cannot read\n"); |
453 | goto Error; | |
c7de829c | 454 | } |
8bde7f77 WD |
455 | if (lseek(mem_fd,(off_t) v_base,SEEK_SET) != (off_t) v_base) |
456 | goto Error; | |
c7de829c WD |
457 | |
458 | if (*tmp != 0x55 || *(tmp+1) != 0xAA ) { | |
8bde7f77 WD |
459 | fprintf(stderr,"No bios found at: 0x%lx\n",v_base); |
460 | goto Error; | |
c7de829c WD |
461 | } |
462 | #ifdef DEBUG | |
8bde7f77 | 463 | dprint((unsigned long)tmp,0x100); |
c7de829c WD |
464 | #endif |
465 | size = *(tmp+2) * 512; | |
466 | ||
467 | if (read(mem_fd, (char *)v_base, (size_t) size) != (size_t) size) { | |
8bde7f77 WD |
468 | fprintf(stderr,"Cannot read\n"); |
469 | goto Error; | |
c7de829c WD |
470 | } |
471 | free(tmp); | |
472 | close(mem_fd); | |
473 | if (!chksum((CARD8*)v_base)) | |
8bde7f77 | 474 | return (0); |
c7de829c WD |
475 | |
476 | return (1); | |
477 | ||
478 | Error: | |
479 | perror("v_bios"); | |
480 | close(mem_fd); | |
481 | return (0); | |
482 | } | |
483 | ||
484 | static int | |
485 | copy_sys_bios(void) | |
486 | { | |
487 | #define SYS_BIOS 0xF0000 | |
488 | int mem_fd; | |
489 | ||
490 | if ((mem_fd = open(MEM_FILE,O_RDONLY))<0) { | |
8bde7f77 WD |
491 | perror("opening memory"); |
492 | return (0); | |
c7de829c | 493 | } |
8bde7f77 WD |
494 | |
495 | if (lseek(mem_fd,(off_t) SYS_BIOS,SEEK_SET) != (off_t) SYS_BIOS) | |
496 | goto Error; | |
497 | if (read(mem_fd, (char *)SYS_BIOS, (size_t) 0xFFFF) != (size_t) 0xFFFF) | |
498 | goto Error; | |
c7de829c WD |
499 | |
500 | close(mem_fd); | |
501 | return (1); | |
502 | ||
503 | Error: | |
504 | perror("sys_bios"); | |
505 | close(mem_fd); | |
506 | return (0); | |
507 | } | |
508 | ||
509 | void | |
510 | loadCodeToMem(unsigned char *ptr, CARD8 code[]) | |
511 | { | |
512 | int i; | |
513 | CARD8 val; | |
514 | int size = code[0]; | |
8bde7f77 | 515 | |
c7de829c | 516 | for ( i=1;i<=size;i++) { |
8bde7f77 WD |
517 | val = code[i]; |
518 | *ptr++ = val; | |
c7de829c WD |
519 | } |
520 | return; | |
521 | } | |
8bde7f77 WD |
522 | |
523 | void | |
c7de829c WD |
524 | dprint(unsigned long start, unsigned long size) |
525 | { | |
526 | int i,j; | |
527 | char *c = (char *)start; | |
528 | ||
529 | for (j = 0; j < (size >> 4); j++) { | |
530 | char *d = c; | |
531 | printf("\n0x%lx: ",(unsigned long)c); | |
8bde7f77 WD |
532 | for (i = 0; i<16; i++) |
533 | printf("%2.2x ",(unsigned char) (*(c++))); | |
c7de829c WD |
534 | c = d; |
535 | for (i = 0; i<16; i++) { | |
8bde7f77 WD |
536 | printf("%c",((((CARD8)(*c)) > 32) && (((CARD8)(*c)) < 128)) ? |
537 | (unsigned char) (*(c)): '.'); | |
538 | c++; | |
c7de829c WD |
539 | } |
540 | } | |
541 | printf("\n"); | |
542 | } | |
543 | ||
544 | static void | |
545 | save_bios_to_file(void) | |
546 | { | |
547 | static int num = 0; | |
548 | int size, count; | |
549 | char file_name[256]; | |
550 | int fd; | |
8bde7f77 | 551 | |
c7de829c WD |
552 | sprintf(file_name,"bios_%i.fil",num); |
553 | if ((fd = open(file_name,O_WRONLY | O_CREAT | O_TRUNC,00644)) == -1) | |
8bde7f77 | 554 | return; |
c7de829c WD |
555 | size = (*(unsigned char*)(V_BIOS + 2)) * 512; |
556 | #ifdef V86BIOS_DEBUG | |
557 | dprint(V_BIOS,20); | |
558 | #endif | |
559 | if ((count = write(fd,(void *)(V_BIOS),size)) != size) | |
8bde7f77 | 560 | fprintf(stderr,"only saved %i of %i bytes\n",size,count); |
c7de829c WD |
561 | num++; |
562 | } | |
563 | ||
564 | static void | |
565 | sig_handler(int unused) | |
566 | { | |
567 | fflush(stdout); | |
568 | fflush(stderr); | |
569 | ||
570 | /* put system back in a save state */ | |
571 | unmap_vram(); | |
572 | pciVideoRestore(); | |
573 | outb(0x102, save_pos102); | |
574 | outb(0x46e8, save_46e8); | |
575 | outb(0x3C3, save_vse); | |
576 | outb(0x3C2, save_msr); | |
577 | ||
578 | close_console(Console); | |
579 | iopl(0); | |
580 | unmap(); | |
581 | ||
582 | exit(1); | |
583 | } | |
584 | ||
585 | /* | |
586 | * For initialization we just pass ax to the BIOS. | |
587 | * PCI BIOSes need this. All other register are set 0. | |
588 | */ | |
589 | static void setup_bios_regs(i86biosRegsPtr regs, CARD32 ax) | |
590 | { | |
591 | regs->ax = ax; | |
592 | regs->bx = 0; | |
593 | regs->cx = 0; | |
594 | regs->dx = 0; | |
595 | regs->es = 0; | |
596 | regs->ds = 0x40; /* standard pc ds */ | |
597 | regs->si = 0; | |
598 | regs->di = 0; | |
599 | } | |
600 | ||
601 | /* | |
602 | * here we are really paranoid about faking a "real" | |
603 | * BIOS. Most of this information was pulled from | |
604 | * dosem. | |
605 | */ | |
606 | ||
607 | #ifdef __ia32__ | |
608 | static CARD32 | |
609 | setup_primary_int_vect(void) | |
610 | { | |
611 | int mem_fd; | |
612 | CARD32 vbase; | |
613 | void *map; | |
614 | ||
8bde7f77 WD |
615 | if ((mem_fd = open(MEM_FILE,O_RDWR))<0) |
616 | { | |
c7de829c WD |
617 | perror("opening memory"); |
618 | return (0); | |
619 | } | |
8bde7f77 | 620 | |
c7de829c | 621 | if ((map = mmap((void *) 0, (size_t) 0x2000, |
8bde7f77 WD |
622 | PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED, |
623 | mem_fd, 0)) == (void *)-1) { | |
c7de829c WD |
624 | perror("mmap error in map_hardware_ram (2)"); |
625 | close(mem_fd); | |
626 | return (0); | |
627 | } | |
628 | ||
629 | close(mem_fd); | |
630 | memcpy(0,map,BIOS_MEM); | |
631 | munmap(map,0x2000); | |
632 | /* | |
633 | * create a backup copy of the bios variables to write back the | |
634 | * modified values | |
635 | */ | |
636 | if (!bios_var) | |
637 | bios_var = (char *)malloc(BIOS_MEM); | |
638 | memcpy(bios_var,0,BIOS_MEM); | |
8bde7f77 | 639 | |
c7de829c WD |
640 | vbase = (*((CARD16*)(0x10 << 2) + 1)) << 4; |
641 | if (Config.Verbose > 0) printf("vbase: 0x%x\n",vbase); | |
642 | return vbase; | |
643 | } | |
644 | #endif | |
645 | ||
646 | static CARD32 | |
647 | setup_int_vect(void) | |
648 | { | |
649 | const CARD16 cs = 0x0; | |
650 | const CARD16 ip = 0x0; | |
651 | int i; | |
8bde7f77 | 652 | |
c7de829c WD |
653 | /* let the int vects point to the SYS_BIOS seg */ |
654 | for (i=0; i<0x80; i++) { | |
8bde7f77 WD |
655 | ((CARD16*)0)[i<<1] = ip; |
656 | ((CARD16*)0)[(i<<1)+1] = cs; | |
c7de829c WD |
657 | } |
658 | /* video interrupts default location */ | |
659 | ((CARD16*)0)[(0x42<<1)+1] = 0xf000; | |
660 | ((CARD16*)0)[0x42<<1] = 0xf065; | |
661 | ((CARD16*)0)[(0x10<<1)+1] = 0xf000; | |
662 | ((CARD16*)0)[0x10<<1] = 0xf065; | |
663 | /* video param table default location (int 1d) */ | |
664 | ((CARD16*)0)[(0x1d<<1)+1] = 0xf000; | |
665 | ((CARD16*)0)[0x1d<<1] = 0xf0A4; | |
666 | /* font tables default location (int 1F) */ | |
667 | ((CARD16*)0)[(0x1f<<1)+1] = 0xf000; | |
668 | ((CARD16*)0)[0x1f<<1] = 0xfa6e; | |
669 | ||
670 | /* int 11 default location */ | |
671 | ((CARD16*)0)[(0x11<<1)+1] = 0xf000; | |
672 | ((CARD16*)0)[0x11<<1] = 0xf84d; | |
673 | /* int 12 default location */ | |
674 | ((CARD16*)0)[(0x12<<1)+1] = 0xf000; | |
675 | ((CARD16*)0)[0x12<<1] = 0xf841; | |
676 | /* int 15 default location */ | |
677 | ((CARD16*)0)[(0x15<<1)+1] = 0xf000; | |
678 | ((CARD16*)0)[0x15<<1] = 0xf859; | |
679 | /* int 1A default location */ | |
680 | ((CARD16*)0)[(0x1a<<1)+1] = 0xf000; | |
681 | ((CARD16*)0)[0x1a<<1] = 0xff6e; | |
682 | /* int 05 default location */ | |
683 | ((CARD16*)0)[(0x05<<1)+1] = 0xf000; | |
684 | ((CARD16*)0)[0x05<<1] = 0xff54; | |
685 | /* int 08 default location */ | |
686 | ((CARD16*)0)[(0x8<<1)+1] = 0xf000; | |
687 | ((CARD16*)0)[0x8<<1] = 0xfea5; | |
688 | /* int 13 default location (fdd) */ | |
689 | ((CARD16*)0)[(0x13<<1)+1] = 0xf000; | |
690 | ((CARD16*)0)[0x13<<1] = 0xec59; | |
691 | /* int 0E default location */ | |
692 | ((CARD16*)0)[(0xe<<1)+1] = 0xf000; | |
693 | ((CARD16*)0)[0xe<<1] = 0xef57; | |
694 | /* int 17 default location */ | |
695 | ((CARD16*)0)[(0x17<<1)+1] = 0xf000; | |
696 | ((CARD16*)0)[0x17<<1] = 0xefd2; | |
697 | /* fdd table default location (int 1e) */ | |
698 | ((CARD16*)0)[(0x1e<<1)+1] = 0xf000; | |
699 | ((CARD16*)0)[0x1e<<1] = 0xefc7; | |
700 | return V_BIOS; | |
701 | } | |
702 | ||
703 | static int | |
704 | setup_system_bios(void) | |
705 | { | |
706 | char *date = "06/01/99"; | |
707 | char *eisa_ident = "PCI/ISA"; | |
8bde7f77 | 708 | |
c7de829c WD |
709 | if (Config.MapSysBios) { |
710 | ||
8bde7f77 WD |
711 | if (!copy_sys_bios()) return 0; |
712 | return 1; | |
c7de829c WD |
713 | |
714 | } else { | |
715 | ||
8bde7f77 WD |
716 | /* memset((void *)0xF0000,0xf4,0xfff7); */ |
717 | ||
718 | /* | |
719 | * we trap the "industry standard entry points" to the BIOS | |
720 | * and all other locations by filling them with "hlt" | |
721 | * TODO: implement hlt-handler for these | |
722 | */ | |
723 | memset((void *)0xF0000,0xf4,0x10000); | |
724 | ||
725 | /* | |
726 | * TODO: we should copy the fdd table (0xfec59-0xfec5b) | |
727 | * the video parameter table (0xf0ac-0xf0fb) | |
728 | * and the font tables (0xfa6e-0xfe6d) | |
729 | * from the original bios here | |
730 | */ | |
731 | ||
732 | /* set bios date */ | |
733 | strcpy((char *)0xFFFF5,date); | |
734 | /* set up eisa ident string */ | |
735 | strcpy((char *)0xFFFD9,eisa_ident); | |
736 | /* write system model id for IBM-AT */ | |
737 | ((char *)0)[0xFFFFE] = 0xfc; | |
738 | ||
739 | return 1; | |
740 | } | |
741 | ||
c7de829c WD |
742 | } |
743 | ||
744 | static void | |
745 | update_bios_vars(void) | |
746 | { | |
747 | int mem_fd; | |
748 | void *map; | |
749 | memType i; | |
8bde7f77 | 750 | |
c7de829c | 751 | #ifdef __ia64__ |
8bde7f77 | 752 | if ((mem_fd = open(MEM_FILE,O_RDWR | O_SYNC))<0) |
c7de829c | 753 | #else |
8bde7f77 | 754 | if ((mem_fd = open(MEM_FILE,O_RDWR))<0) |
c7de829c | 755 | #endif |
8bde7f77 | 756 | { |
c7de829c WD |
757 | perror("opening memory"); |
758 | return; | |
759 | } | |
8bde7f77 | 760 | |
c7de829c | 761 | if ((map = mmap((void *) 0, (size_t) 0x2000, |
8bde7f77 WD |
762 | PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED, |
763 | mem_fd, 0)) == (void *)-1) { | |
c7de829c WD |
764 | perror("mmap error in map_hardware_ram (3)"); |
765 | close(mem_fd); | |
766 | return; | |
767 | } | |
768 | ||
769 | for (i = 0; i < BIOS_MEM; i++) { | |
8bde7f77 WD |
770 | if (bios_var[i] != *(CARD8*)i) |
771 | *((CARD8*)map + i) = *(CARD8*)i; | |
c7de829c WD |
772 | } |
773 | ||
774 | munmap(map,0x2000); | |
775 | close(mem_fd); | |
776 | } | |
777 | ||
778 | static int | |
779 | chksum(CARD8 *start) | |
780 | { | |
781 | CARD16 size; | |
782 | CARD8 val = 0; | |
783 | int i; | |
784 | ||
8bde7f77 | 785 | size = *(start+2) * 512; |
c7de829c WD |
786 | for (i = 0; i<size; i++) |
787 | val += *(start + i); | |
8bde7f77 | 788 | |
c7de829c WD |
789 | if (!val) |
790 | return 1; | |
791 | ||
792 | fprintf(stderr,"BIOS cksum wrong!\n"); | |
793 | return 0; | |
794 | } | |
795 | ||
796 | void | |
797 | runINT(int num, i86biosRegsPtr Regs) | |
798 | { | |
799 | Bool isVideo = FALSE; | |
800 | CARD8 code_int[] = { 3, 0xcd, 0x00, 0xf4 }; | |
801 | ||
802 | code_int[2] = (CARD8) num; | |
8bde7f77 | 803 | |
c7de829c WD |
804 | if (num == 0x10) |
805 | isVideo = TRUE; | |
8bde7f77 | 806 | |
c7de829c WD |
807 | if (!setup_system_bios()) |
808 | return; | |
809 | ||
810 | if ((isVideo && (!CurrentPci || CurrentPci->active)) || !isVideo) { | |
811 | CARD32 vbios_base; | |
812 | ||
813 | #ifdef __ia32__ | |
814 | if (!(vbios_base = setup_primary_int_vect())) | |
815 | #else | |
816 | if (!(vbios_base = setup_int_vect())) | |
817 | #endif | |
8bde7f77 | 818 | return; |
c7de829c | 819 | if (!copy_vbios(vbios_base)) |
8bde7f77 | 820 | return; |
c7de829c | 821 | } |
8bde7f77 | 822 | |
c7de829c WD |
823 | if (!map_vram()) |
824 | return; | |
8bde7f77 | 825 | |
c7de829c | 826 | #ifdef V86BIOS_DEBUG |
8bde7f77 | 827 | printf("starting BIOS\n"); |
c7de829c WD |
828 | #endif |
829 | loadCodeToMem((unsigned char *) BIOS_START, code_int); | |
830 | setup_io(); | |
831 | print_regs(Regs); | |
832 | set_ioperm(); | |
833 | set_hlt(TRUE); | |
834 | do_x86(BIOS_START,Regs); | |
835 | set_hlt(FALSE); | |
836 | print_regs(Regs); | |
8bde7f77 | 837 | |
c7de829c WD |
838 | #ifdef V86BIOS_DEBUG |
839 | printf("done\n"); | |
840 | #endif | |
841 | ||
8bde7f77 | 842 | if ((isVideo && (!CurrentPci || CurrentPci->active)) || !isVideo) |
c7de829c WD |
843 | update_bios_vars(); |
844 | } | |
845 | ||
846 | static void | |
847 | print_regs(i86biosRegsPtr regs) | |
848 | { | |
849 | printf("ax=%x bx=%x cx=%x dx=%x ds=%x es=%x di=%x si=%x\n", | |
850 | (CARD16)regs->ax,(CARD16)regs->bx,(CARD16)regs->cx,(CARD16)regs->dx, | |
851 | (CARD16)regs->ds,(CARD16)regs->es,(CARD16)regs->di, | |
852 | (CARD16)regs->si); | |
853 | } | |
854 | ||
855 | static void | |
856 | print_usage(void) | |
857 | { | |
858 | } | |
859 | ||
860 | void | |
861 | add_hlt(unsigned long val) | |
862 | { | |
863 | int i; | |
864 | ||
865 | if (val < BIOS_MEM || (val > VRAM_START && val < (VRAM_START + VRAM_SIZE)) | |
866 | || val >= SIZE) { | |
867 | printf("address out of range\n"); | |
868 | return; | |
869 | } | |
8bde7f77 | 870 | |
c7de829c WD |
871 | for (i=0; i<20; i++) { |
872 | if (hltp[i].address == 0) { | |
8bde7f77 WD |
873 | hltp[i].address = (void*)val; |
874 | break; | |
c7de829c WD |
875 | } |
876 | } | |
877 | if (i == 20) printf("no more hltpoints available\n"); | |
878 | } | |
879 | ||
880 | void | |
881 | del_hlt(int val) | |
882 | { | |
883 | if (val == 21) { /* delete all */ | |
884 | int i; | |
885 | printf("clearing all hltpoints\n"); | |
886 | for (i=0; i <20; i++) | |
8bde7f77 | 887 | hltp[i].address = NULL; |
c7de829c WD |
888 | } else if (val >= 0 && val <20) |
889 | hltp[val].address = NULL; | |
890 | else printf("hltpoint %i out of range: valid range 0-19\n",val); | |
891 | } | |
892 | ||
893 | void | |
894 | list_hlt() | |
895 | { | |
896 | int i; | |
8bde7f77 | 897 | for (i=0; i<20; i++) |
c7de829c | 898 | if (hltp[i].address) |
8bde7f77 | 899 | printf("hltpoint[%i]: 0x%lx\n",i,(unsigned long)hltp[i].address); |
c7de829c WD |
900 | } |
901 | ||
902 | static void | |
903 | set_hlt(Bool set) | |
904 | { | |
905 | int i; | |
8bde7f77 | 906 | for (i=0; i<20; i++) |
c7de829c | 907 | if (hltp[i].address) { |
8bde7f77 WD |
908 | if (set) { |
909 | hltp[i].orgval = *(CARD8*)hltp[i].address; | |
910 | *(CARD8*)hltp[i].address = 0xf4; | |
911 | } else | |
912 | *(CARD8*)hltp[i].address = hltp[i].orgval; | |
c7de829c WD |
913 | } |
914 | } | |
915 | ||
916 | static void | |
917 | set_ioperm(void) | |
918 | { | |
919 | int i, start; | |
920 | ||
921 | ioperm(0,IOPERM_BITS,0); | |
922 | ||
923 | for (i = 0; i < IOPERM_BITS;i++) | |
924 | if (ioperm_list[i]) { | |
8bde7f77 WD |
925 | start = i; |
926 | for (;i < IOPERM_BITS; i++) { | |
927 | if (!ioperm_list[i]) { | |
928 | ioperm(start,i - start, 1); | |
929 | break; | |
930 | } | |
931 | } | |
c7de829c WD |
932 | } |
933 | } |