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