This is a colection of bug fixes and small imrprovements for RISC-V.

This includes some vector extensions fixes, a PMP bug fix, OpenTitan
 UART bug fix and support for OpenSBI dynamic firmware.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAl8M/HgACgkQIeENKd+X
 cFTFDAf7BiC0iVDUNEdK91MU3eLBf3C+VcVXeFQ1U4WtQutajhC681jWtk4gemRW
 QnZ0HWuOkvvKrdrPqV18c6gKYg+qcgpQ/JMCtl2bFk41nfVLS2Amlza6ycooQAhK
 dMrwFDm0yRGy3gjsZwNaduQKaKWJqtZJc142yELtfgfJvNsHJirYKMt1YXMC/pJO
 62Z5kACbSVsUDAr02ZZnFw9PX09FQh75LZpfRC9haMpyqkyffARmsu6rAtZJpk1G
 XhXhJNq9j3IpBP0nt9BV7KNVW5KrbKnGwEnK+I5UZfEYmGrz4RFb+UWq/rqMF2ui
 fbe9tY2bJRwcnS+EbF0s97M6wEweSw==
 =T+nM
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20200713' into staging

This is a colection of bug fixes and small imrprovements for RISC-V.

This includes some vector extensions fixes, a PMP bug fix, OpenTitan
UART bug fix and support for OpenSBI dynamic firmware.

# gpg: Signature made Tue 14 Jul 2020 01:29:44 BST
# gpg:                using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054
# gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [full]
# Primary key fingerprint: F6C4 AC46 D493 4868 D3B8  CE8F 21E1 0D29 DF97 7054

* remotes/alistair/tags/pull-riscv-to-apply-20200713:
  target/riscv: Fix pmp NA4 implementation
  tcg/riscv: Remove superfluous breaks
  hw/char: Convert the Ibex UART to use the registerfields API
  hw/char: Convert the Ibex UART to use the qdev Clock model
  target/riscv: fix vill bit index in vtype register
  target/riscv: fix return value of do_opivx_widen()
  target/riscv: correct the gvec IR called in gen_vec_rsub16_i64()
  target/riscv: fix rsub gvec tcg_assert_listed_vecop assertion
  hw/riscv: Modify MROM size to end at 0x10000
  RISC-V: Support 64 bit start address
  riscv: Add opensbi firmware dynamic support
  RISC-V: Copy the fdt in dram instead of ROM
  riscv: Unify Qemu's reset vector code path
  hw/riscv: virt: Sort the SoC memmap table entries
  MAINTAINERS: Add an entry for OpenSBI firmware

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-07-14 17:58:00 +01:00
commit aeb07b5f6e
13 changed files with 387 additions and 219 deletions

View File

@ -2681,6 +2681,13 @@ F: hw/i386/intel_iommu.c
F: hw/i386/intel_iommu_internal.h
F: include/hw/i386/intel_iommu.h
OpenSBI Firmware
M: Bin Meng <bmeng.cn@gmail.com>
S: Supported
F: pc-bios/opensbi-*
F: .gitlab-ci.d/opensbi.yml
F: .gitlab-ci.d/opensbi/
Usermode Emulation
------------------
Overall usermode emulation

View File

