]> git.ipfire.org Git - ipfire-2.x.git/blob - src/hwinfo/src/x86emu/sys.c
Signierten GPG-Schluessel importiert.
[ipfire-2.x.git] / src / hwinfo / src / x86emu / sys.c
1 /****************************************************************************
2 *
3 * Realmode X86 Emulator Library
4 *
5 * Copyright (C) 1996-1999 SciTech Software, Inc.
6 * Copyright (C) David Mosberger-Tang
7 * Copyright (C) 1999 Egbert Eich
8 *
9 * ========================================================================
10 *
11 * Permission to use, copy, modify, distribute, and sell this software and
12 * its documentation for any purpose is hereby granted without fee,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation, and that the name of the authors not be used
16 * in advertising or publicity pertaining to distribution of the software
17 * without specific, written prior permission. The authors makes no
18 * representations about the suitability of this software for any purpose.
19 * It is provided "as is" without express or implied warranty.
20 *
21 * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
22 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
23 * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
25 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
26 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
27 * PERFORMANCE OF THIS SOFTWARE.
28 *
29 * ========================================================================
30 *
31 * Language: ANSI C
32 * Environment: Any
33 * Developer: Kendall Bennett
34 *
35 * Description: This file includes subroutines which are related to
36 * programmed I/O and memory access. Included in this module
37 * are default functions with limited usefulness. For real
38 * uses these functions will most likely be overriden by the
39 * user library.
40 *
41 ****************************************************************************/
42 /* $XFree86: xc/extras/x86emu/src/x86emu/sys.c,v 1.6 2002/09/16 18:05:18 eich Exp $ */
43
44 #include "x86emu.h"
45 #include "x86emu/x86emui.h"
46 #include "x86emu/regs.h"
47 #include "x86emu/debug.h"
48 #include "x86emu/prim_ops.h"
49 #ifdef IN_MODULE
50 #include "xf86_ansic.h"
51 #else
52 #include <string.h>
53 #endif
54 /*------------------------- Global Variables ------------------------------*/
55
56 X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */
57 X86EMU_intrFuncs _X86EMU_intrTab[256];
58
59 /*----------------------------- Implementation ----------------------------*/
60 #if defined(__alpha__) || defined(__alpha)
61 /* to cope with broken egcs-1.1.2 :-(((( */
62
63 #define ALPHA_UALOADS
64 /*
65 * inline functions to do unaligned accesses
66 * from linux/include/asm-alpha/unaligned.h
67 */
68
69 /*
70 * EGCS 1.1 knows about arbitrary unaligned loads. Define some
71 * packed structures to talk about such things with.
72 */
73
74 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
75 struct __una_u64 { unsigned long x __attribute__((packed)); };
76 struct __una_u32 { unsigned int x __attribute__((packed)); };
77 struct __una_u16 { unsigned short x __attribute__((packed)); };
78 #endif
79
80 static __inline__ unsigned long ldq_u(unsigned long * r11)
81 {
82 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
83 const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
84 return ptr->x;
85 #else
86 unsigned long r1,r2;
87 __asm__("ldq_u %0,%3\n\t"
88 "ldq_u %1,%4\n\t"
89 "extql %0,%2,%0\n\t"
90 "extqh %1,%2,%1"
91 :"=&r" (r1), "=&r" (r2)
92 :"r" (r11),
93 "m" (*r11),
94 "m" (*(const unsigned long *)(7+(char *) r11)));
95 return r1 | r2;
96 #endif
97 }
98
99 static __inline__ unsigned long ldl_u(unsigned int * r11)
100 {
101 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
102 const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
103 return ptr->x;
104 #else
105 unsigned long r1,r2;
106 __asm__("ldq_u %0,%3\n\t"
107 "ldq_u %1,%4\n\t"
108 "extll %0,%2,%0\n\t"
109 "extlh %1,%2,%1"
110 :"=&r" (r1), "=&r" (r2)
111 :"r" (r11),
112 "m" (*r11),
113 "m" (*(const unsigned long *)(3+(char *) r11)));
114 return r1 | r2;
115 #endif
116 }
117
118 static __inline__ unsigned long ldw_u(unsigned short * r11)
119 {
120 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
121 const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
122 return ptr->x;
123 #else
124 unsigned long r1,r2;
125 __asm__("ldq_u %0,%3\n\t"
126 "ldq_u %1,%4\n\t"
127 "extwl %0,%2,%0\n\t"
128 "extwh %1,%2,%1"
129 :"=&r" (r1), "=&r" (r2)
130 :"r" (r11),
131 "m" (*r11),
132 "m" (*(const unsigned long *)(1+(char *) r11)));
133 return r1 | r2;
134 #endif
135 }
136
137 /*
138 * Elemental unaligned stores
139 */
140
141 static __inline__ void stq_u(unsigned long r5, unsigned long * r11)
142 {
143 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
144 struct __una_u64 *ptr = (struct __una_u64 *) r11;
145 ptr->x = r5;
146 #else
147 unsigned long r1,r2,r3,r4;
148
149 __asm__("ldq_u %3,%1\n\t"
150 "ldq_u %2,%0\n\t"
151 "insqh %6,%7,%5\n\t"
152 "insql %6,%7,%4\n\t"
153 "mskqh %3,%7,%3\n\t"
154 "mskql %2,%7,%2\n\t"
155 "bis %3,%5,%3\n\t"
156 "bis %2,%4,%2\n\t"
157 "stq_u %3,%1\n\t"
158 "stq_u %2,%0"
159 :"=m" (*r11),
160 "=m" (*(unsigned long *)(7+(char *) r11)),
161 "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4)
162 :"r" (r5), "r" (r11));
163 #endif
164 }
165
166 static __inline__ void stl_u(unsigned long r5, unsigned int * r11)
167 {
168 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
169 struct __una_u32 *ptr = (struct __una_u32 *) r11;
170 ptr->x = r5;
171 #else
172 unsigned long r1,r2,r3,r4;
173
174 __asm__("ldq_u %3,%1\n\t"
175 "ldq_u %2,%0\n\t"
176 "inslh %6,%7,%5\n\t"
177 "insll %6,%7,%4\n\t"
178 "msklh %3,%7,%3\n\t"
179 "mskll %2,%7,%2\n\t"
180 "bis %3,%5,%3\n\t"
181 "bis %2,%4,%2\n\t"
182 "stq_u %3,%1\n\t"
183 "stq_u %2,%0"
184 :"=m" (*r11),
185 "=m" (*(unsigned long *)(3+(char *) r11)),
186 "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4)
187 :"r" (r5), "r" (r11));
188 #endif
189 }
190
191 static __inline__ void stw_u(unsigned long r5, unsigned short * r11)
192 {
193 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
194 struct __una_u16 *ptr = (struct __una_u16 *) r11;
195 ptr->x = r5;
196 #else
197 unsigned long r1,r2,r3,r4;
198
199 __asm__("ldq_u %3,%1\n\t"
200 "ldq_u %2,%0\n\t"
201 "inswh %6,%7,%5\n\t"
202 "inswl %6,%7,%4\n\t"
203 "mskwh %3,%7,%3\n\t"
204 "mskwl %2,%7,%2\n\t"
205 "bis %3,%5,%3\n\t"
206 "bis %2,%4,%2\n\t"
207 "stq_u %3,%1\n\t"
208 "stq_u %2,%0"
209 :"=m" (*r11),
210 "=m" (*(unsigned long *)(1+(char *) r11)),
211 "=&r" (r1), "=&r" (r2), "=&r" (r3), "=&r" (r4)
212 :"r" (r5), "r" (r11));
213 #endif
214 }
215
216 #elif defined(__GNUC__) && ((__GNUC__ < 3)) && \
217 (defined (__ia64__) || defined (ia64__))
218 #define IA64_UALOADS
219 /*
220 * EGCS 1.1 knows about arbitrary unaligned loads. Define some
221 * packed structures to talk about such things with.
222 */
223 struct __una_u64 { unsigned long x __attribute__((packed)); };
224 struct __una_u32 { unsigned int x __attribute__((packed)); };
225 struct __una_u16 { unsigned short x __attribute__((packed)); };
226
227 static __inline__ unsigned long
228 __uldq (const unsigned long * r11)
229 {
230 const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
231 return ptr->x;
232 }
233
234 static __inline__ unsigned long
235 uldl (const unsigned int * r11)
236 {
237 const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
238 return ptr->x;
239 }
240
241 static __inline__ unsigned long
242 uldw (const unsigned short * r11)
243 {
244 const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
245 return ptr->x;
246 }
247
248 static __inline__ void
249 ustq (unsigned long r5, unsigned long * r11)
250 {
251 struct __una_u64 *ptr = (struct __una_u64 *) r11;
252 ptr->x = r5;
253 }
254
255 static __inline__ void
256 ustl (unsigned long r5, unsigned int * r11)
257 {
258 struct __una_u32 *ptr = (struct __una_u32 *) r11;
259 ptr->x = r5;
260 }
261
262 static __inline__ void
263 ustw (unsigned long r5, unsigned short * r11)
264 {
265 struct __una_u16 *ptr = (struct __una_u16 *) r11;
266 ptr->x = r5;
267 }
268
269 #endif
270
271 /****************************************************************************
272 PARAMETERS:
273 addr - Emulator memory address to read
274
275 RETURNS:
276 Byte value read from emulator memory.
277
278 REMARKS:
279 Reads a byte value from the emulator memory.
280 ****************************************************************************/
281 u8 X86API rdb(
282 u32 addr)
283 {
284 u8 val;
285
286 if (addr > M.mem_size - 1) {
287 DB(printk("mem_read: address %#lx out of range!\n", addr);)
288 HALT_SYS();
289 }
290 val = *(u8*)(M.mem_base + addr);
291 DB( if (DEBUG_MEM_TRACE())
292 printk("%#08x 1 -> %#x\n", addr, val);)
293 return val;
294 }
295
296 /****************************************************************************
297 PARAMETERS:
298 addr - Emulator memory address to read
299
300 RETURNS:
301 Word value read from emulator memory.
302
303 REMARKS:
304 Reads a word value from the emulator memory.
305 ****************************************************************************/
306 u16 X86API rdw(
307 u32 addr)
308 {
309 u16 val = 0;
310
311 if (addr > M.mem_size - 2) {
312 DB(printk("mem_read: address %#lx out of range!\n", addr);)
313 HALT_SYS();
314 }
315 #ifdef __BIG_ENDIAN__
316 if (addr & 0x1) {
317 val = (*(u8*)(M.mem_base + addr) |
318 (*(u8*)(M.mem_base + addr + 1) << 8));
319 }
320 else
321 #endif
322 #if defined(ALPHA_UALOADS)
323 val = ldw_u((u16*)(M.mem_base + addr));
324 #elif defined(IA64_UALOADS)
325 val = uldw((u16*)(M.mem_base + addr));
326 #else
327 val = *(u16*)(M.mem_base + addr);
328 #endif
329 DB( if (DEBUG_MEM_TRACE())
330 printk("%#08x 2 -> %#x\n", addr, val);)
331 return val;
332 }
333
334 /****************************************************************************
335 PARAMETERS:
336 addr - Emulator memory address to read
337
338 RETURNS:
339 Long value read from emulator memory.
340 REMARKS:
341 Reads a long value from the emulator memory.
342 ****************************************************************************/
343 u32 X86API rdl(
344 u32 addr)
345 {
346 u32 val = 0;
347
348 if (addr > M.mem_size - 4) {
349 DB(printk("mem_read: address %#lx out of range!\n", addr);)
350 HALT_SYS();
351 }
352 #ifdef __BIG_ENDIAN__
353 if (addr & 0x3) {
354 val = (*(u8*)(M.mem_base + addr + 0) |
355 (*(u8*)(M.mem_base + addr + 1) << 8) |
356 (*(u8*)(M.mem_base + addr + 2) << 16) |
357 (*(u8*)(M.mem_base + addr + 3) << 24));
358 }
359 else
360 #endif
361 #if defined(ALPHA_UALOADS)
362 val = ldl_u((u32*)(M.mem_base + addr));
363 #elif defined(IA64_UALOADS)
364 val = uldl((u32*)(M.mem_base + addr));
365 #else
366 val = *(u32*)(M.mem_base + addr);
367 #endif
368 DB( if (DEBUG_MEM_TRACE())
369 printk("%#08x 4 -> %#x\n", addr, val);)
370 return val;
371 }
372
373 /****************************************************************************
374 PARAMETERS:
375 addr - Emulator memory address to read
376 val - Value to store
377
378 REMARKS:
379 Writes a byte value to emulator memory.
380 ****************************************************************************/
381 void X86API wrb(
382 u32 addr,
383 u8 val)
384 {
385 DB( if (DEBUG_MEM_TRACE())
386 printk("%#08x 1 <- %#x\n", addr, val);)
387 if (addr > M.mem_size - 1) {
388 DB(printk("mem_write: address %#lx out of range!\n", addr);)
389 HALT_SYS();
390 }
391 *(u8*)(M.mem_base + addr) = val;
392 }
393
394 /****************************************************************************
395 PARAMETERS:
396 addr - Emulator memory address to read
397 val - Value to store
398
399 REMARKS:
400 Writes a word value to emulator memory.
401 ****************************************************************************/
402 void X86API wrw(
403 u32 addr,
404 u16 val)
405 {
406 DB( if (DEBUG_MEM_TRACE())
407 printk("%#08x 2 <- %#x\n", addr, val);)
408 if (addr > M.mem_size - 2) {
409 DB(printk("mem_write: address %#lx out of range!\n", addr);)
410 HALT_SYS();
411 }
412 #ifdef __BIG_ENDIAN__
413 if (addr & 0x1) {
414 *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff;
415 *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff;
416 }
417 else
418 #endif
419 #if defined(ALPHA_UALOADS)
420 stw_u(val,(u16*)(M.mem_base + addr));
421 #elif defined(IA64_UALOADS)
422 ustw(val,(u16*)(M.mem_base + addr));
423 #else
424 *(u16*)(M.mem_base + addr) = val;
425 #endif
426 }
427
428 /****************************************************************************
429 PARAMETERS:
430 addr - Emulator memory address to read
431 val - Value to store
432
433 REMARKS:
434 Writes a long value to emulator memory.
435 ****************************************************************************/
436 void X86API wrl(
437 u32 addr,
438 u32 val)
439 {
440 DB( if (DEBUG_MEM_TRACE())
441 printk("%#08x 4 <- %#x\n", addr, val);)
442 if (addr > M.mem_size - 4) {
443 DB(printk("mem_write: address %#lx out of range!\n", addr);)
444 HALT_SYS();
445 }
446 #ifdef __BIG_ENDIAN__
447 if (addr & 0x1) {
448 *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff;
449 *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff;
450 *(u8*)(M.mem_base + addr + 2) = (val >> 16) & 0xff;
451 *(u8*)(M.mem_base + addr + 3) = (val >> 24) & 0xff;
452 }
453 else
454 #endif
455 #if defined(ALPHA_UALOADS)
456 stl_u(val,(u32*)(M.mem_base + addr));
457 #elif defined(IA64_UALOADS)
458 ustl(val,(u32*)(M.mem_base + addr));
459 #else
460 *(u32*)(M.mem_base + addr) = val;
461 #endif
462 }
463
464 /****************************************************************************
465 PARAMETERS:
466 addr - PIO address to read
467 RETURN:
468 0
469 REMARKS:
470 Default PIO byte read function. Doesn't perform real inb.
471 ****************************************************************************/
472 static u8 X86API p_inb(
473 X86EMU_pioAddr addr)
474 {
475 DB( if (DEBUG_IO_TRACE())
476 printk("inb %#04x \n", addr);)
477 return 0;
478 }
479
480 /****************************************************************************
481 PARAMETERS:
482 addr - PIO address to read
483 RETURN:
484 0
485 REMARKS:
486 Default PIO word read function. Doesn't perform real inw.
487 ****************************************************************************/
488 static u16 X86API p_inw(
489 X86EMU_pioAddr addr)
490 {
491 DB( if (DEBUG_IO_TRACE())
492 printk("inw %#04x \n", addr);)
493 return 0;
494 }
495
496 /****************************************************************************
497 PARAMETERS:
498 addr - PIO address to read
499 RETURN:
500 0
501 REMARKS:
502 Default PIO long read function. Doesn't perform real inl.
503 ****************************************************************************/
504 static u32 X86API p_inl(
505 X86EMU_pioAddr addr)
506 {
507 DB( if (DEBUG_IO_TRACE())
508 printk("inl %#04x \n", addr);)
509 return 0;
510 }
511
512 /****************************************************************************
513 PARAMETERS:
514 addr - PIO address to write
515 val - Value to store
516 REMARKS:
517 Default PIO byte write function. Doesn't perform real outb.
518 ****************************************************************************/
519 static void X86API p_outb(
520 X86EMU_pioAddr addr,
521 u8 val)
522 {
523 DB( if (DEBUG_IO_TRACE())
524 printk("outb %#02x -> %#04x \n", val, addr);)
525 return;
526 }
527
528 /****************************************************************************
529 PARAMETERS:
530 addr - PIO address to write
531 val - Value to store
532 REMARKS:
533 Default PIO word write function. Doesn't perform real outw.
534 ****************************************************************************/
535 static void X86API p_outw(
536 X86EMU_pioAddr addr,
537 u16 val)
538 {
539 DB( if (DEBUG_IO_TRACE())
540 printk("outw %#04x -> %#04x \n", val, addr);)
541 return;
542 }
543
544 /****************************************************************************
545 PARAMETERS:
546 addr - PIO address to write
547 val - Value to store
548 REMARKS:
549 Default PIO ;ong write function. Doesn't perform real outl.
550 ****************************************************************************/
551 static void X86API p_outl(
552 X86EMU_pioAddr addr,
553 u32 val)
554 {
555 DB( if (DEBUG_IO_TRACE())
556 printk("outl %#08x -> %#04x \n", val, addr);)
557 return;
558 }
559
560 /*------------------------- Global Variables ------------------------------*/
561
562 u8 (X86APIP sys_rdb)(u32 addr) = rdb;
563 u16 (X86APIP sys_rdw)(u32 addr) = rdw;
564 u32 (X86APIP sys_rdl)(u32 addr) = rdl;
565 void (X86APIP sys_wrb)(u32 addr,u8 val) = wrb;
566 void (X86APIP sys_wrw)(u32 addr,u16 val) = wrw;
567 void (X86APIP sys_wrl)(u32 addr,u32 val) = wrl;
568 u8 (X86APIP sys_inb)(X86EMU_pioAddr addr) = p_inb;
569 u16 (X86APIP sys_inw)(X86EMU_pioAddr addr) = p_inw;
570 u32 (X86APIP sys_inl)(X86EMU_pioAddr addr) = p_inl;
571 void (X86APIP sys_outb)(X86EMU_pioAddr addr, u8 val) = p_outb;
572 void (X86APIP sys_outw)(X86EMU_pioAddr addr, u16 val) = p_outw;
573 void (X86APIP sys_outl)(X86EMU_pioAddr addr, u32 val) = p_outl;
574
575 /*----------------------------- Setup -------------------------------------*/
576
577 /****************************************************************************
578 PARAMETERS:
579 funcs - New memory function pointers to make active
580
581 REMARKS:
582 This function is used to set the pointers to functions which access
583 memory space, allowing the user application to override these functions
584 and hook them out as necessary for their application.
585 ****************************************************************************/
586 void X86EMU_setupMemFuncs(
587 X86EMU_memFuncs *funcs)
588 {
589 sys_rdb = funcs->rdb;
590 sys_rdw = funcs->rdw;
591 sys_rdl = funcs->rdl;
592 sys_wrb = funcs->wrb;
593 sys_wrw = funcs->wrw;
594 sys_wrl = funcs->wrl;
595 }
596
597 /****************************************************************************
598 PARAMETERS:
599 funcs - New programmed I/O function pointers to make active
600
601 REMARKS:
602 This function is used to set the pointers to functions which access
603 I/O space, allowing the user application to override these functions
604 and hook them out as necessary for their application.
605 ****************************************************************************/
606 void X86EMU_setupPioFuncs(
607 X86EMU_pioFuncs *funcs)
608 {
609 sys_inb = funcs->inb;
610 sys_inw = funcs->inw;
611 sys_inl = funcs->inl;
612 sys_outb = funcs->outb;
613 sys_outw = funcs->outw;
614 sys_outl = funcs->outl;
615 }
616
617 /****************************************************************************
618 PARAMETERS:
619 funcs - New interrupt vector table to make active
620
621 REMARKS:
622 This function is used to set the pointers to functions which handle
623 interrupt processing in the emulator, allowing the user application to
624 hook interrupts as necessary for their application. Any interrupts that
625 are not hooked by the user application, and reflected and handled internally
626 in the emulator via the interrupt vector table. This allows the application
627 to get control when the code being emulated executes specific software
628 interrupts.
629 ****************************************************************************/
630 void X86EMU_setupIntrFuncs(
631 X86EMU_intrFuncs funcs[])
632 {
633 int i;
634
635 for (i=0; i < 256; i++)
636 _X86EMU_intrTab[i] = NULL;
637 if (funcs) {
638 for (i = 0; i < 256; i++)
639 _X86EMU_intrTab[i] = funcs[i];
640 }
641 }
642
643 /****************************************************************************
644 PARAMETERS:
645 int - New software interrupt to prepare for
646
647 REMARKS:
648 This function is used to set up the emulator state to exceute a software
649 interrupt. This can be used by the user application code to allow an
650 interrupt to be hooked, examined and then reflected back to the emulator
651 so that the code in the emulator will continue processing the software
652 interrupt as per normal. This essentially allows system code to actively
653 hook and handle certain software interrupts as necessary.
654 ****************************************************************************/
655 void X86EMU_prepareForInt(
656 int num)
657 {
658 push_word((u16)M.x86.R_FLG);
659 CLEAR_FLAG(F_IF);
660 CLEAR_FLAG(F_TF);
661 push_word(M.x86.R_CS);
662 M.x86.R_CS = mem_access_word(num * 4 + 2);
663 push_word(M.x86.R_IP);
664 M.x86.R_IP = mem_access_word(num * 4);
665 M.x86.intr = 0;
666 }