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