Commit aff8cee8 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/palmer/tags/riscv-for-master-4.1-sf1-v3' into staging



RISC-V Patches for the 4.1 Soft Freeze, Part 2 v3

This pull request contains a handful of patches that I'd like to target
for the 4.1 soft freeze.  There are a handful of new features:

* Support for the 1.11.0, the latest privileged specification.
* Support for reading and writing the PRCI registers.
* Better control over the ISA of the target machine.
* Support for the cpu-topology device tree node.

Additionally, there are a handful of bug fixes including:

* Load reservations are now broken by both store conditional and by
  scheduling, which fixes issues with parallel applications.
* Various fixes to the PMP implementation.
* Fixes to the 32-bit linux-user syscall ABI.
* Various fixes for instruction decodeing.
* A fix to the PCI device tree "bus-range" property.

This boots 32-bit and 64-bit OpenEmbedded.

Changes since v2 [riscv-for-master-4.1-sf1-v2]:

* Dropped OpenSBI.

Changes since v1 [riscv-for-master-4.1-sf1]:

* Contains a fix to the sifive_u OpenSBI integration.

# gpg: Signature made Wed 03 Jul 2019 09:39:09 BST
# gpg:                using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
# gpg:                issuer "palmer@dabbelt.com"
# gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" [unknown]
# gpg:                 aka "Palmer Dabbelt <palmer@sifive.com>" [unknown]
# 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: 00CE 76D1 8349 60DF CE88  6DF8 EF4C A150 2CCB AB41

* remotes/palmer/tags/riscv-for-master-4.1-sf1-v3: (32 commits)
  hw/riscv: Extend the kernel loading support
  hw/riscv: Add support for loading a firmware
  hw/riscv: Split out the boot functions
  riscv: sifive_u: Update the plic hart config to support multicore
  riscv: sifive_u: Do not create hard-coded phandles in DT
  disas/riscv: Fix `rdinstreth` constraint
  disas/riscv: Disassemble reserved compressed encodings as illegal
  riscv: virt: Add cpu-topology DT node.
  RISC-V: Update syscall list for 32-bit support.
  RISC-V: Clear load reservations on context switch and SC
  RISC-V: Add support for the Zicsr extension
  RISC-V: Add support for the Zifencei extension
  target/riscv: Add support for disabling/enabling Counters
  target/riscv: Remove user version information
  target/riscv: Require either I or E base extension
  qemu-deprecated.texi: Deprecate the RISC-V privledge spec 1.09.1
  target/riscv: Set privledge spec 1.11.0 as default
  target/riscv: Add the mcountinhibit CSR
  target/riscv: Add the privledge spec version 1.11.0
  target/riscv: Restructure deprecatd CPUs
  ...

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents b2e1bc59 395fd695
Loading
Loading
Loading
Loading
+47 −18
Original line number Diff line number Diff line
@@ -504,14 +504,19 @@ typedef struct {
    const rvc_constraint *constraints;
} rv_comp_data;

enum {
    rvcd_imm_nz = 0x1
};

typedef struct {
    const char * const name;
    const rv_codec codec;
    const char * const format;
    const rv_comp_data *pseudo;
    const int decomp_rv32;
    const int decomp_rv64;
    const int decomp_rv128;
    const short decomp_rv32;
    const short decomp_rv64;
    const short decomp_rv128;
    const short decomp_data;
} rv_opcode_data;

