softemu8xx.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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/interrupt.h>
  26. #include <asm/pgtable.h>
  27. #include <asm/uaccess.h>
  28. #include <asm/system.h>
  29. #include <asm/io.h>
  30. /* Eventually we may need a look-up table, but this works for now.
  31. */
  32. #define LFS 48
  33. #define LFD 50
  34. #define LFDU 51
  35. #define STFD 54
  36. #define STFDU 55
  37. #define FMR 63
  38. void print_8xx_pte(struct mm_struct *mm, unsigned long addr)
  39. {
  40. pgd_t *pgd;
  41. pmd_t *pmd;
  42. pte_t *pte;
  43. printk(" pte @ 0x%8lx: ", addr);
  44. pgd = pgd_offset(mm, addr & PAGE_MASK);
  45. if (pgd) {
  46. pmd = pmd_offset(pud_offset(pgd, addr & PAGE_MASK),
  47. addr & PAGE_MASK);
  48. if (pmd && pmd_present(*pmd)) {
  49. pte = pte_offset_kernel(pmd, addr & PAGE_MASK);
  50. if (pte) {
  51. printk(" (0x%08lx)->(0x%08lx)->0x%08lx\n",
  52. (long)pgd, (long)pte, (long)pte_val(*pte));
  53. #define pp ((long)pte_val(*pte))
  54. printk(" RPN: %05lx PP: %lx SPS: %lx SH: %lx "
  55. "CI: %lx v: %lx\n",
  56. pp>>12, /* rpn */
  57. (pp>>10)&3, /* pp */
  58. (pp>>3)&1, /* small */
  59. (pp>>2)&1, /* shared */
  60. (pp>>1)&1, /* cache inhibit */
  61. pp&1 /* valid */
  62. );
  63. #undef pp
  64. }
  65. else {
  66. printk("no pte\n");
  67. }
  68. }
  69. else {
  70. printk("no pmd\n");
  71. }
  72. }
  73. else {
  74. printk("no pgd\n");
  75. }
  76. }
  77. int get_8xx_pte(struct mm_struct *mm, unsigned long addr)
  78. {
  79. pgd_t *pgd;
  80. pmd_t *pmd;
  81. pte_t *pte;
  82. int retval = 0;
  83. pgd = pgd_offset(mm, addr & PAGE_MASK);
  84. if (pgd) {
  85. pmd = pmd_offset(pud_offset(pgd, addr & PAGE_MASK),
  86. addr & PAGE_MASK);
  87. if (pmd && pmd_present(*pmd)) {
  88. pte = pte_offset_kernel(pmd, addr & PAGE_MASK);
  89. if (pte) {
  90. retval = (int)pte_val(*pte);
  91. }
  92. }
  93. }
  94. return retval;
  95. }
  96. /*
  97. * We return 0 on success, 1 on unimplemented instruction, and EFAULT
  98. * if a load/store faulted.
  99. */
  100. int Soft_emulate_8xx(struct pt_regs *regs)
  101. {
  102. u32 inst, instword;
  103. u32 flreg, idxreg, disp;
  104. int retval;
  105. s16 sdisp;
  106. u32 *ea, *ip;
  107. retval = 0;
  108. instword = *((u32 *)regs->nip);
  109. inst = instword >> 26;
  110. flreg = (instword >> 21) & 0x1f;
  111. idxreg = (instword >> 16) & 0x1f;
  112. disp = instword & 0xffff;
  113. ea = (u32 *)(regs->gpr[idxreg] + disp);
  114. ip = (u32 *)&current->thread.TS_FPR(flreg);
  115. switch ( inst )
  116. {
  117. case LFD:
  118. /* this is a 16 bit quantity that is sign extended
  119. * so use a signed short here -- Cort
  120. */
  121. sdisp = (instword & 0xffff);
  122. ea = (u32 *)(regs->gpr[idxreg] + sdisp);
  123. if (copy_from_user(ip, ea, sizeof(double)))
  124. retval = -EFAULT;
  125. break;
  126. case LFDU:
  127. if (copy_from_user(ip, ea, sizeof(double)))
  128. retval = -EFAULT;
  129. else
  130. regs->gpr[idxreg] = (u32)ea;
  131. break;
  132. case LFS:
  133. sdisp = (instword & 0xffff);
  134. ea = (u32 *)(regs->gpr[idxreg] + sdisp);
  135. if (copy_from_user(ip, ea, sizeof(float)))
  136. retval = -EFAULT;
  137. break;
  138. case STFD:
  139. /* this is a 16 bit quantity that is sign extended
  140. * so use a signed short here -- Cort
  141. */
  142. sdisp = (instword & 0xffff);
  143. ea = (u32 *)(regs->gpr[idxreg] + sdisp);
  144. if (copy_to_user(ea, ip, sizeof(double)))
  145. retval = -EFAULT;
  146. break;
  147. case STFDU:
  148. if (copy_to_user(ea, ip, sizeof(double)))
  149. retval = -EFAULT;
  150. else
  151. regs->gpr[idxreg] = (u32)ea;
  152. break;
  153. case FMR:
  154. /* assume this is a fp move -- Cort */
  155. memcpy(ip, &current->thread.TS_FPR((instword>>11)&0x1f),
  156. sizeof(double));
  157. break;
  158. default:
  159. retval = 1;
  160. printk("Bad emulation %s/%d\n"
  161. " NIP: %08lx instruction: %08x opcode: %x "
  162. "A: %x B: %x C: %x code: %x rc: %x\n",
  163. current->comm,current->pid,
  164. regs->nip,
  165. instword,inst,
  166. (instword>>16)&0x1f,
  167. (instword>>11)&0x1f,
  168. (instword>>6)&0x1f,
  169. (instword>>1)&0x3ff,
  170. instword&1);
  171. {
  172. int pa;
  173. print_8xx_pte(current->mm,regs->nip);
  174. pa = get_8xx_pte(current->mm,regs->nip) & PAGE_MASK;
  175. pa |= (regs->nip & ~PAGE_MASK);
  176. pa = (unsigned long)__va(pa);
  177. printk("Kernel VA for NIP %x ", pa);
  178. print_8xx_pte(current->mm,pa);
  179. }
  180. }
  181. if (retval == 0)
  182. regs->nip += 4;
  183. return retval;
  184. }