@ -28,6 +28,7 @@
#include "qemu/osdep.h"
#include "hw/char/ibex_uart.h"
#include "hw/irq.h"
#include "hw/qdev-clock.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qemu/log.h"
@ -35,25 +36,25 @@
static void ibex_uart_update_irqs(IbexUartState *s)
{
if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_WATERMARK_MASK) {
qemu_set_irq(s->tx_watermark, 1);
} else {
qemu_set_irq(s->tx_watermark, 0);
}
if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) {
if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_WATERMARK_MASK) {
qemu_set_irq(s->rx_watermark, 1);
} else {
qemu_set_irq(s->rx_watermark, 0);
}
if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) {
if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_EMPTY_MASK) {
qemu_set_irq(s->tx_empty, 1);
} else {
qemu_set_irq(s->tx_empty, 0);
}
if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) {
if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_OVERFLOW_MASK) {
qemu_set_irq(s->rx_overflow, 1);
} else {
qemu_set_irq(s->rx_overflow, 0);
@ -64,7 +65,7 @@ static int ibex_uart_can_receive(void *opaque)
{
IbexUartState *s = opaque;
if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
return 1;
}
@ -74,16 +75,16 @@ static int ibex_uart_can_receive(void *opaque)
static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
{
IbexUartState *s = opaque;
uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL)
>> FIFO_CTRL_RXILVL_SHIFT;
uint8_t rx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_RXILVL_MASK)
>> R_FIFO_CTRL_RXILVL_SHIFT;
s->uart_rdata = *buf;
s->uart_status &= ~UART_STATUS_RXIDLE;
s->uart_status &= ~UART_STATUS_RXEMPTY;
s->uart_status &= ~R_STATUS_RXIDLE_MASK;
s->uart_status &= ~R_STATUS_RXEMPTY_MASK;
if (size > rx_fifo_level) {
s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
s->uart_intr_state |= R_INTR_STATE_RX_WATERMARK_MASK;
}
ibex_uart_update_irqs(s);
@ -93,8 +94,8 @@ static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
void *opaque)
{
IbexUartState *s = opaque;
uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
>> FIFO_CTRL_TXILVL_SHIFT;
uint8_t tx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK)
>> R_FIFO_CTRL_TXILVL_SHIFT;
int ret;
/* instant drain the fifo when there's no back-end */
@ -104,10 +105,10 @@ static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
}
if (!s->tx_level) {
s->uart_status &= ~UART_STATUS_TXFULL;
s->uart_status |= UART_STATUS_TXEMPTY;
s->uart_intr_state |= INTR_STATE_TX_EMPTY;
s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
s->uart_status &= ~R_STATUS_TXFULL_MASK;
s->uart_status |= R_STATUS_TXEMPTY_MASK;
s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK;
s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK;
ibex_uart_update_irqs(s);
return FALSE;
}
@ -130,18 +131,18 @@ static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond,
/* Clear the TX Full bit */
if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
s->uart_status &= ~UART_STATUS_TXFULL;
s->uart_status &= ~R_STATUS_TXFULL_MASK;
}
/* Disable the TX_WATERMARK IRQ */
if (s->tx_level < tx_fifo_level) {
s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK;
}
/* Set TX empty */
if (s->tx_level == 0) {
s->uart_status |= UART_STATUS_TXEMPTY;
s->uart_intr_state |= INTR_STATE_TX_EMPTY;
s->uart_status |= R_STATUS_TXEMPTY_MASK;
s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK;
}
ibex_uart_update_irqs(s);
@ -152,8 +153,8 @@ static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
int size)
{
uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL)
>> FIFO_CTRL_TXILVL_SHIFT;
uint8_t tx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK)
>> R_FIFO_CTRL_TXILVL_SHIFT;
if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
@ -164,16 +165,16 @@ static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf,
s->tx_level += size;
if (s->tx_level > 0) {
s->uart_status &= ~UART_STATUS_TXEMPTY;
s->uart_status &= ~R_STATUS_TXEMPTY_MASK;
}
if (s->tx_level >= tx_fifo_level) {
s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
s->uart_intr_state |= R_INTR_STATE_TX_WATERMARK_MASK;
ibex_uart_update_irqs(s);
}
if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
s->uart_status |= UART_STATUS_TXFULL;
s->uart_status |= R_STATUS_TXFULL_MASK;
}
timer_mod(s->fifo_trigger_handle, current_time +
@ -203,49 +204,60 @@ static void ibex_uart_reset(DeviceState *dev)
ibex_uart_update_irqs(s);
}
static uint64_t ibex_uart_get_baud(IbexUartState *s)
{
uint64_t baud;
baud = ((s->uart_ctrl & R_CTRL_NCO_MASK) >> 16);
baud *= clock_get_hz(s->f_clk);
baud >>= 20;
return baud;
}
static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
unsigned int size)
{
IbexUartState *s = opaque;
uint64_t retvalue = 0;
switch (addr) {
case IBEX_UART_INTR_STATE:
switch (addr >> 2) {
case R_INTR_STATE:
retvalue = s->uart_intr_state;
break;
case IBEX_UART_INTR_ENABLE:
case R_INTR_ENABLE:
retvalue = s->uart_intr_enable;
break;
case IBEX_UART_INTR_TEST:
case R_INTR_TEST:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: wdata is write only\n", __func__);
break;
case IBEX_UART_CTRL:
case R_CTRL:
retvalue = s->uart_ctrl;
break;
case IBEX_UART_STATUS:
case R_STATUS:
retvalue = s->uart_status;
break;
case IBEX_UART_RDATA:
case R_RDATA:
retvalue = s->uart_rdata;
if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
qemu_chr_fe_accept_input(&s->chr);
s->uart_status |= UART_STATUS_RXIDLE;
s->uart_status |= UART_STATUS_RXEMPTY;
s->uart_status |= R_STATUS_RXIDLE_MASK;
s->uart_status |= R_STATUS_RXEMPTY_MASK;
}
break;
case IBEX_UART_WDATA:
case R_WDATA:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: wdata is write only\n", __func__);
break;
case IBEX_UART_FIFO_CTRL:
case R_FIFO_CTRL:
retvalue = s->uart_fifo_ctrl;
break;
case IBEX_UART_FIFO_STATUS:
case R_FIFO_STATUS:
retvalue = s->uart_fifo_status;
retvalue |= s->tx_level & 0x1F;
@ -254,17 +266,17 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
"%s: RX fifos are not supported\n", __func__);
break;
case IBEX_UART_OVRD:
case R_OVRD:
retvalue = s->uart_ovrd;
qemu_log_mask(LOG_UNIMP,
"%s: ovrd is not supported\n", __func__);
break;
case IBEX_UART_VAL:
case R_VAL:
retvalue = s->uart_val;
qemu_log_mask(LOG_UNIMP,
"%s: val is not supported\n", __func__);
break;
case IBEX_UART_TIMEOUT_CTRL:
case R_TIMEOUT_CTRL:
retvalue = s->uart_timeout_ctrl;
qemu_log_mask(LOG_UNIMP,
"%s: timeout_ctrl is not supported\n", __func__);
@ -284,97 +296,95 @@ static void ibex_uart_write(void *opaque, hwaddr addr,
IbexUartState *s = opaque;
uint32_t value = val64;
switch (addr) {
case IBEX_UART_INTR_STATE:
switch (addr >> 2) {
case R_INTR_STATE:
/* Write 1 clear */
s->uart_intr_state &= ~value;
ibex_uart_update_irqs(s);
break;
case IBEX_UART_INTR_ENABLE:
case R_INTR_ENABLE:
s->uart_intr_enable = value;
ibex_uart_update_irqs(s);
break;
case IBEX_UART_INTR_TEST:
case R_INTR_TEST:
s->uart_intr_state |= value;
ibex_uart_update_irqs(s);
break;
case IBEX_UART_CTRL:
case R_CTRL:
s->uart_ctrl = value;
if (value & UART_CTRL_NF) {
if (value & R_CTRL_NF_MASK) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_NF is not supported\n", __func__);
}
if (value & UART_CTRL_SLPBK) {
if (value & R_CTRL_SLPBK_MASK) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_SLPBK is not supported\n", __func__);
}
if (value & UART_CTRL_LLPBK) {
if (value & R_CTRL_LLPBK_MASK) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_LLPBK is not supported\n", __func__);
}
if (value & UART_CTRL_PARITY_EN) {
if (value & R_CTRL_PARITY_EN_MASK) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_PARITY_EN is not supported\n",
__func__);
}
if (value & UART_CTRL_PARITY_ODD) {
if (value & R_CTRL_PARITY_ODD_MASK) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_PARITY_ODD is not supported\n",
__func__);
}
if (value & UART_CTRL_RXBLVL) {
if (value & R_CTRL_RXBLVL_MASK) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_RXBLVL is not supported\n", __func__);
}
if (value & UART_CTRL_NCO) {
uint64_t baud = ((value & UART_CTRL_NCO) >> 16);
baud *= 1000;
baud >>= 20;
if (value & R_CTRL_NCO_MASK) {
uint64_t baud = ibex_uart_get_baud(s);
s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
}
break;
case IBEX_UART_STATUS:
case R_STATUS:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: status is read only\n", __func__);
break;
case IBEX_UART_RDATA:
case R_RDATA:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: rdata is read only\n", __func__);
break;
case IBEX_UART_WDATA:
case R_WDATA:
uart_write_tx_fifo(s, (uint8_t *) &value, 1);
break;
case IBEX_UART_FIFO_CTRL:
case R_FIFO_CTRL:
s->uart_fifo_ctrl = value;
if (value & FIFO_CTRL_RXRST) {
if (value & R_FIFO_CTRL_RXRST_MASK) {
qemu_log_mask(LOG_UNIMP,
"%s: RX fifos are not supported\n", __func__);
}
if (value & FIFO_CTRL_TXRST) {
if (value & R_FIFO_CTRL_TXRST_MASK) {
s->tx_level = 0;
}
break;
case IBEX_UART_FIFO_STATUS:
case R_FIFO_STATUS:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: fifo_status is read only\n", __func__);
break;
case IBEX_UART_OVRD:
case R_OVRD:
s->uart_ovrd = value;
qemu_log_mask(LOG_UNIMP,
"%s: ovrd is not supported\n", __func__);
break;
case IBEX_UART_VAL:
case R_VAL:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: val is read only\n", __func__);
break;
case IBEX_UART_TIMEOUT_CTRL:
case R_TIMEOUT_CTRL:
s->uart_timeout_ctrl = value;
qemu_log_mask(LOG_UNIMP,
"%s: timeout_ctrl is not supported\n", __func__);
@ -385,11 +395,21 @@ static void ibex_uart_write(void *opaque, hwaddr addr,
}
}
static void ibex_uart_clk_update(void *opaque)
{
IbexUartState *s = opaque;
/* recompute uart's speed on clock change */
uint64_t baud = ibex_uart_get_baud(s);
s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
}
static void fifo_trigger_update(void *opaque)
{
IbexUartState *s = opaque;
if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
if (s->uart_ctrl & R_CTRL_TX_ENABLE_MASK) {
ibex_uart_xmit(NULL, G_IO_OUT, s);
}
}
@ -444,6 +464,10 @@ static void ibex_uart_init(Object *obj)
{
IbexUartState *s = IBEX_UART(obj);
s->f_clk = qdev_init_clock_in(DEVICE(obj), "f_clock",
ibex_uart_clk_update, s);
clock_set_hz(s->f_clk, IBEX_UART_CLOCK);
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark);
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark);
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty);

View File

@ -25,13 +25,19 @@
#include "hw/boards.h"
#include "hw/loader.h"
#include "hw/riscv/boot.h"
#include "hw/riscv/boot_opensbi.h"
#include "elf.h"
#include "sysemu/device_tree.h"
#include "sysemu/qtest.h"
#include <libfdt.h>
#if defined(TARGET_RISCV32)
# define KERNEL_BOOT_ADDRESS 0x80400000
#define fw_dynamic_info_data(__val) cpu_to_le32(__val)
#else
# define KERNEL_BOOT_ADDRESS 0x80200000
#define fw_dynamic_info_data(__val) cpu_to_le64(__val)
#endif
void riscv_find_and_load_firmware(MachineState *machine,
@ -155,3 +161,104 @@ hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size,
return *start + size;
}
uint32_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt)
{
uint32_t temp, fdt_addr;
hwaddr dram_end = dram_base + mem_size;
int fdtsize = fdt_totalsize(fdt);
if (fdtsize <= 0) {
error_report("invalid device-tree");
exit(1);
}
/*
* We should put fdt as far as possible to avoid kernel/initrd overwriting
* its content. But it should be addressable by 32 bit system as well.
* Thus, put it at an aligned address that less than fdt size from end of
* dram or 4GB whichever is lesser.
*/
temp = MIN(dram_end, 4096 * MiB);
fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB);
fdt_pack(fdt);
/* copy in the device tree */
qemu_fdt_dumpdtb(fdt, fdtsize);
rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr,
&address_space_memory);
return fdt_addr;
}
void riscv_rom_copy_firmware_info(hwaddr rom_base, hwaddr rom_size,
uint32_t reset_vec_size, uint64_t kernel_entry)
{
struct fw_dynamic_info dinfo;
size_t dinfo_len;
dinfo.magic = fw_dynamic_info_data(FW_DYNAMIC_INFO_MAGIC_VALUE);
dinfo.version = fw_dynamic_info_data(FW_DYNAMIC_INFO_VERSION);
dinfo.next_mode = fw_dynamic_info_data(FW_DYNAMIC_INFO_NEXT_MODE_S);
dinfo.next_addr = fw_dynamic_info_data(kernel_entry);
dinfo.options = 0;
dinfo.boot_hart = 0;
dinfo_len = sizeof(dinfo);
/**
* copy the dynamic firmware info. This information is specific to
* OpenSBI but doesn't break any other firmware as long as they don't
* expect any certain value in "a2" register.
*/
if (dinfo_len > (rom_size - reset_vec_size)) {
error_report("not enough space to store dynamic firmware info");
exit(1);
}
rom_add_blob_fixed_as("mrom.finfo", &dinfo, dinfo_len,
rom_base + reset_vec_size,
&address_space_memory);
}
void riscv_setup_rom_reset_vec(hwaddr start_addr, hwaddr rom_base,
hwaddr rom_size, uint64_t kernel_entry,
uint32_t fdt_load_addr, void *fdt)
{
int i;
uint32_t start_addr_hi32 = 0x00000000;
#if defined(TARGET_RISCV64)
start_addr_hi32 = start_addr >> 32;
#endif
/* reset vector */
uint32_t reset_vec[10] = {
0x00000297, /* 1: auipc t0, %pcrel_hi(fw_dyn) */
0x02828613, /* addi a2, t0, %pcrel_lo(1b) */
0xf1402573, /* csrr a0, mhartid */
#if defined(TARGET_RISCV32)
0x0202a583, /* lw a1, 32(t0) */
0x0182a283, /* lw t0, 24(t0) */
#elif defined(TARGET_RISCV64)
0x0202b583, /* ld a1, 32(t0) */
0x0182b283, /* ld t0, 24(t0) */
#endif
0x00028067, /* jr t0 */
start_addr, /* start: .dword */
start_addr_hi32,
fdt_load_addr, /* fdt_laddr: .dword */
0x00000000,
/* fw_dyn: */
};
/* copy in the reset vector in little_endian byte order */
for (i = 0; i < ARRAY_SIZE(reset_vec); i++) {
reset_vec[i] = cpu_to_le32(reset_vec[i]);
}
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
rom_base, &address_space_memory);
riscv_rom_copy_firmware_info(rom_base, rom_size, sizeof(reset_vec),
kernel_entry);
return;
}

