softemu8xx.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * Software emulation of some PPC instructions for the 8xx core.
  3. *
  4. * Copyright (C) 1998 Dan Malek (dmalek@jlc.net)
  5. *
  6. * Software floating emuation for the MPC8xx processor. I did this mostly
  7. * because it was easier than trying to get the libraries compiled for
  8. * software floating point. The goal is still to get the libraries done,
  9. * but I lost patience and needed some hacks to at least get init and
  10. * shells running. The first problem is the setjmp/longjmp that save
  11. * and restore the floating point registers.
  12. *
  13. * For this emulation, our working registers are found on the register
  14. * save area.
  15. */
  16. #include <linux/errno.h>
  17. #include <linux/sched.h>
  18. #include <linux/kernel.h>
  19. #include <linux/mm.h>
  20. #include <linux/stddef.h>
  21. #include <linux/unistd.h>
  22. #include <linux/ptrace.h>
  23. #include <linux/slab.h>
  24. #include <linux/user.h>
  25. #include <linux/a.out.h>
  26. #include <linux/interrupt.h>
  27. #include <asm/pgtable.h>
  28. #include <asm/uaccess.h>
  29. #include <asm/system.h>
  30. #include <asm/io.h>
  31. /* Eventually we may need a look-up table, but this works for now.
  32. */
  33. #define LFS 48
  34. #define LFD 50
  35. #define LFDU 51
  36. #define STFD 54
  37. #define STFDU 55
  38. #define FMR 63
  39. void print_8xx_pte(struct mm_struct *mm, unsigned long addr)
  40. {
  41. pgd_t *pgd;
  42. pmd_t *pmd;
  43. pte_t *pte;
  44. printk(" pte @ 0x%8lx: ", addr);
  45. pgd = pgd_offset(mm, addr & PAGE_MASK);
  46. if (pgd) {
  47. pmd = pmd_offset(pud_offset(pgd, addr & PAGE_MASK),
  48. addr & PAGE_MASK);
  49. if (pmd && pmd_present(*pmd)) {
  50. pte = pte_offset_kernel(pmd, addr & PAGE_MASK);
  51. if (pte) {
  52. printk(" (0x%08lx)->(0x%08lx)->0x%08lx\n",
  53. (long)pgd, (long)pte, (long)pte_val(*pte));
  54. #define pp ((long)pte_val(*pte))
  55. printk(" RPN: %05lx PP: %lx SPS: %lx SH: %lx "
  56. "CI: %lx v: %lx\n",
  57. pp>>12, /* rpn */
  58. (pp>>10)&3, /* pp */
  59. (pp>>3)&1, /* small */
  60. (pp>>2)&1, /* shared */
  61. (pp>>1)&1, /* cache inhibit */
  62. pp&1 /* valid */
  63. );
  64. #undef pp
  65. }
  66. else {
  67. printk("no pte\n");
  68. }
  69. }
  70. else {
  71. printk("no pmd\n");
  72. }
  73. }
  74. else {
  75. printk("no pgd\n");
  76. }
  77. }
  78. int get_8xx_pte(struct mm_struct *mm, unsigned long addr)
  79. {
  80. pgd_t *pgd;
  81. pmd_t *pmd;
  82. pte_t *pte;
  83. int retval = 0;
  84. pgd = pgd_offset(mm, addr & PAGE_MASK);
  85. if (pgd) {
  86. pmd = pmd_offset(pud_offset(pgd, addr & PAGE_MASK),
  87. addr & PAGE_MASK);
  88. if (pmd && pmd_present(*pmd)) {
  89. pte = pte_offset_kernel(pmd, addr & PAGE_MASK);
  90. if (pte) {
  91. retval = (int)pte_val(*pte);
  92. }
  93. }
  94. }
  95. return retval;
  96. }
  97. /*
  98. * We return 0 on success, 1 on unimplemented instruction, and EFAULT
  99. * if a load/store faulted.
  100. */
  101. int Soft_emulate_8xx(struct pt_regs *regs)
  102. {
  103. u32 inst, instword;
  104. u32 flreg, idxreg, disp;
  105. int retval;
  106. s16 sdisp;
  107. u32 *ea, *ip;
  108. retval = 0;
  109. instword = *((u32 *)regs->nip);
  110. inst = instword >> 26;
  111. flreg = (instword >> 21) & 0x1f;
  112. idxreg = (instword >> 16) & 0x1f;
  113. disp = instword & 0xffff;
  114. ea = (u32 *)(regs->gpr[idxreg] + disp);
  115. ip = (u32 *)&current->thread.fpr[flreg];
  116. switch ( inst )
  117. {
  118. case LFD:
  119. /* this is a 16 bit quantity that is sign extended
  120. * so use a signed short here -- Cort
  121. */
  122. sdisp = (instword & 0xffff);
  123. ea = (u32 *)(regs->gpr[idxreg] + sdisp);
  124. if (copy_from_user(ip, ea, sizeof(double)))
  125. retval = -EFAULT;
  126. break;
  127. case LFDU:
  128. if (copy_from_user(ip, ea, sizeof(double)))
  129. retval = -EFAULT;
  130. else
  131. regs->gpr[idxreg] = (u32)ea;
  132. break;
  133. case LFS:
  134. sdisp = (instword & 0xffff);
  135. ea = (u32 *)(regs->gpr[idxreg] + sdisp);
  136. if (copy_from_user(ip, ea, sizeof(float)))
  137. retval = -EFAULT;
  138. break;
  139. case STFD:
  140. /* this is a 16 bit quantity that is sign extended
  141. * so use a signed short here -- Cort
  142. */
  143. sdisp = (instword & 0xffff);
  144. ea = (u32 *)(regs->gpr[idxreg] + sdisp);
  145. if (copy_to_user(ea, ip, sizeof(double)))
  146. retval = -EFAULT;
  147. break;
  148. case STFDU:
  149. if (copy_to_user(ea, ip, sizeof(double)))
  150. retval = -EFAULT;
  151. else
  152. regs->gpr[idxreg] = (u32)ea;
  153. break;
  154. case FMR:
  155. /* assume this is a fp move -- Cort */
  156. memcpy(ip, &current->thread.fpr[(instword>>11)&0x1f],
  157. sizeof(double));
  158. break;
  159. default:
  160. retval = 1;
  161. printk("Bad emulation %s/%d\n"
  162. " NIP: %08lx instruction: %08x opcode: %x "
  163. "A: %x B: %x C: %x code: %x rc: %x\n",
  164. current->comm,current->pid,
  165. regs->nip,
  166. instword,inst,
  167. (instword>>16)&0x1f,
  168. (instword>>11)&0x1f,
  169. (instword>>6)&0x1f,
  170. (instword>>1)&0x3ff,
  171. instword&1);
  172. {
  173. int pa;
  174. print_8xx_pte(current->mm,regs->nip);
  175. pa = get_8xx_pte(current->mm,regs->nip) & PAGE_MASK;
  176. pa |= (regs->nip & ~PAGE_MASK);
  177. pa = (unsigned long)__va(pa);
  178. printk("Kernel VA for NIP %x ", pa);
  179. print_8xx_pte(current->mm,pa);
  180. }
  181. }
  182. if (retval == 0)
  183. regs->nip += 4;
  184. return retval;
  185. }