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