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