helper.c 91.9 KB
Newer Older
B
bellard 已提交
1
/*
2
 *  PowerPC emulation helpers for qemu.
3
 *
4
 *  Copyright (c) 2003-2007 Jocelyn Mayer
B
bellard 已提交
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
B
bellard 已提交
18
 */
19 20 21 22 23 24 25 26 27
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <signal.h>

#include "cpu.h"
#include "exec-all.h"
28
#include "helper_regs.h"
29
#include "qemu-common.h"
A
aurel32 已提交
30
#include "kvm.h"
31 32 33

//#define DEBUG_MMU
//#define DEBUG_BATS
34
//#define DEBUG_SLB
35
//#define DEBUG_SOFTWARE_TLB
36
//#define DUMP_PAGE_TABLES
37
//#define DEBUG_EXCEPTIONS
38
//#define FLUSH_ALL_TLBS
39

40
#ifdef DEBUG_MMU
41 42
#  define LOG_MMU(...) qemu_log(__VA_ARGS__)
#  define LOG_MMU_STATE(env) log_cpu_state((env), 0)
43 44 45 46 47 48 49
#else
#  define LOG_MMU(...) do { } while (0)
#  define LOG_MMU_STATE(...) do { } while (0)
#endif


#ifdef DEBUG_SOFTWARE_TLB
50
#  define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
51 52 53 54 55
#else
#  define LOG_SWTLB(...) do { } while (0)
#endif

#ifdef DEBUG_BATS
56
#  define LOG_BATS(...) qemu_log(__VA_ARGS__)
57 58 59 60 61
#else
#  define LOG_BATS(...) do { } while (0)
#endif

#ifdef DEBUG_SLB
62
#  define LOG_SLB(...) qemu_log(__VA_ARGS__)
63 64 65 66 67
#else
#  define LOG_SLB(...) do { } while (0)
#endif

#ifdef DEBUG_EXCEPTIONS
68
#  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
69 70 71 72 73
#else
#  define LOG_EXCP(...) do { } while (0)
#endif


74
/*****************************************************************************/
75
/* PowerPC MMU emulation */
76

77
#if defined(CONFIG_USER_ONLY)
78
int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
79
                              int mmu_idx, int is_softmmu)
80 81
{
    int exception, error_code;
82

83
    if (rw == 2) {
84
        exception = POWERPC_EXCP_ISI;
85
        error_code = 0x40000000;
86
    } else {
87
        exception = POWERPC_EXCP_DSI;
88
        error_code = 0x40000000;
89 90 91 92 93 94 95
        if (rw)
            error_code |= 0x02000000;
        env->spr[SPR_DAR] = address;
        env->spr[SPR_DSISR] = error_code;
    }
    env->exception_index = exception;
    env->error_code = error_code;
96

97 98
    return 1;
}
99

100
#else
101
/* Common routines used by software and hardware TLBs emulation */
B
Blue Swirl 已提交
102
static inline int pte_is_valid(target_ulong pte0)
103 104 105 106
{
    return pte0 & 0x80000000 ? 1 : 0;
}

B
Blue Swirl 已提交
107
static inline void pte_invalidate(target_ulong *pte0)
108 109 110 111
{
    *pte0 &= ~0x80000000;
}

112
#if defined(TARGET_PPC64)
B
Blue Swirl 已提交
113
static inline int pte64_is_valid(target_ulong pte0)
114 115 116 117
{
    return pte0 & 0x0000000000000001ULL ? 1 : 0;
}

B
Blue Swirl 已提交
118
static inline void pte64_invalidate(target_ulong *pte0)
119 120 121 122 123
{
    *pte0 &= ~0x0000000000000001ULL;
}
#endif

124 125
#define PTE_PTEM_MASK 0x7FFFFFBF
#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
126 127 128 129
#if defined(TARGET_PPC64)
#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
#endif
130

B
Blue Swirl 已提交
131
static inline int pp_check(int key, int pp, int nx)
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
{
    int access;

    /* Compute access rights */
    /* When pp is 3/7, the result is undefined. Set it to noaccess */
    access = 0;
    if (key == 0) {
        switch (pp) {
        case 0x0:
        case 0x1:
        case 0x2:
            access |= PAGE_WRITE;
            /* No break here */
        case 0x3:
        case 0x6:
            access |= PAGE_READ;
            break;
        }
    } else {
        switch (pp) {
        case 0x0:
        case 0x6:
            access = 0;
            break;
        case 0x1:
        case 0x3:
            access = PAGE_READ;
            break;
        case 0x2:
            access = PAGE_READ | PAGE_WRITE;
            break;
        }
    }
    if (nx == 0)
        access |= PAGE_EXEC;

    return access;
}

B
Blue Swirl 已提交
171
static inline int check_prot(int prot, int rw, int access_type)
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
{
    int ret;

    if (access_type == ACCESS_CODE) {
        if (prot & PAGE_EXEC)
            ret = 0;
        else
            ret = -2;
    } else if (rw) {
        if (prot & PAGE_WRITE)
            ret = 0;
        else
            ret = -2;
    } else {
        if (prot & PAGE_READ)
            ret = 0;
        else
            ret = -2;
    }

    return ret;
}

A
Anthony Liguori 已提交
195
static inline int _pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
B
Blue Swirl 已提交
196
                             target_ulong pte1, int h, int rw, int type)
197
{
198
    target_ulong ptem, mmask;
199
    int access, ret, pteh, ptev, pp;
200 201 202

    ret = -1;
    /* Check validity and table match */
203 204 205 206 207 208 209 210 211 212 213
#if defined(TARGET_PPC64)
    if (is_64b) {
        ptev = pte64_is_valid(pte0);
        pteh = (pte0 >> 1) & 1;
    } else
#endif
    {
        ptev = pte_is_valid(pte0);
        pteh = (pte0 >> 6) & 1;
    }
    if (ptev && h == pteh) {
214
        /* Check vsid & api */
215 216 217 218
#if defined(TARGET_PPC64)
        if (is_64b) {
            ptem = pte0 & PTE64_PTEM_MASK;
            mmask = PTE64_CHECK_MASK;
219
            pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
B
blueswir1 已提交
220
            ctx->nx  = (pte1 >> 2) & 1; /* No execute bit */
221
            ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit    */
222 223 224 225 226
        } else
#endif
        {
            ptem = pte0 & PTE_PTEM_MASK;
            mmask = PTE_CHECK_MASK;
227
            pp = pte1 & 0x00000003;
228 229
        }
        if (ptem == ctx->ptem) {
A
Anthony Liguori 已提交
230
            if (ctx->raddr != (target_phys_addr_t)-1ULL) {
231
                /* all matches should have equal RPN, WIMG & PP */
232
                if ((ctx->raddr & mmask) != (pte1 & mmask)) {
233
                    qemu_log("Bad RPN/WIMG/PP\n");
234 235 236 237
                    return -3;
                }
            }
            /* Compute access rights */
238
            access = pp_check(ctx->key, pp, ctx->nx);
239 240 241
            /* Keep the matching PTE informations */
            ctx->raddr = pte1;
            ctx->prot = access;
242 243
            ret = check_prot(ctx->prot, rw, type);
            if (ret == 0) {
244
                /* Access granted */
245
                LOG_MMU("PTE access granted !\n");
246 247
            } else {
                /* Access right violation */
248
                LOG_MMU("PTE access rejected\n");
249 250 251 252 253 254 255
            }
        }
    }

    return ret;
}

A
Anthony Liguori 已提交
256
static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
B
Blue Swirl 已提交
257
                              target_ulong pte1, int h, int rw, int type)
258
{
259
    return _pte_check(ctx, 0, pte0, pte1, h, rw, type);
260 261 262
}

#if defined(TARGET_PPC64)
A
Anthony Liguori 已提交
263
static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
B
Blue Swirl 已提交
264
                              target_ulong pte1, int h, int rw, int type)
265
{
266
    return _pte_check(ctx, 1, pte0, pte1, h, rw, type);
267 268 269
}
#endif

A
Anthony Liguori 已提交
270
static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
B
Blue Swirl 已提交
271
                                   int ret, int rw)
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
{
    int store = 0;

    /* Update page flags */
    if (!(*pte1p & 0x00000100)) {
        /* Update accessed flag */
        *pte1p |= 0x00000100;
        store = 1;
    }
    if (!(*pte1p & 0x00000080)) {
        if (rw == 1 && ret == 0) {
            /* Update changed flag */
            *pte1p |= 0x00000080;
            store = 1;
        } else {
            /* Force page fault for first write access */
            ctx->prot &= ~PAGE_WRITE;
        }
    }

    return store;
}

/* Software driven TLB helpers */
B
Blue Swirl 已提交
296 297
static inline int ppc6xx_tlb_getnum(CPUState *env, target_ulong eaddr, int way,
                                    int is_code)
298 299 300 301 302 303 304 305 306 307 308 309 310 311
{
    int nr;

    /* Select TLB num in a way from address */
    nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
    /* Select TLB way */
    nr += env->tlb_per_way * way;
    /* 6xx have separate TLBs for instructions and data */
    if (is_code && env->id_tlbs == 1)
        nr += env->nb_tlb;

    return nr;
}

B
Blue Swirl 已提交
312
static inline void ppc6xx_tlb_invalidate_all(CPUState *env)
313
{
A
Anthony Liguori 已提交
314
    ppc6xx_tlb_t *tlb;
315 316
    int nr, max;

317
    //LOG_SWTLB("Invalidate all TLBs\n");
318 319 320 321 322
    /* Invalidate all defined software TLB */
    max = env->nb_tlb;
    if (env->id_tlbs == 1)
        max *= 2;
    for (nr = 0; nr < max; nr++) {
323
        tlb = &env->tlb[nr].tlb6;
324 325 326 327 328
        pte_invalidate(&tlb->pte0);
    }
    tlb_flush(env, 1);
}

B
Blue Swirl 已提交
329 330 331
static inline void __ppc6xx_tlb_invalidate_virt(CPUState *env,
                                                target_ulong eaddr,
                                                int is_code, int match_epn)
332
{
J
j_mayer 已提交
333
#if !defined(FLUSH_ALL_TLBS)
A
Anthony Liguori 已提交
334
    ppc6xx_tlb_t *tlb;
335 336 337 338 339
    int way, nr;

    /* Invalidate ITLB + DTLB, all ways */
    for (way = 0; way < env->nb_ways; way++) {
        nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
340
        tlb = &env->tlb[nr].tlb6;
341
        if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
342 343
            LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
                      env->nb_tlb, eaddr);
344 345 346 347 348 349 350 351 352 353
            pte_invalidate(&tlb->pte0);
            tlb_flush_page(env, tlb->EPN);
        }
    }
#else
    /* XXX: PowerPC specification say this is valid as well */
    ppc6xx_tlb_invalidate_all(env);
#endif
}

B
Blue Swirl 已提交
354 355
static inline void ppc6xx_tlb_invalidate_virt(CPUState *env,
                                              target_ulong eaddr, int is_code)
356 357 358 359 360 361 362
{
    __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
}

void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
                       target_ulong pte0, target_ulong pte1)
{
A
Anthony Liguori 已提交
363
    ppc6xx_tlb_t *tlb;
364 365 366
    int nr;

    nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
367
    tlb = &env->tlb[nr].tlb6;
368 369
    LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
              " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
370 371 372 373 374 375 376 377 378
    /* Invalidate any pending reference in Qemu for this virtual address */
    __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
    tlb->pte0 = pte0;
    tlb->pte1 = pte1;
    tlb->EPN = EPN;
    /* Store last way for LRU mechanism */
    env->last_way = way;
}

A
Anthony Liguori 已提交
379
static inline int ppc6xx_tlb_check(CPUState *env, mmu_ctx_t *ctx,
B
Blue Swirl 已提交
380
                                   target_ulong eaddr, int rw, int access_type)
381
{
A
Anthony Liguori 已提交
382
    ppc6xx_tlb_t *tlb;
383 384
    int nr, best, way;
    int ret;
385

386 387 388 389 390
    best = -1;
    ret = -1; /* No TLB found */
    for (way = 0; way < env->nb_ways; way++) {
        nr = ppc6xx_tlb_getnum(env, eaddr, way,
                               access_type == ACCESS_CODE ? 1 : 0);
391
        tlb = &env->tlb[nr].tlb6;
392 393
        /* This test "emulates" the PTE index match for hardware TLBs */
        if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
394 395 396 397
            LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
                      "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
                      pte_is_valid(tlb->pte0) ? "valid" : "inval",
                      tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
398 399
            continue;
        }
400 401 402 403 404
        LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
                  TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
                  pte_is_valid(tlb->pte0) ? "valid" : "inval",
                  tlb->EPN, eaddr, tlb->pte1,
                  rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
405
        switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
        case -3:
            /* TLB inconsistency */
            return -1;
        case -2:
            /* Access violation */
            ret = -2;
            best = nr;
            break;
        case -1:
        default:
            /* No match */
            break;
        case 0:
            /* access granted */
            /* XXX: we should go on looping to check all TLBs consistency
             *      but we can speed-up the whole thing as the
             *      result would be undefined if TLBs are not consistent.
             */
            ret = 0;
            best = nr;
            goto done;
        }
    }
    if (best != -1) {
    done:
431 432
        LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
                  ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
433
        /* Update page flags */
434
        pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw);
