Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | #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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
189 | rdb(u32 addr) | |
190 | { | |
191 | u8 val; | |
192 | ||
193 | if (addr > M.mem_size - 1) { | |
194 | DB(printk("mem_read: address %#lx 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 | |
215 | rdw(u32 addr) | |
216 | { | |
217 | u16 val = 0; | |
218 | ||
219 | if (addr > M.mem_size - 2) { | |
220 | DB(printk("mem_read: address %#lx 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 | |
247 | rdl(u32 addr) | |
248 | { | |
249 | u32 val = 0; | |
250 | ||
251 | if (addr > M.mem_size - 4) { | |
252 | DB(printk("mem_read: address %#lx 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 | |
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 %#lx 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 | |
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 %#lx 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 | |
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 %#lx 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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 exceute 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 | |
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 | } |