1 /* 2 * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved. 3 * 4 * Author: Yu Liu, <yu.liu@freescale.com> 5 * 6 * Description: 7 * This file is derived from arch/powerpc/kvm/44x_emulate.c, 8 * by Hollis Blanchard <hollisb@us.ibm.com>. 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License, version 2, as 12 * published by the Free Software Foundation. 13 */ 14 15 #include <asm/kvm_ppc.h> 16 #include <asm/disassemble.h> 17 #include <asm/dbell.h> 18 19 #include "booke.h" 20 #include "e500.h" 21 22 #define XOP_MSGSND 206 23 #define XOP_MSGCLR 238 24 #define XOP_TLBIVAX 786 25 #define XOP_TLBSX 914 26 #define XOP_TLBRE 946 27 #define XOP_TLBWE 978 28 #define XOP_TLBILX 18 29 30 #ifdef CONFIG_KVM_E500MC 31 static int dbell2prio(ulong param) 32 { 33 int msg = param & PPC_DBELL_TYPE_MASK; 34 int prio = -1; 35 36 switch (msg) { 37 case PPC_DBELL_TYPE(PPC_DBELL): 38 prio = BOOKE_IRQPRIO_DBELL; 39 break; 40 case PPC_DBELL_TYPE(PPC_DBELL_CRIT): 41 prio = BOOKE_IRQPRIO_DBELL_CRIT; 42 break; 43 default: 44 break; 45 } 46 47 return prio; 48 } 49 50 static int kvmppc_e500_emul_msgclr(struct kvm_vcpu *vcpu, int rb) 51 { 52 ulong param = vcpu->arch.gpr[rb]; 53 int prio = dbell2prio(param); 54 55 if (prio < 0) 56 return EMULATE_FAIL; 57 58 clear_bit(prio, &vcpu->arch.pending_exceptions); 59 return EMULATE_DONE; 60 } 61 62 static int kvmppc_e500_emul_msgsnd(struct kvm_vcpu *vcpu, int rb) 63 { 64 ulong param = vcpu->arch.gpr[rb]; 65 int prio = dbell2prio(rb); 66 int pir = param & PPC_DBELL_PIR_MASK; 67 int i; 68 struct kvm_vcpu *cvcpu; 69 70 if (prio < 0) 71 return EMULATE_FAIL; 72 73 kvm_for_each_vcpu(i, cvcpu, vcpu->kvm) { 74 int cpir = cvcpu->arch.shared->pir; 75 if ((param & PPC_DBELL_MSG_BRDCAST) || (cpir == pir)) { 76 set_bit(prio, &cvcpu->arch.pending_exceptions); 77 kvm_vcpu_kick(cvcpu); 78 } 79 } 80 81 return EMULATE_DONE; 82 } 83 #endif 84 85 int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, 86 unsigned int inst, int *advance) 87 { 88 int emulated = EMULATE_DONE; 89 int ra = get_ra(inst); 90 int rb = get_rb(inst); 91 int rt = get_rt(inst); 92 93 switch (get_op(inst)) { 94 case 31: 95 switch (get_xop(inst)) { 96 97 #ifdef CONFIG_KVM_E500MC 98 case XOP_MSGSND: 99 emulated = kvmppc_e500_emul_msgsnd(vcpu, rb); 100 break; 101 102 case XOP_MSGCLR: 103 emulated = kvmppc_e500_emul_msgclr(vcpu, rb); 104 break; 105 #endif 106 107 case XOP_TLBRE: 108 emulated = kvmppc_e500_emul_tlbre(vcpu); 109 break; 110 111 case XOP_TLBWE: 112 emulated = kvmppc_e500_emul_tlbwe(vcpu); 113 break; 114 115 case XOP_TLBSX: 116 emulated = kvmppc_e500_emul_tlbsx(vcpu,rb); 117 break; 118 119 case XOP_TLBILX: 120 emulated = kvmppc_e500_emul_tlbilx(vcpu, rt, ra, rb); 121 break; 122 123 case XOP_TLBIVAX: 124 emulated = kvmppc_e500_emul_tlbivax(vcpu, ra, rb); 125 break; 126 127 default: 128 emulated = EMULATE_FAIL; 129 } 130 131 break; 132 133 default: 134 emulated = EMULATE_FAIL; 135 } 136 137 if (emulated == EMULATE_FAIL) 138 emulated = kvmppc_booke_emulate_op(run, vcpu, inst, advance); 139 140 return emulated; 141 } 142 143 int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val) 144 { 145 struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); 146 int emulated = EMULATE_DONE; 147 148 switch (sprn) { 149 #ifndef CONFIG_KVM_BOOKE_HV 150 case SPRN_PID: 151 kvmppc_set_pid(vcpu, spr_val); 152 break; 153 case SPRN_PID1: 154 if (spr_val != 0) 155 return EMULATE_FAIL; 156 vcpu_e500->pid[1] = spr_val; 157 break; 158 case SPRN_PID2: 159 if (spr_val != 0) 160 return EMULATE_FAIL; 161 vcpu_e500->pid[2] = spr_val; 162 break; 163 case SPRN_MAS0: 164 vcpu->arch.shared->mas0 = spr_val; 165 break; 166 case SPRN_MAS1: 167 vcpu->arch.shared->mas1 = spr_val; 168 break; 169 case SPRN_MAS2: 170 vcpu->arch.shared->mas2 = spr_val; 171 break; 172 case SPRN_MAS3: 173 vcpu->arch.shared->mas7_3 &= ~(u64)0xffffffff; 174 vcpu->arch.shared->mas7_3 |= spr_val; 175 break; 176 case SPRN_MAS4: 177 vcpu->arch.shared->mas4 = spr_val; 178 break; 179 case SPRN_MAS6: 180 vcpu->arch.shared->mas6 = spr_val; 181 break; 182 case SPRN_MAS7: 183 vcpu->arch.shared->mas7_3 &= (u64)0xffffffff; 184 vcpu->arch.shared->mas7_3 |= (u64)spr_val << 32; 185 break; 186 #endif 187 case SPRN_L1CSR0: 188 vcpu_e500->l1csr0 = spr_val; 189 vcpu_e500->l1csr0 &= ~(L1CSR0_DCFI | L1CSR0_CLFC); 190 break; 191 case SPRN_L1CSR1: 192 vcpu_e500->l1csr1 = spr_val; 193 break; 194 case SPRN_HID0: 195 vcpu_e500->hid0 = spr_val; 196 break; 197 case SPRN_HID1: 198 vcpu_e500->hid1 = spr_val; 199 break; 200 201 case SPRN_MMUCSR0: 202 emulated = kvmppc_e500_emul_mt_mmucsr0(vcpu_e500, 203 spr_val); 204 break; 205 206 /* extra exceptions */ 207 case SPRN_IVOR32: 208 vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val; 209 break; 210 case SPRN_IVOR33: 211 vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA] = spr_val; 212 break; 213 case SPRN_IVOR34: 214 vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val; 215 break; 216 case SPRN_IVOR35: 217 vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val; 218 break; 219 #ifdef CONFIG_KVM_BOOKE_HV 220 case SPRN_IVOR36: 221 vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL] = spr_val; 222 break; 223 case SPRN_IVOR37: 224 vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT] = spr_val; 225 break; 226 #endif 227 default: 228 emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, spr_val); 229 } 230 231 return emulated; 232 } 233 234 int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val) 235 { 236 struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); 237 int emulated = EMULATE_DONE; 238 239 switch (sprn) { 240 #ifndef CONFIG_KVM_BOOKE_HV 241 case SPRN_PID: 242 *spr_val = vcpu_e500->pid[0]; 243 break; 244 case SPRN_PID1: 245 *spr_val = vcpu_e500->pid[1]; 246 break; 247 case SPRN_PID2: 248 *spr_val = vcpu_e500->pid[2]; 249 break; 250 case SPRN_MAS0: 251 *spr_val = vcpu->arch.shared->mas0; 252 break; 253 case SPRN_MAS1: 254 *spr_val = vcpu->arch.shared->mas1; 255 break; 256 case SPRN_MAS2: 257 *spr_val = vcpu->arch.shared->mas2; 258 break; 259 case SPRN_MAS3: 260 *spr_val = (u32)vcpu->arch.shared->mas7_3; 261 break; 262 case SPRN_MAS4: 263 *spr_val = vcpu->arch.shared->mas4; 264 break; 265 case SPRN_MAS6: 266 *spr_val = vcpu->arch.shared->mas6; 267 break; 268 case SPRN_MAS7: 269 *spr_val = vcpu->arch.shared->mas7_3 >> 32; 270 break; 271 #endif 272 case SPRN_TLB0CFG: 273 *spr_val = vcpu->arch.tlbcfg[0]; 274 break; 275 case SPRN_TLB1CFG: 276 *spr_val = vcpu->arch.tlbcfg[1]; 277 break; 278 case SPRN_L1CSR0: 279 *spr_val = vcpu_e500->l1csr0; 280 break; 281 case SPRN_L1CSR1: 282 *spr_val = vcpu_e500->l1csr1; 283 break; 284 case SPRN_HID0: 285 *spr_val = vcpu_e500->hid0; 286 break; 287 case SPRN_HID1: 288 *spr_val = vcpu_e500->hid1; 289 break; 290 case SPRN_SVR: 291 *spr_val = vcpu_e500->svr; 292 break; 293 294 case SPRN_MMUCSR0: 295 *spr_val = 0; 296 break; 297 298 case SPRN_MMUCFG: 299 *spr_val = vcpu->arch.mmucfg; 300 break; 301 302 /* extra exceptions */ 303 case SPRN_IVOR32: 304 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL]; 305 break; 306 case SPRN_IVOR33: 307 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA]; 308 break; 309 case SPRN_IVOR34: 310 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND]; 311 break; 312 case SPRN_IVOR35: 313 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; 314 break; 315 #ifdef CONFIG_KVM_BOOKE_HV 316 case SPRN_IVOR36: 317 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL]; 318 break; 319 case SPRN_IVOR37: 320 *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT]; 321 break; 322 #endif 323 default: 324 emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, spr_val); 325 } 326 327 return emulated; 328 } 329 330