cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

mmu.c (6013B)


      1/*
      2 * OpenRISC MMU.
      3 *
      4 * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
      5 *                         Zhizhou Zhang <etouzh@gmail.com>
      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 "exec/gdbstub.h"
     25#include "qemu/host-utils.h"
     26#ifndef CONFIG_USER_ONLY
     27#include "hw/loader.h"
     28#endif
     29
     30#ifndef CONFIG_USER_ONLY
     31static inline void get_phys_nommu(hwaddr *phys_addr, int *prot,
     32                                  target_ulong address)
     33{
     34    *phys_addr = address;
     35    *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
     36}
     37
     38static int get_phys_mmu(OpenRISCCPU *cpu, hwaddr *phys_addr, int *prot,
     39                        target_ulong addr, int need, bool super)
     40{
     41    int idx = (addr >> TARGET_PAGE_BITS) & TLB_MASK;
     42    uint32_t imr = cpu->env.tlb.itlb[idx].mr;
     43    uint32_t itr = cpu->env.tlb.itlb[idx].tr;
     44    uint32_t dmr = cpu->env.tlb.dtlb[idx].mr;
     45    uint32_t dtr = cpu->env.tlb.dtlb[idx].tr;
     46    int right, match, valid;
     47
     48    /* If the ITLB and DTLB indexes map to the same page, we want to
     49       load all permissions all at once.  If the destination pages do
     50       not match, zap the one we don't need.  */
     51    if (unlikely((itr ^ dtr) & TARGET_PAGE_MASK)) {
     52        if (need & PAGE_EXEC) {
     53            dmr = dtr = 0;
     54        } else {
     55            imr = itr = 0;
     56        }
     57    }
     58
     59    /* Check if either of the entries matches the source address.  */
     60    match  = (imr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_EXEC;
     61    match |= (dmr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_READ | PAGE_WRITE;
     62
     63    /* Check if either of the entries is valid.  */
     64    valid  = imr & 1 ? PAGE_EXEC : 0;
     65    valid |= dmr & 1 ? PAGE_READ | PAGE_WRITE : 0;
     66    valid &= match;
     67
     68    /* Collect the permissions from the entries.  */
     69    right  = itr & (super ? SXE : UXE) ? PAGE_EXEC : 0;
     70    right |= dtr & (super ? SRE : URE) ? PAGE_READ : 0;
     71    right |= dtr & (super ? SWE : UWE) ? PAGE_WRITE : 0;
     72    right &= valid;
     73
     74    /* Note that above we validated that itr and dtr match on page.
     75       So oring them together changes nothing without having to
     76       check which one we needed.  We also want to store to these
     77       variables even on failure, as it avoids compiler warnings.  */
     78    *phys_addr = ((itr | dtr) & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK);
     79    *prot = right;
     80
     81    qemu_log_mask(CPU_LOG_MMU,
     82                  "MMU lookup: need %d match %d valid %d right %d -> %s\n",
     83                  need, match, valid, right, (need & right) ? "OK" : "FAIL");
     84
     85    /* Check the collective permissions are present.  */
     86    if (likely(need & right)) {
     87        return 0;  /* success! */
     88    }
     89
     90    /* Determine what kind of failure we have.  */
     91    if (need & valid) {
     92        return need & PAGE_EXEC ? EXCP_IPF : EXCP_DPF;
     93    } else {
     94        return need & PAGE_EXEC ? EXCP_ITLBMISS : EXCP_DTLBMISS;
     95    }
     96}
     97#endif
     98
     99static void raise_mmu_exception(OpenRISCCPU *cpu, target_ulong address,
    100                                int exception)
    101{
    102    CPUState *cs = CPU(cpu);
    103
    104    cs->exception_index = exception;
    105    cpu->env.eear = address;
    106    cpu->env.lock_addr = -1;
    107}
    108
    109bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
    110                           MMUAccessType access_type, int mmu_idx,
    111                           bool probe, uintptr_t retaddr)
    112{
    113    OpenRISCCPU *cpu = OPENRISC_CPU(cs);
    114    int excp = EXCP_DPF;
    115
    116#ifndef CONFIG_USER_ONLY
    117    int prot;
    118    hwaddr phys_addr;
    119
    120    if (mmu_idx == MMU_NOMMU_IDX) {
    121        /* The mmu is disabled; lookups never fail.  */
    122        get_phys_nommu(&phys_addr, &prot, addr);
    123        excp = 0;
    124    } else {
    125        bool super = mmu_idx == MMU_SUPERVISOR_IDX;
    126        int need = (access_type == MMU_INST_FETCH ? PAGE_EXEC
    127                    : access_type == MMU_DATA_STORE ? PAGE_WRITE
    128                    : PAGE_READ);
    129        excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, need, super);
    130    }
    131
    132    if (likely(excp == 0)) {
    133        tlb_set_page(cs, addr & TARGET_PAGE_MASK,
    134                     phys_addr & TARGET_PAGE_MASK, prot,
    135                     mmu_idx, TARGET_PAGE_SIZE);
    136        return true;
    137    }
    138    if (probe) {
    139        return false;
    140    }
    141#endif
    142
    143    raise_mmu_exception(cpu, addr, excp);
    144    cpu_loop_exit_restore(cs, retaddr);
    145}
    146
    147#ifndef CONFIG_USER_ONLY
    148hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
    149{
    150    OpenRISCCPU *cpu = OPENRISC_CPU(cs);
    151    int prot, excp, sr = cpu->env.sr;
    152    hwaddr phys_addr;
    153
    154    switch (sr & (SR_DME | SR_IME)) {
    155    case SR_DME | SR_IME:
    156        /* The mmu is definitely enabled.  */
    157        excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
    158                            PAGE_EXEC | PAGE_READ | PAGE_WRITE,
    159                            (sr & SR_SM) != 0);
    160        return excp ? -1 : phys_addr;
    161
    162    default:
    163        /* The mmu is partially enabled, and we don't really have
    164           a "real" access type.  Begin by trying the mmu, but if
    165           that fails try again without.  */
    166        excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
    167                            PAGE_EXEC | PAGE_READ | PAGE_WRITE,
    168                            (sr & SR_SM) != 0);
    169        if (!excp) {
    170            return phys_addr;
    171        }
    172        /* fallthru */
    173
    174    case 0:
    175        /* The mmu is definitely disabled; lookups never fail.  */
    176        get_phys_nommu(&phys_addr, &prot, addr);
    177        return phys_addr;
    178    }
    179}
    180#endif