435 436 437 438 439
    }

    return ret;
}

440
/* Perform BAT hit & translation */
B
Blue Swirl 已提交
441 442 443
static inline void bat_size_prot(CPUState *env, target_ulong *blp, int *validp,
                                 int *protp, target_ulong *BATu,
                                 target_ulong *BATl)
J
j_mayer 已提交
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
{
    target_ulong bl;
    int pp, valid, prot;

    bl = (*BATu & 0x00001FFC) << 15;
    valid = 0;
    prot = 0;
    if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
        ((msr_pr != 0) && (*BATu & 0x00000001))) {
        valid = 1;
        pp = *BATl & 0x00000003;
        if (pp != 0) {
            prot = PAGE_READ | PAGE_EXEC;
            if (pp == 0x2)
                prot |= PAGE_WRITE;
        }
    }
    *blp = bl;
    *validp = valid;
    *protp = prot;
}

B
Blue Swirl 已提交
466 467 468
static inline void bat_601_size_prot(CPUState *env, target_ulong *blp,
                                     int *validp, int *protp,
                                     target_ulong *BATu, target_ulong *BATl)
J
j_mayer 已提交
469 470 471 472 473
{
    target_ulong bl;
    int key, pp, valid, prot;

    bl = (*BATl & 0x0000003F) << 17;
474 475
    LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
             (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
J
j_mayer 已提交
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
    prot = 0;
    valid = (*BATl >> 6) & 1;
    if (valid) {
        pp = *BATu & 0x00000003;
        if (msr_pr == 0)
            key = (*BATu >> 3) & 1;
        else
            key = (*BATu >> 2) & 1;
        prot = pp_check(key, pp, 0);
    }
    *blp = bl;
    *validp = valid;
    *protp = prot;
}

A
Anthony Liguori 已提交
491
static inline int get_bat(CPUState *env, mmu_ctx_t *ctx, target_ulong virtual,
B
Blue Swirl 已提交
492
                          int rw, int type)
493
{
494
    target_ulong *BATlt, *BATut, *BATu, *BATl;
495
    target_ulong BEPIl, BEPIu, bl;
J
j_mayer 已提交
496
    int i, valid, prot;
497 498
    int ret = -1;

499 500
    LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
             type == ACCESS_CODE ? 'I' : 'D', virtual);
501 502 503 504 505 506 507 508 509 510
    switch (type) {
    case ACCESS_CODE:
        BATlt = env->IBAT[1];
        BATut = env->IBAT[0];
        break;
    default:
        BATlt = env->DBAT[1];
        BATut = env->DBAT[0];
        break;
    }
J
j_mayer 已提交
511
    for (i = 0; i < env->nb_BATs; i++) {
512 513 514 515
        BATu = &BATut[i];
        BATl = &BATlt[i];
        BEPIu = *BATu & 0xF0000000;
        BEPIl = *BATu & 0x0FFE0000;
J
j_mayer 已提交
516 517 518 519 520
        if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
            bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
        } else {
            bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
        }
521 522 523
        LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
                 " BATl " TARGET_FMT_lx "\n", __func__,
                 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
524 525 526
        if ((virtual & 0xF0000000) == BEPIu &&
            ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
            /* BAT matches */
J
j_mayer 已提交
527
            if (valid != 0) {
528
                /* Get physical address */
529
                ctx->raddr = (*BATl & 0xF0000000) |
530
                    ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
531
                    (virtual & 0x0001F000);
532
                /* Compute access rights */
J
j_mayer 已提交
533
                ctx->prot = prot;
534
                ret = check_prot(ctx->prot, rw, type);
535
                if (ret == 0)
536
                    LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
537 538
                             i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
                             ctx->prot & PAGE_WRITE ? 'W' : '-');
539 540 541 542 543
                break;
            }
        }
    }
    if (ret < 0) {
544
#if defined(DEBUG_BATS)
545
        if (qemu_log_enabled()) {
546
            LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
J
j_mayer 已提交
547 548 549 550 551 552
            for (i = 0; i < 4; i++) {
                BATu = &BATut[i];
                BATl = &BATlt[i];
                BEPIu = *BATu & 0xF0000000;
                BEPIl = *BATu & 0x0FFE0000;
                bl = (*BATu & 0x00001FFC) << 15;
553 554 555
                LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
                         " BATl " TARGET_FMT_lx " \n\t" TARGET_FMT_lx " "
                         TARGET_FMT_lx " " TARGET_FMT_lx "\n",
556 557
                         __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
                         *BATu, *BATl, BEPIu, BEPIl, bl);
J
j_mayer 已提交
558
            }
559 560 561 562 563 564 565 566
        }
#endif
    }
    /* No hit */
    return ret;
}

/* PTE table lookup */
A
Anthony Liguori 已提交
567
static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
B
Blue Swirl 已提交
568
                            int type, int target_page_bits)
569
{
570 571
    target_ulong base, pte0, pte1;
    int i, good = -1;
572
    int ret, r;
573

574 575
    ret = -1; /* No entry found */
    base = ctx->pg_addr[h];
576
    for (i = 0; i < 8; i++) {
577 578 579
#if defined(TARGET_PPC64)
        if (is_64b) {
            pte0 = ldq_phys(base + (i * 16));
B
blueswir1 已提交
580 581 582 583 584 585 586 587
            pte1 = ldq_phys(base + (i * 16) + 8);

            /* We have a TLB that saves 4K pages, so let's
             * split a huge page to 4k chunks */
            if (target_page_bits != TARGET_PAGE_BITS)
                pte1 |= (ctx->eaddr & (( 1 << target_page_bits ) - 1))
                        & TARGET_PAGE_MASK;

588
            r = pte64_check(ctx, pte0, pte1, h, rw, type);
589 590 591 592
            LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
                    TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
                    base + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
                    (int)((pte0 >> 1) & 1), ctx->ptem);
593 594 595 596 597
        } else
#endif
        {
            pte0 = ldl_phys(base + (i * 8));
            pte1 =  ldl_phys(base + (i * 8) + 4);
598
            r = pte32_check(ctx, pte0, pte1, h, rw, type);
599 600 601 602
            LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
                    TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
                    base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
                    (int)((pte0 >> 6) & 1), ctx->ptem);
603
        }
604
        switch (r) {
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
        case -3:
            /* PTE inconsistency */
            return -1;
        case -2:
            /* Access violation */
            ret = -2;
            good = i;
            break;
        case -1:
        default:
            /* No PTE match */
            break;
        case 0:
            /* access granted */
            /* XXX: we should go on looping to check all PTEs consistency
             *      but if we can speed-up the whole thing as the
             *      result would be undefined if PTEs are not consistent.
             */
            ret = 0;
            good = i;
            goto done;
626 627 628
        }
    }
    if (good != -1) {
629
    done:
630 631
        LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n",
                ctx->raddr, ctx->prot, ret);
632
        /* Update page flags */
633
        pte1 = ctx->raddr;
634 635 636 637 638 639 640 641 642 643
        if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
#if defined(TARGET_PPC64)
            if (is_64b) {
                stq_phys_notdirty(base + (good * 16) + 8, pte1);
            } else
#endif
            {
                stl_phys_notdirty(base + (good * 8) + 4, pte1);
            }
        }
644 645 646
    }

    return ret;
B
bellard 已提交
647 648
}

A
Anthony Liguori 已提交
649
static inline int find_pte32(mmu_ctx_t *ctx, int h, int rw, int type,
B
Blue Swirl 已提交
650
                             int target_page_bits)
651
{
B
blueswir1 已提交
652
    return _find_pte(ctx, 0, h, rw, type, target_page_bits);
653 654 655
}

#if defined(TARGET_PPC64)
A
Anthony Liguori 已提交
656
static inline int find_pte64(mmu_ctx_t *ctx, int h, int rw, int type,
B
Blue Swirl 已提交
657
                             int target_page_bits)
658
{
B
blueswir1 已提交
659
    return _find_pte(ctx, 1, h, rw, type, target_page_bits);
660 661 662
}
#endif

A
Anthony Liguori 已提交
663
static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
B
Blue Swirl 已提交
664
                           int type, int target_page_bits)
665 666
{
#if defined(TARGET_PPC64)
667
    if (env->mmu_model & POWERPC_MMU_64)
B
blueswir1 已提交
668
        return find_pte64(ctx, h, rw, type, target_page_bits);
669 670
#endif

B
blueswir1 已提交
671
    return find_pte32(ctx, h, rw, type, target_page_bits);
672 673 674
}

#if defined(TARGET_PPC64)
A
Anthony Liguori 已提交
675
static ppc_slb_t *slb_get_entry(CPUPPCState *env, int nr)
676
{
A
Anthony Liguori 已提交
677
    ppc_slb_t *retval = &env->slb[nr];
B
blueswir1 已提交
678 679 680

#if 0 // XXX implement bridge mode?
    if (env->spr[SPR_ASR] & 1) {
A
Anthony Liguori 已提交
681
        target_phys_addr_t sr_base;
B
blueswir1 已提交
682 683 684 685 686 687 688 689 690 691

        sr_base = env->spr[SPR_ASR] & 0xfffffffffffff000;
        sr_base += (12 * nr);

        retval->tmp64 = ldq_phys(sr_base);
        retval->tmp = ldl_phys(sr_base + 8);
    }
#endif

    return retval;
692 693
}

A
Anthony Liguori 已提交
694
static void slb_set_entry(CPUPPCState *env, int nr, ppc_slb_t *slb)
695
{
A
Anthony Liguori 已提交
696
    ppc_slb_t *entry = &env->slb[nr];
B
blueswir1 已提交
697 698 699 700 701 702 703 704

    if (slb == entry)
        return;

    entry->tmp64 = slb->tmp64;
    entry->tmp = slb->tmp;
}

A
Anthony Liguori 已提交
705
static inline int slb_is_valid(ppc_slb_t *slb)
B
blueswir1 已提交
706 707 708 709
{
    return (int)(slb->tmp64 & 0x0000000008000000ULL);
}

A
Anthony Liguori 已提交
710
static inline void slb_invalidate(ppc_slb_t *slb)
B
blueswir1 已提交
711 712
{
    slb->tmp64 &= ~0x0000000008000000ULL;
713 714
}

B
Blue Swirl 已提交
715 716 717
static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr,
                             target_ulong *vsid, target_ulong *page_mask,
                             int *attr, int *target_page_bits)
718 719 720 721 722
{
    target_ulong mask;
    int n, ret;

    ret = -5;
723
    LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
724
    mask = 0x0000000000000000ULL; /* Avoid gcc warning */
725
    for (n = 0; n < env->slb_nr; n++) {
A
Anthony Liguori 已提交
726
        ppc_slb_t *slb = slb_get_entry(env, n);
B
blueswir1 已提交
727 728 729 730

        LOG_SLB("%s: seg %d %016" PRIx64 " %08"
                    PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp);
        if (slb_is_valid(slb)) {
731
            /* SLB entry is valid */
A
Alexander Graf 已提交
732
            mask = 0xFFFFFFFFF0000000ULL;
B
blueswir1 已提交
733
            if (slb->tmp & 0x8) {
A
Alexander Graf 已提交
734
                /* 16 MB PTEs */
B
blueswir1 已提交
735
                if (target_page_bits)
A
Alexander Graf 已提交
736
                    *target_page_bits = 24;
B
blueswir1 已提交
737
            } else {
A
Alexander Graf 已提交
738
                /* 4 KB PTEs */
B
blueswir1 已提交
739 740
                if (target_page_bits)
                    *target_page_bits = TARGET_PAGE_BITS;
741
            }
B
blueswir1 已提交
742
            if ((eaddr & mask) == (slb->tmp64 & mask)) {
743
                /* SLB match */
B
blueswir1 已提交
744
                *vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
745
                *page_mask = ~mask;
B
blueswir1 已提交
746
                *attr = slb->tmp & 0xFF;
747
                ret = n;
748 749 750 751 752 753
                break;
            }
        }
    }

    return ret;
B
bellard 已提交
754
}
755

