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