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 (11731B)


      1/*
      2 * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
      3 * All rights reserved.
      4 *
      5 * Redistribution and use in source and binary forms, with or without
      6 * modification, are permitted provided that the following conditions are met:
      7 *     * Redistributions of source code must retain the above copyright
      8 *       notice, this list of conditions and the following disclaimer.
      9 *     * Redistributions in binary form must reproduce the above copyright
     10 *       notice, this list of conditions and the following disclaimer in the
     11 *       documentation and/or other materials provided with the distribution.
     12 *     * Neither the name of the Open Source and Linux Lab nor the
     13 *       names of its contributors may be used to endorse or promote products
     14 *       derived from this software without specific prior written permission.
     15 *
     16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 */
     27
     28#include "qemu/osdep.h"
     29#include "cpu.h"
     30#include "exec/exec-all.h"
     31#include "exec/gdbstub.h"
     32#include "exec/helper-proto.h"
     33#include "qemu/error-report.h"
     34#include "qemu/qemu-print.h"
     35#include "qemu/host-utils.h"
     36
     37static struct XtensaConfigList *xtensa_cores;
     38
     39static void add_translator_to_hash(GHashTable *translator,
     40                                   const char *name,
     41                                   const XtensaOpcodeOps *opcode)
     42{
     43    if (!g_hash_table_insert(translator, (void *)name, (void *)opcode)) {
     44        error_report("Multiple definitions of '%s' opcode in a single table",
     45                     name);
     46    }
     47}
     48
     49static GHashTable *hash_opcode_translators(const XtensaOpcodeTranslators *t)
     50{
     51    unsigned i, j;
     52    GHashTable *translator = g_hash_table_new(g_str_hash, g_str_equal);
     53
     54    for (i = 0; i < t->num_opcodes; ++i) {
     55        if (t->opcode[i].op_flags & XTENSA_OP_NAME_ARRAY) {
     56            const char * const *name = t->opcode[i].name;
     57
     58            for (j = 0; name[j]; ++j) {
     59                add_translator_to_hash(translator,
     60                                       (void *)name[j],
     61                                       (void *)(t->opcode + i));
     62            }
     63        } else {
     64            add_translator_to_hash(translator,
     65                                   (void *)t->opcode[i].name,
     66                                   (void *)(t->opcode + i));
     67        }
     68    }
     69    return translator;
     70}
     71
     72static XtensaOpcodeOps *
     73xtensa_find_opcode_ops(const XtensaOpcodeTranslators *t,
     74                       const char *name)
     75{
     76    static GHashTable *translators;
     77    GHashTable *translator;
     78
     79    if (translators == NULL) {
     80        translators = g_hash_table_new(g_direct_hash, g_direct_equal);
     81    }
     82    translator = g_hash_table_lookup(translators, t);
     83    if (translator == NULL) {
     84        translator = hash_opcode_translators(t);
     85        g_hash_table_insert(translators, (void *)t, translator);
     86    }
     87    return g_hash_table_lookup(translator, name);
     88}
     89
     90static void init_libisa(XtensaConfig *config)
     91{
     92    unsigned i, j;
     93    unsigned opcodes;
     94    unsigned formats;
     95    unsigned regfiles;
     96
     97    config->isa = xtensa_isa_init(config->isa_internal, NULL, NULL);
     98    assert(xtensa_isa_maxlength(config->isa) <= MAX_INSN_LENGTH);
     99    assert(xtensa_insnbuf_size(config->isa) <= MAX_INSNBUF_LENGTH);
    100    opcodes = xtensa_isa_num_opcodes(config->isa);
    101    formats = xtensa_isa_num_formats(config->isa);
    102    regfiles = xtensa_isa_num_regfiles(config->isa);
    103    config->opcode_ops = g_new(XtensaOpcodeOps *, opcodes);
    104
    105    for (i = 0; i < formats; ++i) {
    106        assert(xtensa_format_num_slots(config->isa, i) <= MAX_INSN_SLOTS);
    107    }
    108
    109    for (i = 0; i < opcodes; ++i) {
    110        const char *opc_name = xtensa_opcode_name(config->isa, i);
    111        XtensaOpcodeOps *ops = NULL;
    112
    113        assert(xtensa_opcode_num_operands(config->isa, i) <= MAX_OPCODE_ARGS);
    114        if (!config->opcode_translators) {
    115            ops = xtensa_find_opcode_ops(&xtensa_core_opcodes, opc_name);
    116        } else {
    117            for (j = 0; !ops && config->opcode_translators[j]; ++j) {
    118                ops = xtensa_find_opcode_ops(config->opcode_translators[j],
    119                                             opc_name);
    120            }
    121        }
    122#ifdef DEBUG
    123        if (ops == NULL) {
    124            fprintf(stderr,
    125                    "opcode translator not found for %s's opcode '%s'\n",
    126                    config->name, opc_name);
    127        }
    128#endif
    129        config->opcode_ops[i] = ops;
    130    }
    131    config->a_regfile = xtensa_regfile_lookup(config->isa, "AR");
    132
    133    config->regfile = g_new(void **, regfiles);
    134    for (i = 0; i < regfiles; ++i) {
    135        const char *name = xtensa_regfile_name(config->isa, i);
    136        int entries = xtensa_regfile_num_entries(config->isa, i);
    137        int bits = xtensa_regfile_num_bits(config->isa, i);
    138
    139        config->regfile[i] = xtensa_get_regfile_by_name(name, entries, bits);
    140#ifdef DEBUG
    141        if (config->regfile[i] == NULL) {
    142            fprintf(stderr, "regfile '%s' not found for %s\n",
    143                    name, config->name);
    144        }
    145#endif
    146    }
    147    xtensa_collect_sr_names(config);
    148}
    149
    150static void xtensa_finalize_config(XtensaConfig *config)
    151{
    152    if (config->isa_internal) {
    153        init_libisa(config);
    154    }
    155
    156    if (config->gdb_regmap.num_regs == 0 ||
    157        config->gdb_regmap.num_core_regs == 0) {
    158        unsigned n_regs = 0;
    159        unsigned n_core_regs = 0;
    160
    161        xtensa_count_regs(config, &n_regs, &n_core_regs);
    162        if (config->gdb_regmap.num_regs == 0) {
    163            config->gdb_regmap.num_regs = n_regs;
    164        }
    165        if (config->gdb_regmap.num_core_regs == 0) {
    166            config->gdb_regmap.num_core_regs = n_core_regs;
    167        }
    168    }
    169}
    170
    171static void xtensa_core_class_init(ObjectClass *oc, void *data)
    172{
    173    CPUClass *cc = CPU_CLASS(oc);
    174    XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc);
    175    XtensaConfig *config = data;
    176
    177    xtensa_finalize_config(config);
    178    xcc->config = config;
    179
    180    /*
    181     * Use num_core_regs to see only non-privileged registers in an unmodified
    182     * gdb. Use num_regs to see all registers. gdb modification is required
    183     * for that: reset bit 0 in the 'flags' field of the registers definitions
    184     * in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
    185     */
    186    cc->gdb_num_core_regs = config->gdb_regmap.num_regs;
    187}
    188
    189void xtensa_register_core(XtensaConfigList *node)
    190{
    191    TypeInfo type = {
    192        .parent = TYPE_XTENSA_CPU,
    193        .class_init = xtensa_core_class_init,
    194        .class_data = (void *)node->config,
    195    };
    196
    197    node->next = xtensa_cores;
    198    xtensa_cores = node;
    199    type.name = g_strdup_printf(XTENSA_CPU_TYPE_NAME("%s"), node->config->name);
    200    type_register(&type);
    201    g_free((gpointer)type.name);
    202}
    203
    204static uint32_t check_hw_breakpoints(CPUXtensaState *env)
    205{
    206    unsigned i;
    207
    208    for (i = 0; i < env->config->ndbreak; ++i) {
    209        if (env->cpu_watchpoint[i] &&
    210                env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
    211            return DEBUGCAUSE_DB | (i << DEBUGCAUSE_DBNUM_SHIFT);
    212        }
    213    }
    214    return 0;
    215}
    216
    217void xtensa_breakpoint_handler(CPUState *cs)
    218{
    219    XtensaCPU *cpu = XTENSA_CPU(cs);
    220    CPUXtensaState *env = &cpu->env;
    221
    222    if (cs->watchpoint_hit) {
    223        if (cs->watchpoint_hit->flags & BP_CPU) {
    224            uint32_t cause;
    225
    226            cs->watchpoint_hit = NULL;
    227            cause = check_hw_breakpoints(env);
    228            if (cause) {
    229                debug_exception_env(env, cause);
    230            }
    231            cpu_loop_exit_noexc(cs);
    232        }
    233    }
    234}
    235
    236void xtensa_cpu_list(void)
    237{
    238    XtensaConfigList *core = xtensa_cores;
    239    qemu_printf("Available CPUs:\n");
    240    for (; core; core = core->next) {
    241        qemu_printf("  %s\n", core->config->name);
    242    }
    243}
    244
    245#ifdef CONFIG_USER_ONLY
    246
    247bool xtensa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
    248                         MMUAccessType access_type, int mmu_idx,
    249                         bool probe, uintptr_t retaddr)
    250{
    251    XtensaCPU *cpu = XTENSA_CPU(cs);
    252    CPUXtensaState *env = &cpu->env;
    253
    254    qemu_log_mask(CPU_LOG_INT,
    255                  "%s: rw = %d, address = 0x%08" VADDR_PRIx ", size = %d\n",
    256                  __func__, access_type, address, size);
    257    env->sregs[EXCVADDR] = address;
    258    env->sregs[EXCCAUSE] = (access_type == MMU_DATA_STORE ?
    259                            STORE_PROHIBITED_CAUSE : LOAD_PROHIBITED_CAUSE);
    260    cs->exception_index = EXC_USER;
    261    cpu_loop_exit_restore(cs, retaddr);
    262}
    263
    264#else /* !CONFIG_USER_ONLY */
    265
    266void xtensa_cpu_do_unaligned_access(CPUState *cs,
    267                                    vaddr addr, MMUAccessType access_type,
    268                                    int mmu_idx, uintptr_t retaddr)
    269{
    270    XtensaCPU *cpu = XTENSA_CPU(cs);
    271    CPUXtensaState *env = &cpu->env;
    272
    273    assert(xtensa_option_enabled(env->config,
    274                                 XTENSA_OPTION_UNALIGNED_EXCEPTION));
    275    cpu_restore_state(CPU(cpu), retaddr, true);
    276    HELPER(exception_cause_vaddr)(env,
    277                                  env->pc, LOAD_STORE_ALIGNMENT_CAUSE,
    278                                  addr);
    279}
    280
    281bool xtensa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
    282                         MMUAccessType access_type, int mmu_idx,
    283                         bool probe, uintptr_t retaddr)
    284{
    285    XtensaCPU *cpu = XTENSA_CPU(cs);
    286    CPUXtensaState *env = &cpu->env;
    287    uint32_t paddr;
    288    uint32_t page_size;
    289    unsigned access;
    290    int ret = xtensa_get_physical_addr(env, true, address, access_type,
    291                                       mmu_idx, &paddr, &page_size, &access);
    292
    293    qemu_log_mask(CPU_LOG_MMU, "%s(%08" VADDR_PRIx
    294                  ", %d, %d) -> %08x, ret = %d\n",
    295                  __func__, address, access_type, mmu_idx, paddr, ret);
    296
    297    if (ret == 0) {
    298        tlb_set_page(cs,
    299                     address & TARGET_PAGE_MASK,
    300                     paddr & TARGET_PAGE_MASK,
    301                     access, mmu_idx, page_size);
    302        return true;
    303    } else if (probe) {
    304        return false;
    305    } else {
    306        cpu_restore_state(cs, retaddr, true);
    307        HELPER(exception_cause_vaddr)(env, env->pc, ret, address);
    308    }
    309}
    310
    311void xtensa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
    312                                      unsigned size, MMUAccessType access_type,
    313                                      int mmu_idx, MemTxAttrs attrs,
    314                                      MemTxResult response, uintptr_t retaddr)
    315{
    316    XtensaCPU *cpu = XTENSA_CPU(cs);
    317    CPUXtensaState *env = &cpu->env;
    318
    319    cpu_restore_state(cs, retaddr, true);
    320    HELPER(exception_cause_vaddr)(env, env->pc,
    321                                  access_type == MMU_INST_FETCH ?
    322                                  INSTR_PIF_ADDR_ERROR_CAUSE :
    323                                  LOAD_STORE_PIF_ADDR_ERROR_CAUSE,
    324                                  addr);
    325}
    326
    327void xtensa_runstall(CPUXtensaState *env, bool runstall)
    328{
    329    CPUState *cpu = env_cpu(env);
    330
    331    env->runstall = runstall;
    332    cpu->halted = runstall;
    333    if (runstall) {
    334        cpu_interrupt(cpu, CPU_INTERRUPT_HALT);
    335    } else {
    336        qemu_cpu_kick(cpu);
    337    }
    338}
    339#endif /* !CONFIG_USER_ONLY */