/* register names */
@@ -609,7 +614,8 @@ static const rvc_constraint rvcc_rdtime[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc01, r
static const rvc_constraint rvcc_rdinstret[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc02, rvc_end };
static const rvc_constraint rvcc_rdcycleh[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc80, rvc_end };
static const rvc_constraint rvcc_rdtimeh[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc81, rvc_end };
static const rvc_constraint rvcc_rdinstreth[] = { rvc_rs1_eq_x0, rvc_csr_eq_0xc80, rvc_end };
static const rvc_constraint rvcc_rdinstreth[] = { rvc_rs1_eq_x0,
                                                  rvc_csr_eq_0xc82, rvc_end };
static const rvc_constraint rvcc_frcsr[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x003, rvc_end };
static const rvc_constraint rvcc_frrm[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x002, rvc_end };
static const rvc_constraint rvcc_frflags[] = { rvc_rs1_eq_x0, rvc_csr_eq_0x001, rvc_end };
@@ -1011,7 +1017,8 @@ const rv_opcode_data opcode_data[] = {
    { "fcvt.q.lu", rv_codec_r_m, rv_fmt_rm_frd_rs1, NULL, 0, 0, 0 },
    { "fmv.x.q", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 },
    { "fmv.q.x", rv_codec_r, rv_fmt_frd_rs1, NULL, 0, 0, 0 },
    { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi },
    { "c.addi4spn", rv_codec_ciw_4spn, rv_fmt_rd_rs1_imm, NULL, rv_op_addi,
      rv_op_addi, rv_op_addi, rvcd_imm_nz },
    { "c.fld", rv_codec_cl_ld, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, rv_op_fld, 0 },
    { "c.lw", rv_codec_cl_lw, rv_fmt_rd_offset_rs1, NULL, rv_op_lw, rv_op_lw, rv_op_lw },
    { "c.flw", rv_codec_cl_lw, rv_fmt_frd_offset_rs1, NULL, rv_op_flw, 0, 0 },
@@ -1019,14 +1026,20 @@ const rv_opcode_data opcode_data[] = {
    { "c.sw", rv_codec_cs_sw, rv_fmt_rs2_offset_rs1, NULL, rv_op_sw, rv_op_sw, rv_op_sw },
    { "c.fsw", rv_codec_cs_sw, rv_fmt_frs2_offset_rs1, NULL, rv_op_fsw, 0, 0 },
    { "c.nop", rv_codec_ci_none, rv_fmt_none, NULL, rv_op_addi, rv_op_addi, rv_op_addi },
    { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi },
    { "c.addi", rv_codec_ci, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi,
      rv_op_addi, rvcd_imm_nz },
    { "c.jal", rv_codec_cj_jal, rv_fmt_rd_offset, NULL, rv_op_jal, 0, 0 },
    { "c.li", rv_codec_ci_li, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi },
    { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi, rv_op_addi, rv_op_addi },
    { "c.lui", rv_codec_ci_lui, rv_fmt_rd_imm, NULL, rv_op_lui, rv_op_lui, rv_op_lui },
    { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli, rv_op_srli, rv_op_srli },
    { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai, rv_op_srai, rv_op_srai },
    { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, NULL, rv_op_andi, rv_op_andi, rv_op_andi },
    { "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi,
      rv_op_addi, rv_op_addi, rvcd_imm_nz },
    { "c.lui", rv_codec_ci_lui, rv_fmt_rd_imm, NULL, rv_op_lui, rv_op_lui,
      rv_op_lui, rvcd_imm_nz },
    { "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli,
      rv_op_srli, rv_op_srli, rvcd_imm_nz },
    { "c.srai", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srai,
      rv_op_srai, rv_op_srai, rvcd_imm_nz },
    { "c.andi", rv_codec_cb_imm, rv_fmt_rd_rs1_imm, NULL, rv_op_andi,
      rv_op_andi, rv_op_andi },
    { "c.sub", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_sub, rv_op_sub, rv_op_sub },
    { "c.xor", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_xor, rv_op_xor, rv_op_xor },
    { "c.or", rv_codec_cs, rv_fmt_rd_rs1_rs2, NULL, rv_op_or, rv_op_or, rv_op_or },
@@ -1036,7 +1049,8 @@ const rv_opcode_data opcode_data[] = {
    { "c.j", rv_codec_cj, rv_fmt_rd_offset, NULL, rv_op_jal, rv_op_jal, rv_op_jal },
    { "c.beqz", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_beq, rv_op_beq, rv_op_beq },
    { "c.bnez", rv_codec_cb, rv_fmt_rs1_rs2_offset, NULL, rv_op_bne, rv_op_bne, rv_op_bne },
    { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_slli, rv_op_slli, rv_op_slli },
    { "c.slli", rv_codec_ci_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_slli,
      rv_op_slli, rv_op_slli, rvcd_imm_nz },
    { "c.fldsp", rv_codec_ci_ldsp, rv_fmt_frd_offset_rs1, NULL, rv_op_fld, rv_op_fld, rv_op_fld },
    { "c.lwsp", rv_codec_ci_lwsp, rv_fmt_rd_offset_rs1, NULL, rv_op_lw, rv_op_lw, rv_op_lw },
    { "c.flwsp", rv_codec_ci_lwsp, rv_fmt_frd_offset_rs1, NULL, rv_op_flw, 0, 0 },
@@ -2795,28 +2809,43 @@ static void decode_inst_decompress_rv32(rv_decode *dec)
{
    int decomp_op = opcode_data[dec->op].decomp_rv32;
    if (decomp_op != rv_op_illegal) {
        if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz)
            && dec->imm == 0) {
            dec->op = rv_op_illegal;
        } else {
            dec->op = decomp_op;
            dec->codec = opcode_data[decomp_op].codec;
        }
    }
}

static void decode_inst_decompress_rv64(rv_decode *dec)
{
    int decomp_op = opcode_data[dec->op].decomp_rv64;
    if (decomp_op != rv_op_illegal) {
        if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz)
            && dec->imm == 0) {
            dec->op = rv_op_illegal;
        } else {
            dec->op = decomp_op;
            dec->codec = opcode_data[decomp_op].codec;
        }
    }
}

