initial commit
[profile/ivi/xorg-x11-server.git] / hw / xfree86 / 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
43 #include "x86emu.h"
44 #include "x86emu/x86emui.h"
45 #include "x86emu/regs.h"
46 #include "x86emu/debug.h"
47 #include "x86emu/prim_ops.h"
48 #ifndef NO_SYS_HEADERS
49 #include <string.h>
50 #endif                                                                                           
51
52 # ifndef NO_INLINE
53 #  ifdef __GNUC__
54
55 /* Define some packed structures to use with unaligned accesses */
56
57 struct __una_u64 { u64 x __attribute__((packed)); };
58 struct __una_u32 { u32 x __attribute__((packed)); };
59 struct __una_u16 { u16 x __attribute__((packed)); };
60
61 /* Elemental unaligned loads */
62
63 static __inline__ u64 ldq_u(u64 *p)
64 {
65         const struct __una_u64 *ptr = (const struct __una_u64 *) p;
66         return ptr->x;
67 }
68
69 static __inline__ u32 ldl_u(u32 *p)
70 {
71         const struct __una_u32 *ptr = (const struct __una_u32 *) p;
72         return ptr->x;
73 }
74
75 static __inline__ u16 ldw_u(u16 *p)
76 {
77         const struct __una_u16 *ptr = (const struct __una_u16 *) p;
78         return ptr->x;
79 }
80
81 /* Elemental unaligned stores */
82
83 static __inline__ void stq_u(u64 val, u64 *p)
84 {
85         struct __una_u64 *ptr = (struct __una_u64 *) p;
86         ptr->x = val;
87 }
88
89 static __inline__ void stl_u(u32 val, u32 *p)
90 {
91         struct __una_u32 *ptr = (struct __una_u32 *) p;
92         ptr->x = val;
93 }
94
95 static __inline__ void stw_u(u16 val, u16 *p)
96 {
97         struct __una_u16 *ptr = (struct __una_u16 *) p;
98         ptr->x = val;
99 }
100 #  else /* !__GNUC__ */
101
102 static __inline__ u64 ldq_u(u64 *p)
103 {
104         u64 ret;
105         memmove(&ret, p, sizeof(*p));
106         return ret;
107 }
108
109 static __inline__ u32 ldl_u(u32 *p)
110 {
111         u32 ret;
112         memmove(&ret, p, sizeof(*p));
113         return ret;
114 }
115
116 static __inline__ u16 ldw_u(u16 *p)
117 {
118         u16 ret;
119         memmove(&ret, p, sizeof(*p));
120         return ret;
121 }
122
123 static __inline__ void stq_u(u64 val, u64 *p)
124 {
125         u64 tmp = val;
126         memmove(p, &tmp, sizeof(*p));
127 }
128
129 static __inline__ void stl_u(u32 val, u32 *p)
130 {
131         u32 tmp = val;
132         memmove(p, &tmp, sizeof(*p));
133 }
134
135 static __inline__ void stw_u(u16 val, u16 *p)
136 {
137         u16 tmp = val;
138         memmove(p, &tmp, sizeof(*p));
139 }
140
141 #  endif /* __GNUC__ */
142 # endif /* NO_INLINE */
143 /*------------------------- Global Variables ------------------------------*/
144
145 X86EMU_sysEnv           _X86EMU_env;            /* Global emulator machine state */
146 X86EMU_intrFuncs        _X86EMU_intrTab[256];
147
148 /*----------------------------- Implementation ----------------------------*/
149
150 /****************************************************************************
151 PARAMETERS:
152 addr    - Emulator memory address to read
153
154 RETURNS:
155 Byte value read from emulator memory.
156
157 REMARKS:
158 Reads a byte value from the emulator memory. 
159 ****************************************************************************/
160 u8 X86API rdb(
161     u32 addr)
162 {
163         u8 val;
164
165         if (addr > M.mem_size - 1) {
166                 DB(printk("mem_read: address %#lx out of range!\n", addr);)
167                 HALT_SYS();
168                 }
169         val = *(u8*)(M.mem_base + addr);
170 DB(     if (DEBUG_MEM_TRACE())
171                 printk("%#08x 1 -> %#x\n", addr, val);)
172         return val;
173 }
174
175 /****************************************************************************
176 PARAMETERS:
177 addr    - Emulator memory address to read
178
179 RETURNS:
180 Word value read from emulator memory.
181
182 REMARKS:
183 Reads a word value from the emulator memory.
184 ****************************************************************************/
185 u16 X86API rdw(
186         u32 addr)
187 {
188         u16 val = 0;
189
190         if (addr > M.mem_size - 2) {
191                 DB(printk("mem_read: address %#lx out of range!\n", addr);)
192                 HALT_SYS();
193                 }
194 #ifdef __BIG_ENDIAN__
195         if (addr & 0x1) {
196                 val = (*(u8*)(M.mem_base + addr) |
197                           (*(u8*)(M.mem_base + addr + 1) << 8));
198                 }
199         else
200 #endif
201                 val = ldw_u((u16*)(M.mem_base + addr));
202                 DB(     if (DEBUG_MEM_TRACE())
203                 printk("%#08x 2 -> %#x\n", addr, val);)
204     return val;
205 }
206
207 /****************************************************************************
208 PARAMETERS:
209 addr    - Emulator memory address to read
210
211 RETURNS:
212 Long value read from emulator memory.
213 REMARKS:
214 Reads a long value from the emulator memory. 
215 ****************************************************************************/
216 u32 X86API rdl(
217         u32 addr)
218 {
219         u32 val = 0;
220
221         if (addr > M.mem_size - 4) {
222                 DB(printk("mem_read: address %#lx out of range!\n", addr);)
223                 HALT_SYS();
224                 }
225 #ifdef __BIG_ENDIAN__
226         if (addr & 0x3) {
227                 val = (*(u8*)(M.mem_base + addr + 0) |
228                           (*(u8*)(M.mem_base + addr + 1) << 8) |
229                           (*(u8*)(M.mem_base + addr + 2) << 16) |
230                           (*(u8*)(M.mem_base + addr + 3) << 24));
231                 }
232         else
233 #endif
234                 val = ldl_u((u32*)(M.mem_base + addr));
235 DB(     if (DEBUG_MEM_TRACE())
236                 printk("%#08x 4 -> %#x\n", addr, val);)
237         return val;
238 }
239
240 /****************************************************************************
241 PARAMETERS:
242 addr    - Emulator memory address to read
243 val             - Value to store
244
245 REMARKS:
246 Writes a byte value to emulator memory.
247 ****************************************************************************/
248 void X86API wrb(
249         u32 addr,
250         u8 val)
251 {
252 DB(     if (DEBUG_MEM_TRACE())
253                 printk("%#08x 1 <- %#x\n", addr, val);)
254     if (addr > M.mem_size - 1) {
255                 DB(printk("mem_write: address %#lx out of range!\n", addr);)
256                 HALT_SYS();
257                 }
258         *(u8*)(M.mem_base + addr) = val;
259 }
260
261 /****************************************************************************
262 PARAMETERS:
263 addr    - Emulator memory address to read
264 val             - Value to store
265
266 REMARKS:
267 Writes a word value to emulator memory.
268 ****************************************************************************/
269 void X86API wrw(
270         u32 addr,
271         u16 val)
272 {
273 DB(     if (DEBUG_MEM_TRACE())
274                 printk("%#08x 2 <- %#x\n", addr, val);)
275         if (addr > M.mem_size - 2) {
276                 DB(printk("mem_write: address %#lx out of range!\n", addr);)
277                 HALT_SYS();
278                 }
279 #ifdef __BIG_ENDIAN__
280         if (addr & 0x1) {
281                 *(u8*)(M.mem_base + addr + 0) = (val >> 0) & 0xff;
282                 *(u8*)(M.mem_base + addr + 1) = (val >> 8) & 0xff;
283                 }
284         else
285 #endif
286          stw_u(val,(u16*)(M.mem_base + addr));
287 }
288
289 /****************************************************************************
290 PARAMETERS:
291 addr    - Emulator memory address to read
292 val             - Value to store
293
294 REMARKS:
295 Writes a long value to emulator memory. 
296 ****************************************************************************/
297 void X86API wrl(
298         u32 addr,
299         u32 val)
300 {
301 DB(     if (DEBUG_MEM_TRACE())
302                 printk("%#08x 4 <- %#x\n", addr, val);)
303         if (addr > M.mem_size - 4) {
304                 DB(printk("mem_write: address %#lx out of range!\n", addr);)
305                 HALT_SYS();
306                 }
307 #ifdef __BIG_ENDIAN__
308         if (addr & 0x1) {
309                 *(u8*)(M.mem_base + addr + 0) = (val >>  0) & 0xff;
310                 *(u8*)(M.mem_base + addr + 1) = (val >>  8) & 0xff;
311                 *(u8*)(M.mem_base + addr + 2) = (val >> 16) & 0xff;
312                 *(u8*)(M.mem_base + addr + 3) = (val >> 24) & 0xff;
313                 }
314         else
315 #endif
316          stl_u(val,(u32*)(M.mem_base + addr));
317 }
318
319 /****************************************************************************
320 PARAMETERS:
321 addr    - PIO address to read
322 RETURN:
323 0
324 REMARKS:
325 Default PIO byte read function. Doesn't perform real inb.
326 ****************************************************************************/
327 static u8 X86API p_inb(
328         X86EMU_pioAddr addr)
329 {
330 DB(     if (DEBUG_IO_TRACE())
331                 printk("inb %#04x \n", addr);)
332         return 0;
333 }
334
335 /****************************************************************************
336 PARAMETERS:
337 addr    - PIO address to read
338 RETURN:
339 0
340 REMARKS:
341 Default PIO word read function. Doesn't perform real inw.
342 ****************************************************************************/
343 static u16 X86API p_inw(
344         X86EMU_pioAddr addr)
345 {
346 DB(     if (DEBUG_IO_TRACE())
347                 printk("inw %#04x \n", addr);)
348         return 0;
349 }
350
351 /****************************************************************************
352 PARAMETERS:
353 addr    - PIO address to read
354 RETURN:
355 0
356 REMARKS:
357 Default PIO long read function. Doesn't perform real inl.
358 ****************************************************************************/
359 static u32 X86API p_inl(
360         X86EMU_pioAddr addr)
361 {
362 DB(     if (DEBUG_IO_TRACE())
363                 printk("inl %#04x \n", addr);)
364         return 0;
365 }
366
367 /****************************************************************************
368 PARAMETERS:
369 addr    - PIO address to write
370 val     - Value to store
371 REMARKS:
372 Default PIO byte write function. Doesn't perform real outb.
373 ****************************************************************************/
374 static void X86API p_outb(
375         X86EMU_pioAddr addr,
376         u8 val)
377 {
378 DB(     if (DEBUG_IO_TRACE())
379                 printk("outb %#02x -> %#04x \n", val, addr);)
380     return;
381 }
382
383 /****************************************************************************
384 PARAMETERS:
385 addr    - PIO address to write
386 val     - Value to store
387 REMARKS:
388 Default PIO word write function. Doesn't perform real outw.
389 ****************************************************************************/
390 static void X86API p_outw(
391         X86EMU_pioAddr addr,
392         u16 val)
393 {
394 DB(     if (DEBUG_IO_TRACE())
395                 printk("outw %#04x -> %#04x \n", val, addr);)
396         return;
397 }
398
399 /****************************************************************************
400 PARAMETERS:
401 addr    - PIO address to write
402 val     - Value to store
403 REMARKS:
404 Default PIO ;ong write function. Doesn't perform real outl.
405 ****************************************************************************/
406 static void X86API p_outl(
407         X86EMU_pioAddr addr,
408         u32 val)
409 {
410 DB(     if (DEBUG_IO_TRACE())
411                 printk("outl %#08x -> %#04x \n", val, addr);)
412     return;
413 }
414
415 /*------------------------- Global Variables ------------------------------*/
416
417 u8      (X86APIP sys_rdb)(u32 addr)                                 = rdb;
418 u16     (X86APIP sys_rdw)(u32 addr)                                 = rdw;
419 u32     (X86APIP sys_rdl)(u32 addr)                                 = rdl;
420 void    (X86APIP sys_wrb)(u32 addr,u8 val)                          = wrb;
421 void    (X86APIP sys_wrw)(u32 addr,u16 val)                 = wrw;
422 void    (X86APIP sys_wrl)(u32 addr,u32 val)                 = wrl;
423 u8      (X86APIP sys_inb)(X86EMU_pioAddr addr)              = p_inb;
424 u16     (X86APIP sys_inw)(X86EMU_pioAddr addr)              = p_inw;
425 u32     (X86APIP sys_inl)(X86EMU_pioAddr addr)              = p_inl;
426 void    (X86APIP sys_outb)(X86EMU_pioAddr addr, u8 val)         = p_outb;
427 void    (X86APIP sys_outw)(X86EMU_pioAddr addr, u16 val)        = p_outw;
428 void    (X86APIP sys_outl)(X86EMU_pioAddr addr, u32 val)        = p_outl;
429
430 /*----------------------------- Setup -------------------------------------*/
431
432 /****************************************************************************
433 PARAMETERS:
434 funcs   - New memory function pointers to make active
435
436 REMARKS:
437 This function is used to set the pointers to functions which access
438 memory space, allowing the user application to override these functions
439 and hook them out as necessary for their application.
440 ****************************************************************************/
441 void X86EMU_setupMemFuncs(
442         X86EMU_memFuncs *funcs)
443 {
444     sys_rdb = funcs->rdb;
445     sys_rdw = funcs->rdw;
446     sys_rdl = funcs->rdl;
447     sys_wrb = funcs->wrb;
448     sys_wrw = funcs->wrw;
449     sys_wrl = funcs->wrl;
450 }
451
452 /****************************************************************************
453 PARAMETERS:
454 funcs   - New programmed I/O function pointers to make active
455
456 REMARKS:
457 This function is used to set the pointers to functions which access
458 I/O space, allowing the user application to override these functions
459 and hook them out as necessary for their application.
460 ****************************************************************************/
461 void X86EMU_setupPioFuncs(
462         X86EMU_pioFuncs *funcs)
463 {
464     sys_inb = funcs->inb;
465     sys_inw = funcs->inw;
466     sys_inl = funcs->inl;
467     sys_outb = funcs->outb;
468     sys_outw = funcs->outw;
469     sys_outl = funcs->outl;
470 }
471
472 /****************************************************************************
473 PARAMETERS:
474 funcs   - New interrupt vector table to make active
475
476 REMARKS:
477 This function is used to set the pointers to functions which handle
478 interrupt processing in the emulator, allowing the user application to
479 hook interrupts as necessary for their application. Any interrupts that
480 are not hooked by the user application, and reflected and handled internally
481 in the emulator via the interrupt vector table. This allows the application
482 to get control when the code being emulated executes specific software
483 interrupts.
484 ****************************************************************************/
485 void X86EMU_setupIntrFuncs(
486         X86EMU_intrFuncs funcs[])
487 {
488     int i;
489     
490         for (i=0; i < 256; i++)
491                 _X86EMU_intrTab[i] = NULL;
492         if (funcs) {
493                 for (i = 0; i < 256; i++)
494                         _X86EMU_intrTab[i] = funcs[i];
495                 }
496 }
497
498 /****************************************************************************
499 PARAMETERS:
500 int     - New software interrupt to prepare for
501
502 REMARKS:
503 This function is used to set up the emulator state to exceute a software
504 interrupt. This can be used by the user application code to allow an
505 interrupt to be hooked, examined and then reflected back to the emulator
506 so that the code in the emulator will continue processing the software
507 interrupt as per normal. This essentially allows system code to actively
508 hook and handle certain software interrupts as necessary.
509 ****************************************************************************/
510 void X86EMU_prepareForInt(
511         int num)
512 {
513     push_word((u16)M.x86.R_FLG);
514     CLEAR_FLAG(F_IF);
515     CLEAR_FLAG(F_TF);
516     push_word(M.x86.R_CS);
517     M.x86.R_CS = mem_access_word(num * 4 + 2);
518     push_word(M.x86.R_IP);
519     M.x86.R_IP = mem_access_word(num * 4);
520         M.x86.intr = 0;
521 }