The Pedigree Project  0.1
system/kernel/machine/mach_pc/x86emu/sys.c
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "x86emu.h"
21 #include "x86emu/debug.h"
22 #include "x86emu/prim_ops.h"
23 #include "x86emu/regs.h"
24 #include "x86emu/x86emui.h"
25 #ifndef NO_SYS_HEADERS
26 #include <string.h>
27 #endif
28 /*------------------------- Global Variables ------------------------------*/
29 
30 X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */
31 X86EMU_intrFuncs _X86EMU_intrTab[256];
32 
33 /*----------------------------- Implementation ----------------------------*/
34 #if defined(__alpha__) || defined(__alpha)
35 /* to cope with broken egcs-1.1.2 :-(((( */
36 
37 #define ALPHA_UALOADS
38 /*
39  * inline functions to do unaligned accesses
40  * from linux/include/asm-alpha/unaligned.h
41  */
42 
43 /*
44  * EGCS 1.1 knows about arbitrary unaligned loads. Define some
45  * packed structures to talk about such things with.
46  */
47 
48 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
49 struct __una_u64
50 {
51  unsigned long x __attribute__((packed));
52 };
53 struct __una_u32
54 {
55  unsigned int x __attribute__((packed));
56 };
57 struct __una_u16
58 {
59  unsigned short x __attribute__((packed));
60 };
61 #endif
62 
63 static __inline__ unsigned long ldq_u(unsigned long *r11)
64 {
65 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
66  const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
67  return ptr->x;
68 #else
69  unsigned long r1, r2;
70  __asm__("ldq_u %0,%3\n\t"
71  "ldq_u %1,%4\n\t"
72  "extql %0,%2,%0\n\t"
73  "extqh %1,%2,%1"
74  : "=&r"(r1), "=&r"(r2)
75  : "r"(r11), "m"(*r11),
76  "m"(*(const unsigned long *) (7 + (char *) r11)));
77  return r1 | r2;
78 #endif
79 }
80 
81 static __inline__ unsigned long ldl_u(unsigned int *r11)
82 {
83 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
84  const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
85  return ptr->x;
86 #else
87  unsigned long r1, r2;
88  __asm__("ldq_u %0,%3\n\t"
89  "ldq_u %1,%4\n\t"
90  "extll %0,%2,%0\n\t"
91  "extlh %1,%2,%1"
92  : "=&r"(r1), "=&r"(r2)
93  : "r"(r11), "m"(*r11),
94  "m"(*(const unsigned long *) (3 + (char *) r11)));
95  return r1 | r2;
96 #endif
97 }
98 
99 static __inline__ unsigned long ldw_u(unsigned short *r11)
100 {
101 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
102  const struct __una_u16 *ptr = (const struct __una_u16 *) 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  "extwl %0,%2,%0\n\t"
109  "extwh %1,%2,%1"
110  : "=&r"(r1), "=&r"(r2)
111  : "r"(r11), "m"(*r11),
112  "m"(*(const unsigned long *) (1 + (char *) r11)));
113  return r1 | r2;
114 #endif
115 }
116 
117 /*
118  * Elemental unaligned stores
119  */
120 
121 static __inline__ void stq_u(unsigned long r5, unsigned long *r11)
122 {
123 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
124  struct __una_u64 *ptr = (struct __una_u64 *) r11;
125  ptr->x = r5;
126 #else
127  unsigned long r1, r2, r3, r4;
128 
129  __asm__("ldq_u %3,%1\n\t"
130  "ldq_u %2,%0\n\t"
131  "insqh %6,%7,%5\n\t"
132  "insql %6,%7,%4\n\t"
133  "mskqh %3,%7,%3\n\t"
134  "mskql %2,%7,%2\n\t"
135  "bis %3,%5,%3\n\t"
136  "bis %2,%4,%2\n\t"
137  "stq_u %3,%1\n\t"
138  "stq_u %2,%0"
139  : "=m"(*r11), "=m"(*(unsigned long *) (7 + (char *) r11)),
140  "=&r"(r1), "=&r"(r2), "=&r"(r3), "=&r"(r4)
141  : "r"(r5), "r"(r11));
142 #endif
143 }
144 
145 static __inline__ void stl_u(unsigned long r5, unsigned int *r11)
146 {
147 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
148  struct __una_u32 *ptr = (struct __una_u32 *) r11;
149  ptr->x = r5;
150 #else
151  unsigned long r1, r2, r3, r4;
152 
153  __asm__("ldq_u %3,%1\n\t"
154  "ldq_u %2,%0\n\t"
155  "inslh %6,%7,%5\n\t"
156  "insll %6,%7,%4\n\t"
157  "msklh %3,%7,%3\n\t"
158  "mskll %2,%7,%2\n\t"
159  "bis %3,%5,%3\n\t"
160  "bis %2,%4,%2\n\t"
161  "stq_u %3,%1\n\t"
162  "stq_u %2,%0"
163  : "=m"(*r11), "=m"(*(unsigned long *) (3 + (char *) r11)),
164  "=&r"(r1), "=&r"(r2), "=&r"(r3), "=&r"(r4)
165  : "r"(r5), "r"(r11));
166 #endif
167 }
168 
169 static __inline__ void stw_u(unsigned long r5, unsigned short *r11)
170 {
171 #if defined(__GNUC__) && ((__GNUC__ > 2) || (__GNUC_MINOR__ >= 91))
172  struct __una_u16 *ptr = (struct __una_u16 *) r11;
173  ptr->x = r5;
174 #else
175  unsigned long r1, r2, r3, r4;
176 
177  __asm__("ldq_u %3,%1\n\t"
178  "ldq_u %2,%0\n\t"
179  "inswh %6,%7,%5\n\t"
180  "inswl %6,%7,%4\n\t"
181  "mskwh %3,%7,%3\n\t"
182  "mskwl %2,%7,%2\n\t"
183  "bis %3,%5,%3\n\t"
184  "bis %2,%4,%2\n\t"
185  "stq_u %3,%1\n\t"
186  "stq_u %2,%0"
187  : "=m"(*r11), "=m"(*(unsigned long *) (1 + (char *) r11)),
188  "=&r"(r1), "=&r"(r2), "=&r"(r3), "=&r"(r4)
189  : "r"(r5), "r"(r11));
190 #endif
191 }
192 
193 #elif defined(__GNUC__) && ((__GNUC__ < 3)) && \
194  (defined(__ia64__) || defined(ia64__))
195 #define IA64_UALOADS
196 /*
197  * EGCS 1.1 knows about arbitrary unaligned loads. Define some
198  * packed structures to talk about such things with.
199  */
200 struct __una_u64
201 {
202  unsigned long x __attribute__((packed));
203 };
204 struct __una_u32
205 {
206  unsigned int x __attribute__((packed));
207 };
208 struct __una_u16
209 {
210  unsigned short x __attribute__((packed));
211 };
212 
213 static __inline__ unsigned long __uldq(const unsigned long *r11)
214 {
215  const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
216  return ptr->x;
217 }
218 
219 static __inline__ unsigned long uldl(const unsigned int *r11)
220 {
221  const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
222  return ptr->x;
223 }
224 
225 static __inline__ unsigned long uldw(const unsigned short *r11)
226 {
227  const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
228  return ptr->x;
229 }
230 
231 static __inline__ void ustq(unsigned long r5, unsigned long *r11)
232 {
233  struct __una_u64 *ptr = (struct __una_u64 *) r11;
234  ptr->x = r5;
235 }
236 
237 static __inline__ void ustl(unsigned long r5, unsigned int *r11)
238 {
239  struct __una_u32 *ptr = (struct __una_u32 *) r11;
240  ptr->x = r5;
241 }
242 
243 static __inline__ void ustw(unsigned long r5, unsigned short *r11)
244 {
245  struct __una_u16 *ptr = (struct __una_u16 *) r11;
246  ptr->x = r5;
247 }
248 
249 #endif
250 
251 /****************************************************************************
252 PARAMETERS:
253 addr - Emulator memory address to read
254 
255 RETURNS:
256 Byte value read from emulator memory.
257 
258 REMARKS:
259 Reads a byte value from the emulator memory.
260 ****************************************************************************/
261 u8 X86API rdb(u32 addr)
262 {
263  u8 val;
264 
265  if (addr > M.mem_size - 1)
266  {
267  DB(printk("mem_read: address %#lx out of range!\n", addr);)
268  HALT_SYS();
269  }
270  val = *(u8 *) (M.mem_base + addr);
271  DB(if (DEBUG_MEM_TRACE()) printk("%#08x 1 -> %#x\n", addr, val);)
272  return val;
273 }
274 
275 /****************************************************************************
276 PARAMETERS:
277 addr - Emulator memory address to read
278 
279 RETURNS:
280 Word value read from emulator memory.
281 
282 REMARKS:
283 Reads a word value from the emulator memory.
284 ****************************************************************************/
285 u16 X86API rdw(u32 addr)
286 {
287  u16 val = 0;
288 
289  if (addr > M.mem_size - 2)
290  {
291  DB(printk("mem_read: address %#lx out of range!\n", addr);)
292  HALT_SYS();
293  }
294 #ifdef __BIG_ENDIAN__
295  if (addr & 0x1)
296  {
297  val =
298  (*(u8 *) (M.mem_base + addr) |
299  (*(u8 *) (M.mem_base + addr + 1) << 8));
300  }
301  else
302 #endif
303 #if defined(ALPHA_UALOADS)
304  val = ldw_u((u16 *) (M.mem_base + addr));
305 #elif defined(IA64_UALOADS)
306  val = uldw((u16 *) (M.mem_base + addr));
307 #else
308  val = *(u16 *) (M.mem_base + addr);
309 #endif
310  DB(if (DEBUG_MEM_TRACE()) printk("%#08x 2 -> %#x\n", addr, val);)
311  return val;
312 }
313 
314 /****************************************************************************
315 PARAMETERS:
316 addr - Emulator memory address to read
317 
318 RETURNS:
319 Long value read from emulator memory.
320 REMARKS:
321 Reads a long value from the emulator memory.
322 ****************************************************************************/
323 u32 X86API rdl(u32 addr)
324 {
325  u32 val = 0;
326 
327  if (addr > M.mem_size - 4)
328  {
329  DB(printk("mem_read: address %#lx out of range!\n", addr);)
330  HALT_SYS();
331  }
332 #ifdef __BIG_ENDIAN__
333  if (addr & 0x3)
334  {
335  val =
336  (*(u8 *) (M.mem_base + addr + 0) |
337  (*(u8 *) (M.mem_base + addr + 1) << 8) |
338  (*(u8 *) (M.mem_base + addr + 2) << 16) |
339  (*(u8 *) (M.mem_base + addr + 3) << 24));
340  }
341  else
342 #endif
343 #if defined(ALPHA_UALOADS)
344  val = ldl_u((u32 *) (M.mem_base + addr));
345 #elif defined(IA64_UALOADS)
346  val = uldl((u32 *) (M.mem_base + addr));
347 #else
348  val = *(u32 *) (M.mem_base + addr);
349 #endif
350  DB(if (DEBUG_MEM_TRACE()) printk("%#08x 4 -> %#x\n", addr, val);)
351  return val;
352 }
353 
354 /****************************************************************************
355 PARAMETERS:
356 addr - Emulator memory address to read
357 val - Value to store
358 
359 REMARKS:
360 Writes a byte value to emulator memory.
361 ****************************************************************************/
362 void X86API wrb(u32 addr, u8 val)
363 {
364  DB(if (DEBUG_MEM_TRACE()) printk("%#08x 1 <- %#x\n", addr, val);)
365  if (addr > M.mem_size - 1)
366  {
367  DB(printk("mem_write: address %#lx out of range!\n", addr);)
368  HALT_SYS();
369  }
370  *(u8 *) (M.mem_base + addr) = val;
371 }
372 
373 /****************************************************************************
374 PARAMETERS:
375 addr - Emulator memory address to read
376 val - Value to store
377 
378 REMARKS:
379 Writes a word value to emulator memory.
380 ****************************************************************************/
381 void X86API wrw(u32 addr, u16 val)
382 {
383  DB(if (DEBUG_MEM_TRACE()) printk("%#08x 2 <- %#x\n", addr, val);)
384  if (addr > M.mem_size - 2)
385  {
386  DB(printk("mem_write: address %#lx out of range!\n", addr);)
387  HALT_SYS();
388  }
389 #ifdef __BIG_ENDIAN__
390  if (addr & 0x1)
391  {
392  *(u8 *) (M.mem_base + addr + 0) = (val >> 0) & 0xff;
393  *(u8 *) (M.mem_base + addr + 1) = (val >> 8) & 0xff;
394  }
395  else
396 #endif
397 #if defined(ALPHA_UALOADS)
398  stw_u(val, (u16 *) (M.mem_base + addr));
399 #elif defined(IA64_UALOADS)
400  ustw(val, (u16 *) (M.mem_base + addr));
401 #else
402  *(u16 *) (M.mem_base + addr) = val;
403 #endif
404 }
405 
406 /****************************************************************************
407 PARAMETERS:
408 addr - Emulator memory address to read
409 val - Value to store
410 
411 REMARKS:
412 Writes a long value to emulator memory.
413 ****************************************************************************/
414 void X86API wrl(u32 addr, u32 val)
415 {
416  DB(if (DEBUG_MEM_TRACE()) printk("%#08x 4 <- %#x\n", addr, val);)
417  if (addr > M.mem_size - 4)
418  {
419  DB(printk("mem_write: address %#lx out of range!\n", addr);)
420  HALT_SYS();
421  }
422 #ifdef __BIG_ENDIAN__
423  if (addr & 0x1)
424  {
425  *(u8 *) (M.mem_base + addr + 0) = (val >> 0) & 0xff;
426  *(u8 *) (M.mem_base + addr + 1) = (val >> 8) & 0xff;
427  *(u8 *) (M.mem_base + addr + 2) = (val >> 16) & 0xff;
428  *(u8 *) (M.mem_base + addr + 3) = (val >> 24) & 0xff;
429  }
430  else
431 #endif
432 #if defined(ALPHA_UALOADS)
433  stl_u(val, (u32 *) (M.mem_base + addr));
434 #elif defined(IA64_UALOADS)
435  ustl(val, (u32 *) (M.mem_base + addr));
436 #else
437  *(u32 *) (M.mem_base + addr) = val;
438 #endif
439 }
440 
441 /****************************************************************************
442 PARAMETERS:
443 addr - PIO address to read
444 RETURN:
445 0
446 REMARKS:
447 Default PIO byte read function. Doesn't perform real inb.
448 ****************************************************************************/
449 static u8 X86API p_inb(X86EMU_pioAddr addr)
450 {
451  DB(if (DEBUG_IO_TRACE()) printk("inb %#04x \n", addr);)
452  return 0;
453 }
454 
455 /****************************************************************************
456 PARAMETERS:
457 addr - PIO address to read
458 RETURN:
459 0
460 REMARKS:
461 Default PIO word read function. Doesn't perform real inw.
462 ****************************************************************************/
463 static u16 X86API p_inw(X86EMU_pioAddr addr)
464 {
465  DB(if (DEBUG_IO_TRACE()) printk("inw %#04x \n", addr);)
466  return 0;
467 }
468 
469 /****************************************************************************
470 PARAMETERS:
471 addr - PIO address to read
472 RETURN:
473 0
474 REMARKS:
475 Default PIO long read function. Doesn't perform real inl.
476 ****************************************************************************/
477 static u32 X86API p_inl(X86EMU_pioAddr addr)
478 {
479  DB(if (DEBUG_IO_TRACE()) printk("inl %#04x \n", addr);)
480  return 0;
481 }
482 
483 /****************************************************************************
484 PARAMETERS:
485 addr - PIO address to write
486 val - Value to store
487 REMARKS:
488 Default PIO byte write function. Doesn't perform real outb.
489 ****************************************************************************/
490 static void X86API p_outb(X86EMU_pioAddr addr, u8 val)
491 {
492  DB(if (DEBUG_IO_TRACE()) printk("outb %#02x -> %#04x \n", val, addr);)
493  return;
494 }
495 
496 /****************************************************************************
497 PARAMETERS:
498 addr - PIO address to write
499 val - Value to store
500 REMARKS:
501 Default PIO word write function. Doesn't perform real outw.
502 ****************************************************************************/
503 static void X86API p_outw(X86EMU_pioAddr addr, u16 val)
504 {
505  DB(if (DEBUG_IO_TRACE()) printk("outw %#04x -> %#04x \n", val, addr);)
506  return;
507 }
508 
509 /****************************************************************************
510 PARAMETERS:
511 addr - PIO address to write
512 val - Value to store
513 REMARKS:
514 Default PIO ;ong write function. Doesn't perform real outl.
515 ****************************************************************************/
516 static void X86API p_outl(X86EMU_pioAddr addr, u32 val)
517 {
518  DB(if (DEBUG_IO_TRACE()) printk("outl %#08x -> %#04x \n", val, addr);)
519  return;
520 }
521 
522 /*------------------------- Global Variables ------------------------------*/
523 
524 u8(X86APIP sys_rdb)(u32 addr) = rdb;
525 u16(X86APIP sys_rdw)(u32 addr) = rdw;
526 u32(X86APIP sys_rdl)(u32 addr) = rdl;
527 void(X86APIP sys_wrb)(u32 addr, u8 val) = wrb;
528 void(X86APIP sys_wrw)(u32 addr, u16 val) = wrw;
529 void(X86APIP sys_wrl)(u32 addr, u32 val) = wrl;
530 u8(X86APIP sys_inb)(X86EMU_pioAddr addr) = p_inb;
531 u16(X86APIP sys_inw)(X86EMU_pioAddr addr) = p_inw;
532 u32(X86APIP sys_inl)(X86EMU_pioAddr addr) = p_inl;
533 void(X86APIP sys_outb)(X86EMU_pioAddr addr, u8 val) = p_outb;
534 void(X86APIP sys_outw)(X86EMU_pioAddr addr, u16 val) = p_outw;
535 void(X86APIP sys_outl)(X86EMU_pioAddr addr, u32 val) = p_outl;
536 
537 /*----------------------------- Setup -------------------------------------*/
538 
539 /****************************************************************************
540 PARAMETERS:
541 funcs - New memory function pointers to make active
542 
543 REMARKS:
544 This function is used to set the pointers to functions which access
545 memory space, allowing the user application to override these functions
546 and hook them out as necessary for their application.
547 ****************************************************************************/
548 void X86EMU_setupMemFuncs(X86EMU_memFuncs *funcs)
549 {
550  sys_rdb = funcs->rdb;
551  sys_rdw = funcs->rdw;
552  sys_rdl = funcs->rdl;
553  sys_wrb = funcs->wrb;
554  sys_wrw = funcs->wrw;
555  sys_wrl = funcs->wrl;
556 }
557 
558 /****************************************************************************
559 PARAMETERS:
560 funcs - New programmed I/O function pointers to make active
561 
562 REMARKS:
563 This function is used to set the pointers to functions which access
564 I/O space, allowing the user application to override these functions
565 and hook them out as necessary for their application.
566 ****************************************************************************/
567 void X86EMU_setupPioFuncs(X86EMU_pioFuncs *funcs)
568 {
569  sys_inb = funcs->inb;
570  sys_inw = funcs->inw;
571  sys_inl = funcs->inl;
572  sys_outb = funcs->outb;
573  sys_outw = funcs->outw;
574  sys_outl = funcs->outl;
575 }
576 
577 /****************************************************************************
578 PARAMETERS:
579 funcs - New interrupt vector table to make active
580 
581 REMARKS:
582 This function is used to set the pointers to functions which handle
583 interrupt processing in the emulator, allowing the user application to
584 hook interrupts as necessary for their application. Any interrupts that
585 are not hooked by the user application, and reflected and handled internally
586 in the emulator via the interrupt vector table. This allows the application
587 to get control when the code being emulated executes specific software
588 interrupts.
589 ****************************************************************************/
590 void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[])
591 {
592  int i;
593 
594  for (i = 0; i < 256; i++)
595  _X86EMU_intrTab[i] = NULL;
596  if (funcs)
597  {
598  for (i = 0; i < 256; i++)
599  _X86EMU_intrTab[i] = funcs[i];
600  }
601 }
602 
603 /****************************************************************************
604 PARAMETERS:
605 int - New software interrupt to prepare for
606 
607 REMARKS:
608 This function is used to set up the emulator state to exceute a software
609 interrupt. This can be used by the user application code to allow an
610 interrupt to be hooked, examined and then reflected back to the emulator
611 so that the code in the emulator will continue processing the software
612 interrupt as per normal. This essentially allows system code to actively
613 hook and handle certain software interrupts as necessary.
614 ****************************************************************************/
615 void X86EMU_prepareForInt(int num)
616 {
617  push_word((u16) M.x86.R_FLG);
618  CLEAR_FLAG(F_IF);
619  CLEAR_FLAG(F_TF);
620  push_word(M.x86.R_CS);
621  M.x86.R_CS = mem_access_word(num * 4 + 2);
622  push_word(M.x86.R_IP);
623  M.x86.R_IP = mem_access_word(num * 4);
624  M.x86.intr = 0;
625 }