static void decode_inst_decompress_rv128(rv_decode *dec)
{
    int decomp_op = opcode_data[dec->op].decomp_rv128;
    if (decomp_op != rv_op_illegal) {
        if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz)
            && dec->imm == 0) {
            dec->op = rv_op_illegal;
        } else {
            dec->op = decomp_op;
            dec->codec = opcode_data[decomp_op].codec;
        }
    }
}

static void decode_inst_decompress(rv_decode *dec, rv_isa isa)
{
+1 −0
Original line number Diff line number Diff line
obj-y += boot.o
obj-$(CONFIG_SPIKE) += riscv_htif.o
obj-$(CONFIG_HART) += riscv_hart.o
obj-$(CONFIG_SIFIVE_E) += sifive_e.o

hw/riscv/boot.c

0 → 100644
+105 −0
Original line number Diff line number Diff line
/*
 * QEMU RISC-V Boot Helper
 *
 * Copyright (c) 2017 SiFive, Inc.
 * Copyright (c) 2019 Alistair Francis <alistair.francis@wdc.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2 or later, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/error-report.h"
#include "exec/cpu-defs.h"
#include "hw/loader.h"
#include "hw/riscv/boot.h"
#include "hw/boards.h"
#include "elf.h"

#if defined(TARGET_RISCV32)
# define KERNEL_BOOT_ADDRESS 0x80400000
#else
# define KERNEL_BOOT_ADDRESS 0x80200000
#endif

target_ulong riscv_load_firmware(const char *firmware_filename,
                                 hwaddr firmware_load_addr)
{
    uint64_t firmware_entry, firmware_start, firmware_end;

    if (load_elf(firmware_filename, NULL, NULL, NULL, &firmware_entry,
                 &firmware_start, &firmware_end, 0, EM_RISCV, 1, 0) > 0) {
        return firmware_entry;
    }

    if (load_image_targphys_as(firmware_filename, firmware_load_addr,
                               ram_size, NULL) > 0) {
        return firmware_load_addr;
    }

    error_report("could not load firmware '%s'", firmware_filename);
    exit(1);
}

target_ulong riscv_load_kernel(const char *kernel_filename)
{
    uint64_t kernel_entry, kernel_high;

    if (load_elf(kernel_filename, NULL, NULL, NULL,
                 &kernel_entry, NULL, &kernel_high, 0, EM_RISCV, 1, 0) > 0) {
        return kernel_entry;
    }

    if (load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL,
                       NULL, NULL, NULL) > 0) {
        return kernel_entry;
    }

    if (load_image_targphys_as(kernel_filename, KERNEL_BOOT_ADDRESS,
                               ram_size, NULL) > 0) {
        return KERNEL_BOOT_ADDRESS;
    }

    error_report("could not load kernel '%s'", kernel_filename);
    exit(1);
}

hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size,
                         uint64_t kernel_entry, hwaddr *start)
{
    int size;

    /*
     * We want to put the initrd far enough into RAM that when the
     * kernel is uncompressed it will not clobber the initrd. However
     * on boards without much RAM we must ensure that we still leave
     * enough room for a decent sized initrd, and on boards with large
     * amounts of RAM we must avoid the initrd being so far up in RAM
     * that it is outside lowmem and inaccessible to the kernel.
     * So for boards with less  than 256MB of RAM we put the initrd
     * halfway into RAM, and for boards with 256MB of RAM or more we put
     * the initrd at 128MB.
     */
    *start = kernel_entry + MIN(mem_size / 2, 128 * MiB);

    size = load_ramdisk(filename, *start, mem_size - *start);
    if (size == -1) {
        size = load_image_targphys(filename, *start, mem_size - *start);
        if (size == -1) {
            error_report("could not load ramdisk '%s'", filename);
            exit(1);
        }
    }

    return *start + size;
}
+8 −22
Original line number Diff line number Diff line
@@ -44,10 +44,10 @@
#include "hw/riscv/sifive_prci.h"
#include "hw/riscv/sifive_uart.h"
#include "hw/riscv/sifive_e.h"
#include "hw/riscv/boot.h"
#include "chardev/char.h"
#include "sysemu/arch_init.h"
#include "exec/address-spaces.h"
#include "elf.h"

