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