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