mirror of https://github.com/xemu-project/xemu.git
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:
commit
aeb07b5f6e
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
107
hw/riscv/boot.c
107
hw/riscv/boot.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
|
@ -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];
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue