qemu/target/riscv/pmp.c
<<
>>
Prefs
   1/*
   2 * QEMU RISC-V PMP (Physical Memory Protection)
   3 *
   4 * Author: Daire McNamara, daire.mcnamara@emdalo.com
   5 *         Ivan Griffin, ivan.griffin@emdalo.com
   6 *
   7 * This provides a RISC-V Physical Memory Protection implementation
   8 *
   9 * This program is free software; you can redistribute it and/or modify it
  10 * under the terms and conditions of the GNU General Public License,
  11 * version 2 or later, as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope it will be useful, but WITHOUT
  14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  16 * more details.
  17 *
  18 * You should have received a copy of the GNU General Public License along with
  19 * this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21
  22#include "qemu/osdep.h"
  23#include "qemu/log.h"
  24#include "qapi/error.h"
  25#include "cpu.h"
  26#include "trace.h"
  27#include "exec/exec-all.h"
  28
  29static void pmp_write_cfg(CPURISCVState *env, uint32_t addr_index,
  30    uint8_t val);
  31static uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t addr_index);
  32static void pmp_update_rule(CPURISCVState *env, uint32_t pmp_index);
  33
  34/*
  35 * Accessor method to extract address matching type 'a field' from cfg reg
  36 */
  37static inline uint8_t pmp_get_a_field(uint8_t cfg)
  38{
  39    uint8_t a = cfg >> 3;
  40    return a & 0x3;
  41}
  42
  43/*
  44 * Check whether a PMP is locked or not.
  45 */
  46static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
  47{
  48
  49    if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) {
  50        return 1;
  51    }
  52
  53    /* Top PMP has no 'next' to check */
  54    if ((pmp_index + 1u) >= MAX_RISCV_PMPS) {
  55        return 0;
  56    }
  57
  58    return 0;
  59}
  60
  61/*
  62 * Count the number of active rules.
  63 */
  64uint32_t pmp_get_num_rules(CPURISCVState *env)
  65{
  66     return env->pmp_state.num_rules;
  67}
  68
  69/*
  70 * Accessor to get the cfg reg for a specific PMP/HART
  71 */
  72static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
  73{
  74    if (pmp_index < MAX_RISCV_PMPS) {
  75        return env->pmp_state.pmp[pmp_index].cfg_reg;
  76    }
  77
  78    return 0;
  79}
  80
  81
  82/*
  83 * Accessor to set the cfg reg for a specific PMP/HART
  84 * Bounds checks and relevant lock bit.
  85 */
  86static void pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
  87{
  88    if (pmp_index < MAX_RISCV_PMPS) {
  89        bool locked = true;
  90
  91        if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
  92            /* mseccfg.RLB is set */
  93            if (MSECCFG_RLB_ISSET(env)) {
  94                locked = false;
  95            }
  96
  97            /* mseccfg.MML is not set */
  98            if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) {
  99                locked = false;
 100            }
 101
 102            /* mseccfg.MML is set */
 103            if (MSECCFG_MML_ISSET(env)) {
 104                /* not adding execute bit */
 105                if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
 106                    locked = false;
 107                }
 108                /* shared region and not adding X bit */
 109                if ((val & PMP_LOCK) != PMP_LOCK &&
 110                    (val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
 111                    locked = false;
 112                }
 113            }
 114        } else {
 115            if (!pmp_is_locked(env, pmp_index)) {
 116                locked = false;
 117            }
 118        }
 119
 120        if (locked) {
 121            qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
 122        } else {
 123            env->pmp_state.pmp[pmp_index].cfg_reg = val;
 124            pmp_update_rule(env, pmp_index);
 125        }
 126    } else {
 127        qemu_log_mask(LOG_GUEST_ERROR,
 128                      "ignoring pmpcfg write - out of bounds\n");
 129    }
 130}
 131
 132static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea)
 133{
 134    /*
 135       aaaa...aaa0   8-byte NAPOT range
 136       aaaa...aa01   16-byte NAPOT range
 137       aaaa...a011   32-byte NAPOT range
 138       ...
 139       aa01...1111   2^XLEN-byte NAPOT range
 140       a011...1111   2^(XLEN+1)-byte NAPOT range
 141       0111...1111   2^(XLEN+2)-byte NAPOT range
 142       1111...1111   Reserved
 143    */
 144    a = (a << 2) | 0x3;
 145    *sa = a & (a + 1);
 146    *ea = a | (a + 1);
 147}
 148
 149void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index)
 150{
 151    uint8_t this_cfg = env->pmp_state.pmp[pmp_index].cfg_reg;
 152    target_ulong this_addr = env->pmp_state.pmp[pmp_index].addr_reg;
 153    target_ulong prev_addr = 0u;
 154    target_ulong sa = 0u;
 155    target_ulong ea = 0u;
 156
 157    if (pmp_index >= 1u) {
 158        prev_addr = env->pmp_state.pmp[pmp_index - 1].addr_reg;
 159    }
 160
 161    switch (pmp_get_a_field(this_cfg)) {
 162    case PMP_AMATCH_OFF:
 163        sa = 0u;
 164        ea = -1;
 165        break;
 166
 167    case PMP_AMATCH_TOR:
 168        sa = prev_addr << 2; /* shift up from [xx:0] to [xx+2:2] */
 169        ea = (this_addr << 2) - 1u;
 170        if (sa > ea) {
 171            sa = ea = 0u;
 172        }
 173        break;
 174
 175    case PMP_AMATCH_NA4:
 176        sa = this_addr << 2; /* shift up from [xx:0] to [xx+2:2] */
 177        ea = (sa + 4u) - 1u;
 178        break;
 179
 180    case PMP_AMATCH_NAPOT:
 181        pmp_decode_napot(this_addr, &sa, &ea);
 182        break;
 183
 184    default:
 185        sa = 0u;
 186        ea = 0u;
 187        break;
 188    }
 189
 190    env->pmp_state.addr[pmp_index].sa = sa;
 191    env->pmp_state.addr[pmp_index].ea = ea;
 192}
 193
 194void pmp_update_rule_nums(CPURISCVState *env)
 195{
 196    int i;
 197
 198    env->pmp_state.num_rules = 0;
 199    for (i = 0; i < MAX_RISCV_PMPS; i++) {
 200        const uint8_t a_field =
 201            pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
 202        if (PMP_AMATCH_OFF != a_field) {
 203            env->pmp_state.num_rules++;
 204        }
 205    }
 206}
 207
 208/* Convert cfg/addr reg values here into simple 'sa' --> start address and 'ea'
 209 *   end address values.
 210 *   This function is called relatively infrequently whereas the check that
 211 *   an address is within a pmp rule is called often, so optimise that one
 212 */
 213static void pmp_update_rule(CPURISCVState *env, uint32_t pmp_index)
 214{
 215    pmp_update_rule_addr(env, pmp_index);
 216    pmp_update_rule_nums(env);
 217}
 218
 219static int pmp_is_in_range(CPURISCVState *env, int pmp_index, target_ulong addr)
 220{
 221    int result = 0;
 222
 223    if ((addr >= env->pmp_state.addr[pmp_index].sa)
 224        && (addr <= env->pmp_state.addr[pmp_index].ea)) {
 225        result = 1;
 226    } else {
 227        result = 0;
 228    }
 229
 230    return result;
 231}
 232
 233/*
 234 * Check if the address has required RWX privs when no PMP entry is matched.
 235 */
 236static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr,
 237    target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
 238    target_ulong mode)
 239{
 240    bool ret;
 241
 242    if (riscv_feature(env, RISCV_FEATURE_EPMP)) {
 243        if (MSECCFG_MMWP_ISSET(env)) {
 244            /*
 245             * The Machine Mode Whitelist Policy (mseccfg.MMWP) is set
 246             * so we default to deny all, even for M-mode.
 247             */
 248            *allowed_privs = 0;
 249            return false;
 250        } else if (MSECCFG_MML_ISSET(env)) {
 251            /*
 252             * The Machine Mode Lockdown (mseccfg.MML) bit is set
 253             * so we can only execute code in M-mode with an applicable
 254             * rule. Other modes are disabled.
 255             */
 256            if (mode == PRV_M && !(privs & PMP_EXEC)) {
 257                ret = true;
 258                *allowed_privs = PMP_READ | PMP_WRITE;
 259            } else {
 260                ret = false;
 261                *allowed_privs = 0;
 262            }
 263
 264            return ret;
 265        }
 266    }
 267
 268    if ((!riscv_feature(env, RISCV_FEATURE_PMP)) || (mode == PRV_M)) {
 269        /*
 270         * Privileged spec v1.10 states if HW doesn't implement any PMP entry
 271         * or no PMP entry matches an M-Mode access, the access succeeds.
 272         */
 273        ret = true;
 274        *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
 275    } else {
 276        /*
 277         * Other modes are not allowed to succeed if they don't * match a rule,
 278         * but there are rules. We've checked for no rule earlier in this
 279         * function.
 280         */
 281        ret = false;
 282        *allowed_privs = 0;
 283    }
 284
 285    return ret;
 286}
 287
 288
 289/*
 290 * Public Interface
 291 */
 292
 293/*
 294 * Check if the address has required RWX privs to complete desired operation
 295 */
 296bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
 297    target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
 298    target_ulong mode)
 299{
 300    int i = 0;
 301    int ret = -1;
 302    int pmp_size = 0;
 303    target_ulong s = 0;
 304    target_ulong e = 0;
 305
 306    /* Short cut if no rules */
 307    if (0 == pmp_get_num_rules(env)) {
 308        return pmp_hart_has_privs_default(env, addr, size, privs,
 309                                          allowed_privs, mode);
 310    }
 311
 312    if (size == 0) {
 313        if (riscv_feature(env, RISCV_FEATURE_MMU)) {
 314            /*
 315             * If size is unknown (0), assume that all bytes
 316             * from addr to the end of the page will be accessed.
 317             */
 318            pmp_size = -(addr | TARGET_PAGE_MASK);
 319        } else {
 320            pmp_size = sizeof(target_ulong);
 321        }
 322    } else {
 323        pmp_size = size;
 324    }
 325
 326    /* 1.10 draft priv spec states there is an implicit order
 327         from low to high */
 328    for (i = 0; i < MAX_RISCV_PMPS; i++) {
 329        s = pmp_is_in_range(env, i, addr);
 330        e = pmp_is_in_range(env, i, addr + pmp_size - 1);
 331
 332        /* partially inside */
 333        if ((s + e) == 1) {
 334            qemu_log_mask(LOG_GUEST_ERROR,
 335                          "pmp violation - access is partially inside\n");
 336            ret = 0;
 337            break;
 338        }
 339
 340        /* fully inside */
 341        const uint8_t a_field =
 342            pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
 343
 344        /*
 345         * Convert the PMP permissions to match the truth table in the
 346         * ePMP spec.
 347         */
 348        const uint8_t epmp_operation =
 349            ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) |
 350            ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) |
 351            (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) |
 352            ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2);
 353
 354        if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
 355            /*
 356             * If the PMP entry is not off and the address is in range,
 357             * do the priv check
 358             */
 359            if (!MSECCFG_MML_ISSET(env)) {
 360                /*
 361                 * If mseccfg.MML Bit is not set, do pmp priv check
 362                 * This will always apply to regular PMP.
 363                 */
 364                *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
 365                if ((mode != PRV_M) || pmp_is_locked(env, i)) {
 366                    *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
 367                }
 368            } else {
 369                /*
 370                 * If mseccfg.MML Bit set, do the enhanced pmp priv check
 371                 */
 372                if (mode == PRV_M) {
 373                    switch (epmp_operation) {
 374                    case 0:
 375                    case 1:
 376                    case 4:
 377                    case 5:
 378                    case 6:
 379                    case 7:
 380                    case 8:
 381                        *allowed_privs = 0;
 382                        break;
 383                    case 2:
 384                    case 3:
 385                    case 14:
 386                        *allowed_privs = PMP_READ | PMP_WRITE;
 387                        break;
 388                    case 9:
 389                    case 10:
 390                        *allowed_privs = PMP_EXEC;
 391                        break;
 392                    case 11:
 393                    case 13:
 394                        *allowed_privs = PMP_READ | PMP_EXEC;
 395                        break;
 396                    case 12:
 397                    case 15:
 398                        *allowed_privs = PMP_READ;
 399                        break;
 400                    default:
 401                        g_assert_not_reached();
 402                    }
 403                } else {
 404                    switch (epmp_operation) {
 405                    case 0:
 406                    case 8:
 407                    case 9:
 408                    case 12:
 409                    case 13:
 410                    case 14:
 411                        *allowed_privs = 0;
 412                        break;
 413                    case 1:
 414                    case 10:
 415                    case 11:
 416                        *allowed_privs = PMP_EXEC;
 417                        break;
 418                    case 2:
 419                    case 4:
 420                    case 15:
 421                        *allowed_privs = PMP_READ;
 422                        break;
 423                    case 3:
 424                    case 6:
 425                        *allowed_privs = PMP_READ | PMP_WRITE;
 426                        break;
 427                    case 5:
 428                        *allowed_privs = PMP_READ | PMP_EXEC;
 429                        break;
 430                    case 7:
 431                        *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
 432                        break;
 433                    default:
 434                        g_assert_not_reached();
 435                    }
 436                }
 437            }
 438
 439            ret = ((privs & *allowed_privs) == privs);
 440            break;
 441        }
 442    }
 443
 444    /* No rule matched */
 445    if (ret == -1) {
 446        return pmp_hart_has_privs_default(env, addr, size, privs,
 447                                          allowed_privs, mode);
 448    }
 449
 450    return ret == 1 ? true : false;
 451}
 452
 453/*
 454 * Handle a write to a pmpcfg CSR
 455 */
 456void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
 457    target_ulong val)
 458{
 459    int i;
 460    uint8_t cfg_val;
 461    int pmpcfg_nums = 2 << riscv_cpu_mxl(env);
 462
 463    trace_pmpcfg_csr_write(env->mhartid, reg_index, val);
 464
 465    for (i = 0; i < pmpcfg_nums; i++) {
 466        cfg_val = (val >> 8 * i)  & 0xff;
 467        pmp_write_cfg(env, (reg_index * 4) + i, cfg_val);
 468    }
 469
 470    /* If PMP permission of any addr has been changed, flush TLB pages. */
 471    tlb_flush(env_cpu(env));
 472}
 473
 474
 475/*
 476 * Handle a read from a pmpcfg CSR
 477 */
 478target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index)
 479{
 480    int i;
 481    target_ulong cfg_val = 0;
 482    target_ulong val = 0;
 483    int pmpcfg_nums = 2 << riscv_cpu_mxl(env);
 484
 485    for (i = 0; i < pmpcfg_nums; i++) {
 486        val = pmp_read_cfg(env, (reg_index * 4) + i);
 487        cfg_val |= (val << (i * 8));
 488    }
 489    trace_pmpcfg_csr_read(env->mhartid, reg_index, cfg_val);
 490
 491    return cfg_val;
 492}
 493
 494
 495/*
 496 * Handle a write to a pmpaddr CSR
 497 */
 498void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
 499    target_ulong val)
 500{
 501    trace_pmpaddr_csr_write(env->mhartid, addr_index, val);
 502
 503    if (addr_index < MAX_RISCV_PMPS) {
 504        /*
 505         * In TOR mode, need to check the lock bit of the next pmp
 506         * (if there is a next).
 507         */
 508        if (addr_index + 1 < MAX_RISCV_PMPS) {
 509            uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
 510
 511            if (pmp_cfg & PMP_LOCK &&
 512                PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg)) {
 513                qemu_log_mask(LOG_GUEST_ERROR,
 514                              "ignoring pmpaddr write - pmpcfg + 1 locked\n");
 515                return;
 516            }
 517        }
 518
 519        if (!pmp_is_locked(env, addr_index)) {
 520            env->pmp_state.pmp[addr_index].addr_reg = val;
 521            pmp_update_rule(env, addr_index);
 522        } else {
 523            qemu_log_mask(LOG_GUEST_ERROR,
 524                          "ignoring pmpaddr write - locked\n");
 525        }
 526    } else {
 527        qemu_log_mask(LOG_GUEST_ERROR,
 528                      "ignoring pmpaddr write - out of bounds\n");
 529    }
 530}
 531
 532
 533/*
 534 * Handle a read from a pmpaddr CSR
 535 */
 536target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
 537{
 538    target_ulong val = 0;
 539
 540    if (addr_index < MAX_RISCV_PMPS) {
 541        val = env->pmp_state.pmp[addr_index].addr_reg;
 542        trace_pmpaddr_csr_read(env->mhartid, addr_index, val);
 543    } else {
 544        qemu_log_mask(LOG_GUEST_ERROR,
 545                      "ignoring pmpaddr read - out of bounds\n");
 546    }
 547
 548    return val;
 549}
 550
 551/*
 552 * Handle a write to a mseccfg CSR
 553 */
 554void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
 555{
 556    int i;
 557
 558    trace_mseccfg_csr_write(env->mhartid, val);
 559
 560    /* RLB cannot be enabled if it's already 0 and if any regions are locked */
 561    if (!MSECCFG_RLB_ISSET(env)) {
 562        for (i = 0; i < MAX_RISCV_PMPS; i++) {
 563            if (pmp_is_locked(env, i)) {
 564                val &= ~MSECCFG_RLB;
 565                break;
 566            }
 567        }
 568    }
 569
 570    /* Sticky bits */
 571    val |= (env->mseccfg & (MSECCFG_MMWP | MSECCFG_MML));
 572
 573    env->mseccfg = val;
 574}
 575
 576/*
 577 * Handle a read from a mseccfg CSR
 578 */
 579target_ulong mseccfg_csr_read(CPURISCVState *env)
 580{
 581    trace_mseccfg_csr_read(env->mhartid, env->mseccfg);
 582    return env->mseccfg;
 583}
 584
 585/*
 586 * Calculate the TLB size if the start address or the end address of
 587 * PMP entry is presented in the TLB page.
 588 */
 589static target_ulong pmp_get_tlb_size(CPURISCVState *env, int pmp_index,
 590                                     target_ulong tlb_sa, target_ulong tlb_ea)
 591{
 592    target_ulong pmp_sa = env->pmp_state.addr[pmp_index].sa;
 593    target_ulong pmp_ea = env->pmp_state.addr[pmp_index].ea;
 594
 595    if (pmp_sa >= tlb_sa && pmp_ea <= tlb_ea) {
 596        return pmp_ea - pmp_sa + 1;
 597    }
 598
 599    if (pmp_sa >= tlb_sa && pmp_sa <= tlb_ea && pmp_ea >= tlb_ea) {
 600        return tlb_ea - pmp_sa + 1;
 601    }
 602
 603    if (pmp_ea <= tlb_ea && pmp_ea >= tlb_sa && pmp_sa <= tlb_sa) {
 604        return pmp_ea - tlb_sa + 1;
 605    }
 606
 607    return 0;
 608}
 609
 610/*
 611 * Check is there a PMP entry which range covers this page. If so,
 612 * try to find the minimum granularity for the TLB size.
 613 */
 614bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa,
 615                         target_ulong *tlb_size)
 616{
 617    int i;
 618    target_ulong val;
 619    target_ulong tlb_ea = (tlb_sa + TARGET_PAGE_SIZE - 1);
 620
 621    for (i = 0; i < MAX_RISCV_PMPS; i++) {
 622        val = pmp_get_tlb_size(env, i, tlb_sa, tlb_ea);
 623        if (val) {
 624            if (*tlb_size == 0 || *tlb_size > val) {
 625                *tlb_size = val;
 626            }
 627        }
 628    }
 629
 630    if (*tlb_size != 0) {
 631        return true;
 632    }
 633
 634    return false;
 635}
 636
 637/*
 638 * Convert PMP privilege to TLB page privilege.
 639 */
 640int pmp_priv_to_page_prot(pmp_priv_t pmp_priv)
 641{
 642    int prot = 0;
 643
 644    if (pmp_priv & PMP_READ) {
 645        prot |= PAGE_READ;
 646    }
 647    if (pmp_priv & PMP_WRITE) {
 648        prot |= PAGE_WRITE;
 649    }
 650    if (pmp_priv & PMP_EXEC) {
 651        prot |= PAGE_EXEC;
 652    }
 653
 654    return prot;
 655}
 656