View File

@ -56,7 +56,6 @@
#include "sysemu/device_tree.h"
#include "sysemu/runstate.h"
#include "sysemu/sysemu.h"
#include "exec/address-spaces.h"
#include <libfdt.h>
@ -71,7 +70,7 @@ static const struct MemmapEntry {
hwaddr size;
} sifive_u_memmap[] = {
[SIFIVE_U_DEBUG] = { 0x0, 0x100 },
[SIFIVE_U_MROM] = { 0x1000, 0x11000 },
[SIFIVE_U_MROM] = { 0x1000, 0xf000 },
[SIFIVE_U_CLINT] = { 0x2000000, 0x10000 },
[SIFIVE_U_L2LIM] = { 0x8000000, 0x2000000 },
[SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 },
@ -379,7 +378,10 @@ static void sifive_u_machine_init(MachineState *machine)
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
MemoryRegion *flash0 = g_new(MemoryRegion, 1);
target_ulong start_addr = memmap[SIFIVE_U_DRAM].base;
uint32_t start_addr_hi32 = 0x00000000;
int i;
uint32_t fdt_load_addr;
uint64_t kernel_entry;
/* Initialize SoC */
object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC);
@ -436,8 +438,7 @@ static void sifive_u_machine_init(MachineState *machine)
riscv_find_and_load_firmware(machine, BIOS_FILENAME, start_addr, NULL);
if (machine->kernel_filename) {
uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename,
NULL);
kernel_entry = riscv_load_kernel(machine->kernel_filename, NULL);
if (machine->initrd_filename) {
hwaddr start;
@ -449,42 +450,52 @@ static void sifive_u_machine_init(MachineState *machine)
qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
end);
}
} else {
/*
* If dynamic firmware is used, it doesn't know where is the next mode
* if kernel argument is not set.
*/
kernel_entry = 0;
}
/* Compute the fdt load address in dram */
fdt_load_addr = riscv_load_fdt(memmap[SIFIVE_U_DRAM].base,
machine->ram_size, s->fdt);
#if defined(TARGET_RISCV64)
start_addr_hi32 = start_addr >> 32;
#endif
/* reset vector */
uint32_t reset_vec[8] = {
uint32_t reset_vec[11] = {
s->msel, /* MSEL pin state */
0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */
0x01c28593, /* addi a1, t0, %pcrel_lo(1b) */
0x00000297, /* 1: auipc t0, %pcrel_hi(fw_dyn) */
0x02828613, /* addi a2, t0, %pcrel_lo(1b) */
0xf1402573, /* csrr a0, mhartid */
#if defined(TARGET_RISCV32)
0x0202a583, /* lw a1, 32(t0) */
0x0182a283, /* lw t0, 24(t0) */
#elif defined(TARGET_RISCV64)
0x0182e283, /* lwu t0, 24(t0) */
0x0202b583, /* ld a1, 32(t0) */
0x0182b283, /* ld t0, 24(t0) */
#endif
0x00028067, /* jr t0 */
0x00000000,
start_addr, /* start: .dword */
/* dtb: */
start_addr_hi32,
fdt_load_addr, /* fdt_laddr: .dword */
0x00000000,
/* fw_dyn: */
};
/* copy in the reset vector in little_endian byte order */
for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
for (i = 0; i < ARRAY_SIZE(reset_vec); 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 */
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);
riscv_rom_copy_firmware_info(memmap[SIFIVE_U_MROM].base,
memmap[SIFIVE_U_MROM].size,
sizeof(reset_vec), kernel_entry);
}
static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp)

