Commit 3add3f7e authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/riscv/tags/riscv-qemu-2.13-pull-20180506' into staging



RISC-V: QEMU 2.13 Privileged ISA emulation updates

Several code cleanups, minor specification conformance changes,
fixes to make ROM read-only and add device-tree size checks.

* Honour privileged ISA v1.10 counter enable CSRs.
* Implements WARL behavior for CSRs that don't support writes
  * Past behavior of raising traps was non-conformant
    with the RISC-V Privileged ISA Specification v1.10.
* Allow S-mode access to sstatus.MXR when priv ISA >= v1.10
* Sets mtval/stval to zero on exceptions without addresses
  * Past behavior of leaving the last value was non-conformant
    with the RISC-V Privileged ISA Specition v1.10. mtval/stval
    must be set on all exceptions; to zero if not supported.
* Make ROMs read-only and implement device-tree size checks
  * Uses memory_region_init_rom and rom_add_blob_fixed_as
* Adds hexidecimal instruction bytes to disassembly output.
* Fixes missing break statement for rv128 disassembly.
* Several code cleanups
  * Replacing hard-coded constants with enums
  * Dead-code elimination

This is an incremental pull that contains 20 reviewed changes out
of 38 changes currently queued in the qemu-2.13-for-upstream branch.

# gpg: Signature made Sun 06 May 2018 00:27:37 BST
# gpg:                using DSA key 6BF1D7B357EF3E4F
# gpg: Good signature from "Michael Clark <michaeljclark@mac.com>"
# gpg:                 aka "Michael Clark <mjc@sifive.com>"
# gpg:                 aka "Michael Clark <michael@metaparadigm.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 7C99 930E B17C D8BA 073D  5EFA 6BF1 D7B3 57EF 3E4F

* remotes/riscv/tags/riscv-qemu-2.13-pull-20180506:
  RISC-V: Mark ROM read-only after copying in code
  RISC-V: No traps on writes to misa,minstret,mcycle
  RISC-V: Make mtvec/stvec ignore vectored traps
  RISC-V: Add mcycle/minstret support for -icount auto
  RISC-V: Use [ms]counteren CSRs when priv ISA >= v1.10
  RISC-V: Allow S-mode mxr access when priv ISA >= v1.10
  RISC-V: Clear mtval/stval on exceptions without info
  RISC-V: Hardwire satp to 0 for no-mmu case
  RISC-V: Update E and I extension order
  RISC-V: Remove erroneous comment from translate.c
  RISC-V: Remove EM_RISCV ELF_MACHINE indirection
  RISC-V: Make virt header comment title consistent
  RISC-V: Make some header guards more specific
  RISC-V: Fix missing break statement in disassembler
  RISC-V: Include instruction hex in disassembly
  RISC-V: Remove unused class definitions
  RISC-V: Remove identity_translate from load_elf
  RISC-V: Use ROM base address and size from memmap
  RISC-V: Make virt board description match spike
  RISC-V: Replace hardcoded constants with enum values

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 302a84e8 5aec3247
Loading
Loading
Loading
Loading
+22 −20
Original line number Diff line number Diff line
@@ -1470,8 +1470,9 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
            if (isa == rv128) {
                op = rv_op_c_sqsp;
            } else {
                op = rv_op_c_fsdsp; break;
                op = rv_op_c_fsdsp;
            }
            break;
        case 6: op = rv_op_c_swsp; break;
        case 7:
            if (isa == rv32) {
@@ -2769,25 +2770,6 @@ static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec)
    char tmp[64];
    const char *fmt;

    if (dec->op == rv_op_illegal) {
        size_t len = inst_length(dec->inst);
        switch (len) {
        case 2:
            snprintf(buf, buflen, "(0x%04" PRIx64 ")", dec->inst);
            break;
        case 4:
            snprintf(buf, buflen, "(0x%08" PRIx64 ")", dec->inst);
            break;
        case 6:
            snprintf(buf, buflen, "(0x%012" PRIx64 ")", dec->inst);
            break;
        default:
            snprintf(buf, buflen, "(0x%016" PRIx64 ")", dec->inst);
            break;
        }
        return;
    }

    fmt = opcode_data[dec->op].format;
    while (*fmt) {
        switch (*fmt) {
@@ -3004,6 +2986,11 @@ disasm_inst(char *buf, size_t buflen, rv_isa isa, uint64_t pc, rv_inst inst)
    format_inst(buf, buflen, 16, &dec);
}

#define INST_FMT_2 "%04" PRIx64 "              "
#define INST_FMT_4 "%08" PRIx64 "          "
#define INST_FMT_6 "%012" PRIx64 "      "
#define INST_FMT_8 "%016" PRIx64 "  "

static int
print_insn_riscv(bfd_vma memaddr, struct disassemble_info *info, rv_isa isa)
{
@@ -3031,6 +3018,21 @@ print_insn_riscv(bfd_vma memaddr, struct disassemble_info *info, rv_isa isa)
        }
    }

    switch (len) {
    case 2:
        (*info->fprintf_func)(info->stream, INST_FMT_2, inst);
        break;
    case 4:
        (*info->fprintf_func)(info->stream, INST_FMT_4, inst);
        break;
    case 6:
        (*info->fprintf_func)(info->stream, INST_FMT_6, inst);
        break;
    default:
        (*info->fprintf_func)(info->stream, INST_FMT_8, inst);
        break;
    }

    disasm_inst(buf, sizeof(buf), isa, memaddr, inst);
    (*info->fprintf_func)(info->stream, "%s", buf);

+0 −6
Original line number Diff line number Diff line
@@ -68,16 +68,10 @@ static void riscv_harts_class_init(ObjectClass *klass, void *data)
    dc->realize = riscv_harts_realize;
}

static void riscv_harts_init(Object *obj)
{
    /* RISCVHartArrayState *s = SIFIVE_COREPLEX(obj); */
}

static const TypeInfo riscv_harts_info = {
    .name          = TYPE_RISCV_HART_ARRAY,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(RISCVHartArrayState),
    .instance_init = riscv_harts_init,
    .class_init    = riscv_harts_class_init,
};

+3 −6
Original line number Diff line number Diff line
@@ -26,13 +26,10 @@
#include "hw/riscv/sifive_clint.h"
#include "qemu/timer.h"

/* See: riscv-pk/machine/sbi_entry.S and arch/riscv/kernel/time.c */
#define TIMER_FREQ (10 * 1000 * 1000)

static uint64_t cpu_riscv_read_rtc(void)
{
    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), TIMER_FREQ,
                    NANOSECONDS_PER_SECOND);
    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
        SIFIVE_CLINT_TIMEBASE_FREQ, NANOSECONDS_PER_SECOND);
}

/*
@@ -59,7 +56,7 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value)
    diff = cpu->env.timecmp - rtc_r;
    /* back to ns (note args switched in muldiv64) */
    next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
        muldiv64(diff, NANOSECONDS_PER_SECOND, TIMER_FREQ);
        muldiv64(diff, NANOSECONDS_PER_SECOND, SIFIVE_CLINT_TIMEBASE_FREQ);
    timer_mod(cpu->env.timer, next);
}

+10 −44
Original line number Diff line number Diff line
@@ -74,26 +74,13 @@ static const struct MemmapEntry {
    [SIFIVE_E_DTIM] =     { 0x80000000,     0x4000 }
};

static void copy_le32_to_phys(hwaddr pa, uint32_t *rom, size_t len)
{
    int i;
    for (i = 0; i < (len >> 2); i++) {
        stl_phys(&address_space_memory, pa + (i << 2), rom[i]);
    }
}

static uint64_t identity_translate(void *opaque, uint64_t addr)
{
    return addr;
}

static uint64_t load_kernel(const char *kernel_filename)
{
    uint64_t kernel_entry, kernel_high;

    if (load_elf(kernel_filename, identity_translate, NULL,
    if (load_elf(kernel_filename, NULL, NULL,
                 &kernel_entry, NULL, &kernel_high,
                 0, ELF_MACHINE, 1, 0) < 0) {
                 0, EM_RISCV, 1, 0) < 0) {
        error_report("qemu: could not load kernel '%s'", kernel_filename);
        exit(1);
    }
@@ -117,6 +104,7 @@ static void riscv_sifive_e_init(MachineState *machine)
    MemoryRegion *main_mem = g_new(MemoryRegion, 1);
    MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
    MemoryRegion *xip_mem = g_new(MemoryRegion, 1);
    int i;

    /* Initialize SOC */
    object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
@@ -136,7 +124,7 @@ static void riscv_sifive_e_init(MachineState *machine)
        memmap[SIFIVE_E_DTIM].base, main_mem);

    /* Mask ROM */
    memory_region_init_ram(mask_rom, NULL, "riscv.sifive.e.mrom",
    memory_region_init_rom(mask_rom, NULL, "riscv.sifive.e.mrom",
        memmap[SIFIVE_E_MROM].size, &error_fatal);
    memory_region_add_subregion(sys_mem,
        memmap[SIFIVE_E_MROM].base, mask_rom);
@@ -190,33 +178,18 @@ static void riscv_sifive_e_init(MachineState *machine)
        0x00028067,        /* 0x1004: jr      t0 */
    };

    /* copy in the reset vector */
    copy_le32_to_phys(memmap[SIFIVE_E_MROM].base, reset_vec, sizeof(reset_vec));
    memory_region_set_readonly(mask_rom, true);
    /* copy in the reset vector in little_endian byte order */
    for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
        reset_vec[i] = cpu_to_le32(reset_vec[i]);
    }
    rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
                          memmap[SIFIVE_E_MROM].base, &address_space_memory);

    if (machine->kernel_filename) {
        load_kernel(machine->kernel_filename);
    }
}

static int riscv_sifive_e_sysbus_device_init(SysBusDevice *sysbusdev)
{
    return 0;
}

static void riscv_sifive_e_class_init(ObjectClass *klass, void *data)
{
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
    k->init = riscv_sifive_e_sysbus_device_init;
}

static const TypeInfo riscv_sifive_e_device = {
    .name          = TYPE_SIFIVE_E,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(SiFiveEState),
    .class_init    = riscv_sifive_e_class_init,
};

static void riscv_sifive_e_machine_init(MachineClass *mc)
{
    mc->desc = "RISC-V Board compatible with SiFive E SDK";
@@ -225,10 +198,3 @@ static void riscv_sifive_e_machine_init(MachineClass *mc)
}

DEFINE_MACHINE("sifive_e", riscv_sifive_e_machine_init)

static void riscv_sifive_e_register_types(void)
{
    type_register_static(&riscv_sifive_e_device);
}

type_init(riscv_sifive_e_register_types);
+34 −57
Original line number Diff line number Diff line
@@ -47,12 +47,14 @@
#include "exec/address-spaces.h"
#include "elf.h"

#include <libfdt.h>

static const struct MemmapEntry {
    hwaddr base;
    hwaddr size;
} sifive_u_memmap[] = {
    [SIFIVE_U_DEBUG] =    {        0x0,      0x100 },
    [SIFIVE_U_MROM] =     {     0x1000,     0x2000 },
    [SIFIVE_U_MROM] =     {     0x1000,    0x11000 },
    [SIFIVE_U_CLINT] =    {  0x2000000,    0x10000 },
    [SIFIVE_U_PLIC] =     {  0xc000000,  0x4000000 },
    [SIFIVE_U_UART0] =    { 0x10013000,     0x1000 },
@@ -60,26 +62,13 @@ static const struct MemmapEntry {
    [SIFIVE_U_DRAM] =     { 0x80000000,        0x0 },
};

static void copy_le32_to_phys(hwaddr pa, uint32_t *rom, size_t len)
{
    int i;
    for (i = 0; i < (len >> 2); i++) {
        stl_phys(&address_space_memory, pa + (i << 2), rom[i]);
    }
}

static uint64_t identity_translate(void *opaque, uint64_t addr)
{
    return addr;
}

static uint64_t load_kernel(const char *kernel_filename)
{
    uint64_t kernel_entry, kernel_high;

    if (load_elf(kernel_filename, identity_translate, NULL,
    if (load_elf(kernel_filename, NULL, NULL,
                 &kernel_entry, NULL, &kernel_high,
                 0, ELF_MACHINE, 1, 0) < 0) {
                 0, EM_RISCV, 1, 0) < 0) {
        error_report("qemu: could not load kernel '%s'", kernel_filename);
        exit(1);
    }
@@ -122,7 +111,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
    g_free(nodename);

    qemu_fdt_add_subnode(fdt, "/cpus");
    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency", 10000000);
    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
        SIFIVE_CLINT_TIMEBASE_FREQ);
    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);

@@ -131,7 +121,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
        char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
        char *isa = riscv_isa_string(&s->soc.harts[cpu]);
        qemu_fdt_add_subnode(fdt, nodename);
        qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", 1000000000);
        qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
                              SIFIVE_U_CLOCK_FREQ);
        qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
        qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
        qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
