]> git.ipfire.org Git - ipfire-2.x.git/blame - src/hwinfo/src/x86emu/sys.c
Kleiner netter neuer Versuch.
[ipfire-2.x.git] / src / hwinfo / src / x86emu / sys.c
CommitLineData
a6316ce4
MT
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
56X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */
57X86EMU_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))
75struct __una_u64 { unsigned long x __attribute__((packed)); };
76struct __una_u32 { unsigned int x __attribute__((packed)); };
77struct __una_u16 { unsigned short x __attribute__((packed)); };
78#endif
79
80static __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
99static __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
118static __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
141static __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
166static __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
191static __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 */
223struct __una_u64 { unsigned long x __attribute__((packed)); };
224struct __una_u32 { unsigned int x __attribute__((packed)); };
225struct __una_u16 { unsigned short x __attribute__((packed)); };
226
227static __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
234static __inline__ unsigned long
235uldl (const unsigned int * r11)
236{
237 const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
238 return ptr->x;
239}
240
241static __inline__ unsigned long
242uldw (const unsigned short * r11)
243{
244 const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
245 return ptr->x;
246}
247
248static __inline__ void
249ustq (unsigned long r5, unsigned long * r11)
250{
251 struct __una_u64 *ptr = (struct __una_u64 *) r11;
252 ptr->x = r5;
253}
254
255static __inline__ void
256ustl (unsigned long r5, unsigned int * r11)
257{
258 struct __una_u32 *ptr = (struct __una_u32 *) r11;
259 ptr->x = r5;
260}
261
262static __inline__ void
263ustw (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/****************************************************************************
272PARAMETERS:
273addr - Emulator memory address to read
274
275RETURNS:
276Byte value read from emulator memory.
277
278REMARKS:
279Reads a byte value from the emulator memory.
280****************************************************************************/
281u8 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);
291DB( if (DEBUG_MEM_TRACE())
292 printk("%#08x 1 -> %#x\n", addr, val);)
293 return val;
294}
295
296/****************************************************************************
297PARAMETERS:
298addr - Emulator memory address to read
299
300RETURNS:
301Word value read from emulator memory.
302
303REMARKS:
304Reads a word value from the emulator memory.
305****************************************************************************/
306u16 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/****************************************************************************
335PARAMETERS:
336addr - Emulator memory address to read
337
338RETURNS:
339Long value read from emulator memory.
340REMARKS:
341Reads a long value from the emulator memory.
342****************************************************************************/
343u32 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
368DB( if (DEBUG_MEM_TRACE())
369 printk("%#08x 4 -> %#x\n", addr, val);)
370 return val;
371}
372
373/****************************************************************************
374PARAMETERS:
375addr - Emulator memory address to read
376val - Value to store
377
378REMARKS:
379Writes a byte value to emulator memory.
380****************************************************************************/
381void X86API wrb(
382 u32 addr,
383 u8 val)
384{
385DB( 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/****************************************************************************
395PARAMETERS:
396addr - Emulator memory address to read
397val - Value to store
398
399REMARKS:
400Writes a word value to emulator memory.
401****************************************************************************/
402void X86API wrw(
403 u32 addr,
404 u16 val)
405{
406DB( 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/****************************************************************************
429PARAMETERS:
430addr - Emulator memory address to read
431val - Value to store
432
433REMARKS:
434Writes a long value to emulator memory.
435****************************************************************************/
436void X86API wrl(
437 u32 addr,
438 u32 val)
439{
440DB( 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/****************************************************************************
465PARAMETERS:
466addr - PIO address to read
467RETURN:
4680
469REMARKS:
470Default PIO byte read function. Doesn't perform real inb.
471****************************************************************************/
472static u8 X86API p_inb(
473 X86EMU_pioAddr addr)
474{
475DB( if (DEBUG_IO_TRACE())
476 printk("inb %#04x \n", addr);)
477 return 0;
478}
479
480/****************************************************************************
481PARAMETERS:
482addr - PIO address to read
483RETURN:
4840
485REMARKS:
486Default PIO word read function. Doesn't perform real inw.
487****************************************************************************/
488static u16 X86API p_inw(
489 X86EMU_pioAddr addr)
490{
491DB( if (DEBUG_IO_TRACE())
492 printk("inw %#04x \n", addr);)
493 return 0;
494}
495
496/****************************************************************************
497PARAMETERS:
498addr - PIO address to read
499RETURN:
5000
501REMARKS:
502Default PIO long read function. Doesn't perform real inl.
503****************************************************************************/
504static u32 X86API p_inl(
505 X86EMU_pioAddr addr)
506{
507DB( if (DEBUG_IO_TRACE())
508 printk("inl %#04x \n", addr);)
509 return 0;
510}
511
512/****************************************************************************
513PARAMETERS:
514addr - PIO address to write
515val - Value to store
516REMARKS:
517Default PIO byte write function. Doesn't perform real outb.
518****************************************************************************/
519static void X86API p_outb(
520 X86EMU_pioAddr addr,
521 u8 val)
522{
523DB( if (DEBUG_IO_TRACE())
524 printk("outb %#02x -> %#04x \n", val, addr);)
525 return;
526}
527
528/****************************************************************************
529PARAMETERS:
530addr - PIO address to write
531val - Value to store
532REMARKS:
533Default PIO word write function. Doesn't perform real outw.
534****************************************************************************/
535static void X86API p_outw(
536 X86EMU_pioAddr addr,
537 u16 val)
538{
539DB( if (DEBUG_IO_TRACE())
540 printk("outw %#04x -> %#04x \n", val, addr);)
541 return;
542}
543
544/****************************************************************************
545PARAMETERS:
546addr - PIO address to write
547val - Value to store
548REMARKS:
549Default PIO ;ong write function. Doesn't perform real outl.
550****************************************************************************/
551static void X86API p_outl(
552 X86EMU_pioAddr addr,
553 u32 val)
554{
555DB( if (DEBUG_IO_TRACE())
556 printk("outl %#08x -> %#04x \n", val, addr);)
557 return;
558}
559
560/*------------------------- Global Variables ------------------------------*/
561
562u8 (X86APIP sys_rdb)(u32 addr) = rdb;
563u16 (X86APIP sys_rdw)(u32 addr) = rdw;
564u32 (X86APIP sys_rdl)(u32 addr) = rdl;
565void (X86APIP sys_wrb)(u32 addr,u8 val) = wrb;
566void (X86APIP sys_wrw)(u32 addr,u16 val) = wrw;
567void (X86APIP sys_wrl)(u32 addr,u32 val) = wrl;
568u8 (X86APIP sys_inb)(X86EMU_pioAddr addr) = p_inb;
569u16 (X86APIP sys_inw)(X86EMU_pioAddr addr) = p_inw;
570u32 (X86APIP sys_inl)(X86EMU_pioAddr addr) = p_inl;
571void (X86APIP sys_outb)(X86EMU_pioAddr addr, u8 val) = p_outb;
572void (X86APIP sys_outw)(X86EMU_pioAddr addr, u16 val) = p_outw;
573void (X86APIP sys_outl)(X86EMU_pioAddr addr, u32 val) = p_outl;
574
575/*----------------------------- Setup -------------------------------------*/
576
577/****************************************************************************
578PARAMETERS:
579funcs - New memory function pointers to make active
580
581REMARKS:
582This function is used to set the pointers to functions which access
583memory space, allowing the user application to override these functions
584and hook them out as necessary for their application.
585****************************************************************************/
586void 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/****************************************************************************
598PARAMETERS:
599funcs - New programmed I/O function pointers to make active
600
601REMARKS:
602This function is used to set the pointers to functions which access
603I/O space, allowing the user application to override these functions
604and hook them out as necessary for their application.
605****************************************************************************/
606void 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/****************************************************************************
618PARAMETERS:
619funcs - New interrupt vector table to make active
620
621REMARKS:
622This function is used to set the pointers to functions which handle
623interrupt processing in the emulator, allowing the user application to
624hook interrupts as necessary for their application. Any interrupts that
625are not hooked by the user application, and reflected and handled internally
626in the emulator via the interrupt vector table. This allows the application
627to get control when the code being emulated executes specific software
628interrupts.
629****************************************************************************/
630void 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/****************************************************************************
644PARAMETERS:
645int - New software interrupt to prepare for
646
647REMARKS:
648This function is used to set up the emulator state to exceute a software
649interrupt. This can be used by the user application code to allow an
650interrupt to be hooked, examined and then reflected back to the emulator
651so that the code in the emulator will continue processing the software
652interrupt as per normal. This essentially allows system code to actively
653hook and handle certain software interrupts as necessary.
654****************************************************************************/
655void 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}