Beispiel #1
0
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 */
}
Beispiel #2
0
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);
}