qemu/target/ppc/mmu-hash32.c
<<
>>
Prefs
   1/*
   2 *  PowerPC MMU, TLB and BAT emulation helpers for QEMU.
   3 *
   4 *  Copyright (c) 2003-2007 Jocelyn Mayer
   5 *  Copyright (c) 2013 David Gibson, IBM Corporation
   6 *
   7 * This library is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU Lesser General Public
   9 * License as published by the Free Software Foundation; either
  10 * version 2.1 of the License, or (at your option) any later version.
  11 *
  12 * This library is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * Lesser General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU Lesser General Public
  18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "cpu.h"
  23#include "exec/exec-all.h"
  24#include "sysemu/kvm.h"
  25#include "kvm_ppc.h"
  26#include "internal.h"
  27#include "mmu-hash32.h"
  28#include "mmu-books.h"
  29#include "exec/log.h"
  30
  31/* #define DEBUG_BATS */
  32
  33#ifdef DEBUG_BATS
  34#  define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
  35#else
  36#  define LOG_BATS(...) do { } while (0)
  37#endif
  38
  39struct mmu_ctx_hash32 {
  40    hwaddr raddr;      /* Real address              */
  41    int prot;                      /* Protection bits           */
  42    int key;                       /* Access key                */
  43};
  44
  45static int ppc_hash32_pp_prot(int key, int pp, int nx)
  46{
  47    int prot;
  48
  49    if (key == 0) {
  50        switch (pp) {
  51        case 0x0:
  52        case 0x1:
  53        case 0x2:
  54            prot = PAGE_READ | PAGE_WRITE;
  55            break;
  56
  57        case 0x3:
  58            prot = PAGE_READ;
  59            break;
  60
  61        default:
  62            abort();
  63        }
  64    } else {
  65        switch (pp) {
  66        case 0x0:
  67            prot = 0;
  68            break;
  69
  70        case 0x1:
  71        case 0x3:
  72            prot = PAGE_READ;
  73            break;
  74
  75        case 0x2:
  76            prot = PAGE_READ | PAGE_WRITE;
  77            break;
  78
  79        default:
  80            abort();
  81        }
  82    }
  83    if (nx == 0) {
  84        prot |= PAGE_EXEC;
  85    }
  86
  87    return prot;
  88}
  89
  90static int ppc_hash32_pte_prot(int mmu_idx,
  91                               target_ulong sr, ppc_hash_pte32_t pte)
  92{
  93    unsigned pp, key;
  94
  95    key = !!(mmuidx_pr(mmu_idx) ? (sr & SR32_KP) : (sr & SR32_KS));
  96    pp = pte.pte1 & HPTE32_R_PP;
  97
  98    return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX));
  99}
 100
 101static target_ulong hash32_bat_size(int mmu_idx,
 102                                    target_ulong batu, target_ulong batl)
 103{
 104    if ((mmuidx_pr(mmu_idx) && !(batu & BATU32_VP))
 105        || (!mmuidx_pr(mmu_idx) && !(batu & BATU32_VS))) {
 106        return 0;
 107    }
 108
 109    return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
 110}
 111
 112static int hash32_bat_prot(PowerPCCPU *cpu,
 113                           target_ulong batu, target_ulong batl)
 114{
 115    int pp, prot;
 116
 117    prot = 0;
 118    pp = batl & BATL32_PP;
 119    if (pp != 0) {
 120        prot = PAGE_READ | PAGE_EXEC;
 121        if (pp == 0x2) {
 122            prot |= PAGE_WRITE;
 123        }
 124    }
 125    return prot;
 126}
 127
 128static target_ulong hash32_bat_601_size(PowerPCCPU *cpu,
 129                                target_ulong batu, target_ulong batl)
 130{
 131    if (!(batl & BATL32_601_V)) {
 132        return 0;
 133    }
 134
 135    return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17);
 136}
 137
 138static int hash32_bat_601_prot(int mmu_idx,
 139                               target_ulong batu, target_ulong batl)
 140{
 141    int key, pp;
 142
 143    pp = batu & BATU32_601_PP;
 144    if (mmuidx_pr(mmu_idx) == 0) {
 145        key = !!(batu & BATU32_601_KS);
 146    } else {
 147        key = !!(batu & BATU32_601_KP);
 148    }
 149    return ppc_hash32_pp_prot(key, pp, 0);
 150}
 151
 152static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
 153                                    MMUAccessType access_type, int *prot,
 154                                    int mmu_idx)
 155{
 156    CPUPPCState *env = &cpu->env;
 157    target_ulong *BATlt, *BATut;
 158    bool ifetch = access_type == MMU_INST_FETCH;
 159    int i;
 160
 161    LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
 162             ifetch ? 'I' : 'D', ea);
 163    if (ifetch) {
 164        BATlt = env->IBAT[1];
 165        BATut = env->IBAT[0];
 166    } else {
 167        BATlt = env->DBAT[1];
 168        BATut = env->DBAT[0];
 169    }
 170    for (i = 0; i < env->nb_BATs; i++) {
 171        target_ulong batu = BATut[i];
 172        target_ulong batl = BATlt[i];
 173        target_ulong mask;
 174
 175        if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
 176            mask = hash32_bat_601_size(cpu, batu, batl);
 177        } else {
 178            mask = hash32_bat_size(mmu_idx, batu, batl);
 179        }
 180        LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
 181                 " BATl " TARGET_FMT_lx "\n", __func__,
 182                 ifetch ? 'I' : 'D', i, ea, batu, batl);
 183
 184        if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
 185            hwaddr raddr = (batl & mask) | (ea & ~mask);
 186
 187            if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
 188                *prot = hash32_bat_601_prot(mmu_idx, batu, batl);
 189            } else {
 190                *prot = hash32_bat_prot(cpu, batu, batl);
 191            }
 192
 193            return raddr & TARGET_PAGE_MASK;
 194        }
 195    }
 196
 197    /* No hit */
 198#if defined(DEBUG_BATS)
 199    if (qemu_log_enabled()) {
 200        target_ulong *BATu, *BATl;
 201        target_ulong BEPIl, BEPIu, bl;
 202
 203        LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
 204        for (i = 0; i < 4; i++) {
 205            BATu = &BATut[i];
 206            BATl = &BATlt[i];
 207            BEPIu = *BATu & BATU32_BEPIU;
 208            BEPIl = *BATu & BATU32_BEPIL;
 209            bl = (*BATu & 0x00001FFC) << 15;
 210            LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
 211                     " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
 212                     TARGET_FMT_lx " " TARGET_FMT_lx "\n",
 213                     __func__, ifetch ? 'I' : 'D', i, ea,
 214                     *BATu, *BATl, BEPIu, BEPIl, bl);
 215        }
 216    }
 217#endif
 218
 219    return -1;
 220}
 221
 222static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
 223                                    target_ulong eaddr,
 224                                    MMUAccessType access_type,
 225                                    hwaddr *raddr, int *prot, int mmu_idx,
 226                                    bool guest_visible)
 227{
 228    CPUState *cs = CPU(cpu);
 229    CPUPPCState *env = &cpu->env;
 230    int key = !!(mmuidx_pr(mmu_idx) ? (sr & SR32_KP) : (sr & SR32_KS));
 231
 232    qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
 233
 234    if ((sr & 0x1FF00000) >> 20 == 0x07f) {
 235        /*
 236         * Memory-forced I/O controller interface access
 237         *
 238         * If T=1 and BUID=x'07F', the 601 performs a memory access
 239         * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
 240         */
 241        *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
 242        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 243        return true;
 244    }
 245
 246    if (access_type == MMU_INST_FETCH) {
 247        /* No code fetch is allowed in direct-store areas */
 248        if (guest_visible) {
 249            cs->exception_index = POWERPC_EXCP_ISI;
 250            env->error_code = 0x10000000;
 251        }
 252        return false;
 253    }
 254
 255    /*
 256     * From ppc_cpu_get_phys_page_debug, env->access_type is not set.
 257     * Assume ACCESS_INT for that case.
 258     */
 259    switch (guest_visible ? env->access_type : ACCESS_INT) {
 260    case ACCESS_INT:
 261        /* Integer load/store : only access allowed */
 262        break;
 263    case ACCESS_FLOAT:
 264        /* Floating point load/store */
 265        cs->exception_index = POWERPC_EXCP_ALIGN;
 266        env->error_code = POWERPC_EXCP_ALIGN_FP;
 267        env->spr[SPR_DAR] = eaddr;
 268        return false;
 269    case ACCESS_RES:
 270        /* lwarx, ldarx or srwcx. */
 271        env->error_code = 0;
 272        env->spr[SPR_DAR] = eaddr;
 273        if (access_type == MMU_DATA_STORE) {
 274            env->spr[SPR_DSISR] = 0x06000000;
 275        } else {
 276            env->spr[SPR_DSISR] = 0x04000000;
 277        }
 278        return false;
 279    case ACCESS_CACHE:
 280        /*
 281         * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
 282         *
 283         * Should make the instruction do no-op.  As it already do
 284         * no-op, it's quite easy :-)
 285         */
 286        *raddr = eaddr;
 287        return true;
 288    case ACCESS_EXT:
 289        /* eciwx or ecowx */
 290        cs->exception_index = POWERPC_EXCP_DSI;
 291        env->error_code = 0;
 292        env->spr[SPR_DAR] = eaddr;
 293        if (access_type == MMU_DATA_STORE) {
 294            env->spr[SPR_DSISR] = 0x06100000;
 295        } else {
 296            env->spr[SPR_DSISR] = 0x04100000;
 297        }
 298        return false;
 299    default:
 300        cpu_abort(cs, "ERROR: insn should not need address translation\n");
 301    }
 302
 303    *prot = key ? PAGE_READ | PAGE_WRITE : PAGE_READ;
 304    if (*prot & prot_for_access_type(access_type)) {
 305        *raddr = eaddr;
 306        return true;
 307    }
 308
 309    if (guest_visible) {
 310        cs->exception_index = POWERPC_EXCP_DSI;
 311        env->error_code = 0;
 312        env->spr[SPR_DAR] = eaddr;
 313        if (access_type == MMU_DATA_STORE) {
 314            env->spr[SPR_DSISR] = 0x0a000000;
 315        } else {
 316            env->spr[SPR_DSISR] = 0x08000000;
 317        }
 318    }
 319    return false;
 320}
 321
 322hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
 323{
 324    target_ulong mask = ppc_hash32_hpt_mask(cpu);
 325
 326    return (hash * HASH_PTEG_SIZE_32) & mask;
 327}
 328
 329static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
 330                                     bool secondary, target_ulong ptem,
 331                                     ppc_hash_pte32_t *pte)
 332{
 333    hwaddr pte_offset = pteg_off;
 334    target_ulong pte0, pte1;
 335    int i;
 336
 337    for (i = 0; i < HPTES_PER_GROUP; i++) {
 338        pte0 = ppc_hash32_load_hpte0(cpu, pte_offset);
 339        /*
 340         * pte0 contains the valid bit and must be read before pte1,
 341         * otherwise we might see an old pte1 with a new valid bit and
 342         * thus an inconsistent hpte value
 343         */
 344        smp_rmb();
 345        pte1 = ppc_hash32_load_hpte1(cpu, pte_offset);
 346
 347        if ((pte0 & HPTE32_V_VALID)
 348            && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
 349            && HPTE32_V_COMPARE(pte0, ptem)) {
 350            pte->pte0 = pte0;
 351            pte->pte1 = pte1;
 352            return pte_offset;
 353        }
 354
 355        pte_offset += HASH_PTE_SIZE_32;
 356    }
 357
 358    return -1;
 359}
 360
 361static void ppc_hash32_set_r(PowerPCCPU *cpu, hwaddr pte_offset, uint32_t pte1)
 362{
 363    target_ulong base = ppc_hash32_hpt_base(cpu);
 364    hwaddr offset = pte_offset + 6;
 365
 366    /* The HW performs a non-atomic byte update */
 367    stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01);
 368}
 369
 370static void ppc_hash32_set_c(PowerPCCPU *cpu, hwaddr pte_offset, uint64_t pte1)
 371{
 372    target_ulong base = ppc_hash32_hpt_base(cpu);
 373    hwaddr offset = pte_offset + 7;
 374
 375    /* The HW performs a non-atomic byte update */
 376    stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
 377}
 378
 379static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
 380                                     target_ulong sr, target_ulong eaddr,
 381                                     ppc_hash_pte32_t *pte)
 382{
 383    hwaddr pteg_off, pte_offset;
 384    hwaddr hash;
 385    uint32_t vsid, pgidx, ptem;
 386
 387    vsid = sr & SR32_VSID;
 388    pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
 389    hash = vsid ^ pgidx;
 390    ptem = (vsid << 7) | (pgidx >> 10);
 391
 392    /* Page address translation */
 393    qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
 394            " htab_mask " TARGET_FMT_plx
 395            " hash " TARGET_FMT_plx "\n",
 396            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
 397
 398    /* Primary PTEG lookup */
 399    qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
 400            " vsid=%" PRIx32 " ptem=%" PRIx32
 401            " hash=" TARGET_FMT_plx "\n",
 402            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
 403            vsid, ptem, hash);
 404    pteg_off = get_pteg_offset32(cpu, hash);
 405    pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
 406    if (pte_offset == -1) {
 407        /* Secondary PTEG lookup */
 408        qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
 409                " vsid=%" PRIx32 " api=%" PRIx32
 410                " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
 411                ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
 412        pteg_off = get_pteg_offset32(cpu, ~hash);
 413        pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
 414    }
 415
 416    return pte_offset;
 417}
 418
 419static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
 420                                   target_ulong eaddr)
 421{
 422    hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
 423    hwaddr mask = ~TARGET_PAGE_MASK;
 424
 425    return (rpn & ~mask) | (eaddr & mask);
 426}
 427
 428bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
 429                      hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
 430                      bool guest_visible)
 431{
 432    CPUState *cs = CPU(cpu);
 433    CPUPPCState *env = &cpu->env;
 434    target_ulong sr;
 435    hwaddr pte_offset;
 436    ppc_hash_pte32_t pte;
 437    int prot;
 438    int need_prot;
 439    hwaddr raddr;
 440
 441    /* There are no hash32 large pages. */
 442    *psizep = TARGET_PAGE_BITS;
 443
 444    /* 1. Handle real mode accesses */
 445    if (mmuidx_real(mmu_idx)) {
 446        /* Translation is off */
 447        *raddrp = eaddr;
 448        *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 449        return true;
 450    }
 451
 452    need_prot = prot_for_access_type(access_type);
 453
 454    /* 2. Check Block Address Translation entries (BATs) */
 455    if (env->nb_BATs != 0) {
 456        raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
 457        if (raddr != -1) {
 458            if (need_prot & ~*protp) {
 459                if (guest_visible) {
 460                    if (access_type == MMU_INST_FETCH) {
 461                        cs->exception_index = POWERPC_EXCP_ISI;
 462                        env->error_code = 0x08000000;
 463                    } else {
 464                        cs->exception_index = POWERPC_EXCP_DSI;
 465                        env->error_code = 0;
 466                        env->spr[SPR_DAR] = eaddr;
 467                        if (access_type == MMU_DATA_STORE) {
 468                            env->spr[SPR_DSISR] = 0x0a000000;
 469                        } else {
 470                            env->spr[SPR_DSISR] = 0x08000000;
 471                        }
 472                    }
 473                }
 474                return false;
 475            }
 476            *raddrp = raddr;
 477            return true;
 478        }
 479    }
 480
 481    /* 3. Look up the Segment Register */
 482    sr = env->sr[eaddr >> 28];
 483
 484    /* 4. Handle direct store segments */
 485    if (sr & SR32_T) {
 486        return ppc_hash32_direct_store(cpu, sr, eaddr, access_type,
 487                                       raddrp, protp, mmu_idx, guest_visible);
 488    }
 489
 490    /* 5. Check for segment level no-execute violation */
 491    if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) {
 492        if (guest_visible) {
 493            cs->exception_index = POWERPC_EXCP_ISI;
 494            env->error_code = 0x10000000;
 495        }
 496        return false;
 497    }
 498
 499    /* 6. Locate the PTE in the hash table */
 500    pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
 501    if (pte_offset == -1) {
 502        if (guest_visible) {
 503            if (access_type == MMU_INST_FETCH) {
 504                cs->exception_index = POWERPC_EXCP_ISI;
 505                env->error_code = 0x40000000;
 506            } else {
 507                cs->exception_index = POWERPC_EXCP_DSI;
 508                env->error_code = 0;
 509                env->spr[SPR_DAR] = eaddr;
 510                if (access_type == MMU_DATA_STORE) {
 511                    env->spr[SPR_DSISR] = 0x42000000;
 512                } else {
 513                    env->spr[SPR_DSISR] = 0x40000000;
 514                }
 515            }
 516        }
 517        return false;
 518    }
 519    qemu_log_mask(CPU_LOG_MMU,
 520                "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
 521
 522    /* 7. Check access permissions */
 523
 524    prot = ppc_hash32_pte_prot(mmu_idx, sr, pte);
 525
 526    if (need_prot & ~prot) {
 527        /* Access right violation */
 528        qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
 529        if (guest_visible) {
 530            if (access_type == MMU_INST_FETCH) {
 531                cs->exception_index = POWERPC_EXCP_ISI;
 532                env->error_code = 0x08000000;
 533            } else {
 534                cs->exception_index = POWERPC_EXCP_DSI;
 535                env->error_code = 0;
 536                env->spr[SPR_DAR] = eaddr;
 537                if (access_type == MMU_DATA_STORE) {
 538                    env->spr[SPR_DSISR] = 0x0a000000;
 539                } else {
 540                    env->spr[SPR_DSISR] = 0x08000000;
 541                }
 542            }
 543        }
 544        return false;
 545    }
 546
 547    qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
 548
 549    /* 8. Update PTE referenced and changed bits if necessary */
 550
 551    if (!(pte.pte1 & HPTE32_R_R)) {
 552        ppc_hash32_set_r(cpu, pte_offset, pte.pte1);
 553    }
 554    if (!(pte.pte1 & HPTE32_R_C)) {
 555        if (access_type == MMU_DATA_STORE) {
 556            ppc_hash32_set_c(cpu, pte_offset, pte.pte1);
 557        } else {
 558            /*
 559             * Treat the page as read-only for now, so that a later write
 560             * will pass through this function again to set the C bit
 561             */
 562            prot &= ~PAGE_WRITE;
 563        }
 564     }
 565
 566    /* 9. Determine the real address from the PTE */
 567
 568    *raddrp = ppc_hash32_pte_raddr(sr, pte, eaddr);
 569    *protp = prot;
 570    return true;
 571}
 572