static void sifive_plic_update(SiFivePLICState *plic) { int addrid; /* raise irq on harts where this irq is enabled */ for (addrid = 0; addrid < plic->num_addrs; addrid++) { uint32_t hartid = plic->addr_config[addrid].hartid; PLICMode mode = plic->addr_config[addrid].mode; CPUState *cpu = qemu_get_cpu(hartid); CPURISCVState *env = cpu ? cpu->env_ptr : NULL; if (!env) { continue; } int level = sifive_plic_num_irqs_pending(plic, addrid) > 0; switch (mode) { case PLICMode_M: riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_MEIP, level); break; case PLICMode_S: riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_SEIP, level); break; default: break; } } if (RISCV_DEBUG_PLIC) { sifive_plic_print_state(plic); } }
static void riscv_cpu_init(Object *obj) { CPUState *cs = CPU(obj); RISCVCPU *cpu = RISCV_CPU(obj); cs->env_ptr = &cpu->env; }
static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU); set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); }
static void rv64imacu_nommu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU); set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_10_0); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_PMP); }
static void rv64gcsu_priv1_09_1_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_versions(env, USER_VERSION_2_02_0, PRIV_VERSION_1_09_1); set_resetvec(env, DEFAULT_RSTVEC); set_feature(env, RISCV_FEATURE_MMU); set_feature(env, RISCV_FEATURE_PMP); }
static void riscv_cpu_reset(CPUState *s) { RISCVCPU *cpu = RISCV_CPU(s); RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); CPURISCVState *env = &cpu->env; mcc->parent_reset(s); tlb_flush(s, 1); cpu_state_reset(env); }
/* called by qemu's softmmu to fill the qemu tlb */ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, uintptr_t retaddr) { int ret; ret = riscv_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx); if (ret) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; do_raise_exception_err(env, cs->exception_index, retaddr); } }
static void riscv_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; cs->env_ptr = env; cpu_exec_init(env); if (tcg_enabled()) { riscv_tcg_init(); } }
static bool riscv_cpu_has_work(CPUState *cs) { #ifndef CONFIG_USER_ONLY RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; /* * Definition of the WFI instruction requires it to ignore the privilege * mode and delegation registers, but respect individual enables */ return (atomic_read(&env->mip) & env->mie) != 0; #else return true; #endif }
static void riscv_cpu_reset(CPUState *cs) { RISCVCPU *cpu = RISCV_CPU(cs); RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); CPURISCVState *env = &cpu->env; mcc->parent_reset(cs); #ifndef CONFIG_USER_ONLY env->priv = PRV_M; env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV); env->mcause = 0; env->pc = env->resetvec; #endif cs->exception_index = EXCP_NONE; set_default_nan_mode(1, &env->fp_status); }
static bool riscv_cpu_has_work(CPUState *cs) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; bool has_work = false; /* It is implementation dependent if non-enabled interrupts wake-up the CPU, however most of the implementations only check for interrupts that can be taken. */ if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && cpu_riscv_hw_interrupts_pending(env)) { has_work = true; } return has_work; }
void riscv_cpu_do_unaligned_access(CPUState *cs, target_ulong addr, int rw, int is_user, uintptr_t retaddr) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; printf("addr: %016lx\n", addr); if (rw & 0x2) { fprintf(stderr, "unaligned inst fetch not handled here\n"); exit(1); } else if (rw == 0x1) { printf("Store\n"); cs->exception_index = NEW_RISCV_EXCP_STORE_AMO_ADDR_MIS; env->csr[NEW_CSR_MBADADDR] = addr; } else { printf("Load\n"); cs->exception_index = NEW_RISCV_EXCP_LOAD_ADDR_MIS; env->csr[NEW_CSR_MBADADDR] = addr; } do_raise_exception_err(env, cs->exception_index, retaddr); }
static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; int i; qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc ", env->pc); #ifndef CONFIG_USER_ONLY qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", (target_ulong)atomic_read(&env->mip)); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec ", env->mtvec); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc ", env->mepc); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause ", env->mcause); #endif for (i = 0; i < 32; i++) { qemu_fprintf(f, " %s " TARGET_FMT_lx, riscv_int_regnames[i], env->gpr[i]); if ((i & 3) == 3) { qemu_fprintf(f, "\n"); } } if (flags & CPU_DUMP_FPU) { for (i = 0; i < 32; i++) { qemu_fprintf(f, " %s %016" PRIx64, riscv_fpr_regnames[i], env->fpr[i]); if ((i & 3) == 3) { qemu_fprintf(f, "\n"); } } } }
static void riscv_sifive_board_init(MachineState *args) { ram_addr_t ram_size = args->ram_size; const char *cpu_model = args->cpu_model; const char *kernel_filename = args->kernel_filename; const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); RISCVCPU *cpu; CPURISCVState *env; int i; DeviceState *dev = qdev_create(NULL, TYPE_RISCV_SIFIVE_BOARD); object_property_set_bool(OBJECT(dev), true, "realized", NULL); /* Make sure the first 3 serial ports are associated with a device. */ for (i = 0; i < 3; i++) { if (!serial_hds[i]) { char label[32]; snprintf(label, sizeof(label), "serial%d", i); serial_hds[i] = qemu_chr_new(label, "null", NULL); } } /* init CPUs */ if (cpu_model == NULL) { cpu_model = "any"; } for (i = 0; i < smp_cpus; i++) { cpu = cpu_riscv_init(cpu_model); if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } env = &cpu->env; /* Init internal devices */ cpu_riscv_irq_init_cpu(env); cpu_riscv_clock_init(env); qemu_register_reset(main_cpu_reset, cpu); } cpu = RISCV_CPU(first_cpu); env = &cpu->env; /* register system main memory (actual RAM) */ memory_region_init_ram(main_mem, NULL, "riscv_sifive_board.ram", 2147483648ll + ram_size, &error_fatal); /* for phys mem size check in page table walk */ env->memsize = ram_size; vmstate_register_ram_global(main_mem); memory_region_add_subregion(system_memory, 0x0, main_mem); if (kernel_filename) { loaderparams.ram_size = ram_size; loaderparams.kernel_filename = kernel_filename; loaderparams.kernel_cmdline = kernel_cmdline; loaderparams.initrd_filename = initrd_filename; load_kernel(); } uint32_t reset_vec[8] = { 0x297 + 0x80000000 - 0x1000, /* reset vector */ 0x00028067, /* jump to DRAM_BASE */ 0x00000000, /* reserved */ 0x0, /* config string pointer */ 0, 0, 0, 0 /* trap vector */ }; reset_vec[3] = 0x1000 + sizeof(reset_vec); /* config string pointer */ /* part one of config string - before memory size specified */ const char *config_string1 = "platform {\n" " vendor ucb;\n" " arch spike;\n" "};\n" "plic { \n" " interface \"plic\"; \n" " ndevs 2; \n" " priority { mem { 0x60000000 0x60000fff; }; }; \n" " pending { mem { 0x60001000 0x6000107f; }; }; \n" " 0 { \n" " 0 { \n" " m { \n" " ie { mem { 0x60002000 0x6000207f; }; }; \n" " ctl { mem { 0x60200000 0x60200007; }; }; \n" " }; \n" " s { \n" " ie { mem { 0x60002080 0x600020ff; }; }; \n" " ctl { mem { 0x60201000 0x60201007; }; }; \n" " }; \n" " }; \n" " }; \n" "}; \n" "rtc {\n" " addr 0x" "40000000" ";\n" "};\n" "uart {\n" " addr 0x40002000;\n" "};\n" "ram {\n" " 0 {\n" " addr 0x" "80000000" ";\n" " size 0x"; /* part two of config string - after memory size specified */ const char *config_string2 = ";\n" " };\n" "};\n" "core {\n" " 0" " {\n" " " "0 {\n" " isa " "rv64imafd" ";\n" " timecmp 0x" "40000008" ";\n" " ipi 0x" "40001000" ";\n" " };\n" " };\n" "};\n"; /* build config string with supplied memory size */ uint64_t rsz = ram_size; char *ramsize_as_hex_str = malloc(17); sprintf(ramsize_as_hex_str, "%016" PRIx64, rsz); char *config_string = malloc(strlen(config_string1) + strlen(ramsize_as_hex_str) + strlen(config_string2) + 1); config_string[0] = 0; strcat(config_string, config_string1); strcat(config_string, ramsize_as_hex_str); strcat(config_string, config_string2); /* copy in the reset vec and configstring */ int q; for (q = 0; q < sizeof(reset_vec) / sizeof(reset_vec[0]); q++) { stl_p(memory_region_get_ram_ptr(main_mem) + 0x1000 + q * 4, reset_vec[q]); } int confstrlen = strlen(config_string); for (q = 0; q < confstrlen; q++) { stb_p(memory_region_get_ram_ptr(main_mem) + reset_vec[3] + q, config_string[q]); } sifive_uart_create(0x40002000, serial_hds[0]); /* timer device at 0x40000000, as specified in the config string above */ timer_mm_init(system_memory, 0x40000000, env); /* TODO: VIRTIO */ }
static void riscv_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; env->pc = tb->pc; }
static void riscv_cpu_set_pc(CPUState *cs, vaddr value) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; env->pc = value; }
static void riscv_board_init(QEMUMachineInitArgs *args) { ram_addr_t ram_size = args->ram_size; const char *cpu_model = args->cpu_model; const char *kernel_filename = args->kernel_filename; const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); RISCVCPU *cpu; CPURISCVState *env; int i; #ifdef CONFIG_RISCV_HTIF DriveInfo *htifbd_drive; char *htifbd_fname; // htif block device filename #endif DeviceState *dev = qdev_create(NULL, TYPE_RISCV_BOARD); object_property_set_bool(OBJECT(dev), true, "realized", NULL); /* Make sure the first 3 serial ports are associated with a device. */ for(i = 0; i < 3; i++) { if (!serial_hds[i]) { char label[32]; snprintf(label, sizeof(label), "serial%d", i); serial_hds[i] = qemu_chr_new(label, "null", NULL); } } /* init CPUs */ if (cpu_model == NULL) { cpu_model = "riscv-generic"; } for (i = 0; i < smp_cpus; i++) { cpu = cpu_riscv_init(cpu_model); if (cpu == NULL) { fprintf(stderr, "Unable to find CPU definition\n"); exit(1); } env = &cpu->env; /* Init internal devices */ cpu_riscv_irq_init_cpu(env); cpu_riscv_clock_init(env); qemu_register_reset(main_cpu_reset, cpu); } cpu = RISCV_CPU(first_cpu); env = &cpu->env; /* register system main memory (actual RAM) */ memory_region_init_ram(main_mem, NULL, "riscv_board.ram", ram_size); vmstate_register_ram_global(main_mem); memory_region_add_subregion(system_memory, 0x0, main_mem); if (kernel_filename) { /* Write a small bootloader to the flash location. */ loaderparams.ram_size = ram_size; loaderparams.kernel_filename = kernel_filename; loaderparams.kernel_cmdline = kernel_cmdline; loaderparams.initrd_filename = initrd_filename; load_kernel(); } // write memory amount in MiB to 0x0 stl_p(memory_region_get_ram_ptr(main_mem), loaderparams.ram_size >> 20); #ifdef CONFIG_RISCV_HTIF serial_mm_init(system_memory, 0x3f8, 0, env->irq[4], 1843200/16, serial_hds[0], DEVICE_NATIVE_ENDIAN); // setup HTIF Block Device if one is specified as -hda FILENAME htifbd_drive = drive_get_by_index(IF_IDE, 0); if (NULL == htifbd_drive) { htifbd_fname = NULL; } else { htifbd_fname = (*(htifbd_drive->bdrv)).filename; } // add htif device 0x400 - 0x410 htif_mm_init(system_memory, 0x400, env->irq[0], main_mem, htifbd_fname); #else // add serial device 0x3f8-0x3ff serial_mm_init(system_memory, 0x3f8, 0, env->irq[1], 1843200/16, serial_hds[0], DEVICE_NATIVE_ENDIAN); /* Create MMIO transports, to which virtio backends created by the * user are automatically connected as needed. If no backend is * present, the transport simply remains harmlessly idle. * Each memory-mapped region is 0x200 bytes in size. */ sysbus_create_simple("virtio-mmio", 0x400, env->irq[2]); sysbus_create_simple("virtio-mmio", 0x600, env->irq[3]); sysbus_create_simple("virtio-mmio", 0x800, env->irq[4]); #endif /* Init internal devices */ cpu_riscv_irq_init_cpu(env); cpu_riscv_clock_init(env); }