qemu/target/ppc/mmu-radix64.c
<<
>>
Prefs
   1/*
   2 *  PowerPC Radix MMU mulation helpers for QEMU.
   3 *
   4 *  Copyright (c) 2016 Suraj Jitindar Singh, IBM Corporation
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2.1 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "cpu.h"
  22#include "exec/exec-all.h"
  23#include "qemu/error-report.h"
  24#include "sysemu/kvm.h"
  25#include "kvm_ppc.h"
  26#include "exec/log.h"
  27#include "internal.h"
  28#include "mmu-radix64.h"
  29#include "mmu-book3s-v3.h"
  30
  31static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
  32                                                 vaddr eaddr,
  33                                                 uint64_t *lpid, uint64_t *pid)
  34{
  35    if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */
  36        switch (eaddr & R_EADDR_QUADRANT) {
  37        case R_EADDR_QUADRANT0:
  38            *lpid = 0;
  39            *pid = env->spr[SPR_BOOKS_PID];
  40            break;
  41        case R_EADDR_QUADRANT1:
  42            *lpid = env->spr[SPR_LPIDR];
  43            *pid = env->spr[SPR_BOOKS_PID];
  44            break;
  45        case R_EADDR_QUADRANT2:
  46            *lpid = env->spr[SPR_LPIDR];
  47            *pid = 0;
  48            break;
  49        case R_EADDR_QUADRANT3:
  50            *lpid = 0;
  51            *pid = 0;
  52            break;
  53        default:
  54            g_assert_not_reached();
  55        }
  56    } else {  /* !MSR[HV] -> Guest */
  57        switch (eaddr & R_EADDR_QUADRANT) {
  58        case R_EADDR_QUADRANT0: /* Guest application */
  59            *lpid = env->spr[SPR_LPIDR];
  60            *pid = env->spr[SPR_BOOKS_PID];
  61            break;
  62        case R_EADDR_QUADRANT1: /* Illegal */
  63        case R_EADDR_QUADRANT2:
  64            return false;
  65        case R_EADDR_QUADRANT3: /* Guest OS */
  66            *lpid = env->spr[SPR_LPIDR];
  67            *pid = 0; /* pid set to 0 -> addresses guest operating system */
  68            break;
  69        default:
  70            g_assert_not_reached();
  71        }
  72    }
  73
  74    return true;
  75}
  76
  77static void ppc_radix64_raise_segi(PowerPCCPU *cpu, MMUAccessType access_type,
  78                                   vaddr eaddr)
  79{
  80    CPUState *cs = CPU(cpu);
  81    CPUPPCState *env = &cpu->env;
  82
  83    switch (access_type) {
  84    case MMU_INST_FETCH:
  85        /* Instruction Segment Interrupt */
  86        cs->exception_index = POWERPC_EXCP_ISEG;
  87        break;
  88    case MMU_DATA_STORE:
  89    case MMU_DATA_LOAD:
  90        /* Data Segment Interrupt */
  91        cs->exception_index = POWERPC_EXCP_DSEG;
  92        env->spr[SPR_DAR] = eaddr;
  93        break;
  94    default:
  95        g_assert_not_reached();
  96    }
  97    env->error_code = 0;
  98}
  99
 100static void ppc_radix64_raise_si(PowerPCCPU *cpu, MMUAccessType access_type,
 101                                 vaddr eaddr, uint32_t cause)
 102{
 103    CPUState *cs = CPU(cpu);
 104    CPUPPCState *env = &cpu->env;
 105
 106    switch (access_type) {
 107    case MMU_INST_FETCH:
 108        /* Instruction Storage Interrupt */
 109        cs->exception_index = POWERPC_EXCP_ISI;
 110        env->error_code = cause;
 111        break;
 112    case MMU_DATA_STORE:
 113        cause |= DSISR_ISSTORE;
 114        /* fall through */
 115    case MMU_DATA_LOAD:
 116        /* Data Storage Interrupt */
 117        cs->exception_index = POWERPC_EXCP_DSI;
 118        env->spr[SPR_DSISR] = cause;
 119        env->spr[SPR_DAR] = eaddr;
 120        env->error_code = 0;
 121        break;
 122    default:
 123        g_assert_not_reached();
 124    }
 125}
 126
 127static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type,
 128                                  vaddr eaddr, hwaddr g_raddr, uint32_t cause)
 129{
 130    CPUState *cs = CPU(cpu);
 131    CPUPPCState *env = &cpu->env;
 132
 133    switch (access_type) {
 134    case MMU_INST_FETCH:
 135        /* H Instruction Storage Interrupt */
 136        cs->exception_index = POWERPC_EXCP_HISI;
 137        env->spr[SPR_ASDR] = g_raddr;
 138        env->error_code = cause;
 139        break;
 140    case MMU_DATA_STORE:
 141        cause |= DSISR_ISSTORE;
 142        /* fall through */
 143    case MMU_DATA_LOAD:
 144        /* H Data Storage Interrupt */
 145        cs->exception_index = POWERPC_EXCP_HDSI;
 146        env->spr[SPR_HDSISR] = cause;
 147        env->spr[SPR_HDAR] = eaddr;
 148        env->spr[SPR_ASDR] = g_raddr;
 149        env->error_code = 0;
 150        break;
 151    default:
 152        g_assert_not_reached();
 153    }
 154}
 155
 156static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
 157                                   uint64_t pte, int *fault_cause, int *prot,
 158                                   int mmu_idx, bool partition_scoped)
 159{
 160    CPUPPCState *env = &cpu->env;
 161    int need_prot;
 162
 163    /* Check Page Attributes (pte58:59) */
 164    if ((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO && access_type == MMU_INST_FETCH) {
 165        /*
 166         * Radix PTE entries with the non-idempotent I/O attribute are treated
 167         * as guarded storage
 168         */
 169        *fault_cause |= SRR1_NOEXEC_GUARD;
 170        return true;
 171    }
 172
 173    /* Determine permissions allowed by Encoded Access Authority */
 174    if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && msr_pr) {
 175        *prot = 0;
 176    } else if (mmuidx_pr(mmu_idx) || (pte & R_PTE_EAA_PRIV) ||
 177               partition_scoped) {
 178        *prot = ppc_radix64_get_prot_eaa(pte);
 179    } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */
 180        *prot = ppc_radix64_get_prot_eaa(pte);
 181        *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */
 182    }
 183
 184    /* Check if requested access type is allowed */
 185    need_prot = prot_for_access_type(access_type);
 186    if (need_prot & ~*prot) { /* Page Protected for that Access */
 187        *fault_cause |= DSISR_PROTFAULT;
 188        return true;
 189    }
 190
 191    return false;
 192}
 193
 194static void ppc_radix64_set_rc(PowerPCCPU *cpu, MMUAccessType access_type,
 195                               uint64_t pte, hwaddr pte_addr, int *prot)
 196{
 197    CPUState *cs = CPU(cpu);
 198    uint64_t npte;
 199
 200    npte = pte | R_PTE_R; /* Always set reference bit */
 201
 202    if (access_type == MMU_DATA_STORE) { /* Store/Write */
 203        npte |= R_PTE_C; /* Set change bit */
 204    } else {
 205        /*
 206         * Treat the page as read-only for now, so that a later write
 207         * will pass through this function again to set the C bit.
 208         */
 209        *prot &= ~PAGE_WRITE;
 210    }
 211
 212    if (pte ^ npte) { /* If pte has changed then write it back */
 213        stq_phys(cs->as, pte_addr, npte);
 214    }
 215}
 216
 217static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
 218                                  uint64_t *pte_addr, uint64_t *nls,
 219                                  int *psize, uint64_t *pte, int *fault_cause)
 220{
 221    uint64_t index, pde;
 222
 223    if (*nls < 5) { /* Directory maps less than 2**5 entries */
 224        *fault_cause |= DSISR_R_BADCONFIG;
 225        return 1;
 226    }
 227
 228    /* Read page <directory/table> entry from guest address space */
 229    pde = ldq_phys(as, *pte_addr);
 230    if (!(pde & R_PTE_VALID)) {         /* Invalid Entry */
 231        *fault_cause |= DSISR_NOPTE;
 232        return 1;
 233    }
 234
 235    *pte = pde;
 236    *psize -= *nls;
 237    if (!(pde & R_PTE_LEAF)) { /* Prepare for next iteration */
 238        *nls = pde & R_PDE_NLS;
 239        index = eaddr >> (*psize - *nls);       /* Shift */
 240        index &= ((1UL << *nls) - 1);           /* Mask */
 241        *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde));
 242    }
 243    return 0;
 244}
 245
 246static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr,
 247                                 uint64_t base_addr, uint64_t nls,
 248                                 hwaddr *raddr, int *psize, uint64_t *pte,
 249                                 int *fault_cause, hwaddr *pte_addr)
 250{
 251    uint64_t index, pde, rpn , mask;
 252
 253    if (nls < 5) { /* Directory maps less than 2**5 entries */
 254        *fault_cause |= DSISR_R_BADCONFIG;
 255        return 1;
 256    }
 257
 258    index = eaddr >> (*psize - nls);    /* Shift */
 259    index &= ((1UL << nls) - 1);       /* Mask */
 260    *pte_addr = base_addr + (index * sizeof(pde));
 261    do {
 262        int ret;
 263
 264        ret = ppc_radix64_next_level(as, eaddr, pte_addr, &nls, psize, &pde,
 265                                     fault_cause);
 266        if (ret) {
 267            return ret;
 268        }
 269    } while (!(pde & R_PTE_LEAF));
 270
 271    *pte = pde;
 272    rpn = pde & R_PTE_RPN;
 273    mask = (1UL << *psize) - 1;
 274
 275    /* Or high bits of rpn and low bits to ea to form whole real addr */
 276    *raddr = (rpn & ~mask) | (eaddr & mask);
 277    return 0;
 278}
 279
 280static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
 281{
 282    CPUPPCState *env = &cpu->env;
 283
 284    if (!(pate->dw0 & PATE0_HR)) {
 285        return false;
 286    }
 287    if (lpid == 0 && !msr_hv) {
 288        return false;
 289    }
 290    if ((pate->dw0 & PATE1_R_PRTS) < 5) {
 291        return false;
 292    }
 293    /* More checks ... */
 294    return true;
 295}
 296
 297static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu,
 298                                              MMUAccessType access_type,
 299                                              vaddr eaddr, hwaddr g_raddr,
 300                                              ppc_v3_pate_t pate,
 301                                              hwaddr *h_raddr, int *h_prot,
 302                                              int *h_page_size, bool pde_addr,
 303                                              int mmu_idx, bool guest_visible)
 304{
 305    int fault_cause = 0;
 306    hwaddr pte_addr;
 307    uint64_t pte;
 308
 309    *h_page_size = PRTBE_R_GET_RTS(pate.dw0);
 310    /* No valid pte or access denied due to protection */
 311    if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
 312                              pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
 313                              &pte, &fault_cause, &pte_addr) ||
 314        ppc_radix64_check_prot(cpu, access_type, pte,
 315                               &fault_cause, h_prot, mmu_idx, true)) {
 316        if (pde_addr) { /* address being translated was that of a guest pde */
 317            fault_cause |= DSISR_PRTABLE_FAULT;
 318        }
 319        if (guest_visible) {
 320            ppc_radix64_raise_hsi(cpu, access_type, eaddr, g_raddr, fault_cause);
 321        }
 322        return 1;
 323    }
 324
 325    if (guest_visible) {
 326        ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, h_prot);
 327    }
 328
 329    return 0;
 330}
 331
 332static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
 333                                            MMUAccessType access_type,
 334                                            vaddr eaddr, uint64_t pid,
 335                                            ppc_v3_pate_t pate, hwaddr *g_raddr,
 336                                            int *g_prot, int *g_page_size,
 337                                            int mmu_idx, bool guest_visible)
 338{
 339    CPUState *cs = CPU(cpu);
 340    CPUPPCState *env = &cpu->env;
 341    uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte;
 342    int fault_cause = 0, h_page_size, h_prot;
 343    hwaddr h_raddr, pte_addr;
 344    int ret;
 345
 346    /* Index Process Table by PID to Find Corresponding Process Table Entry */
 347    offset = pid * sizeof(struct prtb_entry);
 348    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
 349    if (offset >= size) {
 350        /* offset exceeds size of the process table */
 351        if (guest_visible) {
 352            ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
 353        }
 354        return 1;
 355    }
 356    prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
 357
 358    if (cpu->vhyp) {
 359        prtbe0 = ldq_phys(cs->as, prtbe_addr);
 360    } else {
 361        /*
 362         * Process table addresses are subject to partition-scoped
 363         * translation
 364         *
 365         * On a Radix host, the partition-scoped page table for LPID=0
 366         * is only used to translate the effective addresses of the
 367         * process table entries.
 368         */
 369        ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr,
 370                                                 pate, &h_raddr, &h_prot,
 371                                                 &h_page_size, true,
 372            /* mmu_idx is 5 because we're translating from hypervisor scope */
 373                                                 5, guest_visible);
 374        if (ret) {
 375            return ret;
 376        }
 377        prtbe0 = ldq_phys(cs->as, h_raddr);
 378    }
 379
 380    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
 381    *g_page_size = PRTBE_R_GET_RTS(prtbe0);
 382    base_addr = prtbe0 & PRTBE_R_RPDB;
 383    nls = prtbe0 & PRTBE_R_RPDS;
 384    if (msr_hv || cpu->vhyp) {
 385        /*
 386         * Can treat process table addresses as real addresses
 387         */
 388        ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr,
 389                                    nls, g_raddr, g_page_size, &pte,
 390                                    &fault_cause, &pte_addr);
 391        if (ret) {
 392            /* No valid PTE */
 393            if (guest_visible) {
 394                ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
 395            }
 396            return ret;
 397        }
 398    } else {
 399        uint64_t rpn, mask;
 400
 401        index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */
 402        index &= ((1UL << nls) - 1);                            /* Mask */
 403        pte_addr = base_addr + (index * sizeof(pte));
 404
 405        /*
 406         * Each process table address is subject to a partition-scoped
 407         * translation
 408         */
 409        do {
 410            ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr,
 411                                                     pate, &h_raddr, &h_prot,
 412                                                     &h_page_size, true,
 413            /* mmu_idx is 5 because we're translating from hypervisor scope */
 414                                                     5, guest_visible);
 415            if (ret) {
 416                return ret;
 417            }
 418
 419            ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr,
 420                                         &nls, g_page_size, &pte, &fault_cause);
 421            if (ret) {
 422                /* No valid pte */
 423                if (guest_visible) {
 424                    ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
 425                }
 426                return ret;
 427            }
 428            pte_addr = h_raddr;
 429        } while (!(pte & R_PTE_LEAF));
 430
 431        rpn = pte & R_PTE_RPN;
 432        mask = (1UL << *g_page_size) - 1;
 433
 434        /* Or high bits of rpn and low bits to ea to form whole real addr */
 435        *g_raddr = (rpn & ~mask) | (eaddr & mask);
 436    }
 437
 438    if (ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause,
 439                               g_prot, mmu_idx, false)) {
 440        /* Access denied due to protection */
 441        if (guest_visible) {
 442            ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
 443        }
 444        return 1;
 445    }
 446
 447    if (guest_visible) {
 448        ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, g_prot);
 449    }
 450
 451    return 0;
 452}
 453
 454/*
 455 * Radix tree translation is a 2 steps translation process:
 456 *
 457 * 1. Process-scoped translation:   Guest Eff Addr  -> Guest Real Addr
 458 * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr
 459 *
 460 *                                  MSR[HV]
 461 *              +-------------+----------------+---------------+
 462 *              |             |     HV = 0     |     HV = 1    |
 463 *              +-------------+----------------+---------------+
 464 *              | Relocation  |    Partition   |      No       |
 465 *              | = Off       |     Scoped     |  Translation  |
 466 *  Relocation  +-------------+----------------+---------------+
 467 *              | Relocation  |   Partition &  |    Process    |
 468 *              | = On        | Process Scoped |    Scoped     |
 469 *              +-------------+----------------+---------------+
 470 */
 471bool ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
 472                       hwaddr *raddr, int *psizep, int *protp, int mmu_idx,
 473                       bool guest_visible)
 474{
 475    CPUPPCState *env = &cpu->env;
 476    uint64_t lpid, pid;
 477    ppc_v3_pate_t pate;
 478    int psize, prot;
 479    hwaddr g_raddr;
 480    bool relocation;
 481
 482    assert(!(mmuidx_hv(mmu_idx) && cpu->vhyp));
 483
 484    relocation = !mmuidx_real(mmu_idx);
 485
 486    /* HV or virtual hypervisor Real Mode Access */
 487    if (!relocation && (mmuidx_hv(mmu_idx) || cpu->vhyp)) {
 488        /* In real mode top 4 effective addr bits (mostly) ignored */
 489        *raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
 490
 491        /* In HV mode, add HRMOR if top EA bit is clear */
 492        if (mmuidx_hv(mmu_idx) || !env->has_hv_mode) {
 493            if (!(eaddr >> 63)) {
 494                *raddr |= env->spr[SPR_HRMOR];
 495           }
 496        }
 497        *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 498        *psizep = TARGET_PAGE_BITS;
 499        return true;
 500    }
 501
 502    /*
 503     * Check UPRT (we avoid the check in real mode to deal with
 504     * transitional states during kexec.
 505     */
 506    if (guest_visible && !ppc64_use_proc_tbl(cpu)) {
 507        qemu_log_mask(LOG_GUEST_ERROR,
 508                      "LPCR:UPRT not set in radix mode ! LPCR="
 509                      TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
 510    }
 511
 512    /* Virtual Mode Access - get the fully qualified address */
 513    if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
 514        if (guest_visible) {
 515            ppc_radix64_raise_segi(cpu, access_type, eaddr);
 516        }
 517        return false;
 518    }
 519
 520    /* Get Process Table */
 521    if (cpu->vhyp) {
 522        PPCVirtualHypervisorClass *vhc;
 523        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
 524        vhc->get_pate(cpu->vhyp, &pate);
 525    } else {
 526        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
 527            if (guest_visible) {
 528                ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
 529            }
 530            return false;
 531        }
 532        if (!validate_pate(cpu, lpid, &pate)) {
 533            if (guest_visible) {
 534                ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG);
 535            }
 536            return false;
 537        }
 538    }
 539
 540    *psizep = INT_MAX;
 541    *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 542
 543    /*
 544     * Perform process-scoped translation if relocation enabled.
 545     *
 546     * - Translates an effective address to a host real address in
 547     *   quadrants 0 and 3 when HV=1.
 548     *
 549     * - Translates an effective address to a guest real address.
 550     */
 551    if (relocation) {
 552        int ret = ppc_radix64_process_scoped_xlate(cpu, access_type, eaddr, pid,
 553                                                   pate, &g_raddr, &prot,
 554                                                   &psize, mmu_idx, guest_visible);
 555        if (ret) {
 556            return false;
 557        }
 558        *psizep = MIN(*psizep, psize);
 559        *protp &= prot;
 560    } else {
 561        g_raddr = eaddr & R_EADDR_MASK;
 562    }
 563
 564    if (cpu->vhyp) {
 565        *raddr = g_raddr;
 566    } else {
 567        /*
 568         * Perform partition-scoped translation if !HV or HV access to
 569         * quadrants 1 or 2. Translates a guest real address to a host
 570         * real address.
 571         */
 572        if (lpid || !mmuidx_hv(mmu_idx)) {
 573            int ret;
 574
 575            ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr,
 576                                                     g_raddr, pate, raddr,
 577                                                     &prot, &psize, false,
 578                                                     mmu_idx, guest_visible);
 579            if (ret) {
 580                return false;
 581            }
 582            *psizep = MIN(*psizep, psize);
 583            *protp &= prot;
 584        } else {
 585            *raddr = g_raddr;
 586        }
 587    }
 588
 589    return true;
 590}
 591