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

helper.c (10172B)


      1/*
      2 * Altera Nios II helper routines.
      3 *
      4 * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com>
      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
     18 * <http://www.gnu.org/licenses/lgpl-2.1.html>
     19 */
     20
     21#include "qemu/osdep.h"
     22
     23#include "cpu.h"
     24#include "qemu/host-utils.h"
     25#include "exec/exec-all.h"
     26#include "exec/cpu_ldst.h"
     27#include "exec/log.h"
     28#include "exec/helper-proto.h"
     29#include "semihosting/semihost.h"
     30
     31#if defined(CONFIG_USER_ONLY)
     32
     33void nios2_cpu_do_interrupt(CPUState *cs)
     34{
     35    Nios2CPU *cpu = NIOS2_CPU(cs);
     36    CPUNios2State *env = &cpu->env;
     37    cs->exception_index = -1;
     38    env->regs[R_EA] = env->regs[R_PC] + 4;
     39}
     40
     41bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     42                        MMUAccessType access_type, int mmu_idx,
     43                        bool probe, uintptr_t retaddr)
     44{
     45    cs->exception_index = 0xaa;
     46    cpu_loop_exit_restore(cs, retaddr);
     47}
     48
     49#else /* !CONFIG_USER_ONLY */
     50
     51void nios2_cpu_do_interrupt(CPUState *cs)
     52{
     53    Nios2CPU *cpu = NIOS2_CPU(cs);
     54    CPUNios2State *env = &cpu->env;
     55
     56    switch (cs->exception_index) {
     57    case EXCP_IRQ:
     58        assert(env->regs[CR_STATUS] & CR_STATUS_PIE);
     59
     60        qemu_log_mask(CPU_LOG_INT, "interrupt at pc=%x\n", env->regs[R_PC]);
     61
     62        env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
     63        env->regs[CR_STATUS] |= CR_STATUS_IH;
     64        env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
     65
     66        env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
     67        env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
     68
     69        env->regs[R_EA] = env->regs[R_PC] + 4;
     70        env->regs[R_PC] = cpu->exception_addr;
     71        break;
     72
     73    case EXCP_TLBD:
     74        if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
     75            qemu_log_mask(CPU_LOG_INT, "TLB MISS (fast) at pc=%x\n",
     76                          env->regs[R_PC]);
     77
     78            /* Fast TLB miss */
     79            /* Variation from the spec. Table 3-35 of the cpu reference shows
     80             * estatus not being changed for TLB miss but this appears to
     81             * be incorrect. */
     82            env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
     83            env->regs[CR_STATUS] |= CR_STATUS_EH;
     84            env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
     85
     86            env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
     87            env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
     88
     89            env->regs[CR_TLBMISC] &= ~CR_TLBMISC_DBL;
     90            env->regs[CR_TLBMISC] |= CR_TLBMISC_WR;
     91
     92            env->regs[R_EA] = env->regs[R_PC] + 4;
     93            env->regs[R_PC] = cpu->fast_tlb_miss_addr;
     94        } else {
     95            qemu_log_mask(CPU_LOG_INT, "TLB MISS (double) at pc=%x\n",
     96                          env->regs[R_PC]);
     97
     98            /* Double TLB miss */
     99            env->regs[CR_STATUS] |= CR_STATUS_EH;
    100            env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
    101
    102            env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
    103            env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
    104
    105            env->regs[CR_TLBMISC] |= CR_TLBMISC_DBL;
    106
    107            env->regs[R_PC] = cpu->exception_addr;
    108        }
    109        break;
    110
    111    case EXCP_TLBR:
    112    case EXCP_TLBW:
    113    case EXCP_TLBX:
    114        qemu_log_mask(CPU_LOG_INT, "TLB PERM at pc=%x\n", env->regs[R_PC]);
    115
    116        env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
    117        env->regs[CR_STATUS] |= CR_STATUS_EH;
    118        env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
    119
    120        env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
    121        env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
    122
    123        if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
    124            env->regs[CR_TLBMISC] |= CR_TLBMISC_WR;
    125        }
    126
    127        env->regs[R_EA] = env->regs[R_PC] + 4;
    128        env->regs[R_PC] = cpu->exception_addr;
    129        break;
    130
    131    case EXCP_SUPERA:
    132    case EXCP_SUPERI:
    133    case EXCP_SUPERD:
    134        qemu_log_mask(CPU_LOG_INT, "SUPERVISOR exception at pc=%x\n",
    135                      env->regs[R_PC]);
    136
    137        if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
    138            env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
    139            env->regs[R_EA] = env->regs[R_PC] + 4;
    140        }
    141
    142        env->regs[CR_STATUS] |= CR_STATUS_EH;
    143        env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
    144
    145        env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
    146        env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
    147
    148        env->regs[R_PC] = cpu->exception_addr;
    149        break;
    150
    151    case EXCP_ILLEGAL:
    152    case EXCP_TRAP:
    153        qemu_log_mask(CPU_LOG_INT, "TRAP exception at pc=%x\n",
    154                      env->regs[R_PC]);
    155
    156        if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
    157            env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
    158            env->regs[R_EA] = env->regs[R_PC] + 4;
    159        }
    160
    161        env->regs[CR_STATUS] |= CR_STATUS_EH;
    162        env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
    163
    164        env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
    165        env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
    166
    167        env->regs[R_PC] = cpu->exception_addr;
    168        break;
    169
    170    case EXCP_BREAK:
    171        qemu_log_mask(CPU_LOG_INT, "BREAK exception at pc=%x\n",
    172                      env->regs[R_PC]);
    173        /* The semihosting instruction is "break 1".  */
    174        if (semihosting_enabled() &&
    175            cpu_ldl_code(env, env->regs[R_PC]) == 0x003da07a)  {
    176            qemu_log_mask(CPU_LOG_INT, "Entering semihosting\n");
    177            env->regs[R_PC] += 4;
    178            do_nios2_semihosting(env);
    179            break;
    180        }
    181
    182        if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
    183            env->regs[CR_BSTATUS] = env->regs[CR_STATUS];
    184            env->regs[R_BA] = env->regs[R_PC] + 4;
    185        }
    186
    187        env->regs[CR_STATUS] |= CR_STATUS_EH;
    188        env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
    189
    190        env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
    191        env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
    192
    193        env->regs[R_PC] = cpu->exception_addr;
    194        break;
    195
    196    default:
    197        cpu_abort(cs, "unhandled exception type=%d\n",
    198                  cs->exception_index);
    199        break;
    200    }
    201}
    202
    203hwaddr nios2_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
    204{
    205    Nios2CPU *cpu = NIOS2_CPU(cs);
    206    CPUNios2State *env = &cpu->env;
    207    target_ulong vaddr, paddr = 0;
    208    Nios2MMULookup lu;
    209    unsigned int hit;
    210
    211    if (cpu->mmu_present && (addr < 0xC0000000)) {
    212        hit = mmu_translate(env, &lu, addr, 0, 0);
    213        if (hit) {
    214            vaddr = addr & TARGET_PAGE_MASK;
    215            paddr = lu.paddr + vaddr - lu.vaddr;
    216        } else {
    217            paddr = -1;
    218            qemu_log("cpu_get_phys_page debug MISS: %#" PRIx64 "\n", addr);
    219        }
    220    } else {
    221        paddr = addr & TARGET_PAGE_MASK;
    222    }
    223
    224    return paddr;
    225}
    226
    227void nios2_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
    228                                   MMUAccessType access_type,
    229                                   int mmu_idx, uintptr_t retaddr)
    230{
    231    Nios2CPU *cpu = NIOS2_CPU(cs);
    232    CPUNios2State *env = &cpu->env;
    233
    234    env->regs[CR_BADADDR] = addr;
    235    env->regs[CR_EXCEPTION] = EXCP_UNALIGN << 2;
    236    helper_raise_exception(env, EXCP_UNALIGN);
    237}
    238
    239bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
    240                        MMUAccessType access_type, int mmu_idx,
    241                        bool probe, uintptr_t retaddr)
    242{
    243    Nios2CPU *cpu = NIOS2_CPU(cs);
    244    CPUNios2State *env = &cpu->env;
    245    unsigned int excp = EXCP_TLBD;
    246    target_ulong vaddr, paddr;
    247    Nios2MMULookup lu;
    248    unsigned int hit;
    249
    250    if (!cpu->mmu_present) {
    251        /* No MMU */
    252        address &= TARGET_PAGE_MASK;
    253        tlb_set_page(cs, address, address, PAGE_BITS,
    254                     mmu_idx, TARGET_PAGE_SIZE);
    255        return true;
    256    }
    257
    258    if (MMU_SUPERVISOR_IDX == mmu_idx) {
    259        if (address >= 0xC0000000) {
    260            /* Kernel physical page - TLB bypassed */
    261            address &= TARGET_PAGE_MASK;
    262            tlb_set_page(cs, address, address, PAGE_BITS,
    263                         mmu_idx, TARGET_PAGE_SIZE);
    264            return true;
    265        }
    266    } else {
    267        if (address >= 0x80000000) {
    268            /* Illegal access from user mode */
    269            if (probe) {
    270                return false;
    271            }
    272            cs->exception_index = EXCP_SUPERA;
    273            env->regs[CR_BADADDR] = address;
    274            cpu_loop_exit_restore(cs, retaddr);
    275        }
    276    }
    277
    278    /* Virtual page.  */
    279    hit = mmu_translate(env, &lu, address, access_type, mmu_idx);
    280    if (hit) {
    281        vaddr = address & TARGET_PAGE_MASK;
    282        paddr = lu.paddr + vaddr - lu.vaddr;
    283
    284        if (((access_type == MMU_DATA_LOAD) && (lu.prot & PAGE_READ)) ||
    285            ((access_type == MMU_DATA_STORE) && (lu.prot & PAGE_WRITE)) ||
    286            ((access_type == MMU_INST_FETCH) && (lu.prot & PAGE_EXEC))) {
    287            tlb_set_page(cs, vaddr, paddr, lu.prot,
    288                         mmu_idx, TARGET_PAGE_SIZE);
    289            return true;
    290        }
    291
    292        /* Permission violation */
    293        excp = (access_type == MMU_DATA_LOAD ? EXCP_TLBR :
    294                access_type == MMU_DATA_STORE ? EXCP_TLBW : EXCP_TLBX);
    295    }
    296
    297    if (probe) {
    298        return false;
    299    }
    300
    301    if (access_type == MMU_INST_FETCH) {
    302        env->regs[CR_TLBMISC] &= ~CR_TLBMISC_D;
    303    } else {
    304        env->regs[CR_TLBMISC] |= CR_TLBMISC_D;
    305    }
    306    env->regs[CR_PTEADDR] &= CR_PTEADDR_PTBASE_MASK;
    307    env->regs[CR_PTEADDR] |= (address >> 10) & CR_PTEADDR_VPN_MASK;
    308    env->mmu.pteaddr_wr = env->regs[CR_PTEADDR];
    309
    310    cs->exception_index = excp;
    311    env->regs[CR_BADADDR] = address;
    312    cpu_loop_exit_restore(cs, retaddr);
    313}
    314#endif /* !CONFIG_USER_ONLY */