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 hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
 129                                    MMUAccessType access_type, int *prot,
 130                                    int mmu_idx)
 131{
 132    CPUPPCState *env = &cpu->env;
 133    target_ulong *BATlt, *BATut;
 134    bool ifetch = access_type == MMU_INST_FETCH;
 135    int i;
 136
 137    LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
 138             ifetch ? 'I' : 'D', ea);
 139    if (ifetch) {
 140        BATlt = env->IBAT[1];
 141        BATut = env->IBAT[0];
 142    } else {
 143        BATlt = env->DBAT[1];
 144        BATut = env->DBAT[0];
 145    }
 146    for (i = 0; i < env->nb_BATs; i++) {
 147        target_ulong batu = BATut[i];
 148        target_ulong batl = BATlt[i];
 149        target_ulong mask;
 150
 151        mask = hash32_bat_size(mmu_idx, batu, batl);
 152        LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
 153                 " BATl " TARGET_FMT_lx "\n", __func__,
 154                 ifetch ? 'I' : 'D', i, ea, batu, batl);
 155
 156        if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
 157            hwaddr raddr = (batl & mask) | (ea & ~mask);
 158
 159            *prot = hash32_bat_prot(cpu, batu, batl);
 160
 161            return raddr & TARGET_PAGE_MASK;
 162        }
 163    }
 164
 165    /* No hit */
 166#if defined(DEBUG_BATS)
 167    if (qemu_log_enabled()) {
 168        target_ulong *BATu, *BATl;
 169        target_ulong BEPIl, BEPIu, bl;
 170
 171        LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
 172        for (i = 0; i < 4; i++) {
 173            BATu = &BATut[i];
 174            BATl = &BATlt[i];
 175            BEPIu = *BATu & BATU32_BEPIU;
 176            BEPIl = *BATu & BATU32_BEPIL;
 177            bl = (*BATu & 0x00001FFC) << 15;
 178            LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
 179                     " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
 180                     TARGET_FMT_lx " " TARGET_FMT_lx "\n",
 181                     __func__, ifetch ? 'I' : 'D', i, ea,
 182                     *BATu, *BATl, BEPIu, BEPIl, bl);
 183        }
 184    }
 185#endif
 186
 187    return -1;
 188}
 189
 190static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
 191                                    target_ulong eaddr,
 192                                    MMUAccessType access_type,
 193                                    hwaddr *raddr, int *prot, int mmu_idx,
 194                                    bool guest_visible)
 195{
 196    CPUState *cs = CPU(cpu);
 197    CPUPPCState *env = &cpu->env;
 198    int key = !!(mmuidx_pr(mmu_idx) ? (sr & SR32_KP) : (sr & SR32_KS));
 199
 200    qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
 201
 202    if (access_type == MMU_INST_FETCH) {
 203        /* No code fetch is allowed in direct-store areas */
 204        if (guest_visible) {
 205            cs->exception_index = POWERPC_EXCP_ISI;
 206            env->error_code = 0x10000000;
 207        }
 208        return false;
 209    }
 210
 211    /*
 212     * From ppc_cpu_get_phys_page_debug, env->access_type is not set.
 213     * Assume ACCESS_INT for that case.
 214     */
 215    switch (guest_visible ? env->access_type : ACCESS_INT) {
 216    case ACCESS_INT:
 217        /* Integer load/store : only access allowed */
 218        break;
 219    case ACCESS_FLOAT:
 220        /* Floating point load/store */
 221        cs->exception_index = POWERPC_EXCP_ALIGN;
 222        env->error_code = POWERPC_EXCP_ALIGN_FP;
 223        env->spr[SPR_DAR] = eaddr;
 224        return false;
 225    case ACCESS_RES:
 226        /* lwarx, ldarx or srwcx. */
 227        env->error_code = 0;
 228        env->spr[SPR_DAR] = eaddr;
 229        if (access_type == MMU_DATA_STORE) {
 230            env->spr[SPR_DSISR] = 0x06000000;
 231        } else {
 232            env->spr[SPR_DSISR] = 0x04000000;
 233        }
 234        return false;
 235    case ACCESS_CACHE:
 236        /*
 237         * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
 238         *
 239         * Should make the instruction do no-op.  As it already do
 240         * no-op, it's quite easy :-)
 241         */
 242        *raddr = eaddr;
 243        return true;
 244    case ACCESS_EXT:
 245        /* eciwx or ecowx */
 246        cs->exception_index = POWERPC_EXCP_DSI;
 247        env->error_code = 0;
 248        env->spr[SPR_DAR] = eaddr;
 249        if (access_type == MMU_DATA_STORE) {
 250            env->spr[SPR_DSISR] = 0x06100000;
 251        } else {
 252            env->spr[SPR_DSISR] = 0x04100000;
 253        }
 254        return false;
 255    default:
 256        cpu_abort(cs, "ERROR: insn should not need address translation\n");
 257    }
 258
 259    *prot = key ? PAGE_READ | PAGE_WRITE : PAGE_READ;
 260    if (*prot & prot_for_access_type(access_type)) {
 261        *raddr = eaddr;
 262        return true;
 263    }
 264
 265    if (guest_visible) {
 266        cs->exception_index = POWERPC_EXCP_DSI;
 267        env->error_code = 0;
 268        env->spr[SPR_DAR] = eaddr;
 269        if (access_type == MMU_DATA_STORE) {
 270            env->spr[SPR_DSISR] = 0x0a000000;
 271        } else {
 272            env->spr[SPR_DSISR] = 0x08000000;
 273        }
 274    }
 275    return false;
 276}
 277
 278hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
 279{
 280    target_ulong mask = ppc_hash32_hpt_mask(cpu);
 281
 282    return (hash * HASH_PTEG_SIZE_32) & mask;
 283}
 284
 285static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
 286                                     bool secondary, target_ulong ptem,
 287                                     ppc_hash_pte32_t *pte)
 288{
 289    hwaddr pte_offset = pteg_off;
 290    target_ulong pte0, pte1;
 291    int i;
 292
 293    for (i = 0; i < HPTES_PER_GROUP; i++) {
 294        pte0 = ppc_hash32_load_hpte0(cpu, pte_offset);
 295        /*
 296         * pte0 contains the valid bit and must be read before pte1,
 297         * otherwise we might see an old pte1 with a new valid bit and
 298         * thus an inconsistent hpte value
 299         */
 300        smp_rmb();
 301        pte1 = ppc_hash32_load_hpte1(cpu, pte_offset);
 302
 303        if ((pte0 & HPTE32_V_VALID)
 304            && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
 305            && HPTE32_V_COMPARE(pte0, ptem)) {
 306            pte->pte0 = pte0;
 307            pte->pte1 = pte1;
 308            return pte_offset;
 309        }
 310
 311        pte_offset += HASH_PTE_SIZE_32;
 312    }
 313
 314    return -1;
 315}
 316
 317static void ppc_hash32_set_r(PowerPCCPU *cpu, hwaddr pte_offset, uint32_t pte1)
 318{
 319    target_ulong base = ppc_hash32_hpt_base(cpu);
 320    hwaddr offset = pte_offset + 6;
 321
 322    /* The HW performs a non-atomic byte update */
 323    stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01);
 324}
 325
 326static void ppc_hash32_set_c(PowerPCCPU *cpu, hwaddr pte_offset, uint64_t pte1)
 327{
 328    target_ulong base = ppc_hash32_hpt_base(cpu);
 329    hwaddr offset = pte_offset + 7;
 330
 331    /* The HW performs a non-atomic byte update */
 332    stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
 333}
 334
 335static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
 336                                     target_ulong sr, target_ulong eaddr,
 337                                     ppc_hash_pte32_t *pte)
 338{
 339    hwaddr pteg_off, pte_offset;
 340    hwaddr hash;
 341    uint32_t vsid, pgidx, ptem;
 342
 343    vsid = sr & SR32_VSID;
 344    pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
 345    hash = vsid ^ pgidx;
 346    ptem = (vsid << 7) | (pgidx >> 10);
 347
 348    /* Page address translation */
 349    qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
 350            " htab_mask " TARGET_FMT_plx
 351            " hash " TARGET_FMT_plx "\n",
 352            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
 353
 354    /* Primary PTEG lookup */
 355    qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
 356            " vsid=%" PRIx32 " ptem=%" PRIx32
 357            " hash=" TARGET_FMT_plx "\n",
 358            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
 359            vsid, ptem, hash);
 360    pteg_off = get_pteg_offset32(cpu, hash);
 361    pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
 362    if (pte_offset == -1) {
 363        /* Secondary PTEG lookup */
 364        qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
 365                " vsid=%" PRIx32 " api=%" PRIx32
 366                " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
 367                ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
 368        pteg_off = get_pteg_offset32(cpu, ~hash);
 369        pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
 370    }
 371
 372    return pte_offset;
 373}
 374
 375static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
 376                                   target_ulong eaddr)
 377{
 378    hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
 379    hwaddr mask = ~TARGET_PAGE_MASK;
 380
 381    return (rpn & ~mask) | (eaddr & mask);
 382}
 383
 384bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
 385                      hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
 386                      bool guest_visible)
 387{
 388    CPUState *cs = CPU(cpu);
 389    CPUPPCState *env = &cpu->env;
 390    target_ulong sr;
 391    hwaddr pte_offset;
 392    ppc_hash_pte32_t pte;
 393    int prot;
 394    int need_prot;
 395    hwaddr raddr;
 396
 397    /* There are no hash32 large pages. */
 398    *psizep = TARGET_PAGE_BITS;
 399
 400    /* 1. Handle real mode accesses */
 401    if (mmuidx_real(mmu_idx)) {
 402        /* Translation is off */
 403        *raddrp = eaddr;
 404        *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 405        return true;
 406    }
 407
 408    need_prot = prot_for_access_type(access_type);
 409
 410    /* 2. Check Block Address Translation entries (BATs) */
 411    if (env->nb_BATs != 0) {
 412        raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
 413        if (raddr != -1) {
 414            if (need_prot & ~*protp) {
 415                if (guest_visible) {
 416                    if (access_type == MMU_INST_FETCH) {
 417                        cs->exception_index = POWERPC_EXCP_ISI;
 418                        env->error_code = 0x08000000;
 419                    } else {
 420                        cs->exception_index = POWERPC_EXCP_DSI;
 421                        env->error_code = 0;
 422                        env->spr[SPR_DAR] = eaddr;
 423                        if (access_type == MMU_DATA_STORE) {
 424                            env->spr[SPR_DSISR] = 0x0a000000;
 425                        } else {
 426                            env->spr[SPR_DSISR] = 0x08000000;
 427                        }
 428                    }
 429                }
 430                return false;
 431            }
 432            *raddrp = raddr;
 433            return true;
 434        }
 435    }
 436
 437    /* 3. Look up the Segment Register */
 438    sr = env->sr[eaddr >> 28];
 439
 440    /* 4. Handle direct store segments */
 441    if (sr & SR32_T) {
 442        return ppc_hash32_direct_store(cpu, sr, eaddr, access_type,
 443                                       raddrp, protp, mmu_idx, guest_visible);
 444    }
 445
 446    /* 5. Check for segment level no-execute violation */
 447    if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) {
 448        if (guest_visible) {
 449            cs->exception_index = POWERPC_EXCP_ISI;
 450            env->error_code = 0x10000000;
 451        }
 452        return false;
 453    }
 454
 455    /* 6. Locate the PTE in the hash table */
 456    pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
 457    if (pte_offset == -1) {
 458        if (guest_visible) {
 459            if (access_type == MMU_INST_FETCH) {
 460                cs->exception_index = POWERPC_EXCP_ISI;
 461                env->error_code = 0x40000000;
 462            } else {
 463                cs->exception_index = POWERPC_EXCP_DSI;
 464                env->error_code = 0;
 465                env->spr[SPR_DAR] = eaddr;
 466                if (access_type == MMU_DATA_STORE) {
 467                    env->spr[SPR_DSISR] = 0x42000000;
 468                } else {
 469                    env->spr[SPR_DSISR] = 0x40000000;
 470                }
 471            }
 472        }
 473        return false;
 474    }
 475    qemu_log_mask(CPU_LOG_MMU,
 476                "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
 477
 478    /* 7. Check access permissions */
 479
 480    prot = ppc_hash32_pte_prot(mmu_idx, sr, pte);
 481
 482    if (need_prot & ~prot) {
 483        /* Access right violation */
 484        qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
 485        if (guest_visible) {
 486            if (access_type == MMU_INST_FETCH) {
 487                cs->exception_index = POWERPC_EXCP_ISI;
 488                env->error_code = 0x08000000;
 489            } else {
 490                cs->exception_index = POWERPC_EXCP_DSI;
 491                env->error_code = 0;
 492                env->spr[SPR_DAR] = eaddr;
 493                if (access_type == MMU_DATA_STORE) {
 494                    env->spr[SPR_DSISR] = 0x0a000000;
 495                } else {
 496                    env->spr[SPR_DSISR] = 0x08000000;
 497                }
 498            }
 499        }
 500        return false;
 501    }
 502
 503    qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
 504
 505    /* 8. Update PTE referenced and changed bits if necessary */
 506
 507    if (!(pte.pte1 & HPTE32_R_R)) {
 508        ppc_hash32_set_r(cpu, pte_offset, pte.pte1);
 509    }
 510    if (!(pte.pte1 & HPTE32_R_C)) {
 511        if (access_type == MMU_DATA_STORE) {
 512            ppc_hash32_set_c(cpu, pte_offset, pte.pte1);
 513        } else {
 514            /*
 515             * Treat the page as read-only for now, so that a later write
 516             * will pass through this function again to set the C bit
 517             */
 518            prot &= ~PAGE_WRITE;
 519        }
 520     }
 521
 522    /* 9. Determine the real address from the PTE */
 523
 524    *raddrp = ppc_hash32_pte_raddr(sr, pte, eaddr);
 525    *protp = prot;
 526    return true;
 527}
 528