static const struct MemmapEntry {
    hwaddr base;
@@ -74,19 +74,6 @@ static const struct MemmapEntry {
    [SIFIVE_E_DTIM] =     { 0x80000000,     0x4000 }
};

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

    if (load_elf(kernel_filename, NULL, NULL, NULL,
                 &kernel_entry, NULL, &kernel_high,
                 0, EM_RISCV, 1, 0) < 0) {
        error_report("could not load kernel '%s'", kernel_filename);
        exit(1);
    }
    return kernel_entry;
}

static void sifive_mmio_emulate(MemoryRegion *parent, const char *name,
                             uintptr_t offset, uintptr_t length)
{
@@ -131,7 +118,7 @@ static void riscv_sifive_e_init(MachineState *machine)
                          memmap[SIFIVE_E_MROM].base, &address_space_memory);

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

@@ -158,17 +145,15 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp)

    SiFiveESoCState *s = RISCV_E_SOC(dev);
    MemoryRegion *sys_mem = get_system_memory();
    MemoryRegion *xip_mem = g_new(MemoryRegion, 1);
    MemoryRegion *mask_rom = g_new(MemoryRegion, 1);

    object_property_set_bool(OBJECT(&s->cpus), true, "realized",
                            &error_abort);

    /* Mask ROM */
    memory_region_init_rom(mask_rom, NULL, "riscv.sifive.e.mrom",
    memory_region_init_rom(&s->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);
        memmap[SIFIVE_E_MROM].base, &s->mask_rom);

    /* MMIO */
    s->plic = sifive_plic_create(memmap[SIFIVE_E_PLIC].base,
@@ -228,10 +213,11 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp)
        memmap[SIFIVE_E_PWM2].base, memmap[SIFIVE_E_PWM2].size);

    /* Flash memory */
    memory_region_init_ram(xip_mem, NULL, "riscv.sifive.e.xip",
    memory_region_init_ram(&s->xip_mem, NULL, "riscv.sifive.e.xip",
        memmap[SIFIVE_E_XIP].size, &error_fatal);
    memory_region_set_readonly(xip_mem, true);
    memory_region_add_subregion(sys_mem, memmap[SIFIVE_E_XIP].base, xip_mem);
    memory_region_set_readonly(&s->xip_mem, true);
    memory_region_add_subregion(sys_mem, memmap[SIFIVE_E_XIP].base,
        &s->xip_mem);
}

