qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

helper.c (11025B)


      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 "qemu/log.h"
     30 #include "cpu.h"
     31 #include "exec/exec-all.h"
     32 #include "exec/gdbstub.h"
     33 #include "exec/helper-proto.h"
     34 #include "qemu/error-report.h"
     35 #include "qemu/qemu-print.h"
     36 #include "qemu/host-utils.h"
     37 
     38 static struct XtensaConfigList *xtensa_cores;
     39 
     40 static void add_translator_to_hash(GHashTable *translator,
     41                                    const char *name,
     42                                    const XtensaOpcodeOps *opcode)
     43 {
     44     if (!g_hash_table_insert(translator, (void *)name, (void *)opcode)) {
     45         error_report("Multiple definitions of '%s' opcode in a single table",
     46                      name);
     47     }
     48 }
     49 
     50 static GHashTable *hash_opcode_translators(const XtensaOpcodeTranslators *t)
     51 {
     52     unsigned i, j;
     53     GHashTable *translator = g_hash_table_new(g_str_hash, g_str_equal);
     54 
     55     for (i = 0; i < t->num_opcodes; ++i) {
     56         if (t->opcode[i].op_flags & XTENSA_OP_NAME_ARRAY) {
     57             const char * const *name = t->opcode[i].name;
     58 
     59             for (j = 0; name[j]; ++j) {
     60                 add_translator_to_hash(translator,
     61                                        (void *)name[j],
     62                                        (void *)(t->opcode + i));
     63             }
     64         } else {
     65             add_translator_to_hash(translator,
     66                                    (void *)t->opcode[i].name,
     67                                    (void *)(t->opcode + i));
     68         }
     69     }
     70     return translator;
     71 }
     72 
     73 static XtensaOpcodeOps *
     74 xtensa_find_opcode_ops(const XtensaOpcodeTranslators *t,
     75                        const char *name)
     76 {
     77     static GHashTable *translators;
     78     GHashTable *translator;
     79 
     80     if (translators == NULL) {
     81         translators = g_hash_table_new(g_direct_hash, g_direct_equal);
     82     }
     83     translator = g_hash_table_lookup(translators, t);
     84     if (translator == NULL) {
     85         translator = hash_opcode_translators(t);
     86         g_hash_table_insert(translators, (void *)t, translator);
     87     }
     88     return g_hash_table_lookup(translator, name);
     89 }
     90 
     91 static void init_libisa(XtensaConfig *config)
     92 {
     93     unsigned i, j;
     94     unsigned opcodes;
     95     unsigned formats;
     96     unsigned regfiles;
     97 
     98     config->isa = xtensa_isa_init(config->isa_internal, NULL, NULL);
     99     assert(xtensa_isa_maxlength(config->isa) <= MAX_INSN_LENGTH);
    100     assert(xtensa_insnbuf_size(config->isa) <= MAX_INSNBUF_LENGTH);
    101     opcodes = xtensa_isa_num_opcodes(config->isa);
    102     formats = xtensa_isa_num_formats(config->isa);
    103     regfiles = xtensa_isa_num_regfiles(config->isa);
    104     config->opcode_ops = g_new(XtensaOpcodeOps *, opcodes);
    105 
    106     for (i = 0; i < formats; ++i) {
    107         assert(xtensa_format_num_slots(config->isa, i) <= MAX_INSN_SLOTS);
    108     }
    109 
    110     for (i = 0; i < opcodes; ++i) {
    111         const char *opc_name = xtensa_opcode_name(config->isa, i);
    112         XtensaOpcodeOps *ops = NULL;
    113 
    114         assert(xtensa_opcode_num_operands(config->isa, i) <= MAX_OPCODE_ARGS);
    115         if (!config->opcode_translators) {
    116             ops = xtensa_find_opcode_ops(&xtensa_core_opcodes, opc_name);
    117         } else {
    118             for (j = 0; !ops && config->opcode_translators[j]; ++j) {
    119                 ops = xtensa_find_opcode_ops(config->opcode_translators[j],
    120                                              opc_name);
    121             }
    122         }
    123 #ifdef DEBUG
    124         if (ops == NULL) {
    125             fprintf(stderr,
    126                     "opcode translator not found for %s's opcode '%s'\n",
    127                     config->name, opc_name);
    128         }
    129 #endif
    130         config->opcode_ops[i] = ops;
    131     }
    132     config->a_regfile = xtensa_regfile_lookup(config->isa, "AR");
    133 
    134     config->regfile = g_new(void **, regfiles);
    135     for (i = 0; i < regfiles; ++i) {
    136         const char *name = xtensa_regfile_name(config->isa, i);
    137         int entries = xtensa_regfile_num_entries(config->isa, i);
    138         int bits = xtensa_regfile_num_bits(config->isa, i);
    139 
    140         config->regfile[i] = xtensa_get_regfile_by_name(name, entries, bits);
    141 #ifdef DEBUG
    142         if (config->regfile[i] == NULL) {
    143             fprintf(stderr, "regfile '%s' not found for %s\n",
    144                     name, config->name);
    145         }
    146 #endif
    147     }
    148     xtensa_collect_sr_names(config);
    149 }
    150 
    151 static void xtensa_finalize_config(XtensaConfig *config)
    152 {
    153     if (config->isa_internal) {
    154         init_libisa(config);
    155     }
    156 
    157     if (config->gdb_regmap.num_regs == 0 ||
    158         config->gdb_regmap.num_core_regs == 0) {
    159         unsigned n_regs = 0;
    160         unsigned n_core_regs = 0;
    161 
    162         xtensa_count_regs(config, &n_regs, &n_core_regs);
    163         if (config->gdb_regmap.num_regs == 0) {
    164             config->gdb_regmap.num_regs = n_regs;
    165         }
    166         if (config->gdb_regmap.num_core_regs == 0) {
    167             config->gdb_regmap.num_core_regs = n_core_regs;
    168         }
    169     }
    170 }
    171 
    172 static void xtensa_core_class_init(ObjectClass *oc, void *data)
    173 {
    174     CPUClass *cc = CPU_CLASS(oc);
    175     XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc);
    176     XtensaConfig *config = data;
    177 
    178     xtensa_finalize_config(config);
    179     xcc->config = config;
    180 
    181     /*
    182      * Use num_core_regs to see only non-privileged registers in an unmodified
    183      * gdb. Use num_regs to see all registers. gdb modification is required
    184      * for that: reset bit 0 in the 'flags' field of the registers definitions
    185      * in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
    186      */
    187     cc->gdb_num_core_regs = config->gdb_regmap.num_regs;
    188 }
    189 
    190 void xtensa_register_core(XtensaConfigList *node)
    191 {
    192     TypeInfo type = {
    193         .parent = TYPE_XTENSA_CPU,
    194         .class_init = xtensa_core_class_init,
    195         .class_data = (void *)node->config,
    196     };
    197 
    198     node->next = xtensa_cores;
    199     xtensa_cores = node;
    200     type.name = g_strdup_printf(XTENSA_CPU_TYPE_NAME("%s"), node->config->name);
    201     type_register(&type);
    202     g_free((gpointer)type.name);
    203 }
    204 
    205 static uint32_t check_hw_breakpoints(CPUXtensaState *env)
    206 {
    207     unsigned i;
    208 
    209     for (i = 0; i < env->config->ndbreak; ++i) {
    210         if (env->cpu_watchpoint[i] &&
    211                 env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
    212             return DEBUGCAUSE_DB | (i << DEBUGCAUSE_DBNUM_SHIFT);
    213         }
    214     }
    215     return 0;
    216 }
    217 
    218 void xtensa_breakpoint_handler(CPUState *cs)
    219 {
    220     XtensaCPU *cpu = XTENSA_CPU(cs);
    221     CPUXtensaState *env = &cpu->env;
    222 
    223     if (cs->watchpoint_hit) {
    224         if (cs->watchpoint_hit->flags & BP_CPU) {
    225             uint32_t cause;
    226 
    227             cs->watchpoint_hit = NULL;
    228             cause = check_hw_breakpoints(env);
    229             if (cause) {
    230                 debug_exception_env(env, cause);
    231             }
    232             cpu_loop_exit_noexc(cs);
    233         }
    234     }
    235 }
    236 
    237 void xtensa_cpu_list(void)
    238 {
    239     XtensaConfigList *core = xtensa_cores;
    240     qemu_printf("Available CPUs:\n");
    241     for (; core; core = core->next) {
    242         qemu_printf("  %s\n", core->config->name);
    243     }
    244 }
    245 
    246 #ifndef CONFIG_USER_ONLY
    247 void xtensa_cpu_do_unaligned_access(CPUState *cs,
    248                                     vaddr addr, MMUAccessType access_type,
    249                                     int mmu_idx, uintptr_t retaddr)
    250 {
    251     XtensaCPU *cpu = XTENSA_CPU(cs);
    252     CPUXtensaState *env = &cpu->env;
    253 
    254     assert(xtensa_option_enabled(env->config,
    255                                  XTENSA_OPTION_UNALIGNED_EXCEPTION));
    256     cpu_restore_state(CPU(cpu), retaddr);
    257     HELPER(exception_cause_vaddr)(env,
    258                                   env->pc, LOAD_STORE_ALIGNMENT_CAUSE,
    259                                   addr);
    260 }
    261 
    262 bool xtensa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
    263                          MMUAccessType access_type, int mmu_idx,
    264                          bool probe, uintptr_t retaddr)
    265 {
    266     XtensaCPU *cpu = XTENSA_CPU(cs);
    267     CPUXtensaState *env = &cpu->env;
    268     uint32_t paddr;
    269     uint32_t page_size;
    270     unsigned access;
    271     int ret = xtensa_get_physical_addr(env, true, address, access_type,
    272                                        mmu_idx, &paddr, &page_size, &access);
    273 
    274     qemu_log_mask(CPU_LOG_MMU, "%s(%08" VADDR_PRIx
    275                   ", %d, %d) -> %08x, ret = %d\n",
    276                   __func__, address, access_type, mmu_idx, paddr, ret);
    277 
    278     if (ret == 0) {
    279         tlb_set_page(cs,
    280                      address & TARGET_PAGE_MASK,
    281                      paddr & TARGET_PAGE_MASK,
    282                      access, mmu_idx, page_size);
    283         return true;
    284     } else if (probe) {
    285         return false;
    286     } else {
    287         cpu_restore_state(cs, retaddr);
    288         HELPER(exception_cause_vaddr)(env, env->pc, ret, address);
    289     }
    290 }
    291 
    292 void xtensa_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
    293                                       unsigned size, MMUAccessType access_type,
    294                                       int mmu_idx, MemTxAttrs attrs,
    295                                       MemTxResult response, uintptr_t retaddr)
    296 {
    297     XtensaCPU *cpu = XTENSA_CPU(cs);
    298     CPUXtensaState *env = &cpu->env;
    299 
    300     cpu_restore_state(cs, retaddr);
    301     HELPER(exception_cause_vaddr)(env, env->pc,
    302                                   access_type == MMU_INST_FETCH ?
    303                                   INSTR_PIF_ADDR_ERROR_CAUSE :
    304                                   LOAD_STORE_PIF_ADDR_ERROR_CAUSE,
    305                                   addr);
    306 }
    307 
    308 void xtensa_runstall(CPUXtensaState *env, bool runstall)
    309 {
    310     CPUState *cpu = env_cpu(env);
    311 
    312     env->runstall = runstall;
    313     cpu->halted = runstall;
    314     if (runstall) {
    315         cpu_interrupt(cpu, CPU_INTERRUPT_HALT);
    316     } else {
    317         qemu_cpu_kick(cpu);
    318     }
    319 }
    320 #endif /* !CONFIG_USER_ONLY */