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

cpu.c (9713B)


      1/*
      2 *  Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
      3 *
      4 *  This program is free software; you can redistribute it and/or modify
      5 *  it under the terms of the GNU General Public License as published by
      6 *  the Free Software Foundation; either version 2 of the License, or
      7 *  (at your option) any later version.
      8 *
      9 *  This program is distributed in the hope that it will be useful,
     10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 *  GNU General Public License for more details.
     13 *
     14 *  You should have received a copy of the GNU General Public License
     15 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
     16 */
     17
     18#include "qemu/osdep.h"
     19#include "qemu/qemu-print.h"
     20#include "cpu.h"
     21#include "internal.h"
     22#include "exec/exec-all.h"
     23#include "qapi/error.h"
     24#include "hw/qdev-properties.h"
     25#include "fpu/softfloat-helpers.h"
     26
     27static void hexagon_v67_cpu_init(Object *obj)
     28{
     29}
     30
     31static ObjectClass *hexagon_cpu_class_by_name(const char *cpu_model)
     32{
     33    ObjectClass *oc;
     34    char *typename;
     35    char **cpuname;
     36
     37    cpuname = g_strsplit(cpu_model, ",", 1);
     38    typename = g_strdup_printf(HEXAGON_CPU_TYPE_NAME("%s"), cpuname[0]);
     39    oc = object_class_by_name(typename);
     40    g_strfreev(cpuname);
     41    g_free(typename);
     42    if (!oc || !object_class_dynamic_cast(oc, TYPE_HEXAGON_CPU) ||
     43        object_class_is_abstract(oc)) {
     44        return NULL;
     45    }
     46    return oc;
     47}
     48
     49static Property hexagon_lldb_compat_property =
     50    DEFINE_PROP_BOOL("lldb-compat", HexagonCPU, lldb_compat, false);
     51static Property hexagon_lldb_stack_adjust_property =
     52    DEFINE_PROP_UNSIGNED("lldb-stack-adjust", HexagonCPU, lldb_stack_adjust,
     53                         0, qdev_prop_uint32, target_ulong);
     54
     55const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = {
     56   "r0", "r1",  "r2",  "r3",  "r4",   "r5",  "r6",  "r7",
     57   "r8", "r9",  "r10", "r11", "r12",  "r13", "r14", "r15",
     58  "r16", "r17", "r18", "r19", "r20",  "r21", "r22", "r23",
     59  "r24", "r25", "r26", "r27", "r28",  "r29", "r30", "r31",
     60  "sa0", "lc0", "sa1", "lc1", "p3_0", "c5",  "m0",  "m1",
     61  "usr", "pc",  "ugp", "gp",  "cs0",  "cs1", "c14", "c15",
     62  "c16", "c17", "c18", "c19", "pkt_cnt",  "insn_cnt", "c22", "c23",
     63  "c24", "c25", "c26", "c27", "c28",  "c29", "c30", "c31",
     64};
     65
     66/*
     67 * One of the main debugging techniques is to use "-d cpu" and compare against
     68 * LLDB output when single stepping.  However, the target and qemu put the
     69 * stacks at different locations.  This is used to compensate so the diff is
     70 * cleaner.
     71 */
     72static target_ulong adjust_stack_ptrs(CPUHexagonState *env, target_ulong addr)
     73{
     74    HexagonCPU *cpu = env_archcpu(env);
     75    target_ulong stack_adjust = cpu->lldb_stack_adjust;
     76    target_ulong stack_start = env->stack_start;
     77    target_ulong stack_size = 0x10000;
     78
     79    if (stack_adjust == 0) {
     80        return addr;
     81    }
     82
     83    if (stack_start + 0x1000 >= addr && addr >= (stack_start - stack_size)) {
     84        return addr - stack_adjust;
     85    }
     86    return addr;
     87}
     88
     89/* HEX_REG_P3_0 (aka C4) is an alias for the predicate registers */
     90static target_ulong read_p3_0(CPUHexagonState *env)
     91{
     92    int32_t control_reg = 0;
     93    int i;
     94    for (i = NUM_PREGS - 1; i >= 0; i--) {
     95        control_reg <<= 8;
     96        control_reg |= env->pred[i] & 0xff;
     97    }
     98    return control_reg;
     99}
    100
    101static void print_reg(FILE *f, CPUHexagonState *env, int regnum)
    102{
    103    target_ulong value;
    104
    105    if (regnum == HEX_REG_P3_0) {
    106        value = read_p3_0(env);
    107    } else {
    108        value = regnum < 32 ? adjust_stack_ptrs(env, env->gpr[regnum])
    109                            : env->gpr[regnum];
    110    }
    111
    112    qemu_fprintf(f, "  %s = 0x" TARGET_FMT_lx "\n",
    113                 hexagon_regnames[regnum], value);
    114}
    115
    116static void hexagon_dump(CPUHexagonState *env, FILE *f)
    117{
    118    HexagonCPU *cpu = env_archcpu(env);
    119
    120    if (cpu->lldb_compat) {
    121        /*
    122         * When comparing with LLDB, it doesn't step through single-cycle
    123         * hardware loops the same way.  So, we just skip them here
    124         */
    125        if (env->gpr[HEX_REG_PC] == env->last_pc_dumped) {
    126            return;
    127        }
    128        env->last_pc_dumped = env->gpr[HEX_REG_PC];
    129    }
    130
    131    qemu_fprintf(f, "General Purpose Registers = {\n");
    132    for (int i = 0; i < 32; i++) {
    133        print_reg(f, env, i);
    134    }
    135    print_reg(f, env, HEX_REG_SA0);
    136    print_reg(f, env, HEX_REG_LC0);
    137    print_reg(f, env, HEX_REG_SA1);
    138    print_reg(f, env, HEX_REG_LC1);
    139    print_reg(f, env, HEX_REG_M0);
    140    print_reg(f, env, HEX_REG_M1);
    141    print_reg(f, env, HEX_REG_USR);
    142    print_reg(f, env, HEX_REG_P3_0);
    143    print_reg(f, env, HEX_REG_GP);
    144    print_reg(f, env, HEX_REG_UGP);
    145    print_reg(f, env, HEX_REG_PC);
    146#ifdef CONFIG_USER_ONLY
    147    /*
    148     * Not modelled in user mode, print junk to minimize the diff's
    149     * with LLDB output
    150     */
    151    qemu_fprintf(f, "  cause = 0x000000db\n");
    152    qemu_fprintf(f, "  badva = 0x00000000\n");
    153    qemu_fprintf(f, "  cs0 = 0x00000000\n");
    154    qemu_fprintf(f, "  cs1 = 0x00000000\n");
    155#else
    156    print_reg(f, env, HEX_REG_CAUSE);
    157    print_reg(f, env, HEX_REG_BADVA);
    158    print_reg(f, env, HEX_REG_CS0);
    159    print_reg(f, env, HEX_REG_CS1);
    160#endif
    161    qemu_fprintf(f, "}\n");
    162}
    163
    164static void hexagon_dump_state(CPUState *cs, FILE *f, int flags)
    165{
    166    HexagonCPU *cpu = HEXAGON_CPU(cs);
    167    CPUHexagonState *env = &cpu->env;
    168
    169    hexagon_dump(env, f);
    170}
    171
    172void hexagon_debug(CPUHexagonState *env)
    173{
    174    hexagon_dump(env, stdout);
    175}
    176
    177static void hexagon_cpu_set_pc(CPUState *cs, vaddr value)
    178{
    179    HexagonCPU *cpu = HEXAGON_CPU(cs);
    180    CPUHexagonState *env = &cpu->env;
    181    env->gpr[HEX_REG_PC] = value;
    182}
    183
    184static void hexagon_cpu_synchronize_from_tb(CPUState *cs,
    185                                            const TranslationBlock *tb)
    186{
    187    HexagonCPU *cpu = HEXAGON_CPU(cs);
    188    CPUHexagonState *env = &cpu->env;
    189    env->gpr[HEX_REG_PC] = tb->pc;
    190}
    191
    192static bool hexagon_cpu_has_work(CPUState *cs)
    193{
    194    return true;
    195}
    196
    197void restore_state_to_opc(CPUHexagonState *env, TranslationBlock *tb,
    198                          target_ulong *data)
    199{
    200    env->gpr[HEX_REG_PC] = data[0];
    201}
    202
    203static void hexagon_cpu_reset(DeviceState *dev)
    204{
    205    CPUState *cs = CPU(dev);
    206    HexagonCPU *cpu = HEXAGON_CPU(cs);
    207    HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(cpu);
    208    CPUHexagonState *env = &cpu->env;
    209
    210    mcc->parent_reset(dev);
    211
    212    set_default_nan_mode(1, &env->fp_status);
    213    set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status);
    214}
    215
    216static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info)
    217{
    218    info->print_insn = print_insn_hexagon;
    219}
    220
    221static void hexagon_cpu_realize(DeviceState *dev, Error **errp)
    222{
    223    CPUState *cs = CPU(dev);
    224    HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(dev);
    225    Error *local_err = NULL;
    226
    227    cpu_exec_realizefn(cs, &local_err);
    228    if (local_err != NULL) {
    229        error_propagate(errp, local_err);
    230        return;
    231    }
    232
    233    qemu_init_vcpu(cs);
    234    cpu_reset(cs);
    235
    236    mcc->parent_realize(dev, errp);
    237}
    238
    239static void hexagon_cpu_init(Object *obj)
    240{
    241    HexagonCPU *cpu = HEXAGON_CPU(obj);
    242
    243    cpu_set_cpustate_pointers(cpu);
    244    qdev_property_add_static(DEVICE(obj), &hexagon_lldb_compat_property);
    245    qdev_property_add_static(DEVICE(obj), &hexagon_lldb_stack_adjust_property);
    246}
    247
    248static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size,
    249                             MMUAccessType access_type, int mmu_idx,
    250                             bool probe, uintptr_t retaddr)
    251{
    252#ifdef CONFIG_USER_ONLY
    253    switch (access_type) {
    254    case MMU_INST_FETCH:
    255        cs->exception_index = HEX_EXCP_FETCH_NO_UPAGE;
    256        break;
    257    case MMU_DATA_LOAD:
    258        cs->exception_index = HEX_EXCP_PRIV_NO_UREAD;
    259        break;
    260    case MMU_DATA_STORE:
    261        cs->exception_index = HEX_EXCP_PRIV_NO_UWRITE;
    262        break;
    263    }
    264    cpu_loop_exit_restore(cs, retaddr);
    265#else
    266#error System mode not implemented for Hexagon
    267#endif
    268}
    269
    270#include "hw/core/tcg-cpu-ops.h"
    271
    272static const struct TCGCPUOps hexagon_tcg_ops = {
    273    .initialize = hexagon_translate_init,
    274    .synchronize_from_tb = hexagon_cpu_synchronize_from_tb,
    275    .tlb_fill = hexagon_tlb_fill,
    276};
    277
    278static void hexagon_cpu_class_init(ObjectClass *c, void *data)
    279{
    280    HexagonCPUClass *mcc = HEXAGON_CPU_CLASS(c);
    281    CPUClass *cc = CPU_CLASS(c);
    282    DeviceClass *dc = DEVICE_CLASS(c);
    283
    284    device_class_set_parent_realize(dc, hexagon_cpu_realize,
    285                                    &mcc->parent_realize);
    286
    287    device_class_set_parent_reset(dc, hexagon_cpu_reset, &mcc->parent_reset);
    288
    289    cc->class_by_name = hexagon_cpu_class_by_name;
    290    cc->has_work = hexagon_cpu_has_work;
    291    cc->dump_state = hexagon_dump_state;
    292    cc->set_pc = hexagon_cpu_set_pc;
    293    cc->gdb_read_register = hexagon_gdb_read_register;
    294    cc->gdb_write_register = hexagon_gdb_write_register;
    295    cc->gdb_num_core_regs = TOTAL_PER_THREAD_REGS;
    296    cc->gdb_stop_before_watchpoint = true;
    297    cc->disas_set_info = hexagon_cpu_disas_set_info;
    298    cc->tcg_ops = &hexagon_tcg_ops;
    299}
    300
    301#define DEFINE_CPU(type_name, initfn)      \
    302    {                                      \
    303        .name = type_name,                 \
    304        .parent = TYPE_HEXAGON_CPU,        \
    305        .instance_init = initfn            \
    306    }
    307
    308static const TypeInfo hexagon_cpu_type_infos[] = {
    309    {
    310        .name = TYPE_HEXAGON_CPU,
    311        .parent = TYPE_CPU,
    312        .instance_size = sizeof(HexagonCPU),
    313        .instance_init = hexagon_cpu_init,
    314        .abstract = true,
    315        .class_size = sizeof(HexagonCPUClass),
    316        .class_init = hexagon_cpu_class_init,
    317    },
    318    DEFINE_CPU(TYPE_HEXAGON_CPU_V67,              hexagon_v67_cpu_init),
    319};
    320
    321DEFINE_TYPES(hexagon_cpu_type_infos)