static void riscv_sifive_e_machine_init(MachineClass *mc)
+41 −8
Original line number Diff line number Diff line
@@ -24,15 +24,18 @@
#include "target/riscv/cpu.h"
#include "hw/riscv/sifive_prci.h"

/* currently implements enough to mock freedom-e-sdk BSP clock programming */

static uint64_t sifive_prci_read(void *opaque, hwaddr addr, unsigned int size)
{
    if (addr == 0 /* PRCI_HFROSCCFG */) {
        return 1 << 31; /* ROSC_RDY */
    }
    if (addr == 8 /* PRCI_PLLCFG    */) {
        return 1 << 31; /* PLL_LOCK */
    SiFivePRCIState *s = opaque;
    switch (addr) {
    case SIFIVE_PRCI_HFROSCCFG:
        return s->hfrosccfg;
    case SIFIVE_PRCI_HFXOSCCFG:
        return s->hfxosccfg;
    case SIFIVE_PRCI_PLLCFG:
        return s->pllcfg;
    case SIFIVE_PRCI_PLLOUTDIV:
        return s->plloutdiv;
    }
    hw_error("%s: read: addr=0x%x\n", __func__, (int)addr);
    return 0;
@@ -41,7 +44,30 @@ static uint64_t sifive_prci_read(void *opaque, hwaddr addr, unsigned int size)
static void sifive_prci_write(void *opaque, hwaddr addr,
           uint64_t val64, unsigned int size)
{
    /* discard writes */
    SiFivePRCIState *s = opaque;
    switch (addr) {
    case SIFIVE_PRCI_HFROSCCFG:
        s->hfrosccfg = (uint32_t) val64;
        /* OSC stays ready */
        s->hfrosccfg |= SIFIVE_PRCI_HFROSCCFG_RDY;
        break;
    case SIFIVE_PRCI_HFXOSCCFG:
        s->hfxosccfg = (uint32_t) val64;
        /* OSC stays ready */
        s->hfxosccfg |= SIFIVE_PRCI_HFXOSCCFG_RDY;
        break;
    case SIFIVE_PRCI_PLLCFG:
        s->pllcfg = (uint32_t) val64;
        /* PLL stays locked */
        s->pllcfg |= SIFIVE_PRCI_PLLCFG_LOCK;
        break;
    case SIFIVE_PRCI_PLLOUTDIV:
        s->plloutdiv = (uint32_t) val64;
        break;
    default:
        hw_error("%s: bad write: addr=0x%x v=0x%x\n",
                 __func__, (int)addr, (int)val64);
    }
}

static const MemoryRegionOps sifive_prci_ops = {
@@ -61,6 +87,13 @@ static void sifive_prci_init(Object *obj)
    memory_region_init_io(&s->mmio, obj, &sifive_prci_ops, s,
                          TYPE_SIFIVE_PRCI, 0x8000);
    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);

    s->hfrosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN);
    s->hfxosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN);
    s->pllcfg = (SIFIVE_PRCI_PLLCFG_REFSEL | SIFIVE_PRCI_PLLCFG_BYPASS |
                SIFIVE_PRCI_PLLCFG_LOCK);
    s->plloutdiv = SIFIVE_PRCI_PLLOUTDIV_DIV1;

}

static const TypeInfo sifive_prci_info = {
Loading