]> git.proxmox.com Git - mirror_qemu.git/blame - target-ppc/helper.c
Implement the bus structure for PAPR virtual IO
[mirror_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) {
fda6a0ec
DG
592 pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
593 pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
5b5aba4f
BS
594
595 /* We have a TLB that saves 4K pages, so let's
596 * split a huge page to 4k chunks */
597 if (target_page_bits != TARGET_PAGE_BITS)
598 pte1 |= (ctx->eaddr & (( 1 << target_page_bits ) - 1))
599 & TARGET_PAGE_MASK;
600
b227a8e9 601 r = pte64_check(ctx, pte0, pte1, h, rw, type);
90e189ec
BS
602 LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
603 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
fda6a0ec 604 pteg_base + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
90e189ec 605 (int)((pte0 >> 1) & 1), ctx->ptem);
caa4039c
JM
606 } else
607#endif
608 {
fda6a0ec
DG
609 pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
610 pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
b227a8e9 611 r = pte32_check(ctx, pte0, pte1, h, rw, type);
90e189ec
BS
612 LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
613 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
fda6a0ec 614 pteg_base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
90e189ec 615 (int)((pte0 >> 6) & 1), ctx->ptem);
12de9a39 616 }
caa4039c 617 switch (r) {
76a66253
JM
618 case -3:
619 /* PTE inconsistency */
620 return -1;
621 case -2:
622 /* Access violation */
623 ret = -2;
624 good = i;
625 break;
626 case -1:
627 default:
628 /* No PTE match */
629 break;
630 case 0:
631 /* access granted */
632 /* XXX: we should go on looping to check all PTEs consistency
633 * but if we can speed-up the whole thing as the
634 * result would be undefined if PTEs are not consistent.
635 */
636 ret = 0;
637 good = i;
638 goto done;
9a64fbe4
FB
639 }
640 }
641 if (good != -1) {
76a66253 642 done:
90e189ec
BS
643 LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n",
644 ctx->raddr, ctx->prot, ret);
9a64fbe4 645 /* Update page flags */
76a66253 646 pte1 = ctx->raddr;
caa4039c
JM
647 if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
648#if defined(TARGET_PPC64)
649 if (is_64b) {
fda6a0ec
DG
650 stq_phys_notdirty(env->htab_base + pteg_off + (good * 16) + 8,
651 pte1);
caa4039c
JM
652 } else
653#endif
654 {
fda6a0ec
DG
655 stl_phys_notdirty(env->htab_base + pteg_off + (good * 8) + 4,
656 pte1);
caa4039c
JM
657 }
658 }
9a64fbe4
FB
659 }
660
661 return ret;
79aceca5
FB
662}
663
c227f099 664static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
636aa200 665 int type, int target_page_bits)
caa4039c
JM
666{
667#if defined(TARGET_PPC64)
add78955 668 if (env->mmu_model & POWERPC_MMU_64)
256cebe5 669 return _find_pte(env, ctx, 1, h, rw, type, target_page_bits);
caa4039c
JM
670#endif
671
256cebe5 672 return _find_pte(env, ctx, 0, h, rw, type, target_page_bits);
caa4039c
JM
673}
674
caa4039c 675#if defined(TARGET_PPC64)
8500e3a9 676static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
caa4039c 677{
cdaee006 678 uint64_t esid_256M, esid_1T;
81762d6d 679 int n;
caa4039c 680
90e189ec 681 LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
81762d6d 682
cdaee006
DG
683 esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
684 esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
81762d6d 685
eacc3249 686 for (n = 0; n < env->slb_nr; n++) {
81762d6d
DG
687 ppc_slb_t *slb = &env->slb[n];
688
689 LOG_SLB("%s: slot %d %016" PRIx64 " %016"
690 PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
cdaee006
DG
691 /* We check for 1T matches on all MMUs here - if the MMU
692 * doesn't have 1T segment support, we will have prevented 1T
693 * entries from being inserted in the slbmte code. */
694 if (((slb->esid == esid_256M) &&
695 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
696 || ((slb->esid == esid_1T) &&
697 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
8500e3a9 698 return slb;
caa4039c 699 }
caa4039c
JM
700 }
701
8500e3a9 702 return NULL;
79aceca5 703}
12de9a39 704
eacc3249
JM
705void ppc_slb_invalidate_all (CPUPPCState *env)
706{
eacc3249
JM
707 int n, do_invalidate;
708
709 do_invalidate = 0;
2c1ee068
JM
710 /* XXX: Warning: slbia never invalidates the first segment */
711 for (n = 1; n < env->slb_nr; n++) {
81762d6d 712 ppc_slb_t *slb = &env->slb[n];
8eee0af9 713
81762d6d
DG
714 if (slb->esid & SLB_ESID_V) {
715 slb->esid &= ~SLB_ESID_V;
eacc3249
JM
716 /* XXX: given the fact that segment size is 256 MB or 1TB,
717 * and we still don't have a tlb_flush_mask(env, n, mask)
718 * in Qemu, we just invalidate all TLBs
719 */
720 do_invalidate = 1;
721 }
eacc3249
JM
722 }
723 if (do_invalidate)
724 tlb_flush(env, 1);
725}
726
727void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
728{
81762d6d 729 ppc_slb_t *slb;
eacc3249 730
8500e3a9
DG
731 slb = slb_lookup(env, T0);
732 if (!slb) {
81762d6d 733 return;
eacc3249 734 }
eacc3249 735
81762d6d
DG
736 if (slb->esid & SLB_ESID_V) {
737 slb->esid &= ~SLB_ESID_V;
12de9a39 738
81762d6d
DG
739 /* XXX: given the fact that segment size is 256 MB or 1TB,
740 * and we still don't have a tlb_flush_mask(env, n, mask)
741 * in Qemu, we just invalidate all TLBs
742 */
743 tlb_flush(env, 1);
744 }
12de9a39
JM
745}
746
81762d6d 747int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
12de9a39 748{
81762d6d 749 int slot = rb & 0xfff;
81762d6d 750 ppc_slb_t *slb = &env->slb[slot];
f6b868fc 751
cdaee006
DG
752 if (rb & (0x1000 - env->slb_nr)) {
753 return -1; /* Reserved bits set or slot too high */
754 }
755 if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
756 return -1; /* Bad segment size */
757 }
758 if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
759 return -1; /* 1T segment on MMU that doesn't support it */
81762d6d 760 }
f6b868fc 761
cdaee006
DG
762 /* Mask out the slot number as we store the entry */
763 slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
81762d6d 764 slb->vsid = rs;
f6b868fc 765
90e189ec 766 LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
81762d6d
DG
767 " %016" PRIx64 "\n", __func__, slot, rb, rs,
768 slb->esid, slb->vsid);
f6b868fc 769
81762d6d 770 return 0;
12de9a39 771}
efdef95f
DG
772
773int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
774{
775 int slot = rb & 0xfff;
776 ppc_slb_t *slb = &env->slb[slot];
777
778 if (slot >= env->slb_nr) {
779 return -1;
780 }
781
782 *rt = slb->esid;
783 return 0;
784}
785
786int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
787{
788 int slot = rb & 0xfff;
789 ppc_slb_t *slb = &env->slb[slot];
790
791 if (slot >= env->slb_nr) {
792 return -1;
793 }
794
795 *rt = slb->vsid;
796 return 0;
797}
caa4039c 798#endif /* defined(TARGET_PPC64) */
79aceca5 799
9a64fbe4 800/* Perform segment based translation */
c227f099 801static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
636aa200 802 target_ulong eaddr, int rw, int type)
79aceca5 803{
bb593904 804 target_phys_addr_t hash;
256cebe5 805 target_ulong vsid;
fda6a0ec 806 int ds, pr, target_page_bits;
caa4039c
JM
807 int ret, ret2;
808
0411a972 809 pr = msr_pr;
256cebe5 810 ctx->eaddr = eaddr;
caa4039c 811#if defined(TARGET_PPC64)
add78955 812 if (env->mmu_model & POWERPC_MMU_64) {
8500e3a9 813 ppc_slb_t *slb;
256cebe5 814 target_ulong pageaddr;
cdaee006 815 int segment_bits;
81762d6d 816
d12d51d5 817 LOG_MMU("Check SLBs\n");
8500e3a9
DG
818 slb = slb_lookup(env, eaddr);
819 if (!slb) {
820 return -5;
821 }
822
cdaee006
DG
823 if (slb->vsid & SLB_VSID_B) {
824 vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
825 segment_bits = 40;
826 } else {
827 vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
828 segment_bits = 28;
829 }
830
8500e3a9
DG
831 target_page_bits = (slb->vsid & SLB_VSID_L)
832 ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
833 ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
834 : (slb->vsid & SLB_VSID_KS));
caa4039c 835 ds = 0;
8500e3a9 836 ctx->nx = !!(slb->vsid & SLB_VSID_N);
256cebe5 837
cdaee006
DG
838 pageaddr = eaddr & ((1ULL << segment_bits)
839 - (1ULL << target_page_bits));
840 if (slb->vsid & SLB_VSID_B) {
841 hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
842 } else {
843 hash = vsid ^ (pageaddr >> target_page_bits);
844 }
256cebe5 845 /* Only 5 bits of the page index are used in the AVPN */
cdaee006
DG
846 ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
847 ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
caa4039c
JM
848 } else
849#endif /* defined(TARGET_PPC64) */
850 {
256cebe5
DG
851 target_ulong sr, pgidx;
852
caa4039c 853 sr = env->sr[eaddr >> 28];
0411a972
JM
854 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
855 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
caa4039c 856 ds = sr & 0x80000000 ? 1 : 0;
b227a8e9 857 ctx->nx = sr & 0x10000000 ? 1 : 0;
caa4039c 858 vsid = sr & 0x00FFFFFF;
5b5aba4f 859 target_page_bits = TARGET_PAGE_BITS;
90e189ec
BS
860 LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
861 TARGET_FMT_lx " lr=" TARGET_FMT_lx
862 " ir=%d dr=%d pr=%d %d t=%d\n",
863 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
864 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
256cebe5
DG
865 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
866 hash = vsid ^ pgidx;
867 ctx->ptem = (vsid << 7) | (pgidx >> 10);
caa4039c 868 }
90e189ec
BS
869 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
870 ctx->key, ds, ctx->nx, vsid);
caa4039c
JM
871 ret = -1;
872 if (!ds) {
9a64fbe4 873 /* Check if instruction fetch is allowed, if needed */
b227a8e9 874 if (type != ACCESS_CODE || ctx->nx == 0) {
9a64fbe4 875 /* Page address translation */
bb593904
DG
876 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
877 " hash " TARGET_FMT_plx "\n",
878 env->htab_base, env->htab_mask, hash);
fda6a0ec
DG
879 ctx->hash[0] = hash;
880 ctx->hash[1] = ~hash;
881
76a66253 882 /* Initialize real address with an invalid value */
c227f099 883 ctx->raddr = (target_phys_addr_t)-1ULL;
7dbe11ac
JM
884 if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
885 env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
76a66253
JM
886 /* Software TLB search */
887 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
76a66253 888 } else {
bb593904 889 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
256cebe5 890 " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
fda6a0ec 891 " hash=" TARGET_FMT_plx "\n",
256cebe5 892 env->htab_base, env->htab_mask, vsid, ctx->ptem,
fda6a0ec 893 ctx->hash[0]);
76a66253 894 /* Primary table lookup */
5b5aba4f 895 ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
76a66253
JM
896 if (ret < 0) {
897 /* Secondary table lookup */
d12d51d5 898 if (eaddr != 0xEFFFFFFF)
bb593904
DG
899 LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
900 " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
901 " hash=" TARGET_FMT_plx " pg_addr="
902 TARGET_FMT_plx "\n", env->htab_base,
256cebe5 903 env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
5b5aba4f
BS
904 ret2 = find_pte(env, ctx, 1, rw, type,
905 target_page_bits);
76a66253
JM
906 if (ret2 != -1)
907 ret = ret2;
908 }
9a64fbe4 909 }
0411a972 910#if defined (DUMP_PAGE_TABLES)
93fcfe39 911 if (qemu_log_enabled()) {
c227f099 912 target_phys_addr_t curaddr;
b33c17e1 913 uint32_t a0, a1, a2, a3;
90e189ec
BS
914 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
915 "\n", sdr, mask + 0x80);
b33c17e1
JM
916 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
917 curaddr += 16) {
918 a0 = ldl_phys(curaddr);
919 a1 = ldl_phys(curaddr + 4);
920 a2 = ldl_phys(curaddr + 8);
921 a3 = ldl_phys(curaddr + 12);
922 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
90e189ec
BS
923 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
924 curaddr, a0, a1, a2, a3);
12de9a39 925 }
b33c17e1
JM
926 }
927 }
12de9a39 928#endif
9a64fbe4 929 } else {
d12d51d5 930 LOG_MMU("No access allowed\n");
76a66253 931 ret = -3;
9a64fbe4
FB
932 }
933 } else {
d12d51d5 934 LOG_MMU("direct store...\n");
9a64fbe4
FB
935 /* Direct-store segment : absolutely *BUGGY* for now */
936 switch (type) {
937 case ACCESS_INT:
938 /* Integer load/store : only access allowed */
939 break;
940 case ACCESS_CODE:
941 /* No code fetch is allowed in direct-store areas */
942 return -4;
943 case ACCESS_FLOAT:
944 /* Floating point load/store */
945 return -4;
946 case ACCESS_RES:
947 /* lwarx, ldarx or srwcx. */
948 return -4;
949 case ACCESS_CACHE:
950 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
951 /* Should make the instruction do no-op.
952 * As it already do no-op, it's quite easy :-)
953 */
76a66253 954 ctx->raddr = eaddr;
9a64fbe4
FB
955 return 0;
956 case ACCESS_EXT:
957 /* eciwx or ecowx */
958 return -4;
959 default:
93fcfe39 960 qemu_log("ERROR: instruction should not need "
9a64fbe4 961 "address translation\n");
9a64fbe4
FB
962 return -4;
963 }
76a66253
JM
964 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
965 ctx->raddr = eaddr;
9a64fbe4
FB
966 ret = 2;
967 } else {
968 ret = -2;
969 }
79aceca5 970 }
9a64fbe4
FB
971
972 return ret;
79aceca5
FB
973}
974
c294fc58 975/* Generic TLB check function for embedded PowerPC implementations */
c227f099
AL
976static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
977 target_phys_addr_t *raddrp,
636aa200
BS
978 target_ulong address, uint32_t pid, int ext,
979 int i)
c294fc58
JM
980{
981 target_ulong mask;
982
983 /* Check valid flag */
984 if (!(tlb->prot & PAGE_VALID)) {
c294fc58
JM
985 return -1;
986 }
987 mask = ~(tlb->size - 1);
90e189ec
BS
988 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
989 " " TARGET_FMT_lx " %u\n", __func__, i, address, pid, tlb->EPN,
990 mask, (uint32_t)tlb->PID);
c294fc58 991 /* Check PID */
36081602 992 if (tlb->PID != 0 && tlb->PID != pid)
c294fc58
JM
993 return -1;
994 /* Check effective address */
995 if ((address & mask) != tlb->EPN)
996 return -1;
997 *raddrp = (tlb->RPN & mask) | (address & ~mask);
9706285b 998#if (TARGET_PHYS_ADDR_BITS >= 36)
36081602
JM
999 if (ext) {
1000 /* Extend the physical address to 36 bits */
c227f099 1001 *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
36081602 1002 }
9706285b 1003#endif
c294fc58
JM
1004
1005 return 0;
1006}
1007
1008/* Generic TLB search function for PowerPC embedded implementations */
36081602 1009int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
c294fc58 1010{
c227f099
AL
1011 ppcemb_tlb_t *tlb;
1012 target_phys_addr_t raddr;
c294fc58
JM
1013 int i, ret;
1014
1015 /* Default return value is no match */
1016 ret = -1;
a750fc0b 1017 for (i = 0; i < env->nb_tlb; i++) {
c294fc58 1018 tlb = &env->tlb[i].tlbe;
36081602 1019 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
c294fc58
JM
1020 ret = i;
1021 break;
1022 }
1023 }
1024
1025 return ret;
1026}
1027
daf4f96e 1028/* Helpers specific to PowerPC 40x implementations */
636aa200 1029static inline void ppc4xx_tlb_invalidate_all(CPUState *env)
a750fc0b 1030{
c227f099 1031 ppcemb_tlb_t *tlb;
a750fc0b
JM
1032 int i;
1033
1034 for (i = 0; i < env->nb_tlb; i++) {
1035 tlb = &env->tlb[i].tlbe;
daf4f96e 1036 tlb->prot &= ~PAGE_VALID;
a750fc0b 1037 }
daf4f96e 1038 tlb_flush(env, 1);
a750fc0b
JM
1039}
1040
636aa200
BS
1041static inline void ppc4xx_tlb_invalidate_virt(CPUState *env,
1042 target_ulong eaddr, uint32_t pid)
0a032cbe 1043{
daf4f96e 1044#if !defined(FLUSH_ALL_TLBS)
c227f099
AL
1045 ppcemb_tlb_t *tlb;
1046 target_phys_addr_t raddr;
daf4f96e 1047 target_ulong page, end;
0a032cbe
JM
1048 int i;
1049
1050 for (i = 0; i < env->nb_tlb; i++) {
1051 tlb = &env->tlb[i].tlbe;
daf4f96e 1052 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
0a032cbe
JM
1053 end = tlb->EPN + tlb->size;
1054 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
1055 tlb_flush_page(env, page);
0a032cbe 1056 tlb->prot &= ~PAGE_VALID;
daf4f96e 1057 break;
0a032cbe
JM
1058 }
1059 }
daf4f96e
JM
1060#else
1061 ppc4xx_tlb_invalidate_all(env);
1062#endif
0a032cbe
JM
1063}
1064
c227f099 1065static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
e96efcfc 1066 target_ulong address, int rw, int access_type)
a8dea12f 1067{
c227f099
AL
1068 ppcemb_tlb_t *tlb;
1069 target_phys_addr_t raddr;
0411a972 1070 int i, ret, zsel, zpr, pr;
3b46e624 1071
c55e9aef 1072 ret = -1;
c227f099 1073 raddr = (target_phys_addr_t)-1ULL;
0411a972 1074 pr = msr_pr;
a8dea12f
JM
1075 for (i = 0; i < env->nb_tlb; i++) {
1076 tlb = &env->tlb[i].tlbe;
36081602
JM
1077 if (ppcemb_tlb_check(env, tlb, &raddr, address,
1078 env->spr[SPR_40x_PID], 0, i) < 0)
a8dea12f 1079 continue;
a8dea12f 1080 zsel = (tlb->attr >> 4) & 0xF;
ec5c3e48 1081 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
d12d51d5 1082 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
a8dea12f 1083 __func__, i, zsel, zpr, rw, tlb->attr);
b227a8e9
JM
1084 /* Check execute enable bit */
1085 switch (zpr) {
1086 case 0x2:
0411a972 1087 if (pr != 0)
b227a8e9
JM
1088 goto check_perms;
1089 /* No break here */
1090 case 0x3:
1091 /* All accesses granted */
1092 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1093 ret = 0;
1094 break;
1095 case 0x0:
0411a972 1096 if (pr != 0) {
dcbc9a70
EI
1097 /* Raise Zone protection fault. */
1098 env->spr[SPR_40x_ESR] = 1 << 22;
b227a8e9
JM
1099 ctx->prot = 0;
1100 ret = -2;
a8dea12f
JM
1101 break;
1102 }
b227a8e9
JM
1103 /* No break here */
1104 case 0x1:
1105 check_perms:
1106 /* Check from TLB entry */
b227a8e9 1107 ctx->prot = tlb->prot;
b227a8e9 1108 ret = check_prot(ctx->prot, rw, access_type);
dcbc9a70
EI
1109 if (ret == -2)
1110 env->spr[SPR_40x_ESR] = 0;
b227a8e9 1111 break;
a8dea12f
JM
1112 }
1113 if (ret >= 0) {
1114 ctx->raddr = raddr;
90e189ec
BS
1115 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1116 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1117 ret);
c55e9aef 1118 return 0;
a8dea12f
JM
1119 }
1120 }
90e189ec
BS
1121 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1122 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
3b46e624 1123
a8dea12f
JM
1124 return ret;
1125}
1126
c294fc58
JM
1127void store_40x_sler (CPUPPCState *env, uint32_t val)
1128{
1129 /* XXX: TO BE FIXED */
1130 if (val != 0x00000000) {
1131 cpu_abort(env, "Little-endian regions are not supported by now\n");
1132 }
1133 env->spr[SPR_405_SLER] = val;
1134}
1135
c227f099 1136static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
93220573
AJ
1137 target_ulong address, int rw,
1138 int access_type)
5eb7995e 1139{
c227f099
AL
1140 ppcemb_tlb_t *tlb;
1141 target_phys_addr_t raddr;
5eb7995e
JM
1142 int i, prot, ret;
1143
1144 ret = -1;
c227f099 1145 raddr = (target_phys_addr_t)-1ULL;
5eb7995e
JM
1146 for (i = 0; i < env->nb_tlb; i++) {
1147 tlb = &env->tlb[i].tlbe;
1148 if (ppcemb_tlb_check(env, tlb, &raddr, address,
1149 env->spr[SPR_BOOKE_PID], 1, i) < 0)
1150 continue;
0411a972 1151 if (msr_pr != 0)
5eb7995e
JM
1152 prot = tlb->prot & 0xF;
1153 else
1154 prot = (tlb->prot >> 4) & 0xF;
1155 /* Check the address space */
1156 if (access_type == ACCESS_CODE) {
d26bfc9a 1157 if (msr_ir != (tlb->attr & 1))
5eb7995e
JM
1158 continue;
1159 ctx->prot = prot;
1160 if (prot & PAGE_EXEC) {
1161 ret = 0;
1162 break;
1163 }
1164 ret = -3;
1165 } else {
d26bfc9a 1166 if (msr_dr != (tlb->attr & 1))
5eb7995e
JM
1167 continue;
1168 ctx->prot = prot;
1169 if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
1170 ret = 0;
1171 break;
1172 }
1173 ret = -2;
1174 }
1175 }
1176 if (ret >= 0)
1177 ctx->raddr = raddr;
1178
1179 return ret;
1180}
1181
c227f099 1182static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
636aa200 1183 target_ulong eaddr, int rw)
76a66253
JM
1184{
1185 int in_plb, ret;
3b46e624 1186
76a66253 1187 ctx->raddr = eaddr;
b227a8e9 1188 ctx->prot = PAGE_READ | PAGE_EXEC;
76a66253 1189 ret = 0;
a750fc0b
JM
1190 switch (env->mmu_model) {
1191 case POWERPC_MMU_32B:
faadf50e 1192 case POWERPC_MMU_601:
a750fc0b 1193 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 1194 case POWERPC_MMU_SOFT_74xx:
a750fc0b 1195 case POWERPC_MMU_SOFT_4xx:
b4095fed 1196 case POWERPC_MMU_REAL:
7dbe11ac 1197 case POWERPC_MMU_BOOKE:
caa4039c
JM
1198 ctx->prot |= PAGE_WRITE;
1199 break;
1200#if defined(TARGET_PPC64)
add78955 1201 case POWERPC_MMU_620:
a750fc0b 1202 case POWERPC_MMU_64B:
9d52e907 1203 case POWERPC_MMU_2_06:
caa4039c 1204 /* Real address are 60 bits long */
a750fc0b 1205 ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
caa4039c
JM
1206 ctx->prot |= PAGE_WRITE;
1207 break;
9706285b 1208#endif
a750fc0b 1209 case POWERPC_MMU_SOFT_4xx_Z:
caa4039c
JM
1210 if (unlikely(msr_pe != 0)) {
1211 /* 403 family add some particular protections,
1212 * using PBL/PBU registers for accesses with no translation.
1213 */
1214 in_plb =
1215 /* Check PLB validity */
1216 (env->pb[0] < env->pb[1] &&
1217 /* and address in plb area */
1218 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1219 (env->pb[2] < env->pb[3] &&
1220 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1221 if (in_plb ^ msr_px) {
1222 /* Access in protected area */
1223 if (rw == 1) {
1224 /* Access is not allowed */
1225 ret = -2;
1226 }
1227 } else {
1228 /* Read-write access is allowed */
1229 ctx->prot |= PAGE_WRITE;
76a66253 1230 }
76a66253 1231 }
e1833e1f 1232 break;
b4095fed
JM
1233 case POWERPC_MMU_MPC8xx:
1234 /* XXX: TODO */
1235 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1236 break;
a750fc0b 1237 case POWERPC_MMU_BOOKE_FSL:
caa4039c
JM
1238 /* XXX: TODO */
1239 cpu_abort(env, "BookE FSL MMU model not implemented\n");
1240 break;
1241 default:
1242 cpu_abort(env, "Unknown or invalid MMU model\n");
1243 return -1;
76a66253
JM
1244 }
1245
1246 return ret;
1247}
1248
c227f099 1249int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
faadf50e 1250 int rw, int access_type)
9a64fbe4
FB
1251{
1252 int ret;
0411a972 1253
514fb8c1 1254#if 0
93fcfe39 1255 qemu_log("%s\n", __func__);
d9bce9d9 1256#endif
4b3686fa
FB
1257 if ((access_type == ACCESS_CODE && msr_ir == 0) ||
1258 (access_type != ACCESS_CODE && msr_dr == 0)) {
a586e548
EI
1259 if (env->mmu_model == POWERPC_MMU_BOOKE) {
1260 /* The BookE MMU always performs address translation. The
1261 IS and DS bits only affect the address space. */
1262 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1263 rw, access_type);
1264 } else {
1265 /* No address translation. */
1266 ret = check_physical(env, ctx, eaddr, rw);
1267 }
9a64fbe4 1268 } else {
c55e9aef 1269 ret = -1;
a750fc0b
JM
1270 switch (env->mmu_model) {
1271 case POWERPC_MMU_32B:
faadf50e 1272 case POWERPC_MMU_601:
a750fc0b 1273 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 1274 case POWERPC_MMU_SOFT_74xx:
94855937
BS
1275 /* Try to find a BAT */
1276 if (env->nb_BATs != 0)
1277 ret = get_bat(env, ctx, eaddr, rw, access_type);
c55e9aef 1278#if defined(TARGET_PPC64)
add78955 1279 case POWERPC_MMU_620:
a750fc0b 1280 case POWERPC_MMU_64B:
9d52e907 1281 case POWERPC_MMU_2_06:
c55e9aef 1282#endif
a8dea12f 1283 if (ret < 0) {
c55e9aef 1284 /* We didn't match any BAT entry or don't have BATs */
a8dea12f
JM
1285 ret = get_segment(env, ctx, eaddr, rw, access_type);
1286 }
1287 break;
a750fc0b
JM
1288 case POWERPC_MMU_SOFT_4xx:
1289 case POWERPC_MMU_SOFT_4xx_Z:
36081602 1290 ret = mmu40x_get_physical_address(env, ctx, eaddr,
a8dea12f
JM
1291 rw, access_type);
1292 break;
a750fc0b 1293 case POWERPC_MMU_BOOKE:
5eb7995e
JM
1294 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1295 rw, access_type);
1296 break;
b4095fed
JM
1297 case POWERPC_MMU_MPC8xx:
1298 /* XXX: TODO */
1299 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1300 break;
a750fc0b 1301 case POWERPC_MMU_BOOKE_FSL:
c55e9aef
JM
1302 /* XXX: TODO */
1303 cpu_abort(env, "BookE FSL MMU model not implemented\n");
1304 return -1;
b4095fed
JM
1305 case POWERPC_MMU_REAL:
1306 cpu_abort(env, "PowerPC in real mode do not do any translation\n");
2662a059 1307 return -1;
c55e9aef
JM
1308 default:
1309 cpu_abort(env, "Unknown or invalid MMU model\n");
a8dea12f 1310 return -1;
9a64fbe4
FB
1311 }
1312 }
514fb8c1 1313#if 0
90e189ec
BS
1314 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1315 __func__, eaddr, ret, ctx->raddr);
76a66253 1316#endif
d9bce9d9 1317
9a64fbe4
FB
1318 return ret;
1319}
1320
c227f099 1321target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
a6b025d3 1322{
c227f099 1323 mmu_ctx_t ctx;
a6b025d3 1324
faadf50e 1325 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0))
a6b025d3 1326 return -1;
76a66253
JM
1327
1328 return ctx.raddr & TARGET_PAGE_MASK;
a6b025d3 1329}
9a64fbe4 1330
9a64fbe4 1331/* Perform address translation */
e96efcfc 1332int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
6ebbf390 1333 int mmu_idx, int is_softmmu)
9a64fbe4 1334{
c227f099 1335 mmu_ctx_t ctx;
a541f297 1336 int access_type;
9a64fbe4 1337 int ret = 0;
d9bce9d9 1338
b769d8fe
FB
1339 if (rw == 2) {
1340 /* code access */
1341 rw = 0;
1342 access_type = ACCESS_CODE;
1343 } else {
1344 /* data access */
b4cec7b4 1345 access_type = env->access_type;
b769d8fe 1346 }
faadf50e 1347 ret = get_physical_address(env, &ctx, address, rw, access_type);
9a64fbe4 1348 if (ret == 0) {
d4c430a8
PB
1349 tlb_set_page(env, address & TARGET_PAGE_MASK,
1350 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1351 mmu_idx, TARGET_PAGE_SIZE);
1352 ret = 0;
9a64fbe4 1353 } else if (ret < 0) {
d12d51d5 1354 LOG_MMU_STATE(env);
9a64fbe4 1355 if (access_type == ACCESS_CODE) {
9a64fbe4
FB
1356 switch (ret) {
1357 case -1:
76a66253 1358 /* No matches in page tables or TLB */
a750fc0b
JM
1359 switch (env->mmu_model) {
1360 case POWERPC_MMU_SOFT_6xx:
8f793433
JM
1361 env->exception_index = POWERPC_EXCP_IFTLB;
1362 env->error_code = 1 << 18;
76a66253
JM
1363 env->spr[SPR_IMISS] = address;
1364 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
76a66253 1365 goto tlb_miss;
7dbe11ac 1366 case POWERPC_MMU_SOFT_74xx:
8f793433 1367 env->exception_index = POWERPC_EXCP_IFTLB;
7dbe11ac 1368 goto tlb_miss_74xx;
a750fc0b
JM
1369 case POWERPC_MMU_SOFT_4xx:
1370 case POWERPC_MMU_SOFT_4xx_Z:
8f793433
JM
1371 env->exception_index = POWERPC_EXCP_ITLB;
1372 env->error_code = 0;
a8dea12f
JM
1373 env->spr[SPR_40x_DEAR] = address;
1374 env->spr[SPR_40x_ESR] = 0x00000000;
c55e9aef 1375 break;
a750fc0b 1376 case POWERPC_MMU_32B:
faadf50e 1377 case POWERPC_MMU_601:
c55e9aef 1378#if defined(TARGET_PPC64)
add78955 1379 case POWERPC_MMU_620:
a750fc0b 1380 case POWERPC_MMU_64B:
9d52e907 1381 case POWERPC_MMU_2_06:
c55e9aef 1382#endif
8f793433
JM
1383 env->exception_index = POWERPC_EXCP_ISI;
1384 env->error_code = 0x40000000;
1385 break;
a750fc0b 1386 case POWERPC_MMU_BOOKE:
a586e548
EI
1387 env->exception_index = POWERPC_EXCP_ITLB;
1388 env->error_code = 0;
1389 env->spr[SPR_BOOKE_DEAR] = address;
c55e9aef 1390 return -1;
a750fc0b 1391 case POWERPC_MMU_BOOKE_FSL:
c55e9aef 1392 /* XXX: TODO */
b4095fed 1393 cpu_abort(env, "BookE FSL MMU model is not implemented\n");
c55e9aef 1394 return -1;
b4095fed
JM
1395 case POWERPC_MMU_MPC8xx:
1396 /* XXX: TODO */
1397 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1398 break;
1399 case POWERPC_MMU_REAL:
1400 cpu_abort(env, "PowerPC in real mode should never raise "
1401 "any MMU exceptions\n");
2662a059 1402 return -1;
c55e9aef
JM
1403 default:
1404 cpu_abort(env, "Unknown or invalid MMU model\n");
1405 return -1;
76a66253 1406 }
9a64fbe4
FB
1407 break;
1408 case -2:
1409 /* Access rights violation */
8f793433
JM
1410 env->exception_index = POWERPC_EXCP_ISI;
1411 env->error_code = 0x08000000;
9a64fbe4
FB
1412 break;
1413 case -3:
76a66253 1414 /* No execute protection violation */
a586e548
EI
1415 if (env->mmu_model == POWERPC_MMU_BOOKE) {
1416 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1417 }
8f793433
JM
1418 env->exception_index = POWERPC_EXCP_ISI;
1419 env->error_code = 0x10000000;
9a64fbe4
FB
1420 break;
1421 case -4:
1422 /* Direct store exception */
1423 /* No code fetch is allowed in direct-store areas */
8f793433
JM
1424 env->exception_index = POWERPC_EXCP_ISI;
1425 env->error_code = 0x10000000;
2be0071f 1426 break;
e1833e1f 1427#if defined(TARGET_PPC64)
2be0071f
FB
1428 case -5:
1429 /* No match in segment table */
add78955
JM
1430 if (env->mmu_model == POWERPC_MMU_620) {
1431 env->exception_index = POWERPC_EXCP_ISI;
1432 /* XXX: this might be incorrect */
1433 env->error_code = 0x40000000;
1434 } else {
1435 env->exception_index = POWERPC_EXCP_ISEG;
1436 env->error_code = 0;
1437 }
9a64fbe4 1438 break;
e1833e1f 1439#endif
9a64fbe4
FB
1440 }
1441 } else {
9a64fbe4
FB
1442 switch (ret) {
1443 case -1:
76a66253 1444 /* No matches in page tables or TLB */
a750fc0b
JM
1445 switch (env->mmu_model) {
1446 case POWERPC_MMU_SOFT_6xx:
76a66253 1447 if (rw == 1) {
8f793433
JM
1448 env->exception_index = POWERPC_EXCP_DSTLB;
1449 env->error_code = 1 << 16;
76a66253 1450 } else {
8f793433
JM
1451 env->exception_index = POWERPC_EXCP_DLTLB;
1452 env->error_code = 0;
76a66253
JM
1453 }
1454 env->spr[SPR_DMISS] = address;
1455 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1456 tlb_miss:
8f793433 1457 env->error_code |= ctx.key << 19;
fda6a0ec
DG
1458 env->spr[SPR_HASH1] = env->htab_base +
1459 get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
1460 env->spr[SPR_HASH2] = env->htab_base +
1461 get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
8f793433 1462 break;
7dbe11ac
JM
1463 case POWERPC_MMU_SOFT_74xx:
1464 if (rw == 1) {
8f793433 1465 env->exception_index = POWERPC_EXCP_DSTLB;
7dbe11ac 1466 } else {
8f793433 1467 env->exception_index = POWERPC_EXCP_DLTLB;
7dbe11ac
JM
1468 }
1469 tlb_miss_74xx:
1470 /* Implement LRU algorithm */
8f793433 1471 env->error_code = ctx.key << 19;
7dbe11ac
JM
1472 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1473 ((env->last_way + 1) & (env->nb_ways - 1));
1474 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
7dbe11ac 1475 break;
a750fc0b
JM
1476 case POWERPC_MMU_SOFT_4xx:
1477 case POWERPC_MMU_SOFT_4xx_Z:
8f793433
JM
1478 env->exception_index = POWERPC_EXCP_DTLB;
1479 env->error_code = 0;
a8dea12f
JM
1480 env->spr[SPR_40x_DEAR] = address;
1481 if (rw)
1482 env->spr[SPR_40x_ESR] = 0x00800000;
1483 else
1484 env->spr[SPR_40x_ESR] = 0x00000000;
c55e9aef 1485 break;
a750fc0b 1486 case POWERPC_MMU_32B:
faadf50e 1487 case POWERPC_MMU_601:
c55e9aef 1488#if defined(TARGET_PPC64)
add78955 1489 case POWERPC_MMU_620:
a750fc0b 1490 case POWERPC_MMU_64B:
9d52e907 1491 case POWERPC_MMU_2_06:
c55e9aef 1492#endif
8f793433
JM
1493 env->exception_index = POWERPC_EXCP_DSI;
1494 env->error_code = 0;
1495 env->spr[SPR_DAR] = address;
1496 if (rw == 1)
1497 env->spr[SPR_DSISR] = 0x42000000;
1498 else
1499 env->spr[SPR_DSISR] = 0x40000000;
1500 break;
b4095fed
JM
1501 case POWERPC_MMU_MPC8xx:
1502 /* XXX: TODO */
1503 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1504 break;
a750fc0b 1505 case POWERPC_MMU_BOOKE:
a586e548
EI
1506 env->exception_index = POWERPC_EXCP_DTLB;
1507 env->error_code = 0;
1508 env->spr[SPR_BOOKE_DEAR] = address;
1509 env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
c55e9aef 1510 return -1;
a750fc0b 1511 case POWERPC_MMU_BOOKE_FSL:
c55e9aef 1512 /* XXX: TODO */
b4095fed 1513 cpu_abort(env, "BookE FSL MMU model is not implemented\n");
c55e9aef 1514 return -1;
b4095fed
JM
1515 case POWERPC_MMU_REAL:
1516 cpu_abort(env, "PowerPC in real mode should never raise "
1517 "any MMU exceptions\n");
2662a059 1518 return -1;
c55e9aef
JM
1519 default:
1520 cpu_abort(env, "Unknown or invalid MMU model\n");
1521 return -1;
76a66253 1522 }
9a64fbe4
FB
1523 break;
1524 case -2:
1525 /* Access rights violation */
8f793433
JM
1526 env->exception_index = POWERPC_EXCP_DSI;
1527 env->error_code = 0;
dcbc9a70
EI
1528 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1529 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1530 env->spr[SPR_40x_DEAR] = address;
1531 if (rw) {
1532 env->spr[SPR_40x_ESR] |= 0x00800000;
1533 }
a586e548
EI
1534 } else if (env->mmu_model == POWERPC_MMU_BOOKE) {
1535 env->spr[SPR_BOOKE_DEAR] = address;
1536 env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
dcbc9a70
EI
1537 } else {
1538 env->spr[SPR_DAR] = address;
1539 if (rw == 1) {
1540 env->spr[SPR_DSISR] = 0x0A000000;
1541 } else {
1542 env->spr[SPR_DSISR] = 0x08000000;
1543 }
1544 }
9a64fbe4
FB
1545 break;
1546 case -4:
1547 /* Direct store exception */
1548 switch (access_type) {
1549 case ACCESS_FLOAT:
1550 /* Floating point load/store */
8f793433
JM
1551 env->exception_index = POWERPC_EXCP_ALIGN;
1552 env->error_code = POWERPC_EXCP_ALIGN_FP;
1553 env->spr[SPR_DAR] = address;
9a64fbe4
FB
1554 break;
1555 case ACCESS_RES:
8f793433
JM
1556 /* lwarx, ldarx or stwcx. */
1557 env->exception_index = POWERPC_EXCP_DSI;
1558 env->error_code = 0;
1559 env->spr[SPR_DAR] = address;
1560 if (rw == 1)
1561 env->spr[SPR_DSISR] = 0x06000000;
1562 else
1563 env->spr[SPR_DSISR] = 0x04000000;
9a64fbe4
FB
1564 break;
1565 case ACCESS_EXT:
1566 /* eciwx or ecowx */
8f793433
JM
1567 env->exception_index = POWERPC_EXCP_DSI;
1568 env->error_code = 0;
1569 env->spr[SPR_DAR] = address;
1570 if (rw == 1)
1571 env->spr[SPR_DSISR] = 0x06100000;
1572 else
1573 env->spr[SPR_DSISR] = 0x04100000;
9a64fbe4
FB
1574 break;
1575 default:
76a66253 1576 printf("DSI: invalid exception (%d)\n", ret);
8f793433
JM
1577 env->exception_index = POWERPC_EXCP_PROGRAM;
1578 env->error_code =
1579 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1580 env->spr[SPR_DAR] = address;
9a64fbe4
FB
1581 break;
1582 }
fdabc366 1583 break;
e1833e1f 1584#if defined(TARGET_PPC64)
2be0071f
FB
1585 case -5:
1586 /* No match in segment table */
add78955
JM
1587 if (env->mmu_model == POWERPC_MMU_620) {
1588 env->exception_index = POWERPC_EXCP_DSI;
1589 env->error_code = 0;
1590 env->spr[SPR_DAR] = address;
1591 /* XXX: this might be incorrect */
1592 if (rw == 1)
1593 env->spr[SPR_DSISR] = 0x42000000;
1594 else
1595 env->spr[SPR_DSISR] = 0x40000000;
1596 } else {
1597 env->exception_index = POWERPC_EXCP_DSEG;
1598 env->error_code = 0;
1599 env->spr[SPR_DAR] = address;
1600 }
2be0071f 1601 break;
e1833e1f 1602#endif
9a64fbe4 1603 }
9a64fbe4
FB
1604 }
1605#if 0
8f793433
JM
1606 printf("%s: set exception to %d %02x\n", __func__,
1607 env->exception, env->error_code);
9a64fbe4 1608#endif
9a64fbe4
FB
1609 ret = 1;
1610 }
76a66253 1611
9a64fbe4
FB
1612 return ret;
1613}
1614
3fc6c082
FB
1615/*****************************************************************************/
1616/* BATs management */
1617#if !defined(FLUSH_ALL_TLBS)
636aa200
BS
1618static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1619 target_ulong mask)
3fc6c082
FB
1620{
1621 target_ulong base, end, page;
76a66253 1622
3fc6c082
FB
1623 base = BATu & ~0x0001FFFF;
1624 end = base + mask + 0x00020000;
90e189ec
BS
1625 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1626 TARGET_FMT_lx ")\n", base, end, mask);
3fc6c082
FB
1627 for (page = base; page != end; page += TARGET_PAGE_SIZE)
1628 tlb_flush_page(env, page);
d12d51d5 1629 LOG_BATS("Flush done\n");
3fc6c082
FB
1630}
1631#endif
1632
636aa200
BS
1633static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1634 target_ulong value)
3fc6c082 1635{
90e189ec
BS
1636 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1637 nr, ul == 0 ? 'u' : 'l', value, env->nip);
3fc6c082
FB
1638}
1639
45d827d2 1640void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
1641{
1642 target_ulong mask;
1643
1644 dump_store_bat(env, 'I', 0, nr, value);
1645 if (env->IBAT[0][nr] != value) {
1646 mask = (value << 15) & 0x0FFE0000UL;
1647#if !defined(FLUSH_ALL_TLBS)
1648 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1649#endif
1650 /* When storing valid upper BAT, mask BEPI and BRPN
1651 * and invalidate all TLBs covered by this BAT
1652 */
1653 mask = (value << 15) & 0x0FFE0000UL;
1654 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1655 (value & ~0x0001FFFFUL & ~mask);
1656 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1657 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1658#if !defined(FLUSH_ALL_TLBS)
1659 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
76a66253 1660#else
3fc6c082
FB
1661 tlb_flush(env, 1);
1662#endif
1663 }
1664}
1665
45d827d2 1666void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
1667{
1668 dump_store_bat(env, 'I', 1, nr, value);
1669 env->IBAT[1][nr] = value;
1670}
1671
45d827d2 1672void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
1673{
1674 target_ulong mask;
1675
1676 dump_store_bat(env, 'D', 0, nr, value);
1677 if (env->DBAT[0][nr] != value) {
1678 /* When storing valid upper BAT, mask BEPI and BRPN
1679 * and invalidate all TLBs covered by this BAT
1680 */
1681 mask = (value << 15) & 0x0FFE0000UL;
1682#if !defined(FLUSH_ALL_TLBS)
1683 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1684#endif
1685 mask = (value << 15) & 0x0FFE0000UL;
1686 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1687 (value & ~0x0001FFFFUL & ~mask);
1688 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1689 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1690#if !defined(FLUSH_ALL_TLBS)
1691 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1692#else
1693 tlb_flush(env, 1);
1694#endif
1695 }
1696}
1697
45d827d2 1698void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
3fc6c082
FB
1699{
1700 dump_store_bat(env, 'D', 1, nr, value);
1701 env->DBAT[1][nr] = value;
1702}
1703
45d827d2 1704void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
056401ea
JM
1705{
1706 target_ulong mask;
05f92404 1707#if defined(FLUSH_ALL_TLBS)
056401ea 1708 int do_inval;
05f92404 1709#endif
056401ea
JM
1710
1711 dump_store_bat(env, 'I', 0, nr, value);
1712 if (env->IBAT[0][nr] != value) {
05f92404 1713#if defined(FLUSH_ALL_TLBS)
056401ea 1714 do_inval = 0;
05f92404 1715#endif
056401ea
JM
1716 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1717 if (env->IBAT[1][nr] & 0x40) {
1718 /* Invalidate BAT only if it is valid */
1719#if !defined(FLUSH_ALL_TLBS)
1720 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1721#else
1722 do_inval = 1;
1723#endif
1724 }
1725 /* When storing valid upper BAT, mask BEPI and BRPN
1726 * and invalidate all TLBs covered by this BAT
1727 */
1728 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1729 (value & ~0x0001FFFFUL & ~mask);
1730 env->DBAT[0][nr] = env->IBAT[0][nr];
1731 if (env->IBAT[1][nr] & 0x40) {
1732#if !defined(FLUSH_ALL_TLBS)
1733 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1734#else
1735 do_inval = 1;
1736#endif
1737 }
1738#if defined(FLUSH_ALL_TLBS)
1739 if (do_inval)
1740 tlb_flush(env, 1);
1741#endif
1742 }
1743}
1744
45d827d2 1745void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
056401ea
JM
1746{
1747 target_ulong mask;
05f92404 1748#if defined(FLUSH_ALL_TLBS)
056401ea 1749 int do_inval;
05f92404 1750#endif
056401ea
JM
1751
1752 dump_store_bat(env, 'I', 1, nr, value);
1753 if (env->IBAT[1][nr] != value) {
05f92404 1754#if defined(FLUSH_ALL_TLBS)
056401ea 1755 do_inval = 0;
05f92404 1756#endif
056401ea
JM
1757 if (env->IBAT[1][nr] & 0x40) {
1758#if !defined(FLUSH_ALL_TLBS)
1759 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1760 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1761#else
1762 do_inval = 1;
1763#endif
1764 }
1765 if (value & 0x40) {
1766#if !defined(FLUSH_ALL_TLBS)
1767 mask = (value << 17) & 0x0FFE0000UL;
1768 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1769#else
1770 do_inval = 1;
1771#endif
1772 }
1773 env->IBAT[1][nr] = value;
1774 env->DBAT[1][nr] = value;
1775#if defined(FLUSH_ALL_TLBS)
1776 if (do_inval)
1777 tlb_flush(env, 1);
1778#endif
1779 }
1780}
1781
0a032cbe
JM
1782/*****************************************************************************/
1783/* TLB management */
1784void ppc_tlb_invalidate_all (CPUPPCState *env)
1785{
daf4f96e
JM
1786 switch (env->mmu_model) {
1787 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 1788 case POWERPC_MMU_SOFT_74xx:
0a032cbe 1789 ppc6xx_tlb_invalidate_all(env);
daf4f96e
JM
1790 break;
1791 case POWERPC_MMU_SOFT_4xx:
1792 case POWERPC_MMU_SOFT_4xx_Z:
0a032cbe 1793 ppc4xx_tlb_invalidate_all(env);
daf4f96e 1794 break;
b4095fed 1795 case POWERPC_MMU_REAL:
7dbe11ac
JM
1796 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
1797 break;
b4095fed
JM
1798 case POWERPC_MMU_MPC8xx:
1799 /* XXX: TODO */
1800 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1801 break;
7dbe11ac 1802 case POWERPC_MMU_BOOKE:
a586e548 1803 tlb_flush(env, 1);
7dbe11ac
JM
1804 break;
1805 case POWERPC_MMU_BOOKE_FSL:
1806 /* XXX: TODO */
da07cf59
AL
1807 if (!kvm_enabled())
1808 cpu_abort(env, "BookE MMU model is not implemented\n");
7dbe11ac 1809 break;
7dbe11ac 1810 case POWERPC_MMU_32B:
faadf50e 1811 case POWERPC_MMU_601:
00af685f 1812#if defined(TARGET_PPC64)
add78955 1813 case POWERPC_MMU_620:
7dbe11ac 1814 case POWERPC_MMU_64B:
9d52e907 1815 case POWERPC_MMU_2_06:
00af685f 1816#endif /* defined(TARGET_PPC64) */
0a032cbe 1817 tlb_flush(env, 1);
daf4f96e 1818 break;
00af685f
JM
1819 default:
1820 /* XXX: TODO */
12de9a39 1821 cpu_abort(env, "Unknown MMU model\n");
00af685f 1822 break;
0a032cbe
JM
1823 }
1824}
1825
daf4f96e
JM
1826void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
1827{
1828#if !defined(FLUSH_ALL_TLBS)
1829 addr &= TARGET_PAGE_MASK;
1830 switch (env->mmu_model) {
1831 case POWERPC_MMU_SOFT_6xx:
7dbe11ac 1832 case POWERPC_MMU_SOFT_74xx:
daf4f96e
JM
1833 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1834 if (env->id_tlbs == 1)
1835 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1836 break;
1837 case POWERPC_MMU_SOFT_4xx:
1838 case POWERPC_MMU_SOFT_4xx_Z:
1839 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
1840 break;
b4095fed 1841 case POWERPC_MMU_REAL:
7dbe11ac
JM
1842 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
1843 break;
b4095fed
JM
1844 case POWERPC_MMU_MPC8xx:
1845 /* XXX: TODO */
1846 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1847 break;
7dbe11ac
JM
1848 case POWERPC_MMU_BOOKE:
1849 /* XXX: TODO */
b4095fed 1850 cpu_abort(env, "BookE MMU model is not implemented\n");
7dbe11ac
JM
1851 break;
1852 case POWERPC_MMU_BOOKE_FSL:
1853 /* XXX: TODO */
b4095fed 1854 cpu_abort(env, "BookE FSL MMU model is not implemented\n");
7dbe11ac
JM
1855 break;
1856 case POWERPC_MMU_32B:
faadf50e 1857 case POWERPC_MMU_601:
daf4f96e 1858 /* tlbie invalidate TLBs for all segments */
6f2d8978 1859 addr &= ~((target_ulong)-1ULL << 28);
daf4f96e
JM
1860 /* XXX: this case should be optimized,
1861 * giving a mask to tlb_flush_page
1862 */
1863 tlb_flush_page(env, addr | (0x0 << 28));
1864 tlb_flush_page(env, addr | (0x1 << 28));
1865 tlb_flush_page(env, addr | (0x2 << 28));
1866 tlb_flush_page(env, addr | (0x3 << 28));
1867 tlb_flush_page(env, addr | (0x4 << 28));
1868 tlb_flush_page(env, addr | (0x5 << 28));
1869 tlb_flush_page(env, addr | (0x6 << 28));
1870 tlb_flush_page(env, addr | (0x7 << 28));
1871 tlb_flush_page(env, addr | (0x8 << 28));
1872 tlb_flush_page(env, addr | (0x9 << 28));
1873 tlb_flush_page(env, addr | (0xA << 28));
1874 tlb_flush_page(env, addr | (0xB << 28));
1875 tlb_flush_page(env, addr | (0xC << 28));
1876 tlb_flush_page(env, addr | (0xD << 28));
1877 tlb_flush_page(env, addr | (0xE << 28));
1878 tlb_flush_page(env, addr | (0xF << 28));
7dbe11ac 1879 break;
00af685f 1880#if defined(TARGET_PPC64)
add78955 1881 case POWERPC_MMU_620:
7dbe11ac 1882 case POWERPC_MMU_64B:
9d52e907 1883 case POWERPC_MMU_2_06:
7dbe11ac
JM
1884 /* tlbie invalidate TLBs for all segments */
1885 /* XXX: given the fact that there are too many segments to invalidate,
00af685f 1886 * and we still don't have a tlb_flush_mask(env, n, mask) in Qemu,
7dbe11ac
JM
1887 * we just invalidate all TLBs
1888 */
1889 tlb_flush(env, 1);
1890 break;
00af685f
JM
1891#endif /* defined(TARGET_PPC64) */
1892 default:
1893 /* XXX: TODO */
12de9a39 1894 cpu_abort(env, "Unknown MMU model\n");
00af685f 1895 break;
daf4f96e
JM
1896 }
1897#else
1898 ppc_tlb_invalidate_all(env);
1899#endif
1900}
1901
3fc6c082
FB
1902/*****************************************************************************/
1903/* Special registers manipulation */
d9bce9d9 1904#if defined(TARGET_PPC64)
d9bce9d9
JM
1905void ppc_store_asr (CPUPPCState *env, target_ulong value)
1906{
1907 if (env->asr != value) {
1908 env->asr = value;
1909 tlb_flush(env, 1);
1910 }
1911}
1912#endif
1913
45d827d2 1914void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
3fc6c082 1915{
90e189ec 1916 LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
bb593904
DG
1917 if (env->spr[SPR_SDR1] != value) {
1918 env->spr[SPR_SDR1] = value;
1919#if defined(TARGET_PPC64)
1920 if (env->mmu_model & POWERPC_MMU_64) {
1921 target_ulong htabsize = value & SDR_64_HTABSIZE;
1922
1923 if (htabsize > 28) {
1924 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
1925 " stored in SDR1\n", htabsize);
1926 htabsize = 28;
1927 }
1928 env->htab_mask = (1ULL << (htabsize + 18)) - 1;
1929 env->htab_base = value & SDR_64_HTABORG;
1930 } else
1931#endif /* defined(TARGET_PPC64) */
1932 {
1933 /* FIXME: Should check for valid HTABMASK values */
1934 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
1935 env->htab_base = value & SDR_32_HTABORG;
1936 }
76a66253 1937 tlb_flush(env, 1);
3fc6c082
FB
1938 }
1939}
1940
f6b868fc
BS
1941#if defined(TARGET_PPC64)
1942target_ulong ppc_load_sr (CPUPPCState *env, int slb_nr)
1943{
1944 // XXX
1945 return 0;
1946}
1947#endif
1948
45d827d2 1949void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value)
3fc6c082 1950{
90e189ec
BS
1951 LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
1952 srnum, value, env->sr[srnum]);
f6b868fc
BS
1953#if defined(TARGET_PPC64)
1954 if (env->mmu_model & POWERPC_MMU_64) {
1955 uint64_t rb = 0, rs = 0;
1956
1957 /* ESID = srnum */
1958 rb |= ((uint32_t)srnum & 0xf) << 28;
1959 /* Set the valid bit */
1960 rb |= 1 << 27;
1961 /* Index = ESID */
1962 rb |= (uint32_t)srnum;
1963
1964 /* VSID = VSID */
1965 rs |= (value & 0xfffffff) << 12;
1966 /* flags = flags */
1967 rs |= ((value >> 27) & 0xf) << 9;
1968
1969 ppc_store_slb(env, rb, rs);
1970 } else
1971#endif
3fc6c082
FB
1972 if (env->sr[srnum] != value) {
1973 env->sr[srnum] = value;
bf1752ef
AJ
1974/* Invalidating 256MB of virtual memory in 4kB pages is way longer than
1975 flusing the whole TLB. */
3fc6c082
FB
1976#if !defined(FLUSH_ALL_TLBS) && 0
1977 {
1978 target_ulong page, end;
1979 /* Invalidate 256 MB of virtual memory */
1980 page = (16 << 20) * srnum;
1981 end = page + (16 << 20);
1982 for (; page != end; page += TARGET_PAGE_SIZE)
1983 tlb_flush_page(env, page);
1984 }
1985#else
76a66253 1986 tlb_flush(env, 1);
3fc6c082
FB
1987#endif
1988 }
1989}
76a66253 1990#endif /* !defined (CONFIG_USER_ONLY) */
3fc6c082 1991
76a66253 1992/* GDBstub can read and write MSR... */
0411a972 1993void ppc_store_msr (CPUPPCState *env, target_ulong value)
3fc6c082 1994{
a4f30719 1995 hreg_store_msr(env, value, 0);
3fc6c082
FB
1996}
1997
1998/*****************************************************************************/
1999/* Exception processing */
18fba28c 2000#if defined (CONFIG_USER_ONLY)
9a64fbe4 2001void do_interrupt (CPUState *env)
79aceca5 2002{
e1833e1f
JM
2003 env->exception_index = POWERPC_EXCP_NONE;
2004 env->error_code = 0;
18fba28c 2005}
47103572 2006
e9df014c 2007void ppc_hw_interrupt (CPUState *env)
47103572 2008{
e1833e1f
JM
2009 env->exception_index = POWERPC_EXCP_NONE;
2010 env->error_code = 0;
47103572 2011}
76a66253 2012#else /* defined (CONFIG_USER_ONLY) */
636aa200 2013static inline void dump_syscall(CPUState *env)
d094807b 2014{
b11ebf64
BS
2015 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
2016 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
2017 " nip=" TARGET_FMT_lx "\n",
90e189ec
BS
2018 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
2019 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
2020 ppc_dump_gpr(env, 6), env->nip);
d094807b
FB
2021}
2022
e1833e1f
JM
2023/* Note that this function should be greatly optimized
2024 * when called with a constant excp, from ppc_hw_interrupt
2025 */
636aa200 2026static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
18fba28c 2027{
0411a972 2028 target_ulong msr, new_msr, vector;
e1833e1f 2029 int srr0, srr1, asrr0, asrr1;
a4f30719 2030 int lpes0, lpes1, lev;
79aceca5 2031
b172c56a
JM
2032 if (0) {
2033 /* XXX: find a suitable condition to enable the hypervisor mode */
2034 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
2035 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
2036 } else {
2037 /* Those values ensure we won't enter the hypervisor mode */
2038 lpes0 = 0;
2039 lpes1 = 1;
2040 }
2041
90e189ec
BS
2042 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
2043 " => %08x (%02x)\n", env->nip, excp, env->error_code);
41557447
AG
2044
2045 /* new srr1 value excluding must-be-zero bits */
2046 msr = env->msr & ~0x783f0000ULL;
2047
2048 /* new interrupt handler msr */
2049 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
2050
2051 /* target registers */
e1833e1f
JM
2052 srr0 = SPR_SRR0;
2053 srr1 = SPR_SRR1;
2054 asrr0 = -1;
2055 asrr1 = -1;
41557447 2056
9a64fbe4 2057 switch (excp) {
e1833e1f
JM
2058 case POWERPC_EXCP_NONE:
2059 /* Should never happen */
2060 return;
2061 case POWERPC_EXCP_CRITICAL: /* Critical input */
e1833e1f 2062 switch (excp_model) {
a750fc0b 2063 case POWERPC_EXCP_40x:
e1833e1f
JM
2064 srr0 = SPR_40x_SRR2;
2065 srr1 = SPR_40x_SRR3;
c62db105 2066 break;
a750fc0b 2067 case POWERPC_EXCP_BOOKE:
e1833e1f
JM
2068 srr0 = SPR_BOOKE_CSRR0;
2069 srr1 = SPR_BOOKE_CSRR1;
c62db105 2070 break;
e1833e1f 2071 case POWERPC_EXCP_G2:
c62db105 2072 break;
e1833e1f
JM
2073 default:
2074 goto excp_invalid;
2be0071f 2075 }
9a64fbe4 2076 goto store_next;
e1833e1f
JM
2077 case POWERPC_EXCP_MCHECK: /* Machine check exception */
2078 if (msr_me == 0) {
e63ecc6f
JM
2079 /* Machine check exception is not enabled.
2080 * Enter checkstop state.
2081 */
93fcfe39
AL
2082 if (qemu_log_enabled()) {
2083 qemu_log("Machine check while not allowed. "
e63ecc6f
JM
2084 "Entering checkstop state\n");
2085 } else {
2086 fprintf(stderr, "Machine check while not allowed. "
2087 "Entering checkstop state\n");
2088 }
2089 env->halted = 1;
2090 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
e1833e1f 2091 }
b172c56a
JM
2092 if (0) {
2093 /* XXX: find a suitable condition to enable the hypervisor mode */
a4f30719 2094 new_msr |= (target_ulong)MSR_HVB;
b172c56a 2095 }
41557447
AG
2096
2097 /* machine check exceptions don't have ME set */
2098 new_msr &= ~((target_ulong)1 << MSR_ME);
2099
e1833e1f
JM
2100 /* XXX: should also have something loaded in DAR / DSISR */
2101 switch (excp_model) {
a750fc0b 2102 case POWERPC_EXCP_40x:
e1833e1f
JM
2103 srr0 = SPR_40x_SRR2;
2104 srr1 = SPR_40x_SRR3;
c62db105 2105 break;
a750fc0b 2106 case POWERPC_EXCP_BOOKE:
e1833e1f
JM
2107 srr0 = SPR_BOOKE_MCSRR0;
2108 srr1 = SPR_BOOKE_MCSRR1;
2109 asrr0 = SPR_BOOKE_CSRR0;
2110 asrr1 = SPR_BOOKE_CSRR1;
c62db105
JM
2111 break;
2112 default:
2113 break;
2be0071f 2114 }
e1833e1f
JM
2115 goto store_next;
2116 case POWERPC_EXCP_DSI: /* Data storage exception */
90e189ec
BS
2117 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
2118 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
e1833e1f 2119 if (lpes1 == 0)
a4f30719 2120 new_msr |= (target_ulong)MSR_HVB;
a541f297 2121 goto store_next;
e1833e1f 2122 case POWERPC_EXCP_ISI: /* Instruction storage exception */
90e189ec
BS
2123 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
2124 "\n", msr, env->nip);
e1833e1f 2125 if (lpes1 == 0)
a4f30719 2126 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2127 msr |= env->error_code;
9a64fbe4 2128 goto store_next;
e1833e1f 2129 case POWERPC_EXCP_EXTERNAL: /* External input */
e1833e1f 2130 if (lpes0 == 1)
a4f30719 2131 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2132 goto store_next;
e1833e1f 2133 case POWERPC_EXCP_ALIGN: /* Alignment exception */
e1833e1f 2134 if (lpes1 == 0)
a4f30719 2135 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2136 /* XXX: this is false */
2137 /* Get rS/rD and rA from faulting opcode */
2138 env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
9a64fbe4 2139 goto store_current;
e1833e1f 2140 case POWERPC_EXCP_PROGRAM: /* Program exception */
9a64fbe4 2141 switch (env->error_code & ~0xF) {
e1833e1f
JM
2142 case POWERPC_EXCP_FP:
2143 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
d12d51d5 2144 LOG_EXCP("Ignore floating point exception\n");
7c58044c
JM
2145 env->exception_index = POWERPC_EXCP_NONE;
2146 env->error_code = 0;
9a64fbe4 2147 return;
76a66253 2148 }
e1833e1f 2149 if (lpes1 == 0)
a4f30719 2150 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2151 msr |= 0x00100000;
5b52b991
JM
2152 if (msr_fe0 == msr_fe1)
2153 goto store_next;
2154 msr |= 0x00010000;
76a66253 2155 break;
e1833e1f 2156 case POWERPC_EXCP_INVAL:
90e189ec 2157 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
e1833e1f 2158 if (lpes1 == 0)
a4f30719 2159 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2160 msr |= 0x00080000;
76a66253 2161 break;
e1833e1f 2162 case POWERPC_EXCP_PRIV:
e1833e1f 2163 if (lpes1 == 0)
a4f30719 2164 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4 2165 msr |= 0x00040000;
76a66253 2166 break;
e1833e1f 2167 case POWERPC_EXCP_TRAP:
e1833e1f 2168 if (lpes1 == 0)
a4f30719 2169 new_msr |= (target_ulong)MSR_HVB;
9a64fbe4
FB
2170 msr |= 0x00020000;
2171 break;
2172 default:
2173 /* Should never occur */
e1833e1f
JM
2174 cpu_abort(env, "Invalid program exception %d. Aborting\n",
2175 env->error_code);
76a66253
JM
2176 break;
2177 }
5b52b991 2178 goto store_current;
e1833e1f 2179 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
e1833e1f 2180 if (lpes1 == 0)
a4f30719 2181 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2182 goto store_current;
2183 case POWERPC_EXCP_SYSCALL: /* System call exception */
93fcfe39 2184 dump_syscall(env);
f9fdea6b 2185 lev = env->error_code;
d569956e
DG
2186 if ((lev == 1) && cpu_ppc_hypercall) {
2187 cpu_ppc_hypercall(env);
2188 return;
2189 }
e1833e1f 2190 if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
a4f30719 2191 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2192 goto store_next;
2193 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
e1833e1f
JM
2194 goto store_current;
2195 case POWERPC_EXCP_DECR: /* Decrementer exception */
e1833e1f 2196 if (lpes1 == 0)
a4f30719 2197 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2198 goto store_next;
2199 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
2200 /* FIT on 4xx */
d12d51d5 2201 LOG_EXCP("FIT exception\n");
9a64fbe4 2202 goto store_next;
e1833e1f 2203 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
d12d51d5 2204 LOG_EXCP("WDT exception\n");
e1833e1f
JM
2205 switch (excp_model) {
2206 case POWERPC_EXCP_BOOKE:
2207 srr0 = SPR_BOOKE_CSRR0;
2208 srr1 = SPR_BOOKE_CSRR1;
2209 break;
2210 default:
2211 break;
2212 }
2be0071f 2213 goto store_next;
e1833e1f 2214 case POWERPC_EXCP_DTLB: /* Data TLB error */
e1833e1f
JM
2215 goto store_next;
2216 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
e1833e1f
JM
2217 goto store_next;
2218 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
2219 switch (excp_model) {
2220 case POWERPC_EXCP_BOOKE:
2221 srr0 = SPR_BOOKE_DSRR0;
2222 srr1 = SPR_BOOKE_DSRR1;
2223 asrr0 = SPR_BOOKE_CSRR0;
2224 asrr1 = SPR_BOOKE_CSRR1;
2225 break;
2226 default:
2227 break;
2228 }
2be0071f 2229 /* XXX: TODO */
e1833e1f 2230 cpu_abort(env, "Debug exception is not implemented yet !\n");
2be0071f 2231 goto store_next;
e1833e1f 2232 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
e1833e1f
JM
2233 goto store_current;
2234 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
2be0071f 2235 /* XXX: TODO */
e1833e1f 2236 cpu_abort(env, "Embedded floating point data exception "
2be0071f
FB
2237 "is not implemented yet !\n");
2238 goto store_next;
e1833e1f 2239 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
2be0071f 2240 /* XXX: TODO */
e1833e1f
JM
2241 cpu_abort(env, "Embedded floating point round exception "
2242 "is not implemented yet !\n");
9a64fbe4 2243 goto store_next;
e1833e1f 2244 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
2be0071f
FB
2245 /* XXX: TODO */
2246 cpu_abort(env,
e1833e1f 2247 "Performance counter exception is not implemented yet !\n");
9a64fbe4 2248 goto store_next;
e1833e1f 2249 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
76a66253 2250 /* XXX: TODO */
e1833e1f
JM
2251 cpu_abort(env,
2252 "Embedded doorbell interrupt is not implemented yet !\n");
2be0071f 2253 goto store_next;
e1833e1f
JM
2254 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
2255 switch (excp_model) {
2256 case POWERPC_EXCP_BOOKE:
2257 srr0 = SPR_BOOKE_CSRR0;
2258 srr1 = SPR_BOOKE_CSRR1;
a750fc0b 2259 break;
2be0071f 2260 default:
2be0071f
FB
2261 break;
2262 }
e1833e1f
JM
2263 /* XXX: TODO */
2264 cpu_abort(env, "Embedded doorbell critical interrupt "
2265 "is not implemented yet !\n");
2266 goto store_next;
e1833e1f 2267 case POWERPC_EXCP_RESET: /* System reset exception */
41557447
AG
2268 if (msr_pow) {
2269 /* indicate that we resumed from power save mode */
2270 msr |= 0x10000;
2271 } else {
2272 new_msr &= ~((target_ulong)1 << MSR_ME);
2273 }
2274
a4f30719
JM
2275 if (0) {
2276 /* XXX: find a suitable condition to enable the hypervisor mode */
2277 new_msr |= (target_ulong)MSR_HVB;
2278 }
e1833e1f 2279 goto store_next;
e1833e1f 2280 case POWERPC_EXCP_DSEG: /* Data segment exception */
e1833e1f 2281 if (lpes1 == 0)
a4f30719 2282 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2283 goto store_next;
2284 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
e1833e1f 2285 if (lpes1 == 0)
a4f30719 2286 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2287 goto store_next;
e1833e1f
JM
2288 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
2289 srr0 = SPR_HSRR0;
f9fdea6b 2290 srr1 = SPR_HSRR1;
a4f30719 2291 new_msr |= (target_ulong)MSR_HVB;
41557447 2292 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
b172c56a 2293 goto store_next;
e1833e1f 2294 case POWERPC_EXCP_TRACE: /* Trace exception */
e1833e1f 2295 if (lpes1 == 0)
a4f30719 2296 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2297 goto store_next;
e1833e1f
JM
2298 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
2299 srr0 = SPR_HSRR0;
f9fdea6b 2300 srr1 = SPR_HSRR1;
a4f30719 2301 new_msr |= (target_ulong)MSR_HVB;
41557447 2302 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f
JM
2303 goto store_next;
2304 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
2305 srr0 = SPR_HSRR0;
f9fdea6b 2306 srr1 = SPR_HSRR1;
a4f30719 2307 new_msr |= (target_ulong)MSR_HVB;
41557447 2308 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f
JM
2309 goto store_next;
2310 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
2311 srr0 = SPR_HSRR0;
f9fdea6b 2312 srr1 = SPR_HSRR1;
a4f30719 2313 new_msr |= (target_ulong)MSR_HVB;
41557447 2314 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f
JM
2315 goto store_next;
2316 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
2317 srr0 = SPR_HSRR0;
f9fdea6b 2318 srr1 = SPR_HSRR1;
a4f30719 2319 new_msr |= (target_ulong)MSR_HVB;
41557447 2320 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
e1833e1f 2321 goto store_next;
e1833e1f 2322 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
e1833e1f 2323 if (lpes1 == 0)
a4f30719 2324 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2325 goto store_current;
2326 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
d12d51d5 2327 LOG_EXCP("PIT exception\n");
e1833e1f
JM
2328 goto store_next;
2329 case POWERPC_EXCP_IO: /* IO error exception */
2330 /* XXX: TODO */
2331 cpu_abort(env, "601 IO error exception is not implemented yet !\n");
2332 goto store_next;
2333 case POWERPC_EXCP_RUNM: /* Run mode exception */
2334 /* XXX: TODO */
2335 cpu_abort(env, "601 run mode exception is not implemented yet !\n");
2336 goto store_next;
2337 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
2338 /* XXX: TODO */
2339 cpu_abort(env, "602 emulation trap exception "
2340 "is not implemented yet !\n");
2341 goto store_next;
2342 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
a4f30719
JM
2343 if (lpes1 == 0) /* XXX: check this */
2344 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2345 switch (excp_model) {
a750fc0b
JM
2346 case POWERPC_EXCP_602:
2347 case POWERPC_EXCP_603:
2348 case POWERPC_EXCP_603E:
2349 case POWERPC_EXCP_G2:
e1833e1f 2350 goto tlb_miss_tgpr;
a750fc0b 2351 case POWERPC_EXCP_7x5:
76a66253 2352 goto tlb_miss;
7dbe11ac
JM
2353 case POWERPC_EXCP_74xx:
2354 goto tlb_miss_74xx;
2be0071f 2355 default:
e1833e1f 2356 cpu_abort(env, "Invalid instruction TLB miss exception\n");
2be0071f
FB
2357 break;
2358 }
e1833e1f
JM
2359 break;
2360 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
a4f30719
JM
2361 if (lpes1 == 0) /* XXX: check this */
2362 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2363 switch (excp_model) {
a750fc0b
JM
2364 case POWERPC_EXCP_602:
2365 case POWERPC_EXCP_603:
2366 case POWERPC_EXCP_603E:
2367 case POWERPC_EXCP_G2:
e1833e1f 2368 goto tlb_miss_tgpr;
a750fc0b 2369 case POWERPC_EXCP_7x5:
76a66253 2370 goto tlb_miss;
7dbe11ac
JM
2371 case POWERPC_EXCP_74xx:
2372 goto tlb_miss_74xx;
2be0071f 2373 default:
e1833e1f 2374 cpu_abort(env, "Invalid data load TLB miss exception\n");
2be0071f
FB
2375 break;
2376 }
e1833e1f
JM
2377 break;
2378 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
a4f30719
JM
2379 if (lpes1 == 0) /* XXX: check this */
2380 new_msr |= (target_ulong)MSR_HVB;
e1833e1f 2381 switch (excp_model) {
a750fc0b
JM
2382 case POWERPC_EXCP_602:
2383 case POWERPC_EXCP_603:
2384 case POWERPC_EXCP_603E:
2385 case POWERPC_EXCP_G2:
e1833e1f 2386 tlb_miss_tgpr:
76a66253 2387 /* Swap temporary saved registers with GPRs */
0411a972
JM
2388 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
2389 new_msr |= (target_ulong)1 << MSR_TGPR;
2390 hreg_swap_gpr_tgpr(env);
2391 }
e1833e1f
JM
2392 goto tlb_miss;
2393 case POWERPC_EXCP_7x5:
2394 tlb_miss:
2be0071f 2395#if defined (DEBUG_SOFTWARE_TLB)
93fcfe39 2396 if (qemu_log_enabled()) {
0bf9e31a 2397 const char *es;
76a66253
JM
2398 target_ulong *miss, *cmp;
2399 int en;
1e6784f9 2400 if (excp == POWERPC_EXCP_IFTLB) {
76a66253
JM
2401 es = "I";
2402 en = 'I';
2403 miss = &env->spr[SPR_IMISS];
2404 cmp = &env->spr[SPR_ICMP];
2405 } else {
1e6784f9 2406 if (excp == POWERPC_EXCP_DLTLB)
76a66253
JM
2407 es = "DL";
2408 else
2409 es = "DS";
2410 en = 'D';
2411 miss = &env->spr[SPR_DMISS];
2412 cmp = &env->spr[SPR_DCMP];
2413 }
90e189ec
BS
2414 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
2415 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
2416 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
2417 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
2418 env->error_code);
2be0071f 2419 }
9a64fbe4 2420#endif
2be0071f
FB
2421 msr |= env->crf[0] << 28;
2422 msr |= env->error_code; /* key, D/I, S/L bits */
2423 /* Set way using a LRU mechanism */
76a66253 2424 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
c62db105 2425 break;
7dbe11ac
JM
2426 case POWERPC_EXCP_74xx:
2427 tlb_miss_74xx:
2428#if defined (DEBUG_SOFTWARE_TLB)
93fcfe39 2429 if (qemu_log_enabled()) {
0bf9e31a 2430 const char *es;
7dbe11ac
JM
2431 target_ulong *miss, *cmp;
2432 int en;
2433 if (excp == POWERPC_EXCP_IFTLB) {
2434 es = "I";
2435 en = 'I';
0411a972
JM
2436 miss = &env->spr[SPR_TLBMISS];
2437 cmp = &env->spr[SPR_PTEHI];
7dbe11ac
JM
2438 } else {
2439 if (excp == POWERPC_EXCP_DLTLB)
2440 es = "DL";
2441 else
2442 es = "DS";
2443 en = 'D';
2444 miss = &env->spr[SPR_TLBMISS];
2445 cmp = &env->spr[SPR_PTEHI];
2446 }
90e189ec
BS
2447 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
2448 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
2449 env->error_code);
7dbe11ac
JM
2450 }
2451#endif
2452 msr |= env->error_code; /* key bit */
2453 break;
2be0071f 2454 default:
e1833e1f 2455 cpu_abort(env, "Invalid data store TLB miss exception\n");
2be0071f
FB
2456 break;
2457 }
e1833e1f
JM
2458 goto store_next;
2459 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
2460 /* XXX: TODO */
2461 cpu_abort(env, "Floating point assist exception "
2462 "is not implemented yet !\n");
2463 goto store_next;
b4095fed
JM
2464 case POWERPC_EXCP_DABR: /* Data address breakpoint */
2465 /* XXX: TODO */
2466 cpu_abort(env, "DABR exception is not implemented yet !\n");
2467 goto store_next;
e1833e1f
JM
2468 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
2469 /* XXX: TODO */
2470 cpu_abort(env, "IABR exception is not implemented yet !\n");
2471 goto store_next;
2472 case POWERPC_EXCP_SMI: /* System management interrupt */
2473 /* XXX: TODO */
2474 cpu_abort(env, "SMI exception is not implemented yet !\n");
2475 goto store_next;
2476 case POWERPC_EXCP_THERM: /* Thermal interrupt */
2477 /* XXX: TODO */
2478 cpu_abort(env, "Thermal management exception "
2479 "is not implemented yet !\n");
2480 goto store_next;
2481 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
e1833e1f 2482 if (lpes1 == 0)
a4f30719 2483 new_msr |= (target_ulong)MSR_HVB;
e1833e1f
JM
2484 /* XXX: TODO */
2485 cpu_abort(env,
2486 "Performance counter exception is not implemented yet !\n");
2487 goto store_next;
2488 case POWERPC_EXCP_VPUA: /* Vector assist exception */
2489 /* XXX: TODO */
2490 cpu_abort(env, "VPU assist exception is not implemented yet !\n");
2491 goto store_next;
2492 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
2493 /* XXX: TODO */
2494 cpu_abort(env,
2495 "970 soft-patch exception is not implemented yet !\n");
2496 goto store_next;
2497 case POWERPC_EXCP_MAINT: /* Maintenance exception */
2498 /* XXX: TODO */
2499 cpu_abort(env,
2500 "970 maintenance exception is not implemented yet !\n");
2501 goto store_next;
b4095fed
JM
2502 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
2503 /* XXX: TODO */
2504 cpu_abort(env, "Maskable external exception "
2505 "is not implemented yet !\n");
2506 goto store_next;
2507 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
2508 /* XXX: TODO */
2509 cpu_abort(env, "Non maskable external exception "
2510 "is not implemented yet !\n");
2511 goto store_next;
2be0071f 2512 default:
e1833e1f
JM
2513 excp_invalid:
2514 cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
2515 break;
9a64fbe4 2516 store_current:
2be0071f 2517 /* save current instruction location */
e1833e1f 2518 env->spr[srr0] = env->nip - 4;
9a64fbe4
FB
2519 break;
2520 store_next:
2be0071f 2521 /* save next instruction location */
e1833e1f 2522 env->spr[srr0] = env->nip;
9a64fbe4
FB
2523 break;
2524 }
e1833e1f
JM
2525 /* Save MSR */
2526 env->spr[srr1] = msr;
2527 /* If any alternate SRR register are defined, duplicate saved values */
2528 if (asrr0 != -1)
2529 env->spr[asrr0] = env->spr[srr0];
2530 if (asrr1 != -1)
2531 env->spr[asrr1] = env->spr[srr1];
2be0071f 2532 /* If we disactivated any translation, flush TLBs */
0411a972 2533 if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR)))
2be0071f 2534 tlb_flush(env, 1);
41557447
AG
2535
2536 if (msr_ile) {
0411a972 2537 new_msr |= (target_ulong)1 << MSR_LE;
41557447
AG
2538 }
2539
e1833e1f
JM
2540 /* Jump to handler */
2541 vector = env->excp_vectors[excp];
6f2d8978 2542 if (vector == (target_ulong)-1ULL) {
e1833e1f
JM
2543 cpu_abort(env, "Raised an exception without defined vector %d\n",
2544 excp);
2545 }
2546 vector |= env->excp_prefix;
c62db105 2547#if defined(TARGET_PPC64)
e1833e1f 2548 if (excp_model == POWERPC_EXCP_BOOKE) {
0411a972 2549 if (!msr_icm) {
e1833e1f 2550 vector = (uint32_t)vector;
0411a972
JM
2551 } else {
2552 new_msr |= (target_ulong)1 << MSR_CM;
2553 }
c62db105 2554 } else {
6ce0ca12 2555 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
e1833e1f 2556 vector = (uint32_t)vector;
0411a972
JM
2557 } else {
2558 new_msr |= (target_ulong)1 << MSR_SF;
2559 }
c62db105 2560 }
e1833e1f 2561#endif
0411a972
JM
2562 /* XXX: we don't use hreg_store_msr here as already have treated
2563 * any special case that could occur. Just store MSR and update hflags
2564 */
a4f30719 2565 env->msr = new_msr & env->msr_mask;
0411a972 2566 hreg_compute_hflags(env);
e1833e1f
JM
2567 env->nip = vector;
2568 /* Reset exception state */
2569 env->exception_index = POWERPC_EXCP_NONE;
2570 env->error_code = 0;
a586e548
EI
2571
2572 if (env->mmu_model == POWERPC_MMU_BOOKE) {
2573 /* XXX: The BookE changes address space when switching modes,
2574 we should probably implement that as different MMU indexes,
2575 but for the moment we do it the slow way and flush all. */
2576 tlb_flush(env, 1);
2577 }
fb0eaffc 2578}
47103572 2579
e1833e1f 2580void do_interrupt (CPUState *env)
47103572 2581{
e1833e1f
JM
2582 powerpc_excp(env, env->excp_model, env->exception_index);
2583}
47103572 2584
e1833e1f
JM
2585void ppc_hw_interrupt (CPUPPCState *env)
2586{
f9fdea6b 2587 int hdice;
f9fdea6b 2588
0411a972 2589#if 0
93fcfe39 2590 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
a496775f 2591 __func__, env, env->pending_interrupts,
0411a972 2592 env->interrupt_request, (int)msr_me, (int)msr_ee);
47103572 2593#endif
e1833e1f 2594 /* External reset */
47103572 2595 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
47103572 2596 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
e1833e1f
JM
2597 powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
2598 return;
2599 }
2600 /* Machine check exception */
2601 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
2602 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
2603 powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
2604 return;
47103572 2605 }
e1833e1f
JM
2606#if 0 /* TODO */
2607 /* External debug exception */
2608 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
2609 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
2610 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
2611 return;
2612 }
2613#endif
b172c56a
JM
2614 if (0) {
2615 /* XXX: find a suitable condition to enable the hypervisor mode */
2616 hdice = env->spr[SPR_LPCR] & 1;
2617 } else {
2618 hdice = 0;
2619 }
f9fdea6b 2620 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
47103572
JM
2621 /* Hypervisor decrementer exception */
2622 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
47103572 2623 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
e1833e1f
JM
2624 powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
2625 return;
2626 }
2627 }
e1833e1f
JM
2628 if (msr_ce != 0) {
2629 /* External critical interrupt */
2630 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
2631 /* Taking a critical external interrupt does not clear the external
2632 * critical interrupt status
2633 */
2634#if 0
2635 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
47103572 2636#endif
e1833e1f
JM
2637 powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
2638 return;
2639 }
2640 }
2641 if (msr_ee != 0) {
2642 /* Watchdog timer on embedded PowerPC */
2643 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
2644 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
2645 powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
2646 return;
2647 }
e1833e1f
JM
2648 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
2649 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
2650 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
2651 return;
2652 }
e1833e1f
JM
2653 /* Fixed interval timer on embedded PowerPC */
2654 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
2655 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
2656 powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
2657 return;
2658 }
2659 /* Programmable interval timer on embedded PowerPC */
2660 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
2661 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
2662 powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
2663 return;
2664 }
47103572
JM
2665 /* Decrementer exception */
2666 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
47103572 2667 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
e1833e1f
JM
2668 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
2669 return;
2670 }
47103572 2671 /* External interrupt */
e1833e1f 2672 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
e9df014c
JM
2673 /* Taking an external interrupt does not clear the external
2674 * interrupt status
2675 */
2676#if 0
47103572 2677 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
e9df014c 2678#endif
e1833e1f
JM
2679 powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
2680 return;
2681 }
e1833e1f
JM
2682 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
2683 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
2684 powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
2685 return;
47103572 2686 }
e1833e1f
JM
2687 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
2688 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
2689 powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
2690 return;
2691 }
2692 /* Thermal interrupt */
2693 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
2694 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
2695 powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
2696 return;
2697 }
47103572 2698 }
47103572 2699}
18fba28c 2700#endif /* !CONFIG_USER_ONLY */
a496775f 2701
4a057712
JM
2702void cpu_dump_rfi (target_ulong RA, target_ulong msr)
2703{
90e189ec
BS
2704 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
2705 TARGET_FMT_lx "\n", RA, msr);
a496775f
JM
2706}
2707
d84bda46 2708void cpu_reset(CPUPPCState *env)
0a032cbe 2709{
0411a972 2710 target_ulong msr;
0a032cbe 2711
eca1bdf4
AL
2712 if (qemu_loglevel_mask(CPU_LOG_RESET)) {
2713 qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
2714 log_cpu_state(env, 0);
2715 }
2716
0411a972 2717 msr = (target_ulong)0;
a4f30719
JM
2718 if (0) {
2719 /* XXX: find a suitable condition to enable the hypervisor mode */
2720 msr |= (target_ulong)MSR_HVB;
2721 }
0411a972
JM
2722 msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
2723 msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
2724 msr |= (target_ulong)1 << MSR_EP;
0a032cbe
JM
2725#if defined (DO_SINGLE_STEP) && 0
2726 /* Single step trace mode */
0411a972
JM
2727 msr |= (target_ulong)1 << MSR_SE;
2728 msr |= (target_ulong)1 << MSR_BE;
0a032cbe
JM
2729#endif
2730#if defined(CONFIG_USER_ONLY)
0411a972 2731 msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
4c2ab988
AJ
2732 msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
2733 msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
0411a972 2734 msr |= (target_ulong)1 << MSR_PR;
fe33cc71 2735#else
fc1c67bc 2736 env->excp_prefix = env->hreset_excp_prefix;
1c27f8fb 2737 env->nip = env->hreset_vector | env->excp_prefix;
b4095fed 2738 if (env->mmu_model != POWERPC_MMU_REAL)
141c8ae2 2739 ppc_tlb_invalidate_all(env);
0a032cbe 2740#endif
07c485ce 2741 env->msr = msr & env->msr_mask;
6ce0ca12
BS
2742#if defined(TARGET_PPC64)
2743 if (env->mmu_model & POWERPC_MMU_64)
2744 env->msr |= (1ULL << MSR_SF);
2745#endif
0411a972 2746 hreg_compute_hflags(env);
18b21a2f 2747 env->reserve_addr = (target_ulong)-1ULL;
5eb7995e
JM
2748 /* Be sure no exception or interrupt is pending */
2749 env->pending_interrupts = 0;
e1833e1f
JM
2750 env->exception_index = POWERPC_EXCP_NONE;
2751 env->error_code = 0;
5eb7995e
JM
2752 /* Flush all TLBs */
2753 tlb_flush(env, 1);
0a032cbe
JM
2754}
2755
aaed909a 2756CPUPPCState *cpu_ppc_init (const char *cpu_model)
0a032cbe
JM
2757{
2758 CPUPPCState *env;
c227f099 2759 const ppc_def_t *def;
aaed909a
FB
2760
2761 def = cpu_ppc_find_by_name(cpu_model);
2762 if (!def)
2763 return NULL;
0a032cbe
JM
2764
2765 env = qemu_mallocz(sizeof(CPUPPCState));
0a032cbe 2766 cpu_exec_init(env);
2e70f6ef 2767 ppc_translate_init();
01ba9816 2768 env->cpu_model_str = cpu_model;
aaed909a 2769 cpu_ppc_register_internal(env, def);
d76d1650 2770
0bf46a40 2771 qemu_init_vcpu(env);
d76d1650 2772
0a032cbe
JM
2773 return env;
2774}
2775
2776void cpu_ppc_close (CPUPPCState *env)
2777{
2778 /* Should also remove all opcode tables... */
aaed909a 2779 qemu_free(env);
0a032cbe 2780}