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
57struct __una_u64 { u64 x __attribute__((packed)); };
58struct __una_u32 { u32 x __attribute__((packed)); };
59struct __una_u16 { u16 x __attribute__((packed)); };
60
61/* Elemental unaligned loads */
62
63static __inline__ u64 ldq_u(u64 *p)
64{
65	const struct __una_u64 *ptr = (const struct __una_u64 *) p;
66	return ptr->x;
67}
68
69static __inline__ u32 ldl_u(u32 *p)
70{
71	const struct __una_u32 *ptr = (const struct __una_u32 *) p;
72	return ptr->x;
73}
74
75static __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
83static __inline__ void stq_u(u64 val, u64 *p)
84{
85	struct __una_u64 *ptr = (struct __una_u64 *) p;
86	ptr->x = val;
87}
88
89static __inline__ void stl_u(u32 val, u32 *p)
90{
91	struct __una_u32 *ptr = (struct __una_u32 *) p;
92	ptr->x = val;
93}
94
95static __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
102static __inline__ u64 ldq_u(u64 *p)
103{
104	u64 ret;
105	memmove(&ret, p, sizeof(*p));
106	return ret;
107}
108
109static __inline__ u32 ldl_u(u32 *p)
110{
111	u32 ret;
112	memmove(&ret, p, sizeof(*p));
113	return ret;
114}
115
116static __inline__ u16 ldw_u(u16 *p)
117{
118	u16 ret;
119	memmove(&ret, p, sizeof(*p));
120	return ret;
121}
122
123static __inline__ void stq_u(u64 val, u64 *p)
124{
125	u64 tmp = val;
126	memmove(p, &tmp, sizeof(*p));
127}
128
129static __inline__ void stl_u(u32 val, u32 *p)
130{
131	u32 tmp = val;
132	memmove(p, &tmp, sizeof(*p));
133}
134
135static __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
145X86EMU_sysEnv		_X86EMU_env;		/* Global emulator machine state */
146X86EMU_intrFuncs	_X86EMU_intrTab[256];
147
148/*----------------------------- Implementation ----------------------------*/
149
150/****************************************************************************
151PARAMETERS:
152addr	- Emulator memory address to read
153
154RETURNS:
155Byte value read from emulator memory.
156
157REMARKS:
158Reads a byte value from the emulator memory.
159****************************************************************************/
160u8 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);
170DB(	if (DEBUG_MEM_TRACE())
171		printk("%#08x 1 -> %#x\n", addr, val);)
172	return val;
173}
174
175/****************************************************************************
176PARAMETERS:
177addr	- Emulator memory address to read
178
179RETURNS:
180Word value read from emulator memory.
181
182REMARKS:
183Reads a word value from the emulator memory.
184****************************************************************************/
185u16 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/****************************************************************************
208PARAMETERS:
209addr	- Emulator memory address to read
210
211RETURNS:
212Long value read from emulator memory.
213REMARKS:
214Reads a long value from the emulator memory.
215****************************************************************************/
216u32 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));
235DB(	if (DEBUG_MEM_TRACE())
236		printk("%#08x 4 -> %#x\n", addr, val);)
237	return val;
238}
239
240/****************************************************************************
241PARAMETERS:
242addr	- Emulator memory address to read
243val		- Value to store
244
245REMARKS:
246Writes a byte value to emulator memory.
247****************************************************************************/
248void X86API wrb(
249	u32 addr,
250	u8 val)
251{
252DB(	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/****************************************************************************
262PARAMETERS:
263addr	- Emulator memory address to read
264val		- Value to store
265
266REMARKS:
267Writes a word value to emulator memory.
268****************************************************************************/
269void X86API wrw(
270	u32 addr,
271	u16 val)
272{
273DB(	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/****************************************************************************
290PARAMETERS:
291addr	- Emulator memory address to read
292val		- Value to store
293
294REMARKS:
295Writes a long value to emulator memory.
296****************************************************************************/
297void X86API wrl(
298	u32 addr,
299	u32 val)
300{
301DB(	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/****************************************************************************
320PARAMETERS:
321addr	- PIO address to read
322RETURN:
3230
324REMARKS:
325Default PIO byte read function. Doesn't perform real inb.
326****************************************************************************/
327static u8 X86API p_inb(
328	X86EMU_pioAddr addr)
329{
330DB(	if (DEBUG_IO_TRACE())
331		printk("inb %#04x \n", addr);)
332	return 0;
333}
334
335/****************************************************************************
336PARAMETERS:
337addr	- PIO address to read
338RETURN:
3390
340REMARKS:
341Default PIO word read function. Doesn't perform real inw.
342****************************************************************************/
343static u16 X86API p_inw(
344	X86EMU_pioAddr addr)
345{
346DB(	if (DEBUG_IO_TRACE())
347		printk("inw %#04x \n", addr);)
348	return 0;
349}
350
351/****************************************************************************
352PARAMETERS:
353addr	- PIO address to read
354RETURN:
3550
356REMARKS:
357Default PIO long read function. Doesn't perform real inl.
358****************************************************************************/
359static u32 X86API p_inl(
360	X86EMU_pioAddr addr)
361{
362DB(	if (DEBUG_IO_TRACE())
363		printk("inl %#04x \n", addr);)
364	return 0;
365}
366
367/****************************************************************************
368PARAMETERS:
369addr	- PIO address to write
370val     - Value to store
371REMARKS:
372Default PIO byte write function. Doesn't perform real outb.
373****************************************************************************/
374static void X86API p_outb(
375	X86EMU_pioAddr addr,
376	u8 val)
377{
378DB(	if (DEBUG_IO_TRACE())
379		printk("outb %#02x -> %#04x \n", val, addr);)
380    return;
381}
382
383/****************************************************************************
384PARAMETERS:
385addr	- PIO address to write
386val     - Value to store
387REMARKS:
388Default PIO word write function. Doesn't perform real outw.
389****************************************************************************/
390static void X86API p_outw(
391	X86EMU_pioAddr addr,
392	u16 val)
393{
394DB(	if (DEBUG_IO_TRACE())
395		printk("outw %#04x -> %#04x \n", val, addr);)
396	return;
397}
398
399/****************************************************************************
400PARAMETERS:
401addr	- PIO address to write
402val     - Value to store
403REMARKS:
404Default PIO ;ong write function. Doesn't perform real outl.
405****************************************************************************/
406static void X86API p_outl(
407	X86EMU_pioAddr addr,
408	u32 val)
409{
410DB(	if (DEBUG_IO_TRACE())
411		printk("outl %#08x -> %#04x \n", val, addr);)
412    return;
413}
414
415/*------------------------- Global Variables ------------------------------*/
416
417u8  	(X86APIP sys_rdb)(u32 addr) 			            = rdb;
418u16 	(X86APIP sys_rdw)(u32 addr) 			            = rdw;
419u32 	(X86APIP sys_rdl)(u32 addr) 			            = rdl;
420void 	(X86APIP sys_wrb)(u32 addr,u8 val) 		            = wrb;
421void 	(X86APIP sys_wrw)(u32 addr,u16 val) 	            = wrw;
422void 	(X86APIP sys_wrl)(u32 addr,u32 val) 	            = wrl;
423u8  	(X86APIP sys_inb)(X86EMU_pioAddr addr)	            = p_inb;
424u16 	(X86APIP sys_inw)(X86EMU_pioAddr addr)	            = p_inw;
425u32 	(X86APIP sys_inl)(X86EMU_pioAddr addr)              = p_inl;
426void 	(X86APIP sys_outb)(X86EMU_pioAddr addr, u8 val) 	= p_outb;
427void 	(X86APIP sys_outw)(X86EMU_pioAddr addr, u16 val)	= p_outw;
428void 	(X86APIP sys_outl)(X86EMU_pioAddr addr, u32 val)	= p_outl;
429
430/*----------------------------- Setup -------------------------------------*/
431
432/****************************************************************************
433PARAMETERS:
434funcs	- New memory function pointers to make active
435
436REMARKS:
437This function is used to set the pointers to functions which access
438memory space, allowing the user application to override these functions
439and hook them out as necessary for their application.
440****************************************************************************/
441void 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/****************************************************************************
453PARAMETERS:
454funcs	- New programmed I/O function pointers to make active
455
456REMARKS:
457This function is used to set the pointers to functions which access
458I/O space, allowing the user application to override these functions
459and hook them out as necessary for their application.
460****************************************************************************/
461void 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/****************************************************************************
473PARAMETERS:
474funcs	- New interrupt vector table to make active
475
476REMARKS:
477This function is used to set the pointers to functions which handle
478interrupt processing in the emulator, allowing the user application to
479hook interrupts as necessary for their application. Any interrupts that
480are not hooked by the user application, and reflected and handled internally
481in the emulator via the interrupt vector table. This allows the application
482to get control when the code being emulated executes specific software
483interrupts.
484****************************************************************************/
485void 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/****************************************************************************
499PARAMETERS:
500int	- New software interrupt to prepare for
501
502REMARKS:
503This function is used to set up the emulator state to exceute a software
504interrupt. This can be used by the user application code to allow an
505interrupt to be hooked, examined and then reflected back to the emulator
506so that the code in the emulator will continue processing the software
507interrupt as per normal. This essentially allows system code to actively
508hook and handle certain software interrupts as necessary.
509****************************************************************************/
510void 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}
522