提交 171199f5 编写于 作者: P Peter Maydell

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

This is a range of patches for RISC-V.

Some key points are:
 - Generalise the CPU init functions
 - Support the SiFive revB machine
 - Improvements to the Hypervisor implementation and error checking
 - Connect some OpenTitan devices
 - Changes to the sifive_u machine to support U-boot

v2:
 - Fix missing realise assert

# gpg: Signature made Fri 19 Jun 2020 17:34:34 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-20200619-3: (32 commits)
  hw/riscv: sifive_u: Add a dummy DDR memory controller device
  hw/riscv: sifive_u: Sort the SoC memmap table entries
  hw/riscv: sifive_u: Support different boot source per MSEL pin state
  hw/riscv: sifive: Change SiFive E/U CPU reset vector to 0x1004
  target/riscv: Rename IBEX CPU init routine
  hw/riscv: sifive_u: Add a new property msel for MSEL pin state
  hw/riscv: sifive_u: Rename serial property get/set functions to a generic name
  hw/riscv: sifive_u: Add reset functionality
  hw/riscv: sifive_gpio: Do not blindly trigger output IRQs
  hw/riscv: sifive_u: Hook a GPIO controller
  hw/riscv: sifive_gpio: Add a new 'ngpio' property
  hw/riscv: sifive_gpio: Clean up the codes
  hw/riscv: sifive_u: Generate device tree node for OTP
  hw/riscv: sifive_u: Simplify the GEM IRQ connect code a little bit
  hw/riscv: opentitan: Remove the riscv_ prefix of the machine* and soc* functions
  hw/riscv: sifive_e: Remove the riscv_ prefix of the machine* and soc* functions
  target/riscv: Use a smaller guess size for no-MMU PMP
  riscv/opentitan: Connect the UART device
  riscv/opentitan: Connect the PLIC device
  hw/intc: Initial commit of lowRISC Ibex PLIC
  ...
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
...@@ -1250,7 +1250,11 @@ M: Alistair Francis <Alistair.Francis@wdc.com> ...@@ -1250,7 +1250,11 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
L: qemu-riscv@nongnu.org L: qemu-riscv@nongnu.org
S: Supported S: Supported
F: hw/riscv/opentitan.c F: hw/riscv/opentitan.c
F: hw/char/ibex_uart.c
F: hw/intc/ibex_plic.c
F: include/hw/riscv/opentitan.h F: include/hw/riscv/opentitan.h
F: include/hw/char/ibex_uart.h
F: include/hw/intc/ibex_plic.h
SH4 Machines SH4 Machines
------------ ------------
......
...@@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o ...@@ -12,6 +12,7 @@ common-obj-$(CONFIG_VIRTIO_SERIAL) += virtio-console.o
common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
common-obj-$(CONFIG_XEN) += xen_console.o common-obj-$(CONFIG_XEN) += xen_console.o
common-obj-$(CONFIG_CADENCE) += cadence_uart.o common-obj-$(CONFIG_CADENCE) += cadence_uart.o
common-obj-$(CONFIG_IBEX) += ibex_uart.o
common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o common-obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o common-obj-$(CONFIG_COLDFIRE) += mcf_uart.o
......
/*
* QEMU lowRISC Ibex UART device
*
* Copyright (c) 2020 Western Digital
*
* For details check the documentation here:
* https://docs.opentitan.org/hw/ip/uart/doc/
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/char/ibex_uart.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/module.h"
static void ibex_uart_update_irqs(IbexUartState *s)
{
if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) {
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) {
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) {
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) {
qemu_set_irq(s->rx_overflow, 1);
} else {
qemu_set_irq(s->rx_overflow, 0);
}
}
static int ibex_uart_can_receive(void *opaque)
{
IbexUartState *s = opaque;
if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
return 1;
}
return 0;
}
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;
s->uart_rdata = *buf;
s->uart_status &= ~UART_STATUS_RXIDLE;
s->uart_status &= ~UART_STATUS_RXEMPTY;
if (size > rx_fifo_level) {
s->uart_intr_state |= INTR_STATE_RX_WATERMARK;
}
ibex_uart_update_irqs(s);
}
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;
int ret;
/* instant drain the fifo when there's no back-end */
if (!qemu_chr_fe_backend_connected(&s->chr)) {
s->tx_level = 0;
return FALSE;
}
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;
ibex_uart_update_irqs(s);
return FALSE;
}
ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level);
if (ret >= 0) {
s->tx_level -= ret;
memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level);
}
if (s->tx_level) {
guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
ibex_uart_xmit, s);
if (!r) {
s->tx_level = 0;
return FALSE;
}
}
/* Clear the TX Full bit */
if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) {
s->uart_status &= ~UART_STATUS_TXFULL;
}
/* Disable the TX_WATERMARK IRQ */
if (s->tx_level < tx_fifo_level) {
s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK;
}
/* Set TX empty */
if (s->tx_level == 0) {
s->uart_status |= UART_STATUS_TXEMPTY;
s->uart_intr_state |= INTR_STATE_TX_EMPTY;
}
ibex_uart_update_irqs(s);
return FALSE;
}
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;
if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) {
size = IBEX_UART_TX_FIFO_SIZE - s->tx_level;
qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow");
}
memcpy(s->tx_fifo + s->tx_level, buf, size);
s->tx_level += size;
if (s->tx_level > 0) {
s->uart_status &= ~UART_STATUS_TXEMPTY;
}
if (s->tx_level >= tx_fifo_level) {
s->uart_intr_state |= INTR_STATE_TX_WATERMARK;
ibex_uart_update_irqs(s);
}
if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) {
s->uart_status |= UART_STATUS_TXFULL;
}
timer_mod(s->fifo_trigger_handle, current_time +
(s->char_tx_time * 4));
}
static void ibex_uart_reset(DeviceState *dev)
{
IbexUartState *s = IBEX_UART(dev);
s->uart_intr_state = 0x00000000;
s->uart_intr_state = 0x00000000;
s->uart_intr_enable = 0x00000000;
s->uart_ctrl = 0x00000000;
s->uart_status = 0x0000003c;
s->uart_rdata = 0x00000000;
s->uart_fifo_ctrl = 0x00000000;
s->uart_fifo_status = 0x00000000;
s->uart_ovrd = 0x00000000;
s->uart_val = 0x00000000;
s->uart_timeout_ctrl = 0x00000000;
s->tx_level = 0;
s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
ibex_uart_update_irqs(s);
}
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:
retvalue = s->uart_intr_state;
break;
case IBEX_UART_INTR_ENABLE:
retvalue = s->uart_intr_enable;
break;
case IBEX_UART_INTR_TEST:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: wdata is write only\n", __func__);
break;
case IBEX_UART_CTRL:
retvalue = s->uart_ctrl;
break;
case IBEX_UART_STATUS:
retvalue = s->uart_status;
break;
case IBEX_UART_RDATA:
retvalue = s->uart_rdata;
if (s->uart_ctrl & UART_CTRL_RX_ENABLE) {
qemu_chr_fe_accept_input(&s->chr);
s->uart_status |= UART_STATUS_RXIDLE;
s->uart_status |= UART_STATUS_RXEMPTY;
}
break;
case IBEX_UART_WDATA:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: wdata is write only\n", __func__);
break;
case IBEX_UART_FIFO_CTRL:
retvalue = s->uart_fifo_ctrl;
break;
case IBEX_UART_FIFO_STATUS:
retvalue = s->uart_fifo_status;
retvalue |= s->tx_level & 0x1F;
qemu_log_mask(LOG_UNIMP,
"%s: RX fifos are not supported\n", __func__);
break;
case IBEX_UART_OVRD:
retvalue = s->uart_ovrd;
qemu_log_mask(LOG_UNIMP,
"%s: ovrd is not supported\n", __func__);
break;
case IBEX_UART_VAL:
retvalue = s->uart_val;
qemu_log_mask(LOG_UNIMP,
"%s: val is not supported\n", __func__);
break;
case IBEX_UART_TIMEOUT_CTRL:
retvalue = s->uart_timeout_ctrl;
qemu_log_mask(LOG_UNIMP,
"%s: timeout_ctrl is not supported\n", __func__);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
return 0;
}
return retvalue;
}
static void ibex_uart_write(void *opaque, hwaddr addr,
uint64_t val64, unsigned int size)
{
IbexUartState *s = opaque;
uint32_t value = val64;
switch (addr) {
case IBEX_UART_INTR_STATE:
/* Write 1 clear */
s->uart_intr_state &= ~value;
ibex_uart_update_irqs(s);
break;
case IBEX_UART_INTR_ENABLE:
s->uart_intr_enable = value;
ibex_uart_update_irqs(s);
break;
case IBEX_UART_INTR_TEST:
s->uart_intr_state |= value;
ibex_uart_update_irqs(s);
break;
case IBEX_UART_CTRL:
s->uart_ctrl = value;
if (value & UART_CTRL_NF) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_NF is not supported\n", __func__);
}
if (value & UART_CTRL_SLPBK) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_SLPBK is not supported\n", __func__);
}
if (value & UART_CTRL_LLPBK) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_LLPBK is not supported\n", __func__);
}
if (value & UART_CTRL_PARITY_EN) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_PARITY_EN is not supported\n",
__func__);
}
if (value & UART_CTRL_PARITY_ODD) {
qemu_log_mask(LOG_UNIMP,
"%s: UART_CTRL_PARITY_ODD is not supported\n",
__func__);
}
if (value & UART_CTRL_RXBLVL) {
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 /= 2 ^ 20;
s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10;
}
break;
case IBEX_UART_STATUS:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: status is read only\n", __func__);
break;
case IBEX_UART_RDATA:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: rdata is read only\n", __func__);
break;
case IBEX_UART_WDATA:
uart_write_tx_fifo(s, (uint8_t *) &value, 1);
break;
case IBEX_UART_FIFO_CTRL:
s->uart_fifo_ctrl = value;
if (value & FIFO_CTRL_RXRST) {
qemu_log_mask(LOG_UNIMP,
"%s: RX fifos are not supported\n", __func__);
}
if (value & FIFO_CTRL_TXRST) {
s->tx_level = 0;
}
break;
case IBEX_UART_FIFO_STATUS:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: fifo_status is read only\n", __func__);
break;
case IBEX_UART_OVRD:
s->uart_ovrd = value;
qemu_log_mask(LOG_UNIMP,
"%s: ovrd is not supported\n", __func__);
break;
case IBEX_UART_VAL:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: val is read only\n", __func__);
break;
case IBEX_UART_TIMEOUT_CTRL:
s->uart_timeout_ctrl = value;
qemu_log_mask(LOG_UNIMP,
"%s: timeout_ctrl is not supported\n", __func__);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
}
}
static void fifo_trigger_update(void *opaque)
{
IbexUartState *s = opaque;
if (s->uart_ctrl & UART_CTRL_TX_ENABLE) {
ibex_uart_xmit(NULL, G_IO_OUT, s);
}
}
static const MemoryRegionOps ibex_uart_ops = {
.read = ibex_uart_read,
.write = ibex_uart_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.impl.min_access_size = 4,
.impl.max_access_size = 4,
};
static int ibex_uart_post_load(void *opaque, int version_id)
{
IbexUartState *s = opaque;
ibex_uart_update_irqs(s);
return 0;
}
static const VMStateDescription vmstate_ibex_uart = {
.name = TYPE_IBEX_UART,
.version_id = 1,
.minimum_version_id = 1,
.post_load = ibex_uart_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState,
IBEX_UART_TX_FIFO_SIZE),
VMSTATE_UINT32(tx_level, IbexUartState),
VMSTATE_UINT64(char_tx_time, IbexUartState),
VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState),
VMSTATE_UINT32(uart_intr_state, IbexUartState),
VMSTATE_UINT32(uart_intr_enable, IbexUartState),
VMSTATE_UINT32(uart_ctrl, IbexUartState),
VMSTATE_UINT32(uart_status, IbexUartState),
VMSTATE_UINT32(uart_rdata, IbexUartState),
VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState),
VMSTATE_UINT32(uart_fifo_status, IbexUartState),
VMSTATE_UINT32(uart_ovrd, IbexUartState),
VMSTATE_UINT32(uart_val, IbexUartState),
VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState),
VMSTATE_END_OF_LIST()
}
};
static Property ibex_uart_properties[] = {
DEFINE_PROP_CHR("chardev", IbexUartState, chr),
DEFINE_PROP_END_OF_LIST(),
};
static void ibex_uart_init(Object *obj)
{
IbexUartState *s = IBEX_UART(obj);
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);
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow);
memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s,
TYPE_IBEX_UART, 0x400);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
}
static void ibex_uart_realize(DeviceState *dev, Error **errp)
{
IbexUartState *s = IBEX_UART(dev);
s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL,
fifo_trigger_update, s);
qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive,
ibex_uart_receive, NULL, NULL,
s, NULL, true);
}
static void ibex_uart_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = ibex_uart_reset;
dc->realize = ibex_uart_realize;
dc->vmsd = &vmstate_ibex_uart;
device_class_set_props(dc, ibex_uart_properties);
}
static const TypeInfo ibex_uart_info = {
.name = TYPE_IBEX_UART,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IbexUartState),
.instance_init = ibex_uart_init,
.class_init = ibex_uart_class_init,
};
static void ibex_uart_register_types(void)
{
type_register_static(&ibex_uart_info);
}
type_init(ibex_uart_register_types)
...@@ -49,3 +49,4 @@ obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o ...@@ -49,3 +49,4 @@ obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpuif.o
obj-$(CONFIG_MIPS_CPS) += mips_gic.o obj-$(CONFIG_MIPS_CPS) += mips_gic.o
obj-$(CONFIG_NIOS2) += nios2_iic.o obj-$(CONFIG_NIOS2) += nios2_iic.o
obj-$(CONFIG_OMPIC) += ompic.o obj-$(CONFIG_OMPIC) += ompic.o
obj-$(CONFIG_IBEX) += ibex_plic.o
/*
* QEMU RISC-V lowRISC Ibex PLIC
*
* Copyright (c) 2020 Western Digital
*
* Documentation avaliable: https://docs.opentitan.org/hw/ip/rv_plic/doc/
*
* 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/log.h"
#include "hw/qdev-properties.h"
#include "hw/core/cpu.h"
#include "hw/boards.h"
#include "hw/pci/msi.h"
#include "target/riscv/cpu_bits.h"
#include "target/riscv/cpu.h"
#include "hw/intc/ibex_plic.h"
static bool addr_between(uint32_t addr, uint32_t base, uint32_t num)
{
uint32_t end = base + (num * 0x04);
if (addr >= base && addr < end) {
return true;
}
return false;
}
static void ibex_plic_irqs_set_pending(IbexPlicState *s, int irq, bool level)
{
int pending_num = irq / 32;
s->pending[pending_num] |= level << (irq % 32);
}
static bool ibex_plic_irqs_pending(IbexPlicState *s, uint32_t context)
{
int i;
for (i = 0; i < s->pending_num; i++) {
uint32_t irq_num = ctz64(s->pending[i]) + (i * 32);
if (!(s->pending[i] & s->enable[i])) {
/* No pending and enabled IRQ */
continue;
}
if (s->priority[irq_num] > s->threshold) {
if (!s->claim) {
s->claim = irq_num;
}
return true;
}
}
return false;
}
static void ibex_plic_update(IbexPlicState *s)
{
CPUState *cpu;
int level, i;
for (i = 0; i < s->num_cpus; i++) {
cpu = qemu_get_cpu(i);
if (!cpu) {
continue;
}
level = ibex_plic_irqs_pending(s, 0);
riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level));
}
}
static void ibex_plic_reset(DeviceState *dev)
{
IbexPlicState *s = IBEX_PLIC(dev);
s->threshold = 0x00000000;
s->claim = 0x00000000;
}
static uint64_t ibex_plic_read(void *opaque, hwaddr addr,
unsigned int size)
{
IbexPlicState *s = opaque;
int offset;
uint32_t ret = 0;
if (addr_between(addr, s->pending_base, s->pending_num)) {
offset = (addr - s->pending_base) / 4;
ret = s->pending[offset];
} else if (addr_between(addr, s->source_base, s->source_num)) {
qemu_log_mask(LOG_UNIMP,
"%s: Interrupt source mode not supported\n", __func__);
} else if (addr_between(addr, s->priority_base, s->priority_num)) {
offset = (addr - s->priority_base) / 4;
ret = s->priority[offset];
} else if (addr_between(addr, s->enable_base, s->enable_num)) {
offset = (addr - s->enable_base) / 4;
ret = s->enable[offset];
} else if (addr_between(addr, s->threshold_base, 1)) {
ret = s->threshold;
} else if (addr_between(addr, s->claim_base, 1)) {
int pending_num = s->claim / 32;
s->pending[pending_num] &= ~(1 << (s->claim % 32));
ret = s->claim;
}
return ret;
}
static void ibex_plic_write(void *opaque, hwaddr addr,
uint64_t value, unsigned int size)
{
IbexPlicState *s = opaque;
if (addr_between(addr, s->pending_base, s->pending_num)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Pending registers are read only\n", __func__);
} else if (addr_between(addr, s->source_base, s->source_num)) {
qemu_log_mask(LOG_UNIMP,
"%s: Interrupt source mode not supported\n", __func__);
} else if (addr_between(addr, s->priority_base, s->priority_num)) {
uint32_t irq = ((addr - s->priority_base) >> 2) + 1;
s->priority[irq] = value & 7;
} else if (addr_between(addr, s->enable_base, s->enable_num)) {
uint32_t enable_reg = (addr - s->enable_base) / 4;
s->enable[enable_reg] = value;
} else if (addr_between(addr, s->threshold_base, 1)) {
s->threshold = value & 3;
} else if (addr_between(addr, s->claim_base, 1)) {
if (s->claim == value) {
/* Interrupt was completed */
s->claim = 0;
}
}
ibex_plic_update(s);
}
static const MemoryRegionOps ibex_plic_ops = {
.read = ibex_plic_read,
.write = ibex_plic_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4
}
};
static void ibex_plic_irq_request(void *opaque, int irq, int level)
{
IbexPlicState *s = opaque;
ibex_plic_irqs_set_pending(s, irq, level > 0);
ibex_plic_update(s);
}
static Property ibex_plic_properties[] = {
DEFINE_PROP_UINT32("num-cpus", IbexPlicState, num_cpus, 1),
DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 80),
DEFINE_PROP_UINT32("pending-base", IbexPlicState, pending_base, 0),
DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 3),
DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x0c),
DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 3),
DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x18),
DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 80),
DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x200),
DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 3),
DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x20c),
DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x210),
DEFINE_PROP_END_OF_LIST(),
};
static void ibex_plic_init(Object *obj)
{
IbexPlicState *s = IBEX_PLIC(obj);
memory_region_init_io(&s->mmio, obj, &ibex_plic_ops, s,
TYPE_IBEX_PLIC, 0x400);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
}
static void ibex_plic_realize(DeviceState *dev, Error **errp)
{
IbexPlicState *s = IBEX_PLIC(dev);
int i;
s->pending = g_new0(uint32_t, s->pending_num);
s->source = g_new0(uint32_t, s->source_num);
s->priority = g_new0(uint32_t, s->priority_num);
s->enable = g_new0(uint32_t, s->enable_num);
qdev_init_gpio_in(dev, ibex_plic_irq_request, s->num_sources);
/*
* We can't allow the supervisor to control SEIP as this would allow the
* supervisor to clear a pending external interrupt which will result in
* a lost interrupt in the case a PLIC is attached. The SEIP bit must be
* hardware controlled when a PLIC is attached.
*/
MachineState *ms = MACHINE(qdev_get_machine());
unsigned int smp_cpus = ms->smp.cpus;
for (i = 0; i < smp_cpus; i++) {
RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(i));
if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) {
error_report("SEIP already claimed");
exit(1);
}
}
msi_nonbroken = true;
}
static void ibex_plic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = ibex_plic_reset;
device_class_set_props(dc, ibex_plic_properties);
dc->realize = ibex_plic_realize;
}
static const TypeInfo ibex_plic_info = {
.name = TYPE_IBEX_PLIC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IbexPlicState),
.instance_init = ibex_plic_init,
.class_init = ibex_plic_class_init,
};
static void ibex_plic_register_types(void)
{
type_register_static(&ibex_plic_info);
}
type_init(ibex_plic_register_types)
...@@ -4,6 +4,9 @@ config HTIF ...@@ -4,6 +4,9 @@ config HTIF
config HART config HART
bool bool
config IBEX
bool
config SIFIVE config SIFIVE
bool bool
select MSI_NONBROKEN select MSI_NONBROKEN
...@@ -29,6 +32,7 @@ config SPIKE ...@@ -29,6 +32,7 @@ config SPIKE
config OPENTITAN config OPENTITAN
bool bool
select IBEX
select HART select HART
select UNIMP select UNIMP
......
...@@ -25,12 +25,14 @@ ...@@ -25,12 +25,14 @@
#include "hw/misc/unimp.h" #include "hw/misc/unimp.h"
#include "hw/riscv/boot.h" #include "hw/riscv/boot.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "qemu/units.h"
#include "sysemu/sysemu.h"
static const struct MemmapEntry { static const struct MemmapEntry {
hwaddr base; hwaddr base;
hwaddr size; hwaddr size;
} ibex_memmap[] = { } ibex_memmap[] = {
[IBEX_ROM] = { 0x00008000, 0xc000 }, [IBEX_ROM] = { 0x00008000, 16 * KiB },
[IBEX_RAM] = { 0x10000000, 0x10000 }, [IBEX_RAM] = { 0x10000000, 0x10000 },
[IBEX_FLASH] = { 0x20000000, 0x80000 }, [IBEX_FLASH] = { 0x20000000, 0x80000 },
[IBEX_UART] = { 0x40000000, 0x10000 }, [IBEX_UART] = { 0x40000000, 0x10000 },
...@@ -51,7 +53,7 @@ static const struct MemmapEntry { ...@@ -51,7 +53,7 @@ static const struct MemmapEntry {
[IBEX_PADCTRL] = { 0x40160000, 0x10000 } [IBEX_PADCTRL] = { 0x40160000, 0x10000 }
}; };
static void riscv_opentitan_init(MachineState *machine) static void opentitan_board_init(MachineState *machine)
{ {
const struct MemmapEntry *memmap = ibex_memmap; const struct MemmapEntry *memmap = ibex_memmap;
OpenTitanState *s = g_new0(OpenTitanState, 1); OpenTitanState *s = g_new0(OpenTitanState, 1);
...@@ -68,7 +70,6 @@ static void riscv_opentitan_init(MachineState *machine) ...@@ -68,7 +70,6 @@ static void riscv_opentitan_init(MachineState *machine)
memory_region_add_subregion(sys_mem, memory_region_add_subregion(sys_mem,
memmap[IBEX_RAM].base, main_mem); memmap[IBEX_RAM].base, main_mem);
if (machine->firmware) { if (machine->firmware) {
riscv_load_firmware(machine->firmware, memmap[IBEX_RAM].base, NULL); riscv_load_firmware(machine->firmware, memmap[IBEX_RAM].base, NULL);
} }
...@@ -78,29 +79,34 @@ static void riscv_opentitan_init(MachineState *machine) ...@@ -78,29 +79,34 @@ static void riscv_opentitan_init(MachineState *machine)
} }
} }
static void riscv_opentitan_machine_init(MachineClass *mc) static void opentitan_machine_init(MachineClass *mc)
{ {
mc->desc = "RISC-V Board compatible with OpenTitan"; mc->desc = "RISC-V Board compatible with OpenTitan";
mc->init = riscv_opentitan_init; mc->init = opentitan_board_init;
mc->max_cpus = 1; mc->max_cpus = 1;
mc->default_cpu_type = TYPE_RISCV_CPU_IBEX; mc->default_cpu_type = TYPE_RISCV_CPU_IBEX;
} }
DEFINE_MACHINE("opentitan", riscv_opentitan_machine_init) DEFINE_MACHINE("opentitan", opentitan_machine_init)
static void riscv_lowrisc_ibex_soc_init(Object *obj) static void lowrisc_ibex_soc_init(Object *obj)
{ {
LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj); LowRISCIbexSoCState *s = RISCV_IBEX_SOC(obj);
object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY);
object_initialize_child(obj, "plic", &s->plic, TYPE_IBEX_PLIC);
object_initialize_child(obj, "uart", &s->uart, TYPE_IBEX_UART);
} }
static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
{ {
const struct MemmapEntry *memmap = ibex_memmap; const struct MemmapEntry *memmap = ibex_memmap;
MachineState *ms = MACHINE(qdev_get_machine()); MachineState *ms = MACHINE(qdev_get_machine());
LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc); LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc);
MemoryRegion *sys_mem = get_system_memory(); MemoryRegion *sys_mem = get_system_memory();
Error *err = NULL;
object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type", object_property_set_str(OBJECT(&s->cpus), ms->cpu_type, "cpu-type",
&error_abort); &error_abort);
...@@ -120,8 +126,35 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) ...@@ -120,8 +126,35 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
memory_region_add_subregion(sys_mem, memmap[IBEX_FLASH].base, memory_region_add_subregion(sys_mem, memmap[IBEX_FLASH].base,
&s->flash_mem); &s->flash_mem);
create_unimplemented_device("riscv.lowrisc.ibex.uart", /* PLIC */
memmap[IBEX_UART].base, memmap[IBEX_UART].size); sysbus_realize(SYS_BUS_DEVICE(&s->plic), &err);
if (err != NULL) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->plic), 0, memmap[IBEX_PLIC].base);
/* UART */
qdev_prop_set_chr(DEVICE(&(s->uart)), "chardev", serial_hd(0));
sysbus_realize(SYS_BUS_DEVICE(&s->uart), &err);
if (err != NULL) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart), 0, memmap[IBEX_UART].base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart),
0, qdev_get_gpio_in(DEVICE(&s->plic),
IBEX_UART_TX_WATERMARK_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart),
1, qdev_get_gpio_in(DEVICE(&s->plic),
IBEX_UART_RX_WATERMARK_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart),
2, qdev_get_gpio_in(DEVICE(&s->plic),
IBEX_UART_TX_EMPTY_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart),
3, qdev_get_gpio_in(DEVICE(&s->plic),
IBEX_UART_RX_OVERFLOW_IRQ));
create_unimplemented_device("riscv.lowrisc.ibex.gpio", create_unimplemented_device("riscv.lowrisc.ibex.gpio",
memmap[IBEX_GPIO].base, memmap[IBEX_GPIO].size); memmap[IBEX_GPIO].base, memmap[IBEX_GPIO].size);
create_unimplemented_device("riscv.lowrisc.ibex.spi", create_unimplemented_device("riscv.lowrisc.ibex.spi",
...@@ -140,8 +173,6 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) ...@@ -140,8 +173,6 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
memmap[IBEX_AES].base, memmap[IBEX_AES].size); memmap[IBEX_AES].base, memmap[IBEX_AES].size);
create_unimplemented_device("riscv.lowrisc.ibex.hmac", create_unimplemented_device("riscv.lowrisc.ibex.hmac",
memmap[IBEX_HMAC].base, memmap[IBEX_HMAC].size); memmap[IBEX_HMAC].base, memmap[IBEX_HMAC].size);
create_unimplemented_device("riscv.lowrisc.ibex.plic",
memmap[IBEX_PLIC].base, memmap[IBEX_PLIC].size);
create_unimplemented_device("riscv.lowrisc.ibex.pinmux", create_unimplemented_device("riscv.lowrisc.ibex.pinmux",
memmap[IBEX_PINMUX].base, memmap[IBEX_PINMUX].size); memmap[IBEX_PINMUX].base, memmap[IBEX_PINMUX].size);
create_unimplemented_device("riscv.lowrisc.ibex.alert_handler", create_unimplemented_device("riscv.lowrisc.ibex.alert_handler",
...@@ -154,26 +185,26 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) ...@@ -154,26 +185,26 @@ static void riscv_lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
memmap[IBEX_PADCTRL].base, memmap[IBEX_PADCTRL].size); memmap[IBEX_PADCTRL].base, memmap[IBEX_PADCTRL].size);
} }
static void riscv_lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data) static void lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = riscv_lowrisc_ibex_soc_realize; dc->realize = lowrisc_ibex_soc_realize;
/* Reason: Uses serial_hds in realize function, thus can't be used twice */ /* Reason: Uses serial_hds in realize function, thus can't be used twice */
dc->user_creatable = false; dc->user_creatable = false;
} }
static const TypeInfo riscv_lowrisc_ibex_soc_type_info = { static const TypeInfo lowrisc_ibex_soc_type_info = {
.name = TYPE_RISCV_IBEX_SOC, .name = TYPE_RISCV_IBEX_SOC,
.parent = TYPE_DEVICE, .parent = TYPE_DEVICE,
.instance_size = sizeof(LowRISCIbexSoCState), .instance_size = sizeof(LowRISCIbexSoCState),
.instance_init = riscv_lowrisc_ibex_soc_init, .instance_init = lowrisc_ibex_soc_init,
.class_init = riscv_lowrisc_ibex_soc_class_init, .class_init = lowrisc_ibex_soc_class_init,
}; };
static void riscv_lowrisc_ibex_soc_register_types(void) static void lowrisc_ibex_soc_register_types(void)
{ {
type_register_static(&riscv_lowrisc_ibex_soc_type_info); type_register_static(&lowrisc_ibex_soc_type_info);
} }
type_init(riscv_lowrisc_ibex_soc_register_types) type_init(lowrisc_ibex_soc_register_types)
...@@ -75,7 +75,7 @@ static const struct MemmapEntry { ...@@ -75,7 +75,7 @@ static const struct MemmapEntry {
[SIFIVE_E_DTIM] = { 0x80000000, 0x4000 } [SIFIVE_E_DTIM] = { 0x80000000, 0x4000 }
}; };
static void riscv_sifive_e_init(MachineState *machine) static void sifive_e_machine_init(MachineState *machine)
{ {
const struct MemmapEntry *memmap = sifive_e_memmap; const struct MemmapEntry *memmap = sifive_e_memmap;
...@@ -95,10 +95,16 @@ static void riscv_sifive_e_init(MachineState *machine) ...@@ -95,10 +95,16 @@ static void riscv_sifive_e_init(MachineState *machine)
memmap[SIFIVE_E_DTIM].base, main_mem); memmap[SIFIVE_E_DTIM].base, main_mem);
/* Mask ROM reset vector */ /* Mask ROM reset vector */
uint32_t reset_vec[2] = { uint32_t reset_vec[4];
0x204002b7, /* 0x1000: lui t0,0x20400 */
0x00028067, /* 0x1004: jr t0 */ if (s->revb) {
}; reset_vec[1] = 0x200102b7; /* 0x1004: lui t0,0x20010 */
} else {
reset_vec[1] = 0x204002b7; /* 0x1004: lui t0,0x20400 */
}
reset_vec[2] = 0x00028067; /* 0x1008: jr t0 */
reset_vec[0] = reset_vec[3] = 0;
/* copy in the reset vector in little_endian byte order */ /* copy in the reset vector in little_endian byte order */
for (i = 0; i < sizeof(reset_vec) >> 2; i++) { for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
...@@ -112,8 +118,30 @@ static void riscv_sifive_e_init(MachineState *machine) ...@@ -112,8 +118,30 @@ static void riscv_sifive_e_init(MachineState *machine)
} }
} }
static bool sifive_e_machine_get_revb(Object *obj, Error **errp)
{
SiFiveEState *s = RISCV_E_MACHINE(obj);
return s->revb;
}
static void sifive_e_machine_set_revb(Object *obj, bool value, Error **errp)
{
SiFiveEState *s = RISCV_E_MACHINE(obj);
s->revb = value;
}
static void sifive_e_machine_instance_init(Object *obj) static void sifive_e_machine_instance_init(Object *obj)
{ {
SiFiveEState *s = RISCV_E_MACHINE(obj);
s->revb = false;
object_property_add_bool(obj, "revb", sifive_e_machine_get_revb,
sifive_e_machine_set_revb);
object_property_set_description(obj, "revb",
"Set on to tell QEMU that it should model "
"the revB HiFive1 board");
} }
static void sifive_e_machine_class_init(ObjectClass *oc, void *data) static void sifive_e_machine_class_init(ObjectClass *oc, void *data)
...@@ -121,7 +149,7 @@ static void sifive_e_machine_class_init(ObjectClass *oc, void *data) ...@@ -121,7 +149,7 @@ static void sifive_e_machine_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "RISC-V Board compatible with SiFive E SDK"; mc->desc = "RISC-V Board compatible with SiFive E SDK";
mc->init = riscv_sifive_e_init; mc->init = sifive_e_machine_init;
mc->max_cpus = 1; mc->max_cpus = 1;
mc->default_cpu_type = SIFIVE_E_CPU; mc->default_cpu_type = SIFIVE_E_CPU;
} }
...@@ -141,7 +169,7 @@ static void sifive_e_machine_init_register_types(void) ...@@ -141,7 +169,7 @@ static void sifive_e_machine_init_register_types(void)
type_init(sifive_e_machine_init_register_types) type_init(sifive_e_machine_init_register_types)
static void riscv_sifive_e_soc_init(Object *obj) static void sifive_e_soc_init(Object *obj)
{ {
MachineState *ms = MACHINE(qdev_get_machine()); MachineState *ms = MACHINE(qdev_get_machine());
SiFiveESoCState *s = RISCV_E_SOC(obj); SiFiveESoCState *s = RISCV_E_SOC(obj);
...@@ -153,7 +181,7 @@ static void riscv_sifive_e_soc_init(Object *obj) ...@@ -153,7 +181,7 @@ static void riscv_sifive_e_soc_init(Object *obj)
TYPE_SIFIVE_GPIO); TYPE_SIFIVE_GPIO);
} }
static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
{ {
MachineState *ms = MACHINE(qdev_get_machine()); MachineState *ms = MACHINE(qdev_get_machine());
const struct MemmapEntry *memmap = sifive_e_memmap; const struct MemmapEntry *memmap = sifive_e_memmap;
...@@ -236,26 +264,26 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) ...@@ -236,26 +264,26 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp)
&s->xip_mem); &s->xip_mem);
} }
static void riscv_sifive_e_soc_class_init(ObjectClass *oc, void *data) static void sifive_e_soc_class_init(ObjectClass *oc, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = riscv_sifive_e_soc_realize; dc->realize = sifive_e_soc_realize;
/* Reason: Uses serial_hds in realize function, thus can't be used twice */ /* Reason: Uses serial_hds in realize function, thus can't be used twice */
dc->user_creatable = false; dc->user_creatable = false;
} }
static const TypeInfo riscv_sifive_e_soc_type_info = { static const TypeInfo sifive_e_soc_type_info = {
.name = TYPE_RISCV_E_SOC, .name = TYPE_RISCV_E_SOC,
.parent = TYPE_DEVICE, .parent = TYPE_DEVICE,
.instance_size = sizeof(SiFiveESoCState), .instance_size = sizeof(SiFiveESoCState),
.instance_init = riscv_sifive_e_soc_init, .instance_init = sifive_e_soc_init,
.class_init = riscv_sifive_e_soc_class_init, .class_init = sifive_e_soc_class_init,
}; };
static void riscv_sifive_e_soc_register_types(void) static void sifive_e_soc_register_types(void)
{ {
type_register_static(&riscv_sifive_e_soc_type_info); type_register_static(&sifive_e_soc_type_info);
} }
type_init(riscv_sifive_e_soc_register_types) type_init(sifive_e_soc_register_types)
/* /*
* sifive System-on-Chip general purpose input/output register definition * SiFive System-on-Chip general purpose input/output register definition
* *
* Copyright 2019 AdaCore * Copyright 2019 AdaCore
* *
...@@ -14,13 +14,13 @@ ...@@ -14,13 +14,13 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "hw/irq.h" #include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/riscv/sifive_gpio.h" #include "hw/riscv/sifive_gpio.h"
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "trace.h" #include "trace.h"
static void update_output_irq(SIFIVEGPIOState *s) static void update_output_irq(SIFIVEGPIOState *s)
{ {
uint32_t pending; uint32_t pending;
uint32_t pin; uint32_t pin;
...@@ -29,7 +29,7 @@ static void update_output_irq(SIFIVEGPIOState *s) ...@@ -29,7 +29,7 @@ static void update_output_irq(SIFIVEGPIOState *s)
pending |= s->rise_ip & s->rise_ie; pending |= s->rise_ip & s->rise_ie;
pending |= s->fall_ip & s->fall_ie; pending |= s->fall_ip & s->fall_ie;
for (int i = 0; i < SIFIVE_GPIO_PINS; i++) { for (int i = 0; i < s->ngpio; i++) {
pin = 1 << i; pin = 1 << i;
qemu_set_irq(s->irq[i], (pending & pin) != 0); qemu_set_irq(s->irq[i], (pending & pin) != 0);
trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0); trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0);
...@@ -42,7 +42,7 @@ static void update_state(SIFIVEGPIOState *s) ...@@ -42,7 +42,7 @@ static void update_state(SIFIVEGPIOState *s)
bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en, bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en,
rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival; rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival;
for (i = 0; i < SIFIVE_GPIO_PINS; i++) { for (i = 0; i < s->ngpio; i++) {
prev_ival = extract32(s->value, i, 1); prev_ival = extract32(s->value, i, 1);
in = extract32(s->in, i, 1); in = extract32(s->in, i, 1);
...@@ -76,7 +76,9 @@ static void update_state(SIFIVEGPIOState *s) ...@@ -76,7 +76,9 @@ static void update_state(SIFIVEGPIOState *s)
actual_value = pull; actual_value = pull;
} }
qemu_set_irq(s->output[i], actual_value); if (output_en) {
qemu_set_irq(s->output[i], actual_value);
}
/* Input value */ /* Input value */
ival = input_en && actual_value; ival = input_en && actual_value;
...@@ -186,7 +188,7 @@ static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size) ...@@ -186,7 +188,7 @@ static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size)
} }
static void sifive_gpio_write(void *opaque, hwaddr offset, static void sifive_gpio_write(void *opaque, hwaddr offset,
uint64_t value, unsigned int size) uint64_t value, unsigned int size)
{ {
SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
...@@ -318,7 +320,6 @@ static void sifive_gpio_reset(DeviceState *dev) ...@@ -318,7 +320,6 @@ static void sifive_gpio_reset(DeviceState *dev)
s->out_xor = 0; s->out_xor = 0;
s->in = 0; s->in = 0;
s->in_mask = 0; s->in_mask = 0;
} }
static const VMStateDescription vmstate_sifive_gpio = { static const VMStateDescription vmstate_sifive_gpio = {
...@@ -342,43 +343,49 @@ static const VMStateDescription vmstate_sifive_gpio = { ...@@ -342,43 +343,49 @@ static const VMStateDescription vmstate_sifive_gpio = {
VMSTATE_UINT32(iof_en, SIFIVEGPIOState), VMSTATE_UINT32(iof_en, SIFIVEGPIOState),
VMSTATE_UINT32(iof_sel, SIFIVEGPIOState), VMSTATE_UINT32(iof_sel, SIFIVEGPIOState),
VMSTATE_UINT32(out_xor, SIFIVEGPIOState), VMSTATE_UINT32(out_xor, SIFIVEGPIOState),
VMSTATE_UINT32(in, SIFIVEGPIOState), VMSTATE_UINT32(in, SIFIVEGPIOState),
VMSTATE_UINT32(in_mask, SIFIVEGPIOState), VMSTATE_UINT32(in_mask, SIFIVEGPIOState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
} }
}; };
static void sifive_gpio_init(Object *obj) static Property sifive_gpio_properties[] = {
DEFINE_PROP_UINT32("ngpio", SIFIVEGPIOState, ngpio, SIFIVE_GPIO_PINS),
DEFINE_PROP_END_OF_LIST(),
};
static void sifive_gpio_realize(DeviceState *dev, Error **errp)
{ {
SIFIVEGPIOState *s = SIFIVE_GPIO(obj); SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
memory_region_init_io(&s->mmio, obj, &gpio_ops, s, memory_region_init_io(&s->mmio, OBJECT(dev), &gpio_ops, s,
TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE); TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE);
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
for (int i = 0; i < SIFIVE_GPIO_PINS; i++) { for (int i = 0; i < s->ngpio; i++) {
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq[i]); sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
} }
qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, SIFIVE_GPIO_PINS); qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, s->ngpio);
qdev_init_gpio_out(DEVICE(s), s->output, SIFIVE_GPIO_PINS); qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio);
} }
static void sifive_gpio_class_init(ObjectClass *klass, void *data) static void sifive_gpio_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_props(dc, sifive_gpio_properties);
dc->vmsd = &vmstate_sifive_gpio; dc->vmsd = &vmstate_sifive_gpio;
dc->realize = sifive_gpio_realize;
dc->reset = sifive_gpio_reset; dc->reset = sifive_gpio_reset;
dc->desc = "sifive GPIO"; dc->desc = "SiFive GPIO";
} }
static const TypeInfo sifive_gpio_info = { static const TypeInfo sifive_gpio_info = {
.name = TYPE_SIFIVE_GPIO, .name = TYPE_SIFIVE_GPIO,
.parent = TYPE_SYS_BUS_DEVICE, .parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SIFIVEGPIOState), .instance_size = sizeof(SIFIVEGPIOState),
.instance_init = sifive_gpio_init,
.class_init = sifive_gpio_class_init .class_init = sifive_gpio_class_init
}; };
......
...@@ -11,8 +11,9 @@ ...@@ -11,8 +11,9 @@
* 1) CLINT (Core Level Interruptor) * 1) CLINT (Core Level Interruptor)
* 2) PLIC (Platform Level Interrupt Controller) * 2) PLIC (Platform Level Interrupt Controller)
* 3) PRCI (Power, Reset, Clock, Interrupt) * 3) PRCI (Power, Reset, Clock, Interrupt)
* 4) OTP (One-Time Programmable) memory with stored serial number * 4) GPIO (General Purpose Input/Output Controller)
* 5) GEM (Gigabit Ethernet Controller) and management block * 5) OTP (One-Time Programmable) memory with stored serial number
* 6) GEM (Gigabit Ethernet Controller) and management block
* *
* This board currently generates devicetree dynamically that indicates at least * This board currently generates devicetree dynamically that indicates at least
* two harts and up to five harts. * two harts and up to five harts.
...@@ -36,6 +37,7 @@ ...@@ -36,6 +37,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/irq.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/char/serial.h" #include "hw/char/serial.h"
...@@ -52,6 +54,7 @@ ...@@ -52,6 +54,7 @@
#include "net/eth.h" #include "net/eth.h"
#include "sysemu/arch_init.h" #include "sysemu/arch_init.h"
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
#include "sysemu/runstate.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
...@@ -75,11 +78,13 @@ static const struct MemmapEntry { ...@@ -75,11 +78,13 @@ static const struct MemmapEntry {
[SIFIVE_U_PRCI] = { 0x10000000, 0x1000 }, [SIFIVE_U_PRCI] = { 0x10000000, 0x1000 },
[SIFIVE_U_UART0] = { 0x10010000, 0x1000 }, [SIFIVE_U_UART0] = { 0x10010000, 0x1000 },
[SIFIVE_U_UART1] = { 0x10011000, 0x1000 }, [SIFIVE_U_UART1] = { 0x10011000, 0x1000 },
[SIFIVE_U_GPIO] = { 0x10060000, 0x1000 },
[SIFIVE_U_OTP] = { 0x10070000, 0x1000 }, [SIFIVE_U_OTP] = { 0x10070000, 0x1000 },
[SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 },
[SIFIVE_U_DRAM] = { 0x80000000, 0x0 },
[SIFIVE_U_GEM] = { 0x10090000, 0x2000 }, [SIFIVE_U_GEM] = { 0x10090000, 0x2000 },
[SIFIVE_U_GEM_MGMT] = { 0x100a0000, 0x1000 }, [SIFIVE_U_GEM_MGMT] = { 0x100a0000, 0x1000 },
[SIFIVE_U_DMC] = { 0x100b0000, 0x10000 },
[SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 },
[SIFIVE_U_DRAM] = { 0x80000000, 0x0 },
}; };
#define OTP_SERIAL 1 #define OTP_SERIAL 1
...@@ -94,7 +99,7 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, ...@@ -94,7 +99,7 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
uint32_t *cells; uint32_t *cells;
char *nodename; char *nodename;
char ethclk_names[] = "pclk\0hclk"; char ethclk_names[] = "pclk\0hclk";
uint32_t plic_phandle, prci_phandle, phandle = 1; uint32_t plic_phandle, prci_phandle, gpio_phandle, phandle = 1;
uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle; uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle;
fdt = s->fdt = create_device_tree(&s->fdt_size); fdt = s->fdt = create_device_tree(&s->fdt_size);
...@@ -207,6 +212,17 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, ...@@ -207,6 +212,17 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
g_free(cells); g_free(cells);
g_free(nodename); g_free(nodename);
nodename = g_strdup_printf("/soc/otp@%lx",
(long)memmap[SIFIVE_U_OTP].base);
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_cell(fdt, nodename, "fuse-count", SIFIVE_U_OTP_REG_SIZE);
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[SIFIVE_U_OTP].base,
0x0, memmap[SIFIVE_U_OTP].size);
qemu_fdt_setprop_string(fdt, nodename, "compatible",
"sifive,fu540-c000-otp");
g_free(nodename);
prci_phandle = phandle++; prci_phandle = phandle++;
nodename = g_strdup_printf("/soc/clock-controller@%lx", nodename = g_strdup_printf("/soc/clock-controller@%lx",
(long)memmap[SIFIVE_U_PRCI].base); (long)memmap[SIFIVE_U_PRCI].base);
...@@ -257,6 +273,36 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, ...@@ -257,6 +273,36 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
g_free(cells); g_free(cells);
g_free(nodename); g_free(nodename);
gpio_phandle = phandle++;
nodename = g_strdup_printf("/soc/gpio@%lx",
(long)memmap[SIFIVE_U_GPIO].base);
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_cell(fdt, nodename, "phandle", gpio_phandle);
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
prci_phandle, PRCI_CLK_TLCLK);
qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 2);
qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
qemu_fdt_setprop_cell(fdt, nodename, "#gpio-cells", 2);
qemu_fdt_setprop(fdt, nodename, "gpio-controller", NULL, 0);
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[SIFIVE_U_GPIO].base,
0x0, memmap[SIFIVE_U_GPIO].size);
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_GPIO_IRQ0,
SIFIVE_U_GPIO_IRQ1, SIFIVE_U_GPIO_IRQ2, SIFIVE_U_GPIO_IRQ3,
SIFIVE_U_GPIO_IRQ4, SIFIVE_U_GPIO_IRQ5, SIFIVE_U_GPIO_IRQ6,
SIFIVE_U_GPIO_IRQ7, SIFIVE_U_GPIO_IRQ8, SIFIVE_U_GPIO_IRQ9,
SIFIVE_U_GPIO_IRQ10, SIFIVE_U_GPIO_IRQ11, SIFIVE_U_GPIO_IRQ12,
SIFIVE_U_GPIO_IRQ13, SIFIVE_U_GPIO_IRQ14, SIFIVE_U_GPIO_IRQ15);
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,gpio0");
g_free(nodename);
nodename = g_strdup_printf("/gpio-restart");
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_cells(fdt, nodename, "gpios", gpio_phandle, 10, 1);
qemu_fdt_setprop_string(fdt, nodename, "compatible", "gpio-restart");
g_free(nodename);
phy_phandle = phandle++; phy_phandle = phandle++;
nodename = g_strdup_printf("/soc/ethernet@%lx", nodename = g_strdup_printf("/soc/ethernet@%lx",
(long)memmap[SIFIVE_U_GEM].base); (long)memmap[SIFIVE_U_GEM].base);
...@@ -317,6 +363,14 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, ...@@ -317,6 +363,14 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
g_free(nodename); g_free(nodename);
} }
static void sifive_u_machine_reset(void *opaque, int n, int level)
{
/* gpio pin active low triggers reset */
if (!level) {
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
}
}
static void sifive_u_machine_init(MachineState *machine) static void sifive_u_machine_init(MachineState *machine)
{ {
const struct MemmapEntry *memmap = sifive_u_memmap; const struct MemmapEntry *memmap = sifive_u_memmap;
...@@ -345,11 +399,41 @@ static void sifive_u_machine_init(MachineState *machine) ...@@ -345,11 +399,41 @@ static void sifive_u_machine_init(MachineState *machine)
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_FLASH0].base, memory_region_add_subregion(system_memory, memmap[SIFIVE_U_FLASH0].base,
flash0); flash0);
/* register gpio-restart */
qdev_connect_gpio_out(DEVICE(&(s->soc.gpio)), 10,
qemu_allocate_irq(sifive_u_machine_reset, NULL, 0));
/* create device tree */ /* create device tree */
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline); create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
riscv_find_and_load_firmware(machine, BIOS_FILENAME, if (s->start_in_flash) {
memmap[SIFIVE_U_DRAM].base, NULL); /*
* If start_in_flash property is given, assign s->msel to a value
* that representing booting from QSPI0 memory-mapped flash.
*
* This also means that when both start_in_flash and msel properties
* are given, start_in_flash takes the precedence over msel.
*
* Note this is to keep backward compatibility not to break existing
* users that use start_in_flash property.
*/
s->msel = MSEL_MEMMAP_QSPI0_FLASH;
}
switch (s->msel) {
case MSEL_MEMMAP_QSPI0_FLASH:
start_addr = memmap[SIFIVE_U_FLASH0].base;
break;
case MSEL_L2LIM_QSPI0_FLASH:
case MSEL_L2LIM_QSPI2_SD:
start_addr = memmap[SIFIVE_U_L2LIM].base;
break;
default:
start_addr = memmap[SIFIVE_U_DRAM].base;
break;
}
riscv_find_and_load_firmware(machine, BIOS_FILENAME, start_addr, NULL);
if (machine->kernel_filename) { if (machine->kernel_filename) {
uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename, uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename,
...@@ -367,24 +451,20 @@ static void sifive_u_machine_init(MachineState *machine) ...@@ -367,24 +451,20 @@ static void sifive_u_machine_init(MachineState *machine)
} }
} }
if (s->start_in_flash) {
start_addr = memmap[SIFIVE_U_FLASH0].base;
}
/* reset vector */ /* reset vector */
uint32_t reset_vec[8] = { uint32_t reset_vec[8] = {
s->msel, /* MSEL pin state */
0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */
0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ 0x01c28593, /* addi a1, t0, %pcrel_lo(1b) */
0xf1402573, /* csrr a0, mhartid */ 0xf1402573, /* csrr a0, mhartid */
#if defined(TARGET_RISCV32) #if defined(TARGET_RISCV32)
0x0182a283, /* lw t0, 24(t0) */ 0x0182a283, /* lw t0, 24(t0) */
#elif defined(TARGET_RISCV64) #elif defined(TARGET_RISCV64)
0x0182b283, /* ld t0, 24(t0) */ 0x0182e283, /* lwu t0, 24(t0) */
#endif #endif
0x00028067, /* jr t0 */ 0x00028067, /* jr t0 */
0x00000000, 0x00000000,
start_addr, /* start: .dword */ start_addr, /* start: .dword */
0x00000000,
/* dtb: */ /* dtb: */
}; };
...@@ -421,14 +501,16 @@ static void sifive_u_machine_set_start_in_flash(Object *obj, bool value, Error * ...@@ -421,14 +501,16 @@ static void sifive_u_machine_set_start_in_flash(Object *obj, bool value, Error *
s->start_in_flash = value; s->start_in_flash = value;
} }
static void sifive_u_machine_get_serial(Object *obj, Visitor *v, const char *name, static void sifive_u_machine_get_uint32_prop(Object *obj, Visitor *v,
void *opaque, Error **errp) const char *name, void *opaque,
Error **errp)
{ {
visit_type_uint32(v, name, (uint32_t *)opaque, errp); visit_type_uint32(v, name, (uint32_t *)opaque, errp);
} }
static void sifive_u_machine_set_serial(Object *obj, Visitor *v, const char *name, static void sifive_u_machine_set_uint32_prop(Object *obj, Visitor *v,
void *opaque, Error **errp) const char *name, void *opaque,
Error **errp)
{ {
visit_type_uint32(v, name, (uint32_t *)opaque, errp); visit_type_uint32(v, name, (uint32_t *)opaque, errp);
} }
...@@ -443,12 +525,20 @@ static void sifive_u_machine_instance_init(Object *obj) ...@@ -443,12 +525,20 @@ static void sifive_u_machine_instance_init(Object *obj)
sifive_u_machine_set_start_in_flash); sifive_u_machine_set_start_in_flash);
object_property_set_description(obj, "start-in-flash", object_property_set_description(obj, "start-in-flash",
"Set on to tell QEMU's ROM to jump to " "Set on to tell QEMU's ROM to jump to "
"flash. Otherwise QEMU will jump to DRAM"); "flash. Otherwise QEMU will jump to DRAM "
"or L2LIM depending on the msel value");
s->msel = 0;
object_property_add(obj, "msel", "uint32",
sifive_u_machine_get_uint32_prop,
sifive_u_machine_set_uint32_prop, NULL, &s->msel);
object_property_set_description(obj, "msel",
"Mode Select (MSEL[3:0]) pin state");
s->serial = OTP_SERIAL; s->serial = OTP_SERIAL;
object_property_add(obj, "serial", "uint32", object_property_add(obj, "serial", "uint32",
sifive_u_machine_get_serial, sifive_u_machine_get_uint32_prop,
sifive_u_machine_set_serial, NULL, &s->serial); sifive_u_machine_set_uint32_prop, NULL, &s->serial);
object_property_set_description(obj, "serial", "Board serial number"); object_property_set_description(obj, "serial", "Board serial number");
} }
...@@ -504,6 +594,7 @@ static void sifive_u_soc_instance_init(Object *obj) ...@@ -504,6 +594,7 @@ static void sifive_u_soc_instance_init(Object *obj)
object_initialize_child(obj, "prci", &s->prci, TYPE_SIFIVE_U_PRCI); object_initialize_child(obj, "prci", &s->prci, TYPE_SIFIVE_U_PRCI);
object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP); object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP);
object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM); object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM);
object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO);
} }
static void sifive_u_soc_realize(DeviceState *dev, Error **errp) static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
...@@ -514,7 +605,6 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) ...@@ -514,7 +605,6 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
MemoryRegion *system_memory = get_system_memory(); MemoryRegion *system_memory = get_system_memory();
MemoryRegion *mask_rom = g_new(MemoryRegion, 1); MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1); MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1);
qemu_irq plic_gpios[SIFIVE_U_PLIC_NUM_SOURCES];
char *plic_hart_config; char *plic_hart_config;
size_t plic_hart_config_len; size_t plic_hart_config_len;
int i; int i;
...@@ -590,14 +680,24 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) ...@@ -590,14 +680,24 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
sysbus_realize(SYS_BUS_DEVICE(&s->prci), &err); sysbus_realize(SYS_BUS_DEVICE(&s->prci), &err);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base); sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base);
qdev_prop_set_uint32(DEVICE(&s->gpio), "ngpio", 16);
sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_U_GPIO].base);
/* Pass all GPIOs to the SOC layer so they are available to the board */
qdev_pass_gpios(DEVICE(&s->gpio), dev, NULL);
/* Connect GPIO interrupts to the PLIC */
for (i = 0; i < 16; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), i,
qdev_get_gpio_in(DEVICE(s->plic),
SIFIVE_U_GPIO_IRQ0 + i));
}
qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial); qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial);
sysbus_realize(SYS_BUS_DEVICE(&s->otp), &err); sysbus_realize(SYS_BUS_DEVICE(&s->otp), &err);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base); sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base);
for (i = 0; i < SIFIVE_U_PLIC_NUM_SOURCES; i++) {
plic_gpios[i] = qdev_get_gpio_in(DEVICE(s->plic), i);
}
if (nd->used) { if (nd->used) {
qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
qdev_set_nic_properties(DEVICE(&s->gem), nd); qdev_set_nic_properties(DEVICE(&s->gem), nd);
...@@ -611,10 +711,13 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) ...@@ -611,10 +711,13 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
} }
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem), 0, memmap[SIFIVE_U_GEM].base); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem), 0, memmap[SIFIVE_U_GEM].base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem), 0, sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem), 0,
plic_gpios[SIFIVE_U_GEM_IRQ]); qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_GEM_IRQ));
create_unimplemented_device("riscv.sifive.u.gem-mgmt", create_unimplemented_device("riscv.sifive.u.gem-mgmt",
memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size); memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size);
create_unimplemented_device("riscv.sifive.u.dmc",
memmap[SIFIVE_U_DMC].base, memmap[SIFIVE_U_DMC].size);
} }
static Property sifive_u_soc_props[] = { static Property sifive_u_soc_props[] = {
......
/*
* QEMU lowRISC Ibex UART device
*
* Copyright (c) 2020 Western Digital
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef HW_IBEX_UART_H
#define HW_IBEX_UART_H
#include "hw/sysbus.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
#define IBEX_UART_TX_FIFO_SIZE 16
#define TYPE_IBEX_UART "ibex-uart"
#define IBEX_UART(obj) \
OBJECT_CHECK(IbexUartState, (obj), TYPE_IBEX_UART)
typedef struct {
/* <private> */
SysBusDevice parent_obj;
/* <public> */
MemoryRegion mmio;
uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
uint32_t tx_level;
QEMUTimer *fifo_trigger_handle;
uint64_t char_tx_time;
uint32_t uart_intr_state;
uint32_t uart_intr_enable;
uint32_t uart_ctrl;
uint32_t uart_status;
uint32_t uart_rdata;
uint32_t uart_fifo_ctrl;
uint32_t uart_fifo_status;
uint32_t uart_ovrd;
uint32_t uart_val;
uint32_t uart_timeout_ctrl;
CharBackend chr;
qemu_irq tx_watermark;
qemu_irq rx_watermark;
qemu_irq tx_empty;
qemu_irq rx_overflow;
} IbexUartState;
#endif /* HW_IBEX_UART_H */
/*
* QEMU RISC-V lowRISC Ibex PLIC
*
* Copyright (c) 2020 Western Digital
*
* 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/>.
*/
#ifndef HW_IBEX_PLIC_H
#define HW_IBEX_PLIC_H
#include "hw/sysbus.h"
#define TYPE_IBEX_PLIC "ibex-plic"
#define IBEX_PLIC(obj) \
OBJECT_CHECK(IbexPlicState, (obj), TYPE_IBEX_PLIC)
typedef struct IbexPlicState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion mmio;
uint32_t *pending;
uint32_t *source;
uint32_t *priority;
uint32_t *enable;
uint32_t threshold;
uint32_t claim;
/* config */
uint32_t num_cpus;
uint32_t num_sources;
uint32_t pending_base;
uint32_t pending_num;
uint32_t source_base;
uint32_t source_num;
uint32_t priority_base;
uint32_t priority_num;
uint32_t enable_base;
uint32_t enable_num;
uint32_t threshold_base;
uint32_t claim_base;
} IbexPlicState;
#endif /* HW_IBEX_PLIC_H */
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#define HW_OPENTITAN_H #define HW_OPENTITAN_H
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#include "hw/intc/ibex_plic.h"
#include "hw/char/ibex_uart.h"
#define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc" #define TYPE_RISCV_IBEX_SOC "riscv.lowrisc.ibex.soc"
#define RISCV_IBEX_SOC(obj) \ #define RISCV_IBEX_SOC(obj) \
...@@ -31,6 +33,9 @@ typedef struct LowRISCIbexSoCState { ...@@ -31,6 +33,9 @@ typedef struct LowRISCIbexSoCState {
/*< public >*/ /*< public >*/
RISCVHartArrayState cpus; RISCVHartArrayState cpus;
IbexPlicState plic;
IbexUartState uart;
MemoryRegion flash_mem; MemoryRegion flash_mem;
MemoryRegion rom; MemoryRegion rom;
} LowRISCIbexSoCState; } LowRISCIbexSoCState;
...@@ -65,4 +70,15 @@ enum { ...@@ -65,4 +70,15 @@ enum {
IBEX_PADCTRL, IBEX_PADCTRL,
}; };
enum {
IBEX_UART_RX_PARITY_ERR_IRQ = 0x28,
IBEX_UART_RX_TIMEOUT_IRQ = 0x27,
IBEX_UART_RX_BREAK_ERR_IRQ = 0x26,
IBEX_UART_RX_FRAME_ERR_IRQ = 0x25,
IBEX_UART_RX_OVERFLOW_IRQ = 0x24,
IBEX_UART_TX_EMPTY_IRQ = 0x23,
IBEX_UART_RX_WATERMARK_IRQ = 0x22,
IBEX_UART_TX_WATERMARK_IRQ = 0x21,
};
#endif #endif
...@@ -45,6 +45,7 @@ typedef struct SiFiveEState { ...@@ -45,6 +45,7 @@ typedef struct SiFiveEState {
/*< public >*/ /*< public >*/
SiFiveESoCState soc; SiFiveESoCState soc;
bool revb;
} SiFiveEState; } SiFiveEState;
#define TYPE_RISCV_E_MACHINE MACHINE_TYPE_NAME("sifive_e") #define TYPE_RISCV_E_MACHINE MACHINE_TYPE_NAME("sifive_e")
......
/* /*
* sifive System-on-Chip general purpose input/output register definition * SiFive System-on-Chip general purpose input/output register definition
* *
* Copyright 2019 AdaCore * Copyright 2019 AdaCore
* *
...@@ -10,10 +10,12 @@ ...@@ -10,10 +10,12 @@
* This code is licensed under the GPL version 2 or later. See * This code is licensed under the GPL version 2 or later. See
* the COPYING file in the top-level directory. * the COPYING file in the top-level directory.
*/ */
#ifndef SIFIVE_GPIO_H #ifndef SIFIVE_GPIO_H
#define SIFIVE_GPIO_H #define SIFIVE_GPIO_H
#include "hw/sysbus.h" #include "hw/sysbus.h"
#define TYPE_SIFIVE_GPIO "sifive_soc.gpio" #define TYPE_SIFIVE_GPIO "sifive_soc.gpio"
#define SIFIVE_GPIO(obj) OBJECT_CHECK(SIFIVEGPIOState, (obj), TYPE_SIFIVE_GPIO) #define SIFIVE_GPIO(obj) OBJECT_CHECK(SIFIVEGPIOState, (obj), TYPE_SIFIVE_GPIO)
...@@ -67,6 +69,8 @@ typedef struct SIFIVEGPIOState { ...@@ -67,6 +69,8 @@ typedef struct SIFIVEGPIOState {
uint32_t in; uint32_t in;
uint32_t in_mask; uint32_t in_mask;
/* config */
uint32_t ngpio;
} SIFIVEGPIOState; } SIFIVEGPIOState;
#endif #endif /* SIFIVE_GPIO_H */
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "hw/net/cadence_gem.h" #include "hw/net/cadence_gem.h"
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_cpu.h" #include "hw/riscv/sifive_cpu.h"
#include "hw/riscv/sifive_gpio.h"
#include "hw/riscv/sifive_u_prci.h" #include "hw/riscv/sifive_u_prci.h"
#include "hw/riscv/sifive_u_otp.h" #include "hw/riscv/sifive_u_otp.h"
...@@ -40,6 +41,7 @@ typedef struct SiFiveUSoCState { ...@@ -40,6 +41,7 @@ typedef struct SiFiveUSoCState {
RISCVHartArrayState u_cpus; RISCVHartArrayState u_cpus;
DeviceState *plic; DeviceState *plic;
SiFiveUPRCIState prci; SiFiveUPRCIState prci;
SIFIVEGPIOState gpio;
SiFiveUOTPState otp; SiFiveUOTPState otp;
CadenceGEMState gem; CadenceGEMState gem;
...@@ -61,6 +63,7 @@ typedef struct SiFiveUState { ...@@ -61,6 +63,7 @@ typedef struct SiFiveUState {
int fdt_size; int fdt_size;
bool start_in_flash; bool start_in_flash;
uint32_t msel;
uint32_t serial; uint32_t serial;
} SiFiveUState; } SiFiveUState;
...@@ -73,7 +76,9 @@ enum { ...@@ -73,7 +76,9 @@ enum {
SIFIVE_U_PRCI, SIFIVE_U_PRCI,
SIFIVE_U_UART0, SIFIVE_U_UART0,
SIFIVE_U_UART1, SIFIVE_U_UART1,
SIFIVE_U_GPIO,
SIFIVE_U_OTP, SIFIVE_U_OTP,
SIFIVE_U_DMC,
SIFIVE_U_FLASH0, SIFIVE_U_FLASH0,
SIFIVE_U_DRAM, SIFIVE_U_DRAM,
SIFIVE_U_GEM, SIFIVE_U_GEM,
...@@ -83,6 +88,22 @@ enum { ...@@ -83,6 +88,22 @@ enum {
enum { enum {
SIFIVE_U_UART0_IRQ = 4, SIFIVE_U_UART0_IRQ = 4,
SIFIVE_U_UART1_IRQ = 5, SIFIVE_U_UART1_IRQ = 5,
SIFIVE_U_GPIO_IRQ0 = 7,
SIFIVE_U_GPIO_IRQ1 = 8,
SIFIVE_U_GPIO_IRQ2 = 9,
SIFIVE_U_GPIO_IRQ3 = 10,
SIFIVE_U_GPIO_IRQ4 = 11,
SIFIVE_U_GPIO_IRQ5 = 12,
SIFIVE_U_GPIO_IRQ6 = 13,
SIFIVE_U_GPIO_IRQ7 = 14,
SIFIVE_U_GPIO_IRQ8 = 15,
SIFIVE_U_GPIO_IRQ9 = 16,
SIFIVE_U_GPIO_IRQ10 = 17,
SIFIVE_U_GPIO_IRQ11 = 18,
SIFIVE_U_GPIO_IRQ12 = 19,
SIFIVE_U_GPIO_IRQ13 = 20,
SIFIVE_U_GPIO_IRQ14 = 21,
SIFIVE_U_GPIO_IRQ15 = 22,
SIFIVE_U_GEM_IRQ = 0x35 SIFIVE_U_GEM_IRQ = 0x35
}; };
...@@ -91,6 +112,12 @@ enum { ...@@ -91,6 +112,12 @@ enum {
SIFIVE_U_RTCCLK_FREQ = 1000000 SIFIVE_U_RTCCLK_FREQ = 1000000
}; };
enum {
MSEL_MEMMAP_QSPI0_FLASH = 1,
MSEL_L2LIM_QSPI0_FLASH = 6,
MSEL_L2LIM_QSPI2_SD = 11
};
#define SIFIVE_U_MANAGEMENT_CPU_COUNT 1 #define SIFIVE_U_MANAGEMENT_CPU_COUNT 1
#define SIFIVE_U_COMPUTE_CPU_COUNT 4 #define SIFIVE_U_COMPUTE_CPU_COUNT 4
......
...@@ -126,9 +126,7 @@ static void riscv_any_cpu_init(Object *obj) ...@@ -126,9 +126,7 @@ static void riscv_any_cpu_init(Object *obj)
set_resetvec(env, DEFAULT_RSTVEC); set_resetvec(env, DEFAULT_RSTVEC);
} }
#if defined(TARGET_RISCV32) static void riscv_base_cpu_init(Object *obj)
static void riscv_base32_cpu_init(Object *obj)
{ {
CPURISCVState *env = &RISCV_CPU(obj)->env; CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */ /* We set this in the realise function */
...@@ -136,63 +134,38 @@ static void riscv_base32_cpu_init(Object *obj) ...@@ -136,63 +134,38 @@ static void riscv_base32_cpu_init(Object *obj)
set_resetvec(env, DEFAULT_RSTVEC); set_resetvec(env, DEFAULT_RSTVEC);
} }
static void rv32gcsu_priv1_10_0_cpu_init(Object *obj) static void rvxx_sifive_u_cpu_init(Object *obj)
{ {
CPURISCVState *env = &RISCV_CPU(obj)->env; CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0); set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC); set_resetvec(env, 0x1004);
} }
static void rv32imcu_nommu_cpu_init(Object *obj) static void rvxx_sifive_e_cpu_init(Object *obj)
{ {
CPURISCVState *env = &RISCV_CPU(obj)->env; CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV32 | RVI | RVM | RVC | RVU); set_misa(env, RVXLEN | RVI | RVM | RVA | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0); set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, 0x8090); set_resetvec(env, 0x1004);
qdev_prop_set_bit(DEVICE(obj), "mmu", false); qdev_prop_set_bit(DEVICE(obj), "mmu", false);
} }
static void rv32imacu_nommu_cpu_init(Object *obj) #if defined(TARGET_RISCV32)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
qdev_prop_set_bit(DEVICE(obj), "mmu", false);
}
static void rv32imafcu_nommu_cpu_init(Object *obj) static void rv32_ibex_cpu_init(Object *obj)
{ {
CPURISCVState *env = &RISCV_CPU(obj)->env; CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVC | RVU); set_misa(env, RV32 | RVI | RVM | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0); set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC); set_resetvec(env, 0x8090);
qdev_prop_set_bit(DEVICE(obj), "mmu", false); qdev_prop_set_bit(DEVICE(obj), "mmu", false);
} }
#elif defined(TARGET_RISCV64) static void rv32_imafcu_nommu_cpu_init(Object *obj)
static void riscv_base64_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, 0);
set_resetvec(env, DEFAULT_RSTVEC);
}
static void rv64gcsu_priv1_10_0_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC);
}
static void rv64imacu_nommu_cpu_init(Object *obj)
{ {
CPURISCVState *env = &RISCV_CPU(obj)->env; CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU); set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0); set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, DEFAULT_RSTVEC); set_resetvec(env, DEFAULT_RSTVEC);
qdev_prop_set_bit(DEVICE(obj), "mmu", false); qdev_prop_set_bit(DEVICE(obj), "mmu", false);
...@@ -603,15 +576,15 @@ static const TypeInfo riscv_cpu_type_infos[] = { ...@@ -603,15 +576,15 @@ static const TypeInfo riscv_cpu_type_infos[] = {
}, },
DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init),
#if defined(TARGET_RISCV32) #if defined(TARGET_RISCV32)
DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32imcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_IBEX, rv32_ibex_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rvxx_sifive_e_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32imafcu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E34, rv32_imafcu_nommu_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rvxx_sifive_u_cpu_init),
#elif defined(TARGET_RISCV64) #elif defined(TARGET_RISCV64)
DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rvxx_sifive_e_cpu_init),
DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rvxx_sifive_u_cpu_init),
#endif #endif
}; };
......
...@@ -435,8 +435,13 @@ restart: ...@@ -435,8 +435,13 @@ restart:
hwaddr vbase; hwaddr vbase;
/* Do the second stage translation on the base PTE address. */ /* Do the second stage translation on the base PTE address. */
get_physical_address(env, &vbase, &vbase_prot, base, access_type, int vbase_ret = get_physical_address(env, &vbase, &vbase_prot,
mmu_idx, false, true); base, MMU_DATA_LOAD,
mmu_idx, false, true);
if (vbase_ret != TRANSLATE_SUCCESS) {
return vbase_ret;
}
pte_addr = vbase + idx * ptesize; pte_addr = vbase + idx * ptesize;
} else { } else {
......
...@@ -76,3 +76,8 @@ DEF_HELPER_2(mret, tl, env, tl) ...@@ -76,3 +76,8 @@ DEF_HELPER_2(mret, tl, env, tl)
DEF_HELPER_1(wfi, void, env) DEF_HELPER_1(wfi, void, env)
DEF_HELPER_1(tlb_flush, void, env) DEF_HELPER_1(tlb_flush, void, env)
#endif #endif
/* Hypervisor functions */
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(hyp_tlb_flush, void, env)
#endif
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
@r2 ....... ..... ..... ... ..... ....... %rs1 %rd @r2 ....... ..... ..... ... ..... ....... %rs1 %rd
@hfence_gvma ....... ..... ..... ... ..... ....... %rs2 %rs1 @hfence_gvma ....... ..... ..... ... ..... ....... %rs2 %rs1
@hfence_bvma ....... ..... ..... ... ..... ....... %rs2 %rs1 @hfence_vvma ....... ..... ..... ... ..... ....... %rs2 %rs1
@sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1 @sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1
@sfence_vm ....... ..... ..... ... ..... ....... %rs1 @sfence_vm ....... ..... ..... ... ..... ....... %rs1
...@@ -77,8 +77,6 @@ uret 0000000 00010 00000 000 00000 1110011 ...@@ -77,8 +77,6 @@ uret 0000000 00010 00000 000 00000 1110011
sret 0001000 00010 00000 000 00000 1110011 sret 0001000 00010 00000 000 00000 1110011
mret 0011000 00010 00000 000 00000 1110011 mret 0011000 00010 00000 000 00000 1110011
wfi 0001000 00101 00000 000 00000 1110011 wfi 0001000 00101 00000 000 00000 1110011
hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma
hfence_bvma 0010001 ..... ..... 000 00000 1110011 @hfence_bvma
sfence_vma 0001001 ..... ..... 000 00000 1110011 @sfence_vma sfence_vma 0001001 ..... ..... 000 00000 1110011 @sfence_vma
sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm
...@@ -207,3 +205,7 @@ fcvt_w_d 1100001 00000 ..... ... ..... 1010011 @r2_rm ...@@ -207,3 +205,7 @@ fcvt_w_d 1100001 00000 ..... ... ..... 1010011 @r2_rm
fcvt_wu_d 1100001 00001 ..... ... ..... 1010011 @r2_rm fcvt_wu_d 1100001 00001 ..... ... ..... 1010011 @r2_rm
fcvt_d_w 1101001 00000 ..... ... ..... 1010011 @r2_rm fcvt_d_w 1101001 00000 ..... ... ..... 1010011 @r2_rm
fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm
# *** RV32H Base Instruction Set ***
hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma
hfence_vvma 0010001 ..... ..... 000 00000 1110011 @hfence_vvma
...@@ -95,41 +95,3 @@ static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a) ...@@ -95,41 +95,3 @@ static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
{ {
return false; return false;
} }
static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
{
#ifndef CONFIG_USER_ONLY
if (has_ext(ctx, RVH)) {
/* Hpervisor extensions exist */
/*
* if (env->priv == PRV_M ||
* (env->priv == PRV_S &&
* !riscv_cpu_virt_enabled(env) &&
* get_field(ctx->mstatus_fs, MSTATUS_TVM))) {
*/
gen_helper_tlb_flush(cpu_env);
return true;
/* } */
}
#endif
return false;
}
static bool trans_hfence_bvma(DisasContext *ctx, arg_sfence_vma *a)
{
#ifndef CONFIG_USER_ONLY
if (has_ext(ctx, RVH)) {
/* Hpervisor extensions exist */
/*
* if (env->priv == PRV_M ||
* (env->priv == PRV_S &&
* !riscv_cpu_virt_enabled(env) &&
* get_field(ctx->mstatus_fs, MSTATUS_TVM))) {
*/
gen_helper_tlb_flush(cpu_env);
return true;
/* } */
}
#endif
return false;
}
...@@ -23,6 +23,20 @@ ...@@ -23,6 +23,20 @@
return false; \ return false; \
} while (0) } while (0)
/*
* RISC-V requires NaN-boxing of narrower width floating
* point values. This applies when a 32-bit value is
* assigned to a 64-bit FP register. Thus this does not
* apply when the RVD extension is not present.
*/
static void gen_nanbox_fpr(DisasContext *ctx, int regno)
{
if (has_ext(ctx, RVD)) {
tcg_gen_ori_i64(cpu_fpr[regno], cpu_fpr[regno],
MAKE_64BIT_MASK(32, 32));
}
}
static bool trans_flw(DisasContext *ctx, arg_flw *a) static bool trans_flw(DisasContext *ctx, arg_flw *a)
{ {
TCGv t0 = tcg_temp_new(); TCGv t0 = tcg_temp_new();
...@@ -32,8 +46,7 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a) ...@@ -32,8 +46,7 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a)
tcg_gen_addi_tl(t0, t0, a->imm); tcg_gen_addi_tl(t0, t0, a->imm);
tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEUL); tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], t0, ctx->mem_idx, MO_TEUL);
/* RISC-V requires NaN-boxing of narrower width floating point values */ gen_nanbox_fpr(ctx, a->rd);
tcg_gen_ori_i64(cpu_fpr[a->rd], cpu_fpr[a->rd], 0xffffffff00000000ULL);
tcg_temp_free(t0); tcg_temp_free(t0);
mark_fs_dirty(ctx); mark_fs_dirty(ctx);
......
/*
* RISC-V translation routines for the RVXI Base Integer Instruction Set.
*
* Copyright (c) 2020 Western Digital
*
* 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/>.
*/
static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
{
REQUIRE_EXT(ctx, RVH);
#ifndef CONFIG_USER_ONLY
gen_helper_hyp_tlb_flush(cpu_env);
return true;
#endif
return false;
}
static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a)
{
REQUIRE_EXT(ctx, RVH);
#ifndef CONFIG_USER_ONLY
gen_helper_hyp_tlb_flush(cpu_env);
return true;
#endif
return false;
}
...@@ -194,4 +194,17 @@ void helper_tlb_flush(CPURISCVState *env) ...@@ -194,4 +194,17 @@ void helper_tlb_flush(CPURISCVState *env)
} }
} }
void helper_hyp_tlb_flush(CPURISCVState *env)
{
CPUState *cs = env_cpu(env);
if (env->priv == PRV_M ||
(env->priv == PRV_S && !riscv_cpu_virt_enabled(env))) {
tlb_flush(cs);
return;
}
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
...@@ -233,12 +233,16 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, ...@@ -233,12 +233,16 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
return true; return true;
} }
/*
* if size is unknown (0), assume that all bytes
* from addr to the end of the page will be accessed.
*/
if (size == 0) { if (size == 0) {
pmp_size = -(addr | TARGET_PAGE_MASK); if (riscv_feature(env, RISCV_FEATURE_MMU)) {
/*
* If size is unknown (0), assume that all bytes
* from addr to the end of the page will be accessed.
*/
pmp_size = -(addr | TARGET_PAGE_MASK);
} else {
pmp_size = sizeof(target_ulong);
}
} else { } else {
pmp_size = size; pmp_size = size;
} }
......
...@@ -711,6 +711,7 @@ static bool gen_shift(DisasContext *ctx, arg_r *a, ...@@ -711,6 +711,7 @@ static bool gen_shift(DisasContext *ctx, arg_r *a,
#include "insn_trans/trans_rva.inc.c" #include "insn_trans/trans_rva.inc.c"
#include "insn_trans/trans_rvf.inc.c" #include "insn_trans/trans_rvf.inc.c"
#include "insn_trans/trans_rvd.inc.c" #include "insn_trans/trans_rvd.inc.c"
#include "insn_trans/trans_rvh.inc.c"
#include "insn_trans/trans_privileged.inc.c" #include "insn_trans/trans_privileged.inc.c"
/* Include the auto-generated decoder for 16 bit insn */ /* Include the auto-generated decoder for 16 bit insn */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册