756 757 758 759 760
void ppc_slb_invalidate_all (CPUPPCState *env)
{
    int n, do_invalidate;

    do_invalidate = 0;
761 762
    /* XXX: Warning: slbia never invalidates the first segment */
    for (n = 1; n < env->slb_nr; n++) {
A
Anthony Liguori 已提交
763
        ppc_slb_t *slb = slb_get_entry(env, n);
B
blueswir1 已提交
764 765 766 767

        if (slb_is_valid(slb)) {
            slb_invalidate(slb);
            slb_set_entry(env, n, slb);
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
            /* XXX: given the fact that segment size is 256 MB or 1TB,
             *      and we still don't have a tlb_flush_mask(env, n, mask)
             *      in Qemu, we just invalidate all TLBs
             */
            do_invalidate = 1;
        }
    }
    if (do_invalidate)
        tlb_flush(env, 1);
}

void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
{
    target_ulong vsid, page_mask;
    int attr;
    int n;

B
blueswir1 已提交
785
    n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
786
    if (n >= 0) {
A
Anthony Liguori 已提交
787
        ppc_slb_t *slb = slb_get_entry(env, n);
B
blueswir1 已提交
788 789 790 791

        if (slb_is_valid(slb)) {
            slb_invalidate(slb);
            slb_set_entry(env, n, slb);
792 793 794 795 796 797 798 799 800
            /* XXX: given the fact that segment size is 256 MB or 1TB,
             *      and we still don't have a tlb_flush_mask(env, n, mask)
             *      in Qemu, we just invalidate all TLBs
             */
            tlb_flush(env, 1);
        }
    }
}

801 802 803
target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
{
    target_ulong rt;
A
Anthony Liguori 已提交
804
    ppc_slb_t *slb = slb_get_entry(env, slb_nr);
B
blueswir1 已提交
805 806

    if (slb_is_valid(slb)) {
807 808
        /* SLB entry is valid */
        /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */
B
blueswir1 已提交
809 810
        rt = slb->tmp >> 8;             /* 65:88 => 40:63 */
        rt |= (slb->tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
811
        /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */
B
blueswir1 已提交
812
        rt |= ((slb->tmp >> 4) & 0xF) << 27;
813 814 815
    } else {
        rt = 0;
    }
B
blueswir1 已提交
816
    LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d "
817
            TARGET_FMT_lx "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt);
818 819 820 821

    return rt;
}

B
blueswir1 已提交
822
void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
823
{
A
Anthony Liguori 已提交
824
    ppc_slb_t *slb;
825

B
blueswir1 已提交
826 827 828 829 830 831 832 833 834 835 836
    uint64_t vsid;
    uint64_t esid;
    int flags, valid, slb_nr;

    vsid = rs >> 12;
    flags = ((rs >> 8) & 0xf);

    esid = rb >> 28;
    valid = (rb & (1 << 27));
    slb_nr = rb & 0xfff;

B
blueswir1 已提交
837 838 839
    slb = slb_get_entry(env, slb_nr);
    slb->tmp64 = (esid << 28) | valid | (vsid >> 24);
    slb->tmp = (vsid << 8) | (flags << 3);
B
blueswir1 已提交
840

841 842 843
    LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
            " %08" PRIx32 "\n", __func__, slb_nr, rb, rs, slb->tmp64,
            slb->tmp);
B
blueswir1 已提交
844

B
blueswir1 已提交
845
    slb_set_entry(env, slb_nr, slb);
846
}
847
#endif /* defined(TARGET_PPC64) */
B
bellard 已提交
848

849
/* Perform segment based translation */
A
Anthony Liguori 已提交
850
static inline target_phys_addr_t get_pgaddr(target_phys_addr_t sdr1,
B
Blue Swirl 已提交
851
                                            int sdr_sh,
A
Anthony Liguori 已提交
852 853
                                            target_phys_addr_t hash,
                                            target_phys_addr_t mask)
854
{
A
Anthony Liguori 已提交
855
    return (sdr1 & ((target_phys_addr_t)(-1ULL) << sdr_sh)) | (hash & mask);
856 857
}

A
Anthony Liguori 已提交
858
static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
B
Blue Swirl 已提交
859
                              target_ulong eaddr, int rw, int type)
B
bellard 已提交
860
{
A
Anthony Liguori 已提交
861
    target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask;
862 863 864
    target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
#if defined(TARGET_PPC64)
    int attr;
865
#endif
B
blueswir1 已提交
866
    int ds, vsid_sh, sdr_sh, pr, target_page_bits;
867 868
    int ret, ret2;

869
    pr = msr_pr;
870
#if defined(TARGET_PPC64)
871
    if (env->mmu_model & POWERPC_MMU_64) {
872
        LOG_MMU("Check SLBs\n");
B
blueswir1 已提交
873 874
        ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr,
                         &target_page_bits);
875 876
        if (ret < 0)
            return ret;
877 878
        ctx->key = ((attr & 0x40) && (pr != 0)) ||
            ((attr & 0x80) && (pr == 0)) ? 1 : 0;
879
        ds = 0;
B
blueswir1 已提交
880 881
        ctx->nx = attr & 0x10 ? 1 : 0;
        ctx->eaddr = eaddr;
882 883 884 885 886 887 888 889 890
        vsid_mask = 0x00003FFFFFFFFF80ULL;
        vsid_sh = 7;
        sdr_sh = 18;
        sdr_mask = 0x3FF80;
    } else
#endif /* defined(TARGET_PPC64) */
    {
        sr = env->sr[eaddr >> 28];
        page_mask = 0x0FFFFFFF;
891 892
        ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
                    ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
893
        ds = sr & 0x80000000 ? 1 : 0;
894
        ctx->nx = sr & 0x10000000 ? 1 : 0;
895 896 897 898 899
        vsid = sr & 0x00FFFFFF;
        vsid_mask = 0x01FFFFC0;
        vsid_sh = 6;
        sdr_sh = 16;
        sdr_mask = 0xFFC0;
B
blueswir1 已提交
900
        target_page_bits = TARGET_PAGE_BITS;
901 902 903 904 905
        LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
                TARGET_FMT_lx " lr=" TARGET_FMT_lx
                " ir=%d dr=%d pr=%d %d t=%d\n",
                eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
                (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
906
    }
907 908
    LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
            ctx->key, ds, ctx->nx, vsid);
909 910
    ret = -1;
    if (!ds) {
911
        /* Check if instruction fetch is allowed, if needed */
912
        if (type != ACCESS_CODE || ctx->nx == 0) {
913
            /* Page address translation */
914 915
            /* Primary table address */
            sdr = env->sdr1;
B
blueswir1 已提交
916
            pgidx = (eaddr & page_mask) >> target_page_bits;
917
#if defined(TARGET_PPC64)
918
            if (env->mmu_model & POWERPC_MMU_64) {
919 920 921 922 923 924 925 926 927 928
                htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F));
                /* XXX: this is false for 1 TB segments */
                hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
            } else
#endif
            {
                htab_mask = sdr & 0x000001FF;
                hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
            }
            mask = (htab_mask << sdr_sh) | sdr_mask;
929 930 931
            LOG_MMU("sdr " TARGET_FMT_plx " sh %d hash " TARGET_FMT_plx
                    " mask " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
                    sdr, sdr_sh, hash, mask, page_mask);
932
            ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask);
933
            /* Secondary table address */
934
            hash = (~hash) & vsid_mask;
935 936
            LOG_MMU("sdr " TARGET_FMT_plx " sh %d hash " TARGET_FMT_plx
                    " mask " TARGET_FMT_plx "\n", sdr, sdr_sh, hash, mask);
937 938
            ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask);
#if defined(TARGET_PPC64)
939
            if (env->mmu_model & POWERPC_MMU_64) {
940
                /* Only 5 bits of the page index are used in the AVPN */
B
blueswir1 已提交
941 942 943 944 945 946
                if (target_page_bits > 23) {
                    ctx->ptem = (vsid << 12) |
                                ((pgidx << (target_page_bits - 16)) & 0xF80);
                } else {
                    ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80);
                }
947 948 949 950 951
            } else
#endif
            {
                ctx->ptem = (vsid << 7) | (pgidx >> 10);
            }
952
            /* Initialize real address with an invalid value */
A
Anthony Liguori 已提交
953
            ctx->raddr = (target_phys_addr_t)-1ULL;
954 955
            if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
                         env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
956 957 958
                /* Software TLB search */
                ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
            } else {
959 960 961 962
                LOG_MMU("0 sdr1=" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " "
                        "api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx
                        " pg_addr=" TARGET_FMT_plx "\n",
                        sdr, vsid, pgidx, hash, ctx->pg_addr[0]);
963
                /* Primary table lookup */
B
blueswir1 已提交
964
                ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
965 966
                if (ret < 0) {
                    /* Secondary table lookup */
967
                    if (eaddr != 0xEFFFFFFF)
968 969 970 971
                        LOG_MMU("1 sdr1=" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " "
                                "api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx
                                " pg_addr=" TARGET_FMT_plx "\n", sdr, vsid,
                                pgidx, hash, ctx->pg_addr[1]);
B
blueswir1 已提交
972 973
                    ret2 = find_pte(env, ctx, 1, rw, type,
                                    target_page_bits);
974 975 976
                    if (ret2 != -1)
                        ret = ret2;
                }
977
            }
978
#if defined (DUMP_PAGE_TABLES)
979
            if (qemu_log_enabled()) {
A
Anthony Liguori 已提交
980
                target_phys_addr_t curaddr;
J
j_mayer 已提交
981
                uint32_t a0, a1, a2, a3;
982 983
                qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
                         "\n", sdr, mask + 0x80);
J
j_mayer 已提交
984 985 986 987 988 989 990
                for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
                     curaddr += 16) {
                    a0 = ldl_phys(curaddr);
                    a1 = ldl_phys(curaddr + 4);
                    a2 = ldl_phys(curaddr + 8);
                    a3 = ldl_phys(curaddr + 12);
                    if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
991 992
                        qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
                                 curaddr, a0, a1, a2, a3);
993
                    }
J
j_mayer 已提交
994 995
                }
            }
996
#endif
997
        } else {
998
            LOG_MMU("No access allowed\n");
999
            ret = -3;
1000 1001
        }
    } else {
1002
        LOG_MMU("direct store...\n");
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
        /* Direct-store segment : absolutely *BUGGY* for now */
        switch (type) {
        case ACCESS_INT:
            /* Integer load/store : only access allowed */
            break;
        case ACCESS_CODE:
            /* No code fetch is allowed in direct-store areas */
            return -4;
        case ACCESS_FLOAT:
            /* Floating point load/store */
            return -4;
        case ACCESS_RES:
            /* lwarx, ldarx or srwcx. */
            return -4;
        case ACCESS_CACHE:
            /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
            /* Should make the instruction do no-op.
             * As it already do no-op, it's quite easy :-)
             */
1022
            ctx->raddr = eaddr;
1023 1024 1025 1026 1027
            return 0;
        case ACCESS_EXT:
            /* eciwx or ecowx */
            return -4;
        default:
1028
            qemu_log("ERROR: instruction should not need "
1029 1030 1031
                        "address translation\n");
            return -4;
        }
1032 1033
        if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
            ctx->raddr = eaddr;
1034 1035 1036 1037
            ret = 2;
        } else {
            ret = -2;
        }
B
bellard 已提交
1038
    }
1039 1040

    return ret;
B
bellard 已提交
1041 1042
}

1043
/* Generic TLB check function for embedded PowerPC implementations */
A
Anthony Liguori 已提交
1044 1045
static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
                                   target_phys_addr_t *raddrp,
B
Blue Swirl 已提交
1046 1047
                                   target_ulong address, uint32_t pid, int ext,
                                   int i)
1048 1049 1050 1051 1052 1053 1054 1055
{
    target_ulong mask;

    /* Check valid flag */
    if (!(tlb->prot & PAGE_VALID)) {
        return -1;
    }
    mask = ~(tlb->size - 1);
1056 1057 1058
    LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
              " " TARGET_FMT_lx " %u\n", __func__, i, address, pid, tlb->EPN,
              mask, (uint32_t)tlb->PID);
1059
    /* Check PID */
1060
    if (tlb->PID != 0 && tlb->PID != pid)
1061 1062 1063 1064 1065
        return -1;
    /* Check effective address */
    if ((address & mask) != tlb->EPN)
        return -1;
    *raddrp = (tlb->RPN & mask) | (address & ~mask);
1066
#if (TARGET_PHYS_ADDR_BITS >= 36)
1067 1068
    if (ext) {
        /* Extend the physical address to 36 bits */
A
Anthony Liguori 已提交
1069
        *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
1070
    }
1071
#endif
1072 1073 1074 1075 1076

    return 0;
}

/* Generic TLB search function for PowerPC embedded implementations */
1077
int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
1078
{
A
Anthony Liguori 已提交
1079 1080
    ppcemb_tlb_t *tlb;
    target_phys_addr_t raddr;
1081 1082 1083 1084
    int i, ret;

    /* Default return value is no match */
    ret = -1;
1085
    for (i = 0; i < env->nb_tlb; i++) {
1086
        tlb = &env->tlb[i].tlbe;
1087
        if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
1088 1089 1090 1091 1092 1093 1094 1095
            ret = i;
            break;
        }
    }

    return ret;
}

