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 17#include <linux/errno.h> 18#include <linux/sched.h> 19#include <linux/kernel.h> 20#include <linux/mm.h> 21#include <linux/stddef.h> 22#include <linux/unistd.h> 23#include <linux/ptrace.h> 24#include <linux/slab.h> 25#include <linux/user.h> 26#include <linux/a.out.h> 27#include <linux/interrupt.h> 28 29#include <asm/pgtable.h> 30#include <asm/uaccess.h> 31#include <asm/system.h> 32#include <asm/io.h> 33 34extern void 35print_8xx_pte(struct mm_struct *mm, unsigned long addr); 36extern int 37get_8xx_pte(struct mm_struct *mm, unsigned long addr); 38 39/* Eventually we may need a look-up table, but this works for now. 40*/ 41#define LFS 48 42#define LFD 50 43#define LFDU 51 44#define STFD 54 45#define STFDU 55 46#define FMR 63 47 48/* 49 * We return 0 on success, 1 on unimplemented instruction, and EFAULT 50 * if a load/store faulted. 51 */ 52int 53Soft_emulate_8xx(struct pt_regs *regs) 54{ 55 uint inst, instword; 56 uint flreg, idxreg, disp; 57 uint retval; 58 signed short sdisp; 59 uint *ea, *ip; 60 61 retval = 0; 62 63 instword = *((uint *)regs->nip); 64 inst = instword >> 26; 65 66 flreg = (instword >> 21) & 0x1f; 67 idxreg = (instword >> 16) & 0x1f; 68 disp = instword & 0xffff; 69 70 ea = (uint *)(regs->gpr[idxreg] + disp); 71 ip = (uint *)¤t->thread.fpr[flreg]; 72 73 switch ( inst ) 74 { 75 case LFD: 76 /* this is a 16 bit quantity that is sign extended 77 * so use a signed short here -- Cort 78 */ 79 sdisp = (instword & 0xffff); 80 ea = (uint *)(regs->gpr[idxreg] + sdisp); 81 if (copy_from_user(ip, ea, sizeof(double))) 82 retval = -EFAULT; 83 break; 84 85 case LFDU: 86 if (copy_from_user(ip, ea, sizeof(double))) 87 retval = -EFAULT; 88 else 89 regs->gpr[idxreg] = (uint)ea; 90 break; 91 case LFS: 92 sdisp = (instword & 0xffff); 93 ea = (uint *)(regs->gpr[idxreg] + sdisp); 94 if (copy_from_user(ip, ea, sizeof(float))) 95 retval = -EFAULT; 96 break; 97 case STFD: 98 /* this is a 16 bit quantity that is sign extended 99 * so use a signed short here -- Cort 100 */ 101 sdisp = (instword & 0xffff); 102 ea = (uint *)(regs->gpr[idxreg] + sdisp); 103 if (copy_to_user(ea, ip, sizeof(double))) 104 retval = -EFAULT; 105 break; 106 107 case STFDU: 108 if (copy_to_user(ea, ip, sizeof(double))) 109 retval = -EFAULT; 110 else 111 regs->gpr[idxreg] = (uint)ea; 112 break; 113 case FMR: 114 /* assume this is a fp move -- Cort */ 115 memcpy( ip, ¤t->thread.fpr[(instword>>11)&0x1f], 116 sizeof(double) ); 117 break; 118 default: 119 retval = 1; 120 printk("Bad emulation %s/%d\n" 121 " NIP: %08lx instruction: %08x opcode: %x " 122 "A: %x B: %x C: %x code: %x rc: %x\n", 123 current->comm,current->pid, 124 regs->nip, 125 instword,inst, 126 (instword>>16)&0x1f, 127 (instword>>11)&0x1f, 128 (instword>>6)&0x1f, 129 (instword>>1)&0x3ff, 130 instword&1); 131 { 132 int pa; 133 print_8xx_pte(current->mm,regs->nip); 134 pa = get_8xx_pte(current->mm,regs->nip) & PAGE_MASK; 135 pa |= (regs->nip & ~PAGE_MASK); 136 pa = (unsigned long)__va(pa); 137 printk("Kernel VA for NIP %x ", pa); 138 print_8xx_pte(current->mm,pa); 139 } 140 141 } 142 143 if (retval == 0) 144 regs->nip += 4; 145 return(retval); 146} 147