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