View File

@ -41,9 +41,6 @@
#include "sysemu/device_tree.h"
#include "sysemu/qtest.h"
#include "sysemu/sysemu.h"
#include "exec/address-spaces.h"
#include <libfdt.h>
#if defined(TARGET_RISCV32)
# define BIOS_FILENAME "opensbi-riscv32-spike-fw_jump.elf"
@ -55,7 +52,7 @@ static const struct MemmapEntry {
hwaddr base;
hwaddr size;
} spike_memmap[] = {
[SPIKE_MROM] = { 0x1000, 0x11000 },
[SPIKE_MROM] = { 0x1000, 0xf000 },
[SPIKE_CLINT] = { 0x2000000, 0x10000 },
[SPIKE_DRAM] = { 0x80000000, 0x0 },
};
@ -165,8 +162,9 @@ static void spike_board_init(MachineState *machine)
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
int i;
unsigned int smp_cpus = machine->smp.cpus;
uint32_t fdt_load_addr;
uint64_t kernel_entry;
/* Initialize SOC */
object_initialize_child(OBJECT(machine), "soc", &s->soc,
@ -197,8 +195,8 @@ static void spike_board_init(MachineState *machine)
htif_symbol_callback);
if (machine->kernel_filename) {
uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename,
htif_symbol_callback);
kernel_entry = riscv_load_kernel(machine->kernel_filename,
htif_symbol_callback);
if (machine->initrd_filename) {
hwaddr start;
@ -210,42 +208,21 @@ static void spike_board_init(MachineState *machine)
qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
end);
}
} else {
/*
* If dynamic firmware is used, it doesn't know where is the next mode
* if kernel argument is not set.
*/
kernel_entry = 0;
}
/* reset vector */
uint32_t reset_vec[8] = {
0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */
0x02028593, /* addi a1, t0, %pcrel_lo(1b) */
0xf1402573, /* csrr a0, mhartid */
#if defined(TARGET_RISCV32)
0x0182a283, /* lw t0, 24(t0) */
#elif defined(TARGET_RISCV64)
0x0182b283, /* ld t0, 24(t0) */
#endif
0x00028067, /* jr t0 */
0x00000000,
memmap[SPIKE_DRAM].base, /* start: .dword DRAM_BASE */
0x00000000,
/* dtb: */
};
/* 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[SPIKE_MROM].base, &address_space_memory);
/* copy in the device tree */
if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) >
memmap[SPIKE_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[SPIKE_MROM].base + sizeof(reset_vec),
&address_space_memory);
/* Compute the fdt load address in dram */
fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base,
machine->ram_size, s->fdt);
/* load the reset vector */
riscv_setup_rom_reset_vec(memmap[SPIKE_DRAM].base, memmap[SPIKE_MROM].base,
memmap[SPIKE_MROM].size, kernel_entry,
fdt_load_addr, s->fdt);
/* initialize HTIF using symbols found in load_kernel */
htif_mm_init(system_memory, mask_rom, &s->soc.harts[0].env, serial_hd(0));