@@ -224,9 +215,10 @@ static void riscv_sifive_u_init(MachineState *machine)
    const struct MemmapEntry *memmap = sifive_u_memmap;

    SiFiveUState *s = g_new0(SiFiveUState, 1);
    MemoryRegion *sys_memory = get_system_memory();
    MemoryRegion *system_memory = get_system_memory();
    MemoryRegion *main_mem = g_new(MemoryRegion, 1);
    MemoryRegion *boot_rom = g_new(MemoryRegion, 1);
    MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
    int i;

    /* Initialize SOC */
    object_initialize(&s->soc, sizeof(s->soc), TYPE_RISCV_HART_ARRAY);
@@ -242,17 +234,17 @@ static void riscv_sifive_u_init(MachineState *machine)
    /* register RAM */
    memory_region_init_ram(main_mem, NULL, "riscv.sifive.u.ram",
                           machine->ram_size, &error_fatal);
    memory_region_add_subregion(sys_memory, memmap[SIFIVE_U_DRAM].base,
    memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DRAM].base,
        main_mem);

    /* create device tree */
    create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);

    /* boot rom */
    memory_region_init_ram(boot_rom, NULL, "riscv.sifive.u.mrom",
                           memmap[SIFIVE_U_MROM].base, &error_fatal);
    memory_region_set_readonly(boot_rom, true);
    memory_region_add_subregion(sys_memory, 0x0, boot_rom);
    memory_region_init_rom(mask_rom, NULL, "riscv.sifive.u.mrom",
                           memmap[SIFIVE_U_MROM].size, &error_fatal);
    memory_region_add_subregion(system_memory, memmap[SIFIVE_U_MROM].base,
                                mask_rom);

    if (machine->kernel_filename) {
        load_kernel(machine->kernel_filename);
@@ -275,13 +267,23 @@ static void riscv_sifive_u_init(MachineState *machine)
                                       /* dtb: */
    };

    /* copy in the reset vector */
    copy_le32_to_phys(memmap[SIFIVE_U_MROM].base, reset_vec, sizeof(reset_vec));
    /* copy in the reset vector in little_endian byte order */
    for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
        reset_vec[i] = cpu_to_le32(reset_vec[i]);
    }
    rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
                          memmap[SIFIVE_U_MROM].base, &address_space_memory);

    /* copy in the device tree */
    qemu_fdt_dumpdtb(s->fdt, s->fdt_size);
    cpu_physical_memory_write(memmap[SIFIVE_U_MROM].base +
        sizeof(reset_vec), s->fdt, s->fdt_size);
    if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) >
            memmap[SIFIVE_U_MROM].size - sizeof(reset_vec)) {
        error_report("not enough space to store device-tree");
        exit(1);
    }
    qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt));
    rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt),
                          memmap[SIFIVE_U_MROM].base + sizeof(reset_vec),
                          &address_space_memory);

    /* MMIO */
    s->plic = sifive_plic_create(memmap[SIFIVE_U_PLIC].base,
@@ -295,40 +297,15 @@ static void riscv_sifive_u_init(MachineState *machine)
        SIFIVE_U_PLIC_CONTEXT_BASE,
        SIFIVE_U_PLIC_CONTEXT_STRIDE,
        memmap[SIFIVE_U_PLIC].size);
    sifive_uart_create(sys_memory, memmap[SIFIVE_U_UART0].base,
    sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base,
        serial_hd(0), SIFIVE_PLIC(s->plic)->irqs[SIFIVE_U_UART0_IRQ]);
    /* sifive_uart_create(sys_memory, memmap[SIFIVE_U_UART1].base,
    /* sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
        serial_hd(1), SIFIVE_PLIC(s->plic)->irqs[SIFIVE_U_UART1_IRQ]); */
    sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
        memmap[SIFIVE_U_CLINT].size, smp_cpus,
        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
}

static int riscv_sifive_u_sysbus_device_init(SysBusDevice *sysbusdev)
{
    return 0;
}

static void riscv_sifive_u_class_init(ObjectClass *klass, void *data)
{
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
    k->init = riscv_sifive_u_sysbus_device_init;
}

static const TypeInfo riscv_sifive_u_device = {
    .name          = TYPE_SIFIVE_U,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(SiFiveUState),
    .class_init    = riscv_sifive_u_class_init,
};

static void riscv_sifive_u_register_types(void)
{
    type_register_static(&riscv_sifive_u_device);
}

type_init(riscv_sifive_u_register_types);

static void riscv_sifive_u_machine_init(MachineClass *mc)
{
    mc->desc = "RISC-V Board compatible with SiFive U SDK";
Loading