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