View File

@ -39,12 +39,9 @@
#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
#include "sysemu/sysemu.h"
#include "exec/address-spaces.h"
#include "hw/pci/pci.h"
#include "hw/pci-host/gpex.h"
#include <libfdt.h>
#if defined(TARGET_RISCV32)
# define BIOS_FILENAME "opensbi-riscv32-virt-fw_jump.bin"
#else
@ -56,18 +53,18 @@ static const struct MemmapEntry {
hwaddr size;
} virt_memmap[] = {
[VIRT_DEBUG] = { 0x0, 0x100 },
[VIRT_MROM] = { 0x1000, 0x11000 },
[VIRT_MROM] = { 0x1000, 0xf000 },
[VIRT_TEST] = { 0x100000, 0x1000 },
[VIRT_RTC] = { 0x101000, 0x1000 },
[VIRT_CLINT] = { 0x2000000, 0x10000 },
[VIRT_PCIE_PIO] = { 0x3000000, 0x10000 },
[VIRT_PLIC] = { 0xc000000, 0x4000000 },
[VIRT_UART0] = { 0x10000000, 0x100 },
[VIRT_VIRTIO] = { 0x10001000, 0x1000 },
[VIRT_FLASH] = { 0x20000000, 0x4000000 },
[VIRT_DRAM] = { 0x80000000, 0x0 },
[VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
[VIRT_PCIE_PIO] = { 0x03000000, 0x00010000 },
[VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 },
[VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
[VIRT_DRAM] = { 0x80000000, 0x0 },
};
#define VIRT_FLASH_SECTOR_SIZE (256 * KiB)
@ -481,6 +478,8 @@ static void virt_machine_init(MachineState *machine)
char *plic_hart_config;
size_t plic_hart_config_len;
target_ulong start_addr = memmap[VIRT_DRAM].base;
uint32_t fdt_load_addr;
uint64_t kernel_entry;
int i;
unsigned int smp_cpus = machine->smp.cpus;
@ -512,8 +511,7 @@ static void virt_machine_init(MachineState *machine)
memmap[VIRT_DRAM].base, NULL);
if (machine->kernel_filename) {
uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename,
NULL);
kernel_entry = riscv_load_kernel(machine->kernel_filename, NULL);
if (machine->initrd_filename) {
hwaddr start;
@ -525,6 +523,12 @@ static void virt_machine_init(MachineState *machine)
qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
end);
}
} else {
/*
* If dynamic firmware is used, it doesn't know where is the next mode
* if kernel argument is not set.
*/
kernel_entry = 0;
}
if (drive_get(IF_PFLASH, 0, 0)) {
@ -535,40 +539,13 @@ static void virt_machine_init(MachineState *machine)
start_addr = virt_memmap[VIRT_FLASH].base;
}
/* reset vector */
uint32_t reset_vec[8] = {
0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */
0x02028593, /* addi a1, t0, %pcrel_lo(1b) */
0xf1402573, /* csrr a0, mhartid */
#if defined(TARGET_RISCV32)
0x0182a283, /* lw t0, 24(t0) */
#elif defined(TARGET_RISCV64)
0x0182b283, /* ld t0, 24(t0) */
#endif
0x00028067, /* jr t0 */
0x00000000,
start_addr, /* start: .dword */
0x00000000,
/* dtb: */
};
/* 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[VIRT_MROM].base, &address_space_memory);
/* copy in the device tree */
if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) >
memmap[VIRT_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[VIRT_MROM].base + sizeof(reset_vec),
&address_space_memory);
/* Compute the fdt load address in dram */
fdt_load_addr = riscv_load_fdt(memmap[VIRT_DRAM].base,
machine->ram_size, s->fdt);
/* load the reset vector */
riscv_setup_rom_reset_vec(start_addr, virt_memmap[VIRT_MROM].base,
virt_memmap[VIRT_MROM].size, kernel_entry,
fdt_load_addr, s->fdt);
/* create PLIC hart topology configuration string */
plic_hart_config_len = (strlen(VIRT_PLIC_HART_CONFIG) + 1) * smp_cpus;

