]> git.proxmox.com Git - qemu.git/blame - target-ppc/helper.c
ehci: add assert
[qemu.git] / target-ppc / helper.c
CommitLineData
79aceca5 1/*
3fc6c082 2 * PowerPC emulation helpers for qemu.
5fafdf24 3 *
76a66253 4 * Copyright (c) 2003-2007 Jocelyn Mayer
79aceca5
FB
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 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
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
79aceca5 18 */
fdabc366
FB
19#include <stdarg.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <inttypes.h>
fdabc366
FB
24
25#include "cpu.h"
0411a972 26#include "helper_regs.h"
ca10f867 27#include "qemu-common.h"
d76d1650 28#include "kvm.h"
e97c3636
DG
29#include "kvm_ppc.h"
30#include "cpus.h"
9a64fbe4
FB
31
32//#define DEBUG_MMU
33//#define DEBUG_BATS
6b542af7 34//#define DEBUG_SLB
76a66253 35//#define DEBUG_SOFTWARE_TLB
0411a972 36//#define DUMP_PAGE_TABLES
9a64fbe4 37//#define DEBUG_EXCEPTIONS
fdabc366 38//#define FLUSH_ALL_TLBS
9a64fbe4 39
d12d51d5 40#ifdef DEBUG_MMU
93fcfe39
AL
41# define LOG_MMU(...) qemu_log(__VA_ARGS__)
42# define LOG_MMU_STATE(env) log_cpu_state((env), 0)
d12d51d5
AL
43#else
44# define LOG_MMU(...) do { } while (0)
45# define LOG_MMU_STATE(...) do { } while (0)
46#endif
47
48
49#ifdef DEBUG_SOFTWARE_TLB
93fcfe39 50# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
d12d51d5
AL
51#else
52# define LOG_SWTLB(...) do { } while (0)
53#endif
54
55#ifdef DEBUG_BATS
93fcfe39 56# define LOG_BATS(...) qemu_log(__VA_ARGS__)
d12d51d5
AL
57#else
58# define LOG_BATS(...) do { } while (0)
59#endif
60
61#ifdef DEBUG_SLB
93fcfe39 62# define LOG_SLB(...) qemu_log(__VA_ARGS__)
d12d51d5
AL
63#else
64# define LOG_SLB(...) do { } while (0)
65#endif
66
67#ifdef DEBUG_EXCEPTIONS
93fcfe39 68# define LOG_EXCP(...) qemu_log(__VA_ARGS__)
d12d51d5
AL
69#else
70# define LOG_EXCP(...) do { } while (0)
71#endif
72
d569956e
DG
73/*****************************************************************************/
74/* PowerPC Hypercall emulation */
75
76void (*cpu_ppc_hypercall)(CPUState *);
d12d51d5 77
64adab3f 78/*****************************************************************************/
3fc6c082 79/* PowerPC MMU emulation */
a541f297 80
d9bce9d9 81#if defined(CONFIG_USER_ONLY)
e96efcfc 82int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
97b348e7 83 int mmu_idx)
24741ef3
FB
84{
85 int exception, error_code;
d9bce9d9 86
24741ef3 87 if (rw == 2) {
e1833e1f 88 exception = POWERPC_EXCP_ISI;
8f793433 89 error_code = 0x40000000;
24741ef3 90 } else {
e1833e1f 91 exception = POWERPC_EXCP_DSI;
8f793433 92 error_code = 0x40000000;
24741ef3
FB
93 if (rw)
94 error_code |= 0x02000000;
95 env->spr[SPR_DAR] = address;
96 env->spr[SPR_DSISR] = error_code;
97 }
98 env->exception_index = exception;
99 env->error_code = error_code;
76a66253 100
24741ef3
FB
101 return 1;
102}
76a66253 103
24741ef3 104#else
76a66253 105/* Common routines used by software and hardware TLBs emulation */
636aa200 106static inline int pte_is_valid(target_ulong pte0)
76a66253
JM
107{
108 return pte0 & 0x80000000 ? 1 : 0;
109}
110
636aa200 111static inline void pte_invalidate(target_ulong *pte0)
76a66253
JM
112{
113 *pte0 &= ~0x80000000;
114}
115
caa4039c 116#if defined(TARGET_PPC64)
636aa200 117static inline int pte64_is_valid(target_ulong pte0)
caa4039c
JM
118{
119 return pte0 & 0x0000000000000001ULL ? 1 : 0;
120}
121
636aa200 122static inline void pte64_invalidate(target_ulong *pte0)
caa4039c
JM
123{
124 *pte0 &= ~0x0000000000000001ULL;
125}
126#endif
127
76a66253
JM
128#define PTE_PTEM_MASK 0x7FFFFFBF
129#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
caa4039c
JM
130#if defined(TARGET_PPC64)
131#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
132#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
133#endif
76a66253 134
636aa200 135static inline int pp_check(int key, int pp, int nx)
b227a8e9
JM
136{
137 int access;
138
139 /* Compute access rights */
140 /* When pp is 3/7, the result is undefined. Set it to noaccess */
141 access = 0;
142 if (key == 0) {
143 switch (pp) {
144 case 0x0:
145 case 0x1:
146 case 0x2:
147 access |= PAGE_WRITE;
148 /* No break here */
149 case 0x3:
150 case 0x6:
151 access |= PAGE_READ;
152 break;
153 }
154 } else {
155 switch (pp) {
156 case 0x0:
157 case 0x6:
158 access = 0;
159 break;
160 case 0x1:
161 case 0x3:
162 access = PAGE_READ;
163 break;
164 case 0x2:
165 access = PAGE_READ | PAGE_WRITE;
166 break;
167 }
168 }
169 if (nx == 0)
170 access |= PAGE_EXEC;
171
172 return access;
173}
174
636aa200 175static inline int check_prot(int prot, int rw, int access_type)
b227a8e9
JM
176{
177 int ret;
178
179 if (access_type == ACCESS_CODE) {
180 if (prot & PAGE_EXEC)
181 ret = 0;
182 else
183 ret = -2;
184 } else if (rw) {
185 if (prot & PAGE_WRITE)
186 ret = 0;
187 else
188 ret = -2;
189 } else {
190 if (prot & PAGE_READ)
191 ret = 0;
192 else
193 ret = -2;
194 }
195
196 return ret;
197}
198
c227f099 199static inline int _pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
636aa200 200 target_ulong pte1, int h, int rw, int type)
76a66253 201{
caa4039c 202 target_ulong ptem, mmask;
b227a8e9 203 int access, ret, pteh, ptev, pp;
76a66253 204
76a66253
JM
205 ret = -1;
206 /* Check validity and table match */
caa4039c
JM
207#if defined(TARGET_PPC64)
208 if (is_64b) {
209 ptev = pte64_is_valid(pte0);
210 pteh = (pte0 >> 1) & 1;
211 } else
212#endif
213 {
214 ptev = pte_is_valid(pte0);
215 pteh = (pte0 >> 6) & 1;
216 }
217 if (ptev && h == pteh) {
76a66253 218 /* Check vsid & api */
caa4039c
JM
219#if defined(TARGET_PPC64)
220 if (is_64b) {
221 ptem = pte0 & PTE64_PTEM_MASK;
222 mmask = PTE64_CHECK_MASK;
b227a8e9 223 pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
29c8ca6f 224 ctx->nx = (pte1 >> 2) & 1; /* No execute bit */
b227a8e9 225 ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
caa4039c
JM
226 } else
227#endif
228 {
229 ptem = pte0 & PTE_PTEM_MASK;
230 mmask = PTE_CHECK_MASK;
b227a8e9 231 pp = pte1 & 0x00000003;
caa4039c
JM
232 }
233 if (ptem == ctx->ptem) {
c227f099 234 if (ctx->raddr != (target_phys_addr_t)-1ULL) {
76a66253 235 /* all matches should have equal RPN, WIMG & PP */
caa4039c 236 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
93fcfe39 237 qemu_log("Bad RPN/WIMG/PP\n");
76a66253
JM
238 return -3;
239 }
240 }
241 /* Compute access rights */
b227a8e9 242 access = pp_check(ctx->key, pp, ctx->nx);
76a66253
JM
243 /* Keep the matching PTE informations */
244 ctx->raddr = pte1;
245 ctx->prot = access;
b227a8e9
JM
246 ret = check_prot(ctx->prot, rw, type);
247 if (ret == 0) {
76a66253 248 /* Access granted */
d12d51d5 249 LOG_MMU("PTE access granted !\n");
76a66253
JM
250 } else {
251 /* Access right violation */
d12d51d5 252 LOG_MMU("PTE access rejected\n");
76a66253
JM
253 }
254 }
255 }
256
257 return ret;
258}
259
c227f099 260static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
636aa200 261 target_ulong pte1, int h, int rw, int type)
caa4039c 262{
b227a8e9 263 return _pte_check(ctx, 0, pte0, pte1, h, rw, type);
caa4039c
JM
264}
265
266#if defined(TARGET_PPC64)
c227f099 267static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
636aa200 268 target_ulong pte1, int h, int rw, int type)
caa4039c 269{
b227a8e9 270 return _pte_check(ctx, 1, pte0, pte1, h, rw, type);
caa4039c
JM
271}
272#endif
273
c227f099 274static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
636aa200 275 int ret, int rw)
76a66253
JM
276{
277 int store = 0;
278
279 /* Update page flags */
280 if (!(*pte1p & 0x00000100)) {
281 /* Update accessed flag */
282 *pte1p |= 0x00000100;
283 store = 1;
284 }
285 if (!(*pte1p & 0x00000080)) {
286 if (rw == 1 && ret == 0) {
287 /* Update changed flag */
288 *pte1p |= 0x00000080;
289 store = 1;
290 } else {
291 /* Force page fault for first write access */
292 ctx->prot &= ~PAGE_WRITE;
293 }
294 }
295
296 return store;
297}
298
299/* Software driven TLB helpers */
636aa200
BS
300static inline int ppc6xx_tlb_getnum(CPUState *env, target_ulong eaddr, int way,
301 int is_code)
76a66253
JM
302{
303 int nr;
304
305 /* Select TLB num in a way from address */
306 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
307 /* Select TLB way */
308 nr += env->tlb_per_way * way;
309 /* 6xx have separate TLBs for instructions and data */
310 if (is_code && env->id_tlbs == 1)
311 nr += env->nb_tlb;
312
313 return nr;
314}
315
636aa200 316static inline void ppc6xx_tlb_invalidate_all(CPUState *env)
76a66253 317{
c227f099 318 ppc6xx_tlb_t *tlb;
76a66253
JM
319 int nr, max;
320
d12d51d5 321 //LOG_SWTLB("Invalidate all TLBs\n");
76a66253
JM
322 /* Invalidate all defined software TLB */
323 max = env->nb_tlb;
324 if (env->id_tlbs == 1)
325 max *= 2;
326 for (nr = 0; nr < max; nr++) {
1c53accc 327 tlb = &env->tlb.tlb6[nr];
76a66253
JM
328 pte_invalidate(&tlb->pte0);
329 }
76a66253 330 tlb_flush(env, 1);
76a66253
JM
331}
332
636aa200
BS
333static inline void __ppc6xx_tlb_invalidate_virt(CPUState *env,
334 target_ulong eaddr,
335 int is_code, int match_epn)
76a66253 336{
4a057712 337#if !defined(FLUSH_ALL_TLBS)
c227f099 338 ppc6xx_tlb_t *tlb;
76a66253
JM
339 int way, nr;
340
76a66253
JM
341 /* Invalidate ITLB + DTLB, all ways */
342 for (way = 0; way < env->nb_ways; way++) {
343 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
1c53accc 344 tlb = &env->tlb.tlb6[nr];
76a66253 345 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
90e189ec
BS
346 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
347 env->nb_tlb, eaddr);
76a66253
JM
348 pte_invalidate(&tlb->pte0);
349 tlb_flush_page(env, tlb->EPN);
350 }
351 }
352#else
353 /* XXX: PowerPC specification say this is valid as well */
354 ppc6xx_tlb_invalidate_all(env);
355#endif
356}
357
636aa200
BS
358static inline void ppc6xx_tlb_invalidate_virt(CPUState *env,
359 target_ulong eaddr, int is_code)
76a66253
JM
360{
361 __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
362}
363
364void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
365 target_ulong pte0, target_ulong pte1)
366{
c227f099 367 ppc6xx_tlb_t *tlb;
76a66253
JM
368 int nr;
369
370 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
1c53accc 371 tlb = &env->tlb.tlb6[nr];
90e189ec
BS
372 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
373 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
76a66253
JM
374 /* Invalidate any pending reference in Qemu for this virtual address */
375 __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
376 tlb->pte0 = pte0;
377 tlb->pte1 = pte1;
378 tlb->EPN = EPN;
76a66253
JM
379 /* Store last way for LRU mechanism */
380 env->last_way = way;
381}
382
c227f099 383static inline int ppc6xx_tlb_check(CPUState *env, mmu_ctx_t *ctx,
636aa200 384 target_ulong eaddr, int rw, int access_type)
76a66253 385{
c227f099 386 ppc6xx_tlb_t *tlb;
76a66253
JM
387 int nr, best, way;
388 int ret;
d9bce9d9 389
76a66253
JM
390 best = -1;
391 ret = -1; /* No TLB found */
392 for (way = 0; way < env->nb_ways; way++) {
393 nr = ppc6xx_tlb_getnum(env, eaddr, way,
394 access_type == ACCESS_CODE ? 1 : 0);
1c53accc 395 tlb = &env->tlb.tlb6[nr];
76a66253
JM
396 /* This test "emulates" the PTE index match for hardware TLBs */
397 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
90e189ec
BS
398 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
399 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
400 pte_is_valid(tlb->pte0) ? "valid" : "inval",
401 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
76a66253
JM
402 continue;
403 }
90e189ec
BS
404 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
405 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
406 pte_is_valid(tlb->pte0) ? "valid" : "inval",
407 tlb->EPN, eaddr, tlb->pte1,
408 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
b227a8e9 409 switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
76a66253
JM
410 case -3:
411 /* TLB inconsistency */
412 return -1;
413 case -2:
414 /* Access violation */
415 ret = -2;
416 best = nr;
417 break;
418 case -1:
419 default:
420 /* No match */
421 break;
422 case 0:
423 /* access granted */
424 /* XXX: we should go on looping to check all TLBs consistency
425 * but we can speed-up the whole thing as the
426 * result would be undefined if TLBs are not consistent.
427 */
428 ret = 0;
429 best = nr;
430 goto done;
431 }
432 }
433 if (best != -1) {
434 done:
90e189ec
BS
435 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
436 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
76a66253 437 /* Update page flags */
1c53accc 438 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
76a66253
JM
439 }
440
441 return ret;
442}
443
9a64fbe4 444/* Perform BAT hit & translation */
636aa200
BS
445static inline void bat_size_prot(CPUState *env, target_ulong *blp, int *validp,
446 int *protp, target_ulong *BATu,
447 target_ulong *BATl)
faadf50e
JM
448{
449 target_ulong bl;
450 int pp, valid, prot;
451
452 bl = (*BATu & 0x00001FFC) << 15;
453 valid = 0;
454 prot = 0;
455 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
456 ((msr_pr != 0) && (*BATu & 0x00000001))) {
457 valid = 1;
458 pp = *BATl & 0x00000003;
459 if (pp != 0) {
460 prot = PAGE_READ | PAGE_EXEC;
461 if (pp == 0x2)
462 prot |= PAGE_WRITE;
463 }
464 }
465 *blp = bl;
466 *validp = valid;
467 *protp = prot;
468}
469
636aa200
BS
470static inline void bat_601_size_prot(CPUState *env, target_ulong *blp,
471 int *validp, int *protp,
472 target_ulong *BATu, target_ulong *BATl)
faadf50e
JM
473{
474 target_ulong bl;
475 int key, pp, valid, prot;
476
477 bl = (*BATl & 0x0000003F) << 17;
90e189ec
BS
478 LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
479 (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
faadf50e
JM
480 prot = 0;
481 valid = (*BATl >> 6) & 1;
482 if (valid) {
483 pp = *BATu & 0x00000003;
484 if (msr_pr == 0)
485 key = (*BATu >> 3) & 1;
486 else
487 key = (*BATu >> 2) & 1;
488 prot = pp_check(key, pp, 0);
489 }
490 *blp = bl;
491 *validp = valid;
492 *protp = prot;
493}
494
c227f099 495static inline int get_bat(CPUState *env, mmu_ctx_t *ctx, target_ulong virtual,
636aa200 496 int rw, int type)
9a64fbe4 497{
76a66253 498 target_ulong *BATlt, *BATut, *BATu, *BATl;
05f92404 499 target_ulong BEPIl, BEPIu, bl;
faadf50e 500 int i, valid, prot;
9a64fbe4
FB
501 int ret = -1;
502
90e189ec
BS
503 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
504 type == ACCESS_CODE ? 'I' : 'D', virtual);
9a64fbe4
FB
505 switch (type) {
506 case ACCESS_CODE:
507 BATlt = env->IBAT[1];
508 BATut = env->IBAT[0];
509 break;
510 default:
511 BATlt = env->DBAT[1];
512 BATut = env->DBAT[0];
513 break;
514 }
faadf50e 515 for (i = 0; i < env->nb_BATs; i++) {
9a64fbe4
FB
516 BATu = &BATut[i];
517 BATl = &BATlt[i];
518 BEPIu = *BATu & 0xF0000000;
519 BEPIl = *BATu & 0x0FFE0000;
faadf50e
JM
520 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
521 bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
522 } else {
523 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
524 }
90e189ec
BS
525 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
526 " BATl " TARGET_FMT_lx "\n", __func__,
527 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
9a64fbe4
FB
528 if ((virtual & 0xF0000000) == BEPIu &&
529 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
530 /* BAT matches */
faadf50e 531 if (valid != 0) {
9a64fbe4 532 /* Get physical address */
76a66253 533 ctx->raddr = (*BATl & 0xF0000000) |
9a64fbe4 534 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
a541f297 535 (virtual & 0x0001F000);
b227a8e9 536 /* Compute access rights */
faadf50e 537 ctx->prot = prot;
b227a8e9 538 ret = check_prot(ctx->prot, rw, type);
d12d51d5 539 if (ret == 0)
90e189ec 540 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
d12d51d5
AL
541 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
542 ctx->prot & PAGE_WRITE ? 'W' : '-');
9a64fbe4
FB
543 break;
544 }
545 }
546 }
547 if (ret < 0) {
d12d51d5 548#if defined(DEBUG_BATS)
0bf9e31a 549 if (qemu_log_enabled()) {
90e189ec 550 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
4a057712
JM
551 for (i = 0; i < 4; i++) {
552 BATu = &BATut[i];
553 BATl = &BATlt[i];
554 BEPIu = *BATu & 0xF0000000;
555 BEPIl = *BATu & 0x0FFE0000;
556 bl = (*BATu & 0x00001FFC) << 15;
90e189ec 557 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
b2bedb21 558 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
90e189ec 559 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
0bf9e31a
BS
560 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
561 *BATu, *BATl, BEPIu, BEPIl, bl);
4a057712 562 }
9a64fbe4
FB
563 }
564#endif
9a64fbe4
FB
565 }
566 /* No hit */
567 return ret;
568}
569
fda6a0ec
DG
570static inline target_phys_addr_t get_pteg_offset(CPUState *env,
571 target_phys_addr_t hash,
572 int pte_size)
573{
574 return (hash * pte_size * 8) & env->htab_mask;
575}
576
9a64fbe4 577/* PTE table lookup */
fda6a0ec
DG
578static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h,
579 int rw, int type, int target_page_bits)
9a64fbe4 580{
fda6a0ec
DG
581 target_phys_addr_t pteg_off;
582 target_ulong pte0, pte1;
76a66253 583 int i, good = -1;
caa4039c 584 int ret, r;
9a64fbe4 585
76a66253 586 ret = -1; /* No entry found */
fda6a0ec
DG
587 pteg_off = get_pteg_offset(env, ctx->hash[h],
588 is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32);
9a64fbe4 589 for (i = 0; i < 8; i++) {
caa4039c
JM
590#if defined(TARGET_PPC64)
591 if (is_64b) {
f43e3525
DG
592 if (env->external_htab) {
593 pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
594 pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
595 } else {
596 pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
597 pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
598 }
5b5aba4f
BS
599
600 /* We have a TLB that saves 4K pages, so let's
601 * split a huge page to 4k chunks */
602 if (target_page_bits != TARGET_PAGE_BITS)
603 pte1 |= (ctx->eaddr & (( 1 << target_page_bits ) - 1))
604 & TARGET_PAGE_MASK;
605
b227a8e9 606 r = pte64_check(ctx, pte0, pte1, h, rw, type);
90e189ec
BS
607 LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
608 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
decb4714 609 pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
90e189ec 610 (int)((pte0 >> 1) & 1), ctx->ptem);
caa4039c
JM
611 } else
612#endif
613 {
f43e3525
DG
614 if (env->external_htab) {
615 pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
616 pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
617 } else {
618 pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
619 pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
620 }
b227a8e9 621 r = pte32_check(ctx, pte0, pte1, h, rw, type);
90e189ec
BS
622 LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
623 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
decb4714 624 pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
90e189ec 625 (int)((pte0 >> 6) & 1), ctx->ptem);
12de9a39 626 }
caa4039c 627 switch (r) {
76a66253
JM
628 case -3:
629 /* PTE inconsistency */
630 return -1;
631 case -2:
632 /* Access violation */
633 ret = -2;
634 good = i;
635 break;
636 case -1:
637 default:
638 /* No PTE match */
639 break;
640 case 0:
641 /* access granted */
642 /* XXX: we should go on looping to check all PTEs consistency
643 * but if we can speed-up the whole thing as the
644 * result would be undefined if PTEs are not consistent.
645 */
646 ret = 0;
647 good = i;
648 goto done;
9a64fbe4
FB
649 }
650 }
651 if (good != -1) {
76a66253 652 done:
90e189ec
BS
653 LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n",
654 ctx->raddr, ctx->prot, ret);
9a64fbe4 655 /* Update page flags */
76a66253 656 pte1 = ctx->raddr;
caa4039c
JM
657 if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
658#if defined(TARGET_PPC64)
659 if (is_64b) {
f43e3525
DG
660 if (env->external_htab) {
661 stq_p(env->external_htab + pteg_off + (good * 16) + 8,
662 pte1);
663 } else {
664 stq_phys_notdirty(env->htab_base + pteg_off +
665 (good * 16) + 8, pte1);
666 }
caa4039c
JM
667 } else
668#endif
669 {
f43e3525
DG
670 if (env->external_htab) {
671 stl_p(env->external_htab + pteg_off + (good * 8) + 4,
672 pte1);
673 } else {
674 stl_phys_notdirty(env->htab_base + pteg_off +
675 (good * 8) + 4, pte1);
676 }
caa4039c
JM
677 }
678 }
9a64fbe4
FB
679 }
680
681 return ret;
79aceca5
FB
682}
683
c227f099 684static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
636aa200 685 int type, int target_page_bits)
caa4039c
JM
686{
687#if defined(TARGET_PPC64)
add78955 688 if (env->mmu_model & POWERPC_MMU_64)
256cebe5 689 return _find_pte(env, ctx, 1, h, rw, type, target_page_bits);
caa4039c
JM
690#endif
691
256cebe5 692 return _find_pte(env, ctx, 0, h, rw, type, target_page_bits);
caa4039c
JM
693}
694
caa4039c 695#if defined(TARGET_PPC64)
8500e3a9 696static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
caa4039c 697{
cdaee006 698 uint64_t esid_256M, esid_1T;
81762d6d 699 int n;
caa4039c 700
90e189ec 701 LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
81762d6d 702
cdaee006
DG
703 esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
704 esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
81762d6d 705
eacc3249 706 for (n = 0; n < env->slb_nr; n++) {
81762d6d
DG
707 ppc_slb_t *slb = &env->slb[n];
708
709 LOG_SLB("%s: slot %d %016" PRIx64 " %016"
710 PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
cdaee006
DG
711 /* We check for 1T matches on all MMUs here - if the MMU
712 * doesn't have 1T segment support, we will have prevented 1T
713 * entries from being inserted in the slbmte code. */
714 if (((slb->esid == esid_256M) &&
715 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
716 || ((slb->esid == esid_1T) &&
717 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
8500e3a9 718 return slb;
caa4039c 719 }
caa4039c
JM
720 }
721
8500e3a9 722 return NULL;
79aceca5 723}
12de9a39 724
eacc3249
JM
725void ppc_slb_invalidate_all (CPUPPCState *env)
726{
eacc3249
JM
727 int n, do_invalidate;
728
729 do_invalidate = 0;
2c1ee068
JM
730 /* XXX: Warning: slbia never invalidates the first segment */
731 for (n = 1; n < env->slb_nr; n++) {
81762d6d 732 ppc_slb_t *slb = &env->slb[n];
8eee0af9 733
81762d6d
DG
734 if (slb->esid & SLB_ESID_V) {
735 slb->esid &= ~SLB_ESID_V;
eacc3249
JM
736 /* XXX: given the fact that segment size is 256 MB or 1TB,
737 * and we still don't have a tlb_flush_mask(env, n, mask)
738 * in Qemu, we just invalidate all TLBs
739 */
740 do_invalidate = 1;
741 }
eacc3249
JM
742 }
743 if (do_invalidate)
744 tlb_flush(env, 1);
745}
746
747void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
748{
81762d6d 749 ppc_slb_t *slb;
eacc3249 750
8500e3a9
DG
751 slb = slb_lookup(env, T0);
752 if (!slb) {
81762d6d 753 return;
eacc3249 754 }
eacc3249 755
81762d6d
DG
756 if (slb->esid & SLB_ESID_V) {
757 slb->esid &= ~SLB_ESID_V;
12de9a39 758
81762d6d
DG
759 /* XXX: given the fact that segment size is 256 MB or 1TB,
760 * and we still don't have a tlb_flush_mask(env, n, mask)
761 * in Qemu, we just invalidate all TLBs
762 */
763 tlb_flush(env, 1);
764 }
12de9a39
JM
765}
766
81762d6d 767int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
12de9a39 768{
81762d6d 769 int slot = rb & 0xfff;
81762d6d 770 ppc_slb_t *slb = &env->slb[slot];
f6b868fc 771
cdaee006
DG
772 if (rb & (0x1000 - env->slb_nr)) {
773 return -1; /* Reserved bits set or slot too high */
774 }
775 if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
776 return -1; /* Bad segment size */
777 }
778 if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
779 return -1; /* 1T segment on MMU that doesn't support it */
81762d6d 780 }
f6b868fc 781
cdaee006
DG
782 /* Mask out the slot number as we store the entry */
783 slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
81762d6d 784 slb->vsid = rs;
f6b868fc 785
90e189ec 786 LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
81762d6d
DG
787 " %016" PRIx64 "\n", __func__, slot, rb, rs,
788 slb->esid, slb->vsid);
f6b868fc 789
81762d6d 790 return 0;
12de9a39 791}
efdef95f
DG
792
793int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
794{
795 int slot = rb & 0xfff;
796 ppc_slb_t *slb = &env->slb[slot];
797
798 if (slot >= env->slb_nr) {
799 return -1;
800 }
801
802 *rt = slb->esid;
803 return 0;
804}
805
806int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
807{
808 int slot = rb & 0xfff;
809 ppc_slb_t *slb = &env->slb[slot];
810
811 if (slot >= env->slb_nr) {
812 return -1;
813 }
814
815 *rt = slb->vsid;
816 return 0;
817}
caa4039c 818#endif /* defined(TARGET_PPC64) */
79aceca5 819
9a64fbe4 820/* Perform segment based translation */
c227f099 821static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
636aa200 822 target_ulong eaddr, int rw, int type)
79aceca5 823{
bb593904 824 target_phys_addr_t hash;
256cebe5 825 target_ulong vsid;
fda6a0ec 826 int ds, pr, target_page_bits;
caa4039c
JM
827 int ret, ret2;
828
0411a972 829 pr = msr_pr;
256cebe5 830 ctx->eaddr = eaddr;
caa4039c 831#if defined(TARGET_PPC64)
add78955 832 if (env->mmu_model & POWERPC_MMU_64) {
8500e3a9 833 ppc_slb_t *slb;
256cebe5 834 target_ulong pageaddr;
cdaee006 835 int segment_bits;
81762d6d 836
d12d51d5 837 LOG_MMU("Check SLBs\n");
8500e3a9
DG
838 slb = slb_lookup(env, eaddr);
839 if (!slb) {
840 return -5;
841 }
842
cdaee006
DG
843 if (slb->vsid & SLB_VSID_B) {
844 vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
845 segment_bits = 40;
846 } else {
847 vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
848 segment_bits = 28;
849 }
850
8500e3a9
DG
851 target_page_bits = (slb->vsid & SLB_VSID_L)
852 ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
853 ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
854 : (slb->vsid & SLB_VSID_KS));
caa4039c 855 ds = 0;
8500e3a9 856 ctx->nx = !!(slb->vsid & SLB_VSID_N);
256cebe5 857
cdaee006
DG
858 pageaddr = eaddr & ((1ULL << segment_bits)
859 - (1ULL << target_page_bits));
860 if (slb->vsid & SLB_VSID_B) {
861 hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
862 } else {
863 hash = vsid ^ (pageaddr >> target_page_bits);
864 }
256cebe5 865 /* Only 5 bits of the page index are used in the AVPN */
cdaee006
DG
866 ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
867 ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
caa4039c
JM
868 } else
869#endif /* defined(TARGET_PPC64) */
870 {
256cebe5
DG
871 target_ulong sr, pgidx;
872
caa4039c 873 sr = env->sr[eaddr >> 28];
0411a972
JM
874 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
875 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
caa4039c 876 ds = sr & 0x80000000 ? 1 : 0;
b227a8e9 877 ctx->nx = sr & 0x10000000 ? 1 : 0;
caa4039c 878 vsid = sr & 0x00FFFFFF;
5b5aba4f 879 target_page_bits = TARGET_PAGE_BITS;
90e189ec
BS
880 LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
881 TARGET_FMT_lx " lr=" TARGET_FMT_lx
882 " ir=%d dr=%d pr=%d %d t=%d\n",
883 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
884 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
256cebe5
DG
885 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
886 hash = vsid ^ pgidx;
887 ctx->ptem = (vsid << 7) | (pgidx >> 10);
caa4039c 888 }
90e189ec
BS
889 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
890 ctx->key, ds, ctx->nx, vsid);
caa4039c
JM
891 ret = -1;
892 if (!ds) {
9a64fbe4 893 /* Check if instruction fetch is allowed, if needed */
b227a8e9 894 if (type != ACCESS_CODE || ctx->nx == 0) {
9a64fbe4 895 /* Page address translation */
bb593904
DG
896 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
897 " hash " TARGET_FMT_plx "\n",
898 env->htab_base, env->htab_mask, hash);
fda6a0ec
DG
899 ctx->hash[0] = hash;
900 ctx->hash[1] = ~hash;
901
76a66253 902 /* Initialize real address with an invalid value */
c227f099 903 ctx->raddr = (target_phys_addr_t)-1ULL;
7dbe11ac
JM
904 if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
905 env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
76a66253
JM
906 /* Software TLB search */
907 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
76a66253 908 } else {
bb593904 909 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
256cebe5 910 " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
fda6a0ec 911 " hash=" TARGET_FMT_plx "\n",
256cebe5 912 env->htab_base, env->htab_mask, vsid, ctx->ptem,
fda6a0ec 913 ctx->hash[0]);
76a66253 914 /* Primary table lookup */
5b5aba4f 915 ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
76a66253
JM
916 if (ret < 0) {
917 /* Secondary table lookup */
d12d51d5 918 if (eaddr != 0xEFFFFFFF)
bb593904
DG
919 LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
920 " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
decb4714 921 " hash=" TARGET_FMT_plx "\n", env->htab_base,
256cebe5 922 env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
5b5aba4f
BS
923 ret2 = find_pte(env, ctx, 1, rw, type,
924 target_page_bits);
76a66253
JM
925 if (ret2 != -1)
926 ret = ret2;
927 }
9a64fbe4 928 }
0411a972 929#if defined (DUMP_PAGE_TABLES)
93fcfe39 930 if (qemu_log_enabled()) {
c227f099 931 target_phys_addr_t curaddr;
b33c17e1 932 uint32_t a0, a1, a2, a3;
90e189ec
BS
933 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
934 "\n", sdr, mask + 0x80);
b33c17e1
JM
935 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
936 curaddr += 16) {
937 a0 = ldl_phys(curaddr);
938 a1 = ldl_phys(curaddr + 4);
939 a2 = ldl_phys(curaddr + 8);
940 a3 = ldl_phys(curaddr + 12);
941 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
90e189ec
BS
942 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
943 curaddr, a0, a1, a2, a3);
12de9a39 944 }
b33c17e1
JM
945 }
946 }
12de9a39 947#endif
9a64fbe4 948 } else {
d12d51d5 949 LOG_MMU("No access allowed\n");
76a66253 950 ret = -3;
9a64fbe4
FB
951 }
952 } else {
826e7b82 953 target_ulong sr;
d12d51d5 954 LOG_MMU("direct store...\n");
9a64fbe4 955 /* Direct-store segment : absolutely *BUGGY* for now */
826e7b82
HP
956
957 /* Direct-store implies a 32-bit MMU.
958 * Check the Segment Register's bus unit ID (BUID).
959 */
960 sr = env->sr[eaddr >> 28];
961 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
962 /* Memory-forced I/O controller interface access */
963 /* If T=1 and BUID=x'07F', the 601 performs a memory access
964 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
965 */
966 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
967 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
968 return 0;
969 }
970
9a64fbe4
FB
971 switch (type) {
972 case ACCESS_INT:
973 /* Integer load/store : only access allowed */
974 break;
975 case ACCESS_CODE:
976 /* No code fetch is allowed in direct-store areas */
977 return -4;
978 case ACCESS_FLOAT:
979 /* Floating point load/store */
980 return -4;
981 case ACCESS_RES:
982 /* lwarx, ldarx or srwcx. */
983 return -4;
984 case ACCESS_CACHE:
985 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
986 /* Should make the instruction do no-op.
987 * As it already do no-op, it's quite easy :-)
988 */
76a66253 989 ctx->raddr = eaddr;
9a64fbe4
FB
990 return 0;
991 case ACCESS_EXT:
992 /* eciwx or ecowx */
993 return -4;
994 default:
93fcfe39 995 qemu_log("ERROR: instruction should not need "
9a64fbe4 996 "address translation\n");
9a64fbe4
FB
997 return -4;
998 }
76a66253
JM
999 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
1000 ctx->raddr = eaddr;
9a64fbe4
FB
1001 ret = 2;
1002 } else {
1003 ret = -2;
1004 }
79aceca5 1005 }
9a64fbe4
FB
1006
1007 return ret;
79aceca5
FB
1008}
1009
c294fc58 1010/* Generic TLB check function for embedded PowerPC implementations */
01662f3e
AG
1011int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
1012 target_phys_addr_t *raddrp,
1013 target_ulong address, uint32_t pid, int ext,
1014 int i)
c294fc58
JM
1015{
1016 target_ulong mask;
1017
1018 /* Check valid flag */
1019 if (!(tlb->prot & PAGE_VALID)) {
c294fc58
JM
1020 return -1;
1021 }
1022 mask = ~(tlb->size - 1);
90e189ec 1023 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
01662f3e
AG
1024 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
1025 mask, (uint32_t)tlb->PID, tlb->prot);
c294fc58 1026 /* Check PID */
36081602 1027 if (tlb->PID != 0 && tlb->PID != pid)
c294fc58
JM
1028 return -1;
1029 /* Check effective address */
1030 if ((address & mask) != tlb->EPN)
1031 return -1;
1032 *raddrp = (tlb->RPN & mask) | (address & ~mask);
9706285b 1033#if (TARGET_PHYS_ADDR_BITS >= 36)
36081602
JM
1034 if (ext) {
1035 /* Extend the physical address to 36 bits */
c227f099 1036 *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
36081602 1037 }
9706285b 1038#endif
c294fc58
JM
1039
1040 return 0;
1041}
1042
1043/* Generic TLB search function for PowerPC embedded implementations */
36081602 1044int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
c294fc58 1045{
c227f099
AL
1046 ppcemb_tlb_t *tlb;
1047 target_phys_addr_t raddr;
c294fc58
JM
1048 int i, ret;
1049
1050 /* Default return value is no match */
1051 ret = -1;
a750fc0b 1052 for (i = 0; i < env->nb_tlb; i++) {
1c53accc 1053 tlb = &env->tlb.tlbe[i];
36081602 1054 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
c294fc58
JM
1055 ret = i;
1056 break;
1057 }
1058 }
1059
1060 return ret;
1061}
1062
daf4f96e 1063/* Helpers specific to PowerPC 40x implementations */
636aa200 1064static inline void ppc4xx_tlb_invalidate_all(CPUState *env)
a750fc0b 1065{
c227f099 1066 ppcemb_tlb_t *tlb;
a750fc0b
JM
1067 int i;
1068
1069 for (i = 0; i < env->nb_tlb; i++) {
1c53accc 1070 tlb = &env->tlb.tlbe[i];
daf4f96e 1071 tlb->prot &= ~PAGE_VALID;
a750fc0b 1072 }
daf4f96e 1073 tlb_flush(env, 1);
a750fc0b
JM
1074}
1075
636aa200
BS
1076static inline void ppc4xx_tlb_invalidate_virt(CPUState *env,
1077 target_ulong eaddr, uint32_t pid)
0a032cbe 1078{
daf4f96e 1079#if !defined(FLUSH_ALL_TLBS)
c227f099
AL
1080 ppcemb_tlb_t *tlb;
1081 target_phys_addr_t raddr;
daf4f96e 1082 target_ulong page, end;
0a032cbe
JM
1083 int i;
1084
1085 for (i = 0; i < env->nb_tlb; i++) {
1c53accc 1086 tlb = &env->tlb.tlbe[i];
daf4f96e 1087 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
0a032cbe
JM
1088 end = tlb->EPN + tlb->size;
1089 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
1090 tlb_flush_page(env, page);
0a032cbe 1091 tlb->prot &= ~PAGE_VALID;
daf4f96e 1092 break;
0a032cbe
JM
1093 }
1094 }
daf4f96e
JM
1095#else
1096 ppc4xx_tlb_invalidate_all(env);
1097#endif
0a032cbe
JM
1098}
1099
c227f099 1100static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
e96efcfc 1101 target_ulong address, int rw, int access_type)
a8dea12f 1102{
c227f099
AL
1103 ppcemb_tlb_t *tlb;
1104 target_phys_addr_t raddr;
0411a972 1105 int i, ret, zsel, zpr, pr;
3b46e624 1106
c55e9aef 1107 ret = -1;
c227f099 1108 raddr = (target_phys_addr_t)-1ULL;
0411a972 1109 pr = msr_pr;
a8dea12f 1110 for (i = 0; i < env->nb_tlb; i++) {
1c53accc 1111 tlb = &env->tlb.tlbe[i];
36081602
JM
1112 if (ppcemb_tlb_check(env, tlb, &raddr, address,
1113 env->spr[SPR_40x_PID], 0, i) < 0)
a8dea12f 1114 continue;
a8dea12f 1115 zsel = (tlb->attr >> 4) & 0xF;
ec5c3e48 1116 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
d12d51d5 1117 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
a8dea12f 1118 __func__, i, zsel, zpr, rw, tlb->attr);
b227a8e9
JM
1119 /* Check execute enable bit */
1120 switch (zpr) {
1121 case 0x2:
0411a972 1122 if (pr != 0)
b227a8e9
JM
1123 goto check_perms;
1124 /* No break here */
1125 case 0x3:
1126 /* All accesses granted */
1127 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1128 ret = 0;
1129 break;
1130 case 0x0:
0411a972 1131 if (pr != 0) {
dcbc9a70
EI
1132 /* Raise Zone protection fault. */
1133 env->spr[SPR_40x_ESR] = 1 << 22;
b227a8e9
JM
1134 ctx->prot = 0;
1135 ret = -2;
a8dea12f
JM
1136 break;
1137 }
b227a8e9
JM
1138 /* No break here */
1139 case 0x1:
1140 check_perms:
1141 /* Check from TLB entry */
b227a8e9 1142 ctx->prot = tlb->prot;
b227a8e9 1143 ret = check_prot(ctx->prot, rw, access_type);
dcbc9a70
EI
1144 if (ret == -2)
1145 env->spr[SPR_40x_ESR] = 0;
b227a8e9 1146 break;
a8dea12f
JM
1147 }
1148 if (ret >= 0) {
1149 ctx->raddr = raddr;
90e189ec
BS
1150 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1151 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1152 ret);
c55e9aef 1153 return 0;
a8dea12f
JM
1154 }
1155 }
90e189ec
BS
1156 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1157 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
3b46e624 1158
a8dea12f
JM
1159 return ret;
1160}
1161
c294fc58
JM
1162void store_40x_sler (CPUPPCState *env, uint32_t val)
1163{
1164 /* XXX: TO BE FIXED */
1165 if (val != 0x00000000) {
1166 cpu_abort(env, "Little-endian regions are not supported by now\n");
1167 }
1168 env->spr[SPR_405_SLER] = val;
1169}
1170
01662f3e
AG
1171static inline int mmubooke_check_tlb (CPUState *env, ppcemb_tlb_t *tlb,
1172 target_phys_addr_t *raddr, int *prot,
1173 target_ulong address, int rw,
1174 int access_type, int i)
1175{
1176 int ret, _prot;
1177
1178 if (ppcemb_tlb_check(env, tlb, raddr, address,
1179 env->spr[SPR_BOOKE_PID],
1180 !env->nb_pids, i) >= 0) {
1181 goto found_tlb;
1182 }
1183
1184 if (env->spr[SPR_BOOKE_PID1] &&
1185 ppcemb_tlb_check(env, tlb, raddr, address,
1186 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
1187 goto found_tlb;
1188 }
1189
1190 if (env->spr[SPR_BOOKE_PID2] &&
1191 ppcemb_tlb_check(env, tlb, raddr, address,
1192 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
1193 goto found_tlb;
1194 }
1195
1196 LOG_SWTLB("%s: TLB entry not found\n", __func__);
1197 return -1;
1198
1199found_tlb:
1200
1201 if (msr_pr != 0) {
1202 _prot = tlb->prot & 0xF;
1203 } else {
1204 _prot = (tlb->prot >> 4) & 0xF;
1205 }
1206
1207 /* Check the address space */
1208 if (access_type == ACCESS_CODE) {
1209 if (msr_ir != (tlb->attr & 1)) {
1210 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1211 return -1;
1212 }
1213
1214 *prot = _prot;
1215 if (_prot & PAGE_EXEC) {
1216 LOG_SWTLB("%s: good TLB!\n", __func__);
1217 return 0;
1218 }
1219
1220 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
1221 ret = -3;
1222 } else {
1223 if (msr_dr != (tlb->attr & 1)) {
1224 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1225 return -1;
1226 }
1227
1228 *prot = _prot;
1229 if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
1230 LOG_SWTLB("%s: found TLB!\n", __func__);
1231 return 0;
1232 }
1233
1234 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
1235 ret = -2;
1236 }
1237
1238 return ret;
1239}
1240
c227f099 1241static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
93220573
AJ
1242 target_ulong address, int rw,
1243 int access_type)
5eb7995e 1244{
c227f099
AL
1245 ppcemb_tlb_t *tlb;
1246 target_phys_addr_t raddr;
01662f3e 1247 int i, ret;
5eb7995e
JM
1248
1249 ret = -1;
c227f099 1250 raddr = (target_phys_addr_t)-1ULL;
5eb7995e 1251 for (i = 0; i < env->nb_tlb; i++) {
1c53accc 1252 tlb = &env->tlb.tlbe[i];
01662f3e
AG
1253 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
1254 access_type, i);
1255 if (!ret) {
1256 break;
1257 }
1258 }
1259
1260 if (ret >= 0) {
1261 ctx->raddr = raddr;
1262 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1263 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1264 ret);
1265 } else {
1266 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1267 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1268 }
1269
1270 return ret;
1271}
1272
1273void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot)
1274{
1275 int tlb_size;
1276 int i, j;
1c53accc 1277 ppcmas_tlb_t *tlb = env->tlb.tlbm;
01662f3e
AG
1278
1279 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1280 if (flags & (1 << i)) {
1281 tlb_size = booke206_tlb_size(env, i);
1282 for (j = 0; j < tlb_size; j++) {
1c53accc
AG
1283 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
1284 tlb[j].mas1 &= ~MAS1_VALID;
01662f3e 1285 }
5eb7995e 1286 }
01662f3e
AG
1287 }
1288 tlb += booke206_tlb_size(env, i);
1289 }
1290
1291 tlb_flush(env, 1);
1292}
1293
d1e256fe
AG
1294target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
1295{
1296 uint32_t tlbncfg;
1297 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2bd9543c 1298 int tlbm_size;
d1e256fe
AG
1299
1300 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
1301
1302 if (tlbncfg & TLBnCFG_AVAIL) {
1303 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1304 } else {
1305 tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
2bd9543c 1306 tlbm_size <<= 1;
d1e256fe
AG
1307 }
1308
2bd9543c 1309 return 1024ULL << tlbm_size;
d1e256fe
AG
1310}
1311
1312/* TLB check function for MAS based SoftTLBs */
1313int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb,
1314 target_phys_addr_t *raddrp,
1315 target_ulong address, uint32_t pid)
1316{
1317 target_ulong mask;
1318 uint32_t tlb_pid;
1319
1320 /* Check valid flag */
1321 if (!(tlb->mas1 & MAS1_VALID)) {
1322 return -1;
1323 }
1324
1325 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
1326 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
1327 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
1328 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
1329 tlb->mas8);
1330
1331 /* Check PID */
1332 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
1333 if (tlb_pid != 0 && tlb_pid != pid) {
1334 return -1;
1335 }
1336
1337 /* Check effective address */
1338 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
1339 return -1;
1340 }
1341 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
1342
1343 return 0;
1344}
1345
1346static int mmubooke206_check_tlb(CPUState *env, ppcmas_tlb_t *tlb,
1347 target_phys_addr_t *raddr, int *prot,
1348 target_ulong address, int rw,
1349 int access_type)
1350{
1351 int ret;
1352 int _prot = 0;
1353
1354 if (ppcmas_tlb_check(env, tlb, raddr, address,
1355 env->spr[SPR_BOOKE_PID]) >= 0) {
1356 goto found_tlb;
1357 }
1358
1359 if (env->spr[SPR_BOOKE_PID1] &&
1360 ppcmas_tlb_check(env, tlb, raddr, address,
1361 env->spr[SPR_BOOKE_PID1]) >= 0) {
1362 goto found_tlb;
1363 }
1364
1365 if (env->spr[SPR_BOOKE_PID2] &&
1366 ppcmas_tlb_check(env, tlb, raddr, address,
1367 env->spr[SPR_BOOKE_PID2]) >= 0) {
1368 goto found_tlb;
1369 }
1370
1371 LOG_SWTLB("%s: TLB entry not found\n", __func__);
1372 return -1;
1373
1374found_tlb:
1375
1376 if (msr_pr != 0) {
1377 if (tlb->mas7_3 & MAS3_UR) {
1378 _prot |= PAGE_READ;
1379 }
1380 if (tlb->mas7_3 & MAS3_UW) {
1381 _prot |= PAGE_WRITE;
1382 }
1383 if (tlb->mas7_3 & MAS3_UX) {
1384 _prot |= PAGE_EXEC;
1385 }
1386 } else {
1387 if (tlb->mas7_3 & MAS3_SR) {
1388 _prot |= PAGE_READ;
1389 }
1390 if (tlb->mas7_3 & MAS3_SW) {
1391 _prot |= PAGE_WRITE;
1392 }
1393 if (tlb->mas7_3 & MAS3_SX) {
1394 _prot |= PAGE_EXEC;
1395 }
1396 }
1397
1398 /* Check the address space and permissions */
1399 if (access_type == ACCESS_CODE) {
1400 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1401 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1402 return -1;
1403 }
1404
1405 *prot = _prot;
1406 if (_prot & PAGE_EXEC) {
1407 LOG_SWTLB("%s: good TLB!\n", __func__);
1408 return 0;
1409 }
1410
1411 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
1412 ret = -3;
1413 } else {
1414 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1415 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1416 return -1;
1417 }
1418
1419 *prot = _prot;
1420 if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
1421 LOG_SWTLB("%s: found TLB!\n", __func__);
1422 return 0;
1423 }
1424
1425 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
1426 ret = -2;
1427 }
1428
1429 return ret;
1430}
1431
01662f3e 1432static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx,
d1e256fe
AG
1433 target_ulong address, int rw,
1434 int access_type)
01662f3e 1435{
d1e256fe 1436 ppcmas_tlb_t *tlb;
01662f3e
AG
1437 target_phys_addr_t raddr;
1438 int i, j, ret;
1439
1440 ret = -1;
1441 raddr = (target_phys_addr_t)-1ULL;
1442
1443 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1444 int ways = booke206_tlb_ways(env, i);
1445
1446 for (j = 0; j < ways; j++) {
d1e256fe
AG
1447 tlb = booke206_get_tlbm(env, i, address, j);
1448 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1449 rw, access_type);
01662f3e
AG
1450 if (ret != -1) {
1451 goto found_tlb;
5eb7995e 1452 }
5eb7995e
JM
1453 }
1454 }
01662f3e
AG
1455
1456found_tlb:
1457
1458 if (ret >= 0) {
5eb7995e 1459 ctx->raddr = raddr;
01662f3e
AG
1460 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1461 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1462 ret);
1463 } else {
1464 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1465 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1466 }
5eb7995e
JM
1467
1468 return ret;
1469}
1470
bebabbc7
SW
1471static const char *book3e_tsize_to_str[32] = {
1472 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1473 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1474 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1475 "1T", "2T"
1476};
1477
1478static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1479 CPUState *env, int tlbn, int offset,
1480 int tlbsize)
1481{
1482 ppcmas_tlb_t *entry;
1483 int i;
1484
1485 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1486 cpu_fprintf(f, "Effective Physical Size TID TS SRWX URWX WIMGE U0123\n");
1487
1488 entry = &env->tlb.tlbm[offset];
1489 for (i = 0; i < tlbsize; i++, entry++) {
1490 target_phys_addr_t ea, pa, size;
1491 int tsize;
1492
1493 if (!(entry->mas1 & MAS1_VALID)) {
1494 continue;
1495 }
1496
1497 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1498 size = 1024ULL << tsize;
1499 ea = entry->mas2 & ~(size - 1);
1500 pa = entry->mas7_3 & ~(size - 1);
1501
1502 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1503 (uint64_t)ea, (uint64_t)pa,
1504 book3e_tsize_to_str[tsize],
1505 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1506 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1507 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1508 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1509 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1510 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1511 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1512 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1513 entry->mas2 & MAS2_W ? 'W' : '-',
1514 entry->mas2 & MAS2_I ? 'I' : '-',
1515 entry->mas2 & MAS2_M ? 'M' : '-',
1516 entry->mas2 & MAS2_G ? 'G' : '-',
1517 entry->mas2 & MAS2_E ? 'E' : '-',
1518 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1519 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1520 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1521 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1522 }
1523}
1524
1525static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1526 CPUState *env)
1527{
1528 int offset = 0;
1529 int i;
1530
1531 if (kvm_enabled() && !env->kvm_sw_tlb) {
1532 cpu_fprintf(f, "Cannot access KVM TLB\n");
1533 return;
1534 }
1535
1536 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1537 int size = booke206_tlb_size(env, i);
1538
1539 if (size == 0) {
1540 continue;
1541 }
1542
1543 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1544 offset += size;
1545 }
1546}
1547
1548void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
1549{
1550 switch (env->mmu_model) {
1551 case POWERPC_MMU_BOOKE206:
1552 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1553 break;
1554 default:
1555 cpu_fprintf(f, "%s: unimplemented\n", __func__);
1556 }
1557}
1558
c227f099 1559static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
636aa200 1560 target_ulong eaddr, int rw)
76a66253
JM
1561{
1562 int in_plb, ret;
3b46e624 1563
76a66253 1564 ctx->raddr = eaddr;
b227a8e9 1565 ctx->prot = PAGE_READ | PAGE_EXEC;
76a66253 1566 ret = 0;
a750fc0b
JM
1567 switch (env->mmu_model) {
1568 case POWERPC_MMU_32B:
faadf50e 1569 case POWERPC_MMU_601:
a750fc0b 1570 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 1571 case POWERPC_MMU_SOFT_74xx:
a750fc0b 1572 case POWERPC_MMU_SOFT_4xx:
b4095fed 1573 case POWERPC_MMU_REAL:
7dbe11ac 1574 case POWERPC_MMU_BOOKE:
caa4039c
JM
1575 ctx->prot |= PAGE_WRITE;
1576 break;
1577#if defined(TARGET_PPC64)
add78955 1578 case POWERPC_MMU_620:
a750fc0b 1579 case POWERPC_MMU_64B:
9d52e907 1580 case POWERPC_MMU_2_06:
caa4039c 1581 /* Real address are 60 bits long */
a750fc0b 1582 ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
caa4039c
JM
1583 ctx->prot |= PAGE_WRITE;
1584 break;
9706285b 1585#endif
a750fc0b 1586 case POWERPC_MMU_SOFT_4xx_Z:
caa4039c
JM
1587 if (unlikely(msr_pe != 0)) {
1588 /* 403 family add some particular protections,
1589 * using PBL/PBU registers for accesses with no translation.
1590 */
1591 in_plb =
1592 /* Check PLB validity */
1593 (env->pb[0] < env->pb[1] &&
1594 /* and address in plb area */
1595 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1596 (env->pb[2] < env->pb[3] &&
1597 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1598 if (in_plb ^ msr_px) {
1599 /* Access in protected area */
1600 if (rw == 1) {
1601 /* Access is not allowed */
1602 ret = -2;
1603 }
1604 } else {
1605 /* Read-write access is allowed */
1606 ctx->prot |= PAGE_WRITE;
76a66253 1607 }
76a66253 1608 }
e1833e1f 1609 break;
b4095fed
JM
1610 case POWERPC_MMU_MPC8xx:
1611 /* XXX: TODO */
1612 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1613 break;
01662f3e
AG
1614 case POWERPC_MMU_BOOKE206:
1615 cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
caa4039c
JM
1616 break;
1617 default:
1618 cpu_abort(env, "Unknown or invalid MMU model\n");
1619 return -1;
76a66253
JM
1620 }
1621
1622 return ret;
1623}
1624
c227f099 1625int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
faadf50e 1626 int rw, int access_type)
9a64fbe4
FB
1627{
1628 int ret;
0411a972 1629
514fb8c1 1630#if 0
93fcfe39 1631 qemu_log("%s\n", __func__);
d9bce9d9 1632#endif
4b3686fa
FB
1633 if ((access_type == ACCESS_CODE && msr_ir == 0) ||
1634 (access_type != ACCESS_CODE && msr_dr == 0)) {
a586e548
EI
1635 if (env->mmu_model == POWERPC_MMU_BOOKE) {
1636 /* The BookE MMU always performs address translation. The
1637 IS and DS bits only affect the address space. */
1638 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1639 rw, access_type);
01662f3e
AG
1640 } else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
1641 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
d1e256fe 1642 access_type);
a586e548
EI
1643 } else {
1644 /* No address translation. */
1645 ret = check_physical(env, ctx, eaddr, rw);
1646 }
9a64fbe4 1647 } else {
c55e9aef 1648 ret = -1;
a750fc0b
JM
1649 switch (env->mmu_model) {
1650 case POWERPC_MMU_32B:
faadf50e 1651 case POWERPC_MMU_601:
a750fc0b 1652 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 1653 case POWERPC_MMU_SOFT_74xx:
94855937
BS
1654 /* Try to find a BAT */
1655 if (env->nb_BATs != 0)
1656 ret = get_bat(env, ctx, eaddr, rw, access_type);
c55e9aef 1657#if defined(TARGET_PPC64)
add78955 1658 case POWERPC_MMU_620:
a750fc0b 1659 case POWERPC_MMU_64B:
9d52e907 1660 case POWERPC_MMU_2_06:
c55e9aef 1661#endif
a8dea12f 1662 if (ret < 0) {
c55e9aef 1663 /* We didn't match any BAT entry or don't have BATs */
a8dea12f
JM
1664 ret = get_segment(env, ctx, eaddr, rw, access_type);
1665 }
1666 break;
a750fc0b
JM
1667 case POWERPC_MMU_SOFT_4xx:
1668 case POWERPC_MMU_SOFT_4xx_Z:
36081602 1669 ret = mmu40x_get_physical_address(env, ctx, eaddr,
a8dea12f
JM
1670 rw, access_type);
1671 break;
a750fc0b 1672 case POWERPC_MMU_BOOKE:
5eb7995e
JM
1673 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1674 rw, access_type);
1675 break;
01662f3e
AG
1676 case POWERPC_MMU_BOOKE206:
1677 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1678 access_type);
1679 break;
b4095fed
JM
1680 case POWERPC_MMU_MPC8xx:
1681 /* XXX: TODO */
1682 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1683 break;
b4095fed
JM
1684 case POWERPC_MMU_REAL:
1685 cpu_abort(env, "PowerPC in real mode do not do any translation\n");
2662a059 1686 return -1;
c55e9aef
JM
1687 default:
1688 cpu_abort(env, "Unknown or invalid MMU model\n");
a8dea12f 1689 return -1;
9a64fbe4
FB
1690 }
1691 }
514fb8c1 1692#if 0
90e189ec
BS
1693 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1694 __func__, eaddr, ret, ctx->raddr);
76a66253 1695#endif
d9bce9d9 1696
9a64fbe4
FB
1697 return ret;
1698}
1699
c227f099 1700target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
a6b025d3 1701{
c227f099 1702 mmu_ctx_t ctx;
a6b025d3 1703
faadf50e 1704 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0))
a6b025d3 1705 return -1;
76a66253
JM
1706
1707 return ctx.raddr & TARGET_PAGE_MASK;
a6b025d3 1708}
9a64fbe4 1709
01662f3e
AG
1710static void booke206_update_mas_tlb_miss(CPUState *env, target_ulong address,
1711 int rw)
1712{
1713 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1714 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1715 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1716 env->spr[SPR_BOOKE_MAS3] = 0;
1717 env->spr[SPR_BOOKE_MAS6] = 0;
1718 env->spr[SPR_BOOKE_MAS7] = 0;
1719
1720 /* AS */
1721 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1722 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1723 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1724 }
1725
1726 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1727 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1728
1729 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1730 case MAS4_TIDSELD_PID0:
1731 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1732 break;
1733 case MAS4_TIDSELD_PID1:
1734 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1735 break;
1736 case MAS4_TIDSELD_PID2:
1737 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1738 break;
1739 }
1740
1741 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1742
1743 /* next victim logic */
1744 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1745 env->last_way++;
1746 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1747 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1748}
1749
9a64fbe4 1750/* Perform address translation */
e96efcfc 1751int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
97b348e7 1752 int mmu_idx)
9a64fbe4 1753{
c227f099 1754 mmu_ctx_t ctx;
a541f297 1755 int access_type;
9a64fbe4 1756 int ret = 0;
d9bce9d9 1757
b769d8fe
FB
1758 if (rw == 2) {
1759 /* code access */
1760 rw = 0;
1761 access_type = ACCESS_CODE;
1762 } else {
1763 /* data access */
b4cec7b4 1764 access_type = env->access_type;
b769d8fe 1765 }
faadf50e 1766 ret = get_physical_address(env, &ctx, address, rw, access_type);
9a64fbe4 1767 if (ret == 0) {
d4c430a8
PB
1768 tlb_set_page(env, address & TARGET_PAGE_MASK,
1769 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1770 mmu_idx, TARGET_PAGE_SIZE);
1771 ret = 0;
9a64fbe4 1772 } else if (ret < 0) {
d12d51d5 1773 LOG_MMU_STATE(env);
9a64fbe4 1774 if (access_type == ACCESS_CODE) {
9a64fbe4
FB
1775 switch (ret) {
1776 case -1:
76a66253 1777 /* No matches in page tables or TLB */
a750fc0b
JM
1778 switch (env->mmu_model) {
1779 case POWERPC_MMU_SOFT_6xx:
8f793433
JM
1780 env->exception_index = POWERPC_EXCP_IFTLB;
1781 env->error_code = 1 << 18;
76a66253
JM
1782 env->spr[SPR_IMISS] = address;
1783 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
76a66253 1784 goto tlb_miss;
7dbe11ac 1785 case POWERPC_MMU_SOFT_74xx:
8f793433 1786 env->exception_index = POWERPC_EXCP_IFTLB;
7dbe11ac 1787 goto tlb_miss_74xx;
a750fc0b
JM
1788 case POWERPC_MMU_SOFT_4xx:
1789 case POWERPC_MMU_SOFT_4xx_Z:
8f793433
JM
1790 env->exception_index = POWERPC_EXCP_ITLB;
1791 env->error_code = 0;
a8dea12f
JM
1792 env->spr[SPR_40x_DEAR] = address;
1793 env->spr[SPR_40x_ESR] = 0x00000000;
c55e9aef 1794 break;
a750fc0b 1795 case POWERPC_MMU_32B:
faadf50e 1796 case POWERPC_MMU_601:
c55e9aef 1797#if defined(TARGET_PPC64)
add78955 1798 case POWERPC_MMU_620:
a750fc0b 1799 case POWERPC_MMU_64B:
9d52e907 1800 case POWERPC_MMU_2_06:
c55e9aef 1801#endif
8f793433
JM
1802 env->exception_index = POWERPC_EXCP_ISI;
1803 env->error_code = 0x40000000;
1804 break;
01662f3e
AG
1805 case POWERPC_MMU_BOOKE206:
1806 booke206_update_mas_tlb_miss(env, address, rw);
1807 /* fall through */
a750fc0b 1808 case POWERPC_MMU_BOOKE:
a586e548
EI
1809 env->exception_index = POWERPC_EXCP_ITLB;
1810 env->error_code = 0;
1811 env->spr[SPR_BOOKE_DEAR] = address;
c55e9aef 1812 return -1;
b4095fed
JM
1813 case POWERPC_MMU_MPC8xx:
1814 /* XXX: TODO */
1815 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1816 break;
1817 case POWERPC_MMU_REAL:
1818 cpu_abort(env, "PowerPC in real mode should never raise "
1819 "any MMU exceptions\n");
2662a059 1820 return -1;
c55e9aef
JM
1821 default:
1822 cpu_abort(env, "Unknown or invalid MMU model\n");
1823 return -1;
76a66253 1824 }
9a64fbe4
FB
1825 break;
1826 case -2:
1827 /* Access rights violation */
8f793433
JM
1828 env->exception_index = POWERPC_EXCP_ISI;
1829 env->error_code = 0x08000000;
9a64fbe4
FB
1830 break;
1831 case -3:
76a66253 1832 /* No execute protection violation */
01662f3e
AG
1833 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1834 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
a586e548
EI
1835 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1836 }
8f793433
JM
1837 env->exception_index = POWERPC_EXCP_ISI;
1838 env->error_code = 0x10000000;
9a64fbe4
FB
1839 break;
1840 case -4:
1841 /* Direct store exception */
1842 /* No code fetch is allowed in direct-store areas */
8f793433
JM
1843 env->exception_index = POWERPC_EXCP_ISI;
1844 env->error_code = 0x10000000;
2be0071f 1845 break;
e1833e1f 1846#if defined(TARGET_PPC64)
2be0071f
FB
1847 case -5:
1848 /* No match in segment table */
add78955
JM
1849 if (env->mmu_model == POWERPC_MMU_620) {
1850 env->exception_index = POWERPC_EXCP_ISI;
1851 /* XXX: this might be incorrect */
1852 env->error_code = 0x40000000;
1853 } else {
1854 env->exception_index = POWERPC_EXCP_ISEG;
1855 env->error_code = 0;
1856 }
9a64fbe4 1857 break;
e1833e1f 1858#endif
9a64fbe4
FB
1859 }
1860 } else {
9a64fbe4
FB
1861 switch (ret) {
1862 case -1:
76a66253 1863 /* No matches in page tables or TLB */
a750fc0b
JM
1864 switch (env->mmu_model) {
1865 case POWERPC_MMU_SOFT_6xx:
76a66253 1866 if (rw == 1) {
8f793433
JM
1867 env->exception_index = POWERPC_EXCP_DSTLB;
1868 env->error_code = 1 << 16;
76a66253 1869 } else {
8f793433
JM
1870 env->exception_index = POWERPC_EXCP_DLTLB;
1871 env->error_code = 0;
76a66253
JM
1872 }
1873 env->spr[SPR_DMISS] = address;
1874 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1875 tlb_miss:
8f793433 1876 env->error_code |= ctx.key << 19;
fda6a0ec
DG
1877 env->spr[SPR_HASH1] = env->htab_base +
1878 get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
1879 env->spr[SPR_HASH2] = env->htab_base +
1880 get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
8f793433 1881 break;
7dbe11ac
JM
1882 case POWERPC_MMU_SOFT_74xx:
1883 if (rw == 1) {
8f793433 1884 env->exception_index = POWERPC_EXCP_DSTLB;
7dbe11ac 1885 } else {
8f793433 1886 env->exception_index = POWERPC_EXCP_DLTLB;
7dbe11ac
JM
1887 }
1888 tlb_miss_74xx:
1889 /* Implement LRU algorithm */
8f793433 1890 env->error_code = ctx.key << 19;
7dbe11ac
JM
1891 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1892 ((env->last_way + 1) & (env->nb_ways - 1));
1893 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
7dbe11ac 1894 break;
a750fc0b
JM
1895 case POWERPC_MMU_SOFT_4xx:
1896 case POWERPC_MMU_SOFT_4xx_Z:
8f793433
JM
1897 env->exception_index = POWERPC_EXCP_DTLB;
1898 env->error_code = 0;
a8dea12f
JM
1899 env->spr[SPR_40x_DEAR] = address;
1900 if (rw)
1901 env->spr[SPR_40x_ESR] = 0x00800000;
1902 else
1903 env->spr[SPR_40x_ESR] = 0x00000000;
c55e9aef 1904 break;
a750fc0b 1905 case POWERPC_MMU_32B:
faadf50e 1906 case POWERPC_MMU_601:
c55e9aef 1907#if defined(TARGET_PPC64)
add78955 1908 case POWERPC_MMU_620:
a750fc0b 1909 case POWERPC_MMU_64B:
9d52e907 1910 case POWERPC_MMU_2_06:
c55e9aef 1911#endif
8f793433
JM
1912 env->exception_index = POWERPC_EXCP_DSI;
1913 env->error_code = 0;
1914 env->spr[SPR_DAR] = address;
1915 if (rw == 1)
1916 env->spr[SPR_DSISR] = 0x42000000;
1917 else
1918 env->spr[SPR_DSISR] = 0x40000000;
1919 break;
b4095fed
JM
1920 case POWERPC_MMU_MPC8xx:
1921 /* XXX: TODO */
1922 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1923 break;
01662f3e
AG
1924 case POWERPC_MMU_BOOKE206:
1925 booke206_update_mas_tlb_miss(env, address, rw);
1926 /* fall through */
a750fc0b 1927 case POWERPC_MMU_BOOKE:
a586e548
EI
1928 env->exception_index = POWERPC_EXCP_DTLB;
1929 env->error_code = 0;
1930 env->spr[SPR_BOOKE_DEAR] = address;
542df9bf 1931 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
c55e9aef 1932 return -1;
b4095fed
JM
1933 case POWERPC_MMU_REAL:
1934 cpu_abort(env, "PowerPC in real mode should never raise "
1935 "any MMU exceptions\n");
2662a059 1936 return -1;
c55e9aef
JM
1937 default:
1938 cpu_abort(env, "Unknown or invalid MMU model\n");
1939 return -1;
76a66253 1940 }
9a64fbe4
FB
1941 break;
1942 case -2:
1943 /* Access rights violation */
8f793433
JM
1944 env->exception_index = POWERPC_EXCP_DSI;
1945 env->error_code = 0;
dcbc9a70
EI
1946 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1947 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1948 env->spr[SPR_40x_DEAR] = address;
1949 if (rw) {
1950 env->spr[SPR_40x_ESR] |= 0x00800000;
1951 }
01662f3e
AG
1952 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1953 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
a586e548 1954 env->spr[SPR_BOOKE_DEAR] = address;
542df9bf 1955 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
dcbc9a70
EI
1956 } else {
1957 env->spr[SPR_DAR] = address;
1958 if (rw == 1) {
1959 env->spr[SPR_DSISR] = 0x0A000000;
1960 } else {
1961 env->spr[SPR_DSISR] = 0x08000000;
1962 }
1963 }
9a64fbe4
FB
1964 break;
1965 case -4:
1966 /* Direct store exception */
1967 switch (access_type) {
1968 case ACCESS_FLOAT:
1969 /* Floating point load/store */
8f793433
JM
1970 env->exception_index = POWERPC_EXCP_ALIGN;
1971 env->error_code = POWERPC_EXCP_ALIGN_FP;
1972 env->spr[SPR_DAR] = address;
9a64fbe4
FB
1973 break;
1974 case ACCESS_RES:
8f793433
JM
1975 /* lwarx, ldarx or stwcx. */
1976 env->exception_index = POWERPC_EXCP_DSI;
1977 env->error_code = 0;
1978 env->spr[SPR_DAR] = address;
1979 if (rw == 1)
1980 env->spr[SPR_DSISR] = 0x06000000;
1981 else
1982 env->spr[SPR_DSISR] = 0x04000000;
9a64fbe4
FB
1983 break;
1984 case ACCESS_EXT:
1985 /* eciwx or ecowx */
8f793433
JM
1986 env->exception_index = POWERPC_EXCP_DSI;
1987 env->error_code = 0;
1988 env->spr[SPR_DAR] = address;
1989 if (rw == 1)
1990 env->spr[SPR_DSISR] = 0x06100000;
1991 else
1992 env->spr[SPR_DSISR] = 0x04100000;
9a64fbe4
FB
1993 break;
1994 default:
76a66253 1995 printf("DSI: invalid exception (%d)\n", ret);
8f793433
JM
1996 env->exception_index = POWERPC_EXCP_PROGRAM;
1997 env->error_code =
1998 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1999 env->spr[SPR_DAR] = address;
9a64fbe4
FB
2000 break;
2001 }
fdabc366 2002 break;
e1833e1f 2003#if defined(TARGET_PPC64)
2be0071f
FB
2004 case -5:
2005 /* No match in segment table */
add78955
JM
2006 if (env->mmu_model == POWERPC_MMU_620) {
2007 env->exception_index = POWERPC_EXCP_DSI;
2008 env->error_code = 0;
2009 env->spr[SPR_DAR] = address;
2010 /* XXX: this might be incorrect */
2011 if (rw == 1)
2012 env->spr[SPR_DSISR] = 0x42000000;
2013 else
2014 env->spr[SPR_DSISR] = 0x40000000;
2015 } else {
2016 env->exception_index = POWERPC_EXCP_DSEG;
2017 env->error_code = 0;
2018 env->spr[SPR_DAR] = address;
2019 }
2be0071f 2020 break;
e1833e1f 2021#endif
9a64fbe4 2022 }
9a64fbe4
FB
2023 }
2024#if 0
8f793433
JM
2025 printf("%s: set exception to %d %02x\n", __func__,
2026 env->exception, env->error_code);
9a64fbe4 2027#endif
9a64fbe4
FB
2028 ret = 1;
2029 }
76a66253 2030
9a64fbe4
FB
2031 return ret;
2032}
2033
3fc6c082
FB
2034/*****************************************************************************/
2035/* BATs management */
2036#if !defined(FLUSH_ALL_TLBS)
636aa200
BS
2037static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
2038 target_ulong mask)
3fc6c082
FB
2039{
2040 target_ulong base, end, page;
76a66253 2041
3fc6c082
FB
2042 base = BATu & ~0x0001FFFF;
2043 end = base + mask + 0x00020000;
90e189ec
BS
2044 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
2045 TARGET_FMT_lx ")\n", base, end, mask);
3fc6c082
FB
2046 for (page = base; page != end; page += TARGET_PAGE_SIZE)
2047 tlb_flush_page(env, page);
d12d51d5 2048 LOG_BATS("Flush done\n");
3fc6c082
FB
2049}
2050#endif
2051
636aa200
BS
2052static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
2053 target_ulong value)
3fc6c082 2054{
90e189ec
BS
2055 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
2056 nr, ul == 0 ? 'u' : 'l', value, env->nip);
3fc6c082
FB
2057}
2058
45d827d2 2059void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
2060{
2061 target_ulong mask;
2062
2063 dump_store_bat(env, 'I', 0, nr, value);
2064 if (env->IBAT[0][nr] != value) {
2065 mask = (value << 15) & 0x0FFE0000UL;
2066#if !defined(FLUSH_ALL_TLBS)
2067 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2068#endif
2069 /* When storing valid upper BAT, mask BEPI and BRPN
2070 * and invalidate all TLBs covered by this BAT
2071 */
2072 mask = (value << 15) & 0x0FFE0000UL;
2073 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
2074 (value & ~0x0001FFFFUL & ~mask);
2075 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
2076 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
2077#if !defined(FLUSH_ALL_TLBS)
2078 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
76a66253 2079#else
3fc6c082
FB
2080 tlb_flush(env, 1);
2081#endif
2082 }
2083}
2084
45d827d2 2085void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
2086{
2087 dump_store_bat(env, 'I', 1, nr, value);
2088 env->IBAT[1][nr] = value;
2089}
2090
45d827d2 2091void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
2092{
2093 target_ulong mask;
2094
2095 dump_store_bat(env, 'D', 0, nr, value);
2096 if (env->DBAT[0][nr] != value) {
2097 /* When storing valid upper BAT, mask BEPI and BRPN
2098 * and invalidate all TLBs covered by this BAT
2099 */
2100 mask = (value << 15) & 0x0FFE0000UL;
2101#if !defined(FLUSH_ALL_TLBS)
2102 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
2103#endif
2104 mask = (value << 15) & 0x0FFE0000UL;
2105 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
2106 (value & ~0x0001FFFFUL & ~mask);
2107 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
2108 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
2109#if !defined(FLUSH_ALL_TLBS)
2110 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
2111#else
2112 tlb_flush(env, 1);
2113#endif
2114 }
2115}
2116
45d827d2 2117void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
2118{
2119 dump_store_bat(env, 'D', 1, nr, value);
2120 env->DBAT[1][nr] = value;
2121}
2122
45d827d2 2123void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
056401ea
JM
2124{
2125 target_ulong mask;
05f92404 2126#if defined(FLUSH_ALL_TLBS)
056401ea 2127 int do_inval;
05f92404 2128#endif
056401ea
JM
2129
2130 dump_store_bat(env, 'I', 0, nr, value);
2131 if (env->IBAT[0][nr] != value) {
05f92404 2132#if defined(FLUSH_ALL_TLBS)
056401ea 2133 do_inval = 0;
05f92404 2134#endif
056401ea
JM
2135 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
2136 if (env->IBAT[1][nr] & 0x40) {
2137 /* Invalidate BAT only if it is valid */
2138#if !defined(FLUSH_ALL_TLBS)
2139 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2140#else
2141 do_inval = 1;
2142#endif
2143 }
2144 /* When storing valid upper BAT, mask BEPI and BRPN
2145 * and invalidate all TLBs covered by this BAT
2146 */
2147 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
2148 (value & ~0x0001FFFFUL & ~mask);
2149 env->DBAT[0][nr] = env->IBAT[0][nr];
2150 if (env->IBAT[1][nr] & 0x40) {
2151#if !defined(FLUSH_ALL_TLBS)
2152 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2153#else
2154 do_inval = 1;
2155#endif
2156 }
2157#if defined(FLUSH_ALL_TLBS)
2158 if (do_inval)
2159 tlb_flush(env, 1);
2160#endif
2161 }
2162}
2163
45d827d2 2164void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
056401ea
JM
2165{
2166 target_ulong mask;
05f92404 2167#if defined(FLUSH_ALL_TLBS)
056401ea 2168 int do_inval;
05f92404 2169#endif
056401ea
JM
2170
2171 dump_store_bat(env, 'I', 1, nr, value);
2172 if (env->IBAT[1][nr] != value) {
05f92404 2173#if defined(FLUSH_ALL_TLBS)
056401ea 2174 do_inval = 0;
05f92404 2175#endif
056401ea
JM
2176 if (env->IBAT[1][nr] & 0x40) {
2177#if !defined(FLUSH_ALL_TLBS)
2178 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
2179 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2180#else
2181 do_inval = 1;
2182#endif
2183 }
2184 if (value & 0x40) {
2185#if !defined(FLUSH_ALL_TLBS)
2186 mask = (value << 17) & 0x0FFE0000UL;
2187 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2188#else
2189 do_inval = 1;
2190#endif
2191 }
2192 env->IBAT[1][nr] = value;
2193 env->DBAT[1][nr] = value;
2194#if defined(FLUSH_ALL_TLBS)
2195 if (do_inval)
2196 tlb_flush(env, 1);
2197#endif
2198 }
2199}
2200
0a032cbe
JM
2201/*****************************************************************************/
2202/* TLB management */
2203void ppc_tlb_invalidate_all (CPUPPCState *env)
2204{
daf4f96e
JM
2205 switch (env->mmu_model) {
2206 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 2207 case POWERPC_MMU_SOFT_74xx:
0a032cbe 2208 ppc6xx_tlb_invalidate_all(env);
daf4f96e
JM
2209 break;
2210 case POWERPC_MMU_SOFT_4xx:
2211 case POWERPC_MMU_SOFT_4xx_Z:
0a032cbe 2212 ppc4xx_tlb_invalidate_all(env);
daf4f96e 2213 break;
b4095fed 2214 case POWERPC_MMU_REAL:
7dbe11ac
JM
2215 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
2216 break;
b4095fed
JM
2217 case POWERPC_MMU_MPC8xx:
2218 /* XXX: TODO */
2219 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
2220 break;
7dbe11ac 2221 case POWERPC_MMU_BOOKE:
a586e548 2222 tlb_flush(env, 1);
7dbe11ac 2223 break;
01662f3e
AG
2224 case POWERPC_MMU_BOOKE206:
2225 booke206_flush_tlb(env, -1, 0);
7dbe11ac 2226 break;
7dbe11ac 2227 case POWERPC_MMU_32B:
faadf50e 2228 case POWERPC_MMU_601:
00af685f 2229#if defined(TARGET_PPC64)
add78955 2230 case POWERPC_MMU_620:
7dbe11ac 2231 case POWERPC_MMU_64B:
9d52e907 2232 case POWERPC_MMU_2_06:
00af685f 2233#endif /* defined(TARGET_PPC64) */
0a032cbe 2234 tlb_flush(env, 1);
daf4f96e 2235 break;
00af685f
JM
2236 default:
2237 /* XXX: TODO */
12de9a39 2238 cpu_abort(env, "Unknown MMU model\n");
00af685f 2239 break;
0a032cbe
JM
2240 }
2241}
2242
daf4f96e
JM
2243void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
2244{
2245#if !defined(FLUSH_ALL_TLBS)
2246 addr &= TARGET_PAGE_MASK;
2247 switch (env->mmu_model) {
2248 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 2249 case POWERPC_MMU_SOFT_74xx:
daf4f96e
JM
2250 ppc6xx_tlb_invalidate_virt(env, addr, 0);
2251 if (env->id_tlbs == 1)
2252 ppc6xx_tlb_invalidate_virt(env, addr, 1);
2253 break;
2254 case POWERPC_MMU_SOFT_4xx:
2255 case POWERPC_MMU_SOFT_4xx_Z:
2256 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
2257 break;
b4095fed 2258 case POWERPC_MMU_REAL:
7dbe11ac
JM
2259 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
2260 break;
b4095fed
JM
2261 case POWERPC_MMU_MPC8xx:
2262 /* XXX: TODO */
2263 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
2264 break;
7dbe11ac
JM
2265 case POWERPC_MMU_BOOKE:
2266 /* XXX: TODO */
b4095fed 2267 cpu_abort(env, "BookE MMU model is not implemented\n");
7dbe11ac 2268 break;
01662f3e 2269 case POWERPC_MMU_BOOKE206:
7dbe11ac 2270 /* XXX: TODO */
01662f3e 2271 cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
7dbe11ac
JM
2272 break;
2273 case POWERPC_MMU_32B:
faadf50e 2274 case POWERPC_MMU_601:
daf4f96e 2275 /* tlbie invalidate TLBs for all segments */
6f2d8978 2276 addr &= ~((target_ulong)-1ULL << 28);
daf4f96e
JM
2277 /* XXX: this case should be optimized,
2278 * giving a mask to tlb_flush_page
2279 */
2280 tlb_flush_page(env, addr | (0x0 << 28));
2281 tlb_flush_page(env, addr | (0x1 << 28));
2282 tlb_flush_page(env, addr | (0x2 << 28));
2283 tlb_flush_page(env, addr | (0x3 << 28));
2284 tlb_flush_page(env, addr | (0x4 << 28));
2285 tlb_flush_page(env, addr | (0x5 << 28));
2286 tlb_flush_page(env, addr | (0x6 << 28));
2287 tlb_flush_page(env, addr | (0x7 << 28));
2288 tlb_flush_page(env, addr | (0x8 << 28));
2289 tlb_flush_page(env, addr | (0x9 << 28));
2290 tlb_flush_page(env, addr | (0xA << 28));
2291 tlb_flush_page(env, addr | (0xB << 28));
2292 tlb_flush_page(env, addr | (0xC << 28));
2293 tlb_flush_page(env, addr | (0xD << 28));
2294 tlb_flush_page(env, addr | (0xE << 28));
2295 tlb_flush_page(env, addr | (0xF << 28));
7dbe11ac 2296 break;
00af685f 2297#if defined(TARGET_PPC64)
add78955 2298 case POWERPC_MMU_620:
7dbe11ac 2299 case POWERPC_MMU_64B:
9d52e907 2300 case POWERPC_MMU_2_06:
7dbe11ac
JM
2301 /* tlbie invalidate TLBs for all segments */
2302 /* XXX: given the fact that there are too many segments to invalidate,
00af685f 2303 * and we still don't have a tlb_flush_mask(env, n, mask) in Qemu,
7dbe11ac
JM
2304 * we just invalidate all TLBs
2305 */
2306 tlb_flush(env, 1);
2307 break;
00af685f
JM
2308#endif /* defined(TARGET_PPC64) */
2309 default:
2310 /* XXX: TODO */
12de9a39 2311 cpu_abort(env, "Unknown MMU model\n");
00af685f 2312 break;
daf4f96e
JM
2313 }
2314#else
2315 ppc_tlb_invalidate_all(env);
2316#endif
2317}
2318
3fc6c082
FB
2319/*****************************************************************************/
2320/* Special registers manipulation */
d9bce9d9 2321#if defined(TARGET_PPC64)
d9bce9d9
JM
2322void ppc_store_asr (CPUPPCState *env, target_ulong value)
2323{
2324 if (env->asr != value) {
2325 env->asr = value;
2326 tlb_flush(env, 1);
2327 }
2328}
2329#endif
2330
45d827d2 2331void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
3fc6c082 2332{
90e189ec 2333 LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
bb593904
DG
2334 if (env->spr[SPR_SDR1] != value) {
2335 env->spr[SPR_SDR1] = value;
2336#if defined(TARGET_PPC64)
2337 if (env->mmu_model & POWERPC_MMU_64) {
2338 target_ulong htabsize = value & SDR_64_HTABSIZE;
2339
2340 if (htabsize > 28) {
2341 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2342 " stored in SDR1\n", htabsize);
2343 htabsize = 28;
2344 }
2345 env->htab_mask = (1ULL << (htabsize + 18)) - 1;
2346 env->htab_base = value & SDR_64_HTABORG;
2347 } else
2348#endif /* defined(TARGET_PPC64) */
2349 {
2350 /* FIXME: Should check for valid HTABMASK values */
2351 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2352 env->htab_base = value & SDR_32_HTABORG;
2353 }
76a66253 2354 tlb_flush(env, 1);
3fc6c082
FB
2355 }
2356}
2357
f6b868fc
BS
2358#if defined(TARGET_PPC64)
2359target_ulong ppc_load_sr (CPUPPCState *env, int slb_nr)
2360{
2361 // XXX
2362 return 0;
2363}
2364#endif
2365
45d827d2 2366void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value)
3fc6c082 2367{
90e189ec
BS
2368 LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2369 srnum, value, env->sr[srnum]);
f6b868fc
BS
2370#if defined(TARGET_PPC64)
2371 if (env->mmu_model & POWERPC_MMU_64) {
2372 uint64_t rb = 0, rs = 0;
2373
2374 /* ESID = srnum */
2375 rb |= ((uint32_t)srnum & 0xf) << 28;
2376 /* Set the valid bit */
2377 rb |= 1 << 27;
2378 /* Index = ESID */
2379 rb |= (uint32_t)srnum;
2380
2381 /* VSID = VSID */
2382 rs |= (value & 0xfffffff) << 12;
2383 /* flags = flags */
decb4714 2384 rs |= ((value >> 27) & 0xf) << 8;
f6b868fc
BS
2385
2386 ppc_store_slb(env, rb, rs);
2387 } else
2388#endif
3fc6c082
FB
2389 if (env->sr[srnum] != value) {
2390 env->sr[srnum] = value;
bf1752ef
AJ
2391/* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2392 flusing the whole TLB. */
3fc6c082
FB
2393#if !defined(FLUSH_ALL_TLBS) && 0
2394 {
2395 target_ulong page, end;
2396 /* Invalidate 256 MB of virtual memory */
2397 page = (16 << 20) * srnum;
2398 end = page + (16 << 20);
2399 for (; page != end; page += TARGET_PAGE_SIZE)
2400 tlb_flush_page(env, page);
2401 }
2402#else
76a66253 2403 tlb_flush(env, 1);
3fc6c082
FB
2404#endif
2405 }
2406}
76a66253 2407#endif /* !defined (CONFIG_USER_ONLY) */
3fc6c082 2408
76a66253 2409/* GDBstub can read and write MSR... */
0411a972 2410void ppc_store_msr (CPUPPCState *env, target_ulong value)
3fc6c082 2411{
a4f30719 2412 hreg_store_msr(env, value, 0);
3fc6c082
FB
2413}
2414
2415/*****************************************************************************/
2416/* Exception processing */
18fba28c 2417#if defined (CONFIG_USER_ONLY)
9a64fbe4 2418void do_interrupt (CPUState *env)
79aceca5 2419{
e1833e1f
JM
2420 env->exception_index = POWERPC_EXCP_NONE;
2421 env->error_code = 0;
18fba28c 2422}
47103572 2423
e9df014c 2424void ppc_hw_interrupt (CPUState *env)
47103572 2425{
e1833e1f
JM
2426 env->exception_index = POWERPC_EXCP_NONE;
2427 env->error_code = 0;
47103572 2428}
76a66253 2429#else /* defined (CONFIG_USER_ONLY) */
636aa200 2430static inline void dump_syscall(CPUState *env)
d094807b 2431{
b11ebf64
BS
2432 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
2433 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
2434 " nip=" TARGET_FMT_lx "\n",
90e189ec
BS
2435 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
2436 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
2437 ppc_dump_gpr(env, 6), env->nip);
d094807b
FB
2438}
2439
e1833e1f
JM
2440/* Note that this function should be greatly optimized
2441 * when called with a constant excp, from ppc_hw_interrupt
2442 */
636aa200 2443static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
18fba28c 2444{
0411a972 2445 target_ulong msr, new_msr, vector;
e1833e1f 2446 int srr0, srr1, asrr0, asrr1;
a4f30719 2447 int lpes0, lpes1, lev;
79aceca5 2448
b172c56a
JM
2449 if (0) {
2450 /* XXX: find a suitable condition to enable the hypervisor mode */
2451 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
2452 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
2453 } else {
2454 /* Those values ensure we won't enter the hypervisor mode */
2455 lpes0 = 0;
2456 lpes1 = 1;
2457 }
2458
90e189ec
BS
2459 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
2460 " => %08x (%02x)\n", env->nip, excp, env->error_code);
41557447
AG
2461
2462 /* new srr1 value excluding must-be-zero bits */
2463 msr = env->msr & ~0x783f0000ULL;
2464
2465 /* new interrupt handler msr */
2466 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
2467
2468 /* target registers */
e1833e1f
JM
2469 srr0 = SPR_SRR0;
2470 srr1 = SPR_SRR1;
2471 asrr0 = -1;
2472 asrr1 = -1;
41557447 2473
9a64fbe4 2474 switch (excp) {
e1833e1f
JM
2475 case POWERPC_EXCP_NONE:
2476 /* Should never happen */
2477 return;
2478 case POWERPC_EXCP_CRITICAL: /* Critical input */
e1833e1f 2479 switch (excp_model) {
a750fc0b 2480 case POWERPC_EXCP_40x:
e1833e1f
JM
2481 srr0 = SPR_40x_SRR2;
2482 srr1 = SPR_40x_SRR3;
c62db105 2483 break;
a750fc0b 2484 case POWERPC_EXCP_BOOKE:
e1833e1f
JM
2485 srr0 = SPR_BOOKE_CSRR0;
2486 srr1 = SPR_BOOKE_CSRR1;
c62db105 2487 break;
e1833e1f 2488 case POWERPC_EXCP_G2:
c62db105 2489 break;
e1833e1f
JM
2490 default:
2491 goto excp_invalid;
2be0071f 2492 }
9a64fbe4 2493 goto store_next;
e1833e1f
JM
2494 case POWERPC_EXCP_MCHECK: /* Machine check exception */
2495 if (msr_me == 0) {
e63ecc6f
JM
2496 /* Machine check exception is not enabled.
2497 * Enter checkstop state.
2498 */
93fcfe39
AL
2499 if (qemu_log_enabled()) {
2500 qemu_log("Machine check while not allowed. "
e63ecc6f
JM
2501 "Entering checkstop state\n");
2502 } else {
2503 fprintf(stderr, "Machine check while not allowed. "
2504 "Entering checkstop state\n");
2505 }
2506 env->halted = 1;
2507 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
e1833e1f 2508 }
b172c56a
JM
2509 if (0) {
2510 /* XXX: find a suitable condition to enable the hypervisor mode */
a4f30719 2511 new_msr |= (target_ulong)MSR_HVB;
b172c56a 2512 }
41557447
AG
2513
2514 /* machine check exceptions don't have ME set */
2515 new_msr &= ~((target_ulong)1 << MSR_ME);
2516
e1833e1f
JM
2517 /* XXX: should also have something loaded in DAR / DSISR */
2518 switch (excp_model) {
a750fc0b 2519 case POWERPC_EXCP_40x:
e1833e1f
JM
2520 srr0 = SPR_40x_SRR2;
2521 srr1 = SPR_40x_SRR3;
c62db105 2522 break;
a750fc0b 2523 case POWERPC_EXCP_BOOKE:
e1833e1f
JM
2524 srr0 = SPR_BOOKE_MCSRR0;
2525 srr1 = SPR_BOOKE_MCSRR1;
2526 asrr0 = SPR_BOOKE_CSRR0;
2527 asrr1 = SPR_BOOKE_CSRR1;
c62db105
JM
2528 break;
2529 default:
2530 break;
2be0071f 2531 }
e1833e1f
JM
2532 goto store_next;
2533 case POWERPC_EXCP_DSI: /* Data storage exception */
90e189ec
BS
2534 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
2535 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
e1833e1f 2536 if (lpes1 == 0)
a4f30719 2537 new_msr |= (target_ulong)MSR_HVB;
a541f297 2538 goto store_next;
e1833e1f 2539 case POWERPC_EXCP_ISI: /* Instruction storage exception */
90e189ec
BS
2540 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
2541 "\n", msr, env->nip);
e1833e1f 2542 if (lpes1 == 0)
a4f30719 2543 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2544 msr |= env->error_code;
9a64fbe4 2545 goto store_next;
e1833e1f 2546 case POWERPC_EXCP_EXTERNAL: /* External input */
e1833e1f 2547 if (lpes0 == 1)
a4f30719 2548 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2549 goto store_next;
e1833e1f 2550 case POWERPC_EXCP_ALIGN: /* Alignment exception */
e1833e1f 2551 if (lpes1 == 0)
a4f30719 2552 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2553 /* XXX: this is false */
2554 /* Get rS/rD and rA from faulting opcode */
2555 env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
9a64fbe4 2556 goto store_current;
e1833e1f 2557 case POWERPC_EXCP_PROGRAM: /* Program exception */
9a64fbe4 2558 switch (env->error_code & ~0xF) {
e1833e1f
JM
2559 case POWERPC_EXCP_FP:
2560 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
d12d51d5 2561 LOG_EXCP("Ignore floating point exception\n");
7c58044c
JM
2562 env->exception_index = POWERPC_EXCP_NONE;
2563 env->error_code = 0;
9a64fbe4 2564 return;
76a66253 2565 }
e1833e1f 2566 if (lpes1 == 0)
a4f30719 2567 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2568 msr |= 0x00100000;
5b52b991
JM
2569 if (msr_fe0 == msr_fe1)
2570 goto store_next;
2571 msr |= 0x00010000;
76a66253 2572 break;
e1833e1f 2573 case POWERPC_EXCP_INVAL:
90e189ec 2574 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
e1833e1f 2575 if (lpes1 == 0)
a4f30719 2576 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2577 msr |= 0x00080000;
e8906f35 2578 env->spr[SPR_BOOKE_ESR] = ESR_PIL;
76a66253 2579 break;
e1833e1f 2580 case POWERPC_EXCP_PRIV:
e1833e1f 2581 if (lpes1 == 0)
a4f30719 2582 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2583 msr |= 0x00040000;
e8906f35 2584 env->spr[SPR_BOOKE_ESR] = ESR_PPR;
76a66253 2585 break;
e1833e1f 2586 case POWERPC_EXCP_TRAP:
e1833e1f 2587 if (lpes1 == 0)
a4f30719 2588 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2589 msr |= 0x00020000;
e8906f35 2590 env->spr[SPR_BOOKE_ESR] = ESR_PTR;
9a64fbe4
FB
2591 break;
2592 default:
2593 /* Should never occur */
e1833e1f
JM
2594 cpu_abort(env, "Invalid program exception %d. Aborting\n",
2595 env->error_code);
76a66253
JM
2596 break;
2597 }
5b52b991 2598 goto store_current;
e1833e1f 2599 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
e1833e1f 2600 if (lpes1 == 0)
a4f30719 2601 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2602 goto store_current;
2603 case POWERPC_EXCP_SYSCALL: /* System call exception */
93fcfe39 2604 dump_syscall(env);
f9fdea6b 2605 lev = env->error_code;
d569956e
DG
2606 if ((lev == 1) && cpu_ppc_hypercall) {
2607 cpu_ppc_hypercall(env);
2608 return;
2609 }
e1833e1f 2610 if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
a4f30719 2611 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2612 goto store_next;
2613 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
e1833e1f
JM
2614 goto store_current;
2615 case POWERPC_EXCP_DECR: /* Decrementer exception */
e1833e1f 2616 if (lpes1 == 0)
a4f30719 2617 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2618 goto store_next;
2619 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
2620 /* FIT on 4xx */
d12d51d5 2621 LOG_EXCP("FIT exception\n");
9a64fbe4 2622 goto store_next;
e1833e1f 2623 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
d12d51d5 2624 LOG_EXCP("WDT exception\n");
e1833e1f
JM
2625 switch (excp_model) {
2626 case POWERPC_EXCP_BOOKE:
2627 srr0 = SPR_BOOKE_CSRR0;
2628 srr1 = SPR_BOOKE_CSRR1;
2629 break;
2630 default:
2631 break;
2632 }
2be0071f 2633 goto store_next;
e1833e1f 2634 case POWERPC_EXCP_DTLB: /* Data TLB error */
e1833e1f
JM
2635 goto store_next;
2636 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
e1833e1f
JM
2637 goto store_next;
2638 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
2639 switch (excp_model) {
2640 case POWERPC_EXCP_BOOKE:
2641 srr0 = SPR_BOOKE_DSRR0;
2642 srr1 = SPR_BOOKE_DSRR1;
2643 asrr0 = SPR_BOOKE_CSRR0;
2644 asrr1 = SPR_BOOKE_CSRR1;
2645 break;
2646 default:
2647 break;
2648 }
2be0071f 2649 /* XXX: TODO */
e1833e1f 2650 cpu_abort(env, "Debug exception is not implemented yet !\n");
2be0071f 2651 goto store_next;
e1833e1f 2652 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
e8906f35 2653 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
e1833e1f
JM
2654 goto store_current;
2655 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
2be0071f 2656 /* XXX: TODO */
e1833e1f 2657 cpu_abort(env, "Embedded floating point data exception "
2be0071f 2658 "is not implemented yet !\n");
e8906f35 2659 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
2be0071f 2660 goto store_next;
e1833e1f 2661 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
2be0071f 2662 /* XXX: TODO */
e1833e1f
JM
2663 cpu_abort(env, "Embedded floating point round exception "
2664 "is not implemented yet !\n");
e8906f35 2665 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
9a64fbe4 2666 goto store_next;
e1833e1f 2667 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
2be0071f
FB
2668 /* XXX: TODO */
2669 cpu_abort(env,
e1833e1f 2670 "Performance counter exception is not implemented yet !\n");
9a64fbe4 2671 goto store_next;
e1833e1f 2672 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
76a66253 2673 /* XXX: TODO */
e1833e1f
JM
2674 cpu_abort(env,
2675 "Embedded doorbell interrupt is not implemented yet !\n");
2be0071f 2676 goto store_next;
e1833e1f
JM
2677 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
2678 switch (excp_model) {
2679 case POWERPC_EXCP_BOOKE:
2680 srr0 = SPR_BOOKE_CSRR0;
2681 srr1 = SPR_BOOKE_CSRR1;
a750fc0b 2682 break;
2be0071f 2683 default:
2be0071f
FB
2684 break;
2685 }
e1833e1f
JM
2686 /* XXX: TODO */
2687 cpu_abort(env, "Embedded doorbell critical interrupt "
2688 "is not implemented yet !\n");
2689 goto store_next;
e1833e1f 2690 case POWERPC_EXCP_RESET: /* System reset exception */
41557447
AG
2691 if (msr_pow) {
2692 /* indicate that we resumed from power save mode */
2693 msr |= 0x10000;
2694 } else {
2695 new_msr &= ~((target_ulong)1 << MSR_ME);
2696 }
2697
a4f30719
JM
2698 if (0) {
2699 /* XXX: find a suitable condition to enable the hypervisor mode */
2700 new_msr |= (target_ulong)MSR_HVB;
2701 }
e1833e1f 2702 goto store_next;
e1833e1f 2703 case POWERPC_EXCP_DSEG: /* Data segment exception */
e1833e1f 2704 if (lpes1 == 0)
a4f30719 2705 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2706 goto store_next;
2707 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
e1833e1f 2708 if (lpes1 == 0)
a4f30719 2709 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2710 goto store_next;
e1833e1f
JM
2711 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
2712 srr0 = SPR_HSRR0;
f9fdea6b 2713 srr1 = SPR_HSRR1;
a4f30719 2714 new_msr |= (target_ulong)MSR_HVB;
41557447 2715 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
b172c56a 2716 goto store_next;
e1833e1f 2717 case POWERPC_EXCP_TRACE: /* Trace exception */
e1833e1f 2718 if (lpes1 == 0)
a4f30719 2719 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2720 goto store_next;
e1833e1f
JM
2721 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
2722 srr0 = SPR_HSRR0;
f9fdea6b 2723 srr1 = SPR_HSRR1;
a4f30719 2724 new_msr |= (target_ulong)MSR_HVB;
41557447 2725 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f
JM
2726 goto store_next;
2727 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
2728 srr0 = SPR_HSRR0;
f9fdea6b 2729 srr1 = SPR_HSRR1;
a4f30719 2730 new_msr |= (target_ulong)MSR_HVB;
41557447 2731 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f
JM
2732 goto store_next;
2733 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
2734 srr0 = SPR_HSRR0;
f9fdea6b 2735 srr1 = SPR_HSRR1;
a4f30719 2736 new_msr |= (target_ulong)MSR_HVB;
41557447 2737 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f
JM
2738 goto store_next;
2739 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
2740 srr0 = SPR_HSRR0;
f9fdea6b 2741 srr1 = SPR_HSRR1;
a4f30719 2742 new_msr |= (target_ulong)MSR_HVB;
41557447 2743 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f 2744 goto store_next;
e1833e1f 2745 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
e1833e1f 2746 if (lpes1 == 0)
a4f30719 2747 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2748 goto store_current;
2749 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
d12d51d5 2750 LOG_EXCP("PIT exception\n");
e1833e1f
JM
2751 goto store_next;
2752 case POWERPC_EXCP_IO: /* IO error exception */
2753 /* XXX: TODO */
2754 cpu_abort(env, "601 IO error exception is not implemented yet !\n");
2755 goto store_next;
2756 case POWERPC_EXCP_RUNM: /* Run mode exception */
2757 /* XXX: TODO */
2758 cpu_abort(env, "601 run mode exception is not implemented yet !\n");
2759 goto store_next;
2760 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
2761 /* XXX: TODO */
2762 cpu_abort(env, "602 emulation trap exception "
2763 "is not implemented yet !\n");
2764 goto store_next;
2765 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
a4f30719
JM
2766 if (lpes1 == 0) /* XXX: check this */
2767 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2768 switch (excp_model) {
a750fc0b
JM
2769 case POWERPC_EXCP_602:
2770 case POWERPC_EXCP_603:
2771 case POWERPC_EXCP_603E:
2772 case POWERPC_EXCP_G2:
e1833e1f 2773 goto tlb_miss_tgpr;
a750fc0b 2774 case POWERPC_EXCP_7x5:
76a66253 2775 goto tlb_miss;
7dbe11ac
JM
2776 case POWERPC_EXCP_74xx:
2777 goto tlb_miss_74xx;
2be0071f 2778 default:
e1833e1f 2779 cpu_abort(env, "Invalid instruction TLB miss exception\n");
2be0071f
FB
2780 break;
2781 }
e1833e1f
JM
2782 break;
2783 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
a4f30719
JM
2784 if (lpes1 == 0) /* XXX: check this */
2785 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2786 switch (excp_model) {
a750fc0b
JM
2787 case POWERPC_EXCP_602:
2788 case POWERPC_EXCP_603:
2789 case POWERPC_EXCP_603E:
2790 case POWERPC_EXCP_G2:
e1833e1f 2791 goto tlb_miss_tgpr;
a750fc0b 2792 case POWERPC_EXCP_7x5:
76a66253 2793 goto tlb_miss;
7dbe11ac
JM
2794 case POWERPC_EXCP_74xx:
2795 goto tlb_miss_74xx;
2be0071f 2796 default:
e1833e1f 2797 cpu_abort(env, "Invalid data load TLB miss exception\n");
2be0071f
FB
2798 break;
2799 }
e1833e1f
JM
2800 break;
2801 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
a4f30719
JM
2802 if (lpes1 == 0) /* XXX: check this */
2803 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2804 switch (excp_model) {
a750fc0b
JM
2805 case POWERPC_EXCP_602:
2806 case POWERPC_EXCP_603:
2807 case POWERPC_EXCP_603E:
2808 case POWERPC_EXCP_G2:
e1833e1f 2809 tlb_miss_tgpr:
76a66253 2810 /* Swap temporary saved registers with GPRs */
0411a972
JM
2811 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
2812 new_msr |= (target_ulong)1 << MSR_TGPR;
2813 hreg_swap_gpr_tgpr(env);
2814 }
e1833e1f
JM
2815 goto tlb_miss;
2816 case POWERPC_EXCP_7x5:
2817 tlb_miss:
2be0071f 2818#if defined (DEBUG_SOFTWARE_TLB)
93fcfe39 2819 if (qemu_log_enabled()) {
0bf9e31a 2820 const char *es;
76a66253
JM
2821 target_ulong *miss, *cmp;
2822 int en;
1e6784f9 2823 if (excp == POWERPC_EXCP_IFTLB) {
76a66253
JM
2824 es = "I";
2825 en = 'I';
2826 miss = &env->spr[SPR_IMISS];
2827 cmp = &env->spr[SPR_ICMP];
2828 } else {
1e6784f9 2829 if (excp == POWERPC_EXCP_DLTLB)
76a66253
JM
2830 es = "DL";
2831 else
2832 es = "DS";
2833 en = 'D';
2834 miss = &env->spr[SPR_DMISS];
2835 cmp = &env->spr[SPR_DCMP];
2836 }
90e189ec
BS
2837 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
2838 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
2839 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
2840 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
2841 env->error_code);
2be0071f 2842 }
9a64fbe4 2843#endif
2be0071f
FB
2844 msr |= env->crf[0] << 28;
2845 msr |= env->error_code; /* key, D/I, S/L bits */
2846 /* Set way using a LRU mechanism */
76a66253 2847 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
c62db105 2848 break;
7dbe11ac
JM
2849 case POWERPC_EXCP_74xx:
2850 tlb_miss_74xx:
2851#if defined (DEBUG_SOFTWARE_TLB)
93fcfe39 2852 if (qemu_log_enabled()) {
0bf9e31a 2853 const char *es;
7dbe11ac
JM
2854 target_ulong *miss, *cmp;
2855 int en;
2856 if (excp == POWERPC_EXCP_IFTLB) {
2857 es = "I";
2858 en = 'I';
0411a972
JM
2859 miss = &env->spr[SPR_TLBMISS];
2860 cmp = &env->spr[SPR_PTEHI];
7dbe11ac
JM
2861 } else {
2862 if (excp == POWERPC_EXCP_DLTLB)
2863 es = "DL";
2864 else
2865 es = "DS";
2866 en = 'D';
2867 miss = &env->spr[SPR_TLBMISS];
2868 cmp = &env->spr[SPR_PTEHI];
2869 }
90e189ec
BS
2870 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
2871 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
2872 env->error_code);
7dbe11ac
JM
2873 }
2874#endif
2875 msr |= env->error_code; /* key bit */
2876 break;
2be0071f 2877 default:
e1833e1f 2878 cpu_abort(env, "Invalid data store TLB miss exception\n");
2be0071f
FB
2879 break;
2880 }
e1833e1f
JM
2881 goto store_next;
2882 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
2883 /* XXX: TODO */
2884 cpu_abort(env, "Floating point assist exception "
2885 "is not implemented yet !\n");
2886 goto store_next;
b4095fed
JM
2887 case POWERPC_EXCP_DABR: /* Data address breakpoint */
2888 /* XXX: TODO */
2889 cpu_abort(env, "DABR exception is not implemented yet !\n");
2890 goto store_next;
e1833e1f
JM
2891 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
2892 /* XXX: TODO */
2893 cpu_abort(env, "IABR exception is not implemented yet !\n");
2894 goto store_next;
2895 case POWERPC_EXCP_SMI: /* System management interrupt */
2896 /* XXX: TODO */
2897 cpu_abort(env, "SMI exception is not implemented yet !\n");
2898 goto store_next;
2899 case POWERPC_EXCP_THERM: /* Thermal interrupt */
2900 /* XXX: TODO */
2901 cpu_abort(env, "Thermal management exception "
2902 "is not implemented yet !\n");
2903 goto store_next;
2904 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
e1833e1f 2905 if (lpes1 == 0)
a4f30719 2906 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2907 /* XXX: TODO */
2908 cpu_abort(env,
2909 "Performance counter exception is not implemented yet !\n");
2910 goto store_next;
2911 case POWERPC_EXCP_VPUA: /* Vector assist exception */
2912 /* XXX: TODO */
2913 cpu_abort(env, "VPU assist exception is not implemented yet !\n");
2914 goto store_next;
2915 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
2916 /* XXX: TODO */
2917 cpu_abort(env,
2918 "970 soft-patch exception is not implemented yet !\n");
2919 goto store_next;
2920 case POWERPC_EXCP_MAINT: /* Maintenance exception */
2921 /* XXX: TODO */
2922 cpu_abort(env,
2923 "970 maintenance exception is not implemented yet !\n");
2924 goto store_next;
b4095fed
JM
2925 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
2926 /* XXX: TODO */
2927 cpu_abort(env, "Maskable external exception "
2928 "is not implemented yet !\n");
2929 goto store_next;
2930 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
2931 /* XXX: TODO */
2932 cpu_abort(env, "Non maskable external exception "
2933 "is not implemented yet !\n");
2934 goto store_next;
2be0071f 2935 default:
e1833e1f
JM
2936 excp_invalid:
2937 cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
2938 break;
9a64fbe4 2939 store_current:
2be0071f 2940 /* save current instruction location */
e1833e1f 2941 env->spr[srr0] = env->nip - 4;
9a64fbe4
FB
2942 break;
2943 store_next:
2be0071f 2944 /* save next instruction location */
e1833e1f 2945 env->spr[srr0] = env->nip;
9a64fbe4
FB
2946 break;
2947 }
e1833e1f
JM
2948 /* Save MSR */
2949 env->spr[srr1] = msr;
2950 /* If any alternate SRR register are defined, duplicate saved values */
2951 if (asrr0 != -1)
2952 env->spr[asrr0] = env->spr[srr0];
2953 if (asrr1 != -1)
2954 env->spr[asrr1] = env->spr[srr1];
2be0071f 2955 /* If we disactivated any translation, flush TLBs */
0411a972 2956 if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR)))
2be0071f 2957 tlb_flush(env, 1);
41557447
AG
2958
2959 if (msr_ile) {
0411a972 2960 new_msr |= (target_ulong)1 << MSR_LE;
41557447
AG
2961 }
2962
e1833e1f
JM
2963 /* Jump to handler */
2964 vector = env->excp_vectors[excp];
6f2d8978 2965 if (vector == (target_ulong)-1ULL) {
e1833e1f
JM
2966 cpu_abort(env, "Raised an exception without defined vector %d\n",
2967 excp);
2968 }
2969 vector |= env->excp_prefix;
c62db105 2970#if defined(TARGET_PPC64)
e1833e1f 2971 if (excp_model == POWERPC_EXCP_BOOKE) {
0411a972 2972 if (!msr_icm) {
e1833e1f 2973 vector = (uint32_t)vector;
0411a972
JM
2974 } else {
2975 new_msr |= (target_ulong)1 << MSR_CM;
2976 }
c62db105 2977 } else {
6ce0ca12 2978 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
e1833e1f 2979 vector = (uint32_t)vector;
0411a972
JM
2980 } else {
2981 new_msr |= (target_ulong)1 << MSR_SF;
2982 }
c62db105 2983 }
e1833e1f 2984#endif
0411a972
JM
2985 /* XXX: we don't use hreg_store_msr here as already have treated
2986 * any special case that could occur. Just store MSR and update hflags
2987 */
a4f30719 2988 env->msr = new_msr & env->msr_mask;
0411a972 2989 hreg_compute_hflags(env);
e1833e1f
JM
2990 env->nip = vector;
2991 /* Reset exception state */
2992 env->exception_index = POWERPC_EXCP_NONE;
2993 env->error_code = 0;
a586e548 2994
01662f3e
AG
2995 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
2996 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
a586e548
EI
2997 /* XXX: The BookE changes address space when switching modes,
2998 we should probably implement that as different MMU indexes,
2999 but for the moment we do it the slow way and flush all. */
3000 tlb_flush(env, 1);
3001 }
fb0eaffc 3002}
47103572 3003
e1833e1f 3004void do_interrupt (CPUState *env)
47103572 3005{
e1833e1f
JM
3006 powerpc_excp(env, env->excp_model, env->exception_index);
3007}
47103572 3008
e1833e1f
JM
3009void ppc_hw_interrupt (CPUPPCState *env)
3010{
f9fdea6b 3011 int hdice;
f9fdea6b 3012
0411a972 3013#if 0
93fcfe39 3014 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
a496775f 3015 __func__, env, env->pending_interrupts,
0411a972 3016 env->interrupt_request, (int)msr_me, (int)msr_ee);
47103572 3017#endif
e1833e1f 3018 /* External reset */
47103572 3019 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
47103572 3020 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
e1833e1f
JM
3021 powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
3022 return;
3023 }
3024 /* Machine check exception */
3025 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
3026 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
3027 powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
3028 return;
47103572 3029 }
e1833e1f
JM
3030#if 0 /* TODO */
3031 /* External debug exception */
3032 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
3033 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
3034 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
3035 return;
3036 }
3037#endif
b172c56a
JM
3038 if (0) {
3039 /* XXX: find a suitable condition to enable the hypervisor mode */
3040 hdice = env->spr[SPR_LPCR] & 1;
3041 } else {
3042 hdice = 0;
3043 }
f9fdea6b 3044 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
47103572
JM
3045 /* Hypervisor decrementer exception */
3046 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
47103572 3047 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
e1833e1f
JM
3048 powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
3049 return;
3050 }
3051 }
e1833e1f
JM
3052 if (msr_ce != 0) {
3053 /* External critical interrupt */
3054 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
3055 /* Taking a critical external interrupt does not clear the external
3056 * critical interrupt status
3057 */
3058#if 0
3059 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
47103572 3060#endif
e1833e1f
JM
3061 powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
3062 return;
3063 }
3064 }
3065 if (msr_ee != 0) {
3066 /* Watchdog timer on embedded PowerPC */
3067 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
3068 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
3069 powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
3070 return;
3071 }
e1833e1f
JM
3072 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
3073 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
3074 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
3075 return;
3076 }
e1833e1f
JM
3077 /* Fixed interval timer on embedded PowerPC */
3078 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
3079 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
3080 powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
3081 return;
3082 }
3083 /* Programmable interval timer on embedded PowerPC */
3084 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
3085 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
3086 powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
3087 return;
3088 }
47103572
JM
3089 /* Decrementer exception */
3090 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
47103572 3091 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
e1833e1f
JM
3092 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
3093 return;
3094 }
47103572 3095 /* External interrupt */
e1833e1f 3096 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
e9df014c
JM
3097 /* Taking an external interrupt does not clear the external
3098 * interrupt status
3099 */
3100#if 0
47103572 3101 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
e9df014c 3102#endif
e1833e1f
JM
3103 powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
3104 return;
3105 }
e1833e1f
JM
3106 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
3107 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
3108 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
3109 return;
47103572 3110 }
e1833e1f
JM
3111 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
3112 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
3113 powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
3114 return;
3115 }
3116 /* Thermal interrupt */
3117 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
3118 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
3119 powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
3120 return;
3121 }
47103572 3122 }
47103572 3123}
18fba28c 3124#endif /* !CONFIG_USER_ONLY */
a496775f 3125
4a057712
JM
3126void cpu_dump_rfi (target_ulong RA, target_ulong msr)
3127{
90e189ec
BS
3128 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
3129 TARGET_FMT_lx "\n", RA, msr);
a496775f
JM
3130}
3131
d84bda46 3132void cpu_reset(CPUPPCState *env)
0a032cbe 3133{
0411a972 3134 target_ulong msr;
0a032cbe 3135
eca1bdf4
AL
3136 if (qemu_loglevel_mask(CPU_LOG_RESET)) {
3137 qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
3138 log_cpu_state(env, 0);
3139 }
3140
0411a972 3141 msr = (target_ulong)0;
a4f30719
JM
3142 if (0) {
3143 /* XXX: find a suitable condition to enable the hypervisor mode */
3144 msr |= (target_ulong)MSR_HVB;
3145 }
0411a972
JM
3146 msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
3147 msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
3148 msr |= (target_ulong)1 << MSR_EP;
0a032cbe
JM
3149#if defined (DO_SINGLE_STEP) && 0
3150 /* Single step trace mode */
0411a972
JM
3151 msr |= (target_ulong)1 << MSR_SE;
3152 msr |= (target_ulong)1 << MSR_BE;
0a032cbe
JM
3153#endif
3154#if defined(CONFIG_USER_ONLY)
0411a972 3155 msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
4c2ab988
AJ
3156 msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
3157 msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
0411a972 3158 msr |= (target_ulong)1 << MSR_PR;
fe33cc71 3159#else
fc1c67bc 3160 env->excp_prefix = env->hreset_excp_prefix;
1c27f8fb 3161 env->nip = env->hreset_vector | env->excp_prefix;
b4095fed 3162 if (env->mmu_model != POWERPC_MMU_REAL)
141c8ae2 3163 ppc_tlb_invalidate_all(env);
0a032cbe 3164#endif
07c485ce 3165 env->msr = msr & env->msr_mask;
6ce0ca12
BS
3166#if defined(TARGET_PPC64)
3167 if (env->mmu_model & POWERPC_MMU_64)
3168 env->msr |= (1ULL << MSR_SF);
3169#endif
0411a972 3170 hreg_compute_hflags(env);
18b21a2f 3171 env->reserve_addr = (target_ulong)-1ULL;
5eb7995e
JM
3172 /* Be sure no exception or interrupt is pending */
3173 env->pending_interrupts = 0;
e1833e1f
JM
3174 env->exception_index = POWERPC_EXCP_NONE;
3175 env->error_code = 0;
5eb7995e
JM
3176 /* Flush all TLBs */
3177 tlb_flush(env, 1);
0a032cbe
JM
3178}
3179
aaed909a 3180CPUPPCState *cpu_ppc_init (const char *cpu_model)
0a032cbe
JM
3181{
3182 CPUPPCState *env;
c227f099 3183 const ppc_def_t *def;
aaed909a
FB
3184
3185 def = cpu_ppc_find_by_name(cpu_model);
3186 if (!def)
3187 return NULL;
0a032cbe 3188
7267c094 3189 env = g_malloc0(sizeof(CPUPPCState));
0a032cbe 3190 cpu_exec_init(env);
d5ab9713
JK
3191 if (tcg_enabled()) {
3192 ppc_translate_init();
3193 }
e97c3636
DG
3194 /* Adjust cpu index for SMT */
3195#if !defined(CONFIG_USER_ONLY)
3196 if (kvm_enabled()) {
3197 int smt = kvmppc_smt_threads();
3198
3199 env->cpu_index = (env->cpu_index / smp_threads)*smt
3200 + (env->cpu_index % smp_threads);
3201 }
3202#endif /* !CONFIG_USER_ONLY */
01ba9816 3203 env->cpu_model_str = cpu_model;
aaed909a 3204 cpu_ppc_register_internal(env, def);
d76d1650 3205
0bf46a40 3206 qemu_init_vcpu(env);
d76d1650 3207
0a032cbe
JM
3208 return env;
3209}
3210
3211void cpu_ppc_close (CPUPPCState *env)
3212{
3213 /* Should also remove all opcode tables... */
7267c094 3214 g_free(env);
0a032cbe 3215}