]> git.proxmox.com Git - mirror_qemu.git/blame - target-ppc/helper.c
termios structure definition fix by Stuart Anderson.
[mirror_qemu.git] / target-ppc / helper.c
CommitLineData
79aceca5 1/*
3fc6c082 2 * PowerPC emulation helpers for qemu.
79aceca5 3 *
76a66253 4 * Copyright (c) 2003-2007 Jocelyn Mayer
79aceca5
FB
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
fdabc366
FB
20#include <stdarg.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <inttypes.h>
25#include <signal.h>
26#include <assert.h>
27
28#include "cpu.h"
29#include "exec-all.h"
9a64fbe4
FB
30
31//#define DEBUG_MMU
32//#define DEBUG_BATS
76a66253 33//#define DEBUG_SOFTWARE_TLB
9a64fbe4 34//#define DEBUG_EXCEPTIONS
fdabc366 35//#define FLUSH_ALL_TLBS
9a64fbe4 36
9a64fbe4 37/*****************************************************************************/
3fc6c082 38/* PowerPC MMU emulation */
a541f297 39
d9bce9d9 40#if defined(CONFIG_USER_ONLY)
e96efcfc 41int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
24741ef3
FB
42 int is_user, int is_softmmu)
43{
44 int exception, error_code;
d9bce9d9 45
24741ef3
FB
46 if (rw == 2) {
47 exception = EXCP_ISI;
48 error_code = 0;
49 } else {
50 exception = EXCP_DSI;
51 error_code = 0;
52 if (rw)
53 error_code |= 0x02000000;
54 env->spr[SPR_DAR] = address;
55 env->spr[SPR_DSISR] = error_code;
56 }
57 env->exception_index = exception;
58 env->error_code = error_code;
76a66253 59
24741ef3
FB
60 return 1;
61}
76a66253 62
9b3c35e0 63target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
24741ef3
FB
64{
65 return addr;
66}
67#else
76a66253
JM
68/* Common routines used by software and hardware TLBs emulation */
69static inline int pte_is_valid (target_ulong pte0)
70{
71 return pte0 & 0x80000000 ? 1 : 0;
72}
73
74static inline void pte_invalidate (target_ulong *pte0)
75{
76 *pte0 &= ~0x80000000;
77}
78
79#define PTE_PTEM_MASK 0x7FFFFFBF
80#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
81
82static int pte_check (mmu_ctx_t *ctx,
83 target_ulong pte0, target_ulong pte1, int h, int rw)
84{
85 int access, ret;
86
87 access = 0;
88 ret = -1;
89 /* Check validity and table match */
90 if (pte_is_valid(pte0) && (h == ((pte0 >> 6) & 1))) {
91 /* Check vsid & api */
92 if ((pte0 & PTE_PTEM_MASK) == ctx->ptem) {
93 if (ctx->raddr != (target_ulong)-1) {
94 /* all matches should have equal RPN, WIMG & PP */
95 if ((ctx->raddr & PTE_CHECK_MASK) != (pte1 & PTE_CHECK_MASK)) {
96 if (loglevel > 0)
97 fprintf(logfile, "Bad RPN/WIMG/PP\n");
98 return -3;
99 }
100 }
101 /* Compute access rights */
102 if (ctx->key == 0) {
103 access = PAGE_READ;
104 if ((pte1 & 0x00000003) != 0x3)
105 access |= PAGE_WRITE;
106 } else {
107 switch (pte1 & 0x00000003) {
108 case 0x0:
109 access = 0;
110 break;
111 case 0x1:
112 case 0x3:
113 access = PAGE_READ;
114 break;
115 case 0x2:
116 access = PAGE_READ | PAGE_WRITE;
117 break;
118 }
119 }
120 /* Keep the matching PTE informations */
121 ctx->raddr = pte1;
122 ctx->prot = access;
123 if ((rw == 0 && (access & PAGE_READ)) ||
124 (rw == 1 && (access & PAGE_WRITE))) {
125 /* Access granted */
126#if defined (DEBUG_MMU)
127 if (loglevel > 0)
128 fprintf(logfile, "PTE access granted !\n");
129#endif
130 ret = 0;
131 } else {
132 /* Access right violation */
133#if defined (DEBUG_MMU)
134 if (loglevel > 0)
135 fprintf(logfile, "PTE access rejected\n");
136#endif
137 ret = -2;
138 }
139 }
140 }
141
142 return ret;
143}
144
145static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p,
146 int ret, int rw)
147{
148 int store = 0;
149
150 /* Update page flags */
151 if (!(*pte1p & 0x00000100)) {
152 /* Update accessed flag */
153 *pte1p |= 0x00000100;
154 store = 1;
155 }
156 if (!(*pte1p & 0x00000080)) {
157 if (rw == 1 && ret == 0) {
158 /* Update changed flag */
159 *pte1p |= 0x00000080;
160 store = 1;
161 } else {
162 /* Force page fault for first write access */
163 ctx->prot &= ~PAGE_WRITE;
164 }
165 }
166
167 return store;
168}
169
170/* Software driven TLB helpers */
171static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
172 int way, int is_code)
173{
174 int nr;
175
176 /* Select TLB num in a way from address */
177 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
178 /* Select TLB way */
179 nr += env->tlb_per_way * way;
180 /* 6xx have separate TLBs for instructions and data */
181 if (is_code && env->id_tlbs == 1)
182 nr += env->nb_tlb;
183
184 return nr;
185}
186
187void ppc6xx_tlb_invalidate_all (CPUState *env)
188{
1d0a48fb 189 ppc6xx_tlb_t *tlb;
76a66253
JM
190 int nr, max;
191
192#if defined (DEBUG_SOFTWARE_TLB) && 0
193 if (loglevel != 0) {
194 fprintf(logfile, "Invalidate all TLBs\n");
195 }
196#endif
197 /* Invalidate all defined software TLB */
198 max = env->nb_tlb;
199 if (env->id_tlbs == 1)
200 max *= 2;
201 for (nr = 0; nr < max; nr++) {
1d0a48fb 202 tlb = &env->tlb[nr].tlb6;
76a66253
JM
203#if !defined(FLUSH_ALL_TLBS)
204 tlb_flush_page(env, tlb->EPN);
205#endif
206 pte_invalidate(&tlb->pte0);
207 }
208#if defined(FLUSH_ALL_TLBS)
209 tlb_flush(env, 1);
210#endif
211}
212
213static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env,
214 target_ulong eaddr,
215 int is_code, int match_epn)
216{
1d0a48fb 217 ppc6xx_tlb_t *tlb;
76a66253
JM
218 int way, nr;
219
220#if !defined(FLUSH_ALL_TLBS)
221 /* Invalidate ITLB + DTLB, all ways */
222 for (way = 0; way < env->nb_ways; way++) {
223 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
1d0a48fb 224 tlb = &env->tlb[nr].tlb6;
76a66253
JM
225 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
226#if defined (DEBUG_SOFTWARE_TLB)
227 if (loglevel != 0) {
1b9eb036 228 fprintf(logfile, "TLB invalidate %d/%d " ADDRX "\n",
76a66253
JM
229 nr, env->nb_tlb, eaddr);
230 }
231#endif
232 pte_invalidate(&tlb->pte0);
233 tlb_flush_page(env, tlb->EPN);
234 }
235 }
236#else
237 /* XXX: PowerPC specification say this is valid as well */
238 ppc6xx_tlb_invalidate_all(env);
239#endif
240}
241
242void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
243 int is_code)
244{
245 __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
246}
247
248void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
249 target_ulong pte0, target_ulong pte1)
250{
1d0a48fb 251 ppc6xx_tlb_t *tlb;
76a66253
JM
252 int nr;
253
254 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
1d0a48fb 255 tlb = &env->tlb[nr].tlb6;
76a66253
JM
256#if defined (DEBUG_SOFTWARE_TLB)
257 if (loglevel != 0) {
1b9eb036
JM
258 fprintf(logfile, "Set TLB %d/%d EPN " ADDRX " PTE0 " ADDRX
259 " PTE1 " ADDRX "\n", nr, env->nb_tlb, EPN, pte0, pte1);
76a66253
JM
260 }
261#endif
262 /* Invalidate any pending reference in Qemu for this virtual address */
263 __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
264 tlb->pte0 = pte0;
265 tlb->pte1 = pte1;
266 tlb->EPN = EPN;
76a66253
JM
267 /* Store last way for LRU mechanism */
268 env->last_way = way;
269}
270
271static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
272 target_ulong eaddr, int rw, int access_type)
273{
1d0a48fb 274 ppc6xx_tlb_t *tlb;
76a66253
JM
275 int nr, best, way;
276 int ret;
d9bce9d9 277
76a66253
JM
278 best = -1;
279 ret = -1; /* No TLB found */
280 for (way = 0; way < env->nb_ways; way++) {
281 nr = ppc6xx_tlb_getnum(env, eaddr, way,
282 access_type == ACCESS_CODE ? 1 : 0);
1d0a48fb 283 tlb = &env->tlb[nr].tlb6;
76a66253
JM
284 /* This test "emulates" the PTE index match for hardware TLBs */
285 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
286#if defined (DEBUG_SOFTWARE_TLB)
287 if (loglevel != 0) {
1b9eb036
JM
288 fprintf(logfile, "TLB %d/%d %s [" ADDRX " " ADDRX
289 "] <> " ADDRX "\n",
76a66253
JM
290 nr, env->nb_tlb,
291 pte_is_valid(tlb->pte0) ? "valid" : "inval",
292 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
293 }
294#endif
295 continue;
296 }
297#if defined (DEBUG_SOFTWARE_TLB)
298 if (loglevel != 0) {
1b9eb036
JM
299 fprintf(logfile, "TLB %d/%d %s " ADDRX " <> " ADDRX " " ADDRX
300 " %c %c\n",
76a66253
JM
301 nr, env->nb_tlb,
302 pte_is_valid(tlb->pte0) ? "valid" : "inval",
303 tlb->EPN, eaddr, tlb->pte1,
304 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
305 }
306#endif
307 switch (pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) {
308 case -3:
309 /* TLB inconsistency */
310 return -1;
311 case -2:
312 /* Access violation */
313 ret = -2;
314 best = nr;
315 break;
316 case -1:
317 default:
318 /* No match */
319 break;
320 case 0:
321 /* access granted */
322 /* XXX: we should go on looping to check all TLBs consistency
323 * but we can speed-up the whole thing as the
324 * result would be undefined if TLBs are not consistent.
325 */
326 ret = 0;
327 best = nr;
328 goto done;
329 }
330 }
331 if (best != -1) {
332 done:
333#if defined (DEBUG_SOFTWARE_TLB)
334 if (loglevel > 0) {
335 fprintf(logfile, "found TLB at addr 0x%08lx prot=0x%01x ret=%d\n",
336 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
337 }
338#endif
339 /* Update page flags */
1d0a48fb 340 pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw);
76a66253
JM
341 }
342
343 return ret;
344}
345
9a64fbe4 346/* Perform BAT hit & translation */
76a66253
JM
347static int get_bat (CPUState *env, mmu_ctx_t *ctx,
348 target_ulong virtual, int rw, int type)
9a64fbe4 349{
76a66253
JM
350 target_ulong *BATlt, *BATut, *BATu, *BATl;
351 target_ulong base, BEPIl, BEPIu, bl;
9a64fbe4
FB
352 int i;
353 int ret = -1;
354
355#if defined (DEBUG_BATS)
356 if (loglevel > 0) {
1b9eb036 357 fprintf(logfile, "%s: %cBAT v 0x" ADDRX "\n", __func__,
76a66253 358 type == ACCESS_CODE ? 'I' : 'D', virtual);
9a64fbe4 359 }
9a64fbe4
FB
360#endif
361 switch (type) {
362 case ACCESS_CODE:
363 BATlt = env->IBAT[1];
364 BATut = env->IBAT[0];
365 break;
366 default:
367 BATlt = env->DBAT[1];
368 BATut = env->DBAT[0];
369 break;
370 }
371#if defined (DEBUG_BATS)
372 if (loglevel > 0) {
1b9eb036 373 fprintf(logfile, "%s...: %cBAT v 0x" ADDRX "\n", __func__,
76a66253 374 type == ACCESS_CODE ? 'I' : 'D', virtual);
9a64fbe4 375 }
9a64fbe4
FB
376#endif
377 base = virtual & 0xFFFC0000;
378 for (i = 0; i < 4; i++) {
379 BATu = &BATut[i];
380 BATl = &BATlt[i];
381 BEPIu = *BATu & 0xF0000000;
382 BEPIl = *BATu & 0x0FFE0000;
383 bl = (*BATu & 0x00001FFC) << 15;
384#if defined (DEBUG_BATS)
385 if (loglevel > 0) {
1b9eb036
JM
386 fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
387 " BATl 0x" ADDRX "\n",
9a64fbe4
FB
388 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
389 *BATu, *BATl);
9a64fbe4
FB
390 }
391#endif
392 if ((virtual & 0xF0000000) == BEPIu &&
393 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
394 /* BAT matches */
395 if ((msr_pr == 0 && (*BATu & 0x00000002)) ||
396 (msr_pr == 1 && (*BATu & 0x00000001))) {
397 /* Get physical address */
76a66253 398 ctx->raddr = (*BATl & 0xF0000000) |
9a64fbe4 399 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
a541f297 400 (virtual & 0x0001F000);
9a64fbe4 401 if (*BATl & 0x00000001)
76a66253 402 ctx->prot = PAGE_READ;
9a64fbe4 403 if (*BATl & 0x00000002)
76a66253 404 ctx->prot = PAGE_WRITE | PAGE_READ;
9a64fbe4
FB
405#if defined (DEBUG_BATS)
406 if (loglevel > 0) {
1b9eb036
JM
407 fprintf(logfile, "BAT %d match: r 0x" ADDRX
408 " prot=%c%c\n",
76a66253
JM
409 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
410 ctx->prot & PAGE_WRITE ? 'W' : '-');
9a64fbe4
FB
411 }
412#endif
413 ret = 0;
414 break;
415 }
416 }
417 }
418 if (ret < 0) {
419#if defined (DEBUG_BATS)
1b9eb036 420 printf("no BAT match for 0x" ADDRX ":\n", virtual);
9a64fbe4
FB
421 for (i = 0; i < 4; i++) {
422 BATu = &BATut[i];
423 BATl = &BATlt[i];
424 BEPIu = *BATu & 0xF0000000;
425 BEPIl = *BATu & 0x0FFE0000;
426 bl = (*BATu & 0x00001FFC) << 15;
1b9eb036
JM
427 printf("%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
428 " BATl 0x" ADDRX " \n\t"
429 "0x" ADDRX " 0x" ADDRX " 0x" ADDRX "\n",
9a64fbe4
FB
430 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
431 *BATu, *BATl, BEPIu, BEPIl, bl);
432 }
433#endif
9a64fbe4
FB
434 }
435 /* No hit */
436 return ret;
437}
438
439/* PTE table lookup */
76a66253 440static int find_pte (mmu_ctx_t *ctx, int h, int rw)
9a64fbe4 441{
76a66253
JM
442 target_ulong base, pte0, pte1;
443 int i, good = -1;
444 int ret;
9a64fbe4 445
76a66253
JM
446 ret = -1; /* No entry found */
447 base = ctx->pg_addr[h];
9a64fbe4 448 for (i = 0; i < 8; i++) {
8df1cd07
FB
449 pte0 = ldl_phys(base + (i * 8));
450 pte1 = ldl_phys(base + (i * 8) + 4);
9a64fbe4 451#if defined (DEBUG_MMU)
d094807b 452 if (loglevel > 0) {
1b9eb036
JM
453 fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
454 " 0x" ADDRX " %d %d %d 0x" ADDRX "\n",
455 base + (i * 8), pte0, pte1,
76a66253
JM
456 pte0 >> 31, h, (pte0 >> 6) & 1, ctx->ptem);
457 }
9a64fbe4 458#endif
76a66253
JM
459 switch (pte_check(ctx, pte0, pte1, h, rw)) {
460 case -3:
461 /* PTE inconsistency */
462 return -1;
463 case -2:
464 /* Access violation */
465 ret = -2;
466 good = i;
467 break;
468 case -1:
469 default:
470 /* No PTE match */
471 break;
472 case 0:
473 /* access granted */
474 /* XXX: we should go on looping to check all PTEs consistency
475 * but if we can speed-up the whole thing as the
476 * result would be undefined if PTEs are not consistent.
477 */
478 ret = 0;
479 good = i;
480 goto done;
9a64fbe4
FB
481 }
482 }
483 if (good != -1) {
76a66253 484 done:
9a64fbe4 485#if defined (DEBUG_MMU)
d094807b 486 if (loglevel > 0) {
1b9eb036
JM
487 fprintf(logfile, "found PTE at addr 0x" ADDRX " prot=0x%01x "
488 "ret=%d\n",
76a66253
JM
489 ctx->raddr, ctx->prot, ret);
490 }
9a64fbe4
FB
491#endif
492 /* Update page flags */
76a66253
JM
493 pte1 = ctx->raddr;
494 if (pte_update_flags(ctx, &pte1, ret, rw) == 1)
495 stl_phys_notdirty(base + (good * 8) + 4, pte1);
9a64fbe4
FB
496 }
497
498 return ret;
79aceca5
FB
499}
500
76a66253
JM
501static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1,
502 target_phys_addr_t hash,
503 target_phys_addr_t mask)
79aceca5 504{
9a64fbe4 505 return (sdr1 & 0xFFFF0000) | (hash & mask);
79aceca5
FB
506}
507
9a64fbe4 508/* Perform segment based translation */
76a66253
JM
509static int get_segment (CPUState *env, mmu_ctx_t *ctx,
510 target_ulong eaddr, int rw, int type)
79aceca5 511{
76a66253
JM
512 target_phys_addr_t sdr, hash, mask;
513 target_ulong sr, vsid, pgidx;
9a64fbe4 514 int ret = -1, ret2;
79aceca5 515
76a66253 516 sr = env->sr[eaddr >> 28];
9a64fbe4 517#if defined (DEBUG_MMU)
a541f297 518 if (loglevel > 0) {
1b9eb036
JM
519 fprintf(logfile, "Check segment v=0x" ADDRX " %d 0x" ADDRX " nip=0x"
520 ADDRX " lr=0x" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n",
76a66253
JM
521 eaddr, eaddr >> 28, sr, env->nip,
522 env->lr, msr_ir, msr_dr, msr_pr, rw, type);
a541f297 523 }
9a64fbe4 524#endif
76a66253
JM
525 ctx->key = (((sr & 0x20000000) && msr_pr == 1) ||
526 ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
9a64fbe4
FB
527 if ((sr & 0x80000000) == 0) {
528#if defined (DEBUG_MMU)
76a66253 529 if (loglevel > 0)
1b9eb036 530 fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n",
76a66253 531 ctx->key, sr & 0x10000000);
9a64fbe4
FB
532#endif
533 /* Check if instruction fetch is allowed, if needed */
534 if (type != ACCESS_CODE || (sr & 0x10000000) == 0) {
535 /* Page address translation */
76a66253 536 pgidx = (eaddr >> TARGET_PAGE_BITS) & 0xFFFF;
9a64fbe4 537 vsid = sr & 0x00FFFFFF;
a541f297 538 hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6;
76a66253
JM
539 /* Primary table address */
540 sdr = env->sdr1;
9a64fbe4 541 mask = ((sdr & 0x000001FF) << 16) | 0xFFC0;
76a66253
JM
542 ctx->pg_addr[0] = get_pgaddr(sdr, hash, mask);
543 /* Secondary table address */
544 hash = (~hash) & 0x01FFFFC0;
545 ctx->pg_addr[1] = get_pgaddr(sdr, hash, mask);
546 ctx->ptem = (vsid << 7) | (pgidx >> 10);
547 /* Initialize real address with an invalid value */
548 ctx->raddr = (target_ulong)-1;
549 if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
550 /* Software TLB search */
551 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
76a66253 552 } else {
9a64fbe4 553#if defined (DEBUG_MMU)
76a66253 554 if (loglevel > 0) {
1b9eb036
JM
555 fprintf(logfile, "0 sdr1=0x" ADDRX " vsid=0x%06x "
556 "api=0x%04x hash=0x%07x pg_addr=0x" ADDRX "\n",
557 sdr, vsid, pgidx, hash, ctx->pg_addr[0]);
76a66253 558 }
9a64fbe4 559#endif
76a66253
JM
560 /* Primary table lookup */
561 ret = find_pte(ctx, 0, rw);
562 if (ret < 0) {
563 /* Secondary table lookup */
9a64fbe4 564#if defined (DEBUG_MMU)
76a66253
JM
565 if (eaddr != 0xEFFFFFFF && loglevel > 0) {
566 fprintf(logfile,
1b9eb036
JM
567 "1 sdr1=0x" ADDRX " vsid=0x%06x api=0x%04x "
568 "hash=0x%05x pg_addr=0x" ADDRX "\n",
569 sdr, vsid, pgidx, hash, ctx->pg_addr[1]);
76a66253 570 }
9a64fbe4 571#endif
76a66253
JM
572 ret2 = find_pte(ctx, 1, rw);
573 if (ret2 != -1)
574 ret = ret2;
575 }
9a64fbe4 576 }
9a64fbe4
FB
577 } else {
578#if defined (DEBUG_MMU)
76a66253
JM
579 if (loglevel > 0)
580 fprintf(logfile, "No access allowed\n");
9a64fbe4 581#endif
76a66253 582 ret = -3;
9a64fbe4
FB
583 }
584 } else {
585#if defined (DEBUG_MMU)
a541f297 586 if (loglevel > 0)
76a66253 587 fprintf(logfile, "direct store...\n");
9a64fbe4
FB
588#endif
589 /* Direct-store segment : absolutely *BUGGY* for now */
590 switch (type) {
591 case ACCESS_INT:
592 /* Integer load/store : only access allowed */
593 break;
594 case ACCESS_CODE:
595 /* No code fetch is allowed in direct-store areas */
596 return -4;
597 case ACCESS_FLOAT:
598 /* Floating point load/store */
599 return -4;
600 case ACCESS_RES:
601 /* lwarx, ldarx or srwcx. */
602 return -4;
603 case ACCESS_CACHE:
604 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
605 /* Should make the instruction do no-op.
606 * As it already do no-op, it's quite easy :-)
607 */
76a66253 608 ctx->raddr = eaddr;
9a64fbe4
FB
609 return 0;
610 case ACCESS_EXT:
611 /* eciwx or ecowx */
612 return -4;
613 default:
614 if (logfile) {
615 fprintf(logfile, "ERROR: instruction should not need "
616 "address translation\n");
617 }
618 printf("ERROR: instruction should not need "
619 "address translation\n");
620 return -4;
621 }
76a66253
JM
622 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
623 ctx->raddr = eaddr;
9a64fbe4
FB
624 ret = 2;
625 } else {
626 ret = -2;
627 }
79aceca5 628 }
9a64fbe4
FB
629
630 return ret;
79aceca5
FB
631}
632
0a032cbe
JM
633void ppc4xx_tlb_invalidate_all (CPUState *env)
634{
635 ppcemb_tlb_t *tlb;
636 int i;
637
638 for (i = 0; i < env->nb_tlb; i++) {
639 tlb = &env->tlb[i].tlbe;
640 if (tlb->prot & PAGE_VALID) {
641#if 0 // XXX: TLB have variable sizes then we flush all Qemu TLB.
642 end = tlb->EPN + tlb->size;
643 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
644 tlb_flush_page(env, page);
645#endif
646 tlb->prot &= ~PAGE_VALID;
647 }
648 }
649 tlb_flush(env, 1);
650}
651
a8dea12f 652int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
e96efcfc 653 target_ulong address, int rw, int access_type)
a8dea12f
JM
654{
655 ppcemb_tlb_t *tlb;
656 target_phys_addr_t raddr;
657 target_ulong mask;
658 int i, ret, zsel, zpr;
659
c55e9aef
JM
660 ret = -1;
661 raddr = -1;
a8dea12f
JM
662 for (i = 0; i < env->nb_tlb; i++) {
663 tlb = &env->tlb[i].tlbe;
664 /* Check valid flag */
665 if (!(tlb->prot & PAGE_VALID)) {
666 if (loglevel)
667 fprintf(logfile, "%s: TLB %d not valid\n", __func__, i);
668 continue;
669 }
670 mask = ~(tlb->size - 1);
671 if (loglevel) {
a496775f
JM
672 fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> "
673 ADDRX " " ADDRX " %d\n",
674 __func__, i, address, (int)env->spr[SPR_40x_PID],
675 tlb->EPN, mask, (int)tlb->PID);
a8dea12f
JM
676 }
677 /* Check PID */
678 if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
679 continue;
680 /* Check effective address */
681 if ((address & mask) != tlb->EPN)
682 continue;
683 raddr = (tlb->RPN & mask) | (address & ~mask);
684 zsel = (tlb->attr >> 4) & 0xF;
685 zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3;
686 if (loglevel) {
687 fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
688 __func__, i, zsel, zpr, rw, tlb->attr);
689 }
690 if (access_type == ACCESS_CODE) {
691 /* Check execute enable bit */
692 switch (zpr) {
693 case 0x0:
694 if (msr_pr) {
a8dea12f 695 ctx->prot = 0;
c55e9aef 696 ret = -3;
a8dea12f
JM
697 break;
698 }
699 /* No break here */
700 case 0x1:
701 case 0x2:
702 /* Check from TLB entry */
703 if (!(tlb->prot & PAGE_EXEC)) {
704 ret = -3;
705 } else {
c55e9aef 706 if (tlb->prot & PAGE_WRITE) {
a8dea12f 707 ctx->prot = PAGE_READ | PAGE_WRITE;
c55e9aef 708 } else {
a8dea12f 709 ctx->prot = PAGE_READ;
c55e9aef 710 }
a8dea12f
JM
711 ret = 0;
712 }
713 break;
714 case 0x3:
715 /* All accesses granted */
a8dea12f 716 ctx->prot = PAGE_READ | PAGE_WRITE;
c55e9aef 717 ret = 0;
a8dea12f
JM
718 break;
719 }
720 } else {
721 switch (zpr) {
722 case 0x0:
723 if (msr_pr) {
a8dea12f 724 ctx->prot = 0;
c55e9aef 725 ret = -2;
a8dea12f
JM
726 break;
727 }
728 /* No break here */
729 case 0x1:
730 case 0x2:
731 /* Check from TLB entry */
732 /* Check write protection bit */
c55e9aef
JM
733 if (tlb->prot & PAGE_WRITE) {
734 ctx->prot = PAGE_READ | PAGE_WRITE;
735 ret = 0;
a8dea12f 736 } else {
c55e9aef
JM
737 ctx->prot = PAGE_READ;
738 if (rw)
739 ret = -2;
a8dea12f 740 else
c55e9aef 741 ret = 0;
a8dea12f
JM
742 }
743 break;
744 case 0x3:
745 /* All accesses granted */
a8dea12f 746 ctx->prot = PAGE_READ | PAGE_WRITE;
c55e9aef 747 ret = 0;
a8dea12f
JM
748 break;
749 }
750 }
751 if (ret >= 0) {
752 ctx->raddr = raddr;
753 if (loglevel) {
754 fprintf(logfile, "%s: access granted " ADDRX " => " REGX
c55e9aef
JM
755 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
756 ret);
a8dea12f 757 }
c55e9aef 758 return 0;
a8dea12f
JM
759 }
760 }
c55e9aef
JM
761 if (loglevel) {
762 fprintf(logfile, "%s: access refused " ADDRX " => " REGX
763 " %d %d\n", __func__, address, raddr, ctx->prot,
764 ret);
765 }
a8dea12f
JM
766
767 return ret;
768}
769
76a66253
JM
770static int check_physical (CPUState *env, mmu_ctx_t *ctx,
771 target_ulong eaddr, int rw)
772{
773 int in_plb, ret;
774
775 ctx->raddr = eaddr;
776 ctx->prot = PAGE_READ;
777 ret = 0;
778 if (unlikely(msr_pe != 0 && PPC_MMU(env) == PPC_FLAGS_MMU_403)) {
779 /* 403 family add some particular protections,
780 * using PBL/PBU registers for accesses with no translation.
781 */
782 in_plb =
783 /* Check PLB validity */
784 (env->pb[0] < env->pb[1] &&
785 /* and address in plb area */
786 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
787 (env->pb[2] < env->pb[3] &&
788 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
789 if (in_plb ^ msr_px) {
790 /* Access in protected area */
791 if (rw == 1) {
792 /* Access is not allowed */
793 ret = -2;
794 }
795 } else {
796 /* Read-write access is allowed */
797 ctx->prot |= PAGE_WRITE;
798 }
799 } else {
800 ctx->prot |= PAGE_WRITE;
801 }
802
803 return ret;
804}
805
806int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
807 int rw, int access_type, int check_BATs)
9a64fbe4
FB
808{
809 int ret;
514fb8c1 810#if 0
9a64fbe4
FB
811 if (loglevel > 0) {
812 fprintf(logfile, "%s\n", __func__);
813 }
d9bce9d9 814#endif
4b3686fa
FB
815 if ((access_type == ACCESS_CODE && msr_ir == 0) ||
816 (access_type != ACCESS_CODE && msr_dr == 0)) {
9a64fbe4 817 /* No address translation */
76a66253 818 ret = check_physical(env, ctx, eaddr, rw);
9a64fbe4 819 } else {
c55e9aef 820 ret = -1;
a8dea12f
JM
821 switch (PPC_MMU(env)) {
822 case PPC_FLAGS_MMU_32B:
823 case PPC_FLAGS_MMU_SOFT_6xx:
824 /* Try to find a BAT */
a8dea12f
JM
825 if (check_BATs)
826 ret = get_bat(env, ctx, eaddr, rw, access_type);
c55e9aef
JM
827 /* No break here */
828#if defined(TARGET_PPC64)
829 case PPC_FLAGS_MMU_64B:
830 case PPC_FLAGS_MMU_64BRIDGE:
831#endif
a8dea12f 832 if (ret < 0) {
c55e9aef 833 /* We didn't match any BAT entry or don't have BATs */
a8dea12f
JM
834 ret = get_segment(env, ctx, eaddr, rw, access_type);
835 }
836 break;
837 case PPC_FLAGS_MMU_SOFT_4xx:
c55e9aef 838 case PPC_FLAGS_MMU_403:
a8dea12f
JM
839 ret = mmu4xx_get_physical_address(env, ctx, eaddr,
840 rw, access_type);
841 break;
c55e9aef
JM
842 case PPC_FLAGS_MMU_601:
843 /* XXX: TODO */
844 cpu_abort(env, "601 MMU model not implemented\n");
845 return -1;
846 case PPC_FLAGS_MMU_BOOKE:
a8dea12f 847 /* XXX: TODO */
c55e9aef
JM
848 cpu_abort(env, "BookeE MMU model not implemented\n");
849 return -1;
850 case PPC_FLAGS_MMU_BOOKE_FSL:
851 /* XXX: TODO */
852 cpu_abort(env, "BookE FSL MMU model not implemented\n");
853 return -1;
854 default:
855 cpu_abort(env, "Unknown or invalid MMU model\n");
a8dea12f 856 return -1;
9a64fbe4
FB
857 }
858 }
514fb8c1 859#if 0
a541f297 860 if (loglevel > 0) {
c55e9aef
JM
861 fprintf(logfile, "%s address " ADDRX " => %d " ADDRX "\n",
862 __func__, eaddr, ret, ctx->raddr);
a541f297 863 }
76a66253 864#endif
d9bce9d9 865
9a64fbe4
FB
866 return ret;
867}
868
9b3c35e0 869target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
a6b025d3 870{
76a66253 871 mmu_ctx_t ctx;
a6b025d3 872
76a66253 873 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT, 1) != 0))
a6b025d3 874 return -1;
76a66253
JM
875
876 return ctx.raddr & TARGET_PAGE_MASK;
a6b025d3 877}
9a64fbe4 878
9a64fbe4 879/* Perform address translation */
e96efcfc 880int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
a541f297 881 int is_user, int is_softmmu)
9a64fbe4 882{
76a66253 883 mmu_ctx_t ctx;
9a64fbe4 884 int exception = 0, error_code = 0;
a541f297 885 int access_type;
9a64fbe4 886 int ret = 0;
d9bce9d9 887
b769d8fe
FB
888 if (rw == 2) {
889 /* code access */
890 rw = 0;
891 access_type = ACCESS_CODE;
892 } else {
893 /* data access */
894 /* XXX: put correct access by using cpu_restore_state()
895 correctly */
896 access_type = ACCESS_INT;
897 // access_type = env->access_type;
898 }
76a66253 899 ret = get_physical_address(env, &ctx, address, rw, access_type, 1);
9a64fbe4 900 if (ret == 0) {
76a66253
JM
901 ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
902 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
903 is_user, is_softmmu);
9a64fbe4 904 } else if (ret < 0) {
9a64fbe4 905#if defined (DEBUG_MMU)
76a66253
JM
906 if (loglevel > 0)
907 cpu_dump_state(env, logfile, fprintf, 0);
9a64fbe4
FB
908#endif
909 if (access_type == ACCESS_CODE) {
910 exception = EXCP_ISI;
911 switch (ret) {
912 case -1:
76a66253 913 /* No matches in page tables or TLB */
c55e9aef
JM
914 switch (PPC_MMU(env)) {
915 case PPC_FLAGS_MMU_SOFT_6xx:
76a66253
JM
916 exception = EXCP_I_TLBMISS;
917 env->spr[SPR_IMISS] = address;
918 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
919 error_code = 1 << 18;
920 goto tlb_miss;
c55e9aef
JM
921 case PPC_FLAGS_MMU_SOFT_4xx:
922 case PPC_FLAGS_MMU_403:
a8dea12f
JM
923 exception = EXCP_40x_ITLBMISS;
924 error_code = 0;
925 env->spr[SPR_40x_DEAR] = address;
926 env->spr[SPR_40x_ESR] = 0x00000000;
c55e9aef
JM
927 break;
928 case PPC_FLAGS_MMU_32B:
76a66253 929 error_code = 0x40000000;
c55e9aef
JM
930 break;
931#if defined(TARGET_PPC64)
932 case PPC_FLAGS_MMU_64B:
933 /* XXX: TODO */
934 cpu_abort(env, "MMU model not implemented\n");
935 return -1;
936 case PPC_FLAGS_MMU_64BRIDGE:
937 /* XXX: TODO */
938 cpu_abort(env, "MMU model not implemented\n");
939 return -1;
940#endif
941 case PPC_FLAGS_MMU_601:
942 /* XXX: TODO */
943 cpu_abort(env, "MMU model not implemented\n");
944 return -1;
945 case PPC_FLAGS_MMU_BOOKE:
946 /* XXX: TODO */
947 cpu_abort(env, "MMU model not implemented\n");
948 return -1;
949 case PPC_FLAGS_MMU_BOOKE_FSL:
950 /* XXX: TODO */
951 cpu_abort(env, "MMU model not implemented\n");
952 return -1;
953 default:
954 cpu_abort(env, "Unknown or invalid MMU model\n");
955 return -1;
76a66253 956 }
9a64fbe4
FB
957 break;
958 case -2:
959 /* Access rights violation */
2be0071f 960 error_code = 0x08000000;
9a64fbe4
FB
961 break;
962 case -3:
76a66253 963 /* No execute protection violation */
2be0071f 964 error_code = 0x10000000;
9a64fbe4
FB
965 break;
966 case -4:
967 /* Direct store exception */
968 /* No code fetch is allowed in direct-store areas */
2be0071f
FB
969 error_code = 0x10000000;
970 break;
971 case -5:
972 /* No match in segment table */
973 exception = EXCP_ISEG;
974 error_code = 0;
9a64fbe4
FB
975 break;
976 }
977 } else {
978 exception = EXCP_DSI;
979 switch (ret) {
980 case -1:
76a66253 981 /* No matches in page tables or TLB */
c55e9aef
JM
982 switch (PPC_MMU(env)) {
983 case PPC_FLAGS_MMU_SOFT_6xx:
76a66253
JM
984 if (rw == 1) {
985 exception = EXCP_DS_TLBMISS;
986 error_code = 1 << 16;
987 } else {
988 exception = EXCP_DL_TLBMISS;
989 error_code = 0;
990 }
991 env->spr[SPR_DMISS] = address;
992 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
993 tlb_miss:
994 error_code |= ctx.key << 19;
995 env->spr[SPR_HASH1] = ctx.pg_addr[0];
996 env->spr[SPR_HASH2] = ctx.pg_addr[1];
997 /* Do not alter DAR nor DSISR */
998 goto out;
c55e9aef
JM
999 case PPC_FLAGS_MMU_SOFT_4xx:
1000 case PPC_FLAGS_MMU_403:
a8dea12f
JM
1001 exception = EXCP_40x_DTLBMISS;
1002 error_code = 0;
1003 env->spr[SPR_40x_DEAR] = address;
1004 if (rw)
1005 env->spr[SPR_40x_ESR] = 0x00800000;
1006 else
1007 env->spr[SPR_40x_ESR] = 0x00000000;
c55e9aef
JM
1008 break;
1009 case PPC_FLAGS_MMU_32B:
76a66253 1010 error_code = 0x40000000;
c55e9aef
JM
1011 break;
1012#if defined(TARGET_PPC64)
1013 case PPC_FLAGS_MMU_64B:
1014 /* XXX: TODO */
1015 cpu_abort(env, "MMU model not implemented\n");
1016 return -1;
1017 case PPC_FLAGS_MMU_64BRIDGE:
1018 /* XXX: TODO */
1019 cpu_abort(env, "MMU model not implemented\n");
1020 return -1;
1021#endif
1022 case PPC_FLAGS_MMU_601:
1023 /* XXX: TODO */
1024 cpu_abort(env, "MMU model not implemented\n");
1025 return -1;
1026 case PPC_FLAGS_MMU_BOOKE:
1027 /* XXX: TODO */
1028 cpu_abort(env, "MMU model not implemented\n");
1029 return -1;
1030 case PPC_FLAGS_MMU_BOOKE_FSL:
1031 /* XXX: TODO */
1032 cpu_abort(env, "MMU model not implemented\n");
1033 return -1;
1034 default:
1035 cpu_abort(env, "Unknown or invalid MMU model\n");
1036 return -1;
76a66253 1037 }
9a64fbe4
FB
1038 break;
1039 case -2:
1040 /* Access rights violation */
2be0071f 1041 error_code = 0x08000000;
9a64fbe4
FB
1042 break;
1043 case -4:
1044 /* Direct store exception */
1045 switch (access_type) {
1046 case ACCESS_FLOAT:
1047 /* Floating point load/store */
1048 exception = EXCP_ALIGN;
1049 error_code = EXCP_ALIGN_FP;
1050 break;
1051 case ACCESS_RES:
1052 /* lwarx, ldarx or srwcx. */
2be0071f 1053 error_code = 0x04000000;
9a64fbe4
FB
1054 break;
1055 case ACCESS_EXT:
1056 /* eciwx or ecowx */
2be0071f 1057 error_code = 0x04100000;
9a64fbe4
FB
1058 break;
1059 default:
76a66253 1060 printf("DSI: invalid exception (%d)\n", ret);
9a64fbe4
FB
1061 exception = EXCP_PROGRAM;
1062 error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
1063 break;
1064 }
fdabc366 1065 break;
2be0071f
FB
1066 case -5:
1067 /* No match in segment table */
1068 exception = EXCP_DSEG;
1069 error_code = 0;
1070 break;
9a64fbe4 1071 }
fdabc366 1072 if (exception == EXCP_DSI && rw == 1)
2be0071f 1073 error_code |= 0x02000000;
76a66253
JM
1074 /* Store fault address */
1075 env->spr[SPR_DAR] = address;
2be0071f 1076 env->spr[SPR_DSISR] = error_code;
9a64fbe4 1077 }
76a66253 1078 out:
9a64fbe4
FB
1079#if 0
1080 printf("%s: set exception to %d %02x\n",
1081 __func__, exception, error_code);
1082#endif
1083 env->exception_index = exception;
1084 env->error_code = error_code;
9a64fbe4
FB
1085 ret = 1;
1086 }
76a66253 1087
9a64fbe4
FB
1088 return ret;
1089}
1090
3fc6c082
FB
1091/*****************************************************************************/
1092/* BATs management */
1093#if !defined(FLUSH_ALL_TLBS)
1094static inline void do_invalidate_BAT (CPUPPCState *env,
1095 target_ulong BATu, target_ulong mask)
1096{
1097 target_ulong base, end, page;
76a66253 1098
3fc6c082
FB
1099 base = BATu & ~0x0001FFFF;
1100 end = base + mask + 0x00020000;
1101#if defined (DEBUG_BATS)
76a66253 1102 if (loglevel != 0) {
1b9eb036 1103 fprintf(logfile, "Flush BAT from " ADDRX " to " ADDRX " (" ADDRX ")\n",
76a66253
JM
1104 base, end, mask);
1105 }
3fc6c082
FB
1106#endif
1107 for (page = base; page != end; page += TARGET_PAGE_SIZE)
1108 tlb_flush_page(env, page);
1109#if defined (DEBUG_BATS)
1110 if (loglevel != 0)
1111 fprintf(logfile, "Flush done\n");
1112#endif
1113}
1114#endif
1115
1116static inline void dump_store_bat (CPUPPCState *env, char ID, int ul, int nr,
1117 target_ulong value)
1118{
1119#if defined (DEBUG_BATS)
1120 if (loglevel != 0) {
1b9eb036
JM
1121 fprintf(logfile, "Set %cBAT%d%c to 0x" ADDRX " (0x" ADDRX ")\n",
1122 ID, nr, ul == 0 ? 'u' : 'l', value, env->nip);
3fc6c082
FB
1123 }
1124#endif
1125}
1126
1127target_ulong do_load_ibatu (CPUPPCState *env, int nr)
1128{
1129 return env->IBAT[0][nr];
1130}
1131
1132target_ulong do_load_ibatl (CPUPPCState *env, int nr)
1133{
1134 return env->IBAT[1][nr];
1135}
1136
1137void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
1138{
1139 target_ulong mask;
1140
1141 dump_store_bat(env, 'I', 0, nr, value);
1142 if (env->IBAT[0][nr] != value) {
1143 mask = (value << 15) & 0x0FFE0000UL;
1144#if !defined(FLUSH_ALL_TLBS)
1145 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1146#endif
1147 /* When storing valid upper BAT, mask BEPI and BRPN
1148 * and invalidate all TLBs covered by this BAT
1149 */
1150 mask = (value << 15) & 0x0FFE0000UL;
1151 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1152 (value & ~0x0001FFFFUL & ~mask);
1153 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1154 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1155#if !defined(FLUSH_ALL_TLBS)
1156 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
76a66253 1157#else
3fc6c082
FB
1158 tlb_flush(env, 1);
1159#endif
1160 }
1161}
1162
1163void do_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
1164{
1165 dump_store_bat(env, 'I', 1, nr, value);
1166 env->IBAT[1][nr] = value;
1167}
1168
1169target_ulong do_load_dbatu (CPUPPCState *env, int nr)
1170{
1171 return env->DBAT[0][nr];
1172}
1173
1174target_ulong do_load_dbatl (CPUPPCState *env, int nr)
1175{
1176 return env->DBAT[1][nr];
1177}
1178
1179void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
1180{
1181 target_ulong mask;
1182
1183 dump_store_bat(env, 'D', 0, nr, value);
1184 if (env->DBAT[0][nr] != value) {
1185 /* When storing valid upper BAT, mask BEPI and BRPN
1186 * and invalidate all TLBs covered by this BAT
1187 */
1188 mask = (value << 15) & 0x0FFE0000UL;
1189#if !defined(FLUSH_ALL_TLBS)
1190 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1191#endif
1192 mask = (value << 15) & 0x0FFE0000UL;
1193 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1194 (value & ~0x0001FFFFUL & ~mask);
1195 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1196 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1197#if !defined(FLUSH_ALL_TLBS)
1198 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1199#else
1200 tlb_flush(env, 1);
1201#endif
1202 }
1203}
1204
1205void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
1206{
1207 dump_store_bat(env, 'D', 1, nr, value);
1208 env->DBAT[1][nr] = value;
1209}
1210
0a032cbe
JM
1211
1212/*****************************************************************************/
1213/* TLB management */
1214void ppc_tlb_invalidate_all (CPUPPCState *env)
1215{
1216 if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
1217 ppc6xx_tlb_invalidate_all(env);
1218 } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
1219 ppc4xx_tlb_invalidate_all(env);
1220 } else {
1221 tlb_flush(env, 1);
1222 }
1223}
1224
3fc6c082
FB
1225/*****************************************************************************/
1226/* Special registers manipulation */
d9bce9d9
JM
1227#if defined(TARGET_PPC64)
1228target_ulong ppc_load_asr (CPUPPCState *env)
1229{
1230 return env->asr;
1231}
1232
1233void ppc_store_asr (CPUPPCState *env, target_ulong value)
1234{
1235 if (env->asr != value) {
1236 env->asr = value;
1237 tlb_flush(env, 1);
1238 }
1239}
1240#endif
1241
3fc6c082
FB
1242target_ulong do_load_sdr1 (CPUPPCState *env)
1243{
1244 return env->sdr1;
1245}
1246
1247void do_store_sdr1 (CPUPPCState *env, target_ulong value)
1248{
1249#if defined (DEBUG_MMU)
1250 if (loglevel != 0) {
1b9eb036 1251 fprintf(logfile, "%s: 0x" ADDRX "\n", __func__, value);
3fc6c082
FB
1252 }
1253#endif
1254 if (env->sdr1 != value) {
1255 env->sdr1 = value;
76a66253 1256 tlb_flush(env, 1);
3fc6c082
FB
1257 }
1258}
1259
1260target_ulong do_load_sr (CPUPPCState *env, int srnum)
1261{
1262 return env->sr[srnum];
1263}
1264
1265void do_store_sr (CPUPPCState *env, int srnum, target_ulong value)
1266{
1267#if defined (DEBUG_MMU)
1268 if (loglevel != 0) {
1b9eb036
JM
1269 fprintf(logfile, "%s: reg=%d 0x" ADDRX " " ADDRX "\n",
1270 __func__, srnum, value, env->sr[srnum]);
3fc6c082
FB
1271 }
1272#endif
1273 if (env->sr[srnum] != value) {
1274 env->sr[srnum] = value;
1275#if !defined(FLUSH_ALL_TLBS) && 0
1276 {
1277 target_ulong page, end;
1278 /* Invalidate 256 MB of virtual memory */
1279 page = (16 << 20) * srnum;
1280 end = page + (16 << 20);
1281 for (; page != end; page += TARGET_PAGE_SIZE)
1282 tlb_flush_page(env, page);
1283 }
1284#else
76a66253 1285 tlb_flush(env, 1);
3fc6c082
FB
1286#endif
1287 }
1288}
76a66253 1289#endif /* !defined (CONFIG_USER_ONLY) */
3fc6c082 1290
76a66253 1291uint32_t ppc_load_xer (CPUPPCState *env)
79aceca5
FB
1292{
1293 return (xer_so << XER_SO) |
1294 (xer_ov << XER_OV) |
1295 (xer_ca << XER_CA) |
3fc6c082
FB
1296 (xer_bc << XER_BC) |
1297 (xer_cmp << XER_CMP);
79aceca5
FB
1298}
1299
76a66253 1300void ppc_store_xer (CPUPPCState *env, uint32_t value)
79aceca5
FB
1301{
1302 xer_so = (value >> XER_SO) & 0x01;
1303 xer_ov = (value >> XER_OV) & 0x01;
1304 xer_ca = (value >> XER_CA) & 0x01;
3fc6c082 1305 xer_cmp = (value >> XER_CMP) & 0xFF;
d9bce9d9 1306 xer_bc = (value >> XER_BC) & 0x7F;
79aceca5
FB
1307}
1308
76a66253
JM
1309/* Swap temporary saved registers with GPRs */
1310static inline void swap_gpr_tgpr (CPUPPCState *env)
79aceca5 1311{
76a66253
JM
1312 ppc_gpr_t tmp;
1313
1314 tmp = env->gpr[0];
1315 env->gpr[0] = env->tgpr[0];
1316 env->tgpr[0] = tmp;
1317 tmp = env->gpr[1];
1318 env->gpr[1] = env->tgpr[1];
1319 env->tgpr[1] = tmp;
1320 tmp = env->gpr[2];
1321 env->gpr[2] = env->tgpr[2];
1322 env->tgpr[2] = tmp;
1323 tmp = env->gpr[3];
1324 env->gpr[3] = env->tgpr[3];
1325 env->tgpr[3] = tmp;
79aceca5
FB
1326}
1327
76a66253
JM
1328/* GDBstub can read and write MSR... */
1329target_ulong do_load_msr (CPUPPCState *env)
79aceca5 1330{
76a66253
JM
1331 return
1332#if defined (TARGET_PPC64)
d9bce9d9
JM
1333 ((target_ulong)msr_sf << MSR_SF) |
1334 ((target_ulong)msr_isf << MSR_ISF) |
1335 ((target_ulong)msr_hv << MSR_HV) |
76a66253 1336#endif
d9bce9d9
JM
1337 ((target_ulong)msr_ucle << MSR_UCLE) |
1338 ((target_ulong)msr_vr << MSR_VR) | /* VR / SPE */
1339 ((target_ulong)msr_ap << MSR_AP) |
1340 ((target_ulong)msr_sa << MSR_SA) |
1341 ((target_ulong)msr_key << MSR_KEY) |
1342 ((target_ulong)msr_pow << MSR_POW) | /* POW / WE */
1343 ((target_ulong)msr_tlb << MSR_TLB) | /* TLB / TGPE / CE */
1344 ((target_ulong)msr_ile << MSR_ILE) |
1345 ((target_ulong)msr_ee << MSR_EE) |
1346 ((target_ulong)msr_pr << MSR_PR) |
1347 ((target_ulong)msr_fp << MSR_FP) |
1348 ((target_ulong)msr_me << MSR_ME) |
1349 ((target_ulong)msr_fe0 << MSR_FE0) |
1350 ((target_ulong)msr_se << MSR_SE) | /* SE / DWE / UBLE */
1351 ((target_ulong)msr_be << MSR_BE) | /* BE / DE */
1352 ((target_ulong)msr_fe1 << MSR_FE1) |
1353 ((target_ulong)msr_al << MSR_AL) |
1354 ((target_ulong)msr_ip << MSR_IP) |
1355 ((target_ulong)msr_ir << MSR_IR) | /* IR / IS */
1356 ((target_ulong)msr_dr << MSR_DR) | /* DR / DS */
1357 ((target_ulong)msr_pe << MSR_PE) | /* PE / EP */
1358 ((target_ulong)msr_px << MSR_PX) | /* PX / PMM */
1359 ((target_ulong)msr_ri << MSR_RI) |
1360 ((target_ulong)msr_le << MSR_LE);
3fc6c082
FB
1361}
1362
1363void do_store_msr (CPUPPCState *env, target_ulong value)
313adae9 1364{
50443c98
FB
1365 int enter_pm;
1366
3fc6c082
FB
1367 value &= env->msr_mask;
1368 if (((value >> MSR_IR) & 1) != msr_ir ||
1369 ((value >> MSR_DR) & 1) != msr_dr) {
76a66253 1370 /* Flush all tlb when changing translation mode */
d094807b 1371 tlb_flush(env, 1);
3fc6c082 1372 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
a541f297 1373 }
3fc6c082
FB
1374#if 0
1375 if (loglevel != 0) {
1376 fprintf(logfile, "%s: T0 %08lx\n", __func__, value);
1377 }
1378#endif
76a66253
JM
1379 switch (PPC_EXCP(env)) {
1380 case PPC_FLAGS_EXCP_602:
1381 case PPC_FLAGS_EXCP_603:
1382 if (((value >> MSR_TGPR) & 1) != msr_tgpr) {
1383 /* Swap temporary saved registers with GPRs */
1384 swap_gpr_tgpr(env);
1385 }
1386 break;
1387 default:
1388 break;
1389 }
1390#if defined (TARGET_PPC64)
1391 msr_sf = (value >> MSR_SF) & 1;
1392 msr_isf = (value >> MSR_ISF) & 1;
1393 msr_hv = (value >> MSR_HV) & 1;
1394#endif
1395 msr_ucle = (value >> MSR_UCLE) & 1;
1396 msr_vr = (value >> MSR_VR) & 1; /* VR / SPE */
1397 msr_ap = (value >> MSR_AP) & 1;
1398 msr_sa = (value >> MSR_SA) & 1;
1399 msr_key = (value >> MSR_KEY) & 1;
1400 msr_pow = (value >> MSR_POW) & 1; /* POW / WE */
1401 msr_tlb = (value >> MSR_TLB) & 1; /* TLB / TGPR / CE */
1402 msr_ile = (value >> MSR_ILE) & 1;
1403 msr_ee = (value >> MSR_EE) & 1;
1404 msr_pr = (value >> MSR_PR) & 1;
1405 msr_fp = (value >> MSR_FP) & 1;
1406 msr_me = (value >> MSR_ME) & 1;
1407 msr_fe0 = (value >> MSR_FE0) & 1;
1408 msr_se = (value >> MSR_SE) & 1; /* SE / DWE / UBLE */
1409 msr_be = (value >> MSR_BE) & 1; /* BE / DE */
1410 msr_fe1 = (value >> MSR_FE1) & 1;
1411 msr_al = (value >> MSR_AL) & 1;
1412 msr_ip = (value >> MSR_IP) & 1;
1413 msr_ir = (value >> MSR_IR) & 1; /* IR / IS */
1414 msr_dr = (value >> MSR_DR) & 1; /* DR / DS */
1415 msr_pe = (value >> MSR_PE) & 1; /* PE / EP */
1416 msr_px = (value >> MSR_PX) & 1; /* PX / PMM */
1417 msr_ri = (value >> MSR_RI) & 1;
1418 msr_le = (value >> MSR_LE) & 1;
3fc6c082 1419 do_compute_hflags(env);
50443c98
FB
1420
1421 enter_pm = 0;
1422 switch (PPC_EXCP(env)) {
d9bce9d9
JM
1423 case PPC_FLAGS_EXCP_603:
1424 /* Don't handle SLEEP mode: we should disable all clocks...
1425 * No dynamic power-management.
1426 */
1427 if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00C00000) != 0)
1428 enter_pm = 1;
1429 break;
1430 case PPC_FLAGS_EXCP_604:
1431 if (msr_pow == 1)
1432 enter_pm = 1;
1433 break;
50443c98 1434 case PPC_FLAGS_EXCP_7x0:
76a66253 1435 if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0)
50443c98
FB
1436 enter_pm = 1;
1437 break;
1438 default:
1439 break;
1440 }
1441 if (enter_pm) {
e80e1cc4 1442 /* power save: exit cpu loop */
50443c98 1443 env->halted = 1;
e80e1cc4
FB
1444 env->exception_index = EXCP_HLT;
1445 cpu_loop_exit();
1446 }
3fc6c082
FB
1447}
1448
d9bce9d9 1449#if defined(TARGET_PPC64)
426613db 1450void ppc_store_msr_32 (CPUPPCState *env, uint32_t value)
d9bce9d9 1451{
426613db
JM
1452 do_store_msr(env,
1453 (do_load_msr(env) & ~0xFFFFFFFFULL) | (value & 0xFFFFFFFF));
d9bce9d9
JM
1454}
1455#endif
1456
76a66253 1457void do_compute_hflags (CPUPPCState *env)
3fc6c082 1458{
76a66253 1459 /* Compute current hflags */
c62db105
JM
1460 env->hflags = (msr_cm << MSR_CM) | (msr_vr << MSR_VR) |
1461 (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_pr << MSR_PR) |
1462 (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) |
1463 (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | (msr_le << MSR_LE);
76a66253 1464#if defined (TARGET_PPC64)
c62db105 1465 /* No care here: PowerPC 64 MSR_SF means the same as MSR_CM for BookE */
d9bce9d9 1466 env->hflags |= (msr_sf << (MSR_SF - 32)) | (msr_hv << (MSR_HV - 32));
4b3686fa 1467#endif
3fc6c082
FB
1468}
1469
1470/*****************************************************************************/
1471/* Exception processing */
18fba28c 1472#if defined (CONFIG_USER_ONLY)
9a64fbe4 1473void do_interrupt (CPUState *env)
79aceca5 1474{
18fba28c
FB
1475 env->exception_index = -1;
1476}
47103572 1477
e9df014c 1478void ppc_hw_interrupt (CPUState *env)
47103572
JM
1479{
1480 env->exception_index = -1;
47103572 1481}
76a66253 1482#else /* defined (CONFIG_USER_ONLY) */
d094807b
FB
1483static void dump_syscall(CPUState *env)
1484{
d9bce9d9 1485 fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX
1b9eb036 1486 " r5=0x" REGX " r6=0x" REGX " nip=0x" ADDRX "\n",
d094807b
FB
1487 env->gpr[0], env->gpr[3], env->gpr[4],
1488 env->gpr[5], env->gpr[6], env->nip);
1489}
1490
18fba28c
FB
1491void do_interrupt (CPUState *env)
1492{
c62db105
JM
1493 target_ulong msr, *srr_0, *srr_1, *asrr_0, *asrr_1;
1494 int excp, idx;
79aceca5 1495
18fba28c 1496 excp = env->exception_index;
3fc6c082 1497 msr = do_load_msr(env);
2be0071f
FB
1498 /* The default is to use SRR0 & SRR1 to save the exception context */
1499 srr_0 = &env->spr[SPR_SRR0];
1500 srr_1 = &env->spr[SPR_SRR1];
c62db105
JM
1501 asrr_0 = NULL;
1502 asrr_1 = NULL;
9a64fbe4 1503#if defined (DEBUG_EXCEPTIONS)
2be0071f
FB
1504 if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) {
1505 if (loglevel != 0) {
1b9eb036
JM
1506 fprintf(logfile,
1507 "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n",
1508 env->nip, excp, env->error_code);
76a66253 1509 cpu_dump_state(env, logfile, fprintf, 0);
b769d8fe 1510 }
79aceca5 1511 }
9a64fbe4 1512#endif
b769d8fe 1513 if (loglevel & CPU_LOG_INT) {
1b9eb036
JM
1514 fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n",
1515 env->nip, excp, env->error_code);
b769d8fe 1516 }
2be0071f 1517 msr_pow = 0;
c62db105 1518 idx = -1;
9a64fbe4
FB
1519 /* Generate informations in save/restore registers */
1520 switch (excp) {
76a66253 1521 /* Generic PowerPC exceptions */
2be0071f 1522 case EXCP_RESET: /* 0x0100 */
c62db105
JM
1523 switch (PPC_EXCP(env)) {
1524 case PPC_FLAGS_EXCP_40x:
1525 srr_0 = &env->spr[SPR_40x_SRR2];
1526 srr_1 = &env->spr[SPR_40x_SRR3];
1527 break;
1528 case PPC_FLAGS_EXCP_BOOKE:
1529 idx = 0;
1530 srr_0 = &env->spr[SPR_BOOKE_CSRR0];
1531 srr_1 = &env->spr[SPR_BOOKE_CSRR1];
1532 break;
1533 default:
2be0071f
FB
1534 if (msr_ip)
1535 excp += 0xFFC00;
1536 excp |= 0xFFC00000;
c62db105 1537 break;
2be0071f 1538 }
9a64fbe4 1539 goto store_next;
2be0071f 1540 case EXCP_MACHINE_CHECK: /* 0x0200 */
c62db105
JM
1541 switch (PPC_EXCP(env)) {
1542 case PPC_FLAGS_EXCP_40x:
2be0071f
FB
1543 srr_0 = &env->spr[SPR_40x_SRR2];
1544 srr_1 = &env->spr[SPR_40x_SRR3];
c62db105
JM
1545 break;
1546 case PPC_FLAGS_EXCP_BOOKE:
1547 idx = 1;
1548 srr_0 = &env->spr[SPR_BOOKE_MCSRR0];
1549 srr_1 = &env->spr[SPR_BOOKE_MCSRR1];
1550 asrr_0 = &env->spr[SPR_BOOKE_CSRR0];
1551 asrr_1 = &env->spr[SPR_BOOKE_CSRR1];
1552 msr_ce = 0;
1553 break;
1554 default:
1555 break;
2be0071f 1556 }
9a64fbe4
FB
1557 msr_me = 0;
1558 break;
2be0071f 1559 case EXCP_DSI: /* 0x0300 */
9a64fbe4
FB
1560 /* Store exception cause */
1561 /* data location address has been stored
1562 * when the fault has been detected
2be0071f 1563 */
c62db105 1564 idx = 2;
76a66253 1565 msr &= ~0xFFFF0000;
a541f297 1566#if defined (DEBUG_EXCEPTIONS)
76a66253 1567 if (loglevel) {
1b9eb036
JM
1568 fprintf(logfile, "DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX
1569 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
76a66253 1570 }
a541f297
FB
1571#endif
1572 goto store_next;
2be0071f 1573 case EXCP_ISI: /* 0x0400 */
9a64fbe4 1574 /* Store exception cause */
c62db105 1575 idx = 3;
76a66253 1576 msr &= ~0xFFFF0000;
2be0071f 1577 msr |= env->error_code;
a541f297 1578#if defined (DEBUG_EXCEPTIONS)
76a66253 1579 if (loglevel != 0) {
1b9eb036
JM
1580 fprintf(logfile, "ISI exception: msr=0x" ADDRX ", nip=0x" ADDRX
1581 "\n", msr, env->nip);
76a66253 1582 }
a541f297 1583#endif
9a64fbe4 1584 goto store_next;
2be0071f 1585 case EXCP_EXTERNAL: /* 0x0500 */
c62db105 1586 idx = 4;
9a64fbe4 1587 goto store_next;
2be0071f 1588 case EXCP_ALIGN: /* 0x0600 */
76a66253 1589 if (likely(PPC_EXCP(env) != PPC_FLAGS_EXCP_601)) {
2be0071f 1590 /* Store exception cause */
c62db105 1591 idx = 5;
2be0071f
FB
1592 /* Get rS/rD and rA from faulting opcode */
1593 env->spr[SPR_DSISR] |=
1594 (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
1595 /* data location address has been stored
1596 * when the fault has been detected
1597 */
1598 } else {
1599 /* IO error exception on PowerPC 601 */
1600 /* XXX: TODO */
1601 cpu_abort(env,
1602 "601 IO error exception is not implemented yet !\n");
1603 }
9a64fbe4 1604 goto store_current;
2be0071f 1605 case EXCP_PROGRAM: /* 0x0700 */
c62db105 1606 idx = 6;
9a64fbe4
FB
1607 msr &= ~0xFFFF0000;
1608 switch (env->error_code & ~0xF) {
1609 case EXCP_FP:
1610 if (msr_fe0 == 0 && msr_fe1 == 0) {
1611#if defined (DEBUG_EXCEPTIONS)
a496775f
JM
1612 if (loglevel) {
1613 fprintf(logfile, "Ignore floating point exception\n");
1614 }
9a64fbe4
FB
1615#endif
1616 return;
76a66253 1617 }
9a64fbe4
FB
1618 msr |= 0x00100000;
1619 /* Set FX */
1620 env->fpscr[7] |= 0x8;
1621 /* Finally, update FEX */
1622 if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
1623 ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
1624 env->fpscr[7] |= 0x4;
76a66253 1625 break;
9a64fbe4 1626 case EXCP_INVAL:
a496775f
JM
1627#if defined (DEBUG_EXCEPTIONS)
1628 if (loglevel) {
1629 fprintf(logfile, "Invalid instruction at 0x" ADDRX "\n",
1630 env->nip);
1631 }
1632#endif
9a64fbe4 1633 msr |= 0x00080000;
76a66253 1634 break;
9a64fbe4
FB
1635 case EXCP_PRIV:
1636 msr |= 0x00040000;
76a66253 1637 break;
9a64fbe4 1638 case EXCP_TRAP:
c62db105 1639 idx = 15;
9a64fbe4
FB
1640 msr |= 0x00020000;
1641 break;
1642 default:
1643 /* Should never occur */
76a66253
JM
1644 break;
1645 }
9a64fbe4
FB
1646 msr |= 0x00010000;
1647 goto store_current;
2be0071f 1648 case EXCP_NO_FP: /* 0x0800 */
c62db105 1649 idx = 7;
4ecc3190 1650 msr &= ~0xFFFF0000;
9a64fbe4
FB
1651 goto store_current;
1652 case EXCP_DECR:
9a64fbe4 1653 goto store_next;
2be0071f 1654 case EXCP_SYSCALL: /* 0x0C00 */
c62db105 1655 idx = 8;
d094807b
FB
1656 /* NOTE: this is a temporary hack to support graphics OSI
1657 calls from the MOL driver */
1658 if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
1659 env->osi_call) {
1660 if (env->osi_call(env) != 0)
1661 return;
1662 }
b769d8fe 1663 if (loglevel & CPU_LOG_INT) {
d094807b 1664 dump_syscall(env);
b769d8fe 1665 }
9a64fbe4 1666 goto store_next;
2be0071f 1667 case EXCP_TRACE: /* 0x0D00 */
2be0071f
FB
1668 goto store_next;
1669 case EXCP_PERF: /* 0x0F00 */
1670 /* XXX: TODO */
1671 cpu_abort(env,
1672 "Performance counter exception is not implemented yet !\n");
1673 goto store_next;
1674 /* 32 bits PowerPC specific exceptions */
1675 case EXCP_FP_ASSIST: /* 0x0E00 */
1676 /* XXX: TODO */
1677 cpu_abort(env, "Floating point assist exception "
1678 "is not implemented yet !\n");
1679 goto store_next;
76a66253 1680 /* 64 bits PowerPC exceptions */
2be0071f
FB
1681 case EXCP_DSEG: /* 0x0380 */
1682 /* XXX: TODO */
1683 cpu_abort(env, "Data segment exception is not implemented yet !\n");
9a64fbe4 1684 goto store_next;
2be0071f
FB
1685 case EXCP_ISEG: /* 0x0480 */
1686 /* XXX: TODO */
1687 cpu_abort(env,
1688 "Instruction segment exception is not implemented yet !\n");
9a64fbe4 1689 goto store_next;
2be0071f 1690 case EXCP_HDECR: /* 0x0980 */
76a66253
JM
1691 /* XXX: TODO */
1692 cpu_abort(env, "Hypervisor decrementer exception is not implemented "
1693 "yet !\n");
2be0071f
FB
1694 goto store_next;
1695 /* Implementation specific exceptions */
1696 case 0x0A00:
76a66253
JM
1697 if (likely(env->spr[SPR_PVR] == CPU_PPC_G2 ||
1698 env->spr[SPR_PVR] == CPU_PPC_G2LE)) {
2be0071f
FB
1699 /* Critical interrupt on G2 */
1700 /* XXX: TODO */
1701 cpu_abort(env, "G2 critical interrupt is not implemented yet !\n");
1702 goto store_next;
1703 } else {
1704 cpu_abort(env, "Invalid exception 0x0A00 !\n");
1705 }
9a64fbe4 1706 return;
2be0071f 1707 case 0x0F20:
c62db105 1708 idx = 9;
2be0071f
FB
1709 switch (PPC_EXCP(env)) {
1710 case PPC_FLAGS_EXCP_40x:
1711 /* APU unavailable on 405 */
1712 /* XXX: TODO */
1713 cpu_abort(env,
1714 "APU unavailable exception is not implemented yet !\n");
1715 goto store_next;
1716 case PPC_FLAGS_EXCP_74xx:
1717 /* Altivec unavailable */
1718 /* XXX: TODO */
1719 cpu_abort(env, "Altivec unavailable exception "
1720 "is not implemented yet !\n");
1721 goto store_next;
1722 default:
1723 cpu_abort(env, "Invalid exception 0x0F20 !\n");
1724 break;
1725 }
1726 return;
1727 case 0x1000:
c62db105 1728 idx = 10;
2be0071f
FB
1729 switch (PPC_EXCP(env)) {
1730 case PPC_FLAGS_EXCP_40x:
1731 /* PIT on 4xx */
c62db105 1732 msr &= ~0xFFFF0000;
a496775f 1733#if defined (DEBUG_EXCEPTIONS)
c62db105
JM
1734 if (loglevel != 0)
1735 fprintf(logfile, "PIT exception\n");
a496775f 1736#endif
2be0071f
FB
1737 goto store_next;
1738 case PPC_FLAGS_EXCP_602:
1739 case PPC_FLAGS_EXCP_603:
1740 /* ITLBMISS on 602/603 */
2be0071f 1741 goto store_gprs;
76a66253
JM
1742 case PPC_FLAGS_EXCP_7x5:
1743 /* ITLBMISS on 745/755 */
1744 goto tlb_miss;
2be0071f
FB
1745 default:
1746 cpu_abort(env, "Invalid exception 0x1000 !\n");
1747 break;
1748 }
1749 return;
1750 case 0x1010:
c62db105 1751 idx = 11;
2be0071f
FB
1752 switch (PPC_EXCP(env)) {
1753 case PPC_FLAGS_EXCP_40x:
1754 /* FIT on 4xx */
c62db105 1755 msr &= ~0xFFFF0000;
a496775f 1756#if defined (DEBUG_EXCEPTIONS)
c62db105
JM
1757 if (loglevel != 0)
1758 fprintf(logfile, "FIT exception\n");
a496775f 1759#endif
2be0071f
FB
1760 goto store_next;
1761 default:
1762 cpu_abort(env, "Invalid exception 0x1010 !\n");
1763 break;
1764 }
1765 return;
1766 case 0x1020:
c62db105 1767 idx = 12;
2be0071f
FB
1768 switch (PPC_EXCP(env)) {
1769 case PPC_FLAGS_EXCP_40x:
1770 /* Watchdog on 4xx */
c62db105 1771 msr &= ~0xFFFF0000;
a496775f 1772#if defined (DEBUG_EXCEPTIONS)
c62db105
JM
1773 if (loglevel != 0)
1774 fprintf(logfile, "WDT exception\n");
a496775f 1775#endif
2be0071f 1776 goto store_next;
c62db105
JM
1777 case PPC_FLAGS_EXCP_BOOKE:
1778 srr_0 = &env->spr[SPR_BOOKE_CSRR0];
1779 srr_1 = &env->spr[SPR_BOOKE_CSRR1];
1780 break;
2be0071f
FB
1781 default:
1782 cpu_abort(env, "Invalid exception 0x1020 !\n");
1783 break;
1784 }
1785 return;
1786 case 0x1100:
c62db105 1787 idx = 13;
2be0071f
FB
1788 switch (PPC_EXCP(env)) {
1789 case PPC_FLAGS_EXCP_40x:
1790 /* DTLBMISS on 4xx */
a8dea12f 1791 msr &= ~0xFFFF0000;
2be0071f
FB
1792 goto store_next;
1793 case PPC_FLAGS_EXCP_602:
1794 case PPC_FLAGS_EXCP_603:
1795 /* DLTLBMISS on 602/603 */
2be0071f 1796 goto store_gprs;
76a66253
JM
1797 case PPC_FLAGS_EXCP_7x5:
1798 /* DLTLBMISS on 745/755 */
1799 goto tlb_miss;
2be0071f
FB
1800 default:
1801 cpu_abort(env, "Invalid exception 0x1100 !\n");
1802 break;
1803 }
1804 return;
1805 case 0x1200:
c62db105 1806 idx = 14;
2be0071f
FB
1807 switch (PPC_EXCP(env)) {
1808 case PPC_FLAGS_EXCP_40x:
1809 /* ITLBMISS on 4xx */
a8dea12f 1810 msr &= ~0xFFFF0000;
2be0071f
FB
1811 goto store_next;
1812 case PPC_FLAGS_EXCP_602:
1813 case PPC_FLAGS_EXCP_603:
1814 /* DSTLBMISS on 602/603 */
2be0071f 1815 store_gprs:
76a66253
JM
1816 /* Swap temporary saved registers with GPRs */
1817 swap_gpr_tgpr(env);
1818 msr_tgpr = 1;
2be0071f
FB
1819#if defined (DEBUG_SOFTWARE_TLB)
1820 if (loglevel != 0) {
76a66253
JM
1821 const unsigned char *es;
1822 target_ulong *miss, *cmp;
1823 int en;
1824 if (excp == 0x1000) {
1825 es = "I";
1826 en = 'I';
1827 miss = &env->spr[SPR_IMISS];
1828 cmp = &env->spr[SPR_ICMP];
1829 } else {
1830 if (excp == 0x1100)
1831 es = "DL";
1832 else
1833 es = "DS";
1834 en = 'D';
1835 miss = &env->spr[SPR_DMISS];
1836 cmp = &env->spr[SPR_DCMP];
1837 }
1b9eb036
JM
1838 fprintf(logfile, "6xx %sTLB miss: %cM " ADDRX " %cC " ADDRX
1839 " H1 " ADDRX " H2 " ADDRX " " ADDRX "\n",
1840 es, en, *miss, en, *cmp,
76a66253 1841 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
2be0071f
FB
1842 env->error_code);
1843 }
9a64fbe4 1844#endif
76a66253
JM
1845 goto tlb_miss;
1846 case PPC_FLAGS_EXCP_7x5:
1847 /* DSTLBMISS on 745/755 */
1848 tlb_miss:
1849 msr &= ~0xF83F0000;
2be0071f
FB
1850 msr |= env->crf[0] << 28;
1851 msr |= env->error_code; /* key, D/I, S/L bits */
1852 /* Set way using a LRU mechanism */
76a66253 1853 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
2be0071f
FB
1854 goto store_next;
1855 default:
1856 cpu_abort(env, "Invalid exception 0x1200 !\n");
1857 break;
1858 }
1859 return;
1860 case 0x1300:
1861 switch (PPC_EXCP(env)) {
1862 case PPC_FLAGS_EXCP_601:
1863 case PPC_FLAGS_EXCP_602:
1864 case PPC_FLAGS_EXCP_603:
1865 case PPC_FLAGS_EXCP_604:
1866 case PPC_FLAGS_EXCP_7x0:
1867 case PPC_FLAGS_EXCP_7x5:
1868 /* IABR on 6xx/7xx */
1869 /* XXX: TODO */
1870 cpu_abort(env, "IABR exception is not implemented yet !\n");
1871 goto store_next;
1872 default:
1873 cpu_abort(env, "Invalid exception 0x1300 !\n");
1874 break;
1875 }
1876 return;
1877 case 0x1400:
1878 switch (PPC_EXCP(env)) {
1879 case PPC_FLAGS_EXCP_601:
1880 case PPC_FLAGS_EXCP_602:
1881 case PPC_FLAGS_EXCP_603:
1882 case PPC_FLAGS_EXCP_604:
1883 case PPC_FLAGS_EXCP_7x0:
1884 case PPC_FLAGS_EXCP_7x5:
1885 /* SMI on 6xx/7xx */
1886 /* XXX: TODO */
1887 cpu_abort(env, "SMI exception is not implemented yet !\n");
1888 goto store_next;
1889 default:
1890 cpu_abort(env, "Invalid exception 0x1400 !\n");
1891 break;
1892 }
1893 return;
1894 case 0x1500:
1895 switch (PPC_EXCP(env)) {
1896 case PPC_FLAGS_EXCP_602:
1897 /* Watchdog on 602 */
76a66253 1898 /* XXX: TODO */
2be0071f
FB
1899 cpu_abort(env,
1900 "602 watchdog exception is not implemented yet !\n");
1901 goto store_next;
1902 case PPC_FLAGS_EXCP_970:
1903 /* Soft patch exception on 970 */
1904 /* XXX: TODO */
1905 cpu_abort(env,
1906 "970 soft-patch exception is not implemented yet !\n");
1907 goto store_next;
1908 case PPC_FLAGS_EXCP_74xx:
1909 /* VPU assist on 74xx */
1910 /* XXX: TODO */
1911 cpu_abort(env, "VPU assist exception is not implemented yet !\n");
1912 goto store_next;
1913 default:
1914 cpu_abort(env, "Invalid exception 0x1500 !\n");
1915 break;
1916 }
1917 return;
1918 case 0x1600:
1919 switch (PPC_EXCP(env)) {
1920 case PPC_FLAGS_EXCP_602:
1921 /* Emulation trap on 602 */
1922 /* XXX: TODO */
1923 cpu_abort(env, "602 emulation trap exception "
1924 "is not implemented yet !\n");
1925 goto store_next;
1926 case PPC_FLAGS_EXCP_970:
1927 /* Maintenance exception on 970 */
1928 /* XXX: TODO */
1929 cpu_abort(env,
1930 "970 maintenance exception is not implemented yet !\n");
1931 goto store_next;
1932 default:
1933 cpu_abort(env, "Invalid exception 0x1600 !\n");
1934 break;
1935 }
1936 return;
1937 case 0x1700:
1938 switch (PPC_EXCP(env)) {
1939 case PPC_FLAGS_EXCP_7x0:
1940 case PPC_FLAGS_EXCP_7x5:
1941 /* Thermal management interrupt on G3 */
1942 /* XXX: TODO */
1943 cpu_abort(env, "G3 thermal management exception "
1944 "is not implemented yet !\n");
1945 goto store_next;
1946 case PPC_FLAGS_EXCP_970:
1947 /* VPU assist on 970 */
1948 /* XXX: TODO */
1949 cpu_abort(env,
1950 "970 VPU assist exception is not implemented yet !\n");
1951 goto store_next;
1952 default:
1953 cpu_abort(env, "Invalid exception 0x1700 !\n");
1954 break;
1955 }
1956 return;
1957 case 0x1800:
1958 switch (PPC_EXCP(env)) {
1959 case PPC_FLAGS_EXCP_970:
1960 /* Thermal exception on 970 */
1961 /* XXX: TODO */
1962 cpu_abort(env, "970 thermal management exception "
1963 "is not implemented yet !\n");
1964 goto store_next;
1965 default:
1966 cpu_abort(env, "Invalid exception 0x1800 !\n");
1967 break;
1968 }
1969 return;
1970 case 0x2000:
1971 switch (PPC_EXCP(env)) {
1972 case PPC_FLAGS_EXCP_40x:
1973 /* DEBUG on 4xx */
1974 /* XXX: TODO */
1975 cpu_abort(env, "40x debug exception is not implemented yet !\n");
1976 goto store_next;
1977 case PPC_FLAGS_EXCP_601:
1978 /* Run mode exception on 601 */
1979 /* XXX: TODO */
1980 cpu_abort(env,
1981 "601 run mode exception is not implemented yet !\n");
1982 goto store_next;
c62db105
JM
1983 case PPC_FLAGS_EXCP_BOOKE:
1984 srr_0 = &env->spr[SPR_BOOKE_CSRR0];
1985 srr_1 = &env->spr[SPR_BOOKE_CSRR1];
1986 break;
2be0071f
FB
1987 default:
1988 cpu_abort(env, "Invalid exception 0x1800 !\n");
1989 break;
1990 }
1991 return;
1992 /* Other exceptions */
1993 /* Qemu internal exceptions:
1994 * we should never come here with those values: abort execution
1995 */
1996 default:
1997 cpu_abort(env, "Invalid exception: code %d (%04x)\n", excp, excp);
9a64fbe4
FB
1998 return;
1999 store_current:
2be0071f 2000 /* save current instruction location */
c62db105 2001 *srr_0 = env->nip - 4;
9a64fbe4
FB
2002 break;
2003 store_next:
2be0071f 2004 /* save next instruction location */
c62db105 2005 *srr_0 = env->nip;
9a64fbe4
FB
2006 break;
2007 }
2be0071f
FB
2008 /* Save msr */
2009 *srr_1 = msr;
c62db105
JM
2010 if (asrr_0 != NULL)
2011 *asrr_0 = *srr_0;
2012 if (asrr_1 != NULL)
2013 *asrr_1 = *srr_1;
2be0071f
FB
2014 /* If we disactivated any translation, flush TLBs */
2015 if (msr_ir || msr_dr) {
2016 tlb_flush(env, 1);
2017 }
9a64fbe4 2018 /* reload MSR with correct bits */
9a64fbe4
FB
2019 msr_ee = 0;
2020 msr_pr = 0;
2021 msr_fp = 0;
2022 msr_fe0 = 0;
2023 msr_se = 0;
2024 msr_be = 0;
2025 msr_fe1 = 0;
2026 msr_ir = 0;
2027 msr_dr = 0;
2028 msr_ri = 0;
2029 msr_le = msr_ile;
c62db105
JM
2030 if (PPC_EXCP(env) == PPC_FLAGS_EXCP_BOOKE) {
2031 msr_cm = msr_icm;
2032 if (idx == -1 || (idx >= 16 && idx < 32)) {
2033 cpu_abort(env, "Invalid exception index for excp %d %08x idx %d\n",
2034 excp, excp, idx);
2035 }
2036#if defined(TARGET_PPC64)
2037 if (msr_cm)
2038 env->nip = (uint64_t)env->spr[SPR_BOOKE_IVPR];
2039 else
2040#endif
2041 env->nip = (uint32_t)env->spr[SPR_BOOKE_IVPR];
2042 if (idx < 16)
2043 env->nip |= env->spr[SPR_BOOKE_IVOR0 + idx];
2044 else if (idx < 38)
2045 env->nip |= env->spr[SPR_BOOKE_IVOR32 + idx - 32];
2046 } else {
2047 msr_sf = msr_isf;
2048 env->nip = excp;
2049 }
3fc6c082 2050 do_compute_hflags(env);
9a64fbe4 2051 /* Jump to handler */
9a64fbe4 2052 env->exception_index = EXCP_NONE;
fb0eaffc 2053}
47103572 2054
e9df014c 2055void ppc_hw_interrupt (CPUPPCState *env)
47103572
JM
2056{
2057 int raised = 0;
2058
a496775f
JM
2059#if 1
2060 if (loglevel & CPU_LOG_INT) {
2061 fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n",
2062 __func__, env, env->pending_interrupts,
2063 env->interrupt_request, msr_me, msr_ee);
2064 }
47103572
JM
2065#endif
2066 /* Raise it */
2067 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
2068 /* External reset / critical input */
e9df014c
JM
2069 /* XXX: critical input should be handled another way.
2070 * This code is not correct !
2071 */
47103572
JM
2072 env->exception_index = EXCP_RESET;
2073 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
2074 raised = 1;
2075 }
2076 if (raised == 0 && msr_me != 0) {
2077 /* Machine check exception */
2078 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
2079 env->exception_index = EXCP_MACHINE_CHECK;
2080 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
2081 raised = 1;
2082 }
2083 }
2084 if (raised == 0 && msr_ee != 0) {
2085#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
2086 /* Hypervisor decrementer exception */
2087 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
2088 env->exception_index = EXCP_HDECR;
2089 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
2090 raised = 1;
2091 } else
2092#endif
2093 /* Decrementer exception */
2094 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
2095 env->exception_index = EXCP_DECR;
2096 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
2097 raised = 1;
2098 /* Programmable interval timer on embedded PowerPC */
2099 } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
2100 env->exception_index = EXCP_40x_PIT;
2101 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
2102 raised = 1;
2103 /* Fixed interval timer on embedded PowerPC */
2104 } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
2105 env->exception_index = EXCP_40x_FIT;
2106 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
2107 raised = 1;
2108 /* Watchdog timer on embedded PowerPC */
2109 } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
2110 env->exception_index = EXCP_40x_WATCHDOG;
2111 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
2112 raised = 1;
2113 /* External interrupt */
2114 } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
2115 env->exception_index = EXCP_EXTERNAL;
e9df014c
JM
2116 /* Taking an external interrupt does not clear the external
2117 * interrupt status
2118 */
2119#if 0
47103572 2120 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
e9df014c 2121#endif
47103572 2122 raised = 1;
d0dfae6e
JM
2123#if 0 // TODO
2124 /* Thermal interrupt */
2125 } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
2126 env->exception_index = EXCP_970_THRM;
2127 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
2128 raised = 1;
2129#endif
47103572
JM
2130 }
2131#if 0 // TODO
2132 /* External debug exception */
2133 } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
2134 env->exception_index = EXCP_xxx;
2135 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
2136 raised = 1;
2137#endif
2138 }
2139 if (raised != 0) {
2140 env->error_code = 0;
2141 do_interrupt(env);
2142 }
47103572 2143}
18fba28c 2144#endif /* !CONFIG_USER_ONLY */
a496775f
JM
2145
2146void cpu_dump_EA (target_ulong EA)
2147{
2148 FILE *f;
2149
2150 if (logfile) {
2151 f = logfile;
2152 } else {
2153 f = stdout;
2154 return;
2155 }
2156 fprintf(f, "Memory access at address " TARGET_FMT_lx "\n", EA);
2157}
2158
0a032cbe
JM
2159void cpu_ppc_reset (void *opaque)
2160{
2161 CPUPPCState *env;
2162
2163 env = opaque;
2164#if defined (DO_SINGLE_STEP) && 0
2165 /* Single step trace mode */
2166 msr_se = 1;
2167 msr_be = 1;
2168#endif
2169 msr_fp = 1; /* Allow floating point exceptions */
2170 msr_me = 1; /* Allow machine check exceptions */
2171#if defined(TARGET_PPC64)
2172 msr_sf = 0; /* Boot in 32 bits mode */
2173 msr_cm = 0;
2174#endif
2175#if defined(CONFIG_USER_ONLY)
2176 msr_pr = 1;
2177 tlb_flush(env, 1);
2178#else
2179 env->nip = 0xFFFFFFFC;
2180 ppc_tlb_invalidate_all(env);
2181#endif
2182 do_compute_hflags(env);
2183 env->reserve = -1;
2184}
2185
2186CPUPPCState *cpu_ppc_init (void)
2187{
2188 CPUPPCState *env;
2189
2190 env = qemu_mallocz(sizeof(CPUPPCState));
2191 if (!env)
2192 return NULL;
2193 cpu_exec_init(env);
2194 cpu_ppc_reset(env);
2195
2196 return env;
2197}
2198
2199void cpu_ppc_close (CPUPPCState *env)
2200{
2201 /* Should also remove all opcode tables... */
2202 free(env);
2203}