1096
/* Helpers specific to PowerPC 40x implementations */
B
Blue Swirl 已提交
1097
static inline void ppc4xx_tlb_invalidate_all(CPUState *env)
1098
{
A
Anthony Liguori 已提交
1099
    ppcemb_tlb_t *tlb;
1100 1101 1102 1103
    int i;

    for (i = 0; i < env->nb_tlb; i++) {
        tlb = &env->tlb[i].tlbe;
1104
        tlb->prot &= ~PAGE_VALID;
1105
    }
1106
    tlb_flush(env, 1);
1107 1108
}

B
Blue Swirl 已提交
1109 1110
static inline void ppc4xx_tlb_invalidate_virt(CPUState *env,
                                              target_ulong eaddr, uint32_t pid)
J
j_mayer 已提交
1111
{
1112
#if !defined(FLUSH_ALL_TLBS)
A
Anthony Liguori 已提交
1113 1114
    ppcemb_tlb_t *tlb;
    target_phys_addr_t raddr;
1115
    target_ulong page, end;
J
j_mayer 已提交
1116 1117 1118 1119
    int i;

    for (i = 0; i < env->nb_tlb; i++) {
        tlb = &env->tlb[i].tlbe;
1120
        if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
J
j_mayer 已提交
1121 1122 1123 1124
            end = tlb->EPN + tlb->size;
            for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
                tlb_flush_page(env, page);
            tlb->prot &= ~PAGE_VALID;
1125
            break;
J
j_mayer 已提交
1126 1127
        }
    }
1128 1129 1130
#else
    ppc4xx_tlb_invalidate_all(env);
#endif
J
j_mayer 已提交
1131 1132
}

A
Anthony Liguori 已提交
1133
static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
1134
                                 target_ulong address, int rw, int access_type)
J
j_mayer 已提交
1135
{
A
Anthony Liguori 已提交
1136 1137
    ppcemb_tlb_t *tlb;
    target_phys_addr_t raddr;
1138
    int i, ret, zsel, zpr, pr;
1139

1140
    ret = -1;
A
Anthony Liguori 已提交
1141
    raddr = (target_phys_addr_t)-1ULL;
1142
    pr = msr_pr;
J
j_mayer 已提交
1143 1144
    for (i = 0; i < env->nb_tlb; i++) {
        tlb = &env->tlb[i].tlbe;
1145 1146
        if (ppcemb_tlb_check(env, tlb, &raddr, address,
                             env->spr[SPR_40x_PID], 0, i) < 0)
J
j_mayer 已提交
1147 1148
            continue;
        zsel = (tlb->attr >> 4) & 0xF;
1149
        zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
1150
        LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
J
j_mayer 已提交
1151
                    __func__, i, zsel, zpr, rw, tlb->attr);
1152 1153 1154
        /* Check execute enable bit */
        switch (zpr) {
        case 0x2:
1155
            if (pr != 0)
1156 1157 1158 1159 1160 1161 1162 1163
                goto check_perms;
            /* No break here */
        case 0x3:
            /* All accesses granted */
            ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
            ret = 0;
            break;
        case 0x0:
1164
            if (pr != 0) {
1165 1166
                /* Raise Zone protection fault.  */
                env->spr[SPR_40x_ESR] = 1 << 22;
1167 1168
                ctx->prot = 0;
                ret = -2;
J
j_mayer 已提交
1169 1170
                break;
            }
1171 1172 1173 1174 1175 1176 1177 1178
            /* No break here */
        case 0x1:
        check_perms:
            /* Check from TLB entry */
            /* XXX: there is a problem here or in the TLB fill code... */
            ctx->prot = tlb->prot;
            ctx->prot |= PAGE_EXEC;
            ret = check_prot(ctx->prot, rw, access_type);
1179 1180
            if (ret == -2)
                env->spr[SPR_40x_ESR] = 0;
1181
            break;
J
j_mayer 已提交
1182 1183 1184
        }
        if (ret >= 0) {
            ctx->raddr = raddr;
1185 1186 1187
            LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
                      " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
                      ret);
1188
            return 0;
J
j_mayer 已提交
1189 1190
        }
    }
1191 1192
    LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
              " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1193

J
j_mayer 已提交
1194 1195 1196
    return ret;
}

1197 1198 1199 1200 1201 1202 1203 1204 1205
void store_40x_sler (CPUPPCState *env, uint32_t val)
{
    /* XXX: TO BE FIXED */
    if (val != 0x00000000) {
        cpu_abort(env, "Little-endian regions are not supported by now\n");
    }
    env->spr[SPR_405_SLER] = val;
}

A
Anthony Liguori 已提交
1206
static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
A
aurel32 已提交
1207 1208
                                          target_ulong address, int rw,
                                          int access_type)
1209
{
A
Anthony Liguori 已提交
1210 1211
    ppcemb_tlb_t *tlb;
    target_phys_addr_t raddr;
1212 1213 1214
    int i, prot, ret;

    ret = -1;
A
Anthony Liguori 已提交
1215
    raddr = (target_phys_addr_t)-1ULL;
1216 1217 1218 1219 1220
    for (i = 0; i < env->nb_tlb; i++) {
        tlb = &env->tlb[i].tlbe;
        if (ppcemb_tlb_check(env, tlb, &raddr, address,
                             env->spr[SPR_BOOKE_PID], 1, i) < 0)
            continue;
1221
        if (msr_pr != 0)
1222 1223 1224 1225 1226
            prot = tlb->prot & 0xF;
        else
            prot = (tlb->prot >> 4) & 0xF;
        /* Check the address space */
        if (access_type == ACCESS_CODE) {
1227
            if (msr_ir != (tlb->attr & 1))
1228 1229 1230 1231 1232 1233 1234 1235
                continue;
            ctx->prot = prot;
            if (prot & PAGE_EXEC) {
                ret = 0;
                break;
            }
            ret = -3;
        } else {
1236
            if (msr_dr != (tlb->attr & 1))
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
                continue;
            ctx->prot = prot;
            if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
                ret = 0;
                break;
            }
            ret = -2;
        }
    }
    if (ret >= 0)
        ctx->raddr = raddr;

    return ret;
}

A
Anthony Liguori 已提交
1252
static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
B
Blue Swirl 已提交
1253
                                 target_ulong eaddr, int rw)
1254 1255
{
    int in_plb, ret;
1256

1257
    ctx->raddr = eaddr;
1258
    ctx->prot = PAGE_READ | PAGE_EXEC;
1259
    ret = 0;
1260 1261
    switch (env->mmu_model) {
    case POWERPC_MMU_32B:
J
j_mayer 已提交
1262
    case POWERPC_MMU_601:
1263
    case POWERPC_MMU_SOFT_6xx:
1264
    case POWERPC_MMU_SOFT_74xx:
1265
    case POWERPC_MMU_SOFT_4xx:
1266
    case POWERPC_MMU_REAL:
1267
    case POWERPC_MMU_BOOKE:
1268 1269 1270
        ctx->prot |= PAGE_WRITE;
        break;
#if defined(TARGET_PPC64)
1271
    case POWERPC_MMU_620:
1272
    case POWERPC_MMU_64B:
1273
        /* Real address are 60 bits long */
1274
        ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
1275 1276
        ctx->prot |= PAGE_WRITE;
        break;
1277
#endif
1278
    case POWERPC_MMU_SOFT_4xx_Z:
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
        if (unlikely(msr_pe != 0)) {
            /* 403 family add some particular protections,
             * using PBL/PBU registers for accesses with no translation.
             */
            in_plb =
                /* Check PLB validity */
                (env->pb[0] < env->pb[1] &&
                 /* and address in plb area */
                 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
                (env->pb[2] < env->pb[3] &&
                 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
            if (in_plb ^ msr_px) {
                /* Access in protected area */
                if (rw == 1) {
                    /* Access is not allowed */
                    ret = -2;
                }
            } else {
                /* Read-write access is allowed */
                ctx->prot |= PAGE_WRITE;
1299 1300
            }
        }
1301
        break;
1302 1303 1304 1305
    case POWERPC_MMU_MPC8xx:
        /* XXX: TODO */
        cpu_abort(env, "MPC8xx MMU model is not implemented\n");
        break;
1306
    case POWERPC_MMU_BOOKE_FSL:
1307 1308 1309 1310 1311 1312
        /* XXX: TODO */
        cpu_abort(env, "BookE FSL MMU model not implemented\n");
        break;
    default:
        cpu_abort(env, "Unknown or invalid MMU model\n");
        return -1;
1313 1314 1315 1316 1317
    }

    return ret;
}

A
Anthony Liguori 已提交
1318
int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
J
j_mayer 已提交
1319
                          int rw, int access_type)
1320 1321
{
    int ret;
1322

B
bellard 已提交
1323
#if 0
1324
    qemu_log("%s\n", __func__);
1325
#endif
B
bellard 已提交
1326 1327
    if ((access_type == ACCESS_CODE && msr_ir == 0) ||
        (access_type != ACCESS_CODE && msr_dr == 0)) {
1328
        /* No address translation */
1329
        ret = check_physical(env, ctx, eaddr, rw);
1330
    } else {
1331
        ret = -1;
1332 1333
        switch (env->mmu_model) {
        case POWERPC_MMU_32B:
J
j_mayer 已提交
1334
        case POWERPC_MMU_601:
1335
        case POWERPC_MMU_SOFT_6xx:
1336
        case POWERPC_MMU_SOFT_74xx:
B
blueswir1 已提交
1337 1338 1339
            /* Try to find a BAT */
            if (env->nb_BATs != 0)
                ret = get_bat(env, ctx, eaddr, rw, access_type);
1340
#if defined(TARGET_PPC64)
1341
        case POWERPC_MMU_620:
1342
        case POWERPC_MMU_64B:
1343
#endif
J
j_mayer 已提交
1344
            if (ret < 0) {
1345
                /* We didn't match any BAT entry or don't have BATs */
J
j_mayer 已提交
1346 1347 1348
                ret = get_segment(env, ctx, eaddr, rw, access_type);
            }
            break;
1349 1350
        case POWERPC_MMU_SOFT_4xx:
        case POWERPC_MMU_SOFT_4xx_Z:
1351
            ret = mmu40x_get_physical_address(env, ctx, eaddr,
J
j_mayer 已提交
1352 1353
                                              rw, access_type);
            break;
1354
        case POWERPC_MMU_BOOKE:
1355 1356 1357
            ret = mmubooke_get_physical_address(env, ctx, eaddr,
                                                rw, access_type);
            break;
1358 1359 1360 1361
        case POWERPC_MMU_MPC8xx:
            /* XXX: TODO */
            cpu_abort(env, "MPC8xx MMU model is not implemented\n");
            break;
1362
        case POWERPC_MMU_BOOKE_FSL:
1363 1364 1365
            /* XXX: TODO */
            cpu_abort(env, "BookE FSL MMU model not implemented\n");
            return -1;
1366 1367
        case POWERPC_MMU_REAL:
            cpu_abort(env, "PowerPC in real mode do not do any translation\n");
1368
            return -1;
1369 1370
        default:
            cpu_abort(env, "Unknown or invalid MMU model\n");
J
j_mayer 已提交
1371
            return -1;
1372 1373
        }
    }
B
bellard 已提交
1374
#if 0
1375 1376
    qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
             __func__, eaddr, ret, ctx->raddr);
1377
#endif
1378

1379 1380 1381
    return ret;
}

A
Anthony Liguori 已提交
1382
target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
B
bellard 已提交
1383
{
A
Anthony Liguori 已提交
1384
    mmu_ctx_t ctx;
B
bellard 已提交
1385

J
j_mayer 已提交
1386
    if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0))
B
bellard 已提交
1387
        return -1;
1388 1389

    return ctx.raddr & TARGET_PAGE_MASK;
B
bellard 已提交
1390
}
1391 1392

/* Perform address translation */
1393
int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
1394
                              int mmu_idx, int is_softmmu)
