aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/system/riscv/microchip-icicle-kit.rst89
-rw-r--r--docs/system/target-riscv.rst1
-rw-r--r--hw/acpi/aml-build.c28
-rw-r--r--hw/acpi/pci.c1
-rw-r--r--hw/acpi/pcihp.c104
-rw-r--r--hw/acpi/piix4.c3
-rw-r--r--hw/acpi/trace-events2
-rw-r--r--hw/acpi/utils.c17
-rw-r--r--hw/arm/virt-acpi-build.c12
-rw-r--r--hw/block/m25p80.c3
-rw-r--r--hw/block/xen-block.c9
-rw-r--r--hw/char/ibex_uart.c23
-rw-r--r--hw/i386/acpi-build.c173
-rw-r--r--hw/i386/acpi-microvm.c32
-rw-r--r--hw/i386/microvm.c66
-rw-r--r--hw/i386/pc.c63
-rw-r--r--hw/i386/x86.c64
-rw-r--r--hw/pci/pci.c1
-rw-r--r--hw/riscv/Kconfig1
-rw-r--r--hw/riscv/microchip_pfsoc.c6
-rw-r--r--hw/riscv/virt.c33
-rw-r--r--hw/virtio/vhost-user.c217
-rw-r--r--hw/virtio/virtio-mmio.c74
-rw-r--r--hw/virtio/virtio-pmem.c2
-rw-r--r--include/hw/acpi/aml-build.h6
-rw-r--r--include/hw/acpi/pci.h1
-rw-r--r--include/hw/acpi/pcihp.h9
-rw-r--r--include/hw/acpi/utils.h3
-rw-r--r--include/hw/char/ibex_uart.h4
-rw-r--r--include/hw/i386/microvm.h4
-rw-r--r--include/hw/i386/pc.h4
-rw-r--r--include/hw/i386/x86.h4
-rw-r--r--include/hw/pci/pci.h1
-rw-r--r--include/hw/riscv/microchip_pfsoc.h1
-rw-r--r--include/hw/riscv/virt.h2
-rw-r--r--target/riscv/cpu.c1
-rw-r--r--target/riscv/cpu.h4
-rw-r--r--target/riscv/cpu_helper.c144
-rw-r--r--target/riscv/csr.c77
-rw-r--r--target/riscv/pmp.c84
-rw-r--r--target/riscv/pmp.h4
-rw-r--r--target/riscv/translate.c179
-rw-r--r--tests/data/acpi/pc/DSDTbin5065 -> 6002 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.acpihmatbin6390 -> 7327 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.bridgebin6924 -> 8668 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.cphpbin5529 -> 6466 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.dimmpxmbin6719 -> 7656 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.hpbridgebin5026 -> 5969 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.ipmikcsbin5137 -> 6074 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.memhpbin6424 -> 7361 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.nohpetbin4923 -> 5860 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.numamembin5071 -> 6008 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.roothpbin5261 -> 6210 bytes
53 files changed, 959 insertions, 597 deletions
diff --git a/docs/system/riscv/microchip-icicle-kit.rst b/docs/system/riscv/microchip-icicle-kit.rst
new file mode 100644
index 0000000000..4fe97bce3f
--- /dev/null
+++ b/docs/system/riscv/microchip-icicle-kit.rst
@@ -0,0 +1,89 @@
+Microchip PolarFire SoC Icicle Kit (``microchip-icicle-kit``)
+=============================================================
+
+Microchip PolarFire SoC Icicle Kit integrates a PolarFire SoC, with one
+SiFive's E51 plus four U54 cores and many on-chip peripherals and an FPGA.
+
+For more details about Microchip PolarFire SoC, please see:
+https://www.microsemi.com/product-directory/soc-fpgas/5498-polarfire-soc-fpga
+
+The Icicle Kit board information can be found here:
+https://www.microsemi.com/existing-parts/parts/152514
+
+Supported devices
+-----------------
+
+The ``microchip-icicle-kit`` machine supports the following devices:
+
+ * 1 E51 core
+ * 4 U54 cores
+ * Core Level Interruptor (CLINT)
+ * Platform-Level Interrupt Controller (PLIC)
+ * L2 Loosely Integrated Memory (L2-LIM)
+ * DDR memory controller
+ * 5 MMUARTs
+ * 1 DMA controller
+ * 2 GEM Ethernet controllers
+ * 1 SDHC storage controller
+
+Boot options
+------------
+
+The ``microchip-icicle-kit`` machine can start using the standard -bios
+functionality for loading its BIOS image, aka Hart Software Services (HSS_).
+HSS loads the second stage bootloader U-Boot from an SD card. It does not
+support direct kernel loading via the -kernel option. One has to load kernel
+from U-Boot.
+
+The memory is set to 1537 MiB by default which is the minimum required high
+memory size by HSS. A sanity check on ram size is performed in the machine
+init routine to prompt user to increase the RAM size to > 1537 MiB when less
+than 1537 MiB ram is detected.
+
+Boot the machine
+----------------
+
+HSS 2020.12 release is tested at the time of writing. To build an HSS image
+that can be booted by the ``microchip-icicle-kit`` machine, type the following
+in the HSS source tree:
+
+.. code-block:: bash
+
+ $ export CROSS_COMPILE=riscv64-linux-
+ $ cp boards/mpfs-icicle-kit-es/def_config .config
+ $ make BOARD=mpfs-icicle-kit-es
+
+Download the official SD card image released by Microchip and prepare it for
+QEMU usage:
+
+.. code-block:: bash
+
+ $ wget ftp://ftpsoc.microsemi.com/outgoing/core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic.gz
+ $ gunzip core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic.gz
+ $ qemu-img resize core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic 4G
+
+Then we can boot the machine by:
+
+.. code-block:: bash
+
+ $ qemu-system-riscv64 -M microchip-icicle-kit -smp 5 \
+ -bios path/to/hss.bin -sd path/to/sdcard.img \
+ -nic user,model=cadence_gem \
+ -nic tap,ifname=tap,model=cadence_gem,script=no \
+ -display none -serial stdio \
+ -chardev socket,id=serial1,path=serial1.sock,server=on,wait=on \
+ -serial chardev:serial1
+
+With above command line, current terminal session will be used for the first
+serial port. Open another terminal window, and use `minicom` to connect the
+second serial port.
+
+.. code-block:: bash
+
+ $ minicom -D unix\#serial1.sock
+
+HSS output is on the first serial port (stdio) and U-Boot outputs on the
+second serial port. U-Boot will automatically load the Linux kernel from
+the SD card image.
+
+.. _HSS: https://github.com/polarfire-soc/hart-software-services
diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
index 94d99c4c82..8d5946fbbb 100644
--- a/docs/system/target-riscv.rst
+++ b/docs/system/target-riscv.rst
@@ -66,6 +66,7 @@ undocumented; you can get a complete list by running
.. toctree::
:maxdepth: 1
+ riscv/microchip-icicle-kit
riscv/sifive_u
RISC-V CPU features
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index a2cd7a5830..d33ce8954a 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -634,6 +634,19 @@ Aml *aml_to_buffer(Aml *src, Aml *dst)
return var;
}
+/* ACPI 2.0a: 17.2.4.4 Type 2 Opcodes Encoding: DefToDecimalString */
+Aml *aml_to_decimalstring(Aml *src, Aml *dst)
+{
+ Aml *var = aml_opcode(0x97 /* ToDecimalStringOp */);
+ aml_append(var, src);
+ if (dst) {
+ aml_append(var, dst);
+ } else {
+ build_append_byte(var->buf, 0x00 /* NullNameOp */);
+ }
+ return var;
+}
+
/* ACPI 1.0b: 16.2.5.4 Type 2 Opcodes Encoding: DefStore */
Aml *aml_store(Aml *val, Aml *target)
{
@@ -835,6 +848,21 @@ Aml *aml_call5(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4,
return var;
}
+/* helper to call method with 5 arguments */
+Aml *aml_call6(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4,
+ Aml *arg5, Aml *arg6)
+{
+ Aml *var = aml_alloc();
+ build_append_namestring(var->buf, "%s", method);
+ aml_append(var, arg1);
+ aml_append(var, arg2);
+ aml_append(var, arg3);
+ aml_append(var, arg4);
+ aml_append(var, arg5);
+ aml_append(var, arg6);
+ return var;
+}
+
/*
* ACPI 5.0: 6.4.3.8.1 GPIO Connection Descriptor
* Type 1, Large Item Name 0xC
diff --git a/hw/acpi/pci.c b/hw/acpi/pci.c
index ec455c3b25..75b1103ec4 100644
--- a/hw/acpi/pci.c
+++ b/hw/acpi/pci.c
@@ -59,4 +59,3 @@ void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info,
build_header(linker, table_data, (void *)(table_data->data + mcfg_start),
"MCFG", table_data->len - mcfg_start, 1, oem_id, oem_table_id);
}
-
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 9dc4d3e2db..f4cb3c979d 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -39,18 +39,34 @@
#include "trace.h"
#define ACPI_PCIHP_ADDR 0xae00
-#define ACPI_PCIHP_SIZE 0x0014
+#define ACPI_PCIHP_SIZE 0x0018
#define PCI_UP_BASE 0x0000
#define PCI_DOWN_BASE 0x0004
#define PCI_EJ_BASE 0x0008
#define PCI_RMV_BASE 0x000c
#define PCI_SEL_BASE 0x0010
+#define PCI_AIDX_BASE 0x0014
typedef struct AcpiPciHpFind {
int bsel;
PCIBus *bus;
} AcpiPciHpFind;
+static gint g_cmp_uint32(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ return a - b;
+}
+
+static GSequence *pci_acpi_index_list(void)
+{
+ static GSequence *used_acpi_index_list;
+
+ if (!used_acpi_index_list) {
+ used_acpi_index_list = g_sequence_new(NULL);
+ }
+ return used_acpi_index_list;
+}
+
static int acpi_pcihp_get_bsel(PCIBus *bus)
{
Error *local_err = NULL;
@@ -251,9 +267,13 @@ void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off)
acpi_pcihp_update(s);
}
+#define ONBOARD_INDEX_MAX (16 * 1024 - 1)
+
void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
+ PCIDevice *pdev = PCI_DEVICE(dev);
+
/* Only hotplugged devices need the hotplug capability. */
if (dev->hotplugged &&
acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev))) < 0) {
@@ -261,6 +281,34 @@ void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
ACPI_PCIHP_PROP_BSEL "' set");
return;
}
+
+ /*
+ * capped by systemd (see: udev-builtin-net_id.c)
+ * as it's the only known user honor it to avoid users
+ * misconfigure QEMU and then wonder why acpi-index doesn't work
+ */
+ if (pdev->acpi_index > ONBOARD_INDEX_MAX) {
+ error_setg(errp, "acpi-index should be less or equal to %u",
+ ONBOARD_INDEX_MAX);
+ return;
+ }
+
+ /*
+ * make sure that acpi-index is unique across all present PCI devices
+ */
+ if (pdev->acpi_index) {
+ GSequence *used_indexes = pci_acpi_index_list();
+
+ if (g_sequence_lookup(used_indexes, GINT_TO_POINTER(pdev->acpi_index),
+ g_cmp_uint32, NULL)) {
+ error_setg(errp, "a PCI device with acpi-index = %" PRIu32
+ " already exist", pdev->acpi_index);
+ return;
+ }
+ g_sequence_insert_sorted(used_indexes,
+ GINT_TO_POINTER(pdev->acpi_index),
+ g_cmp_uint32, NULL);
+ }
}
void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
@@ -299,8 +347,22 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp)
{
+ PCIDevice *pdev = PCI_DEVICE(dev);
+
trace_acpi_pci_unplug(PCI_SLOT(PCI_DEVICE(dev)->devfn),
acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev))));
+
+ /*
+ * clean up acpi-index so it could reused by another device
+ */
+ if (pdev->acpi_index) {
+ GSequence *used_indexes = pci_acpi_index_list();
+
+ g_sequence_remove(g_sequence_lookup(used_indexes,
+ GINT_TO_POINTER(pdev->acpi_index),
+ g_cmp_uint32, NULL));
+ }
+
qdev_unrealize(dev);
}
@@ -347,7 +409,6 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
trace_acpi_pci_down_read(val);
break;
case PCI_EJ_BASE:
- /* No feature defined yet */
trace_acpi_pci_features_read(val);
break;
case PCI_RMV_BASE:
@@ -357,6 +418,12 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
case PCI_SEL_BASE:
val = s->hotplug_select;
trace_acpi_pci_sel_read(val);
+ break;
+ case PCI_AIDX_BASE:
+ val = s->acpi_index;
+ s->acpi_index = 0;
+ trace_acpi_pci_acpi_index_read(val);
+ break;
default:
break;
}
@@ -367,8 +434,35 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
static void pci_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
+ int slot;
+ PCIBus *bus;
+ BusChild *kid, *next;
AcpiPciHpState *s = opaque;
+
+ s->acpi_index = 0;
switch (addr) {
+ case PCI_AIDX_BASE:
+ /*
+ * fetch acpi-index for specified slot so that follow up read from
+ * PCI_AIDX_BASE can return it to guest
+ */
+ slot = ctz32(data);
+
+ if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
+ break;
+ }
+
+ bus = acpi_pcihp_find_hotplug_bus(s, s->hotplug_select);
+ QTAILQ_FOREACH_SAFE(kid, &bus->qbus.children, sibling, next) {
+ Object *o = OBJECT(kid->child);
+ PCIDevice *dev = PCI_DEVICE(o);
+ if (PCI_SLOT(dev->devfn) == slot) {
+ s->acpi_index = object_property_get_uint(o, "acpi-index", NULL);
+ break;
+ }
+ }
+ trace_acpi_pci_acpi_index_write(s->hotplug_select, slot, s->acpi_index);
+ break;
case PCI_EJ_BASE:
if (s->hotplug_select >= ACPI_PCIHP_MAX_HOTPLUG_BUS) {
break;
@@ -413,6 +507,12 @@ void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
OBJ_PROP_FLAG_READ);
}
+bool vmstate_acpi_pcihp_use_acpi_index(void *opaque, int version_id)
+{
+ AcpiPciHpState *s = opaque;
+ return s->acpi_index;
+}
+
const VMStateDescription vmstate_acpi_pcihp_pci_status = {
.name = "acpi_pcihp_pci_status",
.version_id = 1,
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 1efc0ded9f..6056d51667 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -297,7 +297,8 @@ static const VMStateDescription vmstate_acpi = {
2, vmstate_pci_status,
struct AcpiPciHpPciStatus),
VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
- vmstate_test_use_acpi_hotplug_bridge),
+ vmstate_test_use_acpi_hotplug_bridge,
+ vmstate_acpi_pcihp_use_acpi_index),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
diff --git a/hw/acpi/trace-events b/hw/acpi/trace-events
index f91ced477d..dcc1438f3a 100644
--- a/hw/acpi/trace-events
+++ b/hw/acpi/trace-events
@@ -41,6 +41,8 @@ acpi_pci_unplug_request(int bsel, int slot) "bsel: %d slot: %d"
acpi_pci_up_read(uint32_t val) "%" PRIu32
acpi_pci_down_read(uint32_t val) "%" PRIu32
acpi_pci_features_read(uint32_t val) "%" PRIu32
+acpi_pci_acpi_index_read(uint32_t val) "%" PRIu32
+acpi_pci_acpi_index_write(unsigned bsel, unsigned slot, uint32_t aidx) "bsel: %u slot: %u aidx: %" PRIu32
acpi_pci_rmv_read(uint32_t val) "%" PRIu32
acpi_pci_sel_read(uint32_t val) "%" PRIu32
acpi_pci_ej_write(uint64_t addr, uint64_t data) "0x%" PRIx64 " <== %" PRIu64
diff --git a/hw/acpi/utils.c b/hw/acpi/utils.c
index a134a4d554..0c486ea29f 100644
--- a/hw/acpi/utils.c
+++ b/hw/acpi/utils.c
@@ -27,9 +27,22 @@
#include "hw/loader.h"
MemoryRegion *acpi_add_rom_blob(FWCfgCallback update, void *opaque,
- GArray *blob, const char *name,
- uint64_t max_size)
+ GArray *blob, const char *name)
{
+ uint64_t max_size;
+
+ /* Reserve RAM space for tables: add another order of magnitude. */
+ if (!strcmp(name, ACPI_BUILD_TABLE_FILE)) {
+ max_size = 0x200000;
+ } else if (!strcmp(name, ACPI_BUILD_LOADER_FILE)) {
+ max_size = 0x10000;
+ } else if (!strcmp(name, ACPI_BUILD_RSDP_FILE)) {
+ max_size = 0x1000;
+ } else {
+ g_assert_not_reached();
+ }
+ g_assert(acpi_data_len(blob) <= max_size);
+
return rom_add_blob(name, blob->data, acpi_data_len(blob), max_size, -1,
name, update, opaque, NULL, true);
}
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index f9c9df916c..f5a2b2d4cb 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -859,13 +859,13 @@ void virt_acpi_setup(VirtMachineState *vms)
/* Now expose it all to Guest */
build_state->table_mr = acpi_add_rom_blob(virt_acpi_build_update,
build_state, tables.table_data,
- ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_MAX_SIZE);
+ ACPI_BUILD_TABLE_FILE);
assert(build_state->table_mr != NULL);
- build_state->linker_mr =
- acpi_add_rom_blob(virt_acpi_build_update, build_state,
- tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE, 0);
+ build_state->linker_mr = acpi_add_rom_blob(virt_acpi_build_update,
+ build_state,
+ tables.linker->cmd_blob,
+ ACPI_BUILD_LOADER_FILE);
fw_cfg_add_file(vms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data,
acpi_data_len(tables.tcpalog));
@@ -879,7 +879,7 @@ void virt_acpi_setup(VirtMachineState *vms)
build_state->rsdp_mr = acpi_add_rom_blob(virt_acpi_build_update,
build_state, tables.rsdp,
- ACPI_BUILD_RSDP_FILE, 0);
+ ACPI_BUILD_RSDP_FILE);
qemu_register_reset(virt_acpi_build_reset, build_state);
virt_acpi_build_reset(build_state);
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 5f9471d83c..183d3f44c2 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -895,6 +895,9 @@ static void decode_fast_read_cmd(Flash *s)
s->needed_bytes = get_addr_length(s);
switch (get_man(s)) {
/* Dummy cycles - modeled with bytes writes instead of bits */
+ case MAN_SST:
+ s->needed_bytes += 1;
+ break;
case MAN_WINBOND:
s->needed_bytes += 8;
break;
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index ac82d54063..83754a4344 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -972,6 +972,15 @@ static void xen_block_device_destroy(XenBackendInstance *backend,
object_unparent(OBJECT(xendev));
+ /*
+ * Drain all pending RCU callbacks as object_unparent() frees `xendev'
+ * in a RCU callback.
+ * And due to the property "drive" still existing in `xendev', we
+ * can't destroy the XenBlockDrive associated with `xendev' with
+ * xen_block_drive_destroy() below.
+ */
+ drain_call_rcu();
+
if (iothread) {
xen_block_iothread_destroy(iothread, errp);
if (*errp) {
diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c
index edcaa30ade..73b8f2e45b 100644
--- a/hw/char/ibex_uart.c
+++ b/hw/char/ibex_uart.c
@@ -66,7 +66,8 @@ static int ibex_uart_can_receive(void *opaque)
{
IbexUartState *s = opaque;
- if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
+ if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK)
+ && !(s->uart_status & R_STATUS_RXFULL_MASK)) {
return 1;
}
@@ -83,6 +84,11 @@ static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size)
s->uart_status &= ~R_STATUS_RXIDLE_MASK;
s->uart_status &= ~R_STATUS_RXEMPTY_MASK;
+ /* The RXFULL is set after receiving a single byte
+ * as the FIFO buffers are not yet implemented.
+ */
+ s->uart_status |= R_STATUS_RXFULL_MASK;
+ s->rx_level += 1;
if (size > rx_fifo_level) {
s->uart_intr_state |= R_INTR_STATE_RX_WATERMARK_MASK;
@@ -199,6 +205,7 @@ static void ibex_uart_reset(DeviceState *dev)
s->uart_timeout_ctrl = 0x00000000;
s->tx_level = 0;
+ s->rx_level = 0;
s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10;
@@ -243,11 +250,15 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
case R_RDATA:
retvalue = s->uart_rdata;
- if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) {
+ if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) && (s->rx_level > 0)) {
qemu_chr_fe_accept_input(&s->chr);
- s->uart_status |= R_STATUS_RXIDLE_MASK;
- s->uart_status |= R_STATUS_RXEMPTY_MASK;
+ s->rx_level -= 1;
+ s->uart_status &= ~R_STATUS_RXFULL_MASK;
+ if (s->rx_level == 0) {
+ s->uart_status |= R_STATUS_RXIDLE_MASK;
+ s->uart_status |= R_STATUS_RXEMPTY_MASK;
+ }
}
break;
case R_WDATA:
@@ -261,7 +272,8 @@ static uint64_t ibex_uart_read(void *opaque, hwaddr addr,
case R_FIFO_STATUS:
retvalue = s->uart_fifo_status;
- retvalue |= s->tx_level & 0x1F;
+ retvalue |= (s->rx_level & 0x1F) << R_FIFO_STATUS_RXLVL_SHIFT;
+ retvalue |= (s->tx_level & 0x1F) << R_FIFO_STATUS_TXLVL_SHIFT;
qemu_log_mask(LOG_UNIMP,
"%s: RX fifos are not supported\n", __func__);
@@ -364,6 +376,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr,
s->uart_fifo_ctrl = value;
if (value & R_FIFO_CTRL_RXRST_MASK) {
+ s->rx_level = 0;
qemu_log_mask(LOG_UNIMP,
"%s: RX fifos are not supported\n", __func__);
}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 442b4629a9..de98750aef 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -397,6 +397,13 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
aml_append(dev, method);
+ method = aml_method("_DSM", 4, AML_SERIALIZED);
+ aml_append(method,
+ aml_return(aml_call6("PDSM", aml_arg(0), aml_arg(1),
+ aml_arg(2), aml_arg(3),
+ aml_name("BSEL"), aml_name("_SUN")))
+ );
+ aml_append(dev, method);
aml_append(parent_scope, dev);
build_append_pcihp_notify_entry(notify_method, slot);
@@ -424,6 +431,16 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
dev = aml_device("S%.02X", PCI_DEVFN(slot, 0));
aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16)));
+ if (bsel) {
+ aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
+ method = aml_method("_DSM", 4, AML_SERIALIZED);
+ aml_append(method, aml_return(
+ aml_call6("PDSM", aml_arg(0), aml_arg(1), aml_arg(2),
+ aml_arg(3), aml_name("BSEL"), aml_name("_SUN"))
+ ));
+ aml_append(dev, method);
+ }
+
if (pc->class_id == PCI_CLASS_DISPLAY_VGA) {
/* add VGA specific AML methods */
int s3d;
@@ -446,9 +463,7 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
aml_append(method, aml_return(aml_int(s3d)));
aml_append(dev, method);
} else if (hotplug_enabled_dev) {
- /* add _SUN/_EJ0 to make slot hotpluggable */
- aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
-
+ /* add _EJ0 to make slot hotpluggable */
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
@@ -511,6 +526,88 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
qobject_unref(bsel);
}
+Aml *aml_pci_device_dsm(void)
+{
+ Aml *method, *UUID, *ifctx, *ifctx1, *ifctx2, *ifctx3, *elsectx;
+ Aml *acpi_index = aml_local(0);
+ Aml *zero = aml_int(0);
+ Aml *bnum = aml_arg(4);
+ Aml *func = aml_arg(2);
+ Aml *rev = aml_arg(1);
+ Aml *sun = aml_arg(5);
+
+ method = aml_method("PDSM", 6, AML_SERIALIZED);
+
+ /*
+ * PCI Firmware Specification 3.1
+ * 4.6. _DSM Definitions for PCI
+ */
+ UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
+ ifctx = aml_if(aml_equal(aml_arg(0), UUID));
+ {
+ aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sun), acpi_index));
+ ifctx1 = aml_if(aml_equal(func, zero));
+ {
+ uint8_t byte_list[1];
+
+ ifctx2 = aml_if(aml_equal(rev, aml_int(2)));
+ {
+ /*
+ * advertise function 7 if device has acpi-index
+ * acpi_index values:
+ * 0: not present (default value)
+ * FFFFFFFF: not supported (old QEMU without PIDX reg)
+ * other: device's acpi-index
+ */
+ ifctx3 = aml_if(aml_lnot(
+ aml_or(aml_equal(acpi_index, zero),
+ aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL)
+ ));
+ {
+ byte_list[0] =
+ 1 /* have supported functions */ |
+ 1 << 7 /* support for function 7 */
+ ;
+ aml_append(ifctx3, aml_return(aml_buffer(1, byte_list)));
+ }
+ aml_append(ifctx2, ifctx3);
+ }
+ aml_append(ifctx1, ifctx2);
+
+ byte_list[0] = 0; /* nothing supported */
+ aml_append(ifctx1, aml_return(aml_buffer(1, byte_list)));
+ }
+ aml_append(ifctx, ifctx1);
+ elsectx = aml_else();
+ /*
+ * PCI Firmware Specification 3.1
+ * 4.6.7. _DSM for Naming a PCI or PCI Express Device Under
+ * Operating Systems
+ */
+ ifctx1 = aml_if(aml_equal(func, aml_int(7)));
+ {
+ Aml *pkg = aml_package(2);
+ Aml *ret = aml_local(1);
+
+ aml_append(pkg, zero);
+ /*
+ * optional, if not impl. should return null string
+ */
+ aml_append(pkg, aml_string("%s", ""));
+ aml_append(ifctx1, aml_store(pkg, ret));
+ /*
+ * update acpi-index to actual value
+ */
+ aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero)));
+ aml_append(ifctx1, aml_return(ret));
+ }
+ aml_append(elsectx, ifctx1);
+ aml_append(ifctx, elsectx);
+ }
+ aml_append(method, ifctx);
+ return method;
+}
+
/**
* build_prt_entry:
* @link_name: link name for PCI route entry
@@ -1168,9 +1265,10 @@ static void build_piix4_pci_hotplug(Aml *table)
aml_append(scope, field);
aml_append(scope,
- aml_operation_region("BNMR", AML_SYSTEM_IO, aml_int(0xae10), 0x04));
+ aml_operation_region("BNMR", AML_SYSTEM_IO, aml_int(0xae10), 0x08));
field = aml_field("BNMR", AML_DWORD_ACC, AML_NOLOCK, AML_WRITE_AS_ZEROS);
aml_append(field, aml_named_field("BNUM", 32));
+ aml_append(field, aml_named_field("PIDX", 32));
aml_append(scope, field);
aml_append(scope, aml_mutex("BLCK", 0));
@@ -1184,6 +1282,18 @@ static void build_piix4_pci_hotplug(Aml *table)
aml_append(method, aml_return(aml_int(0)));
aml_append(scope, method);
+ method = aml_method("AIDX", 2, AML_NOTSERIALIZED);
+ aml_append(method, aml_acquire(aml_name("BLCK"), 0xFFFF));
+ aml_append(method, aml_store(aml_arg(0), aml_name("BNUM")));
+ aml_append(method,
+ aml_store(aml_shiftleft(aml_int(1), aml_arg(1)), aml_name("PIDX")));
+ aml_append(method, aml_store(aml_name("PIDX"), aml_local(0)));
+ aml_append(method, aml_release(aml_name("BLCK")));
+ aml_append(method, aml_return(aml_local(0)));
+ aml_append(scope, method);
+
+ aml_append(scope, aml_pci_device_dsm());
+
aml_append(table, scope);
}
@@ -1697,7 +1807,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
build_header(linker, table_data,
(void *)(table_data->data + table_data->len - dsdt->buf->len),
- "DSDT", dsdt->buf->len, 1, pcms->oem_id, pcms->oem_table_id);
+ "DSDT", dsdt->buf->len, 1, x86ms->oem_id, x86ms->oem_table_id);
free_aml_allocator();
}
@@ -1874,8 +1984,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
build_header(linker, table_data,
(void *)(table_data->data + srat_start),
"SRAT",
- table_data->len - srat_start, 1, pcms->oem_id,
- pcms->oem_table_id);
+ table_data->len - srat_start, 1, x86ms->oem_id,
+ x86ms->oem_table_id);
}
/*
@@ -2228,13 +2338,13 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
if (slic_oem.id) {
oem_id = slic_oem.id;
} else {
- oem_id = pcms->oem_id;
+ oem_id = x86ms->oem_id;
}
if (slic_oem.table_id) {
oem_table_id = slic_oem.table_id;
} else {
- oem_table_id = pcms->oem_table_id;
+ oem_table_id = x86ms->oem_table_id;
}
table_offsets = g_array_new(false, true /* clear */,
@@ -2275,30 +2385,30 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
acpi_add_table(table_offsets, tables_blob);
acpi_build_madt(tables_blob, tables->linker, x86ms,
- ACPI_DEVICE_IF(x86ms->acpi_dev), pcms->oem_id,
- pcms->oem_table_id);
+ ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id,
+ x86ms->oem_table_id);
vmgenid_dev = find_vmgenid_dev();
if (vmgenid_dev) {
acpi_add_table(table_offsets, tables_blob);
vmgenid_build_acpi(VMGENID(vmgenid_dev), tables_blob,
- tables->vmgenid, tables->linker, pcms->oem_id);
+ tables->vmgenid, tables->linker, x86ms->oem_id);
}
if (misc.has_hpet) {
acpi_add_table(table_offsets, tables_blob);
- build_hpet(tables_blob, tables->linker, pcms->oem_id,
- pcms->oem_table_id);
+ build_hpet(tables_blob, tables->linker, x86ms->oem_id,
+ x86ms->oem_table_id);
}
if (misc.tpm_version != TPM_VERSION_UNSPEC) {
if (misc.tpm_version == TPM_VERSION_1_2) {
acpi_add_table(table_offsets, tables_blob);
build_tpm_tcpa(tables_blob, tables->linker, tables->tcpalog,
- pcms->oem_id, pcms->oem_table_id);
+ x86ms->oem_id, x86ms->oem_table_id);
} else { /* TPM_VERSION_2_0 */
acpi_add_table(table_offsets, tables_blob);
build_tpm2(tables_blob, tables->linker, tables->tcpalog,
- pcms->oem_id, pcms->oem_table_id);
+ x86ms->oem_id, x86ms->oem_table_id);
}
}
if (pcms->numa_nodes) {
@@ -2306,40 +2416,40 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
build_srat(tables_blob, tables->linker, machine);
if (machine->numa_state->have_numa_distance) {
acpi_add_table(table_offsets, tables_blob);
- build_slit(tables_blob, tables->linker, machine, pcms->oem_id,
- pcms->oem_table_id);
+ build_slit(tables_blob, tables->linker, machine, x86ms->oem_id,
+ x86ms->oem_table_id);
}
if (machine->numa_state->hmat_enabled) {
acpi_add_table(table_offsets, tables_blob);
build_hmat(tables_blob, tables->linker, machine->numa_state,
- pcms->oem_id, pcms->oem_table_id);
+ x86ms->oem_id, x86ms->oem_table_id);
}
}
if (acpi_get_mcfg(&mcfg)) {
acpi_add_table(table_offsets, tables_blob);
- build_mcfg(tables_blob, tables->linker, &mcfg, pcms->oem_id,
- pcms->oem_table_id);
+ build_mcfg(tables_blob, tables->linker, &mcfg, x86ms->oem_id,
+ x86ms->oem_table_id);
}
if (x86_iommu_get_default()) {
IommuType IOMMUType = x86_iommu_get_type();
if (IOMMUType == TYPE_AMD) {
acpi_add_table(table_offsets, tables_blob);
- build_amd_iommu(tables_blob, tables->linker, pcms->oem_id,
- pcms->oem_table_id);
+ build_amd_iommu(tables_blob, tables->linker, x86ms->oem_id,
+ x86ms->oem_table_id);
} else if (IOMMUType == TYPE_INTEL) {
acpi_add_table(table_offsets, tables_blob);
- build_dmar_q35(tables_blob, tables->linker, pcms->oem_id,
- pcms->oem_table_id);
+ build_dmar_q35(tables_blob, tables->linker, x86ms->oem_id,
+ x86ms->oem_table_id);
}
}
if (machine->nvdimms_state->is_enabled) {
nvdimm_build_acpi(table_offsets, tables_blob, tables->linker,
machine->nvdimms_state, machine->ram_slots,
- pcms->oem_id, pcms->oem_table_id);
+ x86ms->oem_id, x86ms->oem_table_id);
}
acpi_add_table(table_offsets, tables_blob);
- build_waet(tables_blob, tables->linker, pcms->oem_id, pcms->oem_table_id);
+ build_waet(tables_blob, tables->linker, x86ms->oem_id, x86ms->oem_table_id);
/* Add tables supplied by user (if any) */
for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
@@ -2358,7 +2468,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
{
AcpiRsdpData rsdp_data = {
.revision = 0,
- .oem_id = pcms->oem_id,
+ .oem_id = x86ms->oem_id,
.xsdt_tbl_offset = NULL,
.rsdt_tbl_offset = &rsdt,
};
@@ -2518,13 +2628,12 @@ void acpi_setup(void)
/* Now expose it all to Guest */
build_state->table_mr = acpi_add_rom_blob(acpi_build_update,
build_state, tables.table_data,
- ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_MAX_SIZE);
+ ACPI_BUILD_TABLE_FILE);
assert(build_state->table_mr != NULL);
build_state->linker_mr =
acpi_add_rom_blob(acpi_build_update, build_state,
- tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE, 0);
+ tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE);
fw_cfg_add_file(x86ms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
tables.tcpalog->data, acpi_data_len(tables.tcpalog));
@@ -2563,7 +2672,7 @@ void acpi_setup(void)
build_state->rsdp = NULL;
build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update,
build_state, tables.rsdp,
- ACPI_BUILD_RSDP_FILE, 0);
+ ACPI_BUILD_RSDP_FILE);
}
qemu_register_reset(acpi_build_reset, build_state);
diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c
index 54b3af478a..ccd3303aac 100644
--- a/hw/i386/acpi-microvm.c
+++ b/hw/i386/acpi-microvm.c
@@ -149,7 +149,7 @@ build_dsdt_microvm(GArray *table_data, BIOSLinker *linker,
g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
build_header(linker, table_data,
(void *)(table_data->data + table_data->len - dsdt->buf->len),
- "DSDT", dsdt->buf->len, 2, mms->oem_id, mms->oem_table_id);
+ "DSDT", dsdt->buf->len, 2, x86ms->oem_id, x86ms->oem_table_id);
free_aml_allocator();
}
@@ -201,24 +201,24 @@ static void acpi_build_microvm(AcpiBuildTables *tables,
pmfadt.dsdt_tbl_offset = &dsdt;
pmfadt.xdsdt_tbl_offset = &dsdt;
acpi_add_table(table_offsets, tables_blob);
- build_fadt(tables_blob, tables->linker, &pmfadt, mms->oem_id,
- mms->oem_table_id);
+ build_fadt(tables_blob, tables->linker, &pmfadt, x86ms->oem_id,
+ x86ms->oem_table_id);
acpi_add_table(table_offsets, tables_blob);
acpi_build_madt(tables_blob, tables->linker, X86_MACHINE(machine),
- ACPI_DEVICE_IF(x86ms->acpi_dev), mms->oem_id,
- mms->oem_table_id);
+ ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id,
+ x86ms->oem_table_id);
xsdt = tables_blob->len;
- build_xsdt(tables_blob, tables->linker, table_offsets, mms->oem_id,
- mms->oem_table_id);
+ build_xsdt(tables_blob, tables->linker, table_offsets, x86ms->oem_id,
+ x86ms->oem_table_id);
/* RSDP is in FSEG memory, so allocate it separately */
{
AcpiRsdpData rsdp_data = {
/* ACPI 2.0: 5.2.4.3 RSDP Structure */
.revision = 2, /* xsdt needs v2 */
- .oem_id = mms->oem_id,
+ .oem_id = x86ms->oem_id,
.xsdt_tbl_offset = &xsdt,
.rsdt_tbl_offset = NULL,
};
@@ -249,16 +249,12 @@ void acpi_setup_microvm(MicrovmMachineState *mms)
acpi_build_microvm(&tables, mms);
/* Now expose it all to Guest */
- acpi_add_rom_blob(acpi_build_no_update, NULL,
- tables.table_data,
- ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_MAX_SIZE);
- acpi_add_rom_blob(acpi_build_no_update, NULL,
- tables.linker->cmd_blob,
- "etc/table-loader", 0);
- acpi_add_rom_blob(acpi_build_no_update, NULL,
- tables.rsdp,
- ACPI_BUILD_RSDP_FILE, 0);
+ acpi_add_rom_blob(acpi_build_no_update, NULL, tables.table_data,
+ ACPI_BUILD_TABLE_FILE);
+ acpi_add_rom_blob(acpi_build_no_update, NULL, tables.linker->cmd_blob,
+ ACPI_BUILD_LOADER_FILE);
+ acpi_add_rom_blob(acpi_build_no_update, NULL, tables.rsdp,
+ ACPI_BUILD_RSDP_FILE);
acpi_build_tables_cleanup(&tables, false);
}
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 4e0cf4c522..edf2b0f061 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -648,51 +648,6 @@ static void microvm_powerdown_req(Notifier *notifier, void *data)
}
}
-static char *microvm_machine_get_oem_id(Object *obj, Error **errp)
-{
- MicrovmMachineState *mms = MICROVM_MACHINE(obj);
-
- return g_strdup(mms->oem_id);
-}
-
-static void microvm_machine_set_oem_id(Object *obj, const char *value,
- Error **errp)
-{
- MicrovmMachineState *mms = MICROVM_MACHINE(obj);
- size_t len = strlen(value);
-
- if (len > 6) {
- error_setg(errp,
- "User specified "MICROVM_MACHINE_OEM_ID" value is bigger than "
- "6 bytes in size");
- return;
- }
-
- strncpy(mms->oem_id, value, 6);
-}
-
-static char *microvm_machine_get_oem_table_id(Object *obj, Error **errp)
-{
- MicrovmMachineState *mms = MICROVM_MACHINE(obj);
-
- return g_strdup(mms->oem_table_id);
-}
-
-static void microvm_machine_set_oem_table_id(Object *obj, const char *value,
- Error **errp)
-{
- MicrovmMachineState *mms = MICROVM_MACHINE(obj);
- size_t len = strlen(value);
-
- if (len > 8) {
- error_setg(errp,
- "User specified "MICROVM_MACHINE_OEM_TABLE_ID" value is bigger than "
- "8 bytes in size");
- return;
- }
- strncpy(mms->oem_table_id, value, 8);
-}
-
static void microvm_machine_initfn(Object *obj)
{
MicrovmMachineState *mms = MICROVM_MACHINE(obj);
@@ -714,9 +669,6 @@ static void microvm_machine_initfn(Object *obj)
qemu_add_machine_init_done_notifier(&mms->machine_done);
mms->powerdown_req.notify = microvm_powerdown_req;
qemu_register_powerdown_notifier(&mms->powerdown_req);
-
- mms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
- mms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
}
static void microvm_class_init(ObjectClass *oc, void *data)
@@ -805,24 +757,6 @@ static void microvm_class_init(ObjectClass *oc, void *data)
MICROVM_MACHINE_AUTO_KERNEL_CMDLINE,
"Set off to disable adding virtio-mmio devices to the kernel cmdline");
- object_class_property_add_str(oc, MICROVM_MACHINE_OEM_ID,
- microvm_machine_get_oem_id,
- microvm_machine_set_oem_id);
- object_class_property_set_description(oc, MICROVM_MACHINE_OEM_ID,
- "Override the default value of field OEMID "
- "in ACPI table header."
- "The string may be up to 6 bytes in size");
-
-
- object_class_property_add_str(oc, MICROVM_MACHINE_OEM_TABLE_ID,
- microvm_machine_get_oem_table_id,
- microvm_machine_set_oem_table_id);
- object_class_property_set_description(oc, MICROVM_MACHINE_OEM_TABLE_ID,
- "Override the default value of field OEM Table ID "
- "in ACPI table header."
- "The string may be up to 8 bytes in size");
-
-
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 35e1770950..8a84b25a03 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1608,49 +1608,6 @@ static void pc_machine_set_max_fw_size(Object *obj, Visitor *v,
pcms->max_fw_size = value;
}
-static char *pc_machine_get_oem_id(Object *obj, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
-
- return g_strdup(pcms->oem_id);
-}
-
-static void pc_machine_set_oem_id(Object *obj, const char *value, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
- size_t len = strlen(value);
-
- if (len > 6) {
- error_setg(errp,
- "User specified "PC_MACHINE_OEM_ID" value is bigger than "
- "6 bytes in size");
- return;
- }
-
- strncpy(pcms->oem_id, value, 6);
-}
-
-static char *pc_machine_get_oem_table_id(Object *obj, Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
-
- return g_strdup(pcms->oem_table_id);
-}
-
-static void pc_machine_set_oem_table_id(Object *obj, const char *value,
- Error **errp)
-{
- PCMachineState *pcms = PC_MACHINE(obj);
- size_t len = strlen(value);
-
- if (len > 8) {
- error_setg(errp,
- "User specified "PC_MACHINE_OEM_TABLE_ID" value is bigger than "
- "8 bytes in size");
- return;
- }
- strncpy(pcms->oem_table_id, value, 8);
-}
static void pc_machine_initfn(Object *obj)
{
@@ -1664,8 +1621,6 @@ static void pc_machine_initfn(Object *obj)
pcms->max_ram_below_4g = 0; /* use default */
/* acpi build is enabled by default if machine supports it */
pcms->acpi_build_enabled = PC_MACHINE_GET_CLASS(pcms)->has_acpi_build;
- pcms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
- pcms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
pcms->smbus_enabled = true;
pcms->sata_enabled = true;
pcms->pit_enabled = true;
@@ -1802,24 +1757,6 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
NULL, NULL);
object_class_property_set_description(oc, PC_MACHINE_MAX_FW_SIZE,
"Maximum combined firmware size");
-
- object_class_property_add_str(oc, PC_MACHINE_OEM_ID,
- pc_machine_get_oem_id,
- pc_machine_set_oem_id);
- object_class_property_set_description(oc, PC_MACHINE_OEM_ID,
- "Override the default value of field OEMID "
- "in ACPI table header."
- "The string may be up to 6 bytes in size");
-
-
- object_class_property_add_str(oc, PC_MACHINE_OEM_TABLE_ID,
- pc_machine_get_oem_table_id,
- pc_machine_set_oem_table_id);
- object_class_property_set_description(oc, PC_MACHINE_OEM_TABLE_ID,
- "Override the default value of field OEM Table ID "
- "in ACPI table header."
- "The string may be up to 8 bytes in size");
-
}
static const TypeInfo pc_machine_info = {
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 7865660e2c..ed796fe6ba 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -1201,6 +1201,51 @@ static void x86_machine_set_acpi(Object *obj, Visitor *v, const char *name,
visit_type_OnOffAuto(v, name, &x86ms->acpi, errp);
}
+static char *x86_machine_get_oem_id(Object *obj, Error **errp)
+{
+ X86MachineState *x86ms = X86_MACHINE(obj);
+
+ return g_strdup(x86ms->oem_id);
+}
+
+static void x86_machine_set_oem_id(Object *obj, const char *value, Error **errp)
+{
+ X86MachineState *x86ms = X86_MACHINE(obj);
+ size_t len = strlen(value);
+
+ if (len > 6) {
+ error_setg(errp,
+ "User specified "X86_MACHINE_OEM_ID" value is bigger than "
+ "6 bytes in size");
+ return;
+ }
+
+ strncpy(x86ms->oem_id, value, 6);
+}
+
+static char *x86_machine_get_oem_table_id(Object *obj, Error **errp)
+{
+ X86MachineState *x86ms = X86_MACHINE(obj);
+
+ return g_strdup(x86ms->oem_table_id);
+}
+
+static void x86_machine_set_oem_table_id(Object *obj, const char *value,
+ Error **errp)
+{
+ X86MachineState *x86ms = X86_MACHINE(obj);
+ size_t len = strlen(value);
+
+ if (len > 8) {
+ error_setg(errp,
+ "User specified "X86_MACHINE_OEM_TABLE_ID
+ " value is bigger than "
+ "8 bytes in size");
+ return;
+ }
+ strncpy(x86ms->oem_table_id, value, 8);
+}
+
static void x86_machine_initfn(Object *obj)
{
X86MachineState *x86ms = X86_MACHINE(obj);
@@ -1209,6 +1254,8 @@ static void x86_machine_initfn(Object *obj)
x86ms->acpi = ON_OFF_AUTO_AUTO;
x86ms->smp_dies = 1;
x86ms->pci_irq_mask = ACPI_BUILD_PCI_IRQS;
+ x86ms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
+ x86ms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
}
static void x86_machine_class_init(ObjectClass *oc, void *data)
@@ -1235,6 +1282,23 @@ static void x86_machine_class_init(ObjectClass *oc, void *data)
NULL, NULL);
object_class_property_set_description(oc, X86_MACHINE_ACPI,
"Enable ACPI");
+
+ object_class_property_add_str(oc, X86_MACHINE_OEM_ID,
+ x86_machine_get_oem_id,
+ x86_machine_set_oem_id);
+ object_class_property_set_description(oc, X86_MACHINE_OEM_ID,
+ "Override the default value of field OEMID "
+ "in ACPI table header."
+ "The string may be up to 6 bytes in size");
+
+
+ object_class_property_add_str(oc, X86_MACHINE_OEM_TABLE_ID,
+ x86_machine_get_oem_table_id,
+ x86_machine_set_oem_table_id);
+ object_class_property_set_description(oc, X86_MACHINE_OEM_TABLE_ID,
+ "Override the default value of field OEM Table ID "
+ "in ACPI table header."
+ "The string may be up to 8 bytes in size");
}
static const TypeInfo x86_machine_info = {
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 0eadcdbc9e..ac9a24889c 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -79,6 +79,7 @@ static Property pci_props[] = {
QEMU_PCIE_EXTCAP_INIT_BITNR, true),
DEFINE_PROP_STRING("failover_pair_id", PCIDevice,
failover_pair_id),
+ DEFINE_PROP_UINT32("acpi-index", PCIDevice, acpi_index, 0),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index d139074b02..1de18cdcf1 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -33,6 +33,7 @@ config RISCV_VIRT
select SIFIVE_PLIC
select SIFIVE_TEST
select VIRTIO_MMIO
+ select FW_CFG_DMA
config SIFIVE_E
bool
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index 266f1c3342..c4146b7a6b 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -122,6 +122,7 @@ static const MemMapEntry microchip_pfsoc_memmap[] = {
[MICROCHIP_PFSOC_ENVM_DATA] = { 0x20220000, 0x20000 },
[MICROCHIP_PFSOC_QSPI_XIP] = { 0x21000000, 0x1000000 },
[MICROCHIP_PFSOC_IOSCB] = { 0x30000000, 0x10000000 },
+ [MICROCHIP_PFSOC_EMMC_SD_MUX] = { 0x4f000000, 0x4 },
[MICROCHIP_PFSOC_DRAM_LO] = { 0x80000000, 0x40000000 },
[MICROCHIP_PFSOC_DRAM_LO_ALIAS] = { 0xc0000000, 0x40000000 },
[MICROCHIP_PFSOC_DRAM_HI] = { 0x1000000000, 0x0 },
@@ -411,6 +412,11 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ioscb), 0,
memmap[MICROCHIP_PFSOC_IOSCB].base);
+ /* eMMC/SD mux */
+ create_unimplemented_device("microchip.pfsoc.emmc_sd_mux",
+ memmap[MICROCHIP_PFSOC_EMMC_SD_MUX].base,
+ memmap[MICROCHIP_PFSOC_EMMC_SD_MUX].size);
+
/* QSPI Flash */
memory_region_init_rom(qspi_xip_mem, OBJECT(dev),
"microchip.pfsoc.qspi_xip",
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 0b39101a5e..c0dc69ff33 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -42,6 +42,7 @@
#include "sysemu/sysemu.h"
#include "hw/pci/pci.h"
#include "hw/pci-host/gpex.h"
+#include "hw/display/ramfb.h"
static const MemMapEntry virt_memmap[] = {
[VIRT_DEBUG] = { 0x0, 0x100 },
@@ -53,6 +54,7 @@ static const MemMapEntry virt_memmap[] = {
[VIRT_PLIC] = { 0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
[VIRT_UART0] = { 0x10000000, 0x100 },
[VIRT_VIRTIO] = { 0x10001000, 0x1000 },
+ [VIRT_FW_CFG] = { 0x10100000, 0x18 },
[VIRT_FLASH] = { 0x20000000, 0x4000000 },
[VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 },
[VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
@@ -507,6 +509,28 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
return dev;
}
+static FWCfgState *create_fw_cfg(const MachineState *mc)
+{
+ hwaddr base = virt_memmap[VIRT_FW_CFG].base;
+ hwaddr size = virt_memmap[VIRT_FW_CFG].size;
+ FWCfgState *fw_cfg;
+ char *nodename;
+
+ fw_cfg = fw_cfg_init_mem_wide(base + 8, base, 8, base + 16,
+ &address_space_memory);
+ fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)mc->smp.cpus);
+
+ nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base);
+ qemu_fdt_add_subnode(mc->fdt, nodename);
+ qemu_fdt_setprop_string(mc->fdt, nodename,
+ "compatible", "qemu,fw-cfg-mmio");
+ qemu_fdt_setprop_sized_cells(mc->fdt, nodename, "reg",
+ 2, base, 2, size);
+ qemu_fdt_setprop(mc->fdt, nodename, "dma-coherent", NULL, 0);
+ g_free(nodename);
+ return fw_cfg;
+}
+
static void virt_machine_init(MachineState *machine)
{
const MemMapEntry *memmap = virt_memmap;
@@ -688,6 +712,13 @@ static void virt_machine_init(MachineState *machine)
start_addr = virt_memmap[VIRT_FLASH].base;
}
+ /*
+ * Init fw_cfg. Must be done before riscv_load_fdt, otherwise the device
+ * tree cannot be altered and we get FDT_ERR_NOSPACE.
+ */
+ s->fw_cfg = create_fw_cfg(machine);
+ rom_set_fw(s->fw_cfg);
+
/* Compute the fdt load address in dram */
fdt_load_addr = riscv_load_fdt(memmap[VIRT_DRAM].base,
machine->ram_size, machine->fdt);
@@ -751,6 +782,8 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props;
mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id;
mc->numa_mem_supported = true;
+
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
}
static const TypeInfo virt_machine_typeinfo = {
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 2fdd5daf74..ded0c10453 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -16,6 +16,7 @@
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-net.h"
#include "chardev/char-fe.h"
+#include "io/channel-socket.h"
#include "sysemu/kvm.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
@@ -237,7 +238,8 @@ struct vhost_user {
struct vhost_dev *dev;
/* Shared between vhost devs of the same virtio device */
VhostUserState *user;
- int slave_fd;
+ QIOChannel *slave_ioc;
+ GSource *slave_src;
NotifierWithReturn postcopy_notifier;
struct PostCopyFD postcopy_fd;
uint64_t postcopy_client_bases[VHOST_USER_MAX_RAM_SLOTS];
@@ -294,15 +296,27 @@ static int vhost_user_read_header(struct vhost_dev *dev, VhostUserMsg *msg)
return 0;
}
-static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
+struct vhost_user_read_cb_data {
+ struct vhost_dev *dev;
+ VhostUserMsg *msg;
+ GMainLoop *loop;
+ int ret;
+};
+
+static gboolean vhost_user_read_cb(GIOChannel *source, GIOCondition condition,
+ gpointer opaque)
{
+ struct vhost_user_read_cb_data *data = opaque;
+ struct vhost_dev *dev = data->dev;
+ VhostUserMsg *msg = data->msg;
struct vhost_user *u = dev->opaque;
CharBackend *chr = u->user->chr;
uint8_t *p = (uint8_t *) msg;
int r, size;
if (vhost_user_read_header(dev, msg) < 0) {
- return -1;
+ data->ret = -1;
+ goto end;
}
/* validate message size is sane */
@@ -310,7 +324,8 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
error_report("Failed to read msg header."
" Size %d exceeds the maximum %zu.", msg->hdr.size,
VHOST_USER_PAYLOAD_SIZE);
- return -1;
+ data->ret = -1;
+ goto end;
}
if (msg->hdr.size) {
@@ -320,11 +335,84 @@ static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
if (r != size) {
error_report("Failed to read msg payload."
" Read %d instead of %d.", r, msg->hdr.size);
- return -1;
+ data->ret = -1;
+ goto end;
}
}
- return 0;
+end:
+ g_main_loop_quit(data->loop);
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean slave_read(QIOChannel *ioc, GIOCondition condition,
+ gpointer opaque);
+
+/*
+ * This updates the read handler to use a new event loop context.
+ * Event sources are removed from the previous context : this ensures
+ * that events detected in the previous context are purged. They will
+ * be re-detected and processed in the new context.
+ */
+static void slave_update_read_handler(struct vhost_dev *dev,
+ GMainContext *ctxt)
+{
+ struct vhost_user *u = dev->opaque;
+
+ if (!u->slave_ioc) {
+ return;
+ }
+
+ if (u->slave_src) {
+ g_source_destroy(u->slave_src);
+ g_source_unref(u->slave_src);
+ }
+
+ u->slave_src = qio_channel_add_watch_source(u->slave_ioc,
+ G_IO_IN | G_IO_HUP,
+ slave_read, dev, NULL,
+ ctxt);
+}
+
+static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg)
+{
+ struct vhost_user *u = dev->opaque;
+ CharBackend *chr = u->user->chr;
+ GMainContext *prev_ctxt = chr->chr->gcontext;
+ GMainContext *ctxt = g_main_context_new();
+ GMainLoop *loop = g_main_loop_new(ctxt, FALSE);
+ struct vhost_user_read_cb_data data = {
+ .dev = dev,
+ .loop = loop,
+ .msg = msg,
+ .ret = 0
+ };
+
+ /*
+ * We want to be able to monitor the slave channel fd while waiting
+ * for chr I/O. This requires an event loop, but we can't nest the
+ * one to which chr is currently attached : its fd handlers might not
+ * be prepared for re-entrancy. So we create a new one and switch chr
+ * to use it.
+ */
+ slave_update_read_handler(dev, ctxt);
+ qemu_chr_be_update_read_handlers(chr->chr, ctxt);
+ qemu_chr_fe_add_watch(chr, G_IO_IN | G_IO_HUP, vhost_user_read_cb, &data);
+
+ g_main_loop_run(loop);
+
+ /*
+ * Restore the previous event loop context. This also destroys/recreates
+ * event sources : this guarantees that all pending events in the original
+ * context that have been processed by the nested loop are purged.
+ */
+ qemu_chr_be_update_read_handlers(chr->chr, prev_ctxt);
+ slave_update_read_handler(dev, NULL);
+
+ g_main_loop_unref(loop);
+ g_main_context_unref(ctxt);
+
+ return data.ret;
}
static int process_message_reply(struct vhost_dev *dev,
@@ -1392,56 +1480,39 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
return 0;
}
-static void slave_read(void *opaque)
+static void close_slave_channel(struct vhost_user *u)
+{
+ g_source_destroy(u->slave_src);
+ g_source_unref(u->slave_src);
+ u->slave_src = NULL;
+ object_unref(OBJECT(u->slave_ioc));
+ u->slave_ioc = NULL;
+}
+
+static gboolean slave_read(QIOChannel *ioc, GIOCondition condition,
+ gpointer opaque)
{
struct vhost_dev *dev = opaque;
struct vhost_user *u = dev->opaque;
VhostUserHeader hdr = { 0, };
VhostUserPayload payload = { 0, };
- int size, ret = 0;
+ Error *local_err = NULL;
+ gboolean rc = G_SOURCE_CONTINUE;
+ int ret = 0;
struct iovec iov;
- struct msghdr msgh;
- int fd[VHOST_USER_SLAVE_MAX_FDS];
- char control[CMSG_SPACE(sizeof(fd))];
- struct cmsghdr *cmsg;
- int i, fdsize = 0;
-
- memset(&msgh, 0, sizeof(msgh));
- msgh.msg_iov = &iov;
- msgh.msg_iovlen = 1;
- msgh.msg_control = control;
- msgh.msg_controllen = sizeof(control);
-
- memset(fd, -1, sizeof(fd));
+ g_autofree int *fd = NULL;
+ size_t fdsize = 0;
+ int i;
/* Read header */
iov.iov_base = &hdr;
iov.iov_len = VHOST_USER_HDR_SIZE;
- do {
- size = recvmsg(u->slave_fd, &msgh, 0);
- } while (size < 0 && (errno == EINTR || errno == EAGAIN));
-
- if (size != VHOST_USER_HDR_SIZE) {
- error_report("Failed to read from slave.");
+ if (qio_channel_readv_full_all(ioc, &iov, 1, &fd, &fdsize, &local_err)) {
+ error_report_err(local_err);
goto err;
}
- if (msgh.msg_flags & MSG_CTRUNC) {
- error_report("Truncated message.");
- goto err;
- }
-
- for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
- cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_RIGHTS) {
- fdsize = cmsg->cmsg_len - CMSG_LEN(0);
- memcpy(fd, CMSG_DATA(cmsg), fdsize);
- break;
- }
- }
-
if (hdr.size > VHOST_USER_PAYLOAD_SIZE) {
error_report("Failed to read msg header."
" Size %d exceeds the maximum %zu.", hdr.size,
@@ -1450,12 +1521,8 @@ static void slave_read(void *opaque)
}
/* Read payload */
- do {
- size = read(u->slave_fd, &payload, hdr.size);
- } while (size < 0 && (errno == EINTR || errno == EAGAIN));
-
- if (size != hdr.size) {
- error_report("Failed to read payload from slave.");
+ if (qio_channel_read_all(ioc, (char *) &payload, hdr.size, &local_err)) {
+ error_report_err(local_err);
goto err;
}
@@ -1468,20 +1535,13 @@ static void slave_read(void *opaque)
break;
case VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG:
ret = vhost_user_slave_handle_vring_host_notifier(dev, &payload.area,
- fd[0]);
+ fd ? fd[0] : -1);
break;
default:
error_report("Received unexpected msg type: %d.", hdr.request);
ret = -EINVAL;
}
- /* Close the remaining file descriptors. */
- for (i = 0; i < fdsize; i++) {
- if (fd[i] != -1) {
- close(fd[i]);
- }
- }
-
/*
* REPLY_ACK feature handling. Other reply types has to be managed
* directly in their request handlers.
@@ -1501,28 +1561,25 @@ static void slave_read(void *opaque)
iovec[1].iov_base = &payload;
iovec[1].iov_len = hdr.size;
- do {
- size = writev(u->slave_fd, iovec, ARRAY_SIZE(iovec));
- } while (size < 0 && (errno == EINTR || errno == EAGAIN));
-
- if (size != VHOST_USER_HDR_SIZE + hdr.size) {
- error_report("Failed to send msg reply to slave.");
+ if (qio_channel_writev_all(ioc, iovec, ARRAY_SIZE(iovec), &local_err)) {
+ error_report_err(local_err);
goto err;
}
}
- return;
+ goto fdcleanup;
err:
- qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL);
- close(u->slave_fd);
- u->slave_fd = -1;
- for (i = 0; i < fdsize; i++) {
- if (fd[i] != -1) {
+ close_slave_channel(u);
+ rc = G_SOURCE_REMOVE;
+
+fdcleanup:
+ if (fd) {
+ for (i = 0; i < fdsize; i++) {
close(fd[i]);
}
}
- return;
+ return rc;
}
static int vhost_setup_slave_channel(struct vhost_dev *dev)
@@ -1535,6 +1592,8 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev)
int sv[2], ret = 0;
bool reply_supported = virtio_has_feature(dev->protocol_features,
VHOST_USER_PROTOCOL_F_REPLY_ACK);
+ Error *local_err = NULL;
+ QIOChannel *ioc;
if (!virtio_has_feature(dev->protocol_features,
VHOST_USER_PROTOCOL_F_SLAVE_REQ)) {
@@ -1546,8 +1605,13 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev)
return -1;
}
- u->slave_fd = sv[0];
- qemu_set_fd_handler(u->slave_fd, slave_read, NULL, dev);
+ ioc = QIO_CHANNEL(qio_channel_socket_new_fd(sv[0], &local_err));
+ if (!ioc) {
+ error_report_err(local_err);
+ return -1;
+ }
+ u->slave_ioc = ioc;
+ slave_update_read_handler(dev, NULL);
if (reply_supported) {
msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK;
@@ -1565,9 +1629,7 @@ static int vhost_setup_slave_channel(struct vhost_dev *dev)
out:
close(sv[1]);
if (ret) {
- qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL);
- close(u->slave_fd);
- u->slave_fd = -1;
+ close_slave_channel(u);
}
return ret;
@@ -1804,7 +1866,6 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque)
u = g_new0(struct vhost_user, 1);
u->user = opaque;
- u->slave_fd = -1;
u->dev = dev;
dev->opaque = u;
@@ -1919,10 +1980,8 @@ static int vhost_user_backend_cleanup(struct vhost_dev *dev)
close(u->postcopy_fd.fd);
u->postcopy_fd.handler = NULL;
}
- if (u->slave_fd >= 0) {
- qemu_set_fd_handler(u->slave_fd, NULL, NULL, NULL);
- close(u->slave_fd);
- u->slave_fd = -1;
+ if (u->slave_ioc) {
+ close_slave_channel(u);
}
g_free(u->region_rb);
u->region_rb = NULL;
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 6990b9879c..342c918ea7 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -112,15 +112,28 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
if (offset >= VIRTIO_MMIO_CONFIG) {
offset -= VIRTIO_MMIO_CONFIG;
- switch (size) {
- case 1:
- return virtio_config_readb(vdev, offset);
- case 2:
- return virtio_config_readw(vdev, offset);
- case 4:
- return virtio_config_readl(vdev, offset);
- default:
- abort();
+ if (proxy->legacy) {
+ switch (size) {
+ case 1:
+ return virtio_config_readb(vdev, offset);
+ case 2:
+ return virtio_config_readw(vdev, offset);
+ case 4:
+ return virtio_config_readl(vdev, offset);
+ default:
+ abort();
+ }
+ } else {
+ switch (size) {
+ case 1:
+ return virtio_config_modern_readb(vdev, offset);
+ case 2:
+ return virtio_config_modern_readw(vdev, offset);
+ case 4:
+ return virtio_config_modern_readl(vdev, offset);
+ default:
+ abort();
+ }
}
}
if (size != 4) {
@@ -245,20 +258,37 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value,
if (offset >= VIRTIO_MMIO_CONFIG) {
offset -= VIRTIO_MMIO_CONFIG;
- switch (size) {
- case 1:
- virtio_config_writeb(vdev, offset, value);
- break;
- case 2:
- virtio_config_writew(vdev, offset, value);
- break;
- case 4:
- virtio_config_writel(vdev, offset, value);
- break;
- default:
- abort();
+ if (proxy->legacy) {
+ switch (size) {
+ case 1:
+ virtio_config_writeb(vdev, offset, value);
+ break;
+ case 2:
+ virtio_config_writew(vdev, offset, value);
+ break;
+ case 4:
+ virtio_config_writel(vdev, offset, value);
+ break;
+ default:
+ abort();
+ }
+ return;
+ } else {
+ switch (size) {
+ case 1:
+ virtio_config_modern_writeb(vdev, offset, value);
+ break;
+ case 2:
+ virtio_config_modern_writew(vdev, offset, value);
+ break;
+ case 4:
+ virtio_config_modern_writel(vdev, offset, value);
+ break;
+ default:
+ abort();
+ }
+ return;
}
- return;
}
if (size != 4) {
qemu_log_mask(LOG_GUEST_ERROR,
diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c
index a3e0688a89..d1aeb90a31 100644
--- a/hw/virtio/virtio-pmem.c
+++ b/hw/virtio/virtio-pmem.c
@@ -47,7 +47,7 @@ static int worker_cb(void *opaque)
err = 1;
}
- virtio_stw_p(req_data->vdev, &req_data->resp.ret, err);
+ virtio_stl_p(req_data->vdev, &req_data->resp.ret, err);
return 0;
}
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 380d3e3924..471266d739 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -4,9 +4,6 @@
#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/bios-linker-loader.h"
-/* Reserve RAM space for tables: add another order of magnitude. */
-#define ACPI_BUILD_TABLE_MAX_SIZE 0x200000
-
#define ACPI_BUILD_APPNAME6 "BOCHS "
#define ACPI_BUILD_APPNAME8 "BXPC "
@@ -301,6 +298,7 @@ Aml *aml_arg(int pos);
Aml *aml_to_integer(Aml *arg);
Aml *aml_to_hexstring(Aml *src, Aml *dst);
Aml *aml_to_buffer(Aml *src, Aml *dst);
+Aml *aml_to_decimalstring(Aml *src, Aml *dst);
Aml *aml_store(Aml *val, Aml *target);
Aml *aml_and(Aml *arg1, Aml *arg2, Aml *dst);
Aml *aml_or(Aml *arg1, Aml *arg2, Aml *dst);
@@ -323,6 +321,8 @@ Aml *aml_call3(const char *method, Aml *arg1, Aml *arg2, Aml *arg3);
Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4);
Aml *aml_call5(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4,
Aml *arg5);
+Aml *aml_call6(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4,
+ Aml *arg5, Aml *arg6);
Aml *aml_gpio_int(AmlConsumerAndProducer con_and_pro,
AmlLevelAndEdge edge_level,
AmlActiveHighAndLow active_level, AmlShared shared,
diff --git a/include/hw/acpi/pci.h b/include/hw/acpi/pci.h
index e514f179d8..b5deee0a9d 100644
--- a/include/hw/acpi/pci.h
+++ b/include/hw/acpi/pci.h
@@ -35,4 +35,5 @@ typedef struct AcpiMcfgInfo {
void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info,
const char *oem_id, const char *oem_table_id);
+Aml *aml_pci_device_dsm(void);
#endif
diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h
index dfd375820f..2dd90aea30 100644
--- a/include/hw/acpi/pcihp.h
+++ b/include/hw/acpi/pcihp.h
@@ -46,6 +46,7 @@ typedef struct AcpiPciHpPciStatus {
typedef struct AcpiPciHpState {
AcpiPciHpPciStatus acpi_pcihp_pci_status[ACPI_PCIHP_MAX_HOTPLUG_BUS];
uint32_t hotplug_select;
+ uint32_t acpi_index;
PCIBus *root;
MemoryRegion io;
bool legacy_piix;
@@ -71,13 +72,17 @@ void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off);
extern const VMStateDescription vmstate_acpi_pcihp_pci_status;
-#define VMSTATE_PCI_HOTPLUG(pcihp, state, test_pcihp) \
+bool vmstate_acpi_pcihp_use_acpi_index(void *opaque, int version_id);
+
+#define VMSTATE_PCI_HOTPLUG(pcihp, state, test_pcihp, test_acpi_index) \
VMSTATE_UINT32_TEST(pcihp.hotplug_select, state, \
test_pcihp), \
VMSTATE_STRUCT_ARRAY_TEST(pcihp.acpi_pcihp_pci_status, state, \
ACPI_PCIHP_MAX_HOTPLUG_BUS, \
test_pcihp, 1, \
vmstate_acpi_pcihp_pci_status, \
- AcpiPciHpPciStatus)
+ AcpiPciHpPciStatus), \
+ VMSTATE_UINT32_TEST(pcihp.acpi_index, state, \
+ test_acpi_index)
#endif
diff --git a/include/hw/acpi/utils.h b/include/hw/acpi/utils.h
index 140b4de603..0022df027d 100644
--- a/include/hw/acpi/utils.h
+++ b/include/hw/acpi/utils.h
@@ -4,6 +4,5 @@
#include "hw/nvram/fw_cfg.h"
MemoryRegion *acpi_add_rom_blob(FWCfgCallback update, void *opaque,
- GArray *blob, const char *name,
- uint64_t max_size);
+ GArray *blob, const char *name);
#endif
diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h
index 03d19e3f6f..546f958eb8 100644
--- a/include/hw/char/ibex_uart.h
+++ b/include/hw/char/ibex_uart.h
@@ -62,6 +62,8 @@ REG32(FIFO_CTRL, 0x1c)
FIELD(FIFO_CTRL, RXILVL, 2, 3)
FIELD(FIFO_CTRL, TXILVL, 5, 2)
REG32(FIFO_STATUS, 0x20)
+ FIELD(FIFO_STATUS, TXLVL, 0, 5)
+ FIELD(FIFO_STATUS, RXLVL, 16, 5)
REG32(OVRD, 0x24)
REG32(VAL, 0x28)
REG32(TIMEOUT_CTRL, 0x2c)
@@ -82,6 +84,8 @@ struct IbexUartState {
uint8_t tx_fifo[IBEX_UART_TX_FIFO_SIZE];
uint32_t tx_level;
+ uint32_t rx_level;
+
QEMUTimer *fifo_trigger_handle;
uint64_t char_tx_time;
diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h
index 372b05774e..f25f837441 100644
--- a/include/hw/i386/microvm.h
+++ b/include/hw/i386/microvm.h
@@ -76,8 +76,6 @@
#define MICROVM_MACHINE_ISA_SERIAL "isa-serial"
#define MICROVM_MACHINE_OPTION_ROMS "x-option-roms"
#define MICROVM_MACHINE_AUTO_KERNEL_CMDLINE "auto-kernel-cmdline"
-#define MICROVM_MACHINE_OEM_ID "oem-id"
-#define MICROVM_MACHINE_OEM_TABLE_ID "oem-table-id"
struct MicrovmMachineClass {
X86MachineClass parent;
@@ -106,8 +104,6 @@ struct MicrovmMachineState {
Notifier machine_done;
Notifier powerdown_req;
struct GPEXConfig gpex;
- char *oem_id;
- char *oem_table_id;
};
#define TYPE_MICROVM_MACHINE MACHINE_TYPE_NAME("microvm")
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index d4c3d73c11..dcf060b791 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -46,8 +46,6 @@ typedef struct PCMachineState {
bool pit_enabled;
bool hpet_enabled;
uint64_t max_fw_size;
- char *oem_id;
- char *oem_table_id;
/* NUMA information: */
uint64_t numa_nodes;
@@ -65,8 +63,6 @@ typedef struct PCMachineState {
#define PC_MACHINE_SATA "sata"
#define PC_MACHINE_PIT "pit"
#define PC_MACHINE_MAX_FW_SIZE "max-fw-size"
-#define PC_MACHINE_OEM_ID "oem-id"
-#define PC_MACHINE_OEM_TABLE_ID "oem-table-id"
/**
* PCMachineClass:
*
diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
index 56080bd1fb..26c9cc45a4 100644
--- a/include/hw/i386/x86.h
+++ b/include/hw/i386/x86.h
@@ -67,6 +67,8 @@ struct X86MachineState {
OnOffAuto smm;
OnOffAuto acpi;
+ char *oem_id;
+ char *oem_table_id;
/*
* Address space used by IOAPIC device. All IOAPIC interrupts
* will be translated to MSI messages in the address space.
@@ -76,6 +78,8 @@ struct X86MachineState {
#define X86_MACHINE_SMM "smm"
#define X86_MACHINE_ACPI "acpi"
+#define X86_MACHINE_OEM_ID "oem-id"
+#define X86_MACHINE_OEM_TABLE_ID "oem-table-id"
#define TYPE_X86_MACHINE MACHINE_TYPE_NAME("x86")
OBJECT_DECLARE_TYPE(X86MachineState, X86MachineClass, X86_MACHINE)
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 1bc231480f..6be4e0c460 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -359,6 +359,7 @@ struct PCIDevice {
/* ID of standby device in net_failover pair */
char *failover_pair_id;
+ uint32_t acpi_index;
};
void pci_register_bar(PCIDevice *pci_dev, int region_num,
diff --git a/include/hw/riscv/microchip_pfsoc.h b/include/hw/riscv/microchip_pfsoc.h
index d0c666aae0..d30916f45d 100644
--- a/include/hw/riscv/microchip_pfsoc.h
+++ b/include/hw/riscv/microchip_pfsoc.h
@@ -109,6 +109,7 @@ enum {
MICROCHIP_PFSOC_ENVM_DATA,
MICROCHIP_PFSOC_QSPI_XIP,
MICROCHIP_PFSOC_IOSCB,
+ MICROCHIP_PFSOC_EMMC_SD_MUX,
MICROCHIP_PFSOC_DRAM_LO,
MICROCHIP_PFSOC_DRAM_LO_ALIAS,
MICROCHIP_PFSOC_DRAM_HI,
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 632da52018..349fee1f89 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -40,6 +40,7 @@ struct RISCVVirtState {
RISCVHartArrayState soc[VIRT_SOCKETS_MAX];
DeviceState *plic[VIRT_SOCKETS_MAX];
PFlashCFI01 *flash[2];
+ FWCfgState *fw_cfg;
int fdt_size;
};
@@ -53,6 +54,7 @@ enum {
VIRT_PLIC,
VIRT_UART0,
VIRT_VIRTIO,
+ VIRT_FW_CFG,
VIRT_FLASH,
VIRT_DRAM,
VIRT_PCIE_MMIO,
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 2a990f6253..7d6ed80f6b 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -356,6 +356,7 @@ static void riscv_cpu_reset(DeviceState *dev)
env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
env->mcause = 0;
env->pc = env->resetvec;
+ env->two_stage_lookup = false;
#endif
cs->exception_index = EXCP_NONE;
env->load_res = -1;
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0edb2826a2..0a33d387ba 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -213,6 +213,10 @@ struct CPURISCVState {
target_ulong satp_hs;
uint64_t mstatus_hs;
+ /* Signals whether the current exception occurred with two-stage address
+ translation active. */
+ bool two_stage_lookup;
+
target_ulong scounteren;
target_ulong mcounteren;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 83a6bcfad0..21c54ef561 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -280,6 +280,49 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
env->load_res = -1;
}
+/*
+ * get_physical_address_pmp - check PMP permission for this physical address
+ *
+ * Match the PMP region and check permission for this physical address and it's
+ * TLB page. Returns 0 if the permission checking was successful
+ *
+ * @env: CPURISCVState
+ * @prot: The returned protection attributes
+ * @tlb_size: TLB page size containing addr. It could be modified after PMP
+ * permission checking. NULL if not set TLB page for addr.
+ * @addr: The physical address to be checked permission
+ * @access_type: The type of MMU access
+ * @mode: Indicates current privilege level.
+ */
+static int get_physical_address_pmp(CPURISCVState *env, int *prot,
+ target_ulong *tlb_size, hwaddr addr,
+ int size, MMUAccessType access_type,
+ int mode)
+{
+ pmp_priv_t pmp_priv;
+ target_ulong tlb_size_pmp = 0;
+
+ if (!riscv_feature(env, RISCV_FEATURE_PMP)) {
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return TRANSLATE_SUCCESS;
+ }
+
+ if (!pmp_hart_has_privs(env, addr, size, 1 << access_type, &pmp_priv,
+ mode)) {
+ *prot = 0;
+ return TRANSLATE_PMP_FAIL;
+ }
+
+ *prot = pmp_priv_to_page_prot(pmp_priv);
+ if (tlb_size != NULL) {
+ if (pmp_is_range_in_tlb(env, addr & ~(*tlb_size - 1), &tlb_size_pmp)) {
+ *tlb_size = tlb_size_pmp;
+ }
+ }
+
+ return TRANSLATE_SUCCESS;
+}
+
/* get_physical_address - get the physical address for this virtual address
*
* Do a page table walk to obtain the physical address corresponding to a
@@ -321,11 +364,15 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
* was called. Background registers will be used if the guest has
* forced a two stage translation to be on (in HS or M mode).
*/
- if (!riscv_cpu_virt_enabled(env) && riscv_cpu_two_stage_lookup(mmu_idx)) {
+ if (!riscv_cpu_virt_enabled(env) && two_stage) {
use_background = true;
}
- if (mode == PRV_M && access_type != MMU_INST_FETCH) {
+ /* MPRV does not affect the virtual-machine load/store
+ instructions, HLV, HLVX, and HSV. */
+ if (riscv_cpu_two_stage_lookup(mmu_idx)) {
+ mode = get_field(env->hstatus, HSTATUS_SPVP);
+ } else if (mode == PRV_M && access_type != MMU_INST_FETCH) {
if (get_field(env->mstatus, MSTATUS_MPRV)) {
mode = get_field(env->mstatus, MSTATUS_MPP);
}
@@ -442,9 +489,11 @@ restart:
pte_addr = base + idx * ptesize;
}
- if (riscv_feature(env, RISCV_FEATURE_PMP) &&
- !pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong),
- 1 << MMU_DATA_LOAD, PRV_S)) {
+ int pmp_prot;
+ int pmp_ret = get_physical_address_pmp(env, &pmp_prot, NULL, pte_addr,
+ sizeof(target_ulong),
+ MMU_DATA_LOAD, PRV_S);
+ if (pmp_ret != TRANSLATE_SUCCESS) {
return TRANSLATE_PMP_FAIL;
}
@@ -605,6 +654,7 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
g_assert_not_reached();
}
env->badaddr = address;
+ env->two_stage_lookup = two_stage;
}
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
@@ -646,6 +696,8 @@ void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
}
env->badaddr = addr;
+ env->two_stage_lookup = riscv_cpu_virt_enabled(env) ||
+ riscv_cpu_two_stage_lookup(mmu_idx);
riscv_raise_exception(&cpu->env, cs->exception_index, retaddr);
}
@@ -669,6 +721,8 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
g_assert_not_reached();
}
env->badaddr = addr;
+ env->two_stage_lookup = riscv_cpu_virt_enabled(env) ||
+ riscv_cpu_two_stage_lookup(mmu_idx);
riscv_raise_exception(env, cs->exception_index, retaddr);
}
#endif /* !CONFIG_USER_ONLY */
@@ -682,32 +736,32 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
#ifndef CONFIG_USER_ONLY
vaddr im_address;
hwaddr pa = 0;
- int prot, prot2;
+ int prot, prot2, prot_pmp;
bool pmp_violation = false;
bool first_stage_error = true;
bool two_stage_lookup = false;
int ret = TRANSLATE_FAIL;
int mode = mmu_idx;
- target_ulong tlb_size = 0;
+ /* default TLB page size */
+ target_ulong tlb_size = TARGET_PAGE_SIZE;
env->guest_phys_fault_addr = 0;
qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
__func__, address, access_type, mmu_idx);
- if (mode == PRV_M && access_type != MMU_INST_FETCH) {
- if (get_field(env->mstatus, MSTATUS_MPRV)) {
- mode = get_field(env->mstatus, MSTATUS_MPP);
+ /* MPRV does not affect the virtual-machine load/store
+ instructions, HLV, HLVX, and HSV. */
+ if (riscv_cpu_two_stage_lookup(mmu_idx)) {
+ mode = get_field(env->hstatus, HSTATUS_SPVP);
+ } else if (mode == PRV_M && access_type != MMU_INST_FETCH &&
+ get_field(env->mstatus, MSTATUS_MPRV)) {
+ mode = get_field(env->mstatus, MSTATUS_MPP);
+ if (riscv_has_ext(env, RVH) && get_field(env->mstatus, MSTATUS_MPV)) {
+ two_stage_lookup = true;
}
}
- if (riscv_has_ext(env, RVH) && env->priv == PRV_M &&
- access_type != MMU_INST_FETCH &&
- get_field(env->mstatus, MSTATUS_MPRV) &&
- get_field(env->mstatus, MSTATUS_MPV)) {
- two_stage_lookup = true;
- }
-
if (riscv_cpu_virt_enabled(env) ||
((riscv_cpu_two_stage_lookup(mmu_idx) || two_stage_lookup) &&
access_type != MMU_INST_FETCH)) {
@@ -745,10 +799,16 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
prot &= prot2;
- if (riscv_feature(env, RISCV_FEATURE_PMP) &&
- (ret == TRANSLATE_SUCCESS) &&
- !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
- ret = TRANSLATE_PMP_FAIL;
+ if (ret == TRANSLATE_SUCCESS) {
+ ret = get_physical_address_pmp(env, &prot_pmp, &tlb_size, pa,
+ size, access_type, mode);
+
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s PMP address=" TARGET_FMT_plx " ret %d prot"
+ " %d tlb_size " TARGET_FMT_lu "\n",
+ __func__, pa, ret, prot_pmp, tlb_size);
+
+ prot &= prot_pmp;
}
if (ret != TRANSLATE_SUCCESS) {
@@ -771,25 +831,27 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
"%s address=%" VADDR_PRIx " ret %d physical "
TARGET_FMT_plx " prot %d\n",
__func__, address, ret, pa, prot);
- }
- if (riscv_feature(env, RISCV_FEATURE_PMP) &&
- (ret == TRANSLATE_SUCCESS) &&
- !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
- ret = TRANSLATE_PMP_FAIL;
+ if (ret == TRANSLATE_SUCCESS) {
+ ret = get_physical_address_pmp(env, &prot_pmp, &tlb_size, pa,
+ size, access_type, mode);
+
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s PMP address=" TARGET_FMT_plx " ret %d prot"
+ " %d tlb_size " TARGET_FMT_lu "\n",
+ __func__, pa, ret, prot_pmp, tlb_size);
+
+ prot &= prot_pmp;
+ }
}
+
if (ret == TRANSLATE_PMP_FAIL) {
pmp_violation = true;
}
if (ret == TRANSLATE_SUCCESS) {
- if (pmp_is_range_in_tlb(env, pa & TARGET_PAGE_MASK, &tlb_size)) {
- tlb_set_page(cs, address & ~(tlb_size - 1), pa & ~(tlb_size - 1),
- prot, mmu_idx, tlb_size);
- } else {
- tlb_set_page(cs, address & TARGET_PAGE_MASK, pa & TARGET_PAGE_MASK,
- prot, mmu_idx, TARGET_PAGE_SIZE);
- }
+ tlb_set_page(cs, address & ~(tlb_size - 1), pa & ~(tlb_size - 1),
+ prot, mmu_idx, tlb_size);
return true;
} else if (probe) {
return false;
@@ -910,16 +972,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
/* handle the trap in S-mode */
if (riscv_has_ext(env, RVH)) {
target_ulong hdeleg = async ? env->hideleg : env->hedeleg;
- bool two_stage_lookup = false;
-
- if (env->priv == PRV_M ||
- (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
- (env->priv == PRV_U && !riscv_cpu_virt_enabled(env) &&
- get_field(env->hstatus, HSTATUS_HU))) {
- two_stage_lookup = true;
- }
- if ((riscv_cpu_virt_enabled(env) || two_stage_lookup) && write_tval) {
+ if (env->two_stage_lookup && write_tval) {
/*
* If we are writing a guest virtual address to stval, set
* this to 1. If we are trapping to VS we will set this to 0
@@ -957,10 +1011,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
riscv_cpu_set_force_hs_excep(env, 0);
} else {
/* Trap into HS mode */
- if (!two_stage_lookup) {
- env->hstatus = set_field(env->hstatus, HSTATUS_SPV,
- riscv_cpu_virt_enabled(env));
- }
+ env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
htval = env->guest_phys_fault_addr;
}
}
@@ -1016,6 +1067,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
* RISC-V ISA Specification.
*/
+ env->two_stage_lookup = false;
#endif
cs->exception_index = EXCP_NONE; /* mark handled to qemu */
}
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index fd2e6363f3..d2585395bf 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -54,7 +54,7 @@ static int vs(CPURISCVState *env, int csrno)
if (env->misa & RVV) {
return 0;
}
- return -1;
+ return -RISCV_EXCP_ILLEGAL_INST;
}
static int ctr(CPURISCVState *env, int csrno)
@@ -420,7 +420,8 @@ static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
-static const target_ulong hip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
+static const target_ulong hip_writable_mask = MIP_VSSIP;
+static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
static const target_ulong vsip_writable_mask = MIP_VSSIP;
static const char valid_vm_1_10_32[16] = {
@@ -748,30 +749,42 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
return write_mstatus(env, CSR_MSTATUS, newval);
}
+static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ /* Shift the VS bits to their S bit location in vsie */
+ *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
+ return 0;
+}
+
static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
{
if (riscv_cpu_virt_enabled(env)) {
- /* Tell the guest the VS bits, shifted to the S bit locations */
- *val = (env->mie & env->mideleg & VS_MODE_INTERRUPTS) >> 1;
+ read_vsie(env, CSR_VSIE, val);
} else {
*val = env->mie & env->mideleg;
}
return 0;
}
-static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
+static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
{
- target_ulong newval;
+ /* Shift the S bits to their VS bit location in mie */
+ target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
+ ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS);
+ return write_mie(env, CSR_MIE, newval);
+}
+static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
+{
if (riscv_cpu_virt_enabled(env)) {
- /* Shift the guests S bits to VS */
- newval = (env->mie & ~VS_MODE_INTERRUPTS) |
- ((val << 1) & VS_MODE_INTERRUPTS);
+ write_vsie(env, CSR_VSIE, val);
} else {
- newval = (env->mie & ~S_MODE_INTERRUPTS) | (val & S_MODE_INTERRUPTS);
+ target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) |
+ (val & S_MODE_INTERRUPTS);
+ write_mie(env, CSR_MIE, newval);
}
- return write_mie(env, CSR_MIE, newval);
+ return 0;
}
static int read_stvec(CPURISCVState *env, int csrno, target_ulong *val)
@@ -852,17 +865,25 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
return 0;
}
+static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
+ target_ulong new_value, target_ulong write_mask)
+{
+ /* Shift the S bits to their VS bit location in mip */
+ int ret = rmw_mip(env, 0, ret_value, new_value << 1,
+ (write_mask << 1) & vsip_writable_mask & env->hideleg);
+ *ret_value &= VS_MODE_INTERRUPTS;
+ /* Shift the VS bits to their S bit location in vsip */
+ *ret_value >>= 1;
+ return ret;
+}
+
static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
target_ulong new_value, target_ulong write_mask)
{
int ret;
if (riscv_cpu_virt_enabled(env)) {
- /* Shift the new values to line up with the VS bits */
- ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value << 1,
- (write_mask & sip_writable_mask) << 1 & env->mideleg);
- ret &= vsip_writable_mask;
- ret >>= 1;
+ ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
} else {
ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
write_mask & env->mideleg & sip_writable_mask);
@@ -962,9 +983,9 @@ static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
target_ulong new_value, target_ulong write_mask)
{
int ret = rmw_mip(env, 0, ret_value, new_value,
- write_mask & hip_writable_mask);
+ write_mask & hvip_writable_mask);
- *ret_value &= hip_writable_mask;
+ *ret_value &= hvip_writable_mask;
return ret;
}
@@ -1121,26 +1142,6 @@ static int write_vsstatus(CPURISCVState *env, int csrno, target_ulong val)
return 0;
}
-static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
- target_ulong new_value, target_ulong write_mask)
-{
- int ret = rmw_mip(env, 0, ret_value, new_value,
- write_mask & env->mideleg & vsip_writable_mask);
- return ret;
-}
-
-static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
-{
- *val = env->mie & env->mideleg & VS_MODE_INTERRUPTS;
- return 0;
-}
-
-static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
-{
- target_ulong newval = (env->mie & ~env->mideleg) | (val & env->mideleg & MIP_VSSIP);
- return write_mie(env, CSR_MIE, newval);
-}
-
static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val)
{
*val = env->vstvec;
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 80d0334e1b..cff020122a 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -28,6 +28,7 @@
#include "qapi/error.h"
#include "cpu.h"
#include "trace.h"
+#include "exec/exec-all.h"
static void pmp_write_cfg(CPURISCVState *env, uint32_t addr_index,
uint8_t val);
@@ -217,6 +218,35 @@ static int pmp_is_in_range(CPURISCVState *env, int pmp_index, target_ulong addr)
return result;
}
+/*
+ * Check if the address has required RWX privs when no PMP entry is matched.
+ */
+static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr,
+ target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
+ target_ulong mode)
+{
+ bool ret;
+
+ if ((!riscv_feature(env, RISCV_FEATURE_PMP)) || (mode == PRV_M)) {
+ /*
+ * Privileged spec v1.10 states if HW doesn't implement any PMP entry
+ * or no PMP entry matches an M-Mode access, the access succeeds.
+ */
+ ret = true;
+ *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
+ } else {
+ /*
+ * Other modes are not allowed to succeed if they don't * match a rule,
+ * but there are rules. We've checked for no rule earlier in this
+ * function.
+ */
+ ret = false;
+ *allowed_privs = 0;
+ }
+
+ return ret;
+}
+
/*
* Public Interface
@@ -226,18 +256,19 @@ static int pmp_is_in_range(CPURISCVState *env, int pmp_index, target_ulong addr)
* Check if the address has required RWX privs to complete desired operation
*/
bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
- target_ulong size, pmp_priv_t privs, target_ulong mode)
+ target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
+ target_ulong mode)
{
int i = 0;
int ret = -1;
int pmp_size = 0;
target_ulong s = 0;
target_ulong e = 0;
- pmp_priv_t allowed_privs = 0;
/* Short cut if no rules */
if (0 == pmp_get_num_rules(env)) {
- return (env->priv == PRV_M) ? true : false;
+ return pmp_hart_has_privs_default(env, addr, size, privs,
+ allowed_privs, mode);
}
if (size == 0) {
@@ -277,37 +308,25 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
* check
*/
if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
- allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
+ *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
if ((mode != PRV_M) || pmp_is_locked(env, i)) {
- allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
+ *allowed_privs &= env->pmp_state.pmp[i].cfg_reg;
}
- if ((privs & allowed_privs) == privs) {
- ret = 1;
- break;
- } else {
- ret = 0;
- break;
- }
+ ret = ((privs & *allowed_privs) == privs);
+ break;
}
}
/* No rule matched */
if (ret == -1) {
- if (mode == PRV_M) {
- ret = 1; /* Privileged spec v1.10 states if no PMP entry matches an
- * M-Mode access, the access succeeds */
- } else {
- ret = 0; /* Other modes are not allowed to succeed if they don't
- * match a rule, but there are rules. We've checked for
- * no rule earlier in this function. */
- }
+ return pmp_hart_has_privs_default(env, addr, size, privs,
+ allowed_privs, mode);
}
return ret == 1 ? true : false;
}
-
/*
* Handle a write to a pmpcfg CSP
*/
@@ -329,6 +348,9 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
cfg_val = (val >> 8 * i) & 0xff;
pmp_write_cfg(env, (reg_index * 4) + i, cfg_val);
}
+
+ /* If PMP permission of any addr has been changed, flush TLB pages. */
+ tlb_flush(env_cpu(env));
}
@@ -442,3 +464,23 @@ bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa,
return false;
}
+
+/*
+ * Convert PMP privilege to TLB page privilege.
+ */
+int pmp_priv_to_page_prot(pmp_priv_t pmp_priv)
+{
+ int prot = 0;
+
+ if (pmp_priv & PMP_READ) {
+ prot |= PAGE_READ;
+ }
+ if (pmp_priv & PMP_WRITE) {
+ prot |= PAGE_WRITE;
+ }
+ if (pmp_priv & PMP_EXEC) {
+ prot |= PAGE_EXEC;
+ }
+
+ return prot;
+}
diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
index c8d5ef4a69..b82a30f0d5 100644
--- a/target/riscv/pmp.h
+++ b/target/riscv/pmp.h
@@ -59,11 +59,13 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
target_ulong val);
target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index);
bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr,
- target_ulong size, pmp_priv_t priv, target_ulong mode);
+ target_ulong size, pmp_priv_t privs, pmp_priv_t *allowed_privs,
+ target_ulong mode);
bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa,
target_ulong *tlb_size);
void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index);
void pmp_update_rule_nums(CPURISCVState *env);
uint32_t pmp_get_num_rules(CPURISCVState *env);
+int pmp_priv_to_page_prot(pmp_priv_t pmp_priv);
#endif
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 0f28b5f41e..2f9f5ccc62 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -68,20 +68,6 @@ typedef struct DisasContext {
} DisasContext;
#ifdef TARGET_RISCV64
-/* convert riscv funct3 to qemu memop for load/store */
-static const int tcg_memop_lookup[8] = {
- [0 ... 7] = -1,
- [0] = MO_SB,
- [1] = MO_TESW,
- [2] = MO_TESL,
- [3] = MO_TEQ,
- [4] = MO_UB,
- [5] = MO_TEUW,
- [6] = MO_TEUL,
-};
-#endif
-
-#ifdef TARGET_RISCV64
#define CASE_OP_32_64(X) case X: case glue(X, W)
#else
#define CASE_OP_32_64(X) case X
@@ -374,48 +360,6 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
ctx->base.is_jmp = DISAS_NORETURN;
}
-#ifdef TARGET_RISCV64
-static void gen_load_c(DisasContext *ctx, uint32_t opc, int rd, int rs1,
- target_long imm)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- gen_get_gpr(t0, rs1);
- tcg_gen_addi_tl(t0, t0, imm);
- int memop = tcg_memop_lookup[(opc >> 12) & 0x7];
-
- if (memop < 0) {
- gen_exception_illegal(ctx);
- return;
- }
-
- tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, memop);
- gen_set_gpr(rd, t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
-}
-
-static void gen_store_c(DisasContext *ctx, uint32_t opc, int rs1, int rs2,
- target_long imm)
-{
- TCGv t0 = tcg_temp_new();
- TCGv dat = tcg_temp_new();
- gen_get_gpr(t0, rs1);
- tcg_gen_addi_tl(t0, t0, imm);
- gen_get_gpr(dat, rs2);
- int memop = tcg_memop_lookup[(opc >> 12) & 0x7];
-
- if (memop < 0) {
- gen_exception_illegal(ctx);
- return;
- }
-
- tcg_gen_qemu_st_tl(dat, t0, ctx->mem_idx, memop);
- tcg_temp_free(t0);
- tcg_temp_free(dat);
-}
-#endif
-
#ifndef CONFIG_USER_ONLY
/* The states of mstatus_fs are:
* 0 = disabled, 1 = initial, 2 = clean, 3 = dirty
@@ -447,83 +391,6 @@ static void mark_fs_dirty(DisasContext *ctx)
static inline void mark_fs_dirty(DisasContext *ctx) { }
#endif
-#if !defined(TARGET_RISCV64)
-static void gen_fp_load(DisasContext *ctx, uint32_t opc, int rd,
- int rs1, target_long imm)
-{
- TCGv t0;
-
- if (ctx->mstatus_fs == 0) {
- gen_exception_illegal(ctx);
- return;
- }
-
- t0 = tcg_temp_new();
- gen_get_gpr(t0, rs1);
- tcg_gen_addi_tl(t0, t0, imm);
-
- switch (opc) {
- case OPC_RISC_FLW:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- tcg_gen_qemu_ld_i64(cpu_fpr[rd], t0, ctx->mem_idx, MO_TEUL);
- /* RISC-V requires NaN-boxing of narrower width floating point values */
- tcg_gen_ori_i64(cpu_fpr[rd], cpu_fpr[rd], 0xffffffff00000000ULL);
- break;
- case OPC_RISC_FLD:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- tcg_gen_qemu_ld_i64(cpu_fpr[rd], t0, ctx->mem_idx, MO_TEQ);
- break;
- do_illegal:
- default:
- gen_exception_illegal(ctx);
- break;
- }
- tcg_temp_free(t0);
-
- mark_fs_dirty(ctx);
-}
-
-static void gen_fp_store(DisasContext *ctx, uint32_t opc, int rs1,
- int rs2, target_long imm)
-{
- TCGv t0;
-
- if (ctx->mstatus_fs == 0) {
- gen_exception_illegal(ctx);
- return;
- }
-
- t0 = tcg_temp_new();
- gen_get_gpr(t0, rs1);
- tcg_gen_addi_tl(t0, t0, imm);
-
- switch (opc) {
- case OPC_RISC_FSW:
- if (!has_ext(ctx, RVF)) {
- goto do_illegal;
- }
- tcg_gen_qemu_st_i64(cpu_fpr[rs2], t0, ctx->mem_idx, MO_TEUL);
- break;
- case OPC_RISC_FSD:
- if (!has_ext(ctx, RVD)) {
- goto do_illegal;
- }
- tcg_gen_qemu_st_i64(cpu_fpr[rs2], t0, ctx->mem_idx, MO_TEQ);
- break;
- do_illegal:
- default:
- gen_exception_illegal(ctx);
- break;
- }
-
- tcg_temp_free(t0);
-}
-#endif
-
static void gen_set_rm(DisasContext *ctx, int rm)
{
TCGv_i32 t0;
@@ -537,49 +404,6 @@ static void gen_set_rm(DisasContext *ctx, int rm)
tcg_temp_free_i32(t0);
}
-static void decode_RV32_64C0(DisasContext *ctx, uint16_t opcode)
-{
- uint8_t funct3 = extract16(opcode, 13, 3);
- uint8_t rd_rs2 = GET_C_RS2S(opcode);
- uint8_t rs1s = GET_C_RS1S(opcode);
-
- switch (funct3) {
- case 3:
-#if defined(TARGET_RISCV64)
- /* C.LD(RV64/128) -> ld rd', offset[7:3](rs1')*/
- gen_load_c(ctx, OPC_RISC_LD, rd_rs2, rs1s,
- GET_C_LD_IMM(opcode));
-#else
- /* C.FLW (RV32) -> flw rd', offset[6:2](rs1')*/
- gen_fp_load(ctx, OPC_RISC_FLW, rd_rs2, rs1s,
- GET_C_LW_IMM(opcode));
-#endif
- break;
- case 7:
-#if defined(TARGET_RISCV64)
- /* C.SD (RV64/128) -> sd rs2', offset[7:3](rs1')*/
- gen_store_c(ctx, OPC_RISC_SD, rs1s, rd_rs2,
- GET_C_LD_IMM(opcode));
-#else
- /* C.FSW (RV32) -> fsw rs2', offset[6:2](rs1')*/
- gen_fp_store(ctx, OPC_RISC_FSW, rs1s, rd_rs2,
- GET_C_LW_IMM(opcode));
-#endif
- break;
- }
-}
-
-static void decode_RV32_64C(DisasContext *ctx, uint16_t opcode)
-{
- uint8_t op = extract16(opcode, 0, 2);
-
- switch (op) {
- case 0:
- decode_RV32_64C0(ctx, opcode);
- break;
- }
-}
-
static int ex_plus_1(DisasContext *ctx, int nf)
{
return nf + 1;
@@ -779,8 +603,7 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
} else {
ctx->pc_succ_insn = ctx->base.pc_next + 2;
if (!decode_insn16(ctx, opcode)) {
- /* fall back to old decoder */
- decode_RV32_64C(ctx, opcode);
+ gen_exception_illegal(ctx);
}
}
} else {
diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT
index 11ef89bd32..b9dd9b38e4 100644
--- a/tests/data/acpi/pc/DSDT
+++ b/tests/data/acpi/pc/DSDT
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.acpihmat b/tests/data/acpi/pc/DSDT.acpihmat
index c561e91be7..cba5a1dcb0 100644
--- a/tests/data/acpi/pc/DSDT.acpihmat
+++ b/tests/data/acpi/pc/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge
index a234075518..a9b4d56594 100644
--- a/tests/data/acpi/pc/DSDT.bridge
+++ b/tests/data/acpi/pc/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp
index 6ac47a7d10..8d86155e27 100644
--- a/tests/data/acpi/pc/DSDT.cphp
+++ b/tests/data/acpi/pc/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm
index d24377279c..e00a447f92 100644
--- a/tests/data/acpi/pc/DSDT.dimmpxm
+++ b/tests/data/acpi/pc/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.hpbridge b/tests/data/acpi/pc/DSDT.hpbridge
index 9dfac45eab..5d8ba19505 100644
--- a/tests/data/acpi/pc/DSDT.hpbridge
+++ b/tests/data/acpi/pc/DSDT.hpbridge
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.ipmikcs b/tests/data/acpi/pc/DSDT.ipmikcs
index 1814f291b7..01e53bd436 100644
--- a/tests/data/acpi/pc/DSDT.ipmikcs
+++ b/tests/data/acpi/pc/DSDT.ipmikcs
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp
index 3c81339d39..b8103799b4 100644
--- a/tests/data/acpi/pc/DSDT.memhp
+++ b/tests/data/acpi/pc/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.nohpet b/tests/data/acpi/pc/DSDT.nohpet
index d7d21be070..d4f0050533 100644
--- a/tests/data/acpi/pc/DSDT.nohpet
+++ b/tests/data/acpi/pc/DSDT.nohpet
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.numamem b/tests/data/acpi/pc/DSDT.numamem
index 195f8da900..8632dfe8a8 100644
--- a/tests/data/acpi/pc/DSDT.numamem
+++ b/tests/data/acpi/pc/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.roothp b/tests/data/acpi/pc/DSDT.roothp
index 1d0a2c2f3c..cee3b4d80b 100644
--- a/tests/data/acpi/pc/DSDT.roothp
+++ b/tests/data/acpi/pc/DSDT.roothp
Binary files differ