| 1 | /* |
| 2 | * PowerPC emulation special registers manipulation helpers for qemu. |
| 3 | * |
| 4 | * Copyright (c) 2003-2007 Jocelyn Mayer |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
| 9 | * version 2.1 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| 18 | */ |
| 19 | |
| 20 | #include "qemu/osdep.h" |
| 21 | #include "cpu.h" |
| 22 | #include "qemu/main-loop.h" |
| 23 | #include "exec/cputlb.h" |
| 24 | #include "system/kvm.h" |
| 25 | #include "system/tcg.h" |
| 26 | #include "helper_regs.h" |
| 27 | #include "power8-pmu.h" |
| 28 | #include "cpu-models.h" |
| 29 | #include "spr_common.h" |
| 30 | #include "internal.h" |
| 31 | |
| 32 | /* Swap temporary saved registers with GPRs */ |
| 33 | void hreg_swap_gpr_tgpr(CPUPPCState *env) |
| 34 | { |
| 35 | target_ulong tmp; |
| 36 | |
| 37 | tmp = env->gpr[0]; |
| 38 | env->gpr[0] = env->tgpr[0]; |
| 39 | env->tgpr[0] = tmp; |
| 40 | tmp = env->gpr[1]; |
| 41 | env->gpr[1] = env->tgpr[1]; |
| 42 | env->tgpr[1] = tmp; |
| 43 | tmp = env->gpr[2]; |
| 44 | env->gpr[2] = env->tgpr[2]; |
| 45 | env->tgpr[2] = tmp; |
| 46 | tmp = env->gpr[3]; |
| 47 | env->gpr[3] = env->tgpr[3]; |
| 48 | env->tgpr[3] = tmp; |
| 49 | } |
| 50 | |
| 51 | #if defined(TARGET_PPC64) |
| 52 | static bool hreg_check_bhrb_enable(CPUPPCState *env) |
| 53 | { |
| 54 | bool pr = !!(env->msr & (1 << MSR_PR)); |
| 55 | target_long mmcr0; |
| 56 | bool fcp; |
| 57 | bool hv; |
| 58 | |
| 59 | /* ISA 3.1 adds the PMCRA[BRHBRD] and problem state checks */ |
| 60 | if ((env->insns_flags2 & PPC2_ISA310) && |
| 61 | ((env->spr[SPR_POWER_MMCRA] & MMCRA_BHRBRD) || !pr)) { |
| 62 | return false; |
| 63 | } |
| 64 | |
| 65 | /* Check for BHRB "frozen" conditions */ |
| 66 | mmcr0 = env->spr[SPR_POWER_MMCR0]; |
| 67 | fcp = !!(mmcr0 & MMCR0_FCP); |
| 68 | if (mmcr0 & MMCR0_FCPC) { |
| 69 | hv = !!(env->msr & (1ull << MSR_HV)); |
| 70 | if (fcp) { |
| 71 | if (hv && pr) { |
| 72 | return false; |
| 73 | } |
| 74 | } else if (!hv && pr) { |
| 75 | return false; |
| 76 | } |
| 77 | } else if (fcp && pr) { |
| 78 | return false; |
| 79 | } |
| 80 | return true; |
| 81 | } |
| 82 | #endif |
| 83 | |
| 84 | static uint32_t hreg_compute_pmu_hflags_value(CPUPPCState *env) |
| 85 | { |
| 86 | uint32_t hflags = 0; |
| 87 | #if defined(TARGET_PPC64) |
| 88 | target_ulong mmcr0 = env->spr[SPR_POWER_MMCR0]; |
| 89 | |
| 90 | if (mmcr0 & MMCR0_PMCC0) { |
| 91 | hflags |= 1 << HFLAGS_PMCC0; |
| 92 | } |
| 93 | if (mmcr0 & MMCR0_PMCC1) { |
| 94 | hflags |= 1 << HFLAGS_PMCC1; |
| 95 | } |
| 96 | if (mmcr0 & MMCR0_PMCjCE) { |
| 97 | hflags |= 1 << HFLAGS_PMCJCE; |
| 98 | } |
| 99 | if (hreg_check_bhrb_enable(env)) { |
| 100 | hflags |= 1 << HFLAGS_BHRB_ENABLE; |
| 101 | } |
| 102 | |
| 103 | #ifndef CONFIG_USER_ONLY |
| 104 | if (env->pmc_ins_cnt) { |
| 105 | hflags |= 1 << HFLAGS_INSN_CNT; |
| 106 | if (env->pmc_ins_cnt & 0x1e) { |
| 107 | hflags |= 1 << HFLAGS_PMC_OTHER; |
| 108 | } |
| 109 | } |
| 110 | #endif |
| 111 | #endif |
| 112 | |
| 113 | return hflags; |
| 114 | } |
| 115 | |
| 116 | /* Mask of all PMU hflags */ |
| 117 | static uint32_t hreg_compute_pmu_hflags_mask(CPUPPCState *env) |
| 118 | { |
| 119 | uint32_t hflags_mask = 0; |
| 120 | #if defined(TARGET_PPC64) |
| 121 | hflags_mask |= 1 << HFLAGS_PMCC0; |
| 122 | hflags_mask |= 1 << HFLAGS_PMCC1; |
| 123 | hflags_mask |= 1 << HFLAGS_PMCJCE; |
| 124 | hflags_mask |= 1 << HFLAGS_INSN_CNT; |
| 125 | hflags_mask |= 1 << HFLAGS_PMC_OTHER; |
| 126 | hflags_mask |= 1 << HFLAGS_BHRB_ENABLE; |
| 127 | #endif |
| 128 | return hflags_mask; |
| 129 | } |
| 130 | |
| 131 | static uint32_t hreg_compute_hflags_value(CPUPPCState *env) |
| 132 | { |
| 133 | target_ulong msr = env->msr; |
| 134 | uint32_t ppc_flags = env->flags; |
| 135 | uint32_t hflags = 0; |
| 136 | uint32_t msr_mask; |
| 137 | |
| 138 | /* Some bits come straight across from MSR. */ |
| 139 | QEMU_BUILD_BUG_ON(MSR_LE != HFLAGS_LE); |
| 140 | QEMU_BUILD_BUG_ON(MSR_PR != HFLAGS_PR); |
| 141 | QEMU_BUILD_BUG_ON(MSR_DR != HFLAGS_DR); |
| 142 | QEMU_BUILD_BUG_ON(MSR_FP != HFLAGS_FP); |
| 143 | msr_mask = ((1 << MSR_LE) | (1 << MSR_PR) | |
| 144 | (1 << MSR_DR) | (1 << MSR_FP)); |
| 145 | |
| 146 | if (ppc_flags & POWERPC_FLAG_DE) { |
| 147 | target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0]; |
| 148 | if ((dbcr0 & DBCR0_ICMP) && FIELD_EX64(msr, MSR, DE)) { |
| 149 | hflags |= 1 << HFLAGS_SE; |
| 150 | } |
| 151 | if ((dbcr0 & DBCR0_BRT) && FIELD_EX64(msr, MSR, DE)) { |
| 152 | hflags |= 1 << HFLAGS_BE; |
| 153 | } |
| 154 | } else { |
| 155 | if (ppc_flags & POWERPC_FLAG_BE) { |
| 156 | QEMU_BUILD_BUG_ON(MSR_BE != HFLAGS_BE); |
| 157 | msr_mask |= 1 << MSR_BE; |
| 158 | } |
| 159 | if (ppc_flags & POWERPC_FLAG_SE) { |
| 160 | QEMU_BUILD_BUG_ON(MSR_SE != HFLAGS_SE); |
| 161 | msr_mask |= 1 << MSR_SE; |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | if (msr_is_64bit(env, msr)) { |
| 166 | hflags |= 1 << HFLAGS_64; |
| 167 | } |
| 168 | if ((ppc_flags & POWERPC_FLAG_SPE) && (msr & (1 << MSR_SPE))) { |
| 169 | hflags |= 1 << HFLAGS_SPE; |
| 170 | } |
| 171 | if (ppc_flags & POWERPC_FLAG_VRE) { |
| 172 | QEMU_BUILD_BUG_ON(MSR_VR != HFLAGS_VR); |
| 173 | msr_mask |= 1 << MSR_VR; |
| 174 | } |
| 175 | if (ppc_flags & POWERPC_FLAG_VSX) { |
| 176 | QEMU_BUILD_BUG_ON(MSR_VSX != HFLAGS_VSX); |
| 177 | msr_mask |= 1 << MSR_VSX; |
| 178 | } |
| 179 | if ((ppc_flags & POWERPC_FLAG_TM) && (msr & (1ull << MSR_TM))) { |
| 180 | hflags |= 1 << HFLAGS_TM; |
| 181 | } |
| 182 | if (env->spr[SPR_LPCR] & LPCR_GTSE) { |
| 183 | hflags |= 1 << HFLAGS_GTSE; |
| 184 | } |
| 185 | if (env->spr[SPR_LPCR] & LPCR_HR) { |
| 186 | hflags |= 1 << HFLAGS_HR; |
| 187 | } |
| 188 | if (unlikely(ppc_flags & POWERPC_FLAG_PPE42)) { |
| 189 | /* PPE42 has a single address space and no problem state */ |
| 190 | msr = 0; |
| 191 | } |
| 192 | |
| 193 | #ifndef CONFIG_USER_ONLY |
| 194 | if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) { |
| 195 | hflags |= 1 << HFLAGS_HV; |
| 196 | } |
| 197 | |
| 198 | /* |
| 199 | * This is our encoding for server processors. The architecture |
| 200 | * specifies that there is no such thing as userspace with |
| 201 | * translation off, however it appears that MacOS does it and some |
| 202 | * 32-bit CPUs support it. Weird... |
| 203 | * |
| 204 | * 0 = Guest User space virtual mode |
| 205 | * 1 = Guest Kernel space virtual mode |
| 206 | * 2 = Guest User space real mode |
| 207 | * 3 = Guest Kernel space real mode |
| 208 | * 4 = HV User space virtual mode |
| 209 | * 5 = HV Kernel space virtual mode |
| 210 | * 6 = HV User space real mode |
| 211 | * 7 = HV Kernel space real mode |
| 212 | * |
| 213 | * For BookE, we need 8 MMU modes as follow: |
| 214 | * |
| 215 | * 0 = AS 0 HV User space |
| 216 | * 1 = AS 0 HV Kernel space |
| 217 | * 2 = AS 1 HV User space |
| 218 | * 3 = AS 1 HV Kernel space |
| 219 | * 4 = AS 0 Guest User space |
| 220 | * 5 = AS 0 Guest Kernel space |
| 221 | * 6 = AS 1 Guest User space |
| 222 | * 7 = AS 1 Guest Kernel space |
| 223 | */ |
| 224 | unsigned immu_idx, dmmu_idx; |
| 225 | dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1; |
| 226 | if (env->mmu_model == POWERPC_MMU_BOOKE || |
| 227 | env->mmu_model == POWERPC_MMU_BOOKE206) { |
| 228 | dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0; |
| 229 | immu_idx = dmmu_idx; |
| 230 | immu_idx |= msr & (1 << MSR_IS) ? 2 : 0; |
| 231 | dmmu_idx |= msr & (1 << MSR_DS) ? 2 : 0; |
| 232 | } else { |
| 233 | dmmu_idx |= msr & (1ull << MSR_HV) ? 4 : 0; |
| 234 | immu_idx = dmmu_idx; |
| 235 | immu_idx |= msr & (1 << MSR_IR) ? 0 : 2; |
| 236 | dmmu_idx |= msr & (1 << MSR_DR) ? 0 : 2; |
| 237 | } |
| 238 | hflags |= immu_idx << HFLAGS_IMMU_IDX; |
| 239 | hflags |= dmmu_idx << HFLAGS_DMMU_IDX; |
| 240 | #endif |
| 241 | |
| 242 | hflags |= hreg_compute_pmu_hflags_value(env); |
| 243 | |
| 244 | return hflags | (msr & msr_mask); |
| 245 | } |
| 246 | |
| 247 | void hreg_compute_hflags(CPUPPCState *env) |
| 248 | { |
| 249 | env->hflags = hreg_compute_hflags_value(env); |
| 250 | } |
| 251 | |
| 252 | /* |
| 253 | * This can be used as a lighter-weight alternative to hreg_compute_hflags |
| 254 | * when PMU MMCR0 or pmc_ins_cnt changes. pmc_ins_cnt is changed by |
| 255 | * pmu_update_summaries. |
| 256 | */ |
| 257 | void hreg_update_pmu_hflags(CPUPPCState *env) |
| 258 | { |
| 259 | env->hflags &= ~hreg_compute_pmu_hflags_mask(env); |
| 260 | env->hflags |= hreg_compute_pmu_hflags_value(env); |
| 261 | } |
| 262 | |
| 263 | #ifdef CONFIG_TCG |
| 264 | TCGTBCPUState ppc_get_tb_cpu_state(CPUState *cs) |
| 265 | { |
| 266 | CPUPPCState *env = cpu_env(cs); |
| 267 | uint32_t hflags_current = env->hflags; |
| 268 | |
| 269 | #ifdef CONFIG_DEBUG_TCG |
| 270 | uint32_t hflags_rebuilt = hreg_compute_hflags_value(env); |
| 271 | if (unlikely(hflags_current != hflags_rebuilt)) { |
| 272 | cpu_abort(env_cpu(env), |
| 273 | "TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n", |
| 274 | hflags_current, hflags_rebuilt); |
| 275 | } |
| 276 | #endif |
| 277 | |
| 278 | return (TCGTBCPUState){ .pc = env->nip, .flags = hflags_current }; |
| 279 | } |
| 280 | #endif /* CONFIG_TCG */ |
| 281 | |
| 282 | #ifndef CONFIG_USER_ONLY |
| 283 | void cpu_interrupt_exittb(CPUState *cs) |
| 284 | { |
| 285 | /* |
| 286 | * We don't need to worry about translation blocks |
| 287 | * unless running with TCG. |
| 288 | */ |
| 289 | if (tcg_enabled()) { |
| 290 | BQL_LOCK_GUARD(); |
| 291 | cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); |
| 292 | } |
| 293 | } |
| 294 | #endif |
| 295 | |
| 296 | int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) |
| 297 | { |
| 298 | int excp; |
| 299 | #if !defined(CONFIG_USER_ONLY) |
| 300 | CPUState *cs = env_cpu(env); |
| 301 | #endif |
| 302 | |
| 303 | excp = 0; |
| 304 | value &= env->msr_mask; |
| 305 | #if !defined(CONFIG_USER_ONLY) |
| 306 | /* Neither mtmsr nor guest state can alter HV */ |
| 307 | if (!alter_hv || !(env->msr & MSR_HVB)) { |
| 308 | value &= ~MSR_HVB; |
| 309 | value |= env->msr & MSR_HVB; |
| 310 | } |
| 311 | /* Attempt to modify MSR[ME] in guest state is ignored */ |
| 312 | if (is_book3s_arch2x(env) && !(env->msr & MSR_HVB)) { |
| 313 | value &= ~(1 << MSR_ME); |
| 314 | value |= env->msr & (1 << MSR_ME); |
| 315 | } |
| 316 | if ((env->mmu_model == POWERPC_MMU_BOOKE || |
| 317 | env->mmu_model == POWERPC_MMU_BOOKE206) && |
| 318 | ((value ^ env->msr) & R_MSR_GS_MASK)) { |
| 319 | cpu_interrupt_exittb(cs); |
| 320 | } |
| 321 | if (unlikely((env->flags & POWERPC_FLAG_TGPR) && |
| 322 | ((value ^ env->msr) & (1 << MSR_TGPR)))) { |
| 323 | /* Swap temporary saved registers with GPRs */ |
| 324 | hreg_swap_gpr_tgpr(env); |
| 325 | } |
| 326 | /* PPE42 uses IR, DR and EP MSR bits for other purposes */ |
| 327 | if (likely(!(env->flags & POWERPC_FLAG_PPE42))) { |
| 328 | if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) { |
| 329 | cpu_interrupt_exittb(cs); |
| 330 | } |
| 331 | if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) { |
| 332 | env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000; |
| 333 | } |
| 334 | } |
| 335 | /* |
| 336 | * If PR=1 then EE, IR and DR must be 1 |
| 337 | * |
| 338 | * Note: We only enforce this on 64-bit server processors. |
| 339 | * It appears that: |
| 340 | * - 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS |
| 341 | * exploits it. |
| 342 | * - 64-bit embedded implementations do not need any operation to be |
| 343 | * performed when PR is set. |
| 344 | */ |
| 345 | if (is_book3s_arch2x(env) && ((value >> MSR_PR) & 1)) { |
| 346 | value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR); |
| 347 | } |
| 348 | #endif |
| 349 | env->msr = value; |
| 350 | hreg_compute_hflags(env); |
| 351 | #if !defined(CONFIG_USER_ONLY) |
| 352 | ppc_maybe_interrupt(env); |
| 353 | |
| 354 | if (unlikely(FIELD_EX64(env->msr, MSR, POW))) { |
| 355 | if (!env->pending_interrupts && (*env->check_pow)(env)) { |
| 356 | cs->halted = 1; |
| 357 | excp = EXCP_HALTED; |
| 358 | } |
| 359 | } |
| 360 | #endif |
| 361 | |
| 362 | return excp; |
| 363 | } |
| 364 | |
| 365 | #ifndef CONFIG_USER_ONLY |
| 366 | void store_40x_sler(CPUPPCState *env, uint32_t val) |
| 367 | { |
| 368 | /* XXX: TO BE FIXED */ |
| 369 | if (val != 0x00000000) { |
| 370 | cpu_abort(env_cpu(env), |
| 371 | "Little-endian regions are not supported by now\n"); |
| 372 | } |
| 373 | env->spr[SPR_405_SLER] = val; |
| 374 | } |
| 375 | |
| 376 | void check_tlb_flush(CPUPPCState *env, bool global) |
| 377 | { |
| 378 | CPUState *cs = env_cpu(env); |
| 379 | |
| 380 | /* Handle global flushes first */ |
| 381 | if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { |
| 382 | env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; |
| 383 | env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; |
| 384 | tlb_flush_all_cpus_synced(cs); |
| 385 | return; |
| 386 | } |
| 387 | |
| 388 | /* Then handle local ones */ |
| 389 | if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { |
| 390 | env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; |
| 391 | tlb_flush(cs); |
| 392 | } |
| 393 | } |
| 394 | #endif /* !CONFIG_USER_ONLY */ |
| 395 | |
| 396 | /** |
| 397 | * _spr_register |
| 398 | * |
| 399 | * Register an SPR with all the callbacks required for tcg, |
| 400 | * and the ID number for KVM. |
| 401 | * |
| 402 | * The reason for the conditional compilation is that the tcg functions |
| 403 | * may be compiled out, and the system kvm header may not be available |
| 404 | * for supplying the ID numbers. This is ugly, but the best we can do. |
| 405 | */ |
| 406 | void _spr_register(CPUPPCState *env, int num, const char *name, |
| 407 | USR_ARG(spr_callback *uea_read) |
| 408 | USR_ARG(spr_callback *uea_write) |
| 409 | SYS_ARG(spr_callback *oea_read) |
| 410 | SYS_ARG(spr_callback *oea_write) |
| 411 | SYS_ARG(spr_callback *hea_read) |
| 412 | SYS_ARG(spr_callback *hea_write) |
| 413 | KVM_ARG(uint64_t one_reg_id) |
| 414 | target_ulong initial_value) |
| 415 | { |
| 416 | ppc_spr_t *spr = &env->spr_cb[num]; |
| 417 | |
| 418 | /* No SPR should be registered twice. */ |
| 419 | assert(spr->name == NULL); |
| 420 | assert(name != NULL); |
| 421 | |
| 422 | spr->name = name; |
| 423 | spr->default_value = initial_value; |
| 424 | env->spr[num] = initial_value; |
| 425 | |
| 426 | #ifdef CONFIG_TCG |
| 427 | spr->uea_read = uea_read; |
| 428 | spr->uea_write = uea_write; |
| 429 | # ifndef CONFIG_USER_ONLY |
| 430 | spr->oea_read = oea_read; |
| 431 | spr->oea_write = oea_write; |
| 432 | spr->hea_read = hea_read; |
| 433 | spr->hea_write = hea_write; |
| 434 | # endif |
| 435 | #endif |
| 436 | #ifdef CONFIG_KVM |
| 437 | spr->one_reg_id = one_reg_id; |
| 438 | #endif |
| 439 | } |
| 440 | |
| 441 | /* Generic PowerPC SPRs */ |
| 442 | void register_generic_sprs(PowerPCCPU *cpu) |
| 443 | { |
| 444 | PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); |
| 445 | CPUPPCState *env = &cpu->env; |
| 446 | |
| 447 | /* Integer processing */ |
| 448 | spr_register(env, SPR_XER, "XER", |
| 449 | &spr_read_xer, &spr_write_xer, |
| 450 | &spr_read_xer, &spr_write_xer, |
| 451 | 0x00000000); |
| 452 | /* Branch control */ |
| 453 | spr_register(env, SPR_LR, "LR", |
| 454 | &spr_read_lr, &spr_write_lr, |
| 455 | &spr_read_lr, &spr_write_lr, |
| 456 | 0x00000000); |
| 457 | spr_register(env, SPR_CTR, "CTR", |
| 458 | &spr_read_ctr, &spr_write_ctr, |
| 459 | &spr_read_ctr, &spr_write_ctr, |
| 460 | 0x00000000); |
| 461 | /* Interrupt processing */ |
| 462 | spr_register(env, SPR_SRR0, "SRR0", |
| 463 | SPR_NOACCESS, SPR_NOACCESS, |
| 464 | &spr_read_generic, &spr_write_generic, |
| 465 | 0x00000000); |
| 466 | spr_register(env, SPR_SRR1, "SRR1", |
| 467 | SPR_NOACCESS, SPR_NOACCESS, |
| 468 | &spr_read_generic, &spr_write_generic, |
| 469 | 0x00000000); |
| 470 | /* Processor control */ |
| 471 | spr_register(env, SPR_SPRG0, "SPRG0", |
| 472 | SPR_NOACCESS, SPR_NOACCESS, |
| 473 | &spr_read_generic, &spr_write_generic, |
| 474 | 0x00000000); |
| 475 | |
| 476 | spr_register(env, SPR_PVR, "PVR", |
| 477 | /* Linux permits userspace to read PVR */ |
| 478 | #if defined(CONFIG_LINUX_USER) |
| 479 | &spr_read_generic, |
| 480 | #else |
| 481 | SPR_NOACCESS, |
| 482 | #endif |
| 483 | SPR_NOACCESS, |
| 484 | &spr_read_generic, SPR_NOACCESS, |
| 485 | pcc->pvr); |
| 486 | |
| 487 | /* PPE42 doesn't support SPRG1-3, SVR or TB regs */ |
| 488 | if (env->insns_flags2 & PPC2_PPE42) { |
| 489 | return; |
| 490 | } |
| 491 | |
| 492 | spr_register(env, SPR_SPRG1, "SPRG1", |
| 493 | SPR_NOACCESS, SPR_NOACCESS, |
| 494 | &spr_read_generic, &spr_write_generic, |
| 495 | 0x00000000); |
| 496 | spr_register(env, SPR_SPRG2, "SPRG2", |
| 497 | SPR_NOACCESS, SPR_NOACCESS, |
| 498 | &spr_read_generic, &spr_write_generic, |
| 499 | 0x00000000); |
| 500 | spr_register(env, SPR_SPRG3, "SPRG3", |
| 501 | SPR_NOACCESS, SPR_NOACCESS, |
| 502 | &spr_read_generic, &spr_write_generic, |
| 503 | 0x00000000); |
| 504 | |
| 505 | /* Register SVR if it's defined to anything else than POWERPC_SVR_NONE */ |
| 506 | if (pcc->svr != POWERPC_SVR_NONE) { |
| 507 | if (pcc->svr & POWERPC_SVR_E500) { |
| 508 | spr_register(env, SPR_E500_SVR, "SVR", |
| 509 | SPR_NOACCESS, SPR_NOACCESS, |
| 510 | &spr_read_generic, SPR_NOACCESS, |
| 511 | pcc->svr & ~POWERPC_SVR_E500); |
| 512 | } else { |
| 513 | spr_register(env, SPR_SVR, "SVR", |
| 514 | SPR_NOACCESS, SPR_NOACCESS, |
| 515 | &spr_read_generic, SPR_NOACCESS, |
| 516 | pcc->svr); |
| 517 | } |
| 518 | } |
| 519 | |
| 520 | /* Time base */ |
| 521 | #if defined(TARGET_PPC64) |
| 522 | spr_register(env, SPR_TBL, "TB", |
| 523 | #else |
| 524 | spr_register(env, SPR_TBL, "TBL", |
| 525 | #endif |
| 526 | &spr_read_tbl, SPR_NOACCESS, |
| 527 | &spr_read_tbl, SPR_NOACCESS, |
| 528 | 0x00000000); |
| 529 | spr_register(env, SPR_TBU, "TBU", |
| 530 | &spr_read_tbu, SPR_NOACCESS, |
| 531 | &spr_read_tbu, SPR_NOACCESS, |
| 532 | 0x00000000); |
| 533 | #ifndef CONFIG_USER_ONLY |
| 534 | if (env->has_hv_mode) { |
| 535 | spr_register_hv(env, SPR_WR_TBL, "TBL", |
| 536 | SPR_NOACCESS, SPR_NOACCESS, |
| 537 | SPR_NOACCESS, SPR_NOACCESS, |
| 538 | SPR_NOACCESS, &spr_write_tbl, |
| 539 | 0x00000000); |
| 540 | spr_register_hv(env, SPR_WR_TBU, "TBU", |
| 541 | SPR_NOACCESS, SPR_NOACCESS, |
| 542 | SPR_NOACCESS, SPR_NOACCESS, |
| 543 | SPR_NOACCESS, &spr_write_tbu, |
| 544 | 0x00000000); |
| 545 | } else { |
| 546 | spr_register(env, SPR_WR_TBL, "TBL", |
| 547 | SPR_NOACCESS, SPR_NOACCESS, |
| 548 | SPR_NOACCESS, &spr_write_tbl, |
| 549 | 0x00000000); |
| 550 | spr_register(env, SPR_WR_TBU, "TBU", |
| 551 | SPR_NOACCESS, SPR_NOACCESS, |
| 552 | SPR_NOACCESS, &spr_write_tbu, |
| 553 | 0x00000000); |
| 554 | } |
| 555 | #endif |
| 556 | } |
| 557 | |
| 558 | void register_non_embedded_sprs(CPUPPCState *env) |
| 559 | { |
| 560 | /* Exception processing */ |
| 561 | spr_register_kvm(env, SPR_DSISR, "DSISR", |
| 562 | SPR_NOACCESS, SPR_NOACCESS, |
| 563 | &spr_read_generic, &spr_write_generic32, |
| 564 | KVM_REG_PPC_DSISR, 0x00000000); |
| 565 | spr_register_kvm(env, SPR_DAR, "DAR", |
| 566 | SPR_NOACCESS, SPR_NOACCESS, |
| 567 | &spr_read_generic, &spr_write_generic, |
| 568 | KVM_REG_PPC_DAR, 0x00000000); |
| 569 | /* Timer */ |
| 570 | spr_register(env, SPR_DECR, "DEC", |
| 571 | SPR_NOACCESS, SPR_NOACCESS, |
| 572 | &spr_read_decr, &spr_write_decr, |
| 573 | 0x00000000); |
| 574 | } |
| 575 | |
| 576 | /* Storage Description Register 1 */ |
| 577 | void register_sdr1_sprs(CPUPPCState *env) |
| 578 | { |
| 579 | #ifndef CONFIG_USER_ONLY |
| 580 | if (env->has_hv_mode) { |
| 581 | /* |
| 582 | * SDR1 is a hypervisor resource on CPUs which have a |
| 583 | * hypervisor mode |
| 584 | */ |
| 585 | spr_register_hv(env, SPR_SDR1, "SDR1", |
| 586 | SPR_NOACCESS, SPR_NOACCESS, |
| 587 | SPR_NOACCESS, SPR_NOACCESS, |
| 588 | &spr_read_generic, &spr_write_sdr1, |
| 589 | 0x00000000); |
| 590 | } else { |
| 591 | spr_register(env, SPR_SDR1, "SDR1", |
| 592 | SPR_NOACCESS, SPR_NOACCESS, |
| 593 | &spr_read_generic, &spr_write_sdr1, |
| 594 | 0x00000000); |
| 595 | } |
| 596 | #endif |
| 597 | } |
| 598 | |
| 599 | /* BATs 0-3 */ |
| 600 | void register_low_BATs(CPUPPCState *env) |
| 601 | { |
| 602 | #if !defined(CONFIG_USER_ONLY) |
| 603 | spr_register(env, SPR_IBAT0U, "IBAT0U", |
| 604 | SPR_NOACCESS, SPR_NOACCESS, |
| 605 | &spr_read_ibat, &spr_write_ibatu, |
| 606 | 0x00000000); |
| 607 | spr_register(env, SPR_IBAT0L, "IBAT0L", |
| 608 | SPR_NOACCESS, SPR_NOACCESS, |
| 609 | &spr_read_ibat, &spr_write_ibatl, |
| 610 | 0x00000000); |
| 611 | spr_register(env, SPR_IBAT1U, "IBAT1U", |
| 612 | SPR_NOACCESS, SPR_NOACCESS, |
| 613 | &spr_read_ibat, &spr_write_ibatu, |
| 614 | 0x00000000); |
| 615 | spr_register(env, SPR_IBAT1L, "IBAT1L", |
| 616 | SPR_NOACCESS, SPR_NOACCESS, |
| 617 | &spr_read_ibat, &spr_write_ibatl, |
| 618 | 0x00000000); |
| 619 | spr_register(env, SPR_IBAT2U, "IBAT2U", |
| 620 | SPR_NOACCESS, SPR_NOACCESS, |
| 621 | &spr_read_ibat, &spr_write_ibatu, |
| 622 | 0x00000000); |
| 623 | spr_register(env, SPR_IBAT2L, "IBAT2L", |
| 624 | SPR_NOACCESS, SPR_NOACCESS, |
| 625 | &spr_read_ibat, &spr_write_ibatl, |
| 626 | 0x00000000); |
| 627 | spr_register(env, SPR_IBAT3U, "IBAT3U", |
| 628 | SPR_NOACCESS, SPR_NOACCESS, |
| 629 | &spr_read_ibat, &spr_write_ibatu, |
| 630 | 0x00000000); |
| 631 | spr_register(env, SPR_IBAT3L, "IBAT3L", |
| 632 | SPR_NOACCESS, SPR_NOACCESS, |
| 633 | &spr_read_ibat, &spr_write_ibatl, |
| 634 | 0x00000000); |
| 635 | spr_register(env, SPR_DBAT0U, "DBAT0U", |
| 636 | SPR_NOACCESS, SPR_NOACCESS, |
| 637 | &spr_read_dbat, &spr_write_dbatu, |
| 638 | 0x00000000); |
| 639 | spr_register(env, SPR_DBAT0L, "DBAT0L", |
| 640 | SPR_NOACCESS, SPR_NOACCESS, |
| 641 | &spr_read_dbat, &spr_write_dbatl, |
| 642 | 0x00000000); |
| 643 | spr_register(env, SPR_DBAT1U, "DBAT1U", |
| 644 | SPR_NOACCESS, SPR_NOACCESS, |
| 645 | &spr_read_dbat, &spr_write_dbatu, |
| 646 | 0x00000000); |
| 647 | spr_register(env, SPR_DBAT1L, "DBAT1L", |
| 648 | SPR_NOACCESS, SPR_NOACCESS, |
| 649 | &spr_read_dbat, &spr_write_dbatl, |
| 650 | 0x00000000); |
| 651 | spr_register(env, SPR_DBAT2U, "DBAT2U", |
| 652 | SPR_NOACCESS, SPR_NOACCESS, |
| 653 | &spr_read_dbat, &spr_write_dbatu, |
| 654 | 0x00000000); |
| 655 | spr_register(env, SPR_DBAT2L, "DBAT2L", |
| 656 | SPR_NOACCESS, SPR_NOACCESS, |
| 657 | &spr_read_dbat, &spr_write_dbatl, |
| 658 | 0x00000000); |
| 659 | spr_register(env, SPR_DBAT3U, "DBAT3U", |
| 660 | SPR_NOACCESS, SPR_NOACCESS, |
| 661 | &spr_read_dbat, &spr_write_dbatu, |
| 662 | 0x00000000); |
| 663 | spr_register(env, SPR_DBAT3L, "DBAT3L", |
| 664 | SPR_NOACCESS, SPR_NOACCESS, |
| 665 | &spr_read_dbat, &spr_write_dbatl, |
| 666 | 0x00000000); |
| 667 | env->nb_BATs += 4; |
| 668 | #endif |
| 669 | } |
| 670 | |
| 671 | /* BATs 4-7 */ |
| 672 | void register_high_BATs(CPUPPCState *env) |
| 673 | { |
| 674 | #if !defined(CONFIG_USER_ONLY) |
| 675 | spr_register(env, SPR_IBAT4U, "IBAT4U", |
| 676 | SPR_NOACCESS, SPR_NOACCESS, |
| 677 | &spr_read_ibat_h, &spr_write_ibatu_h, |
| 678 | 0x00000000); |
| 679 | spr_register(env, SPR_IBAT4L, "IBAT4L", |
| 680 | SPR_NOACCESS, SPR_NOACCESS, |
| 681 | &spr_read_ibat_h, &spr_write_ibatl_h, |
| 682 | 0x00000000); |
| 683 | spr_register(env, SPR_IBAT5U, "IBAT5U", |
| 684 | SPR_NOACCESS, SPR_NOACCESS, |
| 685 | &spr_read_ibat_h, &spr_write_ibatu_h, |
| 686 | 0x00000000); |
| 687 | spr_register(env, SPR_IBAT5L, "IBAT5L", |
| 688 | SPR_NOACCESS, SPR_NOACCESS, |
| 689 | &spr_read_ibat_h, &spr_write_ibatl_h, |
| 690 | 0x00000000); |
| 691 | spr_register(env, SPR_IBAT6U, "IBAT6U", |
| 692 | SPR_NOACCESS, SPR_NOACCESS, |
| 693 | &spr_read_ibat_h, &spr_write_ibatu_h, |
| 694 | 0x00000000); |
| 695 | spr_register(env, SPR_IBAT6L, "IBAT6L", |
| 696 | SPR_NOACCESS, SPR_NOACCESS, |
| 697 | &spr_read_ibat_h, &spr_write_ibatl_h, |
| 698 | 0x00000000); |
| 699 | spr_register(env, SPR_IBAT7U, "IBAT7U", |
| 700 | SPR_NOACCESS, SPR_NOACCESS, |
| 701 | &spr_read_ibat_h, &spr_write_ibatu_h, |
| 702 | 0x00000000); |
| 703 | spr_register(env, SPR_IBAT7L, "IBAT7L", |
| 704 | SPR_NOACCESS, SPR_NOACCESS, |
| 705 | &spr_read_ibat_h, &spr_write_ibatl_h, |
| 706 | 0x00000000); |
| 707 | spr_register(env, SPR_DBAT4U, "DBAT4U", |
| 708 | SPR_NOACCESS, SPR_NOACCESS, |
| 709 | &spr_read_dbat_h, &spr_write_dbatu_h, |
| 710 | 0x00000000); |
| 711 | spr_register(env, SPR_DBAT4L, "DBAT4L", |
| 712 | SPR_NOACCESS, SPR_NOACCESS, |
| 713 | &spr_read_dbat_h, &spr_write_dbatl_h, |
| 714 | 0x00000000); |
| 715 | spr_register(env, SPR_DBAT5U, "DBAT5U", |
| 716 | SPR_NOACCESS, SPR_NOACCESS, |
| 717 | &spr_read_dbat_h, &spr_write_dbatu_h, |
| 718 | 0x00000000); |
| 719 | spr_register(env, SPR_DBAT5L, "DBAT5L", |
| 720 | SPR_NOACCESS, SPR_NOACCESS, |
| 721 | &spr_read_dbat_h, &spr_write_dbatl_h, |
| 722 | 0x00000000); |
| 723 | spr_register(env, SPR_DBAT6U, "DBAT6U", |
| 724 | SPR_NOACCESS, SPR_NOACCESS, |
| 725 | &spr_read_dbat_h, &spr_write_dbatu_h, |
| 726 | 0x00000000); |
| 727 | spr_register(env, SPR_DBAT6L, "DBAT6L", |
| 728 | SPR_NOACCESS, SPR_NOACCESS, |
| 729 | &spr_read_dbat_h, &spr_write_dbatl_h, |
| 730 | 0x00000000); |
| 731 | spr_register(env, SPR_DBAT7U, "DBAT7U", |
| 732 | SPR_NOACCESS, SPR_NOACCESS, |
| 733 | &spr_read_dbat_h, &spr_write_dbatu_h, |
| 734 | 0x00000000); |
| 735 | spr_register(env, SPR_DBAT7L, "DBAT7L", |
| 736 | SPR_NOACCESS, SPR_NOACCESS, |
| 737 | &spr_read_dbat_h, &spr_write_dbatl_h, |
| 738 | 0x00000000); |
| 739 | env->nb_BATs += 4; |
| 740 | #endif |
| 741 | } |
| 742 | |
| 743 | /* Softare table search registers */ |
| 744 | void register_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways) |
| 745 | { |
| 746 | #if !defined(CONFIG_USER_ONLY) |
| 747 | env->nb_tlb = nb_tlbs; |
| 748 | env->nb_ways = nb_ways; |
| 749 | env->tlb_type = TLB_6XX; |
| 750 | spr_register(env, SPR_DMISS, "DMISS", |
| 751 | SPR_NOACCESS, SPR_NOACCESS, |
| 752 | &spr_read_generic, SPR_NOACCESS, |
| 753 | 0x00000000); |
| 754 | spr_register(env, SPR_DCMP, "DCMP", |
| 755 | SPR_NOACCESS, SPR_NOACCESS, |
| 756 | &spr_read_generic, SPR_NOACCESS, |
| 757 | 0x00000000); |
| 758 | spr_register(env, SPR_HASH1, "HASH1", |
| 759 | SPR_NOACCESS, SPR_NOACCESS, |
| 760 | &spr_read_generic, SPR_NOACCESS, |
| 761 | 0x00000000); |
| 762 | spr_register(env, SPR_HASH2, "HASH2", |
| 763 | SPR_NOACCESS, SPR_NOACCESS, |
| 764 | &spr_read_generic, SPR_NOACCESS, |
| 765 | 0x00000000); |
| 766 | spr_register(env, SPR_IMISS, "IMISS", |
| 767 | SPR_NOACCESS, SPR_NOACCESS, |
| 768 | &spr_read_generic, SPR_NOACCESS, |
| 769 | 0x00000000); |
| 770 | spr_register(env, SPR_ICMP, "ICMP", |
| 771 | SPR_NOACCESS, SPR_NOACCESS, |
| 772 | &spr_read_generic, SPR_NOACCESS, |
| 773 | 0x00000000); |
| 774 | spr_register(env, SPR_RPA, "RPA", |
| 775 | SPR_NOACCESS, SPR_NOACCESS, |
| 776 | &spr_read_generic, &spr_write_generic, |
| 777 | 0x00000000); |
| 778 | #endif |
| 779 | } |
| 780 | |
| 781 | void register_thrm_sprs(CPUPPCState *env) |
| 782 | { |
| 783 | /* Thermal management */ |
| 784 | spr_register(env, SPR_THRM1, "THRM1", |
| 785 | SPR_NOACCESS, SPR_NOACCESS, |
| 786 | &spr_read_thrm, &spr_write_generic, |
| 787 | 0x00000000); |
| 788 | |
| 789 | spr_register(env, SPR_THRM2, "THRM2", |
| 790 | SPR_NOACCESS, SPR_NOACCESS, |
| 791 | &spr_read_thrm, &spr_write_generic, |
| 792 | 0x00000000); |
| 793 | |
| 794 | spr_register(env, SPR_THRM3, "THRM3", |
| 795 | SPR_NOACCESS, SPR_NOACCESS, |
| 796 | &spr_read_thrm, &spr_write_generic, |
| 797 | 0x00000000); |
| 798 | } |
| 799 | |
| 800 | void register_usprgh_sprs(CPUPPCState *env) |
| 801 | { |
| 802 | spr_register(env, SPR_USPRG4, "USPRG4", |
| 803 | &spr_read_ureg, SPR_NOACCESS, |
| 804 | &spr_read_ureg, SPR_NOACCESS, |
| 805 | 0x00000000); |
| 806 | spr_register(env, SPR_USPRG5, "USPRG5", |
| 807 | &spr_read_ureg, SPR_NOACCESS, |
| 808 | &spr_read_ureg, SPR_NOACCESS, |
| 809 | 0x00000000); |
| 810 | spr_register(env, SPR_USPRG6, "USPRG6", |
| 811 | &spr_read_ureg, SPR_NOACCESS, |
| 812 | &spr_read_ureg, SPR_NOACCESS, |
| 813 | 0x00000000); |
| 814 | spr_register(env, SPR_USPRG7, "USPRG7", |
| 815 | &spr_read_ureg, SPR_NOACCESS, |
| 816 | &spr_read_ureg, SPR_NOACCESS, |
| 817 | 0x00000000); |
| 818 | } |