1395
{
A
Anthony Liguori 已提交
1396
    mmu_ctx_t ctx;
1397
    int access_type;
1398
    int ret = 0;
1399

B
bellard 已提交
1400 1401 1402 1403 1404 1405
    if (rw == 2) {
        /* code access */
        rw = 0;
        access_type = ACCESS_CODE;
    } else {
        /* data access */
A
aurel32 已提交
1406
        access_type = env->access_type;
B
bellard 已提交
1407
    }
J
j_mayer 已提交
1408
    ret = get_physical_address(env, &ctx, address, rw, access_type);
1409
    if (ret == 0) {
P
Paul Brook 已提交
1410 1411 1412 1413
        tlb_set_page(env, address & TARGET_PAGE_MASK,
                     ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
                     mmu_idx, TARGET_PAGE_SIZE);
        ret = 0;
1414
    } else if (ret < 0) {
1415
        LOG_MMU_STATE(env);
1416 1417 1418
        if (access_type == ACCESS_CODE) {
            switch (ret) {
            case -1:
1419
                /* No matches in page tables or TLB */
1420 1421
                switch (env->mmu_model) {
                case POWERPC_MMU_SOFT_6xx:
1422 1423
                    env->exception_index = POWERPC_EXCP_IFTLB;
                    env->error_code = 1 << 18;
1424 1425 1426
                    env->spr[SPR_IMISS] = address;
                    env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
                    goto tlb_miss;
1427
                case POWERPC_MMU_SOFT_74xx:
1428
                    env->exception_index = POWERPC_EXCP_IFTLB;
1429
                    goto tlb_miss_74xx;
1430 1431
                case POWERPC_MMU_SOFT_4xx:
                case POWERPC_MMU_SOFT_4xx_Z:
1432 1433
                    env->exception_index = POWERPC_EXCP_ITLB;
                    env->error_code = 0;
J
j_mayer 已提交
1434 1435
                    env->spr[SPR_40x_DEAR] = address;
                    env->spr[SPR_40x_ESR] = 0x00000000;
1436
                    break;
1437
                case POWERPC_MMU_32B:
J
j_mayer 已提交
1438
                case POWERPC_MMU_601:
1439
#if defined(TARGET_PPC64)
1440
                case POWERPC_MMU_620:
1441
                case POWERPC_MMU_64B:
1442
#endif
1443 1444 1445
                    env->exception_index = POWERPC_EXCP_ISI;
                    env->error_code = 0x40000000;
                    break;
1446
                case POWERPC_MMU_BOOKE:
1447
                    /* XXX: TODO */
1448
                    cpu_abort(env, "BookE MMU model is not implemented\n");
1449
                    return -1;
1450
                case POWERPC_MMU_BOOKE_FSL:
1451
                    /* XXX: TODO */
1452
                    cpu_abort(env, "BookE FSL MMU model is not implemented\n");
1453
                    return -1;
1454 1455 1456 1457 1458 1459 1460
                case POWERPC_MMU_MPC8xx:
                    /* XXX: TODO */
                    cpu_abort(env, "MPC8xx MMU model is not implemented\n");
                    break;
                case POWERPC_MMU_REAL:
                    cpu_abort(env, "PowerPC in real mode should never raise "
                              "any MMU exceptions\n");
1461
                    return -1;
1462 1463 1464
                default:
                    cpu_abort(env, "Unknown or invalid MMU model\n");
                    return -1;
1465
                }
1466 1467 1468
                break;
            case -2:
                /* Access rights violation */
1469 1470
                env->exception_index = POWERPC_EXCP_ISI;
                env->error_code = 0x08000000;
1471 1472
                break;
            case -3:
1473
                /* No execute protection violation */
1474 1475
                env->exception_index = POWERPC_EXCP_ISI;
                env->error_code = 0x10000000;
1476 1477 1478 1479
                break;
            case -4:
                /* Direct store exception */
                /* No code fetch is allowed in direct-store areas */
1480 1481
                env->exception_index = POWERPC_EXCP_ISI;
                env->error_code = 0x10000000;
1482
                break;
1483
#if defined(TARGET_PPC64)
1484 1485
            case -5:
                /* No match in segment table */
1486 1487 1488 1489 1490 1491 1492 1493
                if (env->mmu_model == POWERPC_MMU_620) {
                    env->exception_index = POWERPC_EXCP_ISI;
                    /* XXX: this might be incorrect */
                    env->error_code = 0x40000000;
                } else {
                    env->exception_index = POWERPC_EXCP_ISEG;
                    env->error_code = 0;
                }
1494
                break;
1495
#endif
1496 1497 1498 1499
            }
        } else {
            switch (ret) {
            case -1:
1500
                /* No matches in page tables or TLB */
1501 1502
                switch (env->mmu_model) {
                case POWERPC_MMU_SOFT_6xx:
1503
                    if (rw == 1) {
1504 1505
                        env->exception_index = POWERPC_EXCP_DSTLB;
                        env->error_code = 1 << 16;
1506
                    } else {
1507 1508
                        env->exception_index = POWERPC_EXCP_DLTLB;
                        env->error_code = 0;
1509 1510 1511 1512
                    }
                    env->spr[SPR_DMISS] = address;
                    env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
                tlb_miss:
1513
                    env->error_code |= ctx.key << 19;
1514 1515
                    env->spr[SPR_HASH1] = ctx.pg_addr[0];
                    env->spr[SPR_HASH2] = ctx.pg_addr[1];
1516
                    break;
1517 1518
                case POWERPC_MMU_SOFT_74xx:
                    if (rw == 1) {
1519
                        env->exception_index = POWERPC_EXCP_DSTLB;
1520
                    } else {
1521
                        env->exception_index = POWERPC_EXCP_DLTLB;
1522 1523 1524
                    }
                tlb_miss_74xx:
                    /* Implement LRU algorithm */
1525
                    env->error_code = ctx.key << 19;
1526 1527 1528 1529
                    env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
                        ((env->last_way + 1) & (env->nb_ways - 1));
                    env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
                    break;
1530 1531
                case POWERPC_MMU_SOFT_4xx:
                case POWERPC_MMU_SOFT_4xx_Z:
1532 1533
                    env->exception_index = POWERPC_EXCP_DTLB;
                    env->error_code = 0;
J
j_mayer 已提交
1534 1535 1536 1537 1538
                    env->spr[SPR_40x_DEAR] = address;
                    if (rw)
                        env->spr[SPR_40x_ESR] = 0x00800000;
                    else
                        env->spr[SPR_40x_ESR] = 0x00000000;
1539
                    break;
1540
                case POWERPC_MMU_32B:
J
j_mayer 已提交
1541
                case POWERPC_MMU_601:
1542
#if defined(TARGET_PPC64)
1543
                case POWERPC_MMU_620:
1544
                case POWERPC_MMU_64B:
1545
#endif
1546 1547 1548 1549 1550 1551 1552 1553
                    env->exception_index = POWERPC_EXCP_DSI;
                    env->error_code = 0;
                    env->spr[SPR_DAR] = address;
                    if (rw == 1)
                        env->spr[SPR_DSISR] = 0x42000000;
                    else
                        env->spr[SPR_DSISR] = 0x40000000;
                    break;
1554 1555 1556 1557
                case POWERPC_MMU_MPC8xx:
                    /* XXX: TODO */
                    cpu_abort(env, "MPC8xx MMU model is not implemented\n");
                    break;
1558
                case POWERPC_MMU_BOOKE:
1559
                    /* XXX: TODO */
1560
                    cpu_abort(env, "BookE MMU model is not implemented\n");
1561
                    return -1;
1562
                case POWERPC_MMU_BOOKE_FSL:
1563
                    /* XXX: TODO */
1564
                    cpu_abort(env, "BookE FSL MMU model is not implemented\n");
1565
                    return -1;
1566 1567 1568
                case POWERPC_MMU_REAL:
                    cpu_abort(env, "PowerPC in real mode should never raise "
                              "any MMU exceptions\n");
1569
                    return -1;
1570 1571 1572
                default:
                    cpu_abort(env, "Unknown or invalid MMU model\n");
                    return -1;
1573
                }
1574 1575 1576
                break;
            case -2:
                /* Access rights violation */
1577 1578
                env->exception_index = POWERPC_EXCP_DSI;
                env->error_code = 0;
1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
                if (env->mmu_model == POWERPC_MMU_SOFT_4xx
                    || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
                    env->spr[SPR_40x_DEAR] = address;
                    if (rw) {
                        env->spr[SPR_40x_ESR] |= 0x00800000;
                    }
                } else {
                    env->spr[SPR_DAR] = address;
                    if (rw == 1) {
                        env->spr[SPR_DSISR] = 0x0A000000;
                    } else {
                        env->spr[SPR_DSISR] = 0x08000000;
                    }
                }
1593 1594 1595 1596 1597 1598
                break;
            case -4:
                /* Direct store exception */
                switch (access_type) {
                case ACCESS_FLOAT:
                    /* Floating point load/store */
1599 1600 1601
                    env->exception_index = POWERPC_EXCP_ALIGN;
                    env->error_code = POWERPC_EXCP_ALIGN_FP;
                    env->spr[SPR_DAR] = address;
1602 1603
                    break;
                case ACCESS_RES:
1604 1605 1606 1607 1608 1609 1610 1611
                    /* lwarx, ldarx or stwcx. */
                    env->exception_index = POWERPC_EXCP_DSI;
                    env->error_code = 0;
                    env->spr[SPR_DAR] = address;
                    if (rw == 1)
                        env->spr[SPR_DSISR] = 0x06000000;
                    else
                        env->spr[SPR_DSISR] = 0x04000000;
1612 1613 1614
                    break;
                case ACCESS_EXT:
                    /* eciwx or ecowx */
1615 1616 1617 1618 1619 1620 1621
                    env->exception_index = POWERPC_EXCP_DSI;
                    env->error_code = 0;
                    env->spr[SPR_DAR] = address;
                    if (rw == 1)
                        env->spr[SPR_DSISR] = 0x06100000;
                    else
                        env->spr[SPR_DSISR] = 0x04100000;
1622 1623
                    break;
                default:
1624
                    printf("DSI: invalid exception (%d)\n", ret);
1625 1626 1627 1628
                    env->exception_index = POWERPC_EXCP_PROGRAM;
                    env->error_code =
                        POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
                    env->spr[SPR_DAR] = address;
1629 1630
                    break;
                }
1631
                break;
1632
#if defined(TARGET_PPC64)
1633 1634
            case -5:
                /* No match in segment table */
1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648
                if (env->mmu_model == POWERPC_MMU_620) {
                    env->exception_index = POWERPC_EXCP_DSI;
                    env->error_code = 0;
                    env->spr[SPR_DAR] = address;
                    /* XXX: this might be incorrect */
                    if (rw == 1)
                        env->spr[SPR_DSISR] = 0x42000000;
                    else
                        env->spr[SPR_DSISR] = 0x40000000;
                } else {
                    env->exception_index = POWERPC_EXCP_DSEG;
                    env->error_code = 0;
                    env->spr[SPR_DAR] = address;
                }
1649
                break;
1650
#endif
1651 1652 1653
            }
        }
#if 0
1654 1655
        printf("%s: set exception to %d %02x\n", __func__,
               env->exception, env->error_code);
1656 1657 1658
#endif
        ret = 1;
    }
1659

1660 1661 1662
    return ret;
}

1663 1664 1665
/*****************************************************************************/
/* BATs management */
#if !defined(FLUSH_ALL_TLBS)
B
Blue Swirl 已提交
1666 1667
static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
                                     target_ulong mask)
1668 1669
{
    target_ulong base, end, page;
1670

1671 1672
    base = BATu & ~0x0001FFFF;
    end = base + mask + 0x00020000;
1673 1674
    LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
             TARGET_FMT_lx ")\n", base, end, mask);
1675 1676
    for (page = base; page != end; page += TARGET_PAGE_SIZE)
        tlb_flush_page(env, page);
1677
    LOG_BATS("Flush done\n");
1678 1679 1680
}
#endif

B
Blue Swirl 已提交
1681 1682
static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
                                  target_ulong value)
1683
{
1684 1685
    LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
             nr, ul == 0 ? 'u' : 'l', value, env->nip);
1686 1687
}

