]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/hwinfo/src/int10/i10_vbios.c
Kleiner netter neuer Versuch.
[people/pmueller/ipfire-2.x.git] / src / hwinfo / src / int10 / i10_vbios.c
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 #include <unistd.h>
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <errno.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 <setjmp.h>
33 #if defined(__alpha__) || defined (__ia64__)
34 #include <sys/io.h>
35 //#elif defined(HAVE_SYS_PERM)
36 #else
37 #include <sys/perm.h>
38 #endif
39 #include "v86bios.h"
40 #include "pci.h"
41 #include "AsmMacros.h"
42 #include "vbios.h"
43
44 void log_err(char *format, ...) __attribute__ ((format (printf, 1, 2)));
45
46 #define SIZE 0x100000
47 #define VRAM_START 0xA0000
48 #define VRAM_SIZE 0x1FFFF
49 #define V_BIOS_SIZE 0x1FFFF
50 #define BIOS_START 0x7C00 /* default BIOS entry */
51
52 static CARD8 code[] = { 0xcd, 0x10, 0xf4 }; /* int 0x10, hlt */
53 // static CARD8 code13[] = { 0xcd, 0x13, 0xf4 }; /* int 0x13, hlt */
54
55 static int int10_bios_ok(void);
56 static int map(void);
57 static void unmap(void);
58 static int map_vram(void);
59 static void unmap_vram(void);
60 static int copy_vbios(hd_data_t *hd_data);
61 // static int copy_sbios(void);
62 #if MAP_SYS_BIOS
63 static int copy_sys_bios(hd_data_t *hd_data);
64 #endif
65 static int copy_bios_ram(hd_data_t *hd_data);
66 static int setup_system_bios(hd_data_t *hd_data);
67 static void setup_int_vect(void);
68 static int chksum(CARD8 *start);
69
70 void loadCodeToMem(unsigned char *ptr, CARD8 *code);
71
72 static int vram_mapped = 0;
73 static int int10inited = 0;
74
75 static sigjmp_buf longjmp_buf;
76
77 static void sigsegv_handler(int);
78
79 int InitInt10(hd_data_t *hd_data, int pci_cfg_method)
80 {
81 if(geteuid()) return -1;
82
83 if(!map()) return -1;
84
85 if(!setup_system_bios(hd_data)) {
86 unmap();
87 return -1;
88 }
89
90 setup_io();
91
92 if(iopl(3) < 0) {
93 unmap();
94 return -1;
95 }
96
97 scan_pci(pci_cfg_method);
98
99 for(; CurrentPci; CurrentPci = CurrentPci->next) {
100 if(CurrentPci->active) break;
101 }
102
103 iopl(0);
104
105 setup_int_vect();
106
107 if(!copy_vbios(hd_data)) {
108 unmap();
109 return -1;
110 }
111
112 if(!map_vram() || !copy_bios_ram(hd_data)) {
113 unmap();
114 return -1;
115 }
116
117 if(!int10_bios_ok()) {
118 unmap();
119 return -1;
120 }
121
122 int10inited = 1;
123
124 return 0;
125 }
126
127
128 void FreeInt10()
129 {
130 if(!int10inited) return;
131
132 unmap_vram();
133 unmap();
134
135 int10inited = 0;
136 }
137
138
139 /*
140 * Check whether int 0x10 points to some useful code.
141 */
142 int int10_bios_ok()
143 {
144 unsigned cs, ip;
145 unsigned char *p;
146
147 ip = ((uint16_t *) 0)[0x10 * 2];
148 cs = ((uint16_t *) 0)[0x10 * 2 + 1];
149
150 p = (unsigned char *) ((cs << 4) + ip);
151
152 log_err(
153 " vbe: int 10h points to %04x:%04x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
154 cs, ip,
155 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]
156 );
157
158 /* It can't possibly start with all zeros. */
159 if(!*(uint32_t *) p) {
160 log_err(" vbe: oops, int 10h points into nirvana!\n");
161
162 return 0;
163 }
164
165 return 1;
166 }
167
168
169 void sigsegv_handler(int num)
170 {
171 siglongjmp(longjmp_buf, num + 1000);
172 }
173
174
175 int CallInt10(int *ax, int *bx, int *cx, unsigned char *buf, int len, int cpuemu)
176 {
177 i86biosRegs bRegs;
178 void (*old_sigsegv_handler)(int) = SIG_DFL;
179 void (*old_sigill_handler)(int) = SIG_DFL;
180 void (*old_sigtrap_handler)(int) = SIG_DFL;
181 int jmp;
182
183 if(!int10inited) return -1;
184 memset(&bRegs, 0, sizeof bRegs);
185 bRegs.ax = *ax;
186 bRegs.bx = *bx;
187 bRegs.cx = *cx;
188 bRegs.dx = 0;
189 bRegs.es = 0x7e0;
190 bRegs.di = 0x0;
191 if(buf) memcpy((unsigned char *) 0x7e00, buf, len);
192
193 iopl(3);
194
195 jmp = sigsetjmp(longjmp_buf, 1);
196
197 if(!jmp) {
198 old_sigsegv_handler = signal(SIGSEGV, sigsegv_handler);
199 old_sigill_handler = signal(SIGILL, sigsegv_handler);
200 old_sigtrap_handler = signal(SIGTRAP, sigsegv_handler);
201
202 loadCodeToMem((unsigned char *) BIOS_START, code);
203 do_x86(BIOS_START, &bRegs, cpuemu);
204 }
205 else {
206 int10inited = 0;
207 log_err("oops: got signal %d in vm86() code\n", jmp - 1000);
208 }
209
210 signal(SIGTRAP, old_sigtrap_handler);
211 signal(SIGILL, old_sigill_handler);
212 signal(SIGSEGV, old_sigsegv_handler);
213
214 iopl(0);
215
216 if(buf) memcpy(buf, (unsigned char *) 0x7e00, len);
217
218 *ax = bRegs.ax;
219 *bx = bRegs.bx;
220 *cx = bRegs.cx;
221
222 return bRegs.ax;
223 }
224
225
226 #if 0
227 int CallInt13(int *ax, int *bx, int *cx, int *dx, unsigned char *buf, int len, int cpuemu)
228 {
229 i86biosRegs bRegs;
230
231 if(!int10inited) return -1;
232 memset(&bRegs, 0, sizeof bRegs);
233 bRegs.ax = *ax;
234 bRegs.bx = *bx;
235 bRegs.cx = *cx;
236 bRegs.dx = *dx;
237 bRegs.es = 0x7e0;
238 bRegs.ds = 0x7e0;
239 bRegs.di = 0x0;
240 bRegs.si = 0x0;
241 if(buf) memcpy((unsigned char *) 0x7e00, buf, len);
242
243 iopl(3);
244
245 loadCodeToMem((unsigned char *) BIOS_START, code13);
246 do_x86(BIOS_START, &bRegs, cpuemu);
247
248 iopl(0);
249
250 if(buf) memcpy(buf, (unsigned char *) 0x7e00, len);
251
252 *ax = bRegs.ax;
253 *bx = bRegs.bx;
254 *cx = bRegs.cx;
255 *dx = bRegs.dx;
256
257 return bRegs.ax;
258 }
259 #endif
260
261
262 int map()
263 {
264 void* mem;
265
266 mem = mmap(0, (size_t) SIZE, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
267
268 if(mem) {
269 perror("anonymous map");
270 return 0;
271 }
272
273 memset(mem, 0, SIZE);
274
275 loadCodeToMem((unsigned char *) BIOS_START, code);
276
277 return 1;
278 }
279
280
281 void unmap()
282 {
283 munmap(0, SIZE);
284 }
285
286
287 static int
288 map_vram(void)
289 {
290 int mem_fd;
291
292 #ifdef __ia64__
293 if ((mem_fd = open(MEM_FILE,O_RDWR | O_SYNC))<0)
294 #else
295 if ((mem_fd = open(MEM_FILE,O_RDWR))<0)
296 #endif
297 {
298 perror("opening memory");
299 return 0;
300 }
301
302 #ifndef __alpha__
303 if (mmap((void *) VRAM_START, (size_t) VRAM_SIZE,
304 PROT_EXEC | PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
305 mem_fd, VRAM_START) == (void *) -1)
306 #else
307 if (!_bus_base()) sparse_shift = 7; /* Uh, oh, JENSEN... */
308 if (!_bus_base_sparse()) sparse_shift = 0;
309 if ((vram_map = mmap(0,(size_t) (VRAM_SIZE << sparse_shift),
310 PROT_READ | PROT_WRITE,
311 MAP_SHARED,
312 mem_fd, (VRAM_START << sparse_shift)
313 | _bus_base_sparse())) == (void *) -1)
314 #endif
315 {
316 perror("mmap error in map_hardware_ram");
317 close(mem_fd);
318 return (0);
319 }
320 vram_mapped = 1;
321 close(mem_fd);
322 return (1);
323 }
324
325
326 void unmap_vram()
327 {
328 if(!vram_mapped) return;
329
330 munmap((void*) VRAM_START, VRAM_SIZE);
331
332 vram_mapped = 0;
333 }
334
335
336 /*
337 * Read video BIOS from /dev/mem.
338 *
339 * Return:
340 * 0: failed
341 * 1: ok
342 */
343 int copy_vbios(hd_data_t *hd_data)
344 {
345 unsigned size;
346 unsigned char tmp[3];
347
348 if(!hd_read_mmap(hd_data, MEM_FILE, tmp, V_BIOS, sizeof tmp)) {
349 log_err("vbe: failed to read %u bytes at 0x%x\n", (unsigned) sizeof tmp, V_BIOS);
350 return 0;
351 }
352
353 if(tmp[0] != 0x55 || tmp[1] != 0xAA ) {
354 log_err("vbe: no bios found at: 0x%x\n", V_BIOS);
355 return 0;
356 }
357
358 size = tmp[2] * 0x200;
359
360 if(!hd_read_mmap(hd_data, MEM_FILE, (unsigned char *) V_BIOS, V_BIOS, size)) {
361 log_err("vbe: failed to read %d bytes at 0x%x\n", size, V_BIOS);
362 return 0;
363 }
364
365 return chksum((CARD8 *) V_BIOS) ? 1 : 0;
366 }
367
368
369 #if MAP_SYS_BIOS
370 static int
371 copy_sys_bios(hd_data_t *hd_data)
372 {
373 return hd_read_mmap(hd_data, MEM_FILE, (unsigned char *) 0xf0000, 0xf0000, 0xffff);
374 }
375 #endif
376
377
378 static int copy_bios_ram(hd_data_t *hd_data)
379 {
380 return hd_read_mmap(hd_data, MEM_FILE, (unsigned char *) 0, 0, 0x1000);
381 }
382
383 void loadCodeToMem(unsigned char *ptr, CARD8 *code)
384 {
385 while((*ptr++ = *code++) != 0xf4 /* hlt */);
386
387 return;
388 }
389
390
391 /*
392 * here we are really paranoid about faking a "real"
393 * BIOS. Most of this information was pulled from
394 * dosem.
395 */
396 static void
397 setup_int_vect(void)
398 {
399 const CARD16 cs = 0x0000;
400 const CARD16 ip = 0x0;
401 int i;
402
403 /* let the int vects point to the SYS_BIOS seg */
404 for (i=0; i<0x80; i++) {
405 ((CARD16*)0)[i<<1] = ip;
406 ((CARD16*)0)[(i<<1)+1] = cs;
407 }
408 /* video interrupts default location */
409 ((CARD16*)0)[(0x42<<1)+1] = 0xf000;
410 ((CARD16*)0)[0x42<<1] = 0xf065;
411 ((CARD16*)0)[(0x10<<1)+1] = 0xf000;
412 ((CARD16*)0)[0x10<<1] = 0xf065;
413 /* video param table default location (int 1d) */
414 ((CARD16*)0)[(0x1d<<1)+1] = 0xf000;
415 ((CARD16*)0)[0x1d<<1] = 0xf0A4;
416 /* font tables default location (int 1F) */
417 ((CARD16*)0)[(0x1f<<1)+1] = 0xf000;
418 ((CARD16*)0)[0x1f<<1] = 0xfa6e;
419
420 /* int 11 default location */
421 ((CARD16*)0)[(0x11<1)+1] = 0xf000;
422 ((CARD16*)0)[0x11<<1] = 0xf84d;
423 /* int 12 default location */
424 ((CARD16*)0)[(0x12<<1)+1] = 0xf000;
425 ((CARD16*)0)[0x12<<1] = 0xf841;
426 /* int 15 default location */
427 ((CARD16*)0)[(0x15<<1)+1] = 0xf000;
428 ((CARD16*)0)[0x15<<1] = 0xf859;
429 /* int 1A default location */
430 ((CARD16*)0)[(0x1a<<1)+1] = 0xf000;
431 ((CARD16*)0)[0x1a<<1] = 0xff6e;
432 /* int 05 default location */
433 ((CARD16*)0)[(0x05<<1)+1] = 0xf000;
434 ((CARD16*)0)[0x05<<1] = 0xff54;
435 /* int 08 default location */
436 ((CARD16*)0)[(0x8<<1)+1] = 0xf000;
437 ((CARD16*)0)[0x8<<1] = 0xfea5;
438 /* int 13 default location (fdd) */
439 ((CARD16*)0)[(0x13<<1)+1] = 0xf000;
440 ((CARD16*)0)[0x13<<1] = 0xec59;
441 /* int 0E default location */
442 ((CARD16*)0)[(0xe<<1)+1] = 0xf000;
443 ((CARD16*)0)[0xe<<1] = 0xef57;
444 /* int 17 default location */
445 ((CARD16*)0)[(0x17<<1)+1] = 0xf000;
446 ((CARD16*)0)[0x17<<1] = 0xefd2;
447 /* fdd table default location (int 1e) */
448 ((CARD16*)0)[(0x1e<<1)+1] = 0xf000;
449 ((CARD16*)0)[0x1e<<1] = 0xefc7;
450 }
451
452 static int
453 setup_system_bios(hd_data_t *hd_data)
454 {
455 char *date = "06/01/99";
456 char *eisa_ident = "PCI/ISA";
457
458 #if MAP_SYS_BIOS
459 if (!copy_sys_bios(hd_data)) return 0;
460 return 1;
461 #endif
462 // memset((void *)0xF0000,0xf4,0xfff7);
463
464 /*
465 * we trap the "industry standard entry points" to the BIOS
466 * and all other locations by filling them with "hlt"
467 * TODO: implement hlt-handler for these
468 */
469 memset((void *)0xF0000,0xf4,0x10000);
470
471 /*
472 * TODO: we should copy the fdd table (0xfec59-0xfec5b)
473 * the video parameter table (0xf0ac-0xf0fb)
474 * and the font tables (0xfa6e-0xfe6d)
475 * from the original bios here
476 */
477
478 /* set bios date */
479 strcpy((char *)0xFFFF5,date);
480 /* set up eisa ident string */
481 strcpy((char *)0xFFFD9,eisa_ident);
482 /* write system model id for IBM-AT */
483 ((char *)0)[0xFFFFE] = 0xfc;
484
485 return 1;
486 }
487
488
489 /*
490 * Check BIOS CRC.
491 *
492 * Return:
493 * 0: failed
494 * 1: ok
495 */
496 int chksum(CARD8 *start)
497 {
498 CARD16 size;
499 CARD8 val = 0;
500 int i;
501
502 size = start[2] * 0x200;
503 for(i = 0; i < size; i++) val += start[i];
504
505 if(!val) return 1;
506
507 log_err("vbe: BIOS chksum wrong\n");
508
509 return 0;
510 }
511