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_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); }