A
aurel32 已提交
1688
void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
{
    target_ulong mask;

    dump_store_bat(env, 'I', 0, nr, value);
    if (env->IBAT[0][nr] != value) {
        mask = (value << 15) & 0x0FFE0000UL;
#if !defined(FLUSH_ALL_TLBS)
        do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#endif
        /* When storing valid upper BAT, mask BEPI and BRPN
         * and invalidate all TLBs covered by this BAT
         */
        mask = (value << 15) & 0x0FFE0000UL;
        env->IBAT[0][nr] = (value & 0x00001FFFUL) |
            (value & ~0x0001FFFFUL & ~mask);
        env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
            (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
#if !defined(FLUSH_ALL_TLBS)
        do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1708
#else
1709 1710 1711 1712 1713
        tlb_flush(env, 1);
#endif
    }
}

A
aurel32 已提交
1714
void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
1715 1716 1717 1718 1719
{
    dump_store_bat(env, 'I', 1, nr, value);
    env->IBAT[1][nr] = value;
}

A
aurel32 已提交
1720
void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745
{
    target_ulong mask;

    dump_store_bat(env, 'D', 0, nr, value);
    if (env->DBAT[0][nr] != value) {
        /* When storing valid upper BAT, mask BEPI and BRPN
         * and invalidate all TLBs covered by this BAT
         */
        mask = (value << 15) & 0x0FFE0000UL;
#if !defined(FLUSH_ALL_TLBS)
        do_invalidate_BAT(env, env->DBAT[0][nr], mask);
#endif
        mask = (value << 15) & 0x0FFE0000UL;
        env->DBAT[0][nr] = (value & 0x00001FFFUL) |
            (value & ~0x0001FFFFUL & ~mask);
        env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
            (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
#if !defined(FLUSH_ALL_TLBS)
        do_invalidate_BAT(env, env->DBAT[0][nr], mask);
#else
        tlb_flush(env, 1);
#endif
    }
}

A
aurel32 已提交
1746
void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
1747 1748 1749 1750 1751
{
    dump_store_bat(env, 'D', 1, nr, value);
    env->DBAT[1][nr] = value;
}

A
aurel32 已提交
1752
void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
1753 1754
{
    target_ulong mask;
1755
#if defined(FLUSH_ALL_TLBS)
1756
    int do_inval;
1757
#endif
1758 1759 1760

    dump_store_bat(env, 'I', 0, nr, value);
    if (env->IBAT[0][nr] != value) {
1761
#if defined(FLUSH_ALL_TLBS)
1762
        do_inval = 0;
1763
#endif
1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792
        mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
        if (env->IBAT[1][nr] & 0x40) {
            /* Invalidate BAT only if it is valid */
#if !defined(FLUSH_ALL_TLBS)
            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#else
            do_inval = 1;
#endif
        }
        /* When storing valid upper BAT, mask BEPI and BRPN
         * and invalidate all TLBs covered by this BAT
         */
        env->IBAT[0][nr] = (value & 0x00001FFFUL) |
            (value & ~0x0001FFFFUL & ~mask);
        env->DBAT[0][nr] = env->IBAT[0][nr];
        if (env->IBAT[1][nr] & 0x40) {
#if !defined(FLUSH_ALL_TLBS)
            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#else
            do_inval = 1;
#endif
        }
#if defined(FLUSH_ALL_TLBS)
        if (do_inval)
            tlb_flush(env, 1);
#endif
    }
}

A
aurel32 已提交
1793
void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
1794 1795
{
    target_ulong mask;
1796
#if defined(FLUSH_ALL_TLBS)
1797
    int do_inval;
1798
#endif
1799 1800 1801

    dump_store_bat(env, 'I', 1, nr, value);
    if (env->IBAT[1][nr] != value) {
1802
#if defined(FLUSH_ALL_TLBS)
1803
        do_inval = 0;
1804
#endif
1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
        if (env->IBAT[1][nr] & 0x40) {
#if !defined(FLUSH_ALL_TLBS)
            mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#else
            do_inval = 1;
#endif
        }
        if (value & 0x40) {
#if !defined(FLUSH_ALL_TLBS)
            mask = (value << 17) & 0x0FFE0000UL;
            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
#else
            do_inval = 1;
#endif
        }
        env->IBAT[1][nr] = value;
        env->DBAT[1][nr] = value;
#if defined(FLUSH_ALL_TLBS)
        if (do_inval)
            tlb_flush(env, 1);
#endif
    }
}

J
j_mayer 已提交
1830 1831 1832 1833
/*****************************************************************************/
/* TLB management */
void ppc_tlb_invalidate_all (CPUPPCState *env)
{
1834 1835
    switch (env->mmu_model) {
    case POWERPC_MMU_SOFT_6xx:
1836
    case POWERPC_MMU_SOFT_74xx:
J
j_mayer 已提交
1837
        ppc6xx_tlb_invalidate_all(env);
1838 1839 1840
        break;
    case POWERPC_MMU_SOFT_4xx:
    case POWERPC_MMU_SOFT_4xx_Z:
J
j_mayer 已提交
1841
        ppc4xx_tlb_invalidate_all(env);
1842
        break;
1843
    case POWERPC_MMU_REAL:
1844 1845
        cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
        break;
1846 1847 1848 1849
    case POWERPC_MMU_MPC8xx:
        /* XXX: TODO */
        cpu_abort(env, "MPC8xx MMU model is not implemented\n");
        break;
1850 1851
    case POWERPC_MMU_BOOKE:
        /* XXX: TODO */
1852
        cpu_abort(env, "BookE MMU model is not implemented\n");
1853 1854 1855
        break;
    case POWERPC_MMU_BOOKE_FSL:
        /* XXX: TODO */
1856 1857
        if (!kvm_enabled())
            cpu_abort(env, "BookE MMU model is not implemented\n");
1858 1859
        break;
    case POWERPC_MMU_32B:
J
j_mayer 已提交
1860
    case POWERPC_MMU_601:
J
j_mayer 已提交
1861
#if defined(TARGET_PPC64)
1862
    case POWERPC_MMU_620:
1863
    case POWERPC_MMU_64B:
J
j_mayer 已提交
1864
#endif /* defined(TARGET_PPC64) */
J
j_mayer 已提交
1865
        tlb_flush(env, 1);
1866
        break;
J
j_mayer 已提交
1867 1868
    default:
        /* XXX: TODO */
1869
        cpu_abort(env, "Unknown MMU model\n");
J
j_mayer 已提交
1870
        break;
J
j_mayer 已提交
1871 1872 1873
    }
}

1874 1875 1876 1877 1878 1879
void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
{
#if !defined(FLUSH_ALL_TLBS)
    addr &= TARGET_PAGE_MASK;
    switch (env->mmu_model) {
    case POWERPC_MMU_SOFT_6xx:
1880
    case POWERPC_MMU_SOFT_74xx:
1881 1882 1883 1884 1885 1886 1887 1888
        ppc6xx_tlb_invalidate_virt(env, addr, 0);
        if (env->id_tlbs == 1)
            ppc6xx_tlb_invalidate_virt(env, addr, 1);
        break;
    case POWERPC_MMU_SOFT_4xx:
    case POWERPC_MMU_SOFT_4xx_Z:
        ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
        break;
1889
    case POWERPC_MMU_REAL:
1890 1891
        cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
        break;
1892 1893 1894 1895
    case POWERPC_MMU_MPC8xx:
        /* XXX: TODO */
        cpu_abort(env, "MPC8xx MMU model is not implemented\n");
        break;
1896 1897
    case POWERPC_MMU_BOOKE:
        /* XXX: TODO */
1898
        cpu_abort(env, "BookE MMU model is not implemented\n");
1899 1900 1901
        break;
    case POWERPC_MMU_BOOKE_FSL:
        /* XXX: TODO */
1902
        cpu_abort(env, "BookE FSL MMU model is not implemented\n");
1903 1904
        break;
    case POWERPC_MMU_32B:
J
j_mayer 已提交
1905
    case POWERPC_MMU_601:
1906
        /* tlbie invalidate TLBs for all segments */
1907
        addr &= ~((target_ulong)-1ULL << 28);
1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926
        /* XXX: this case should be optimized,
         * giving a mask to tlb_flush_page
         */
        tlb_flush_page(env, addr | (0x0 << 28));
        tlb_flush_page(env, addr | (0x1 << 28));
        tlb_flush_page(env, addr | (0x2 << 28));
        tlb_flush_page(env, addr | (0x3 << 28));
        tlb_flush_page(env, addr | (0x4 << 28));
        tlb_flush_page(env, addr | (0x5 << 28));
        tlb_flush_page(env, addr | (0x6 << 28));
        tlb_flush_page(env, addr | (0x7 << 28));
        tlb_flush_page(env, addr | (0x8 << 28));
        tlb_flush_page(env, addr | (0x9 << 28));
        tlb_flush_page(env, addr | (0xA << 28));
        tlb_flush_page(env, addr | (0xB << 28));
        tlb_flush_page(env, addr | (0xC << 28));
        tlb_flush_page(env, addr | (0xD << 28));
        tlb_flush_page(env, addr | (0xE << 28));
        tlb_flush_page(env, addr | (0xF << 28));
1927
        break;
J
j_mayer 已提交
1928
#if defined(TARGET_PPC64)
1929
    case POWERPC_MMU_620:
1930 1931 1932
    case POWERPC_MMU_64B:
        /* tlbie invalidate TLBs for all segments */
        /* XXX: given the fact that there are too many segments to invalidate,
J
j_mayer 已提交
1933
         *      and we still don't have a tlb_flush_mask(env, n, mask) in Qemu,
1934 1935 1936 1937
         *      we just invalidate all TLBs
         */
        tlb_flush(env, 1);
        break;
J
j_mayer 已提交
1938 1939 1940
#endif /* defined(TARGET_PPC64) */
    default:
        /* XXX: TODO */
1941
        cpu_abort(env, "Unknown MMU model\n");
J
j_mayer 已提交
1942
        break;
1943 1944 1945 1946 1947 1948
    }
#else
    ppc_tlb_invalidate_all(env);
#endif
}

1949 1950
/*****************************************************************************/
/* Special registers manipulation */
1951 1952 1953 1954 1955 1956 1957 1958 1959 1960
#if defined(TARGET_PPC64)
void ppc_store_asr (CPUPPCState *env, target_ulong value)
{
    if (env->asr != value) {
        env->asr = value;
        tlb_flush(env, 1);
    }
}
#endif

A
aurel32 已提交
1961
void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
1962
{
1963
    LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
1964
    if (env->sdr1 != value) {
1965 1966 1967
        /* XXX: for PowerPC 64, should check that the HTABSIZE value
         *      is <= 28
         */
1968
        env->sdr1 = value;
1969
        tlb_flush(env, 1);
1970 1971 1972
    }
}

B
blueswir1 已提交
1973 1974 1975 1976 1977 1978 1979 1980
#if defined(TARGET_PPC64)
target_ulong ppc_load_sr (CPUPPCState *env, int slb_nr)
{
    // XXX
    return 0;
}
#endif

A
aurel32 已提交
1981
void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value)
1982
{
1983 1984
    LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
            srnum, value, env->sr[srnum]);
B
blueswir1 已提交
1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
#if defined(TARGET_PPC64)
    if (env->mmu_model & POWERPC_MMU_64) {
        uint64_t rb = 0, rs = 0;

        /* ESID = srnum */
        rb |= ((uint32_t)srnum & 0xf) << 28;
        /* Set the valid bit */
        rb |= 1 << 27;
        /* Index = ESID */
        rb |= (uint32_t)srnum;

        /* VSID = VSID */
        rs |= (value & 0xfffffff) << 12;
        /* flags = flags */
        rs |= ((value >> 27) & 0xf) << 9;

        ppc_store_slb(env, rb, rs);
    } else
#endif
2004 2005
    if (env->sr[srnum] != value) {
        env->sr[srnum] = value;
2006 2007
/* Invalidating 256MB of virtual memory in 4kB pages is way longer than
   flusing the whole TLB. */
2008 2009 2010 2011 2012 2013 2014 2015 2016 2017
#if !defined(FLUSH_ALL_TLBS) && 0
        {
            target_ulong page, end;
            /* Invalidate 256 MB of virtual memory */
            page = (16 << 20) * srnum;
            end = page + (16 << 20);
            for (; page != end; page += TARGET_PAGE_SIZE)
                tlb_flush_page(env, page);
        }
#else
2018
        tlb_flush(env, 1);
2019 2020 2021
#endif
    }
}
2022
#endif /* !defined (CONFIG_USER_ONLY) */
2023

2024
/* GDBstub can read and write MSR... */
2025
void ppc_store_msr (CPUPPCState *env, target_ulong value)
2026
{
2027
    hreg_store_msr(env, value, 0);
2028 2029 2030 2031
}

/*****************************************************************************/
/* Exception processing */
2032
#if defined (CONFIG_USER_ONLY)
2033
void do_interrupt (CPUState *env)
B
bellard 已提交
2034
{
2035 2036
    env->exception_index = POWERPC_EXCP_NONE;
    env->error_code = 0;
2037
}
2038

2039
void ppc_hw_interrupt (CPUState *env)
2040
{
2041 2042
    env->exception_index = POWERPC_EXCP_NONE;
    env->error_code = 0;
2043
}
2044
#else /* defined (CONFIG_USER_ONLY) */
B
Blue Swirl 已提交
2045
static inline void dump_syscall(CPUState *env)
2046
{
B
Blue Swirl 已提交
2047 2048 2049
    qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
                  " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
                  " nip=" TARGET_FMT_lx "\n",
2050 2051 2052
                  ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
                  ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
                  ppc_dump_gpr(env, 6), env->nip);
2053 2054
}

2055 2056 2057
/* Note that this function should be greatly optimized
 * when called with a constant excp, from ppc_hw_interrupt
 */
B
Blue Swirl 已提交
2058
static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
2059
{
2060
    target_ulong msr, new_msr, vector;
2061
    int srr0, srr1, asrr0, asrr1;
2062
    int lpes0, lpes1, lev;
B
bellard 已提交
2063

2064 2065 2066 2067 2068 2069 2070 2071 2072 2073
    if (0) {
        /* XXX: find a suitable condition to enable the hypervisor mode */
        lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
        lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
    } else {
        /* Those values ensure we won't enter the hypervisor mode */
        lpes0 = 0;
        lpes1 = 1;
    }

2074 2075
    qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
                  " => %08x (%02x)\n", env->nip, excp, env->error_code);