View File

@ -26,52 +26,47 @@
#define HW_IBEX_UART_H
#include "hw/sysbus.h"
#include "hw/registerfields.h"
#include "chardev/char-fe.h"
#include "qemu/timer.h"
#define IBEX_UART_INTR_STATE 0x00
#define INTR_STATE_TX_WATERMARK (1 << 0)
#define INTR_STATE_RX_WATERMARK (1 << 1)
#define INTR_STATE_TX_EMPTY (1 << 2)
#define INTR_STATE_RX_OVERFLOW (1 << 3)
#define IBEX_UART_INTR_ENABLE 0x04
#define IBEX_UART_INTR_TEST 0x08
#define IBEX_UART_CTRL 0x0c
#define UART_CTRL_TX_ENABLE (1 << 0)
#define UART_CTRL_RX_ENABLE (1 << 1)
#define UART_CTRL_NF (1 << 2)
#define UART_CTRL_SLPBK (1 << 4)
#define UART_CTRL_LLPBK (1 << 5)
#define UART_CTRL_PARITY_EN (1 << 6)
#define UART_CTRL_PARITY_ODD (1 << 7)
#define UART_CTRL_RXBLVL (3 << 8)
#define UART_CTRL_NCO (0xFFFF << 16)
#define IBEX_UART_STATUS 0x10
#define UART_STATUS_TXFULL (1 << 0)
#define UART_STATUS_RXFULL (1 << 1)
#define UART_STATUS_TXEMPTY (1 << 2)
#define UART_STATUS_RXIDLE (1 << 4)
#define UART_STATUS_RXEMPTY (1 << 5)
#define IBEX_UART_RDATA 0x14
#define IBEX_UART_WDATA 0x18
#define IBEX_UART_FIFO_CTRL 0x1c
#define FIFO_CTRL_RXRST (1 << 0)
#define FIFO_CTRL_TXRST (1 << 1)
#define FIFO_CTRL_RXILVL (7 << 2)
#define FIFO_CTRL_RXILVL_SHIFT (2)
#define FIFO_CTRL_TXILVL (3 << 5)
#define FIFO_CTRL_TXILVL_SHIFT (5)
#define IBEX_UART_FIFO_STATUS 0x20
#define IBEX_UART_OVRD 0x24
#define IBEX_UART_VAL 0x28
#define IBEX_UART_TIMEOUT_CTRL 0x2c
REG32(INTR_STATE, 0x00)
FIELD(INTR_STATE, TX_WATERMARK, 0, 1)
FIELD(INTR_STATE, RX_WATERMARK, 1, 1)
FIELD(INTR_STATE, TX_EMPTY, 2, 1)
FIELD(INTR_STATE, RX_OVERFLOW, 3, 1)
REG32(INTR_ENABLE, 0x04)
REG32(INTR_TEST, 0x08)
REG32(CTRL, 0x0C)
FIELD(CTRL, TX_ENABLE, 0, 1)
FIELD(CTRL, RX_ENABLE, 1, 1)
FIELD(CTRL, NF, 2, 1)
FIELD(CTRL, SLPBK, 4, 1)
FIELD(CTRL, LLPBK, 5, 1)
FIELD(CTRL, PARITY_EN, 6, 1)
FIELD(CTRL, PARITY_ODD, 7, 1)
FIELD(CTRL, RXBLVL, 8, 2)
FIELD(CTRL, NCO, 16, 16)
REG32(STATUS, 0x10)
FIELD(STATUS, TXFULL, 0, 1)
FIELD(STATUS, RXFULL, 1, 1)
FIELD(STATUS, TXEMPTY, 2, 1)
FIELD(STATUS, RXIDLE, 4, 1)
FIELD(STATUS, RXEMPTY, 5, 1)
REG32(RDATA, 0x14)
REG32(WDATA, 0x18)
REG32(FIFO_CTRL, 0x1c)
FIELD(FIFO_CTRL, RXRST, 0, 1)
FIELD(FIFO_CTRL, TXRST, 1, 1)
FIELD(FIFO_CTRL, RXILVL, 2, 3)
FIELD(FIFO_CTRL, TXILVL, 5, 2)
REG32(FIFO_STATUS, 0x20)
REG32(OVRD, 0x24)
REG32(VAL, 0x28)
REG32(TIMEOUT_CTRL, 0x2c)
#define IBEX_UART_TX_FIFO_SIZE 16
#define IBEX_UART_CLOCK 50000000 /* 50MHz clock */
#define TYPE_IBEX_UART "ibex-uart"
#define IBEX_UART(obj) \
@ -101,6 +96,8 @@ typedef struct {
uint32_t uart_val;
uint32_t uart_timeout_ctrl;
Clock *f_clk;
CharBackend chr;
qemu_irq tx_watermark;
qemu_irq rx_watermark;

View File

@ -35,5 +35,12 @@ target_ulong riscv_load_kernel(const char *kernel_filename,
symbol_fn_t sym_cb);
hwaddr riscv_load_initrd(const char *filename, uint64_t mem_size,
uint64_t kernel_entry, hwaddr *start);
uint32_t riscv_load_fdt(hwaddr dram_start, uint64_t dram_size, void *fdt);
void riscv_setup_rom_reset_vec(hwaddr saddr, hwaddr rom_base,
hwaddr rom_size, uint64_t kernel_entry,
uint32_t fdt_load_addr, void *fdt);
void riscv_rom_copy_firmware_info(hwaddr rom_base, hwaddr rom_size,
uint32_t reset_vec_size,
uint64_t kernel_entry);
#endif /* RISCV_BOOT_H */

View File

@ -0,0 +1,58 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (c) 2019 Western Digital Corporation or its affiliates.
*
* Based on include/sbi/{fw_dynamic.h,sbi_scratch.h} from the OpenSBI project.
*/
#ifndef OPENSBI_H
#define OPENSBI_H
/** Expected value of info magic ('OSBI' ascii string in hex) */
#define FW_DYNAMIC_INFO_MAGIC_VALUE 0x4942534f
/** Maximum supported info version */
#define FW_DYNAMIC_INFO_VERSION 0x2
/** Possible next mode values */
#define FW_DYNAMIC_INFO_NEXT_MODE_U 0x0
#define FW_DYNAMIC_INFO_NEXT_MODE_S 0x1
#define FW_DYNAMIC_INFO_NEXT_MODE_M 0x3
enum sbi_scratch_options {
/** Disable prints during boot */
SBI_SCRATCH_NO_BOOT_PRINTS = (1 << 0),
/** Enable runtime debug prints */
SBI_SCRATCH_DEBUG_PRINTS = (1 << 1),
};
/** Representation dynamic info passed by previous booting stage */
struct fw_dynamic_info {
/** Info magic */
target_long magic;
/** Info version */
target_long version;
/** Next booting stage address */
target_long next_addr;
/** Next booting stage mode */
target_long next_mode;
/** Options for OpenSBI library */
target_long options;
/**
* Preferred boot HART id
*
* It is possible that the previous booting stage uses same link
* address as the FW_DYNAMIC firmware. In this case, the relocation
* lottery mechanism can potentially overwrite the previous booting
* stage while other HARTs are still running in the previous booting
* stage leading to boot-time crash. To avoid this boot-time crash,
* the previous booting stage can specify last HART that will jump
* to the FW_DYNAMIC firmware as the preferred boot HART.
*
* To avoid specifying a preferred boot HART, the previous booting
* stage can set it to -1UL which will force the FW_DYNAMIC firmware
* to use the relocation lottery mechanism.
*/
target_long boot_hart;
};
#endif

View File

@ -98,7 +98,7 @@ FIELD(VTYPE, VLMUL, 0, 2)
FIELD(VTYPE, VSEW, 2, 3)
FIELD(VTYPE, VEDIV, 5, 2)
FIELD(VTYPE, RESERVED, 7, sizeof(target_ulong) * 8 - 9)
FIELD(VTYPE, VILL, sizeof(target_ulong) * 8 - 2, 1)
FIELD(VTYPE, VILL, sizeof(target_ulong) * 8 - 1, 1)
struct CPURISCVState {
target_ulong gpr[32];

View File

@ -937,7 +937,7 @@ static void gen_vec_rsub8_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
static void gen_vec_rsub16_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
{
tcg_gen_vec_sub8_i64(d, b, a);
tcg_gen_vec_sub16_i64(d, b, a);
}
static void gen_rsub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
@ -958,22 +958,27 @@ static void gen_rsub_vec(unsigned vece, TCGv_vec r, TCGv_vec a, TCGv_vec b)
static void tcg_gen_gvec_rsubs(unsigned vece, uint32_t dofs, uint32_t aofs,
TCGv_i64 c, uint32_t oprsz, uint32_t maxsz)
{
static const TCGOpcode vecop_list[] = { INDEX_op_sub_vec, 0 };
static const GVecGen2s rsub_op[4] = {
{ .fni8 = gen_vec_rsub8_i64,
.fniv = gen_rsub_vec,
.fno = gen_helper_vec_rsubs8,
.opt_opc = vecop_list,
.vece = MO_8 },
{ .fni8 = gen_vec_rsub16_i64,
.fniv = gen_rsub_vec,
.fno = gen_helper_vec_rsubs16,
.opt_opc = vecop_list,
.vece = MO_16 },
{ .fni4 = gen_rsub_i32,
.fniv = gen_rsub_vec,
.fno = gen_helper_vec_rsubs32,
.opt_opc = vecop_list,
.vece = MO_32 },
{ .fni8 = gen_rsub_i64,
.fniv = gen_rsub_vec,
.fno = gen_helper_vec_rsubs64,
.opt_opc = vecop_list,
.prefer_i64 = TCG_TARGET_REG_BITS == 64,
.vece = MO_64 },
};
@ -1146,7 +1151,7 @@ static bool do_opivx_widen(DisasContext *s, arg_rmrr *a,
if (opivx_widen_check(s, a)) {
return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, fn, s);
}
return true;
return false;
}
#define GEN_OPIVX_WIDEN_TRANS(NAME) \

View File

@ -171,7 +171,7 @@ static void pmp_update_rule(CPURISCVState *env, uint32_t pmp_index)
case PMP_AMATCH_NA4:
sa = this_addr << 2; /* shift up from [xx:0] to [xx+2:2] */
ea = (this_addr + 4u) - 1u;
ea = (sa + 4u) - 1u;
break;
case PMP_AMATCH_NAPOT:

View File

@ -502,10 +502,8 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type,
break;
case R_RISCV_JAL:
return reloc_jimm20(code_ptr, (tcg_insn_unit *)value);
break;
case R_RISCV_CALL:
return reloc_call(code_ptr, (tcg_insn_unit *)value);
break;
default:
tcg_abort();
}