2076 2077 2078 2079 2080 2081 2082 2083

    /* new srr1 value excluding must-be-zero bits */
    msr = env->msr & ~0x783f0000ULL;

    /* new interrupt handler msr */
    new_msr = env->msr & ((target_ulong)1 << MSR_ME);

    /* target registers */
2084 2085 2086 2087
    srr0 = SPR_SRR0;
    srr1 = SPR_SRR1;
    asrr0 = -1;
    asrr1 = -1;
2088

2089
    switch (excp) {
2090 2091 2092 2093 2094
    case POWERPC_EXCP_NONE:
        /* Should never happen */
        return;
    case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
        switch (excp_model) {
2095
        case POWERPC_EXCP_40x:
2096 2097
            srr0 = SPR_40x_SRR2;
            srr1 = SPR_40x_SRR3;
2098
            break;
2099
        case POWERPC_EXCP_BOOKE:
2100 2101
            srr0 = SPR_BOOKE_CSRR0;
            srr1 = SPR_BOOKE_CSRR1;
2102
            break;
2103
        case POWERPC_EXCP_G2:
2104
            break;
2105 2106
        default:
            goto excp_invalid;
2107
        }
2108
        goto store_next;
2109 2110
    case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
        if (msr_me == 0) {
2111 2112 2113
            /* Machine check exception is not enabled.
             * Enter checkstop state.
             */
2114 2115
            if (qemu_log_enabled()) {
                qemu_log("Machine check while not allowed. "
2116 2117 2118 2119 2120 2121 2122
                        "Entering checkstop state\n");
            } else {
                fprintf(stderr, "Machine check while not allowed. "
                        "Entering checkstop state\n");
            }
            env->halted = 1;
            env->interrupt_request |= CPU_INTERRUPT_EXITTB;
2123
        }
2124 2125
        if (0) {
            /* XXX: find a suitable condition to enable the hypervisor mode */
2126
            new_msr |= (target_ulong)MSR_HVB;
2127
        }
2128 2129 2130 2131

        /* machine check exceptions don't have ME set */
        new_msr &= ~((target_ulong)1 << MSR_ME);

2132 2133
        /* XXX: should also have something loaded in DAR / DSISR */
        switch (excp_model) {
2134
        case POWERPC_EXCP_40x:
2135 2136
            srr0 = SPR_40x_SRR2;
            srr1 = SPR_40x_SRR3;
2137
            break;
2138
        case POWERPC_EXCP_BOOKE:
2139 2140 2141 2142
            srr0 = SPR_BOOKE_MCSRR0;
            srr1 = SPR_BOOKE_MCSRR1;
            asrr0 = SPR_BOOKE_CSRR0;
            asrr1 = SPR_BOOKE_CSRR1;
2143 2144 2145
            break;
        default:
            break;
2146
        }
2147 2148
        goto store_next;
    case POWERPC_EXCP_DSI:       /* Data storage exception                   */
2149 2150
        LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
                 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
2151
        if (lpes1 == 0)
2152
            new_msr |= (target_ulong)MSR_HVB;
2153
        goto store_next;
2154
    case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
2155 2156
        LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
                 "\n", msr, env->nip);
2157
        if (lpes1 == 0)
2158
            new_msr |= (target_ulong)MSR_HVB;
2159
        msr |= env->error_code;
2160
        goto store_next;
2161 2162
    case POWERPC_EXCP_EXTERNAL:  /* External input                           */
        if (lpes0 == 1)
2163
            new_msr |= (target_ulong)MSR_HVB;
2164
        goto store_next;
2165 2166
    case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
        if (lpes1 == 0)
2167
            new_msr |= (target_ulong)MSR_HVB;
2168 2169 2170
        /* XXX: this is false */
        /* Get rS/rD and rA from faulting opcode */
        env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
2171
        goto store_current;
2172
    case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
2173
        switch (env->error_code & ~0xF) {
2174 2175
        case POWERPC_EXCP_FP:
            if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
2176
                LOG_EXCP("Ignore floating point exception\n");
2177 2178
                env->exception_index = POWERPC_EXCP_NONE;
                env->error_code = 0;
2179
                return;
2180
            }
2181
            if (lpes1 == 0)
2182
                new_msr |= (target_ulong)MSR_HVB;
2183
            msr |= 0x00100000;
2184 2185 2186
            if (msr_fe0 == msr_fe1)
                goto store_next;
            msr |= 0x00010000;
2187
            break;
2188
        case POWERPC_EXCP_INVAL:
2189
            LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
2190
            if (lpes1 == 0)
2191
                new_msr |= (target_ulong)MSR_HVB;
2192
            msr |= 0x00080000;
2193
            break;
2194 2195
        case POWERPC_EXCP_PRIV:
            if (lpes1 == 0)
2196
                new_msr |= (target_ulong)MSR_HVB;
2197
            msr |= 0x00040000;
2198
            break;
2199 2200
        case POWERPC_EXCP_TRAP:
            if (lpes1 == 0)
2201
                new_msr |= (target_ulong)MSR_HVB;
2202 2203 2204 2205
            msr |= 0x00020000;
            break;
        default:
            /* Should never occur */
2206 2207
            cpu_abort(env, "Invalid program exception %d. Aborting\n",
                      env->error_code);
2208 2209
            break;
        }
2210
        goto store_current;
2211 2212
    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
        if (lpes1 == 0)
2213
            new_msr |= (target_ulong)MSR_HVB;
2214 2215
        goto store_current;
    case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
2216 2217
        /* NOTE: this is a temporary hack to support graphics OSI
           calls from the MOL driver */
2218
        /* XXX: To be removed */
2219 2220
        if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
            env->osi_call) {
2221 2222 2223
            if (env->osi_call(env) != 0) {
                env->exception_index = POWERPC_EXCP_NONE;
                env->error_code = 0;
2224
                return;
2225
            }
2226
        }
2227
        dump_syscall(env);
2228
        lev = env->error_code;
2229
        if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
2230
            new_msr |= (target_ulong)MSR_HVB;
2231 2232 2233 2234 2235
        goto store_next;
    case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
        goto store_current;
    case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
        if (lpes1 == 0)
2236
            new_msr |= (target_ulong)MSR_HVB;
2237 2238 2239
        goto store_next;
    case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
        /* FIT on 4xx */
2240
        LOG_EXCP("FIT exception\n");
2241
        goto store_next;
2242
    case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
2243
        LOG_EXCP("WDT exception\n");
2244 2245 2246 2247 2248 2249 2250 2251
        switch (excp_model) {
        case POWERPC_EXCP_BOOKE:
            srr0 = SPR_BOOKE_CSRR0;
            srr1 = SPR_BOOKE_CSRR1;
            break;
        default:
            break;
        }
2252
        goto store_next;
2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267
    case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
        goto store_next;
    case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
        goto store_next;
    case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
        switch (excp_model) {
        case POWERPC_EXCP_BOOKE:
            srr0 = SPR_BOOKE_DSRR0;
            srr1 = SPR_BOOKE_DSRR1;
            asrr0 = SPR_BOOKE_CSRR0;
            asrr1 = SPR_BOOKE_CSRR1;
            break;
        default:
            break;
        }
2268
        /* XXX: TODO */
2269
        cpu_abort(env, "Debug exception is not implemented yet !\n");
2270
        goto store_next;
2271 2272 2273
    case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
        goto store_current;
    case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
2274
        /* XXX: TODO */
2275
        cpu_abort(env, "Embedded floating point data exception "
2276 2277
                  "is not implemented yet !\n");
        goto store_next;
2278
    case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
2279
        /* XXX: TODO */
2280 2281
        cpu_abort(env, "Embedded floating point round exception "
                  "is not implemented yet !\n");
2282
        goto store_next;
2283
    case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
2284 2285
        /* XXX: TODO */
        cpu_abort(env,
2286
                  "Performance counter exception is not implemented yet !\n");
2287
        goto store_next;
2288
    case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
2289
        /* XXX: TODO */
2290 2291
        cpu_abort(env,
                  "Embedded doorbell interrupt is not implemented yet !\n");
2292
        goto store_next;
2293 2294 2295 2296 2297
    case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
        switch (excp_model) {
        case POWERPC_EXCP_BOOKE:
            srr0 = SPR_BOOKE_CSRR0;
            srr1 = SPR_BOOKE_CSRR1;
2298
            break;
2299 2300 2301
        default:
            break;
        }
2302 2303 2304 2305 2306
        /* XXX: TODO */
        cpu_abort(env, "Embedded doorbell critical interrupt "
                  "is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_RESET:     /* System reset exception                   */
2307 2308 2309 2310 2311 2312 2313
        if (msr_pow) {
            /* indicate that we resumed from power save mode */
            msr |= 0x10000;
        } else {
            new_msr &= ~((target_ulong)1 << MSR_ME);
        }

2314 2315 2316 2317
        if (0) {
            /* XXX: find a suitable condition to enable the hypervisor mode */
            new_msr |= (target_ulong)MSR_HVB;
        }
2318 2319 2320
        goto store_next;
    case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
        if (lpes1 == 0)
2321
            new_msr |= (target_ulong)MSR_HVB;
2322 2323 2324
        goto store_next;
    case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
        if (lpes1 == 0)
2325
            new_msr |= (target_ulong)MSR_HVB;
2326 2327 2328
        goto store_next;
    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
        srr0 = SPR_HSRR0;
2329
        srr1 = SPR_HSRR1;
2330
        new_msr |= (target_ulong)MSR_HVB;
2331
        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2332
        goto store_next;
2333 2334
    case POWERPC_EXCP_TRACE:     /* Trace exception                          */
        if (lpes1 == 0)
2335
            new_msr |= (target_ulong)MSR_HVB;
2336 2337 2338
        goto store_next;
    case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
        srr0 = SPR_HSRR0;
2339
        srr1 = SPR_HSRR1;
2340
        new_msr |= (target_ulong)MSR_HVB;
2341
        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2342 2343 2344
        goto store_next;
    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
        srr0 = SPR_HSRR0;
2345
        srr1 = SPR_HSRR1;
2346
        new_msr |= (target_ulong)MSR_HVB;
2347
        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2348 2349 2350
        goto store_next;
    case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
        srr0 = SPR_HSRR0;
2351
        srr1 = SPR_HSRR1;
2352
        new_msr |= (target_ulong)MSR_HVB;
2353
        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2354 2355 2356
        goto store_next;
    case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
        srr0 = SPR_HSRR0;
2357
        srr1 = SPR_HSRR1;
2358
        new_msr |= (target_ulong)MSR_HVB;
2359
        new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
2360 2361 2362
        goto store_next;
    case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
        if (lpes1 == 0)
2363
            new_msr |= (target_ulong)MSR_HVB;
2364 2365
        goto store_current;
    case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
2366
        LOG_EXCP("PIT exception\n");
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381
        goto store_next;
    case POWERPC_EXCP_IO:        /* IO error exception                       */
        /* XXX: TODO */
        cpu_abort(env, "601 IO error exception is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
        /* XXX: TODO */
        cpu_abort(env, "601 run mode exception is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
        /* XXX: TODO */
        cpu_abort(env, "602 emulation trap exception "
                  "is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
2382 2383
        if (lpes1 == 0) /* XXX: check this */
            new_msr |= (target_ulong)MSR_HVB;
2384
        switch (excp_model) {
2385 2386 2387 2388
        case POWERPC_EXCP_602:
        case POWERPC_EXCP_603:
        case POWERPC_EXCP_603E:
        case POWERPC_EXCP_G2:
2389
            goto tlb_miss_tgpr;
2390
        case POWERPC_EXCP_7x5:
2391
            goto tlb_miss;
2392 2393
        case POWERPC_EXCP_74xx:
            goto tlb_miss_74xx;
2394
        default:
2395
            cpu_abort(env, "Invalid instruction TLB miss exception\n");
2396 2397
            break;
        }
2398 2399
        break;
    case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
2400 2401
        if (lpes1 == 0) /* XXX: check this */
            new_msr |= (target_ulong)MSR_HVB;
2402
        switch (excp_model) {
2403 2404 2405 2406
        case POWERPC_EXCP_602:
        case POWERPC_EXCP_603:
        case POWERPC_EXCP_603E:
        case POWERPC_EXCP_G2:
2407
            goto tlb_miss_tgpr;
2408
        case POWERPC_EXCP_7x5:
2409
            goto tlb_miss;
2410 2411
        case POWERPC_EXCP_74xx:
            goto tlb_miss_74xx;
2412
        default:
2413
            cpu_abort(env, "Invalid data load TLB miss exception\n");
2414 2415
            break;
        }
2416 2417
        break;
    case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
2418 2419
        if (lpes1 == 0) /* XXX: check this */
            new_msr |= (target_ulong)MSR_HVB;
2420
        switch (excp_model) {
2421 2422 2423 2424
        case POWERPC_EXCP_602:
        case POWERPC_EXCP_603:
        case POWERPC_EXCP_603E:
        case POWERPC_EXCP_G2:
2425
        tlb_miss_tgpr:
2426
            /* Swap temporary saved registers with GPRs */
2427 2428 2429 2430
            if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
                new_msr |= (target_ulong)1 << MSR_TGPR;
                hreg_swap_gpr_tgpr(env);
            }
2431 2432 2433
            goto tlb_miss;
        case POWERPC_EXCP_7x5:
        tlb_miss:
2434
#if defined (DEBUG_SOFTWARE_TLB)
2435
            if (qemu_log_enabled()) {
2436
                const char *es;
2437 2438
                target_ulong *miss, *cmp;
                int en;
J
j_mayer 已提交
2439
                if (excp == POWERPC_EXCP_IFTLB) {
2440 2441 2442 2443 2444
                    es = "I";
                    en = 'I';
                    miss = &env->spr[SPR_IMISS];
                    cmp = &env->spr[SPR_ICMP];
                } else {
J
j_mayer 已提交
2445
                    if (excp == POWERPC_EXCP_DLTLB)
2446 2447 2448 2449 2450 2451 2452
                        es = "DL";
                    else
                        es = "DS";
                    en = 'D';
                    miss = &env->spr[SPR_DMISS];
                    cmp = &env->spr[SPR_DCMP];
                }
2453 2454 2455 2456 2457
                qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
                         TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
                         env->spr[SPR_HASH1], env->spr[SPR_HASH2],
                         env->error_code);
2458
            }
2459
#endif
2460 2461 2462
            msr |= env->crf[0] << 28;
            msr |= env->error_code; /* key, D/I, S/L bits */
            /* Set way using a LRU mechanism */
2463
            msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
2464
            break;
2465 2466 2467
        case POWERPC_EXCP_74xx:
        tlb_miss_74xx:
#if defined (DEBUG_SOFTWARE_TLB)
2468
            if (qemu_log_enabled()) {
2469
                const char *es;
2470 2471 2472 2473 2474
                target_ulong *miss, *cmp;
                int en;
                if (excp == POWERPC_EXCP_IFTLB) {
                    es = "I";
                    en = 'I';
2475 2476
                    miss = &env->spr[SPR_TLBMISS];
                    cmp = &env->spr[SPR_PTEHI];
2477 2478 2479 2480 2481 2482 2483 2484 2485
                } else {
                    if (excp == POWERPC_EXCP_DLTLB)
                        es = "DL";
                    else
                        es = "DS";
                    en = 'D';
                    miss = &env->spr[SPR_TLBMISS];
                    cmp = &env->spr[SPR_PTEHI];
                }
2486 2487 2488
                qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
                         env->error_code);
2489 2490 2491 2492
            }
#endif
            msr |= env->error_code; /* key bit */
            break;
2493
        default:
2494
            cpu_abort(env, "Invalid data store TLB miss exception\n");
2495 2496
            break;
        }
2497 2498 2499 2500 2501 2502
        goto store_next;
    case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
        /* XXX: TODO */
        cpu_abort(env, "Floating point assist exception "
                  "is not implemented yet !\n");
        goto store_next;
2503 2504 2505 2506
    case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
        /* XXX: TODO */
        cpu_abort(env, "DABR exception is not implemented yet !\n");
        goto store_next;
2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521
    case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
        /* XXX: TODO */
        cpu_abort(env, "IABR exception is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_SMI:       /* System management interrupt              */
        /* XXX: TODO */
        cpu_abort(env, "SMI exception is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
        /* XXX: TODO */
        cpu_abort(env, "Thermal management exception "
                  "is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
        if (lpes1 == 0)
2522
            new_msr |= (target_ulong)MSR_HVB;
2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540
        /* XXX: TODO */
        cpu_abort(env,
                  "Performance counter exception is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
        /* XXX: TODO */
        cpu_abort(env, "VPU assist exception is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
        /* XXX: TODO */
        cpu_abort(env,
                  "970 soft-patch exception is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
        /* XXX: TODO */
        cpu_abort(env,
                  "970 maintenance exception is not implemented yet !\n");
        goto store_next;
2541 2542 2543 2544 2545 2546 2547 2548 2549 2550
    case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
        /* XXX: TODO */
        cpu_abort(env, "Maskable external exception "
                  "is not implemented yet !\n");
        goto store_next;
    case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
        /* XXX: TODO */
        cpu_abort(env, "Non maskable external exception "
                  "is not implemented yet !\n");
        goto store_next;
2551
    default:
2552 2553 2554
    excp_invalid:
        cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
        break;
2555
    store_current:
2556
        /* save current instruction location */
2557
        env->spr[srr0] = env->nip - 4;
2558 2559
        break;
    store_next:
2560
        /* save next instruction location */
2561
        env->spr[srr0] = env->nip;
2562 2563
        break;
    }
2564 2565 2566 2567 2568 2569 2570
    /* Save MSR */
    env->spr[srr1] = msr;
    /* If any alternate SRR register are defined, duplicate saved values */
    if (asrr0 != -1)
        env->spr[asrr0] = env->spr[srr0];
    if (asrr1 != -1)
        env->spr[asrr1] = env->spr[srr1];
2571
    /* If we disactivated any translation, flush TLBs */
2572
    if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR)))
2573
        tlb_flush(env, 1);
2574 2575

    if (msr_ile) {
2576
        new_msr |= (target_ulong)1 << MSR_LE;
2577 2578
    }

2579 2580
    /* Jump to handler */
    vector = env->excp_vectors[excp];
2581
    if (vector == (target_ulong)-1ULL) {
2582 2583 2584 2585
        cpu_abort(env, "Raised an exception without defined vector %d\n",
                  excp);
    }
    vector |= env->excp_prefix;
2586
#if defined(TARGET_PPC64)
2587
    if (excp_model == POWERPC_EXCP_BOOKE) {
2588
        if (!msr_icm) {
2589
            vector = (uint32_t)vector;
2590 2591 2592
        } else {
            new_msr |= (target_ulong)1 << MSR_CM;
        }
2593
    } else {
B
blueswir1 已提交
2594
        if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
2595
            vector = (uint32_t)vector;
2596 2597 2598
        } else {
            new_msr |= (target_ulong)1 << MSR_SF;
        }
2599
    }
2600
#endif
2601 2602 2603
    /* XXX: we don't use hreg_store_msr here as already have treated
     *      any special case that could occur. Just store MSR and update hflags
     */
2604
    env->msr = new_msr & env->msr_mask;
2605
    hreg_compute_hflags(env);
2606 2607 2608 2609
    env->nip = vector;
    /* Reset exception state */
    env->exception_index = POWERPC_EXCP_NONE;
    env->error_code = 0;
B
bellard 已提交
2610
}
2611

2612
void do_interrupt (CPUState *env)
2613
{
2614 2615
    powerpc_excp(env, env->excp_model, env->exception_index);
}
2616

2617 2618
void ppc_hw_interrupt (CPUPPCState *env)
{
2619 2620
    int hdice;

2621
#if 0
2622
    qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
2623
                __func__, env, env->pending_interrupts,
2624
                env->interrupt_request, (int)msr_me, (int)msr_ee);
2625
#endif
2626
    /* External reset */
2627 2628
    if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
2629 2630 2631 2632 2633 2634 2635 2636
        powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
        return;
    }
    /* Machine check exception */
    if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
        powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
        return;
2637
    }
2638 2639 2640 2641 2642 2643 2644 2645
#if 0 /* TODO */
    /* External debug exception */
    if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
        powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
        return;
    }
#endif
2646 2647 2648 2649 2650 2651
    if (0) {
        /* XXX: find a suitable condition to enable the hypervisor mode */
        hdice = env->spr[SPR_LPCR] & 1;
    } else {
        hdice = 0;
    }
2652
    if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
2653 2654 2655
        /* Hypervisor decrementer exception */
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
            return;
        }
    }
    if (msr_ce != 0) {
        /* External critical interrupt */
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
            /* Taking a critical external interrupt does not clear the external
             * critical interrupt status
             */
#if 0
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
2668
#endif
2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
            return;
        }
    }
    if (msr_ee != 0) {
        /* Watchdog timer on embedded PowerPC */
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
            return;
        }
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
            return;
        }
        /* Fixed interval timer on embedded PowerPC */
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
            return;
        }
        /* Programmable interval timer on embedded PowerPC */
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
            return;
        }
2697 2698 2699
        /* Decrementer exception */
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
2700 2701 2702
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
            return;
        }
2703
        /* External interrupt */
2704
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
2705 2706 2707 2708
            /* Taking an external interrupt does not clear the external
             * interrupt status
             */
#if 0
2709
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
2710
#endif
2711 2712 2713 2714 2715 2716 2717
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
            return;
        }
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
            return;
2718
        }
2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
            return;
        }
        /* Thermal interrupt */
        if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
            powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
            return;
        }
2730 2731
    }
}
2732
#endif /* !CONFIG_USER_ONLY */
2733

J
j_mayer 已提交
2734 2735
void cpu_dump_rfi (target_ulong RA, target_ulong msr)
{
2736 2737
    qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
             TARGET_FMT_lx "\n", RA, msr);
2738 2739
}

2740
void cpu_reset(CPUPPCState *env)
J
j_mayer 已提交
2741
{
2742
    target_ulong msr;
J
j_mayer 已提交
2743

A
aliguori 已提交
2744 2745 2746 2747 2748
    if (qemu_loglevel_mask(CPU_LOG_RESET)) {
        qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
        log_cpu_state(env, 0);
    }

2749
    msr = (target_ulong)0;
2750 2751 2752 2753
    if (0) {
        /* XXX: find a suitable condition to enable the hypervisor mode */
        msr |= (target_ulong)MSR_HVB;
    }
2754 2755 2756
    msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
    msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
    msr |= (target_ulong)1 << MSR_EP;
J
j_mayer 已提交
2757 2758
#if defined (DO_SINGLE_STEP) && 0
    /* Single step trace mode */
2759 2760
    msr |= (target_ulong)1 << MSR_SE;
    msr |= (target_ulong)1 << MSR_BE;
J
j_mayer 已提交
2761 2762
#endif
#if defined(CONFIG_USER_ONLY)
2763
    msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
2764 2765
    msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
    msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
2766
    msr |= (target_ulong)1 << MSR_PR;
2767
#else
B
Blue Swirl 已提交
2768
    env->excp_prefix = env->hreset_excp_prefix;
2769
    env->nip = env->hreset_vector | env->excp_prefix;
2770
    if (env->mmu_model != POWERPC_MMU_REAL)
2771
        ppc_tlb_invalidate_all(env);
J
j_mayer 已提交
2772
#endif
B
blueswir1 已提交
2773
    env->msr = msr & env->msr_mask;
B
blueswir1 已提交
2774 2775 2776 2777
#if defined(TARGET_PPC64)
    if (env->mmu_model & POWERPC_MMU_64)
        env->msr |= (1ULL << MSR_SF);
#endif
2778
    hreg_compute_hflags(env);
2779
    env->reserve_addr = (target_ulong)-1ULL;
2780 2781
    /* Be sure no exception or interrupt is pending */
    env->pending_interrupts = 0;
2782 2783
    env->exception_index = POWERPC_EXCP_NONE;
    env->error_code = 0;
2784 2785
    /* Flush all TLBs */
    tlb_flush(env, 1);
J
j_mayer 已提交
2786 2787
}

B
bellard 已提交
2788
CPUPPCState *cpu_ppc_init (const char *cpu_model)
J
j_mayer 已提交
2789 2790
{
    CPUPPCState *env;
A
Anthony Liguori 已提交
2791
    const ppc_def_t *def;
B
bellard 已提交
2792 2793 2794 2795

    def = cpu_ppc_find_by_name(cpu_model);
    if (!def)
        return NULL;
J
j_mayer 已提交
2796 2797 2798

    env = qemu_mallocz(sizeof(CPUPPCState));
    cpu_exec_init(env);
P
pbrook 已提交
2799
    ppc_translate_init();
2800
    env->cpu_model_str = cpu_model;
B
bellard 已提交
2801
    cpu_ppc_register_internal(env, def);
A
aurel32 已提交
2802

2803
    qemu_init_vcpu(env);
A
aurel32 已提交
2804

J
j_mayer 已提交
2805 2806 2807 2808 2809 2810
    return env;
}

void cpu_ppc_close (CPUPPCState *env)
{
    /* Should also remove all opcode tables... */
B
bellard 已提交
2811
    qemu_free(env);
J
j_mayer 已提交
2812
}