aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS6
-rw-r--r--Makefile2
-rw-r--r--accel/kvm/kvm-all.c13
-rw-r--r--block/blkdebug.c3
-rw-r--r--chardev/char-socket.c13
-rw-r--r--chardev/char.c3
-rw-r--r--docs/system/arm/mps2.rst24
-rw-r--r--docs/system/arm/nuvoton.rst3
-rw-r--r--docs/system/deprecated.rst13
-rw-r--r--gdbstub.c2
-rw-r--r--hw/arm/mps2-tz.c642
-rw-r--r--hw/arm/mps2.c5
-rw-r--r--hw/arm/musicpal.c64
-rw-r--r--hw/arm/npcm7xx.c50
-rw-r--r--hw/arm/sbsa-ref.c2
-rw-r--r--hw/arm/xlnx-zynqmp.c6
-rw-r--r--hw/block/Kconfig3
-rw-r--r--hw/block/meson.build2
-rw-r--r--hw/block/tc58128.c26
-rw-r--r--hw/char/Kconfig3
-rw-r--r--hw/char/meson.build2
-rw-r--r--hw/display/omap_lcd_template.h169
-rw-r--r--hw/display/omap_lcdc.c129
-rw-r--r--hw/display/tc6393xb.c50
-rw-r--r--hw/display/tc6393xb_template.h72
-rw-r--r--hw/display/tcx.c31
-rw-r--r--hw/i2c/npcm7xx_smbus.c1
-rw-r--r--hw/i386/x86.c6
-rw-r--r--hw/intc/Kconfig3
-rw-r--r--hw/intc/apic.c6
-rw-r--r--hw/intc/meson.build2
-rw-r--r--hw/misc/armsse-cpuid.c2
-rw-r--r--hw/misc/armsse-mhu.c2
-rw-r--r--hw/misc/iotkit-sysctl.c2
-rw-r--r--hw/misc/iotkit-sysinfo.c2
-rw-r--r--hw/misc/mps2-fpgaio.c43
-rw-r--r--hw/misc/mps2-scc.c93
-rw-r--r--hw/net/meson.build1
-rw-r--r--hw/net/npcm7xx_emc.c857
-rw-r--r--hw/net/trace-events17
-rw-r--r--hw/pci-host/Kconfig4
-rw-r--r--hw/pci-host/meson.build1
-rw-r--r--hw/pci-host/sh_pci.c (renamed from hw/sh4/sh_pci.c)0
-rw-r--r--hw/scsi/lsi53c895a.c4
-rw-r--r--hw/scsi/scsi-bus.c33
-rw-r--r--hw/scsi/scsi-disk.c47
-rw-r--r--hw/scsi/scsi-generic.c25
-rw-r--r--hw/scsi/virtio-scsi.c46
-rw-r--r--hw/scsi/vmw_pvscsi.c39
-rw-r--r--hw/sh4/Kconfig12
-rw-r--r--hw/sh4/meson.build1
-rw-r--r--hw/sh4/sh7750_regs.h24
-rw-r--r--hw/timer/Kconfig4
-rw-r--r--hw/timer/meson.build2
-rw-r--r--hw/virtio/virtio-mmio.c13
-rw-r--r--include/hw/arm/armsse.h4
-rw-r--r--include/hw/arm/npcm7xx.h2
-rw-r--r--include/hw/arm/xlnx-zynqmp.h2
-rw-r--r--include/hw/elf_ops.h4
-rw-r--r--include/hw/misc/armsse-cpuid.h2
-rw-r--r--include/hw/misc/armsse-mhu.h2
-rw-r--r--include/hw/misc/iotkit-secctl.h2
-rw-r--r--include/hw/misc/iotkit-sysctl.h2
-rw-r--r--include/hw/misc/iotkit-sysinfo.h2
-rw-r--r--include/hw/misc/mps2-fpgaio.h8
-rw-r--r--include/hw/misc/mps2-scc.h10
-rw-r--r--include/hw/net/npcm7xx_emc.h286
-rw-r--r--include/hw/scsi/scsi.h5
-rw-r--r--include/hw/sh4/sh.h31
-rw-r--r--include/qemu/config-file.h5
-rw-r--r--include/scsi/utils.h27
-rw-r--r--meson.build12
-rw-r--r--qemu-options.hx14
-rw-r--r--qga/vss-win32/meson.build4
-rw-r--r--qom/object_interfaces.c9
-rw-r--r--scsi/qemu-pr-helper.c24
-rw-r--r--scsi/utils.c72
-rw-r--r--softmmu/vl.c51
-rw-r--r--target/arm/cpu.c23
-rw-r--r--target/arm/cpu.h15
-rw-r--r--target/arm/cpu64.c5
-rw-r--r--target/arm/cpu_tcg.c8
-rw-r--r--target/arm/helper-a64.c32
-rw-r--r--target/arm/helper-a64.h2
-rw-r--r--target/arm/helper.c39
-rw-r--r--target/arm/internals.h6
-rw-r--r--target/arm/mte_helper.c13
-rw-r--r--target/arm/translate-a64.c70
-rw-r--r--target/arm/vec_helper.c48
-rw-r--r--target/i386/kvm/kvm.c9
-rw-r--r--target/sh4/cpu.h11
-rw-r--r--target/sh4/helper.c101
-rw-r--r--tests/fp/meson.build2
-rw-r--r--tests/meson.build8
-rw-r--r--tests/qtest/meson.build18
-rw-r--r--tests/qtest/npcm7xx_emc-test.c862
-rw-r--r--trace/control.c13
-rw-r--r--util/qemu-config.c23
-rw-r--r--util/qemu-option.c6
99 files changed, 3703 insertions, 821 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 26c9454823..f22d83c178 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1397,16 +1397,22 @@ R2D
M: Yoshinori Sato <ysato@users.sourceforge.jp>
R: Magnus Damm <magnus.damm@gmail.com>
S: Odd Fixes
+F: hw/char/sh_serial.c
F: hw/sh4/r2d.c
F: hw/intc/sh_intc.c
+F: hw/pci-host/sh_pci.c
+F: hw/timer/sh_timer.c
F: include/hw/sh4/sh_intc.h
Shix
M: Yoshinori Sato <ysato@users.sourceforge.jp>
R: Magnus Damm <magnus.damm@gmail.com>
S: Odd Fixes
+F: hw/block/tc58128.c
+F: hw/char/sh_serial.c
F: hw/sh4/shix.c
F: hw/intc/sh_intc.c
+F: hw/timer/sh_timer.c
F: include/hw/sh4/sh_intc.h
SPARC Machines
diff --git a/Makefile b/Makefile
index d7fb6b270e..bcbbec71a1 100644
--- a/Makefile
+++ b/Makefile
@@ -149,7 +149,7 @@ $(ninja-targets): run-ninja
# --output-sync line.
run-ninja: config-host.mak
ifneq ($(filter $(ninja-targets), $(ninja-cmd-goals)),)
- +$(quiet-@)$(if $(MAKE.nq),@:, $(NINJA) \
+ +$(quiet-@)$(if $(MAKE.nq),@:, $(NINJA) -d keepdepfile \
$(NINJAFLAGS) $(sort $(filter $(ninja-targets), $(ninja-cmd-goals))) | cat)
endif
endif
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 84c943fcdb..f88a52393f 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -598,8 +598,12 @@ static void kvm_memslot_init_dirty_bitmap(KVMSlot *mem)
* too, in most cases).
* So for now, let's align to 64 instead of HOST_LONG_BITS here, in
* a hope that sizeof(long) won't become >8 any time soon.
+ *
+ * Note: the granule of kvm dirty log is qemu_real_host_page_size.
+ * And mem->memory_size is aligned to it (otherwise this mem can't
+ * be registered to KVM).
*/
- hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
+ hwaddr bitmap_size = ALIGN(mem->memory_size / qemu_real_host_page_size,
/*HOST_LONG_BITS*/ 64) / 8;
mem->dirty_bmap = g_malloc0(bitmap_size);
}
@@ -669,6 +673,10 @@ out:
#define KVM_CLEAR_LOG_ALIGN (qemu_real_host_page_size << KVM_CLEAR_LOG_SHIFT)
#define KVM_CLEAR_LOG_MASK (-KVM_CLEAR_LOG_ALIGN)
+/*
+ * As the granule of kvm dirty log is qemu_real_host_page_size,
+ * @start and @size are expected and restricted to align to it.
+ */
static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start,
uint64_t size)
{
@@ -678,6 +686,9 @@ static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start,
unsigned long *bmap_clear = NULL, psize = qemu_real_host_page_size;
int ret;
+ /* Make sure start and size are qemu_real_host_page_size aligned */
+ assert(QEMU_IS_ALIGNED(start | size, psize));
+
/*
* We need to extend either the start or the size or both to
* satisfy the KVM interface requirement. Firstly, do the start
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 5fe6172da9..7eaa8a28bf 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -279,9 +279,8 @@ static int read_config(BDRVBlkdebugState *s, const char *filename,
return -errno;
}
- ret = qemu_config_parse(f, config_groups, filename);
+ ret = qemu_config_parse(f, config_groups, filename, errp);
if (ret < 0) {
- error_setg(errp, "Could not parse blkdebug config file");
goto fail;
}
}
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 06a37c0cc8..c8bced76b7 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -1472,8 +1472,17 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
- sock->has_nodelay = qemu_opt_get(opts, "delay");
- sock->nodelay = !qemu_opt_get_bool(opts, "delay", true);
+ if (qemu_opt_get(opts, "delay") && qemu_opt_get(opts, "nodelay")) {
+ error_setg(errp, "'delay' and 'nodelay' are mutually exclusive");
+ return;
+ }
+ sock->has_nodelay =
+ qemu_opt_get(opts, "delay") ||
+ qemu_opt_get(opts, "nodelay");
+ sock->nodelay =
+ !qemu_opt_get_bool(opts, "delay", true) ||
+ qemu_opt_get_bool(opts, "nodelay", false);
+
/*
* We have different default to QMP for 'server', hence
* we can't just check for existence of 'server'
diff --git a/chardev/char.c b/chardev/char.c
index 288efebd12..97cafd6849 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -868,6 +868,9 @@ QemuOptsList qemu_chardev_opts = {
.name = "delay",
.type = QEMU_OPT_BOOL,
},{
+ .name = "nodelay",
+ .type = QEMU_OPT_BOOL,
+ },{
.name = "reconnect",
.type = QEMU_OPT_NUMBER,
},{
diff --git a/docs/system/arm/mps2.rst b/docs/system/arm/mps2.rst
index 8c5b5f1fe0..601ccea15c 100644
--- a/docs/system/arm/mps2.rst
+++ b/docs/system/arm/mps2.rst
@@ -1,12 +1,15 @@
-Arm MPS2 boards (``mps2-an385``, ``mps2-an386``, ``mps2-an500``, ``mps2-an505``, ``mps2-an511``, ``mps2-an521``)
-================================================================================================================
+Arm MPS2 and MPS3 boards (``mps2-an385``, ``mps2-an386``, ``mps2-an500``, ``mps2-an505``, ``mps2-an511``, ``mps2-an521``, ``mps3-an524``)
+=========================================================================================================================================
These board models all use Arm M-profile CPUs.
-The Arm MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger
-FPGA but is otherwise the same as the 2). Since the CPU itself
-and most of the devices are in the FPGA, the details of the board
-as seen by the guest depend significantly on the FPGA image.
+The Arm MPS2, MPS2+ and MPS3 dev boards are FPGA based (the 2+ has a
+bigger FPGA but is otherwise the same as the 2; the 3 has a bigger
+FPGA again, can handle 4GB of RAM and has a USB controller and QSPI flash).
+
+Since the CPU itself and most of the devices are in the FPGA, the
+details of the board as seen by the guest depend significantly on the
+FPGA image.
QEMU models the following FPGA images:
@@ -22,12 +25,21 @@ QEMU models the following FPGA images:
Cortex-M3 'DesignStart' as documented in Arm Application Note AN511
``mps2-an521``
Dual Cortex-M33 as documented in Arm Application Note AN521
+``mps3-an524``
+ Dual Cortex-M33 on an MPS3, as documented in Arm Application Note AN524
Differences between QEMU and real hardware:
- AN385/AN386 remapping of low 16K of memory to either ZBT SSRAM1 or to
block RAM is unimplemented (QEMU always maps this to ZBT SSRAM1, as
if zbt_boot_ctrl is always zero)
+- AN524 remapping of low memory to either BRAM or to QSPI flash is
+ unimplemented (QEMU always maps this to BRAM, ignoring the
+ SCC CFG_REG0 memory-remap bit)
- QEMU provides a LAN9118 ethernet rather than LAN9220; the only guest
visible difference is that the LAN9118 doesn't support checksum
offloading
+- QEMU does not model the QSPI flash in MPS3 boards as real QSPI
+ flash, but only as simple ROM, so attempting to rewrite the flash
+ from the guest will fail
+- QEMU does not model the USB controller in MPS3 boards
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
index 34fc799b2d..f9fb9224da 100644
--- a/docs/system/arm/nuvoton.rst
+++ b/docs/system/arm/nuvoton.rst
@@ -44,6 +44,7 @@ Supported devices
* Analog to Digital Converter (ADC)
* Pulse Width Modulation (PWM)
* SMBus controller (SMBF)
+ * Ethernet controller (EMC)
Missing devices
---------------
@@ -57,7 +58,7 @@ Missing devices
* Shared memory (SHM)
* eSPI slave interface
- * Ethernet controllers (GMAC and EMC)
+ * Ethernet controller (GMAC)
* USB device (USBD)
* Peripheral SPI controller (PSPI)
* SD/MMC host
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
index 561c916da2..cfabe69846 100644
--- a/docs/system/deprecated.rst
+++ b/docs/system/deprecated.rst
@@ -134,6 +134,12 @@ Boolean options such as ``share=on``/``share=off`` could be written
in short form as ``share`` and ``noshare``. This is now deprecated
and will cause a warning.
+``delay`` option for socket character devices (since 6.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+The replacement for the ``nodelay`` short-form boolean option is ``nodelay=on``
+rather than ``delay=off``.
+
``--enable-fips`` (since 6.0)
'''''''''''''''''''''''''''''
@@ -153,6 +159,13 @@ The ``-writeconfig`` option is not able to serialize the entire contents
of the QEMU command line. It is thus considered a failed experiment
and deprecated, with no current replacement.
+Userspace local APIC with KVM (x86, since 6.0)
+''''''''''''''''''''''''''''''''''''''''''''''
+
+Using ``-M kernel-irqchip=off`` with x86 machine types that include a local
+APIC is deprecated. The ``split`` setting is supported, as is using
+``-M kernel-irqchip=off`` with the ISA PC machine type.
+
QEMU Machine Protocol (QMP) commands
------------------------------------
diff --git a/gdbstub.c b/gdbstub.c
index 3ee40479b6..16d7c8f534 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -3505,7 +3505,7 @@ int gdbserver_start(const char *device)
if (strstart(device, "tcp:", NULL)) {
/* enforce required TCP attributes */
snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
- "%s,wait=off,delay=off,server=on", device);
+ "%s,wait=off,nodelay=on,server=on", device);
device = gdbstub_device_name;
}
#ifndef _WIN32
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index 90caa91493..72da8cb1a1 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -16,25 +16,27 @@
* This source file covers the following FPGA images, for TrustZone cores:
* "mps2-an505" -- Cortex-M33 as documented in ARM Application Note AN505
* "mps2-an521" -- Dual Cortex-M33 as documented in Application Note AN521
+ * "mps2-an524" -- Dual Cortex-M33 as documented in Application Note AN524
*
* Links to the TRM for the board itself and to the various Application
* Notes which document the FPGA images can be found here:
* https://developer.arm.com/products/system-design/development-boards/fpga-prototyping-boards/mps2
*
* Board TRM:
- * http://infocenter.arm.com/help/topic/com.arm.doc.100112_0200_06_en/versatile_express_cortex_m_prototyping_systems_v2m_mps2_and_v2m_mps2plus_technical_reference_100112_0200_06_en.pdf
+ * https://developer.arm.com/documentation/100112/latest/
* Application Note AN505:
- * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html
+ * https://developer.arm.com/documentation/dai0505/latest/
* Application Note AN521:
- * http://infocenter.arm.com/help/topic/com.arm.doc.dai0521c/index.html
+ * https://developer.arm.com/documentation/dai0521/latest/
+ * Application Note AN524:
+ * https://developer.arm.com/documentation/dai0524/latest/
*
* The AN505 defers to the Cortex-M33 processor ARMv8M IoT Kit FVP User Guide
* (ARM ECM0601256) for the details of some of the device layout:
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
- * Similarly, the AN521 uses the SSE-200, and the SSE-200 TRM defines
+ * https://developer.arm.com/documentation/ecm0601256/latest
+ * Similarly, the AN521 and AN524 use the SSE-200, and the SSE-200 TRM defines
* most of the device layout:
- * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf
- *
+ * https://developer.arm.com/documentation/101104/latest/
*/
#include "qemu/osdep.h"
@@ -57,6 +59,7 @@
#include "hw/misc/tz-msc.h"
#include "hw/arm/armsse.h"
#include "hw/dma/pl080.h"
+#include "hw/rtc/pl031.h"
#include "hw/ssi/pl022.h"
#include "hw/i2c/arm_sbcon_i2c.h"
#include "hw/net/lan9118.h"
@@ -65,17 +68,50 @@
#include "hw/qdev-clock.h"
#include "qom/object.h"
-#define MPS2TZ_NUMIRQ 92
+#define MPS2TZ_NUMIRQ_MAX 95
+#define MPS2TZ_RAM_MAX 4
typedef enum MPS2TZFPGAType {
FPGA_AN505,
FPGA_AN521,
+ FPGA_AN524,
} MPS2TZFPGAType;
+/*
+ * Define the layout of RAM in a board, including which parts are
+ * behind which MPCs.
+ * mrindex specifies the index into mms->ram[] to use for the backing RAM;
+ * -1 means "use the system RAM".
+ */
+typedef struct RAMInfo {
+ const char *name;
+ uint32_t base;
+ uint32_t size;
+ int mpc; /* MPC number, -1 for "not behind an MPC" */
+ int mrindex;
+ int flags;
+} RAMInfo;
+
+/*
+ * Flag values:
+ * IS_ALIAS: this RAM area is an alias to the upstream end of the
+ * MPC specified by its .mpc value
+ * IS_ROM: this RAM area is read-only
+ */
+#define IS_ALIAS 1
+#define IS_ROM 2
+
struct MPS2TZMachineClass {
MachineClass parent;
MPS2TZFPGAType fpga_type;
uint32_t scc_id;
+ uint32_t sysclk_frq; /* Main SYSCLK frequency in Hz */
+ uint32_t len_oscclk;
+ const uint32_t *oscclk;
+ uint32_t fpgaio_num_leds; /* Number of LEDs in FPGAIO LED0 register */
+ bool fpgaio_has_switches; /* Does FPGAIO have SWITCH register? */
+ int numirq; /* Number of external interrupts */
+ const RAMInfo *raminfo;
const char *armsse_type;
};
@@ -83,24 +119,28 @@ struct MPS2TZMachineState {
MachineState parent;
ARMSSE iotkit;
- MemoryRegion ssram[3];
- MemoryRegion ssram1_m;
+ MemoryRegion ram[MPS2TZ_RAM_MAX];
+ MemoryRegion eth_usb_container;
+
MPS2SCC scc;
MPS2FPGAIO fpgaio;
TZPPC ppc[5];
- TZMPC ssram_mpc[3];
+ TZMPC mpc[3];
PL022State spi[5];
- ArmSbconI2CState i2c[4];
+ ArmSbconI2CState i2c[5];
UnimplementedDeviceState i2s_audio;
UnimplementedDeviceState gpio[4];
UnimplementedDeviceState gfx;
+ UnimplementedDeviceState cldc;
+ UnimplementedDeviceState usb;
+ PL031State rtc;
PL080State dma[4];
TZMSC msc[4];
- CMSDKAPBUART uart[5];
+ CMSDKAPBUART uart[6];
SplitIRQ sec_resp_splitter;
qemu_or_irq uart_irq_orgate;
DeviceState *lan9118;
- SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ];
+ SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ_MAX];
Clock *sysclk;
Clock *s32kclk;
};
@@ -108,14 +148,144 @@ struct MPS2TZMachineState {
#define TYPE_MPS2TZ_MACHINE "mps2tz"
#define TYPE_MPS2TZ_AN505_MACHINE MACHINE_TYPE_NAME("mps2-an505")
#define TYPE_MPS2TZ_AN521_MACHINE MACHINE_TYPE_NAME("mps2-an521")
+#define TYPE_MPS3TZ_AN524_MACHINE MACHINE_TYPE_NAME("mps3-an524")
OBJECT_DECLARE_TYPE(MPS2TZMachineState, MPS2TZMachineClass, MPS2TZ_MACHINE)
-/* Main SYSCLK frequency in Hz */
-#define SYSCLK_FRQ 20000000
/* Slow 32Khz S32KCLK frequency in Hz */
#define S32KCLK_FRQ (32 * 1000)
+/*
+ * The MPS3 DDR is 2GiB, but on a 32-bit host QEMU doesn't permit
+ * emulation of that much guest RAM, so artificially make it smaller.
+ */
+#if HOST_LONG_BITS == 32
+#define MPS3_DDR_SIZE (1 * GiB)
+#else
+#define MPS3_DDR_SIZE (2 * GiB)
+#endif
+
+static const uint32_t an505_oscclk[] = {
+ 40000000,
+ 24580000,
+ 25000000,
+};
+
+static const uint32_t an524_oscclk[] = {
+ 24000000,
+ 32000000,
+ 50000000,
+ 50000000,
+ 24576000,
+ 23750000,
+};
+
+static const RAMInfo an505_raminfo[] = { {
+ .name = "ssram-0",
+ .base = 0x00000000,
+ .size = 0x00400000,
+ .mpc = 0,
+ .mrindex = 0,
+ }, {
+ .name = "ssram-1",
+ .base = 0x28000000,
+ .size = 0x00200000,
+ .mpc = 1,
+ .mrindex = 1,
+ }, {
+ .name = "ssram-2",
+ .base = 0x28200000,
+ .size = 0x00200000,
+ .mpc = 2,
+ .mrindex = 2,
+ }, {
+ .name = "ssram-0-alias",
+ .base = 0x00400000,
+ .size = 0x00400000,
+ .mpc = 0,
+ .mrindex = 3,
+ .flags = IS_ALIAS,
+ }, {
+ /* Use the largest bit of contiguous RAM as our "system memory" */
+ .name = "mps.ram",
+ .base = 0x80000000,
+ .size = 16 * MiB,
+ .mpc = -1,
+ .mrindex = -1,
+ }, {
+ .name = NULL,
+ },
+};
+
+static const RAMInfo an524_raminfo[] = { {
+ .name = "bram",
+ .base = 0x00000000,
+ .size = 512 * KiB,
+ .mpc = 0,
+ .mrindex = 0,
+ }, {
+ .name = "sram",
+ .base = 0x20000000,
+ .size = 32 * 4 * KiB,
+ .mpc = 1,
+ .mrindex = 1,
+ }, {
+ /* We don't model QSPI flash yet; for now expose it as simple ROM */
+ .name = "QSPI",
+ .base = 0x28000000,
+ .size = 8 * MiB,
+ .mpc = 1,
+ .mrindex = 2,
+ .flags = IS_ROM,
+ }, {
+ .name = "DDR",
+ .base = 0x60000000,
+ .size = MPS3_DDR_SIZE,
+ .mpc = 2,
+ .mrindex = -1,
+ }, {
+ .name = NULL,
+ },
+};
+
+static const RAMInfo *find_raminfo_for_mpc(MPS2TZMachineState *mms, int mpc)
+{
+ MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
+ const RAMInfo *p;
+
+ for (p = mmc->raminfo; p->name; p++) {
+ if (p->mpc == mpc && !(p->flags & IS_ALIAS)) {
+ return p;
+ }
+ }
+ /* if raminfo array doesn't have an entry for each MPC this is a bug */
+ g_assert_not_reached();
+}
+
+static MemoryRegion *mr_for_raminfo(MPS2TZMachineState *mms,
+ const RAMInfo *raminfo)
+{
+ /* Return an initialized MemoryRegion for the RAMInfo. */
+ MemoryRegion *ram;
+
+ if (raminfo->mrindex < 0) {
+ /* Means this RAMInfo is for QEMU's "system memory" */
+ MachineState *machine = MACHINE(mms);
+ assert(!(raminfo->flags & IS_ROM));
+ return machine->ram;
+ }
+
+ assert(raminfo->mrindex < MPS2TZ_RAM_MAX);
+ ram = &mms->ram[raminfo->mrindex];
+
+ memory_region_init_ram(ram, NULL, raminfo->name,
+ raminfo->size, &error_fatal);
+ if (raminfo->flags & IS_ROM) {
+ memory_region_set_readonly(ram, true);
+ }
+ return ram;
+}
+
/* Create an alias of an entire original MemoryRegion @orig
* located at @base in the memory map.
*/
@@ -129,18 +299,26 @@ static void make_ram_alias(MemoryRegion *mr, const char *name,
static qemu_irq get_sse_irq_in(MPS2TZMachineState *mms, int irqno)
{
- /* Return a qemu_irq which will signal IRQ n to all CPUs in the SSE. */
+ /*
+ * Return a qemu_irq which will signal IRQ n to all CPUs in the
+ * SSE. The irqno should be as the CPU sees it, so the first
+ * external-to-the-SSE interrupt is 32.
+ */
+ MachineClass *mc = MACHINE_GET_CLASS(mms);
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
- assert(irqno < MPS2TZ_NUMIRQ);
+ assert(irqno >= 32 && irqno < (mmc->numirq + 32));
- switch (mmc->fpga_type) {
- case FPGA_AN505:
- return qdev_get_gpio_in_named(DEVICE(&mms->iotkit), "EXP_IRQ", irqno);
- case FPGA_AN521:
+ /*
+ * Convert from "CPU irq number" (as listed in the FPGA image
+ * documentation) to the SSE external-interrupt number.
+ */
+ irqno -= 32;
+
+ if (mc->max_cpus > 1) {
return qdev_get_gpio_in(DEVICE(&mms->cpu_irq_splitter[irqno]), 0);
- default:
- g_assert_not_reached();
+ } else {
+ return qdev_get_gpio_in_named(DEVICE(&mms->iotkit), "EXP_IRQ", irqno);
}
}
@@ -152,7 +330,8 @@ static qemu_irq get_sse_irq_in(MPS2TZMachineState *mms, int irqno)
* needs to be plugged into the downstream end of the PPC port.
*/
typedef MemoryRegion *MakeDevFn(MPS2TZMachineState *mms, void *opaque,
- const char *name, hwaddr size);
+ const char *name, hwaddr size,
+ const int *irqs);
typedef struct PPCPortInfo {
const char *name;
@@ -160,6 +339,7 @@ typedef struct PPCPortInfo {
void *opaque;
hwaddr addr;
hwaddr size;
+ int irqs[3]; /* currently no device needs more IRQ lines than this */
} PPCPortInfo;
typedef struct PPCInfo {
@@ -168,8 +348,9 @@ typedef struct PPCInfo {
} PPCInfo;
static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms,
- void *opaque,
- const char *name, hwaddr size)
+ void *opaque,
+ const char *name, hwaddr size,
+ const int *irqs)
{
/* Initialize, configure and realize a TYPE_UNIMPLEMENTED_DEVICE,
* and return a pointer to its MemoryRegion.
@@ -184,57 +365,69 @@ static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms,
}
static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque,
- const char *name, hwaddr size)
+ const char *name, hwaddr size,
+ const int *irqs)
{
+ /* The irq[] array is tx, rx, combined, in that order */
+ MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
CMSDKAPBUART *uart = opaque;
int i = uart - &mms->uart[0];
- int rxirqno = i * 2;
- int txirqno = i * 2 + 1;
- int combirqno = i + 10;
SysBusDevice *s;
DeviceState *orgate_dev = DEVICE(&mms->uart_irq_orgate);
object_initialize_child(OBJECT(mms), name, uart, TYPE_CMSDK_APB_UART);
qdev_prop_set_chr(DEVICE(uart), "chardev", serial_hd(i));
- qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", SYSCLK_FRQ);
+ qdev_prop_set_uint32(DEVICE(uart), "pclk-frq", mmc->sysclk_frq);
sysbus_realize(SYS_BUS_DEVICE(uart), &error_fatal);
s = SYS_BUS_DEVICE(uart);
- sysbus_connect_irq(s, 0, get_sse_irq_in(mms, txirqno));
- sysbus_connect_irq(s, 1, get_sse_irq_in(mms, rxirqno));
+ sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0]));
+ sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqs[1]));
sysbus_connect_irq(s, 2, qdev_get_gpio_in(orgate_dev, i * 2));
sysbus_connect_irq(s, 3, qdev_get_gpio_in(orgate_dev, i * 2 + 1));
- sysbus_connect_irq(s, 4, get_sse_irq_in(mms, combirqno));
+ sysbus_connect_irq(s, 4, get_sse_irq_in(mms, irqs[2]));
return sysbus_mmio_get_region(SYS_BUS_DEVICE(uart), 0);
}
static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
- const char *name, hwaddr size)
+ const char *name, hwaddr size,
+ const int *irqs)
{
MPS2SCC *scc = opaque;
DeviceState *sccdev;
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
+ uint32_t i;
object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC);
sccdev = DEVICE(scc);
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
+ qdev_prop_set_uint32(sccdev, "len-oscclk", mmc->len_oscclk);
+ for (i = 0; i < mmc->len_oscclk; i++) {
+ g_autofree char *propname = g_strdup_printf("oscclk[%u]", i);
+ qdev_prop_set_uint32(sccdev, propname, mmc->oscclk[i]);
+ }
sysbus_realize(SYS_BUS_DEVICE(scc), &error_fatal);
return sysbus_mmio_get_region(SYS_BUS_DEVICE(sccdev), 0);
}
static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque,
- const char *name, hwaddr size)
+ const char *name, hwaddr size,
+ const int *irqs)
{
MPS2FPGAIO *fpgaio = opaque;
+ MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
object_initialize_child(OBJECT(mms), "fpgaio", fpgaio, TYPE_MPS2_FPGAIO);
+ qdev_prop_set_uint32(DEVICE(fpgaio), "num-leds", mmc->fpgaio_num_leds);
+ qdev_prop_set_bit(DEVICE(fpgaio), "has-switches", mmc->fpgaio_has_switches);
sysbus_realize(SYS_BUS_DEVICE(fpgaio), &error_fatal);
return sysbus_mmio_get_region(SYS_BUS_DEVICE(fpgaio), 0);
}
static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque,
- const char *name, hwaddr size)
+ const char *name, hwaddr size,
+ const int *irqs)
{
SysBusDevice *s;
NICInfo *nd = &nd_table[0];
@@ -248,50 +441,84 @@ static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque,
s = SYS_BUS_DEVICE(mms->lan9118);
sysbus_realize_and_unref(s, &error_fatal);
- sysbus_connect_irq(s, 0, get_sse_irq_in(mms, 16));
+ sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0]));
return sysbus_mmio_get_region(s, 0);
}
+static MemoryRegion *make_eth_usb(MPS2TZMachineState *mms, void *opaque,
+ const char *name, hwaddr size,
+ const int *irqs)
+{
+ /*
+ * The AN524 makes the ethernet and USB share a PPC port.
+ * irqs[] is the ethernet IRQ.
+ */
+ SysBusDevice *s;
+ NICInfo *nd = &nd_table[0];
+
+ memory_region_init(&mms->eth_usb_container, OBJECT(mms),
+ "mps2-tz-eth-usb-container", 0x200000);
+
+ /*
+ * In hardware this is a LAN9220; the LAN9118 is software compatible
+ * except that it doesn't support the checksum-offload feature.
+ */
+ qemu_check_nic_model(nd, "lan9118");
+ mms->lan9118 = qdev_new(TYPE_LAN9118);
+ qdev_set_nic_properties(mms->lan9118, nd);
+
+ s = SYS_BUS_DEVICE(mms->lan9118);
+ sysbus_realize_and_unref(s, &error_fatal);
+ sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0]));
+
+ memory_region_add_subregion(&mms->eth_usb_container,
+ 0, sysbus_mmio_get_region(s, 0));
+
+ /* The USB OTG controller is an ISP1763; we don't have a model of it. */
+ object_initialize_child(OBJECT(mms), "usb-otg",
+ &mms->usb, TYPE_UNIMPLEMENTED_DEVICE);
+ qdev_prop_set_string(DEVICE(&mms->usb), "name", "usb-otg");
+ qdev_prop_set_uint64(DEVICE(&mms->usb), "size", 0x100000);
+ s = SYS_BUS_DEVICE(&mms->usb);
+ sysbus_realize(s, &error_fatal);
+
+ memory_region_add_subregion(&mms->eth_usb_container,
+ 0x100000, sysbus_mmio_get_region(s, 0));
+
+ return &mms->eth_usb_container;
+}
+
static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
- const char *name, hwaddr size)
+ const char *name, hwaddr size,
+ const int *irqs)
{
TZMPC *mpc = opaque;
- int i = mpc - &mms->ssram_mpc[0];
- MemoryRegion *ssram = &mms->ssram[i];
+ int i = mpc - &mms->mpc[0];
MemoryRegion *upstream;
- char *mpcname = g_strdup_printf("%s-mpc", name);
- static uint32_t ramsize[] = { 0x00400000, 0x00200000, 0x00200000 };
- static uint32_t rambase[] = { 0x00000000, 0x28000000, 0x28200000 };
+ const RAMInfo *raminfo = find_raminfo_for_mpc(mms, i);
+ MemoryRegion *ram = mr_for_raminfo(mms, raminfo);
- memory_region_init_ram(ssram, NULL, name, ramsize[i], &error_fatal);
-
- object_initialize_child(OBJECT(mms), mpcname, mpc, TYPE_TZ_MPC);
- object_property_set_link(OBJECT(mpc), "downstream", OBJECT(ssram),
+ object_initialize_child(OBJECT(mms), name, mpc, TYPE_TZ_MPC);
+ object_property_set_link(OBJECT(mpc), "downstream", OBJECT(ram),
&error_fatal);
sysbus_realize(SYS_BUS_DEVICE(mpc), &error_fatal);
/* Map the upstream end of the MPC into system memory */
upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1);
- memory_region_add_subregion(get_system_memory(), rambase[i], upstream);
+ memory_region_add_subregion(get_system_memory(), raminfo->base, upstream);
/* and connect its interrupt to the IoTKit */
qdev_connect_gpio_out_named(DEVICE(mpc), "irq", 0,
qdev_get_gpio_in_named(DEVICE(&mms->iotkit),
"mpcexp_status", i));
- /* The first SSRAM is a special case as it has an alias; accesses to
- * the alias region at 0x00400000 must also go to the MPC upstream.
- */
- if (i == 0) {
- make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", upstream, 0x00400000);
- }
-
- g_free(mpcname);
/* Return the register interface MR for our caller to map behind the PPC */
return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
}
static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
- const char *name, hwaddr size)
+ const char *name, hwaddr size,
+ const int *irqs)
{
+ /* The irq[] array is DMACINTR, DMACINTERR, DMACINTTC, in that order */
PL080State *dma = opaque;
int i = dma - &mms->dma[0];
SysBusDevice *s;
@@ -336,16 +563,17 @@ static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
s = SYS_BUS_DEVICE(dma);
/* Wire up DMACINTR, DMACINTERR, DMACINTTC */
- sysbus_connect_irq(s, 0, get_sse_irq_in(mms, 58 + i * 3));
- sysbus_connect_irq(s, 1, get_sse_irq_in(mms, 56 + i * 3));
- sysbus_connect_irq(s, 2, get_sse_irq_in(mms, 57 + i * 3));
+ sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0]));
+ sysbus_connect_irq(s, 1, get_sse_irq_in(mms, irqs[1]));
+ sysbus_connect_irq(s, 2, get_sse_irq_in(mms, irqs[2]));
g_free(mscname);
return sysbus_mmio_get_region(s, 0);
}
static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque,
- const char *name, hwaddr size)
+ const char *name, hwaddr size,
+ const int *irqs)
{
/*
* The AN505 has five PL022 SPI controllers.
@@ -356,18 +584,18 @@ static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque,
* lines are set via the "MISC" register in the MPS2 FPGAIO device.
*/
PL022State *spi = opaque;
- int i = spi - &mms->spi[0];
SysBusDevice *s;
object_initialize_child(OBJECT(mms), name, spi, TYPE_PL022);
sysbus_realize(SYS_BUS_DEVICE(spi), &error_fatal);
s = SYS_BUS_DEVICE(spi);
- sysbus_connect_irq(s, 0, get_sse_irq_in(mms, 51 + i));
+ sysbus_connect_irq(s, 0, get_sse_irq_in(mms, irqs[0]));
return sysbus_mmio_get_region(s, 0);
}
static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque,
- const char *name, hwaddr size)
+ const char *name, hwaddr size,
+ const int *irqs)
{
ArmSbconI2CState *i2c = opaque;
SysBusDevice *s;
@@ -378,6 +606,59 @@ static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque,
return sysbus_mmio_get_region(s, 0);
}
+static MemoryRegion *make_rtc(MPS2TZMachineState *mms, void *opaque,
+ const char *name, hwaddr size,
+ const int *irqs)
+{
+ PL031State *pl031 = opaque;
+ SysBusDevice *s;
+
+ object_initialize_child(OBJECT(mms), name, pl031, TYPE_PL031);
+ s = SYS_BUS_DEVICE(pl031);
+ sysbus_realize(s, &error_fatal);
+ /*
+ * The board docs don't give an IRQ number for the PL031, so
+ * presumably it is not connected.
+ */
+ return sysbus_mmio_get_region(s, 0);
+}
+
+static void create_non_mpc_ram(MPS2TZMachineState *mms)
+{
+ /*
+ * Handle the RAMs which are either not behind MPCs or which are
+ * aliases to another MPC.
+ */
+ const RAMInfo *p;
+ MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
+
+ for (p = mmc->raminfo; p->name; p++) {
+ if (p->flags & IS_ALIAS) {
+ SysBusDevice *mpc_sbd = SYS_BUS_DEVICE(&mms->mpc[p->mpc]);
+ MemoryRegion *upstream = sysbus_mmio_get_region(mpc_sbd, 1);
+ make_ram_alias(&mms->ram[p->mrindex], p->name, upstream, p->base);
+ } else if (p->mpc == -1) {
+ /* RAM not behind an MPC */
+ MemoryRegion *mr = mr_for_raminfo(mms, p);
+ memory_region_add_subregion(get_system_memory(), p->base, mr);
+ }
+ }
+}
+
+static uint32_t boot_ram_size(MPS2TZMachineState *mms)
+{
+ /* Return the size of the RAM block at guest address zero */
+ const RAMInfo *p;
+ MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
+
+ for (p = mmc->raminfo; p->name; p++) {
+ if (p->base == 0) {
+ return p->size;
+ }
+ }
+ g_assert_not_reached();
+}
+
static void mps2tz_common_init(MachineState *machine)
{
MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
@@ -386,6 +667,8 @@ static void mps2tz_common_init(MachineState *machine)
MemoryRegion *system_memory = get_system_memory();
DeviceState *iotkitdev;
DeviceState *dev_splitter;
+ const PPCInfo *ppcs;
+ int num_ppcs;
int i;
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
@@ -403,7 +686,7 @@ static void mps2tz_common_init(MachineState *machine)
/* These clocks don't need migration because they are fixed-frequency */
mms->sysclk = clock_new(OBJECT(machine), "SYSCLK");
- clock_set_hz(mms->sysclk, SYSCLK_FRQ);
+ clock_set_hz(mms->sysclk, mmc->sysclk_frq);
mms->s32kclk = clock_new(OBJECT(machine), "S32KCLK");
clock_set_hz(mms->s32kclk, S32KCLK_FRQ);
@@ -412,17 +695,20 @@ static void mps2tz_common_init(MachineState *machine)
iotkitdev = DEVICE(&mms->iotkit);
object_property_set_link(OBJECT(&mms->iotkit), "memory",
OBJECT(system_memory), &error_abort);
- qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", MPS2TZ_NUMIRQ);
+ qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", mmc->numirq);
qdev_connect_clock_in(iotkitdev, "MAINCLK", mms->sysclk);
qdev_connect_clock_in(iotkitdev, "S32KCLK", mms->s32kclk);
sysbus_realize(SYS_BUS_DEVICE(&mms->iotkit), &error_fatal);
/*
- * The AN521 needs us to create splitters to feed the IRQ inputs
- * for each CPU in the SSE-200 from each device in the board.
+ * If this board has more than one CPU, then we need to create splitters
+ * to feed the IRQ inputs for each CPU in the SSE from each device in the
+ * board. If there is only one CPU, we can just wire the device IRQ
+ * directly to the SSE's IRQ input.
*/
- if (mmc->fpga_type == FPGA_AN521) {
- for (i = 0; i < MPS2TZ_NUMIRQ; i++) {
+ assert(mmc->numirq <= MPS2TZ_NUMIRQ_MAX);
+ if (mc->max_cpus > 1) {
+ for (i = 0; i < mmc->numirq; i++) {
char *name = g_strdup_printf("mps2-irq-splitter%d", i);
SplitIRQ *splitter = &mms->cpu_irq_splitter[i];
@@ -457,36 +743,34 @@ static void mps2tz_common_init(MachineState *machine)
qdev_connect_gpio_out_named(iotkitdev, "sec_resp_cfg", 0,
qdev_get_gpio_in(dev_splitter, 0));
- /* The IoTKit sets up much of the memory layout, including
+ /*
+ * The IoTKit sets up much of the memory layout, including
* the aliases between secure and non-secure regions in the
- * address space. The FPGA itself contains:
- *
- * 0x00000000..0x003fffff SSRAM1
- * 0x00400000..0x007fffff alias of SSRAM1
- * 0x28000000..0x283fffff 4MB SSRAM2 + SSRAM3
- * 0x40100000..0x4fffffff AHB Master Expansion 1 interface devices
- * 0x80000000..0x80ffffff 16MB PSRAM
- */
-
- /* The FPGA images have an odd combination of different RAMs,
+ * address space, and also most of the devices in the system.
+ * The FPGA itself contains various RAMs and some additional devices.
+ * The FPGA images have an odd combination of different RAMs,
* because in hardware they are different implementations and
* connected to different buses, giving varying performance/size
* tradeoffs. For QEMU they're all just RAM, though. We arbitrarily
- * call the 16MB our "system memory", as it's the largest lump.
+ * call the largest lump our "system memory".
*/
- memory_region_add_subregion(system_memory, 0x80000000, machine->ram);
- /* The overflow IRQs for all UARTs are ORed together.
+ /*
+ * The overflow IRQs for all UARTs are ORed together.
* Tx, Rx and "combined" IRQs are sent to the NVIC separately.
- * Create the OR gate for this.
+ * Create the OR gate for this: it has one input for the TX overflow
+ * and one for the RX overflow for each UART we might have.
+ * (If the board has fewer than the maximum possible number of UARTs
+ * those inputs are never wired up and are treated as always-zero.)
*/
object_initialize_child(OBJECT(mms), "uart-irq-orgate",
&mms->uart_irq_orgate, TYPE_OR_IRQ);
- object_property_set_int(OBJECT(&mms->uart_irq_orgate), "num-lines", 10,
+ object_property_set_int(OBJECT(&mms->uart_irq_orgate), "num-lines",
+ 2 * ARRAY_SIZE(mms->uart),
&error_fatal);
qdev_realize(DEVICE(&mms->uart_irq_orgate), NULL, &error_fatal);
qdev_connect_gpio_out(DEVICE(&mms->uart_irq_orgate), 0,
- get_sse_irq_in(mms, 15));
+ get_sse_irq_in(mms, 47));
/* Most of the devices in the FPGA are behind Peripheral Protection
* Controllers. The required order for initializing things is:
@@ -499,26 +783,26 @@ static void mps2tz_common_init(MachineState *machine)
* + wire up the PPC's control lines to the IoTKit object
*/
- const PPCInfo ppcs[] = { {
+ const PPCInfo an505_ppcs[] = { {
.name = "apb_ppcexp0",
.ports = {
- { "ssram-0", make_mpc, &mms->ssram_mpc[0], 0x58007000, 0x1000 },
- { "ssram-1", make_mpc, &mms->ssram_mpc[1], 0x58008000, 0x1000 },
- { "ssram-2", make_mpc, &mms->ssram_mpc[2], 0x58009000, 0x1000 },
+ { "ssram-0-mpc", make_mpc, &mms->mpc[0], 0x58007000, 0x1000 },
+ { "ssram-1-mpc", make_mpc, &mms->mpc[1], 0x58008000, 0x1000 },
+ { "ssram-2-mpc", make_mpc, &mms->mpc[2], 0x58009000, 0x1000 },
},
}, {
.name = "apb_ppcexp1",
.ports = {
- { "spi0", make_spi, &mms->spi[0], 0x40205000, 0x1000 },
- { "spi1", make_spi, &mms->spi[1], 0x40206000, 0x1000 },
- { "spi2", make_spi, &mms->spi[2], 0x40209000, 0x1000 },
- { "spi3", make_spi, &mms->spi[3], 0x4020a000, 0x1000 },
- { "spi4", make_spi, &mms->spi[4], 0x4020b000, 0x1000 },
- { "uart0", make_uart, &mms->uart[0], 0x40200000, 0x1000 },
- { "uart1", make_uart, &mms->uart[1], 0x40201000, 0x1000 },
- { "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000 },
- { "uart3", make_uart, &mms->uart[3], 0x40203000, 0x1000 },
- { "uart4", make_uart, &mms->uart[4], 0x40204000, 0x1000 },
+ { "spi0", make_spi, &mms->spi[0], 0x40205000, 0x1000, { 51 } },
+ { "spi1", make_spi, &mms->spi[1], 0x40206000, 0x1000, { 52 } },
+ { "spi2", make_spi, &mms->spi[2], 0x40209000, 0x1000, { 53 } },
+ { "spi3", make_spi, &mms->spi[3], 0x4020a000, 0x1000, { 54 } },
+ { "spi4", make_spi, &mms->spi[4], 0x4020b000, 0x1000, { 55 } },
+ { "uart0", make_uart, &mms->uart[0], 0x40200000, 0x1000, { 32, 33, 42 } },
+ { "uart1", make_uart, &mms->uart[1], 0x40201000, 0x1000, { 34, 35, 43 } },
+ { "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000, { 36, 37, 44 } },
+ { "uart3", make_uart, &mms->uart[3], 0x40203000, 0x1000, { 38, 39, 45 } },
+ { "uart4", make_uart, &mms->uart[4], 0x40204000, 0x1000, { 40, 41, 46 } },
{ "i2c0", make_i2c, &mms->i2c[0], 0x40207000, 0x1000 },
{ "i2c1", make_i2c, &mms->i2c[1], 0x40208000, 0x1000 },
{ "i2c2", make_i2c, &mms->i2c[2], 0x4020c000, 0x1000 },
@@ -540,20 +824,84 @@ static void mps2tz_common_init(MachineState *machine)
{ "gpio1", make_unimp_dev, &mms->gpio[1], 0x40101000, 0x1000 },
{ "gpio2", make_unimp_dev, &mms->gpio[2], 0x40102000, 0x1000 },
{ "gpio3", make_unimp_dev, &mms->gpio[3], 0x40103000, 0x1000 },
- { "eth", make_eth_dev, NULL, 0x42000000, 0x100000 },
+ { "eth", make_eth_dev, NULL, 0x42000000, 0x100000, { 48 } },
},
}, {
.name = "ahb_ppcexp1",
.ports = {
- { "dma0", make_dma, &mms->dma[0], 0x40110000, 0x1000 },
- { "dma1", make_dma, &mms->dma[1], 0x40111000, 0x1000 },
- { "dma2", make_dma, &mms->dma[2], 0x40112000, 0x1000 },
- { "dma3", make_dma, &mms->dma[3], 0x40113000, 0x1000 },
+ { "dma0", make_dma, &mms->dma[0], 0x40110000, 0x1000, { 58, 56, 57 } },
+ { "dma1", make_dma, &mms->dma[1], 0x40111000, 0x1000, { 61, 59, 60 } },
+ { "dma2", make_dma, &mms->dma[2], 0x40112000, 0x1000, { 64, 62, 63 } },
+ { "dma3", make_dma, &mms->dma[3], 0x40113000, 0x1000, { 67, 65, 66 } },
},
},
};
- for (i = 0; i < ARRAY_SIZE(ppcs); i++) {
+ const PPCInfo an524_ppcs[] = { {
+ .name = "apb_ppcexp0",
+ .ports = {
+ { "bram-mpc", make_mpc, &mms->mpc[0], 0x58007000, 0x1000 },
+ { "qspi-mpc", make_mpc, &mms->mpc[1], 0x58008000, 0x1000 },
+ { "ddr-mpc", make_mpc, &mms->mpc[2], 0x58009000, 0x1000 },
+ },
+ }, {
+ .name = "apb_ppcexp1",
+ .ports = {
+ { "i2c0", make_i2c, &mms->i2c[0], 0x41200000, 0x1000 },
+ { "i2c1", make_i2c, &mms->i2c[1], 0x41201000, 0x1000 },
+ { "spi0", make_spi, &mms->spi[0], 0x41202000, 0x1000, { 52 } },
+ { "spi1", make_spi, &mms->spi[1], 0x41203000, 0x1000, { 53 } },
+ { "spi2", make_spi, &mms->spi[2], 0x41204000, 0x1000, { 54 } },
+ { "i2c2", make_i2c, &mms->i2c[2], 0x41205000, 0x1000 },
+ { "i2c3", make_i2c, &mms->i2c[3], 0x41206000, 0x1000 },
+ { /* port 7 reserved */ },
+ { "i2c4", make_i2c, &mms->i2c[4], 0x41208000, 0x1000 },
+ },
+ }, {
+ .name = "apb_ppcexp2",
+ .ports = {
+ { "scc", make_scc, &mms->scc, 0x41300000, 0x1000 },
+ { "i2s-audio", make_unimp_dev, &mms->i2s_audio,
+ 0x41301000, 0x1000 },
+ { "fpgaio", make_fpgaio, &mms->fpgaio, 0x41302000, 0x1000 },
+ { "uart0", make_uart, &mms->uart[0], 0x41303000, 0x1000, { 32, 33, 42 } },
+ { "uart1", make_uart, &mms->uart[1], 0x41304000, 0x1000, { 34, 35, 43 } },
+ { "uart2", make_uart, &mms->uart[2], 0x41305000, 0x1000, { 36, 37, 44 } },
+ { "uart3", make_uart, &mms->uart[3], 0x41306000, 0x1000, { 38, 39, 45 } },
+ { "uart4", make_uart, &mms->uart[4], 0x41307000, 0x1000, { 40, 41, 46 } },
+ { "uart5", make_uart, &mms->uart[5], 0x41308000, 0x1000, { 124, 125, 126 } },
+
+ { /* port 9 reserved */ },
+ { "clcd", make_unimp_dev, &mms->cldc, 0x4130a000, 0x1000 },
+ { "rtc", make_rtc, &mms->rtc, 0x4130b000, 0x1000 },
+ },
+ }, {
+ .name = "ahb_ppcexp0",
+ .ports = {
+ { "gpio0", make_unimp_dev, &mms->gpio[0], 0x41100000, 0x1000 },
+ { "gpio1", make_unimp_dev, &mms->gpio[1], 0x41101000, 0x1000 },
+ { "gpio2", make_unimp_dev, &mms->gpio[2], 0x41102000, 0x1000 },
+ { "gpio3", make_unimp_dev, &mms->gpio[3], 0x41103000, 0x1000 },
+ { "eth-usb", make_eth_usb, NULL, 0x41400000, 0x200000, { 48 } },
+ },
+ },
+ };
+
+ switch (mmc->fpga_type) {
+ case FPGA_AN505:
+ case FPGA_AN521:
+ ppcs = an505_ppcs;
+ num_ppcs = ARRAY_SIZE(an505_ppcs);
+ break;
+ case FPGA_AN524:
+ ppcs = an524_ppcs;
+ num_ppcs = ARRAY_SIZE(an524_ppcs);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ for (i = 0; i < num_ppcs; i++) {
const PPCInfo *ppcinfo = &ppcs[i];
TZPPC *ppc = &mms->ppc[i];
DeviceState *ppcdev;
@@ -573,7 +921,8 @@ static void mps2tz_common_init(MachineState *machine)
continue;
}
- mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size);
+ mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size,
+ pinfo->irqs);
portname = g_strdup_printf("port[%d]", port);
object_property_set_link(OBJECT(ppc), portname, OBJECT(mr),
&error_fatal);
@@ -626,7 +975,10 @@ static void mps2tz_common_init(MachineState *machine)
create_unimplemented_device("FPGA NS PC", 0x48007000, 0x1000);
- armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x400000);
+ create_non_mpc_ram(mms);
+
+ armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
+ boot_ram_size(mms));
}
static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address,
@@ -654,8 +1006,26 @@ static void mps2tz_class_init(ObjectClass *oc, void *data)
mc->init = mps2tz_common_init;
iic->check = mps2_tz_idau_check;
- mc->default_ram_size = 16 * MiB;
- mc->default_ram_id = "mps.ram";
+}
+
+static void mps2tz_set_default_ram_info(MPS2TZMachineClass *mmc)
+{
+ /*
+ * Set mc->default_ram_size and default_ram_id from the
+ * information in mmc->raminfo.
+ */
+ MachineClass *mc = MACHINE_CLASS(mmc);
+ const RAMInfo *p;
+
+ for (p = mmc->raminfo; p->name; p++) {
+ if (p->mrindex < 0) {
+ /* Found the entry for "system memory" */
+ mc->default_ram_size = p->size;
+ mc->default_ram_id = p->name;
+ return;
+ }
+ }
+ g_assert_not_reached();
}
static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
@@ -670,7 +1040,15 @@ static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
mmc->fpga_type = FPGA_AN505;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
mmc->scc_id = 0x41045050;
+ mmc->sysclk_frq = 20 * 1000 * 1000; /* 20MHz */
+ mmc->oscclk = an505_oscclk;
+ mmc->len_oscclk = ARRAY_SIZE(an505_oscclk);
+ mmc->fpgaio_num_leds = 2;
+ mmc->fpgaio_has_switches = false;
+ mmc->numirq = 92;
+ mmc->raminfo = an505_raminfo;
mmc->armsse_type = TYPE_IOTKIT;
+ mps2tz_set_default_ram_info(mmc);
}
static void mps2tz_an521_class_init(ObjectClass *oc, void *data)
@@ -685,7 +1063,38 @@ static void mps2tz_an521_class_init(ObjectClass *oc, void *data)
mmc->fpga_type = FPGA_AN521;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
mmc->scc_id = 0x41045210;
+ mmc->sysclk_frq = 20 * 1000 * 1000; /* 20MHz */
+ mmc->oscclk = an505_oscclk; /* AN521 is the same as AN505 here */
+ mmc->len_oscclk = ARRAY_SIZE(an505_oscclk);
+ mmc->fpgaio_num_leds = 2;
+ mmc->fpgaio_has_switches = false;
+ mmc->numirq = 92;
+ mmc->raminfo = an505_raminfo; /* AN521 is the same as AN505 here */
mmc->armsse_type = TYPE_SSE200;
+ mps2tz_set_default_ram_info(mmc);
+}
+
+static void mps3tz_an524_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc);
+
+ mc->desc = "ARM MPS3 with AN524 FPGA image for dual Cortex-M33";
+ mc->default_cpus = 2;
+ mc->min_cpus = mc->default_cpus;
+ mc->max_cpus = mc->default_cpus;
+ mmc->fpga_type = FPGA_AN524;
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
+ mmc->scc_id = 0x41045240;
+ mmc->sysclk_frq = 32 * 1000 * 1000; /* 32MHz */
+ mmc->oscclk = an524_oscclk;
+ mmc->len_oscclk = ARRAY_SIZE(an524_oscclk);
+ mmc->fpgaio_num_leds = 10;
+ mmc->fpgaio_has_switches = true;
+ mmc->numirq = 95;
+ mmc->raminfo = an524_raminfo;
+ mmc->armsse_type = TYPE_SSE200;
+ mps2tz_set_default_ram_info(mmc);
}
static const TypeInfo mps2tz_info = {
@@ -713,11 +1122,18 @@ static const TypeInfo mps2tz_an521_info = {
.class_init = mps2tz_an521_class_init,
};
+static const TypeInfo mps3tz_an524_info = {
+ .name = TYPE_MPS3TZ_AN524_MACHINE,
+ .parent = TYPE_MPS2TZ_MACHINE,
+ .class_init = mps3tz_an524_class_init,
+};
+
static void mps2tz_machine_init(void)
{
type_register_static(&mps2tz_info);
type_register_static(&mps2tz_an505_info);
type_register_static(&mps2tz_an521_info);
+ type_register_static(&mps3tz_an524_info);
}
type_init(mps2tz_machine_init);
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
index 39add416db..81413b7133 100644
--- a/hw/arm/mps2.c
+++ b/hw/arm/mps2.c
@@ -373,6 +373,11 @@ static void mps2_common_init(MachineState *machine)
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
+ /* All these FPGA images have the same OSCCLK configuration */
+ qdev_prop_set_uint32(sccdev, "len-oscclk", 3);
+ qdev_prop_set_uint32(sccdev, "oscclk[0]", 50000000);
+ qdev_prop_set_uint32(sccdev, "oscclk[1]", 24576000);
+ qdev_prop_set_uint32(sccdev, "oscclk[2]", 25000000);
sysbus_realize(SYS_BUS_DEVICE(&mms->scc), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(sccdev), 0, 0x4002f000);
object_initialize_child(OBJECT(mms), "fpgaio",
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 6aec84aeed..9cebece2de 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -512,53 +512,37 @@ static uint8_t scale_lcd_color(musicpal_lcd_state *s, uint8_t col)
}
}
-#define SET_LCD_PIXEL(depth, type) \
-static inline void glue(set_lcd_pixel, depth) \
- (musicpal_lcd_state *s, int x, int y, type col) \
-{ \
- int dx, dy; \
- DisplaySurface *surface = qemu_console_surface(s->con); \
- type *pixel = &((type *) surface_data(surface))[(y * 128 * 3 + x) * 3]; \
-\
- for (dy = 0; dy < 3; dy++, pixel += 127 * 3) \
- for (dx = 0; dx < 3; dx++, pixel++) \
- *pixel = col; \
+static inline void set_lcd_pixel32(musicpal_lcd_state *s,
+ int x, int y, uint32_t col)
+{
+ int dx, dy;
+ DisplaySurface *surface = qemu_console_surface(s->con);
+ uint32_t *pixel =
+ &((uint32_t *) surface_data(surface))[(y * 128 * 3 + x) * 3];
+
+ for (dy = 0; dy < 3; dy++, pixel += 127 * 3) {
+ for (dx = 0; dx < 3; dx++, pixel++) {
+ *pixel = col;
+ }
+ }
}
-SET_LCD_PIXEL(8, uint8_t)
-SET_LCD_PIXEL(16, uint16_t)
-SET_LCD_PIXEL(32, uint32_t)
static void lcd_refresh(void *opaque)
{
musicpal_lcd_state *s = opaque;
- DisplaySurface *surface = qemu_console_surface(s->con);
int x, y, col;
- switch (surface_bits_per_pixel(surface)) {
- case 0:
- return;
-#define LCD_REFRESH(depth, func) \
- case depth: \
- col = func(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff), \
- scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff), \
- scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff)); \
- for (x = 0; x < 128; x++) { \
- for (y = 0; y < 64; y++) { \
- if (s->video_ram[x + (y/8)*128] & (1 << (y % 8))) { \
- glue(set_lcd_pixel, depth)(s, x, y, col); \
- } else { \
- glue(set_lcd_pixel, depth)(s, x, y, 0); \
- } \
- } \
- } \
- break;
- LCD_REFRESH(8, rgb_to_pixel8)
- LCD_REFRESH(16, rgb_to_pixel16)
- LCD_REFRESH(32, (is_surface_bgr(surface) ?
- rgb_to_pixel32bgr : rgb_to_pixel32))
- default:
- hw_error("unsupported colour depth %i\n",
- surface_bits_per_pixel(surface));
+ col = rgb_to_pixel32(scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 16) & 0xff),
+ scale_lcd_color(s, (MP_LCD_TEXTCOLOR >> 8) & 0xff),
+ scale_lcd_color(s, MP_LCD_TEXTCOLOR & 0xff));
+ for (x = 0; x < 128; x++) {
+ for (y = 0; y < 64; y++) {
+ if (s->video_ram[x + (y / 8) * 128] & (1 << (y % 8))) {
+ set_lcd_pixel32(s, x, y, col);
+ } else {
+ set_lcd_pixel32(s, x, y, 0);
+ }
+ }
}
dpy_gfx_update(s->con, 0, 0, 128*3, 64*3);
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index f8950f9470..9bd1e83f02 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -82,6 +82,8 @@ enum NPCM7xxInterrupt {
NPCM7XX_UART1_IRQ,
NPCM7XX_UART2_IRQ,
NPCM7XX_UART3_IRQ,
+ NPCM7XX_EMC1RX_IRQ = 15,
+ NPCM7XX_EMC1TX_IRQ,
NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */
NPCM7XX_TIMER1_IRQ,
NPCM7XX_TIMER2_IRQ,
@@ -120,6 +122,8 @@ enum NPCM7xxInterrupt {
NPCM7XX_SMBUS15_IRQ,
NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */
NPCM7XX_PWM1_IRQ, /* PWM module 1 */
+ NPCM7XX_EMC2RX_IRQ = 114,
+ NPCM7XX_EMC2TX_IRQ,
NPCM7XX_GPIO0_IRQ = 116,
NPCM7XX_GPIO1_IRQ,
NPCM7XX_GPIO2_IRQ,
@@ -188,6 +192,12 @@ static const hwaddr npcm7xx_smbus_addr[] = {
0xf008f000,
};
+/* Register base address for each EMC Module */
+static const hwaddr npcm7xx_emc_addr[] = {
+ 0xf0825000,
+ 0xf0826000,
+};
+
static const struct {
hwaddr regs_addr;
uint32_t unconnected_pins;
@@ -406,6 +416,10 @@ static void npcm7xx_init(Object *obj)
for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
}
+
+ for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
+ object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC);
+ }
}
static void npcm7xx_realize(DeviceState *dev, Error **errp)
@@ -590,6 +604,40 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
}
/*
+ * EMC Modules. Cannot fail.
+ * The mapping of the device to its netdev backend works as follows:
+ * emc[i] = nd_table[i]
+ * This works around the inability to specify the netdev property for the
+ * emc device: it's not pluggable and thus the -device option can't be
+ * used.
+ */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_emc_addr) != ARRAY_SIZE(s->emc));
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(s->emc) != 2);
+ for (i = 0; i < ARRAY_SIZE(s->emc); i++) {
+ s->emc[i].emc_num = i;
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->emc[i]);
+ if (nd_table[i].used) {
+ qemu_check_nic_model(&nd_table[i], TYPE_NPCM7XX_EMC);
+ qdev_set_nic_properties(DEVICE(sbd), &nd_table[i]);
+ }
+ /*
+ * The device exists regardless of whether it's connected to a QEMU
+ * netdev backend. So always instantiate it even if there is no
+ * backend.
+ */
+ sysbus_realize(sbd, &error_abort);
+ sysbus_mmio_map(sbd, 0, npcm7xx_emc_addr[i]);
+ int tx_irq = i == 0 ? NPCM7XX_EMC1TX_IRQ : NPCM7XX_EMC2TX_IRQ;
+ int rx_irq = i == 0 ? NPCM7XX_EMC1RX_IRQ : NPCM7XX_EMC2RX_IRQ;
+ /*
+ * N.B. The values for the second argument sysbus_connect_irq are
+ * chosen to match the registration order in npcm7xx_emc_realize.
+ */
+ sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, tx_irq));
+ sysbus_connect_irq(sbd, 1, npcm7xx_irq(s, rx_irq));
+ }
+
+ /*
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
* specified, but this is a programming error.
*/
@@ -649,8 +697,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB);
create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB);
create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB);
- create_unimplemented_device("npcm7xx.emc1", 0xf0825000, 4 * KiB);
- create_unimplemented_device("npcm7xx.emc2", 0xf0826000, 4 * KiB);
create_unimplemented_device("npcm7xx.usbd[0]", 0xf0830000, 4 * KiB);
create_unimplemented_device("npcm7xx.usbd[1]", 0xf0831000, 4 * KiB);
create_unimplemented_device("npcm7xx.usbd[2]", 0xf0832000, 4 * KiB);
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
index 9f70735153..88dfb2284c 100644
--- a/hw/arm/sbsa-ref.c
+++ b/hw/arm/sbsa-ref.c
@@ -145,9 +145,9 @@ static const int sbsa_ref_irqmap[] = {
};
static const char * const valid_cpus[] = {
- ARM_CPU_TYPE_NAME("cortex-a53"),
ARM_CPU_TYPE_NAME("cortex-a57"),
ARM_CPU_TYPE_NAME("cortex-a72"),
+ ARM_CPU_TYPE_NAME("max"),
};
static bool cpu_type_valid(const char *cpu)
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 881847255b..46030c1ef8 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -443,11 +443,6 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
}
}
- if (s->has_rpu) {
- info_report("The 'has_rpu' property is no longer required, to use the "
- "RPUs just use -smp 6.");
- }
-
xlnx_zynqmp_create_rpu(ms, s, boot_cpu, &err);
if (err) {
error_propagate(errp, err);
@@ -646,7 +641,6 @@ static Property xlnx_zynqmp_props[] = {
DEFINE_PROP_STRING("boot-cpu", XlnxZynqMPState, boot_cpu),
DEFINE_PROP_BOOL("secure", XlnxZynqMPState, secure, false),
DEFINE_PROP_BOOL("virtualization", XlnxZynqMPState, virt, false),
- DEFINE_PROP_BOOL("has_rpu", XlnxZynqMPState, has_rpu, false),
DEFINE_PROP_LINK("ddr-ram", XlnxZynqMPState, ddr_ram, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_LINK("canbus0", XlnxZynqMPState, canbus[0], TYPE_CAN_BUS,
diff --git a/hw/block/Kconfig b/hw/block/Kconfig
index 2d17f481ad..4fcd152166 100644
--- a/hw/block/Kconfig
+++ b/hw/block/Kconfig
@@ -22,6 +22,9 @@ config ECC
config ONENAND
bool
+config TC58128
+ bool
+
config NVME_PCI
bool
default y if PCI_DEVICES
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 602ca6c854..4bf994c64f 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -12,7 +12,7 @@ softmmu_ss.add(when: 'CONFIG_PFLASH_CFI02', if_true: files('pflash_cfi02.c'))
softmmu_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c'))
softmmu_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c'))
softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c'))
-softmmu_ss.add(when: 'CONFIG_SH4', if_true: files('tc58128.c'))
+softmmu_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c'))
softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c', 'nvme-ns.c'))
specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
diff --git a/hw/block/tc58128.c b/hw/block/tc58128.c
index 9888f01ac6..bfc27ad899 100644
--- a/hw/block/tc58128.c
+++ b/hw/block/tc58128.c
@@ -1,3 +1,29 @@
+/*
+ * TC58128 NAND EEPROM emulation
+ *
+ * Copyright (c) 2005 Samuel Tardieu
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ *
+ * SPDX-License-Identifier: MIT
+ */
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "hw/sh4/sh.h"
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 939bc44758..f6f4fffd1b 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -50,6 +50,9 @@ config SCLPCONSOLE
config TERMINAL3270
bool
+config SH_SCI
+ bool
+
config RENESAS_SCI
bool
diff --git a/hw/char/meson.build b/hw/char/meson.build
index 196ac91fa2..afe9a0af88 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -31,7 +31,7 @@ softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_uart.c'))
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_aux.c'))
softmmu_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c'))
-softmmu_ss.add(when: 'CONFIG_SH4', if_true: files('sh_serial.c'))
+softmmu_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c'))
softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c'))
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c'))
diff --git a/hw/display/omap_lcd_template.h b/hw/display/omap_lcd_template.h
deleted file mode 100644
index 1025ff3825..0000000000
--- a/hw/display/omap_lcd_template.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * QEMU OMAP LCD Emulator templates
- *
- * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#if DEPTH == 32
-# define BPP 4
-# define PIXEL_TYPE uint32_t
-#else
-# error unsupport depth
-#endif
-
-/*
- * 2-bit colour
- */
-static void glue(draw_line2_, DEPTH)(void *opaque,
- uint8_t *d, const uint8_t *s, int width, int deststep)
-{
- uint16_t *pal = opaque;
- uint8_t v, r, g, b;
-
- do {
- v = ldub_p((void *) s);
- r = (pal[v & 3] >> 4) & 0xf0;
- g = pal[v & 3] & 0xf0;
- b = (pal[v & 3] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- v >>= 2;
- r = (pal[v & 3] >> 4) & 0xf0;
- g = pal[v & 3] & 0xf0;
- b = (pal[v & 3] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- v >>= 2;
- r = (pal[v & 3] >> 4) & 0xf0;
- g = pal[v & 3] & 0xf0;
- b = (pal[v & 3] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- v >>= 2;
- r = (pal[v & 3] >> 4) & 0xf0;
- g = pal[v & 3] & 0xf0;
- b = (pal[v & 3] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- s ++;
- width -= 4;
- } while (width > 0);
-}
-
-/*
- * 4-bit colour
- */
-static void glue(draw_line4_, DEPTH)(void *opaque,
- uint8_t *d, const uint8_t *s, int width, int deststep)
-{
- uint16_t *pal = opaque;
- uint8_t v, r, g, b;
-
- do {
- v = ldub_p((void *) s);
- r = (pal[v & 0xf] >> 4) & 0xf0;
- g = pal[v & 0xf] & 0xf0;
- b = (pal[v & 0xf] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- v >>= 4;
- r = (pal[v & 0xf] >> 4) & 0xf0;
- g = pal[v & 0xf] & 0xf0;
- b = (pal[v & 0xf] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- d += BPP;
- s ++;
- width -= 2;
- } while (width > 0);
-}
-
-/*
- * 8-bit colour
- */
-static void glue(draw_line8_, DEPTH)(void *opaque,
- uint8_t *d, const uint8_t *s, int width, int deststep)
-{
- uint16_t *pal = opaque;
- uint8_t v, r, g, b;
-
- do {
- v = ldub_p((void *) s);
- r = (pal[v] >> 4) & 0xf0;
- g = pal[v] & 0xf0;
- b = (pal[v] << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- s ++;
- d += BPP;
- } while (-- width != 0);
-}
-
-/*
- * 12-bit colour
- */
-static void glue(draw_line12_, DEPTH)(void *opaque,
- uint8_t *d, const uint8_t *s, int width, int deststep)
-{
- uint16_t v;
- uint8_t r, g, b;
-
- do {
- v = lduw_le_p((void *) s);
- r = (v >> 4) & 0xf0;
- g = v & 0xf0;
- b = (v << 4) & 0xf0;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- s += 2;
- d += BPP;
- } while (-- width != 0);
-}
-
-/*
- * 16-bit colour
- */
-static void glue(draw_line16_, DEPTH)(void *opaque,
- uint8_t *d, const uint8_t *s, int width, int deststep)
-{
-#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
- memcpy(d, s, width * 2);
-#else
- uint16_t v;
- uint8_t r, g, b;
-
- do {
- v = lduw_le_p((void *) s);
- r = (v >> 8) & 0xf8;
- g = (v >> 3) & 0xfc;
- b = (v << 3) & 0xf8;
- ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
- s += 2;
- d += BPP;
- } while (-- width != 0);
-#endif
-}
-
-#undef DEPTH
-#undef BPP
-#undef PIXEL_TYPE
diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c
index 58e659c94f..0ba42ef637 100644
--- a/hw/display/omap_lcdc.c
+++ b/hw/display/omap_lcdc.c
@@ -70,16 +70,137 @@ static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
qemu_irq_lower(s->irq);
}
-#define draw_line_func drawfn
+/*
+ * 2-bit colour
+ */
+static void draw_line2_32(void *opaque, uint8_t *d, const uint8_t *s,
+ int width, int deststep)
+{
+ uint16_t *pal = opaque;
+ uint8_t v, r, g, b;
+
+ do {
+ v = ldub_p((void *) s);
+ r = (pal[v & 3] >> 4) & 0xf0;
+ g = pal[v & 3] & 0xf0;
+ b = (pal[v & 3] << 4) & 0xf0;
+ ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
+ d += 4;
+ v >>= 2;
+ r = (pal[v & 3] >> 4) & 0xf0;
+ g = pal[v & 3] & 0xf0;
+ b = (pal[v & 3] << 4) & 0xf0;
+ ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
+ d += 4;
+ v >>= 2;
+ r = (pal[v & 3] >> 4) & 0xf0;
+ g = pal[v & 3] & 0xf0;
+ b = (pal[v & 3] << 4) & 0xf0;
+ ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
+ d += 4;
+ v >>= 2;
+ r = (pal[v & 3] >> 4) & 0xf0;
+ g = pal[v & 3] & 0xf0;
+ b = (pal[v & 3] << 4) & 0xf0;
+ ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
+ d += 4;
+ s++;
+ width -= 4;
+ } while (width > 0);
+}
+
+/*
+ * 4-bit colour
+ */
+static void draw_line4_32(void *opaque, uint8_t *d, const uint8_t *s,
+ int width, int deststep)
+{
+ uint16_t *pal = opaque;
+ uint8_t v, r, g, b;
+
+ do {
+ v = ldub_p((void *) s);
+ r = (pal[v & 0xf] >> 4) & 0xf0;
+ g = pal[v & 0xf] & 0xf0;
+ b = (pal[v & 0xf] << 4) & 0xf0;
+ ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
+ d += 4;
+ v >>= 4;
+ r = (pal[v & 0xf] >> 4) & 0xf0;
+ g = pal[v & 0xf] & 0xf0;
+ b = (pal[v & 0xf] << 4) & 0xf0;
+ ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
+ d += 4;
+ s++;
+ width -= 2;
+ } while (width > 0);
+}
-#define DEPTH 32
-#include "omap_lcd_template.h"
+/*
+ * 8-bit colour
+ */
+static void draw_line8_32(void *opaque, uint8_t *d, const uint8_t *s,
+ int width, int deststep)
+{
+ uint16_t *pal = opaque;
+ uint8_t v, r, g, b;
+
+ do {
+ v = ldub_p((void *) s);
+ r = (pal[v] >> 4) & 0xf0;
+ g = pal[v] & 0xf0;
+ b = (pal[v] << 4) & 0xf0;
+ ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
+ s++;
+ d += 4;
+ } while (-- width != 0);
+}
+
+/*
+ * 12-bit colour
+ */
+static void draw_line12_32(void *opaque, uint8_t *d, const uint8_t *s,
+ int width, int deststep)
+{
+ uint16_t v;
+ uint8_t r, g, b;
+
+ do {
+ v = lduw_le_p((void *) s);
+ r = (v >> 4) & 0xf0;
+ g = v & 0xf0;
+ b = (v << 4) & 0xf0;
+ ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
+ s += 2;
+ d += 4;
+ } while (-- width != 0);
+}
+
+/*
+ * 16-bit colour
+ */
+static void draw_line16_32(void *opaque, uint8_t *d, const uint8_t *s,
+ int width, int deststep)
+{
+ uint16_t v;
+ uint8_t r, g, b;
+
+ do {
+ v = lduw_le_p((void *) s);
+ r = (v >> 8) & 0xf8;
+ g = (v >> 3) & 0xfc;
+ b = (v << 3) & 0xf8;
+ ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b);
+ s += 2;
+ d += 4;
+ } while (-- width != 0);
+}
static void omap_update_display(void *opaque)
{
struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
DisplaySurface *surface;
- draw_line_func draw_line;
+ drawfn draw_line;
int size, height, first, last;
int width, linesize, step, bpp, frame_offset;
hwaddr frame_base;
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
index 49a676d1b0..1f28223c7b 100644
--- a/hw/display/tc6393xb.c
+++ b/hw/display/tc6393xb.c
@@ -410,43 +410,27 @@ static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
(uint32_t) addr, value & 0xff);
}
-#define BITS 8
-#include "tc6393xb_template.h"
-#define BITS 15
-#include "tc6393xb_template.h"
-#define BITS 16
-#include "tc6393xb_template.h"
-#define BITS 24
-#include "tc6393xb_template.h"
-#define BITS 32
-#include "tc6393xb_template.h"
-
static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update)
{
DisplaySurface *surface = qemu_console_surface(s->con);
-
- switch (surface_bits_per_pixel(surface)) {
- case 8:
- tc6393xb_draw_graphic8(s);
- break;
- case 15:
- tc6393xb_draw_graphic15(s);
- break;
- case 16:
- tc6393xb_draw_graphic16(s);
- break;
- case 24:
- tc6393xb_draw_graphic24(s);
- break;
- case 32:
- tc6393xb_draw_graphic32(s);
- break;
- default:
- printf("tc6393xb: unknown depth %d\n",
- surface_bits_per_pixel(surface));
- return;
+ int i;
+ uint16_t *data_buffer;
+ uint8_t *data_display;
+
+ data_buffer = s->vram_ptr;
+ data_display = surface_data(surface);
+ for (i = 0; i < s->scr_height; i++) {
+ int j;
+ for (j = 0; j < s->scr_width; j++, data_display += 4, data_buffer++) {
+ uint16_t color = *data_buffer;
+ uint32_t dest_color = rgb_to_pixel32(
+ ((color & 0xf800) * 0x108) >> 11,
+ ((color & 0x7e0) * 0x41) >> 9,
+ ((color & 0x1f) * 0x21) >> 2
+ );
+ *(uint32_t *)data_display = dest_color;
+ }
}
-
dpy_gfx_update_full(s->con);
}
diff --git a/hw/display/tc6393xb_template.h b/hw/display/tc6393xb_template.h
deleted file mode 100644
index 78629c07f9..0000000000
--- a/hw/display/tc6393xb_template.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Toshiba TC6393XB I/O Controller.
- * Found in Sharp Zaurus SL-6000 (tosa) or some
- * Toshiba e-Series PDAs.
- *
- * FB support code. Based on G364 fb emulator
- *
- * Copyright (c) 2007 Hervé Poussineau
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that 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/>.
- */
-
-#if BITS == 8
-# define SET_PIXEL(addr, color) (*(uint8_t *)addr = color)
-#elif BITS == 15 || BITS == 16
-# define SET_PIXEL(addr, color) (*(uint16_t *)addr = color)
-#elif BITS == 24
-# define SET_PIXEL(addr, color) \
- do { \
- addr[0] = color; \
- addr[1] = (color) >> 8; \
- addr[2] = (color) >> 16; \
- } while (0)
-#elif BITS == 32
-# define SET_PIXEL(addr, color) (*(uint32_t *)addr = color)
-#else
-# error unknown bit depth
-#endif
-
-
-static void glue(tc6393xb_draw_graphic, BITS)(TC6393xbState *s)
-{
- DisplaySurface *surface = qemu_console_surface(s->con);
- int i;
- uint16_t *data_buffer;
- uint8_t *data_display;
-
- data_buffer = s->vram_ptr;
- data_display = surface_data(surface);
- for(i = 0; i < s->scr_height; i++) {
-#if (BITS == 16)
- memcpy(data_display, data_buffer, s->scr_width * 2);
- data_buffer += s->scr_width;
- data_display += surface_stride(surface);
-#else
- int j;
- for (j = 0; j < s->scr_width; j++, data_display += BITS / 8, data_buffer++) {
- uint16_t color = *data_buffer;
- uint32_t dest_color = glue(rgb_to_pixel, BITS)(
- ((color & 0xf800) * 0x108) >> 11,
- ((color & 0x7e0) * 0x41) >> 9,
- ((color & 0x1f) * 0x21) >> 2
- );
- SET_PIXEL(data_display, dest_color);
- }
-#endif
- }
-}
-
-#undef BITS
-#undef SET_PIXEL
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index 965f92ff6b..d3db304657 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -128,15 +128,10 @@ static int tcx_check_dirty(TCXState *s, DirtyBitmapSnapshot *snap,
static void update_palette_entries(TCXState *s, int start, int end)
{
- DisplaySurface *surface = qemu_console_surface(s->con);
int i;
for (i = start; i < end; i++) {
- if (is_surface_bgr(surface)) {
- s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
- } else {
- s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
- }
+ s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
}
tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem));
}
@@ -181,21 +176,18 @@ static void tcx_draw_cursor32(TCXState *s1, uint8_t *d,
}
/*
- XXX Could be much more optimal:
- * detect if line/page/whole screen is in 24 bit mode
- * if destination is also BGR, use memcpy
- */
+ * XXX Could be much more optimal:
+ * detect if line/page/whole screen is in 24 bit mode
+ */
static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
const uint8_t *s, int width,
const uint32_t *cplane,
const uint32_t *s24)
{
- DisplaySurface *surface = qemu_console_surface(s1->con);
- int x, bgr, r, g, b;
+ int x, r, g, b;
uint8_t val, *p8;
uint32_t *p = (uint32_t *)d;
uint32_t dval;
- bgr = is_surface_bgr(surface);
for(x = 0; x < width; x++, s++, s24++) {
if (be32_to_cpu(*cplane) & 0x03000000) {
/* 24-bit direct, BGR order */
@@ -204,10 +196,7 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
b = *p8++;
g = *p8++;
r = *p8;
- if (bgr)
- dval = rgb_to_pixel32bgr(r, g, b);
- else
- dval = rgb_to_pixel32(r, g, b);
+ dval = rgb_to_pixel32(r, g, b);
} else {
/* 8-bit pseudocolor */
val = *s;
@@ -230,9 +219,7 @@ static void tcx_update_display(void *opaque)
int y, y_start, dd, ds;
uint8_t *d, *s;
- if (surface_bits_per_pixel(surface) != 32) {
- return;
- }
+ assert(surface_bits_per_pixel(surface) == 32);
page = 0;
y_start = -1;
@@ -283,9 +270,7 @@ static void tcx24_update_display(void *opaque)
uint8_t *d, *s;
uint32_t *cptr, *s24;
- if (surface_bits_per_pixel(surface) != 32) {
- return;
- }
+ assert(surface_bits_per_pixel(surface) == 32);
page = 0;
y_start = -1;
diff --git a/hw/i2c/npcm7xx_smbus.c b/hw/i2c/npcm7xx_smbus.c
index 6b2f9e1aaa..e7e0ba66fe 100644
--- a/hw/i2c/npcm7xx_smbus.c
+++ b/hw/i2c/npcm7xx_smbus.c
@@ -1040,7 +1040,6 @@ static void npcm7xx_smbus_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem);
s->bus = i2c_init_bus(DEVICE(s), "i2c-bus");
- s->status = NPCM7XX_SMBUS_STATUS_IDLE;
}
static const VMStateDescription vmstate_npcm7xx_smbus = {
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 6329f90ef9..7865660e2c 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -690,6 +690,8 @@ static uint64_t read_pvh_start_addr(void *arg1, void *arg2, bool is64)
elf_note_data_addr =
((void *)nhdr64) + nhdr_size64 +
QEMU_ALIGN_UP(nhdr_namesz, phdr_align);
+
+ pvh_start_addr = *elf_note_data_addr;
} else {
struct elf32_note *nhdr32 = (struct elf32_note *)arg1;
uint32_t nhdr_size32 = sizeof(struct elf32_note);
@@ -699,9 +701,9 @@ static uint64_t read_pvh_start_addr(void *arg1, void *arg2, bool is64)
elf_note_data_addr =
((void *)nhdr32) + nhdr_size32 +
QEMU_ALIGN_UP(nhdr_namesz, phdr_align);
- }
- pvh_start_addr = *elf_note_data_addr;
+ pvh_start_addr = *(uint32_t *)elf_note_data_addr;
+ }
return pvh_start_addr;
}
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index c18d11142a..66bf0b90b4 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -53,6 +53,9 @@ config OMPIC
config PPC_UIC
bool
+config SH_INTC
+ bool
+
config RX_ICU
bool
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index 3ada22f427..f4f50f974e 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -25,6 +25,7 @@
#include "hw/intc/i8259.h"
#include "hw/pci/msi.h"
#include "qemu/host-utils.h"
+#include "sysemu/kvm.h"
#include "trace.h"
#include "hw/i386/apic-msidef.h"
#include "qapi/error.h"
@@ -875,6 +876,11 @@ static void apic_realize(DeviceState *dev, Error **errp)
return;
}
+ if (kvm_enabled()) {
+ warn_report("Userspace local APIC is deprecated for KVM.");
+ warn_report("Do not use kernel-irqchip except for the -M isapc machine type.");
+ }
+
memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
APIC_SPACE_SIZE);
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 53cba11569..b3d9345a0d 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -47,7 +47,7 @@ specific_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_ic.c', 'bcm2836_co
specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
-specific_ss.add(when: 'CONFIG_SH4', if_true: files('sh_intc.c'))
+specific_ss.add(when: 'CONFIG_SH_INTC', if_true: files('sh_intc.c'))
specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
diff --git a/hw/misc/armsse-cpuid.c b/hw/misc/armsse-cpuid.c
index d58138dc28..e785a09051 100644
--- a/hw/misc/armsse-cpuid.c
+++ b/hw/misc/armsse-cpuid.c
@@ -12,7 +12,7 @@
/*
* This is a model of the "CPU_IDENTITY" register block which is part of the
* Arm SSE-200 and documented in
- * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf
+ * https://developer.arm.com/documentation/101104/latest/
*
* It consists of one read-only CPUID register (set by QOM property), plus the
* usual ID registers.
diff --git a/hw/misc/armsse-mhu.c b/hw/misc/armsse-mhu.c
index a45d97fada..0be7f0fc87 100644
--- a/hw/misc/armsse-mhu.c
+++ b/hw/misc/armsse-mhu.c
@@ -12,7 +12,7 @@
/*
* This is a model of the Message Handling Unit (MHU) which is part of the
* Arm SSE-200 and documented in
- * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf
+ * https://developer.arm.com/documentation/101104/latest/
*/
#include "qemu/osdep.h"
diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c
index 964b48c74d..222511c4b0 100644
--- a/hw/misc/iotkit-sysctl.c
+++ b/hw/misc/iotkit-sysctl.c
@@ -12,7 +12,7 @@
/*
* This is a model of the "system control element" which is part of the
* Arm IoTKit and documented in
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * https://developer.arm.com/documentation/ecm0601256/latest
* Specifically, it implements the "system control register" blocks.
*/
diff --git a/hw/misc/iotkit-sysinfo.c b/hw/misc/iotkit-sysinfo.c
index b2dcfc4376..52e70053df 100644
--- a/hw/misc/iotkit-sysinfo.c
+++ b/hw/misc/iotkit-sysinfo.c
@@ -12,7 +12,7 @@
/*
* This is a model of the "system information block" which is part of the
* Arm IoTKit and documented in
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * https://developer.arm.com/documentation/ecm0601256/latest
* It consists of 2 read-only version/config registers, plus the
* usual ID registers.
*/
diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
index 6af0e8f837..f3db88ddcc 100644
--- a/hw/misc/mps2-fpgaio.c
+++ b/hw/misc/mps2-fpgaio.c
@@ -12,7 +12,7 @@
/* This is a model of the "FPGA system control and I/O" block found
* in the AN505 FPGA image for the MPS2 devboard.
* It is documented in AN505:
- * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html
+ * https://developer.arm.com/documentation/dai0505/latest/
*/
#include "qemu/osdep.h"
@@ -35,6 +35,7 @@ REG32(CLK100HZ, 0x14)
REG32(COUNTER, 0x18)
REG32(PRESCALE, 0x1c)
REG32(PSCNTR, 0x20)
+REG32(SWITCH, 0x28)
REG32(MISC, 0x4c)
static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int frq)
@@ -156,7 +157,15 @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
resync_counter(s);
r = s->pscntr;
break;
+ case A_SWITCH:
+ if (!s->has_switches) {
+ goto bad_offset;
+ }
+ /* User-togglable board switches. We don't model that, so report 0. */
+ r = 0;
+ break;
default:
+ bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 FPGAIO read: bad offset %x\n", (int) offset);
r = 0;
@@ -177,9 +186,14 @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
switch (offset) {
case A_LED0:
- s->led0 = value & 0x3;
- led_set_state(s->led[0], value & 0x01);
- led_set_state(s->led[1], value & 0x02);
+ if (s->num_leds != 0) {
+ uint32_t i;
+
+ s->led0 = value & MAKE_64BIT_MASK(0, s->num_leds);
+ for (i = 0; i < s->num_leds; i++) {
+ led_set_state(s->led[i], value & (1 << i));
+ }
+ }
break;
case A_PRESCALE:
resync_counter(s);
@@ -238,7 +252,7 @@ static void mps2_fpgaio_reset(DeviceState *dev)
s->pscntr = 0;
s->pscntr_sync_ticks = now;
- for (size_t i = 0; i < ARRAY_SIZE(s->led); i++) {
+ for (size_t i = 0; i < s->num_leds; i++) {
device_cold_reset(DEVICE(s->led[i]));
}
}
@@ -256,11 +270,19 @@ static void mps2_fpgaio_init(Object *obj)
static void mps2_fpgaio_realize(DeviceState *dev, Error **errp)
{
MPS2FPGAIO *s = MPS2_FPGAIO(dev);
+ uint32_t i;
- s->led[0] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_GREEN, "USERLED0");
- s->led[1] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH,
- LED_COLOR_GREEN, "USERLED1");
+ if (s->num_leds > MPS2FPGAIO_MAX_LEDS) {
+ error_setg(errp, "num-leds cannot be greater than %d",
+ MPS2FPGAIO_MAX_LEDS);
+ return;
+ }
+
+ for (i = 0; i < s->num_leds; i++) {
+ g_autofree char *ledname = g_strdup_printf("USERLED%d", i);
+ s->led[i] = led_create_simple(OBJECT(dev), GPIO_POLARITY_ACTIVE_HIGH,
+ LED_COLOR_GREEN, ledname);
+ }
}
static bool mps2_fpgaio_counters_needed(void *opaque)
@@ -303,6 +325,9 @@ static const VMStateDescription mps2_fpgaio_vmstate = {
static Property mps2_fpgaio_properties[] = {
/* Frequency of the prescale counter */
DEFINE_PROP_UINT32("prescale-clk", MPS2FPGAIO, prescale_clk, 20000000),
+ /* Number of LEDs controlled by LED0 register */
+ DEFINE_PROP_UINT32("num-leds", MPS2FPGAIO, num_leds, 2),
+ DEFINE_PROP_BOOL("has-switches", MPS2FPGAIO, has_switches, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c
index ce1dfe9356..140a4b9ceb 100644
--- a/hw/misc/mps2-scc.c
+++ b/hw/misc/mps2-scc.c
@@ -13,7 +13,7 @@
* found in the FPGA images of MPS2 development boards.
*
* Documentation of it can be found in the MPS2 TRM:
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.100112_0100_03_en/index.html
+ * https://developer.arm.com/documentation/100112/latest/
* and also in the Application Notes documenting individual FPGA images.
*/
@@ -31,8 +31,11 @@
REG32(CFG0, 0)
REG32(CFG1, 4)
+REG32(CFG2, 8)
REG32(CFG3, 0xc)
REG32(CFG4, 0x10)
+REG32(CFG5, 0x14)
+REG32(CFG6, 0x18)
REG32(CFGDATA_RTN, 0xa0)
REG32(CFGDATA_OUT, 0xa4)
REG32(CFGCTRL, 0xa8)
@@ -49,6 +52,12 @@ REG32(DLL, 0x100)
REG32(AID, 0xFF8)
REG32(ID, 0xFFC)
+static int scc_partno(MPS2SCC *s)
+{
+ /* Return the partno field of the SCC_ID (0x524, 0x511, etc) */
+ return extract32(s->id, 4, 8);
+}
+
/* Handle a write via the SYS_CFG channel to the specified function/device.
* Return false on error (reported to guest via SYS_CFGCTRL ERROR bit).
*/
@@ -57,7 +66,7 @@ static bool scc_cfg_write(MPS2SCC *s, unsigned function,
{
trace_mps2_scc_cfg_write(function, device, value);
- if (function != 1 || device >= NUM_OSCCLK) {
+ if (function != 1 || device >= s->num_oscclk) {
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 SCC config write: bad function %d device %d\n",
function, device);
@@ -75,7 +84,7 @@ static bool scc_cfg_write(MPS2SCC *s, unsigned function,
static bool scc_cfg_read(MPS2SCC *s, unsigned function,
unsigned device, uint32_t *value)
{
- if (function != 1 || device >= NUM_OSCCLK) {
+ if (function != 1 || device >= s->num_oscclk) {
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 SCC config read: bad function %d device %d\n",
function, device);
@@ -100,7 +109,18 @@ static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
case A_CFG1:
r = s->cfg1;
break;
+ case A_CFG2:
+ if (scc_partno(s) != 0x524) {
+ /* CFG2 reserved on other boards */
+ goto bad_offset;
+ }
+ r = s->cfg2;
+ break;
case A_CFG3:
+ if (scc_partno(s) == 0x524) {
+ /* CFG3 reserved on AN524 */
+ goto bad_offset;
+ }
/* These are user-settable DIP switches on the board. We don't
* model that, so just return zeroes.
*/
@@ -109,6 +129,20 @@ static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
case A_CFG4:
r = s->cfg4;
break;
+ case A_CFG5:
+ if (scc_partno(s) != 0x524) {
+ /* CFG5 reserved on other boards */
+ goto bad_offset;
+ }
+ r = s->cfg5;
+ break;
+ case A_CFG6:
+ if (scc_partno(s) != 0x524) {
+ /* CFG6 reserved on other boards */
+ goto bad_offset;
+ }
+ r = s->cfg6;
+ break;
case A_CFGDATA_RTN:
r = s->cfgdata_rtn;
break;
@@ -131,6 +165,7 @@ static uint64_t mps2_scc_read(void *opaque, hwaddr offset, unsigned size)
r = s->id;
break;
default:
+ bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 SCC read: bad offset %x\n", (int) offset);
r = 0;
@@ -159,6 +194,30 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value,
led_set_state(s->led[i], extract32(value, i, 1));
}
break;
+ case A_CFG2:
+ if (scc_partno(s) != 0x524) {
+ /* CFG2 reserved on other boards */
+ goto bad_offset;
+ }
+ /* AN524: QSPI Select signal */
+ s->cfg2 = value;
+ break;
+ case A_CFG5:
+ if (scc_partno(s) != 0x524) {
+ /* CFG5 reserved on other boards */
+ goto bad_offset;
+ }
+ /* AN524: ACLK frequency in Hz */
+ s->cfg5 = value;
+ break;
+ case A_CFG6:
+ if (scc_partno(s) != 0x524) {
+ /* CFG6 reserved on other boards */
+ goto bad_offset;
+ }
+ /* AN524: Clock divider for BRAM */
+ s->cfg6 = value;
+ break;
case A_CFGDATA_OUT:
s->cfgdata_out = value;
break;
@@ -202,6 +261,7 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value,
s->dll = deposit32(s->dll, 24, 8, extract32(value, 24, 8));
break;
default:
+ bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"MPS2 SCC write: bad offset 0x%x\n", (int) offset);
break;
@@ -222,12 +282,15 @@ static void mps2_scc_reset(DeviceState *dev)
trace_mps2_scc_reset();
s->cfg0 = 0;
s->cfg1 = 0;
+ s->cfg2 = 0;
+ s->cfg5 = 0;
+ s->cfg6 = 0;
s->cfgdata_rtn = 0;
s->cfgdata_out = 0;
s->cfgctrl = 0x100000;
s->cfgstat = 0;
s->dll = 0xffff0001;
- for (i = 0; i < NUM_OSCCLK; i++) {
+ for (i = 0; i < s->num_oscclk; i++) {
s->oscclk[i] = s->oscclk_reset[i];
}
for (i = 0; i < ARRAY_SIZE(s->led); i++) {
@@ -254,21 +317,28 @@ static void mps2_scc_realize(DeviceState *dev, Error **errp)
LED_COLOR_GREEN, name);
g_free(name);
}
+
+ s->oscclk = g_new0(uint32_t, s->num_oscclk);
}
static const VMStateDescription mps2_scc_vmstate = {
.name = "mps2-scc",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (VMStateField[]) {
VMSTATE_UINT32(cfg0, MPS2SCC),
VMSTATE_UINT32(cfg1, MPS2SCC),
+ VMSTATE_UINT32(cfg2, MPS2SCC),
+ /* cfg3, cfg4 are read-only so need not be migrated */
+ VMSTATE_UINT32(cfg5, MPS2SCC),
+ VMSTATE_UINT32(cfg6, MPS2SCC),
VMSTATE_UINT32(cfgdata_rtn, MPS2SCC),
VMSTATE_UINT32(cfgdata_out, MPS2SCC),
VMSTATE_UINT32(cfgctrl, MPS2SCC),
VMSTATE_UINT32(cfgstat, MPS2SCC),
VMSTATE_UINT32(dll, MPS2SCC),
- VMSTATE_UINT32_ARRAY(oscclk, MPS2SCC, NUM_OSCCLK),
+ VMSTATE_VARRAY_UINT32(oscclk, MPS2SCC, num_oscclk,
+ 0, vmstate_info_uint32, uint32_t),
VMSTATE_END_OF_LIST()
}
};
@@ -280,14 +350,13 @@ static Property mps2_scc_properties[] = {
DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0),
DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0),
DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0),
- /* These are the initial settings for the source clocks on the board.
+ /*
+ * These are the initial settings for the source clocks on the board.
* In hardware they can be configured via a config file read by the
* motherboard configuration controller to suit the FPGA image.
- * These default values are used by most of the standard FPGA images.
*/
- DEFINE_PROP_UINT32("oscclk0", MPS2SCC, oscclk_reset[0], 50000000),
- DEFINE_PROP_UINT32("oscclk1", MPS2SCC, oscclk_reset[1], 24576000),
- DEFINE_PROP_UINT32("oscclk2", MPS2SCC, oscclk_reset[2], 25000000),
+ DEFINE_PROP_ARRAY("oscclk", MPS2SCC, num_oscclk, oscclk_reset,
+ qdev_prop_uint32, uint32_t),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/net/meson.build b/hw/net/meson.build
index 4a7051b54a..af0749c42b 100644
--- a/hw/net/meson.build
+++ b/hw/net/meson.build
@@ -35,6 +35,7 @@ softmmu_ss.add(when: 'CONFIG_I82596_COMMON', if_true: files('i82596.c'))
softmmu_ss.add(when: 'CONFIG_SUNHME', if_true: files('sunhme.c'))
softmmu_ss.add(when: 'CONFIG_FTGMAC100', if_true: files('ftgmac100.c'))
softmmu_ss.add(when: 'CONFIG_SUNGEM', if_true: files('sungem.c'))
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c'))
softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c'))
softmmu_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c'))
diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c
new file mode 100644
index 0000000000..714a742ba7
--- /dev/null
+++ b/hw/net/npcm7xx_emc.c
@@ -0,0 +1,857 @@
+/*
+ * Nuvoton NPCM7xx EMC Module
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ *
+ * Unsupported/unimplemented features:
+ * - MCMDR.FDUP (full duplex) is ignored, half duplex is not supported
+ * - Only CAM0 is supported, CAM[1-15] are not
+ * - writes to CAMEN.[1-15] are ignored, these bits always read as zeroes
+ * - MII is not implemented, MIIDA.BUSY and MIID always return zero
+ * - MCMDR.LBK is not implemented
+ * - MCMDR.{OPMOD,ENSQE,AEP,ARP} are not supported
+ * - H/W FIFOs are not supported, MCMDR.FFTCR is ignored
+ * - MGSTA.SQE is not supported
+ * - pause and control frames are not implemented
+ * - MGSTA.CCNT is not supported
+ * - MPCNT, DMARFS are not implemented
+ */
+
+#include "qemu/osdep.h"
+
+/* For crc32 */
+#include <zlib.h>
+
+#include "qemu-common.h"
+#include "hw/irq.h"
+#include "hw/qdev-clock.h"
+#include "hw/qdev-properties.h"
+#include "hw/net/npcm7xx_emc.h"
+#include "net/eth.h"
+#include "migration/vmstate.h"
+#include "qemu/bitops.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+#include "sysemu/dma.h"
+#include "trace.h"
+
+#define CRC_LENGTH 4
+
+/*
+ * The maximum size of a (layer 2) ethernet frame as defined by 802.3.
+ * 1518 = 6(dest macaddr) + 6(src macaddr) + 2(proto) + 4(crc) + 1500(payload)
+ * This does not include an additional 4 for the vlan field (802.1q).
+ */
+#define MAX_ETH_FRAME_SIZE 1518
+
+static const char *emc_reg_name(int regno)
+{
+#define REG(name) case REG_ ## name: return #name;
+ switch (regno) {
+ REG(CAMCMR)
+ REG(CAMEN)
+ REG(TXDLSA)
+ REG(RXDLSA)
+ REG(MCMDR)
+ REG(MIID)
+ REG(MIIDA)
+ REG(FFTCR)
+ REG(TSDR)
+ REG(RSDR)
+ REG(DMARFC)
+ REG(MIEN)
+ REG(MISTA)
+ REG(MGSTA)
+ REG(MPCNT)
+ REG(MRPC)
+ REG(MRPCC)
+ REG(MREPC)
+ REG(DMARFS)
+ REG(CTXDSA)
+ REG(CTXBSA)
+ REG(CRXDSA)
+ REG(CRXBSA)
+ case REG_CAMM_BASE + 0: return "CAM0M";
+ case REG_CAML_BASE + 0: return "CAM0L";
+ case REG_CAMM_BASE + 2 ... REG_CAMML_LAST:
+ /* Only CAM0 is supported, fold the others into something simple. */
+ if (regno & 1) {
+ return "CAM<n>L";
+ } else {
+ return "CAM<n>M";
+ }
+ default: return "UNKNOWN";
+ }
+#undef REG
+}
+
+static void emc_reset(NPCM7xxEMCState *emc)
+{
+ trace_npcm7xx_emc_reset(emc->emc_num);
+
+ memset(&emc->regs[0], 0, sizeof(emc->regs));
+
+ /* These regs have non-zero reset values. */
+ emc->regs[REG_TXDLSA] = 0xfffffffc;
+ emc->regs[REG_RXDLSA] = 0xfffffffc;
+ emc->regs[REG_MIIDA] = 0x00900000;
+ emc->regs[REG_FFTCR] = 0x0101;
+ emc->regs[REG_DMARFC] = 0x0800;
+ emc->regs[REG_MPCNT] = 0x7fff;
+
+ emc->tx_active = false;
+ emc->rx_active = false;
+}
+
+static void npcm7xx_emc_reset(DeviceState *dev)
+{
+ NPCM7xxEMCState *emc = NPCM7XX_EMC(dev);
+ emc_reset(emc);
+}
+
+static void emc_soft_reset(NPCM7xxEMCState *emc)
+{
+ /*
+ * The docs say at least MCMDR.{LBK,OPMOD} bits are not changed during a
+ * soft reset, but does not go into further detail. For now, KISS.
+ */
+ uint32_t mcmdr = emc->regs[REG_MCMDR];
+ emc_reset(emc);
+ emc->regs[REG_MCMDR] = mcmdr & (REG_MCMDR_LBK | REG_MCMDR_OPMOD);
+
+ qemu_set_irq(emc->tx_irq, 0);
+ qemu_set_irq(emc->rx_irq, 0);
+}
+
+static void emc_set_link(NetClientState *nc)
+{
+ /* Nothing to do yet. */
+}
+
+/* MISTA.TXINTR is the union of the individual bits with their enables. */
+static void emc_update_mista_txintr(NPCM7xxEMCState *emc)
+{
+ /* Only look at the bits we support. */
+ uint32_t mask = (REG_MISTA_TXBERR |
+ REG_MISTA_TDU |
+ REG_MISTA_TXCP);
+ if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & mask) {
+ emc->regs[REG_MISTA] |= REG_MISTA_TXINTR;
+ } else {
+ emc->regs[REG_MISTA] &= ~REG_MISTA_TXINTR;
+ }
+}
+
+/* MISTA.RXINTR is the union of the individual bits with their enables. */
+static void emc_update_mista_rxintr(NPCM7xxEMCState *emc)
+{
+ /* Only look at the bits we support. */
+ uint32_t mask = (REG_MISTA_RXBERR |
+ REG_MISTA_RDU |
+ REG_MISTA_RXGD);
+ if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & mask) {
+ emc->regs[REG_MISTA] |= REG_MISTA_RXINTR;
+ } else {
+ emc->regs[REG_MISTA] &= ~REG_MISTA_RXINTR;
+ }
+}
+
+/* N.B. emc_update_mista_txintr must have already been called. */
+static void emc_update_tx_irq(NPCM7xxEMCState *emc)
+{
+ int level = !!(emc->regs[REG_MISTA] &
+ emc->regs[REG_MIEN] &
+ REG_MISTA_TXINTR);
+ trace_npcm7xx_emc_update_tx_irq(level);
+ qemu_set_irq(emc->tx_irq, level);
+}
+
+/* N.B. emc_update_mista_rxintr must have already been called. */
+static void emc_update_rx_irq(NPCM7xxEMCState *emc)
+{
+ int level = !!(emc->regs[REG_MISTA] &
+ emc->regs[REG_MIEN] &
+ REG_MISTA_RXINTR);
+ trace_npcm7xx_emc_update_rx_irq(level);
+ qemu_set_irq(emc->rx_irq, level);
+}
+
+/* Update IRQ states due to changes in MIEN,MISTA. */
+static void emc_update_irq_from_reg_change(NPCM7xxEMCState *emc)
+{
+ emc_update_mista_txintr(emc);
+ emc_update_tx_irq(emc);
+
+ emc_update_mista_rxintr(emc);
+ emc_update_rx_irq(emc);
+}
+
+static int emc_read_tx_desc(dma_addr_t addr, NPCM7xxEMCTxDesc *desc)
+{
+ if (dma_memory_read(&address_space_memory, addr, desc, sizeof(*desc))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return -1;
+ }
+ desc->flags = le32_to_cpu(desc->flags);
+ desc->txbsa = le32_to_cpu(desc->txbsa);
+ desc->status_and_length = le32_to_cpu(desc->status_and_length);
+ desc->ntxdsa = le32_to_cpu(desc->ntxdsa);
+ return 0;
+}
+
+static int emc_write_tx_desc(const NPCM7xxEMCTxDesc *desc, dma_addr_t addr)
+{
+ NPCM7xxEMCTxDesc le_desc;
+
+ le_desc.flags = cpu_to_le32(desc->flags);
+ le_desc.txbsa = cpu_to_le32(desc->txbsa);
+ le_desc.status_and_length = cpu_to_le32(desc->status_and_length);
+ le_desc.ntxdsa = cpu_to_le32(desc->ntxdsa);
+ if (dma_memory_write(&address_space_memory, addr, &le_desc,
+ sizeof(le_desc))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return -1;
+ }
+ return 0;
+}
+
+static int emc_read_rx_desc(dma_addr_t addr, NPCM7xxEMCRxDesc *desc)
+{
+ if (dma_memory_read(&address_space_memory, addr, desc, sizeof(*desc))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read descriptor @ 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return -1;
+ }
+ desc->status_and_length = le32_to_cpu(desc->status_and_length);
+ desc->rxbsa = le32_to_cpu(desc->rxbsa);
+ desc->reserved = le32_to_cpu(desc->reserved);
+ desc->nrxdsa = le32_to_cpu(desc->nrxdsa);
+ return 0;
+}
+
+static int emc_write_rx_desc(const NPCM7xxEMCRxDesc *desc, dma_addr_t addr)
+{
+ NPCM7xxEMCRxDesc le_desc;
+
+ le_desc.status_and_length = cpu_to_le32(desc->status_and_length);
+ le_desc.rxbsa = cpu_to_le32(desc->rxbsa);
+ le_desc.reserved = cpu_to_le32(desc->reserved);
+ le_desc.nrxdsa = cpu_to_le32(desc->nrxdsa);
+ if (dma_memory_write(&address_space_memory, addr, &le_desc,
+ sizeof(le_desc))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to write descriptor @ 0x%"
+ HWADDR_PRIx "\n", __func__, addr);
+ return -1;
+ }
+ return 0;
+}
+
+static void emc_set_mista(NPCM7xxEMCState *emc, uint32_t flags)
+{
+ trace_npcm7xx_emc_set_mista(flags);
+ emc->regs[REG_MISTA] |= flags;
+ if (extract32(flags, 16, 16)) {
+ emc_update_mista_txintr(emc);
+ }
+ if (extract32(flags, 0, 16)) {
+ emc_update_mista_rxintr(emc);
+ }
+}
+
+static void emc_halt_tx(NPCM7xxEMCState *emc, uint32_t mista_flag)
+{
+ emc->tx_active = false;
+ emc_set_mista(emc, mista_flag);
+}
+
+static void emc_halt_rx(NPCM7xxEMCState *emc, uint32_t mista_flag)
+{
+ emc->rx_active = false;
+ emc_set_mista(emc, mista_flag);
+}
+
+static void emc_set_next_tx_descriptor(NPCM7xxEMCState *emc,
+ const NPCM7xxEMCTxDesc *tx_desc,
+ uint32_t desc_addr)
+{
+ /* Update the current descriptor, if only to reset the owner flag. */
+ if (emc_write_tx_desc(tx_desc, desc_addr)) {
+ /*
+ * We just read it so this shouldn't generally happen.
+ * Error already reported.
+ */
+ emc_set_mista(emc, REG_MISTA_TXBERR);
+ }
+ emc->regs[REG_CTXDSA] = TX_DESC_NTXDSA(tx_desc->ntxdsa);
+}
+
+static void emc_set_next_rx_descriptor(NPCM7xxEMCState *emc,
+ const NPCM7xxEMCRxDesc *rx_desc,
+ uint32_t desc_addr)
+{
+ /* Update the current descriptor, if only to reset the owner flag. */
+ if (emc_write_rx_desc(rx_desc, desc_addr)) {
+ /*
+ * We just read it so this shouldn't generally happen.
+ * Error already reported.
+ */
+ emc_set_mista(emc, REG_MISTA_RXBERR);
+ }
+ emc->regs[REG_CRXDSA] = RX_DESC_NRXDSA(rx_desc->nrxdsa);
+}
+
+static void emc_try_send_next_packet(NPCM7xxEMCState *emc)
+{
+ /* Working buffer for sending out packets. Most packets fit in this. */
+#define TX_BUFFER_SIZE 2048
+ uint8_t tx_send_buffer[TX_BUFFER_SIZE];
+ uint32_t desc_addr = TX_DESC_NTXDSA(emc->regs[REG_CTXDSA]);
+ NPCM7xxEMCTxDesc tx_desc;
+ uint32_t next_buf_addr, length;
+ uint8_t *buf;
+ g_autofree uint8_t *malloced_buf = NULL;
+
+ if (emc_read_tx_desc(desc_addr, &tx_desc)) {
+ /* Error reading descriptor, already reported. */
+ emc_halt_tx(emc, REG_MISTA_TXBERR);
+ emc_update_tx_irq(emc);
+ return;
+ }
+
+ /* Nothing we can do if we don't own the descriptor. */
+ if (!(tx_desc.flags & TX_DESC_FLAG_OWNER_MASK)) {
+ trace_npcm7xx_emc_cpu_owned_desc(desc_addr);
+ emc_halt_tx(emc, REG_MISTA_TDU);
+ emc_update_tx_irq(emc);
+ return;
+ }
+
+ /* Give the descriptor back regardless of what happens. */
+ tx_desc.flags &= ~TX_DESC_FLAG_OWNER_MASK;
+ tx_desc.status_and_length &= 0xffff;
+
+ /*
+ * Despite the h/w documentation saying the tx buffer is word aligned,
+ * the linux driver does not word align the buffer. There is value in not
+ * aligning the buffer: See the description of NET_IP_ALIGN in linux
+ * kernel sources.
+ */
+ next_buf_addr = tx_desc.txbsa;
+ emc->regs[REG_CTXBSA] = next_buf_addr;
+ length = TX_DESC_PKT_LEN(tx_desc.status_and_length);
+ buf = &tx_send_buffer[0];
+
+ if (length > sizeof(tx_send_buffer)) {
+ malloced_buf = g_malloc(length);
+ buf = malloced_buf;
+ }
+
+ if (dma_memory_read(&address_space_memory, next_buf_addr, buf, length)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Failed to read packet @ 0x%x\n",
+ __func__, next_buf_addr);
+ emc_set_mista(emc, REG_MISTA_TXBERR);
+ emc_set_next_tx_descriptor(emc, &tx_desc, desc_addr);
+ emc_update_tx_irq(emc);
+ trace_npcm7xx_emc_tx_done(emc->regs[REG_CTXDSA]);
+ return;
+ }
+
+ if ((tx_desc.flags & TX_DESC_FLAG_PADEN) && (length < MIN_PACKET_LENGTH)) {
+ memset(buf + length, 0, MIN_PACKET_LENGTH - length);
+ length = MIN_PACKET_LENGTH;
+ }
+
+ /* N.B. emc_receive can get called here. */
+ qemu_send_packet(qemu_get_queue(emc->nic), buf, length);
+ trace_npcm7xx_emc_sent_packet(length);
+
+ tx_desc.status_and_length |= TX_DESC_STATUS_TXCP;
+ if (tx_desc.flags & TX_DESC_FLAG_INTEN) {
+ emc_set_mista(emc, REG_MISTA_TXCP);
+ }
+ if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & REG_MISTA_TXINTR) {
+ tx_desc.status_and_length |= TX_DESC_STATUS_TXINTR;
+ }
+
+ emc_set_next_tx_descriptor(emc, &tx_desc, desc_addr);
+ emc_update_tx_irq(emc);
+ trace_npcm7xx_emc_tx_done(emc->regs[REG_CTXDSA]);
+}
+
+static bool emc_can_receive(NetClientState *nc)
+{
+ NPCM7xxEMCState *emc = NPCM7XX_EMC(qemu_get_nic_opaque(nc));
+
+ bool can_receive = emc->rx_active;
+ trace_npcm7xx_emc_can_receive(can_receive);
+ return can_receive;
+}
+
+/* If result is false then *fail_reason contains the reason. */
+static bool emc_receive_filter1(NPCM7xxEMCState *emc, const uint8_t *buf,
+ size_t len, const char **fail_reason)
+{
+ eth_pkt_types_e pkt_type = get_eth_packet_type(PKT_GET_ETH_HDR(buf));
+
+ switch (pkt_type) {
+ case ETH_PKT_BCAST:
+ if (emc->regs[REG_CAMCMR] & REG_CAMCMR_CCAM) {
+ return true;
+ } else {
+ *fail_reason = "Broadcast packet disabled";
+ return !!(emc->regs[REG_CAMCMR] & REG_CAMCMR_ABP);
+ }
+ case ETH_PKT_MCAST:
+ if (emc->regs[REG_CAMCMR] & REG_CAMCMR_CCAM) {
+ return true;
+ } else {
+ *fail_reason = "Multicast packet disabled";
+ return !!(emc->regs[REG_CAMCMR] & REG_CAMCMR_AMP);
+ }
+ case ETH_PKT_UCAST: {
+ bool matches;
+ if (emc->regs[REG_CAMCMR] & REG_CAMCMR_AUP) {
+ return true;
+ }
+ matches = ((emc->regs[REG_CAMCMR] & REG_CAMCMR_ECMP) &&
+ /* We only support one CAM register, CAM0. */
+ (emc->regs[REG_CAMEN] & (1 << 0)) &&
+ memcmp(buf, emc->conf.macaddr.a, ETH_ALEN) == 0);
+ if (emc->regs[REG_CAMCMR] & REG_CAMCMR_CCAM) {
+ *fail_reason = "MACADDR matched, comparison complemented";
+ return !matches;
+ } else {
+ *fail_reason = "MACADDR didn't match";
+ return matches;
+ }
+ }
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static bool emc_receive_filter(NPCM7xxEMCState *emc, const uint8_t *buf,
+ size_t len)
+{
+ const char *fail_reason = NULL;
+ bool ok = emc_receive_filter1(emc, buf, len, &fail_reason);
+ if (!ok) {
+ trace_npcm7xx_emc_packet_filtered_out(fail_reason);
+ }
+ return ok;
+}
+
+static ssize_t emc_receive(NetClientState *nc, const uint8_t *buf, size_t len1)
+{
+ NPCM7xxEMCState *emc = NPCM7XX_EMC(qemu_get_nic_opaque(nc));
+ const uint32_t len = len1;
+ size_t max_frame_len;
+ bool long_frame;
+ uint32_t desc_addr;
+ NPCM7xxEMCRxDesc rx_desc;
+ uint32_t crc;
+ uint8_t *crc_ptr;
+ uint32_t buf_addr;
+
+ trace_npcm7xx_emc_receiving_packet(len);
+
+ if (!emc_can_receive(nc)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Unexpected packet\n", __func__);
+ return -1;
+ }
+
+ if (len < ETH_HLEN ||
+ /* Defensive programming: drop unsupportable large packets. */
+ len > 0xffff - CRC_LENGTH) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Dropped frame of %u bytes\n",
+ __func__, len);
+ return len;
+ }
+
+ /*
+ * DENI is set if EMC received the Length/Type field of the incoming
+ * packet, so it will be set regardless of what happens next.
+ */
+ emc_set_mista(emc, REG_MISTA_DENI);
+
+ if (!emc_receive_filter(emc, buf, len)) {
+ emc_update_rx_irq(emc);
+ return len;
+ }
+
+ /* Huge frames (> DMARFC) are dropped. */
+ max_frame_len = REG_DMARFC_RXMS(emc->regs[REG_DMARFC]);
+ if (len + CRC_LENGTH > max_frame_len) {
+ trace_npcm7xx_emc_packet_dropped(len);
+ emc_set_mista(emc, REG_MISTA_DFOI);
+ emc_update_rx_irq(emc);
+ return len;
+ }
+
+ /*
+ * Long Frames (> MAX_ETH_FRAME_SIZE) are also dropped, unless MCMDR.ALP
+ * is set.
+ */
+ long_frame = false;
+ if (len + CRC_LENGTH > MAX_ETH_FRAME_SIZE) {
+ if (emc->regs[REG_MCMDR] & REG_MCMDR_ALP) {
+ long_frame = true;
+ } else {
+ trace_npcm7xx_emc_packet_dropped(len);
+ emc_set_mista(emc, REG_MISTA_PTLE);
+ emc_update_rx_irq(emc);
+ return len;
+ }
+ }
+
+ desc_addr = RX_DESC_NRXDSA(emc->regs[REG_CRXDSA]);
+ if (emc_read_rx_desc(desc_addr, &rx_desc)) {
+ /* Error reading descriptor, already reported. */
+ emc_halt_rx(emc, REG_MISTA_RXBERR);
+ emc_update_rx_irq(emc);
+ return len;
+ }
+
+ /* Nothing we can do if we don't own the descriptor. */
+ if (!(rx_desc.status_and_length & RX_DESC_STATUS_OWNER_MASK)) {
+ trace_npcm7xx_emc_cpu_owned_desc(desc_addr);
+ emc_halt_rx(emc, REG_MISTA_RDU);
+ emc_update_rx_irq(emc);
+ return len;
+ }
+
+ crc = 0;
+ crc_ptr = (uint8_t *) &crc;
+ if (!(emc->regs[REG_MCMDR] & REG_MCMDR_SPCRC)) {
+ crc = cpu_to_be32(crc32(~0, buf, len));
+ }
+
+ /* Give the descriptor back regardless of what happens. */
+ rx_desc.status_and_length &= ~RX_DESC_STATUS_OWNER_MASK;
+
+ buf_addr = rx_desc.rxbsa;
+ emc->regs[REG_CRXBSA] = buf_addr;
+ if (dma_memory_write(&address_space_memory, buf_addr, buf, len) ||
+ (!(emc->regs[REG_MCMDR] & REG_MCMDR_SPCRC) &&
+ dma_memory_write(&address_space_memory, buf_addr + len, crc_ptr,
+ 4))) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bus error writing packet\n",
+ __func__);
+ emc_set_mista(emc, REG_MISTA_RXBERR);
+ emc_set_next_rx_descriptor(emc, &rx_desc, desc_addr);
+ emc_update_rx_irq(emc);
+ trace_npcm7xx_emc_rx_done(emc->regs[REG_CRXDSA]);
+ return len;
+ }
+
+ trace_npcm7xx_emc_received_packet(len);
+
+ /* Note: We've already verified len+4 <= 0xffff. */
+ rx_desc.status_and_length = len;
+ if (!(emc->regs[REG_MCMDR] & REG_MCMDR_SPCRC)) {
+ rx_desc.status_and_length += 4;
+ }
+ rx_desc.status_and_length |= RX_DESC_STATUS_RXGD;
+ emc_set_mista(emc, REG_MISTA_RXGD);
+
+ if (emc->regs[REG_MISTA] & emc->regs[REG_MIEN] & REG_MISTA_RXINTR) {
+ rx_desc.status_and_length |= RX_DESC_STATUS_RXINTR;
+ }
+ if (long_frame) {
+ rx_desc.status_and_length |= RX_DESC_STATUS_PTLE;
+ }
+
+ emc_set_next_rx_descriptor(emc, &rx_desc, desc_addr);
+ emc_update_rx_irq(emc);
+ trace_npcm7xx_emc_rx_done(emc->regs[REG_CRXDSA]);
+ return len;
+}
+
+static void emc_try_receive_next_packet(NPCM7xxEMCState *emc)
+{
+ if (emc_can_receive(qemu_get_queue(emc->nic))) {
+ qemu_flush_queued_packets(qemu_get_queue(emc->nic));
+ }
+}
+
+static uint64_t npcm7xx_emc_read(void *opaque, hwaddr offset, unsigned size)
+{
+ NPCM7xxEMCState *emc = opaque;
+ uint32_t reg = offset / sizeof(uint32_t);
+ uint32_t result;
+
+ if (reg >= NPCM7XX_NUM_EMC_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Invalid offset 0x%04" HWADDR_PRIx "\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (reg) {
+ case REG_MIID:
+ /*
+ * We don't implement MII. For determinism, always return zero as
+ * writes record the last value written for debugging purposes.
+ */
+ qemu_log_mask(LOG_UNIMP, "%s: Read of MIID, returning 0\n", __func__);
+ result = 0;
+ break;
+ case REG_TSDR:
+ case REG_RSDR:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Read of write-only reg, %s/%d\n",
+ __func__, emc_reg_name(reg), reg);
+ return 0;
+ default:
+ result = emc->regs[reg];
+ break;
+ }
+
+ trace_npcm7xx_emc_reg_read(emc->emc_num, result, emc_reg_name(reg), reg);
+ return result;
+}
+
+static void npcm7xx_emc_write(void *opaque, hwaddr offset,
+ uint64_t v, unsigned size)
+{
+ NPCM7xxEMCState *emc = opaque;
+ uint32_t reg = offset / sizeof(uint32_t);
+ uint32_t value = v;
+
+ g_assert(size == sizeof(uint32_t));
+
+ if (reg >= NPCM7XX_NUM_EMC_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Invalid offset 0x%04" HWADDR_PRIx "\n",
+ __func__, offset);
+ return;
+ }
+
+ trace_npcm7xx_emc_reg_write(emc->emc_num, emc_reg_name(reg), reg, value);
+
+ switch (reg) {
+ case REG_CAMCMR:
+ emc->regs[reg] = value;
+ break;
+ case REG_CAMEN:
+ /* Only CAM0 is supported, don't pretend otherwise. */
+ if (value & ~1) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Only CAM0 is supported, cannot enable others"
+ ": 0x%x\n",
+ __func__, value);
+ }
+ emc->regs[reg] = value & 1;
+ break;
+ case REG_CAMM_BASE + 0:
+ emc->regs[reg] = value;
+ emc->conf.macaddr.a[0] = value >> 24;
+ emc->conf.macaddr.a[1] = value >> 16;
+ emc->conf.macaddr.a[2] = value >> 8;
+ emc->conf.macaddr.a[3] = value >> 0;
+ break;
+ case REG_CAML_BASE + 0:
+ emc->regs[reg] = value;
+ emc->conf.macaddr.a[4] = value >> 24;
+ emc->conf.macaddr.a[5] = value >> 16;
+ break;
+ case REG_MCMDR: {
+ uint32_t prev;
+ if (value & REG_MCMDR_SWR) {
+ emc_soft_reset(emc);
+ /* On h/w the reset happens over multiple cycles. For now KISS. */
+ break;
+ }
+ prev = emc->regs[reg];
+ emc->regs[reg] = value;
+ /* Update tx state. */
+ if (!(prev & REG_MCMDR_TXON) &&
+ (value & REG_MCMDR_TXON)) {
+ emc->regs[REG_CTXDSA] = emc->regs[REG_TXDLSA];
+ /*
+ * Linux kernel turns TX on with CPU still holding descriptor,
+ * which suggests we should wait for a write to TSDR before trying
+ * to send a packet: so we don't send one here.
+ */
+ } else if ((prev & REG_MCMDR_TXON) &&
+ !(value & REG_MCMDR_TXON)) {
+ emc->regs[REG_MGSTA] |= REG_MGSTA_TXHA;
+ }
+ if (!(value & REG_MCMDR_TXON)) {
+ emc_halt_tx(emc, 0);
+ }
+ /* Update rx state. */
+ if (!(prev & REG_MCMDR_RXON) &&
+ (value & REG_MCMDR_RXON)) {
+ emc->regs[REG_CRXDSA] = emc->regs[REG_RXDLSA];
+ } else if ((prev & REG_MCMDR_RXON) &&
+ !(value & REG_MCMDR_RXON)) {
+ emc->regs[REG_MGSTA] |= REG_MGSTA_RXHA;
+ }
+ if (!(value & REG_MCMDR_RXON)) {
+ emc_halt_rx(emc, 0);
+ }
+ break;
+ }
+ case REG_TXDLSA:
+ case REG_RXDLSA:
+ case REG_DMARFC:
+ case REG_MIID:
+ emc->regs[reg] = value;
+ break;
+ case REG_MIEN:
+ emc->regs[reg] = value;
+ emc_update_irq_from_reg_change(emc);
+ break;
+ case REG_MISTA:
+ /* Clear the bits that have 1 in "value". */
+ emc->regs[reg] &= ~value;
+ emc_update_irq_from_reg_change(emc);
+ break;
+ case REG_MGSTA:
+ /* Clear the bits that have 1 in "value". */
+ emc->regs[reg] &= ~value;
+ break;
+ case REG_TSDR:
+ if (emc->regs[REG_MCMDR] & REG_MCMDR_TXON) {
+ emc->tx_active = true;
+ /* Keep trying to send packets until we run out. */
+ while (emc->tx_active) {
+ emc_try_send_next_packet(emc);
+ }
+ }
+ break;
+ case REG_RSDR:
+ if (emc->regs[REG_MCMDR] & REG_MCMDR_RXON) {
+ emc->rx_active = true;
+ emc_try_receive_next_packet(emc);
+ }
+ break;
+ case REG_MIIDA:
+ emc->regs[reg] = value & ~REG_MIIDA_BUSY;
+ break;
+ case REG_MRPC:
+ case REG_MRPCC:
+ case REG_MREPC:
+ case REG_CTXDSA:
+ case REG_CTXBSA:
+ case REG_CRXDSA:
+ case REG_CRXBSA:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Write to read-only reg %s/%d\n",
+ __func__, emc_reg_name(reg), reg);
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: Write to unimplemented reg %s/%d\n",
+ __func__, emc_reg_name(reg), reg);
+ break;
+ }
+}
+
+static const struct MemoryRegionOps npcm7xx_emc_ops = {
+ .read = npcm7xx_emc_read,
+ .write = npcm7xx_emc_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+};
+
+static void emc_cleanup(NetClientState *nc)
+{
+ /* Nothing to do yet. */
+}
+
+static NetClientInfo net_npcm7xx_emc_info = {
+ .type = NET_CLIENT_DRIVER_NIC,
+ .size = sizeof(NICState),
+ .can_receive = emc_can_receive,
+ .receive = emc_receive,
+ .cleanup = emc_cleanup,
+ .link_status_changed = emc_set_link,
+};
+
+static void npcm7xx_emc_realize(DeviceState *dev, Error **errp)
+{
+ NPCM7xxEMCState *emc = NPCM7XX_EMC(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(emc);
+
+ memory_region_init_io(&emc->iomem, OBJECT(emc), &npcm7xx_emc_ops, emc,
+ TYPE_NPCM7XX_EMC, 4 * KiB);
+ sysbus_init_mmio(sbd, &emc->iomem);
+ sysbus_init_irq(sbd, &emc->tx_irq);
+ sysbus_init_irq(sbd, &emc->rx_irq);
+
+ qemu_macaddr_default_if_unset(&emc->conf.macaddr);
+ emc->nic = qemu_new_nic(&net_npcm7xx_emc_info, &emc->conf,
+ object_get_typename(OBJECT(dev)), dev->id, emc);
+ qemu_format_nic_info_str(qemu_get_queue(emc->nic), emc->conf.macaddr.a);
+}
+
+static void npcm7xx_emc_unrealize(DeviceState *dev)
+{
+ NPCM7xxEMCState *emc = NPCM7XX_EMC(dev);
+
+ qemu_del_nic(emc->nic);
+}
+
+static const VMStateDescription vmstate_npcm7xx_emc = {
+ .name = TYPE_NPCM7XX_EMC,
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(emc_num, NPCM7xxEMCState),
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxEMCState, NPCM7XX_NUM_EMC_REGS),
+ VMSTATE_BOOL(tx_active, NPCM7xxEMCState),
+ VMSTATE_BOOL(rx_active, NPCM7xxEMCState),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static Property npcm7xx_emc_properties[] = {
+ DEFINE_NIC_PROPERTIES(NPCM7xxEMCState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void npcm7xx_emc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
+ dc->desc = "NPCM7xx EMC Controller";
+ dc->realize = npcm7xx_emc_realize;
+ dc->unrealize = npcm7xx_emc_unrealize;
+ dc->reset = npcm7xx_emc_reset;
+ dc->vmsd = &vmstate_npcm7xx_emc;
+ device_class_set_props(dc, npcm7xx_emc_properties);
+}
+
+static const TypeInfo npcm7xx_emc_info = {
+ .name = TYPE_NPCM7XX_EMC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCM7xxEMCState),
+ .class_init = npcm7xx_emc_class_init,
+};
+
+static void npcm7xx_emc_register_type(void)
+{
+ type_register_static(&npcm7xx_emc_info);
+}
+
+type_init(npcm7xx_emc_register_type)
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 5db45456d9..baf25ffa7e 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -429,3 +429,20 @@ imx_fec_receive_last(int last) "rx frame flags 0x%04x"
imx_enet_receive(size_t size) "len %zu"
imx_enet_receive_len(uint64_t addr, int len) "rx_bd 0x%"PRIx64" length %d"
imx_enet_receive_last(int last) "rx frame flags 0x%04x"
+
+# npcm7xx_emc.c
+npcm7xx_emc_reset(int emc_num) "Resetting emc%d"
+npcm7xx_emc_update_tx_irq(int level) "Setting tx irq to %d"
+npcm7xx_emc_update_rx_irq(int level) "Setting rx irq to %d"
+npcm7xx_emc_set_mista(uint32_t flags) "ORing 0x%x into MISTA"
+npcm7xx_emc_cpu_owned_desc(uint32_t addr) "Can't process cpu-owned descriptor @0x%x"
+npcm7xx_emc_sent_packet(uint32_t len) "Sent %u byte packet"
+npcm7xx_emc_tx_done(uint32_t ctxdsa) "TX done, CTXDSA=0x%x"
+npcm7xx_emc_can_receive(int can_receive) "Can receive: %d"
+npcm7xx_emc_packet_filtered_out(const char* fail_reason) "Packet filtered out: %s"
+npcm7xx_emc_packet_dropped(uint32_t len) "%u byte packet dropped"
+npcm7xx_emc_receiving_packet(uint32_t len) "Receiving %u byte packet"
+npcm7xx_emc_received_packet(uint32_t len) "Received %u byte packet"
+npcm7xx_emc_rx_done(uint32_t crxdsa) "RX done, CRXDSA=0x%x"
+npcm7xx_emc_reg_read(int emc_num, uint32_t result, const char *name, int regno) "emc%d: 0x%x = reg[%s/%d]"
+npcm7xx_emc_reg_write(int emc_num, const char *name, int regno, uint32_t value) "emc%d: reg[%s/%d] = 0x%x"
diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig
index 8b8c763c28..2ccc96f02c 100644
--- a/hw/pci-host/Kconfig
+++ b/hw/pci-host/Kconfig
@@ -68,3 +68,7 @@ config PCI_POWERNV
config REMOTE_PCIHOST
bool
+
+config SH_PCI
+ bool
+ select PCI
diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build
index 1847c69905..87a896973e 100644
--- a/hw/pci-host/meson.build
+++ b/hw/pci-host/meson.build
@@ -10,6 +10,7 @@ pci_ss.add(when: 'CONFIG_PCI_I440FX', if_true: files('i440fx.c'))
pci_ss.add(when: 'CONFIG_PCI_SABRE', if_true: files('sabre.c'))
pci_ss.add(when: 'CONFIG_XEN_IGD_PASSTHROUGH', if_true: files('xen_igd_pt.c'))
pci_ss.add(when: 'CONFIG_REMOTE_PCIHOST', if_true: files('remote.c'))
+pci_ss.add(when: 'CONFIG_SH_PCI', if_true: files('sh_pci.c'))
# PPC devices
pci_ss.add(when: 'CONFIG_PREP_PCI', if_true: files('prep.c'))
diff --git a/hw/sh4/sh_pci.c b/hw/pci-host/sh_pci.c
index 734892f47c..734892f47c 100644
--- a/hw/sh4/sh_pci.c
+++ b/hw/pci-host/sh_pci.c
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index a4e58580e4..e2c19180a0 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -2312,7 +2312,7 @@ static void lsi_scsi_realize(PCIDevice *dev, Error **errp)
scsi_bus_new(&s->bus, sizeof(s->bus), d, &lsi_scsi_info, NULL);
}
-static void lsi_scsi_unrealize(DeviceState *dev)
+static void lsi_scsi_exit(PCIDevice *dev)
{
LSIState *s = LSI53C895A(dev);
@@ -2325,11 +2325,11 @@ static void lsi_class_init(ObjectClass *klass, void *data)
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->realize = lsi_scsi_realize;
+ k->exit = lsi_scsi_exit;
k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
k->device_id = PCI_DEVICE_ID_LSI_53C895A;
k->class_id = PCI_CLASS_STORAGE_SCSI;
k->subsystem_id = 0x1000;
- dc->unrealize = lsi_scsi_unrealize;
dc->reset = lsi_scsi_reset;
dc->vmsd = &vmstate_lsi_scsi;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index dc4141ec8d..2d674f94d7 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -692,6 +692,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
req->lun = lun;
req->hba_private = hba_private;
req->status = -1;
+ req->host_status = -1;
req->ops = reqops;
object_ref(OBJECT(d));
object_ref(OBJECT(qbus->parent));
@@ -1455,10 +1456,38 @@ void scsi_req_print(SCSIRequest *req)
}
}
+void scsi_req_complete_failed(SCSIRequest *req, int host_status)
+{
+ SCSISense sense;
+ int status;
+
+ assert(req->status == -1 && req->host_status == -1);
+ assert(req->ops != &reqops_unit_attention);
+
+ if (!req->bus->info->fail) {
+ status = scsi_sense_from_host_status(req->host_status, &sense);
+ if (status == CHECK_CONDITION) {
+ scsi_req_build_sense(req, sense);
+ }
+ scsi_req_complete(req, status);
+ return;
+ }
+
+ req->host_status = host_status;
+ scsi_req_ref(req);
+ scsi_req_dequeue(req);
+ req->bus->info->fail(req);
+
+ /* Cancelled requests might end up being completed instead of cancelled */
+ notifier_list_notify(&req->cancel_notifiers, req);
+ scsi_req_unref(req);
+}
+
void scsi_req_complete(SCSIRequest *req, int status)
{
- assert(req->status == -1);
+ assert(req->status == -1 && req->host_status == -1);
req->status = status;
+ req->host_status = SCSI_HOST_OK;
assert(req->sense_len <= sizeof(req->sense));
if (status == GOOD) {
@@ -1646,7 +1675,7 @@ static int put_scsi_requests(QEMUFile *f, void *pv, size_t size,
QTAILQ_FOREACH(req, &s->requests, next) {
assert(!req->io_canceled);
- assert(req->status == -1);
+ assert(req->status == -1 && req->host_status == -1);
assert(req->enqueued);
qemu_put_sbyte(f, req->retry ? 1 : 2);
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index a5a58d7db3..bd7103cd0e 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -77,7 +77,6 @@ typedef struct SCSIDiskReq {
struct iovec iov;
QEMUIOVector qiov;
BlockAcctCookie acct;
- unsigned char *status;
} SCSIDiskReq;
#define SCSI_DISK_F_REMOVABLE 0
@@ -261,8 +260,6 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)
if (ret < 0) {
return scsi_handle_rw_error(r, ret, acct_failed);
- } else if (r->status && *r->status) {
- return scsi_handle_rw_error(r, *r->status, acct_failed);
}
return false;
@@ -2697,8 +2694,47 @@ typedef struct SCSIBlockReq {
/* CDB passed to SG_IO. */
uint8_t cdb[16];
+ BlockCompletionFunc *cb;
+ void *cb_opaque;
} SCSIBlockReq;
+static void scsi_block_sgio_complete(void *opaque, int ret)
+{
+ SCSIBlockReq *req = (SCSIBlockReq *)opaque;
+ SCSIDiskReq *r = &req->req;
+ SCSIDevice *s = r->req.dev;
+ sg_io_hdr_t *io_hdr = &req->io_header;
+
+ if (ret == 0) {
+ if (io_hdr->host_status != SCSI_HOST_OK) {
+ scsi_req_complete_failed(&r->req, io_hdr->host_status);
+ scsi_req_unref(&r->req);
+ return;
+ }
+
+ if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
+ ret = BUSY;
+ } else {
+ ret = io_hdr->status;
+ }
+
+ if (ret > 0) {
+ aio_context_acquire(blk_get_aio_context(s->conf.blk));
+ if (scsi_handle_rw_error(r, ret, true)) {
+ aio_context_release(blk_get_aio_context(s->conf.blk));
+ scsi_req_unref(&r->req);
+ return;
+ }
+ aio_context_release(blk_get_aio_context(s->conf.blk));
+
+ /* Ignore error. */
+ ret = 0;
+ }
+ }
+
+ req->cb(req->cb_opaque, ret);
+}
+
static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
int64_t offset, QEMUIOVector *iov,
int direction,
@@ -2777,9 +2813,11 @@ static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
io_header->timeout = s->qdev.io_timeout * 1000;
io_header->usr_ptr = r;
io_header->flags |= SG_FLAG_DIRECT_IO;
+ req->cb = cb;
+ req->cb_opaque = opaque;
trace_scsi_disk_aio_sgio_command(r->req.tag, req->cdb[0], lba,
nb_logical_blocks, io_header->timeout);
- aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, cb, opaque);
+ aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, scsi_block_sgio_complete, req);
assert(aiocb != NULL);
return aiocb;
}
@@ -2893,7 +2931,6 @@ static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
- r->req.status = &r->io_header.status;
return scsi_disk_dma_command(req, buf);
}
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index cf7e11cf44..98c30c5d5c 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -75,6 +75,7 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
{
int status;
SCSISense sense;
+ sg_io_hdr_t *io_hdr = &r->io_header;
assert(r->req.aiocb == NULL);
@@ -82,15 +83,22 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
scsi_req_cancel_complete(&r->req);
goto done;
}
- status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
- if (status == CHECK_CONDITION) {
- if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
- r->req.sense_len = r->io_header.sb_len_wr;
- } else {
+ if (ret < 0) {
+ status = scsi_sense_from_errno(-ret, &sense);
+ if (status == CHECK_CONDITION) {
scsi_req_build_sense(&r->req, sense);
}
+ } else if (io_hdr->host_status != SCSI_HOST_OK) {
+ scsi_req_complete_failed(&r->req, io_hdr->host_status);
+ goto done;
+ } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
+ status = BUSY;
+ } else {
+ status = io_hdr->status;
+ if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
+ r->req.sense_len = io_hdr->sb_len_wr;
+ }
}
-
trace_scsi_generic_command_complete_noio(r, r->req.tag, status);
scsi_req_complete(&r->req, status);
@@ -288,7 +296,10 @@ static void scsi_read_complete(void * opaque, int ret)
}
}
- if (len == 0) {
+ if (r->io_header.host_status != SCSI_HOST_OK ||
+ (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) ||
+ r->io_header.status != GOOD ||
+ len == 0) {
scsi_command_complete_noio(r, 0);
goto done;
}
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 358c0e70b0..6d80730287 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -500,6 +500,51 @@ static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req)
virtio_scsi_complete_req(req);
}
+static void virtio_scsi_command_failed(SCSIRequest *r)
+{
+ VirtIOSCSIReq *req = r->hba_private;
+
+ if (r->io_canceled) {
+ return;
+ }
+
+ req->resp.cmd.status = GOOD;
+ switch (r->host_status) {
+ case SCSI_HOST_NO_LUN:
+ req->resp.cmd.response = VIRTIO_SCSI_S_INCORRECT_LUN;
+ break;
+ case SCSI_HOST_BUSY:
+ req->resp.cmd.response = VIRTIO_SCSI_S_BUSY;
+ break;
+ case SCSI_HOST_TIME_OUT:
+ case SCSI_HOST_ABORTED:
+ req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED;
+ break;
+ case SCSI_HOST_BAD_RESPONSE:
+ req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
+ break;
+ case SCSI_HOST_RESET:
+ req->resp.cmd.response = VIRTIO_SCSI_S_RESET;
+ break;
+ case SCSI_HOST_TRANSPORT_DISRUPTED:
+ req->resp.cmd.response = VIRTIO_SCSI_S_TRANSPORT_FAILURE;
+ break;
+ case SCSI_HOST_TARGET_FAILURE:
+ req->resp.cmd.response = VIRTIO_SCSI_S_TARGET_FAILURE;
+ break;
+ case SCSI_HOST_RESERVATION_ERROR:
+ req->resp.cmd.response = VIRTIO_SCSI_S_NEXUS_FAILURE;
+ break;
+ case SCSI_HOST_ALLOCATION_FAILURE:
+ case SCSI_HOST_MEDIUM_ERROR:
+ case SCSI_HOST_ERROR:
+ default:
+ req->resp.cmd.response = VIRTIO_SCSI_S_FAILURE;
+ break;
+ }
+ virtio_scsi_complete_cmd_req(req);
+}
+
static void virtio_scsi_command_complete(SCSIRequest *r, size_t resid)
{
VirtIOSCSIReq *req = r->hba_private;
@@ -908,6 +953,7 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
.max_lun = VIRTIO_SCSI_MAX_LUN,
.complete = virtio_scsi_command_complete,
+ .fail = virtio_scsi_command_failed,
.cancel = virtio_scsi_request_cancelled,
.change = virtio_scsi_change,
.parse_cdb = virtio_scsi_parse_cdb,
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index 0da378ed50..1f30cb020a 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -511,6 +511,44 @@ pvscsi_write_sense(PVSCSIRequest *r, uint8_t *sense, int len)
}
static void
+pvscsi_command_failed(SCSIRequest *req)
+{
+ PVSCSIRequest *pvscsi_req = req->hba_private;
+ PVSCSIState *s;
+
+ if (!pvscsi_req) {
+ trace_pvscsi_command_complete_not_found(req->tag);
+ return;
+ }
+ s = pvscsi_req->dev;
+
+ switch (req->host_status) {
+ case SCSI_HOST_NO_LUN:
+ pvscsi_req->cmp.hostStatus = BTSTAT_LUNMISMATCH;
+ break;
+ case SCSI_HOST_BUSY:
+ pvscsi_req->cmp.hostStatus = BTSTAT_ABORTQUEUE;
+ break;
+ case SCSI_HOST_TIME_OUT:
+ case SCSI_HOST_ABORTED:
+ pvscsi_req->cmp.hostStatus = BTSTAT_SENTRST;
+ break;
+ case SCSI_HOST_BAD_RESPONSE:
+ pvscsi_req->cmp.hostStatus = BTSTAT_SELTIMEO;
+ break;
+ case SCSI_HOST_RESET:
+ pvscsi_req->cmp.hostStatus = BTSTAT_BUSRESET;
+ break;
+ default:
+ pvscsi_req->cmp.hostStatus = BTSTAT_HASOFTWARE;
+ break;
+ }
+ pvscsi_req->cmp.scsiStatus = GOOD;
+ qemu_sglist_destroy(&pvscsi_req->sgl);
+ pvscsi_complete_request(s, pvscsi_req);
+}
+
+static void
pvscsi_command_complete(SCSIRequest *req, size_t resid)
{
PVSCSIRequest *pvscsi_req = req->hba_private;
@@ -1103,6 +1141,7 @@ static const struct SCSIBusInfo pvscsi_scsi_info = {
.get_sg_list = pvscsi_get_sg_list,
.complete = pvscsi_command_complete,
.cancel = pvscsi_request_cancelled,
+ .fail = pvscsi_command_failed,
};
static void
diff --git a/hw/sh4/Kconfig b/hw/sh4/Kconfig
index 4cbce3a0ed..ab733a3f76 100644
--- a/hw/sh4/Kconfig
+++ b/hw/sh4/Kconfig
@@ -9,16 +9,16 @@ config R2D
select USB_OHCI_PCI
select PCI
select SM501
- select SH4
+ select SH7750
+ select SH_PCI
config SHIX
bool
select SH7750
- select SH4
+ select TC58128
config SH7750
bool
-
-config SH4
- bool
- select PTIMER
+ select SH_INTC
+ select SH_SCI
+ select SH_TIMER
diff --git a/hw/sh4/meson.build b/hw/sh4/meson.build
index 303c0f4287..424d5674de 100644
--- a/hw/sh4/meson.build
+++ b/hw/sh4/meson.build
@@ -2,7 +2,6 @@ sh4_ss = ss.source_set()
sh4_ss.add(files(
'sh7750.c',
'sh7750_regnames.c',
- 'sh_pci.c'
))
sh4_ss.add(when: 'CONFIG_R2D', if_true: files('r2d.c'))
sh4_ss.add(when: 'CONFIG_SHIX', if_true: files('shix.c'))
diff --git a/hw/sh4/sh7750_regs.h b/hw/sh4/sh7750_regs.h
index 3e4554af31..ab073dadc7 100644
--- a/hw/sh4/sh7750_regs.h
+++ b/hw/sh4/sh7750_regs.h
@@ -10,8 +10,28 @@
* Victor V. Vengerov <vvv@oktet.ru>
*
* The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
+ * found in this file hereafter or at http://www.rtems.com/license/LICENSE.
+ *
+ * LICENSE INFORMATION
+ *
+ * RTEMS is free software; you can redistribute it and/or modify it under
+ * terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version. RTEMS is distributed in the hope that 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 RTEMS; see
+ * file COPYING. If not, write to the Free Software Foundation, 675
+ * Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * As a special exception, including RTEMS header files in a file,
+ * instantiating RTEMS generics or templates, or linking other files
+ * with RTEMS objects to produce an executable application, does not
+ * by itself cause the resulting executable application to be covered
+ * by the GNU General Public License. This exception does not
+ * however invalidate any other reasons why the executable file might be
+ * covered by the GNU Public License.
*
* @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp
*/
diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig
index 8749edfb6a..18936ef55b 100644
--- a/hw/timer/Kconfig
+++ b/hw/timer/Kconfig
@@ -36,6 +36,10 @@ config CMSDK_APB_DUALTIMER
bool
select PTIMER
+config SH_TIMER
+ bool
+ select PTIMER
+
config RENESAS_TMR
bool
diff --git a/hw/timer/meson.build b/hw/timer/meson.build
index be343f68fe..26c2701fd7 100644
--- a/hw/timer/meson.build
+++ b/hw/timer/meson.build
@@ -30,7 +30,7 @@ softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_synctimer.c'))
softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_ost.c'))
softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_timer.c'))
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_systmr.c'))
-softmmu_ss.add(when: 'CONFIG_SH4', if_true: files('sh_timer.c'))
+softmmu_ss.add(when: 'CONFIG_SH_TIMER', if_true: files('sh_timer.c'))
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_timer.c'))
softmmu_ss.add(when: 'CONFIG_STM32F2XX_TIMER', if_true: files('stm32f2xx_timer.c'))
softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_timer.c'))
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 610661d6a5..6990b9879c 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -737,8 +737,8 @@ static char *virtio_mmio_bus_get_dev_path(DeviceState *dev)
BusState *virtio_mmio_bus;
VirtIOMMIOProxy *virtio_mmio_proxy;
char *proxy_path;
- SysBusDevice *proxy_sbd;
char *path;
+ MemoryRegionSection section;
virtio_mmio_bus = qdev_get_parent_bus(dev);
virtio_mmio_proxy = VIRTIO_MMIO(virtio_mmio_bus->parent);
@@ -757,17 +757,18 @@ static char *virtio_mmio_bus_get_dev_path(DeviceState *dev)
}
/* Otherwise, we append the base address of the transport. */
- proxy_sbd = SYS_BUS_DEVICE(virtio_mmio_proxy);
- assert(proxy_sbd->num_mmio == 1);
- assert(proxy_sbd->mmio[0].memory == &virtio_mmio_proxy->iomem);
+ section = memory_region_find(&virtio_mmio_proxy->iomem, 0, 0x200);
+ assert(section.mr);
if (proxy_path) {
path = g_strdup_printf("%s/virtio-mmio@" TARGET_FMT_plx, proxy_path,
- proxy_sbd->mmio[0].addr);
+ section.offset_within_address_space);
} else {
path = g_strdup_printf("virtio-mmio@" TARGET_FMT_plx,
- proxy_sbd->mmio[0].addr);
+ section.offset_within_address_space);
}
+ memory_region_unref(section.mr);
+
g_free(proxy_path);
return path;
}
diff --git a/include/hw/arm/armsse.h b/include/hw/arm/armsse.h
index 676cd4f36b..09284ca75c 100644
--- a/include/hw/arm/armsse.h
+++ b/include/hw/arm/armsse.h
@@ -14,9 +14,9 @@
* hardware, which include the IoT Kit and the SSE-050, SSE-100 and
* SSE-200. Currently we model:
* - the Arm IoT Kit which is documented in
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * https://developer.arm.com/documentation/ecm0601256/latest
* - the SSE-200 which is documented in
- * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf
+ * https://developer.arm.com/documentation/101104/latest/
*
* The IoTKit contains:
* a Cortex-M33
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
index cea1bd1f62..d32849a456 100644
--- a/include/hw/arm/npcm7xx.h
+++ b/include/hw/arm/npcm7xx.h
@@ -26,6 +26,7 @@
#include "hw/misc/npcm7xx_gcr.h"
#include "hw/misc/npcm7xx_pwm.h"
#include "hw/misc/npcm7xx_rng.h"
+#include "hw/net/npcm7xx_emc.h"
#include "hw/nvram/npcm7xx_otp.h"
#include "hw/timer/npcm7xx_timer.h"
#include "hw/ssi/npcm7xx_fiu.h"
@@ -90,6 +91,7 @@ typedef struct NPCM7xxState {
EHCISysBusState ehci;
OHCISysBusState ohci;
NPCM7xxFIUState fiu[2];
+ NPCM7xxEMCState emc[2];
} NPCM7xxState;
#define TYPE_NPCM7XX "npcm7xx"
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index 6f45387a17..0678b419a2 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -115,8 +115,6 @@ struct XlnxZynqMPState {
bool secure;
/* Has the ARM Virtualization extensions? */
bool virt;
- /* Has the RPU subsystem? */
- bool has_rpu;
/* CAN bus. */
CanBusState *canbus[XLNX_ZYNQMP_NUM_CAN];
diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
index 8e8436831d..78409ab34a 100644
--- a/include/hw/elf_ops.h
+++ b/include/hw/elf_ops.h
@@ -598,9 +598,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
nhdr = glue(get_elf_note_type, SZ)(nhdr, file_size, ph->p_align,
*(uint64_t *)translate_opaque);
if (nhdr != NULL) {
- bool is64 =
- sizeof(struct elf_note) == sizeof(struct elf64_note);
- elf_note_fn((void *)nhdr, (void *)&ph->p_align, is64);
+ elf_note_fn((void *)nhdr, (void *)&ph->p_align, SZ == 64);
}
data = NULL;
}
diff --git a/include/hw/misc/armsse-cpuid.h b/include/hw/misc/armsse-cpuid.h
index a61355e516..9c0926322c 100644
--- a/include/hw/misc/armsse-cpuid.h
+++ b/include/hw/misc/armsse-cpuid.h
@@ -12,7 +12,7 @@
/*
* This is a model of the "CPU_IDENTITY" register block which is part of the
* Arm SSE-200 and documented in
- * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf
+ * https://developer.arm.com/documentation/101104/latest/
*
* QEMU interface:
* + QOM property "CPUID": the value to use for the CPUID register
diff --git a/include/hw/misc/armsse-mhu.h b/include/hw/misc/armsse-mhu.h
index 2671b5b978..41925ded89 100644
--- a/include/hw/misc/armsse-mhu.h
+++ b/include/hw/misc/armsse-mhu.h
@@ -12,7 +12,7 @@
/*
* This is a model of the Message Handling Unit (MHU) which is part of the
* Arm SSE-200 and documented in
- * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf
+ * https://developer.arm.com/documentation/101104/latest/
*
* QEMU interface:
* + sysbus MMIO region 0: the system information register bank
diff --git a/include/hw/misc/iotkit-secctl.h b/include/hw/misc/iotkit-secctl.h
index 54c212b515..227d44abe4 100644
--- a/include/hw/misc/iotkit-secctl.h
+++ b/include/hw/misc/iotkit-secctl.h
@@ -11,7 +11,7 @@
/* This is a model of the security controller which is part of the
* Arm IoT Kit and documented in
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * https://developer.arm.com/documentation/ecm0601256/latest
*
* QEMU interface:
* + sysbus MMIO region 0 is the "secure privilege control block" registers
diff --git a/include/hw/misc/iotkit-sysctl.h b/include/hw/misc/iotkit-sysctl.h
index 2b5636b218..2bc391138d 100644
--- a/include/hw/misc/iotkit-sysctl.h
+++ b/include/hw/misc/iotkit-sysctl.h
@@ -12,7 +12,7 @@
/*
* This is a model of the "system control element" which is part of the
* Arm IoTKit and documented in
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * https://developer.arm.com/documentation/ecm0601256/latest
* Specifically, it implements the "system information block" and
* "system control register" blocks.
*
diff --git a/include/hw/misc/iotkit-sysinfo.h b/include/hw/misc/iotkit-sysinfo.h
index 7e620e2eaf..055771d209 100644
--- a/include/hw/misc/iotkit-sysinfo.h
+++ b/include/hw/misc/iotkit-sysinfo.h
@@ -12,7 +12,7 @@
/*
* This is a model of the "system information block" which is part of the
* Arm IoTKit and documented in
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * https://developer.arm.com/documentation/ecm0601256/latest
* QEMU interface:
* + QOM property "SYS_VERSION": value to use for SYS_VERSION register
* + QOM property "SYS_CONFIG": value to use for SYS_CONFIG register
diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h
index a010fdb2b6..e04fd590b6 100644
--- a/include/hw/misc/mps2-fpgaio.h
+++ b/include/hw/misc/mps2-fpgaio.h
@@ -12,7 +12,7 @@
/* This is a model of the FPGAIO register block in the AN505
* FPGA image for the MPS2 dev board; it is documented in the
* application note:
- * http://infocenter.arm.com/help/topic/com.arm.doc.dai0505b/index.html
+ * https://developer.arm.com/documentation/dai0505/latest/
*
* QEMU interface:
* + sysbus MMIO region 0: the register bank
@@ -28,13 +28,17 @@
#define TYPE_MPS2_FPGAIO "mps2-fpgaio"
OBJECT_DECLARE_SIMPLE_TYPE(MPS2FPGAIO, MPS2_FPGAIO)
+#define MPS2FPGAIO_MAX_LEDS 32
+
struct MPS2FPGAIO {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion iomem;
- LEDState *led[2];
+ LEDState *led[MPS2FPGAIO_MAX_LEDS];
+ uint32_t num_leds;
+ bool has_switches;
uint32_t led0;
uint32_t prescale;
diff --git a/include/hw/misc/mps2-scc.h b/include/hw/misc/mps2-scc.h
index f65d873203..49d070616a 100644
--- a/include/hw/misc/mps2-scc.h
+++ b/include/hw/misc/mps2-scc.h
@@ -19,8 +19,6 @@
#define TYPE_MPS2_SCC "mps2-scc"
OBJECT_DECLARE_SIMPLE_TYPE(MPS2SCC, MPS2_SCC)
-#define NUM_OSCCLK 3
-
struct MPS2SCC {
/*< private >*/
SysBusDevice parent_obj;
@@ -31,7 +29,10 @@ struct MPS2SCC {
uint32_t cfg0;
uint32_t cfg1;
+ uint32_t cfg2;
uint32_t cfg4;
+ uint32_t cfg5;
+ uint32_t cfg6;
uint32_t cfgdata_rtn;
uint32_t cfgdata_out;
uint32_t cfgctrl;
@@ -39,8 +40,9 @@ struct MPS2SCC {
uint32_t dll;
uint32_t aid;
uint32_t id;
- uint32_t oscclk[NUM_OSCCLK];
- uint32_t oscclk_reset[NUM_OSCCLK];
+ uint32_t num_oscclk;
+ uint32_t *oscclk;
+ uint32_t *oscclk_reset;
};
#endif
diff --git a/include/hw/net/npcm7xx_emc.h b/include/hw/net/npcm7xx_emc.h
new file mode 100644
index 0000000000..eac7f29816
--- /dev/null
+++ b/include/hw/net/npcm7xx_emc.h
@@ -0,0 +1,286 @@
+/*
+ * Nuvoton NPCM7xx EMC Module
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef NPCM7XX_EMC_H
+#define NPCM7XX_EMC_H
+
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "net/net.h"
+
+/* 32-bit register indices. */
+enum NPCM7xxPWMRegister {
+ /* Control registers. */
+ REG_CAMCMR,
+ REG_CAMEN,
+
+ /* There are 16 CAMn[ML] registers. */
+ REG_CAMM_BASE,
+ REG_CAML_BASE,
+ REG_CAMML_LAST = 0x21,
+
+ REG_TXDLSA = 0x22,
+ REG_RXDLSA,
+ REG_MCMDR,
+ REG_MIID,
+ REG_MIIDA,
+ REG_FFTCR,
+ REG_TSDR,
+ REG_RSDR,
+ REG_DMARFC,
+ REG_MIEN,
+
+ /* Status registers. */
+ REG_MISTA,
+ REG_MGSTA,
+ REG_MPCNT,
+ REG_MRPC,
+ REG_MRPCC,
+ REG_MREPC,
+ REG_DMARFS,
+ REG_CTXDSA,
+ REG_CTXBSA,
+ REG_CRXDSA,
+ REG_CRXBSA,
+
+ NPCM7XX_NUM_EMC_REGS,
+};
+
+/* REG_CAMCMR fields */
+/* Enable CAM Compare */
+#define REG_CAMCMR_ECMP (1 << 4)
+/* Complement CAM Compare */
+#define REG_CAMCMR_CCAM (1 << 3)
+/* Accept Broadcast Packet */
+#define REG_CAMCMR_ABP (1 << 2)
+/* Accept Multicast Packet */
+#define REG_CAMCMR_AMP (1 << 1)
+/* Accept Unicast Packet */
+#define REG_CAMCMR_AUP (1 << 0)
+
+/* REG_MCMDR fields */
+/* Software Reset */
+#define REG_MCMDR_SWR (1 << 24)
+/* Internal Loopback Select */
+#define REG_MCMDR_LBK (1 << 21)
+/* Operation Mode Select */
+#define REG_MCMDR_OPMOD (1 << 20)
+/* Enable MDC Clock Generation */
+#define REG_MCMDR_ENMDC (1 << 19)
+/* Full-Duplex Mode Select */
+#define REG_MCMDR_FDUP (1 << 18)
+/* Enable SQE Checking */
+#define REG_MCMDR_ENSEQ (1 << 17)
+/* Send PAUSE Frame */
+#define REG_MCMDR_SDPZ (1 << 16)
+/* No Defer */
+#define REG_MCMDR_NDEF (1 << 9)
+/* Frame Transmission On */
+#define REG_MCMDR_TXON (1 << 8)
+/* Strip CRC Checksum */
+#define REG_MCMDR_SPCRC (1 << 5)
+/* Accept CRC Error Packet */
+#define REG_MCMDR_AEP (1 << 4)
+/* Accept Control Packet */
+#define REG_MCMDR_ACP (1 << 3)
+/* Accept Runt Packet */
+#define REG_MCMDR_ARP (1 << 2)
+/* Accept Long Packet */
+#define REG_MCMDR_ALP (1 << 1)
+/* Frame Reception On */
+#define REG_MCMDR_RXON (1 << 0)
+
+/* REG_MIEN fields */
+/* Enable Transmit Descriptor Unavailable Interrupt */
+#define REG_MIEN_ENTDU (1 << 23)
+/* Enable Transmit Completion Interrupt */
+#define REG_MIEN_ENTXCP (1 << 18)
+/* Enable Transmit Interrupt */
+#define REG_MIEN_ENTXINTR (1 << 16)
+/* Enable Receive Descriptor Unavailable Interrupt */
+#define REG_MIEN_ENRDU (1 << 10)
+/* Enable Receive Good Interrupt */
+#define REG_MIEN_ENRXGD (1 << 4)
+/* Enable Receive Interrupt */
+#define REG_MIEN_ENRXINTR (1 << 0)
+
+/* REG_MISTA fields */
+/* TODO: Add error fields and support simulated errors? */
+/* Transmit Bus Error Interrupt */
+#define REG_MISTA_TXBERR (1 << 24)
+/* Transmit Descriptor Unavailable Interrupt */
+#define REG_MISTA_TDU (1 << 23)
+/* Transmit Completion Interrupt */
+#define REG_MISTA_TXCP (1 << 18)
+/* Transmit Interrupt */
+#define REG_MISTA_TXINTR (1 << 16)
+/* Receive Bus Error Interrupt */
+#define REG_MISTA_RXBERR (1 << 11)
+/* Receive Descriptor Unavailable Interrupt */
+#define REG_MISTA_RDU (1 << 10)
+/* DMA Early Notification Interrupt */
+#define REG_MISTA_DENI (1 << 9)
+/* Maximum Frame Length Interrupt */
+#define REG_MISTA_DFOI (1 << 8)
+/* Receive Good Interrupt */
+#define REG_MISTA_RXGD (1 << 4)
+/* Packet Too Long Interrupt */
+#define REG_MISTA_PTLE (1 << 3)
+/* Receive Interrupt */
+#define REG_MISTA_RXINTR (1 << 0)
+
+/* REG_MGSTA fields */
+/* Transmission Halted */
+#define REG_MGSTA_TXHA (1 << 11)
+/* Receive Halted */
+#define REG_MGSTA_RXHA (1 << 11)
+
+/* REG_DMARFC fields */
+/* Maximum Receive Frame Length */
+#define REG_DMARFC_RXMS(word) extract32((word), 0, 16)
+
+/* REG MIIDA fields */
+/* Busy Bit */
+#define REG_MIIDA_BUSY (1 << 17)
+
+/* Transmit and receive descriptors */
+typedef struct NPCM7xxEMCTxDesc NPCM7xxEMCTxDesc;
+typedef struct NPCM7xxEMCRxDesc NPCM7xxEMCRxDesc;
+
+struct NPCM7xxEMCTxDesc {
+ uint32_t flags;
+ uint32_t txbsa;
+ uint32_t status_and_length;
+ uint32_t ntxdsa;
+};
+
+struct NPCM7xxEMCRxDesc {
+ uint32_t status_and_length;
+ uint32_t rxbsa;
+ uint32_t reserved;
+ uint32_t nrxdsa;
+};
+
+/* NPCM7xxEMCTxDesc.flags values */
+/* Owner: 0 = cpu, 1 = emc */
+#define TX_DESC_FLAG_OWNER_MASK (1 << 31)
+/* Transmit interrupt enable */
+#define TX_DESC_FLAG_INTEN (1 << 2)
+/* CRC append */
+#define TX_DESC_FLAG_CRCAPP (1 << 1)
+/* Padding enable */
+#define TX_DESC_FLAG_PADEN (1 << 0)
+
+/* NPCM7xxEMCTxDesc.status_and_length values */
+/* Collision count */
+#define TX_DESC_STATUS_CCNT_SHIFT 28
+#define TX_DESC_STATUS_CCNT_BITSIZE 4
+/* SQE error */
+#define TX_DESC_STATUS_SQE (1 << 26)
+/* Transmission paused */
+#define TX_DESC_STATUS_PAU (1 << 25)
+/* P transmission halted */
+#define TX_DESC_STATUS_TXHA (1 << 24)
+/* Late collision */
+#define TX_DESC_STATUS_LC (1 << 23)
+/* Transmission abort */
+#define TX_DESC_STATUS_TXABT (1 << 22)
+/* No carrier sense */
+#define TX_DESC_STATUS_NCS (1 << 21)
+/* Defer exceed */
+#define TX_DESC_STATUS_EXDEF (1 << 20)
+/* Transmission complete */
+#define TX_DESC_STATUS_TXCP (1 << 19)
+/* Transmission deferred */
+#define TX_DESC_STATUS_DEF (1 << 17)
+/* Transmit interrupt */
+#define TX_DESC_STATUS_TXINTR (1 << 16)
+
+#define TX_DESC_PKT_LEN(word) extract32((word), 0, 16)
+
+/* Transmit buffer start address */
+#define TX_DESC_TXBSA(word) ((uint32_t) (word) & ~3u)
+
+/* Next transmit descriptor start address */
+#define TX_DESC_NTXDSA(word) ((uint32_t) (word) & ~3u)
+
+/* NPCM7xxEMCRxDesc.status_and_length values */
+/* Owner: 0b00 = cpu, 0b01 = undefined, 0b10 = emc, 0b11 = undefined */
+#define RX_DESC_STATUS_OWNER_SHIFT 30
+#define RX_DESC_STATUS_OWNER_BITSIZE 2
+#define RX_DESC_STATUS_OWNER_MASK (3 << RX_DESC_STATUS_OWNER_SHIFT)
+/* Runt packet */
+#define RX_DESC_STATUS_RP (1 << 22)
+/* Alignment error */
+#define RX_DESC_STATUS_ALIE (1 << 21)
+/* Frame reception complete */
+#define RX_DESC_STATUS_RXGD (1 << 20)
+/* Packet too long */
+#define RX_DESC_STATUS_PTLE (1 << 19)
+/* CRC error */
+#define RX_DESC_STATUS_CRCE (1 << 17)
+/* Receive interrupt */
+#define RX_DESC_STATUS_RXINTR (1 << 16)
+
+#define RX_DESC_PKT_LEN(word) extract32((word), 0, 16)
+
+/* Receive buffer start address */
+#define RX_DESC_RXBSA(word) ((uint32_t) (word) & ~3u)
+
+/* Next receive descriptor start address */
+#define RX_DESC_NRXDSA(word) ((uint32_t) (word) & ~3u)
+
+/* Minimum packet length, when TX_DESC_FLAG_PADEN is set. */
+#define MIN_PACKET_LENGTH 64
+
+struct NPCM7xxEMCState {
+ /*< private >*/
+ SysBusDevice parent;
+ /*< public >*/
+
+ MemoryRegion iomem;
+
+ qemu_irq tx_irq;
+ qemu_irq rx_irq;
+
+ NICState *nic;
+ NICConf conf;
+
+ /* 0 or 1, for log messages */
+ uint8_t emc_num;
+
+ uint32_t regs[NPCM7XX_NUM_EMC_REGS];
+
+ /*
+ * tx is active. Set to true by TSDR and then switches off when out of
+ * descriptors. If the TXON bit in REG_MCMDR is off then this is off.
+ */
+ bool tx_active;
+
+ /*
+ * rx is active. Set to true by RSDR and then switches off when out of
+ * descriptors. If the RXON bit in REG_MCMDR is off then this is off.
+ */
+ bool rx_active;
+};
+
+typedef struct NPCM7xxEMCState NPCM7xxEMCState;
+
+#define TYPE_NPCM7XX_EMC "npcm7xx-emc"
+#define NPCM7XX_EMC(obj) \
+ OBJECT_CHECK(NPCM7xxEMCState, (obj), TYPE_NPCM7XX_EMC)
+
+#endif /* NPCM7XX_EMC_H */
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index 5d992e6e1d..0b726bc78c 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -27,7 +27,8 @@ struct SCSIRequest {
uint32_t refcount;
uint32_t tag;
uint32_t lun;
- uint32_t status;
+ int16_t status;
+ int16_t host_status;
void *hba_private;
size_t resid;
SCSICommand cmd;
@@ -123,6 +124,7 @@ struct SCSIBusInfo {
int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
void *hba_private);
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
+ void (*fail)(SCSIRequest *req);
void (*complete)(SCSIRequest *req, size_t resid);
void (*cancel)(SCSIRequest *req);
void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
@@ -177,6 +179,7 @@ void scsi_req_print(SCSIRequest *req);
void scsi_req_continue(SCSIRequest *req);
void scsi_req_data(SCSIRequest *req, int len);
void scsi_req_complete(SCSIRequest *req, int status);
+void scsi_req_complete_failed(SCSIRequest *req, int host_status);
uint8_t *scsi_req_get_buf(SCSIRequest *req);
int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
void scsi_req_cancel_complete(SCSIRequest *req);
diff --git a/include/hw/sh4/sh.h b/include/hw/sh4/sh.h
index 93f464bf4c..becb596979 100644
--- a/include/hw/sh4/sh.h
+++ b/include/hw/sh4/sh.h
@@ -1,6 +1,31 @@
-#ifndef QEMU_SH_H
-#define QEMU_SH_H
-/* Definitions for SH board emulation. */
+/*
+ * Definitions for SH board emulation
+ *
+ * Copyright (c) 2005 Samuel Tardieu
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+#ifndef QEMU_HW_SH_H
+#define QEMU_HW_SH_H
#include "hw/sh4/sh_intc.h"
#include "target/sh4/cpu-qom.h"
diff --git a/include/qemu/config-file.h b/include/qemu/config-file.h
index 29226107bd..8d3e53ae4d 100644
--- a/include/qemu/config-file.h
+++ b/include/qemu/config-file.h
@@ -11,9 +11,10 @@ void qemu_add_drive_opts(QemuOptsList *list);
int qemu_global_option(const char *str);
void qemu_config_write(FILE *fp);
-int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname);
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname,
+ Error **errp);
-int qemu_read_config_file(const char *filename);
+int qemu_read_config_file(const char *filename, Error **errp);
/* Parse QDict options as a replacement for a config file (allowing multiple
enumerated (0..(n-1)) configuration "sections") */
diff --git a/include/scsi/utils.h b/include/scsi/utils.h
index ff7c7091b6..d5c8efa16e 100644
--- a/include/scsi/utils.h
+++ b/include/scsi/utils.h
@@ -16,6 +16,22 @@ enum SCSIXferMode {
SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */
};
+enum SCSIHostStatus {
+ SCSI_HOST_OK,
+ SCSI_HOST_NO_LUN,
+ SCSI_HOST_BUSY,
+ SCSI_HOST_TIME_OUT,
+ SCSI_HOST_BAD_RESPONSE,
+ SCSI_HOST_ABORTED,
+ SCSI_HOST_ERROR = 0x07,
+ SCSI_HOST_RESET = 0x08,
+ SCSI_HOST_TRANSPORT_DISRUPTED = 0xe,
+ SCSI_HOST_TARGET_FAILURE = 0x10,
+ SCSI_HOST_RESERVATION_ERROR = 0x11,
+ SCSI_HOST_ALLOCATION_FAILURE = 0x12,
+ SCSI_HOST_MEDIUM_ERROR = 0x13,
+};
+
typedef struct SCSICommand {
uint8_t buf[SCSI_CMD_BUF_SIZE];
int len;
@@ -123,18 +139,9 @@ int scsi_cdb_length(uint8_t *buf);
#ifdef CONFIG_LINUX
#define SG_ERR_DRIVER_TIMEOUT 0x06
#define SG_ERR_DRIVER_SENSE 0x08
-
-#define SG_ERR_DID_OK 0x00
-#define SG_ERR_DID_NO_CONNECT 0x01
-#define SG_ERR_DID_BUS_BUSY 0x02
-#define SG_ERR_DID_TIME_OUT 0x03
-
-#define SG_ERR_DRIVER_SENSE 0x08
-
-int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
- SCSISense *sense);
#endif
int scsi_sense_from_errno(int errno_value, SCSISense *sense);
+int scsi_sense_from_host_status(uint8_t host_status, SCSISense *sense);
#endif
diff --git a/meson.build b/meson.build
index 81d760d6e8..adeec153d9 100644
--- a/meson.build
+++ b/meson.build
@@ -1574,6 +1574,18 @@ if have_system
endif
endif
+# For CFI, we need to compile slirp as a static library together with qemu.
+# This is because we register slirp functions as callbacks for QEMU Timers.
+# When using a system-wide shared libslirp, the type information for the
+# callback is missing and the timer call produces a false positive with CFI.
+#
+# Now that slirp_opt has been defined, check if the selected slirp is compatible
+# with control-flow integrity.
+if get_option('cfi') and slirp_opt == 'system'
+ error('Control-Flow Integrity is not compatible with system-wide slirp.' \
+ + ' Please configure with --enable-slirp=git')
+endif
+
fdt = not_found
fdt_opt = get_option('fdt')
if have_system
diff --git a/qemu-options.hx b/qemu-options.hx
index 252db9357c..90801286c6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3033,7 +3033,7 @@ DEFHEADING(Character device options:)
DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
"-chardev help\n"
"-chardev null,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
- "-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4=on|off][,ipv6=on|off][,delay=on|off][,reconnect=seconds]\n"
+ "-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4=on|off][,ipv6=on|off][,nodelay=on|off][,reconnect=seconds]\n"
" [,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds][,mux=on|off]\n"
" [,logfile=PATH][,logappend=on|off][,tls-creds=ID][,tls-authz=ID] (tcp)\n"
"-chardev socket,id=id,path=path[,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds]\n"
@@ -3184,7 +3184,7 @@ The available backends are:
TCP and unix socket options are given below:
- ``TCP options: port=port[,host=host][,to=to][,ipv4=on|off][,ipv6=on|off][,delay=on|off]``
+ ``TCP options: port=port[,host=host][,to=to][,ipv4=on|off][,ipv6=on|off][,nodelay=on|off]``
``host`` for a listening socket specifies the local address to
be bound. For a connecting socket species the remote host to
connect to. ``host`` is optional for listening sockets. If not
@@ -3204,7 +3204,7 @@ The available backends are:
or IPv6 must be used. If neither is specified the socket may
use either protocol.
- ``delay=on|off`` disables the Nagle algorithm.
+ ``nodelay=on|off`` disables the Nagle algorithm.
``unix options: path=path[,abstract=on|off][,tight=on|off]``
``path`` specifies the local path of the unix socket. ``path``
@@ -3593,13 +3593,13 @@ SRST
``telnet options:``
localhost 5555
- ``tcp:[host]:port[,server=on|off][,wait=on|off][,delay=on|off][,reconnect=seconds]``
+ ``tcp:[host]:port[,server=on|off][,wait=on|off][,nodelay=on|off][,reconnect=seconds]``
The TCP Net Console has two modes of operation. It can send the
serial I/O to a location or wait for a connection from a
location. By default the TCP Net Console is sent to host at the
port. If you use the ``server=on`` option QEMU will wait for a client
socket application to connect to the port before continuing,
- unless the ``wait=on|off`` option was specified. The ``delay=on|off``
+ unless the ``wait=on|off`` option was specified. The ``nodelay=on|off``
option disables the Nagle buffering algorithm. The ``reconnect=on``
option only applies if ``server=no`` is set, if the connection goes
down it will attempt to reconnect at the given interval. If host
@@ -3616,7 +3616,7 @@ SRST
``Example to not wait and listen on ip 192.168.0.100 port 4444``
-serial tcp:192.168.0.100:4444,server=on,wait=off
- ``telnet:host:port[,server=on|off][,wait=on|off][,delay=on|off]``
+ ``telnet:host:port[,server=on|off][,wait=on|off][,nodelay=on|off]``
The telnet protocol is used instead of raw tcp sockets. The
options work the same as if you had specified ``-serial tcp``.
The difference is that the port acts like a telnet server or
@@ -3626,7 +3626,7 @@ SRST
you do it with Control-] and then type "send break" followed by
pressing the enter key.
- ``websocket:host:port,server=on[,wait=on|off][,delay=on|off]``
+ ``websocket:host:port,server=on[,wait=on|off][,nodelay=on|off]``
The WebSocket protocol is used instead of raw tcp socket. The
port acts as a WebSocket server. Client mode is not supported.
diff --git a/qga/vss-win32/meson.build b/qga/vss-win32/meson.build
index 780c461432..90825edef3 100644
--- a/qga/vss-win32/meson.build
+++ b/qga/vss-win32/meson.build
@@ -1,5 +1,5 @@
if add_languages('cpp', required: false)
- glib_static = dependency('glib-2.0', static: true)
+ glib_dynamic = dependency('glib-2.0', static: false)
link_args = cc.get_supported_link_arguments(['-fstack-protector-all', '-fstack-protector-strong',
'-Wl,--add-stdcall-alias', '-Wl,--enable-stdcall-fixup'])
@@ -8,7 +8,7 @@ if add_languages('cpp', required: false)
cpp_args: ['-Wno-unknown-pragmas', '-Wno-delete-non-virtual-dtor', '-Wno-non-virtual-dtor'],
link_args: link_args,
vs_module_defs: 'qga-vss.def',
- dependencies: [glib_static, socket,
+ dependencies: [glib_dynamic, socket,
cc.find_library('ole32'),
cc.find_library('oleaut32'),
cc.find_library('shlwapi'),
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index 1e9ad6f08a..7661270b98 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -8,6 +8,7 @@
#include "qapi/qobject-input-visitor.h"
#include "qom/object_interfaces.h"
#include "qemu/help_option.h"
+#include "qemu/id.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qapi/opts-visitor.h"
@@ -41,11 +42,19 @@ Object *user_creatable_add_type(const char *type, const char *id,
const QDict *qdict,
Visitor *v, Error **errp)
{
+ ERRP_GUARD();
Object *obj;
ObjectClass *klass;
const QDictEntry *e;
Error *local_err = NULL;
+ if (id != NULL && !id_wellformed(id)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
+ error_append_hint(errp, "Identifiers consist of letters, digits, "
+ "'-', '.', '_', starting with a letter.\n");
+ return NULL;
+ }
+
klass = object_class_by_name(type);
if (!klass) {
error_setg(errp, "invalid object type: %s", type);
diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
index 2733d92f2d..7b9389b47b 100644
--- a/scsi/qemu-pr-helper.c
+++ b/scsi/qemu-pr-helper.c
@@ -149,19 +149,29 @@ static int do_sgio_worker(void *opaque)
io_hdr.dxferp = (char *)data->buf;
io_hdr.dxfer_len = data->sz;
ret = ioctl(data->fd, SG_IO, &io_hdr);
- status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr,
- &sense_code);
+
+ if (ret < 0) {
+ status = scsi_sense_from_errno(errno, &sense_code);
+ if (status == CHECK_CONDITION) {
+ scsi_build_sense(data->sense, sense_code);
+ }
+ } else if (io_hdr.host_status != SCSI_HOST_OK) {
+ status = scsi_sense_from_host_status(io_hdr.host_status, &sense_code);
+ if (status == CHECK_CONDITION) {
+ scsi_build_sense(data->sense, sense_code);
+ }
+ } else if (io_hdr.driver_status & SG_ERR_DRIVER_TIMEOUT) {
+ status = BUSY;
+ } else {
+ status = io_hdr.status;
+ }
+
if (status == GOOD) {
data->sz -= io_hdr.resid;
} else {
data->sz = 0;
}
- if (status == CHECK_CONDITION &&
- !(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) {
- scsi_build_sense(data->sense, sense_code);
- }
-
return status;
}
diff --git a/scsi/utils.c b/scsi/utils.c
index 6b56e01002..873e05aeaf 100644
--- a/scsi/utils.c
+++ b/scsi/utils.c
@@ -257,6 +257,21 @@ const struct SCSISense sense_code_LUN_COMM_FAILURE = {
.key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00
};
+/* Command aborted, LUN does not respond to selection */
+const struct SCSISense sense_code_LUN_NOT_RESPONDING = {
+ .key = ABORTED_COMMAND, .asc = 0x05, .ascq = 0x00
+};
+
+/* Command aborted, Command Timeout during processing */
+const struct SCSISense sense_code_COMMAND_TIMEOUT = {
+ .key = ABORTED_COMMAND, .asc = 0x2e, .ascq = 0x02
+};
+
+/* Command aborted, Commands cleared by device server */
+const struct SCSISense sense_code_COMMAND_ABORTED = {
+ .key = ABORTED_COMMAND, .asc = 0x2f, .ascq = 0x02
+};
+
/* Medium Error, Unrecovered read error */
const struct SCSISense sense_code_READ_ERROR = {
.key = MEDIUM_ERROR, .asc = 0x11, .ascq = 0x00
@@ -605,28 +620,41 @@ int scsi_sense_from_errno(int errno_value, SCSISense *sense)
}
}
-#ifdef CONFIG_LINUX
-int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
- SCSISense *sense)
+int scsi_sense_from_host_status(uint8_t host_status,
+ SCSISense *sense)
{
- if (errno_value != 0) {
- return scsi_sense_from_errno(errno_value, sense);
- } else {
- if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT ||
- io_hdr->host_status == SG_ERR_DID_BUS_BUSY ||
- io_hdr->host_status == SG_ERR_DID_TIME_OUT ||
- (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) {
- return BUSY;
- } else if (io_hdr->host_status) {
- *sense = SENSE_CODE(I_T_NEXUS_LOSS);
- return CHECK_CONDITION;
- } else if (io_hdr->status) {
- return io_hdr->status;
- } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
- return CHECK_CONDITION;
- } else {
- return GOOD;
- }
+ switch (host_status) {
+ case SCSI_HOST_NO_LUN:
+ *sense = SENSE_CODE(LUN_NOT_RESPONDING);
+ return CHECK_CONDITION;
+ case SCSI_HOST_BUSY:
+ return BUSY;
+ case SCSI_HOST_TIME_OUT:
+ *sense = SENSE_CODE(COMMAND_TIMEOUT);
+ return CHECK_CONDITION;
+ case SCSI_HOST_BAD_RESPONSE:
+ *sense = SENSE_CODE(LUN_COMM_FAILURE);
+ return CHECK_CONDITION;
+ case SCSI_HOST_ABORTED:
+ *sense = SENSE_CODE(COMMAND_ABORTED);
+ return CHECK_CONDITION;
+ case SCSI_HOST_RESET:
+ *sense = SENSE_CODE(RESET);
+ return CHECK_CONDITION;
+ case SCSI_HOST_TRANSPORT_DISRUPTED:
+ *sense = SENSE_CODE(I_T_NEXUS_LOSS);
+ return CHECK_CONDITION;
+ case SCSI_HOST_TARGET_FAILURE:
+ *sense = SENSE_CODE(TARGET_FAILURE);
+ return CHECK_CONDITION;
+ case SCSI_HOST_RESERVATION_ERROR:
+ return RESERVATION_CONFLICT;
+ case SCSI_HOST_ALLOCATION_FAILURE:
+ *sense = SENSE_CODE(SPACE_ALLOC_FAILED);
+ return CHECK_CONDITION;
+ case SCSI_HOST_MEDIUM_ERROR:
+ *sense = SENSE_CODE(READ_ERROR);
+ return CHECK_CONDITION;
}
+ return GOOD;
}
-#endif
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 10bd8a10a3..ff488ea3e7 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -2062,17 +2062,19 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
return 0;
}
-static int qemu_read_default_config_file(void)
+static void qemu_read_default_config_file(Error **errp)
{
+ ERRP_GUARD();
int ret;
g_autofree char *file = get_relocated_path(CONFIG_QEMU_CONFDIR "/qemu.conf");
- ret = qemu_read_config_file(file);
- if (ret < 0 && ret != -ENOENT) {
- return ret;
+ ret = qemu_read_config_file(file, errp);
+ if (ret < 0) {
+ if (ret == -ENOENT) {
+ error_free(*errp);
+ *errp = NULL;
+ }
}
-
- return 0;
}
static int qemu_set_option(const char *str)
@@ -2361,13 +2363,10 @@ static void qemu_process_early_options(void)
cleanup_add_fd, NULL, &error_fatal);
#endif
- if (!trace_init_backends()) {
- exit(1);
- }
- trace_init_file();
-
/* Open the logfile at this point and set the log mask if necessary. */
- qemu_set_log_filename(log_file, &error_fatal);
+ if (log_file) {
+ qemu_set_log_filename(log_file, &error_fatal);
+ }
if (log_mask) {
int mask;
mask = qemu_str_to_log_mask(log_mask);
@@ -2638,9 +2637,7 @@ void qemu_init(int argc, char **argv, char **envp)
}
if (userconfig) {
- if (qemu_read_default_config_file() < 0) {
- exit(1);
- }
+ qemu_read_default_config_file(&error_fatal);
}
/* second pass of option parsing */
@@ -3328,15 +3325,8 @@ void qemu_init(int argc, char **argv, char **envp)
qemu_plugin_opt_parse(optarg, &plugin_list);
break;
case QEMU_OPTION_readconfig:
- {
- int ret = qemu_read_config_file(optarg);
- if (ret < 0) {
- error_report("read config %s: %s", optarg,
- strerror(-ret));
- exit(1);
- }
- break;
- }
+ qemu_read_config_file(optarg, &error_fatal);
+ break;
case QEMU_OPTION_spice:
olist = qemu_find_opts_err("spice", NULL);
if (!olist) {
@@ -3475,6 +3465,19 @@ void qemu_init(int argc, char **argv, char **envp)
qemu_process_help_options();
qemu_maybe_daemonize(pid_file);
+ /*
+ * The trace backend must be initialized after daemonizing.
+ * trace_init_backends() will call st_init(), which will create the
+ * trace thread in the parent, and also register st_flush_trace_buffer()
+ * in atexit(). This function will force the parent to wait for the
+ * writeout thread to finish, which will not occur, and the parent
+ * process will be left in the host.
+ */
+ if (!trace_init_backends()) {
+ exit(1);
+ }
+ trace_init_file();
+
qemu_init_main_loop(&error_fatal);
cpu_timers_init();
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index b8bc89e71f..6facb66f4d 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1972,7 +1972,8 @@ static void cortex_a8_initfn(Object *obj)
}
static const ARMCPRegInfo cortexa9_cp_reginfo[] = {
- /* power_control should be set to maximum latency. Again,
+ /*
+ * power_control should be set to maximum latency. Again,
* default to 0 and set by private hook
*/
{ .name = "A9_PWRCTL", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0,
@@ -2009,7 +2010,8 @@ static void cortex_a9_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
set_feature(&cpu->env, ARM_FEATURE_EL3);
- /* Note that A9 supports the MP extensions even for
+ /*
+ * Note that A9 supports the MP extensions even for
* A9UP and single-core A9MP (which are both different
* and valid configurations; we don't model A9UP).
*/
@@ -2046,7 +2048,8 @@ static uint64_t a15_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
MachineState *ms = MACHINE(qdev_get_machine());
- /* Linux wants the number of processors from here.
+ /*
+ * Linux wants the number of processors from here.
* Might as well set the interrupt-controller bit too.
*/
return ((ms->smp.cpus - 1) << 24) | (1 << 23);
@@ -2093,7 +2096,8 @@ static void cortex_a7_initfn(Object *obj)
cpu->isar.id_mmfr1 = 0x40000000;
cpu->isar.id_mmfr2 = 0x01240000;
cpu->isar.id_mmfr3 = 0x02102211;
- /* a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but
+ /*
+ * a7_mpcore_r0p5_trm, page 4-4 gives 0x01101110; but
* table 4-41 gives 0x02101110, which includes the arm div insns.
*/
cpu->isar.id_isar0 = 0x02101110;
@@ -2217,6 +2221,10 @@ static void arm_max_initfn(Object *obj)
t = cpu->isar.id_pfr0;
t = FIELD_DP32(t, ID_PFR0, DIT, 1);
cpu->isar.id_pfr0 = t;
+
+ t = cpu->isar.id_pfr2;
+ t = FIELD_DP32(t, ID_PFR2, SSBS, 1);
+ cpu->isar.id_pfr2 = t;
}
#endif
}
@@ -2380,12 +2388,6 @@ static const TypeInfo arm_cpu_type_info = {
.class_init = arm_cpu_class_init,
};
-static const TypeInfo idau_interface_type_info = {
- .name = TYPE_IDAU_INTERFACE,
- .parent = TYPE_INTERFACE,
- .class_size = sizeof(IDAUInterfaceClass),
-};
-
static void arm_cpu_register_types(void)
{
const size_t cpu_count = ARRAY_SIZE(arm_cpus);
@@ -2399,7 +2401,6 @@ static void arm_cpu_register_types(void)
if (cpu_count) {
size_t i;
- type_register_static(&idau_interface_type_info);
for (i = 0; i < cpu_count; ++i) {
arm_cpu_register(&arm_cpus[i]);
}
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index efa1618c4d..193a49ec7f 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1206,6 +1206,7 @@ void pmu_init(ARMCPU *cpu);
#define SCTLR_TE (1U << 30) /* AArch32 only */
#define SCTLR_EnIB (1U << 30) /* v8.3, AArch64 only */
#define SCTLR_EnIA (1U << 31) /* v8.3, AArch64 only */
+#define SCTLR_DSSBS_32 (1U << 31) /* v8.5, AArch32 only */
#define SCTLR_BT0 (1ULL << 35) /* v8.5-BTI */
#define SCTLR_BT1 (1ULL << 36) /* v8.5-BTI */
#define SCTLR_ITFSB (1ULL << 37) /* v8.5-MemTag */
@@ -1213,7 +1214,7 @@ void pmu_init(ARMCPU *cpu);
#define SCTLR_TCF (3ULL << 40) /* v8.5-MemTag */
#define SCTLR_ATA0 (1ULL << 42) /* v8.5-MemTag */
#define SCTLR_ATA (1ULL << 43) /* v8.5-MemTag */
-#define SCTLR_DSSBS (1ULL << 44) /* v8.5 */
+#define SCTLR_DSSBS_64 (1ULL << 44) /* v8.5, AArch64 only */
#define CPTR_TCPAC (1U << 31)
#define CPTR_TTA (1U << 20)
@@ -1250,6 +1251,7 @@ void pmu_init(ARMCPU *cpu);
#define CPSR_IL (1U << 20)
#define CPSR_DIT (1U << 21)
#define CPSR_PAN (1U << 22)
+#define CPSR_SSBS (1U << 23)
#define CPSR_J (1U << 24)
#define CPSR_IT_0_1 (3U << 25)
#define CPSR_Q (1U << 27)
@@ -1312,6 +1314,7 @@ void pmu_init(ARMCPU *cpu);
#define PSTATE_A (1U << 8)
#define PSTATE_D (1U << 9)
#define PSTATE_BTYPE (3U << 10)
+#define PSTATE_SSBS (1U << 12)
#define PSTATE_IL (1U << 20)
#define PSTATE_SS (1U << 21)
#define PSTATE_PAN (1U << 22)
@@ -3915,6 +3918,11 @@ static inline bool isar_feature_aa32_dit(const ARMISARegisters *id)
return FIELD_EX32(id->id_pfr0, ID_PFR0, DIT) != 0;
}
+static inline bool isar_feature_aa32_ssbs(const ARMISARegisters *id)
+{
+ return FIELD_EX32(id->id_pfr2, ID_PFR2, SSBS) != 0;
+}
+
/*
* 64-bit feature tests via id registers.
*/
@@ -4169,6 +4177,11 @@ static inline bool isar_feature_aa64_dit(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, DIT) != 0;
}
+static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0;
+}
+
/*
* Feature tests for "does this exist in either 32-bit or 64-bit?"
*/
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index c255f1bcc3..f0a9e968c9 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -674,6 +674,7 @@ static void aarch64_max_initfn(Object *obj)
t = cpu->isar.id_aa64pfr1;
t = FIELD_DP64(t, ID_AA64PFR1, BT, 1);
+ t = FIELD_DP64(t, ID_AA64PFR1, SSBS, 2);
/*
* Begin with full support for MTE. This will be downgraded to MTE=0
* during realize if the board provides no tag memory, much like
@@ -723,6 +724,10 @@ static void aarch64_max_initfn(Object *obj)
u = FIELD_DP32(u, ID_PFR0, DIT, 1);
cpu->isar.id_pfr0 = u;
+ u = cpu->isar.id_pfr2;
+ u = FIELD_DP32(u, ID_PFR2, SSBS, 1);
+ cpu->isar.id_pfr2 = u;
+
u = cpu->isar.id_mmfr3;
u = FIELD_DP32(u, ID_MMFR3, PAN, 2); /* ATS1E1 */
cpu->isar.id_mmfr3 = u;
diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c
index c29b434c60..fb07a33693 100644
--- a/target/arm/cpu_tcg.c
+++ b/target/arm/cpu_tcg.c
@@ -14,6 +14,7 @@
#include "hw/core/tcg-cpu-ops.h"
#endif /* CONFIG_TCG */
#include "internals.h"
+#include "target/arm/idau.h"
/* CPU models. These are not needed for the AArch64 linux-user build. */
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
@@ -739,10 +740,17 @@ static const ARMCPUInfo arm_tcg_cpus[] = {
{ .name = "pxa270-c5", .initfn = pxa270c5_initfn },
};
+static const TypeInfo idau_interface_type_info = {
+ .name = TYPE_IDAU_INTERFACE,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(IDAUInterfaceClass),
+};
+
static void arm_tcg_cpu_register_types(void)
{
size_t i;
+ type_register_static(&idau_interface_type_info);
for (i = 0; i < ARRAY_SIZE(arm_tcg_cpus); ++i) {
arm_cpu_register(&arm_tcg_cpus[i]);
}
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
index 7f56c78fa6..061c8ff846 100644
--- a/target/arm/helper-a64.c
+++ b/target/arm/helper-a64.c
@@ -179,38 +179,6 @@ float64 HELPER(vfp_mulxd)(float64 a, float64 b, void *fpstp)
return float64_mul(a, b, fpst);
}
-uint64_t HELPER(simd_tbl)(CPUARMState *env, uint64_t result, uint64_t indices,
- uint32_t rn, uint32_t numregs)
-{
- /* Helper function for SIMD TBL and TBX. We have to do the table
- * lookup part for the 64 bits worth of indices we're passed in.
- * result is the initial results vector (either zeroes for TBL
- * or some guest values for TBX), rn the register number where
- * the table starts, and numregs the number of registers in the table.
- * We return the results of the lookups.
- */
- int shift;
-
- for (shift = 0; shift < 64; shift += 8) {
- int index = extract64(indices, shift, 8);
- if (index < 16 * numregs) {
- /* Convert index (a byte offset into the virtual table
- * which is a series of 128-bit vectors concatenated)
- * into the correct register element plus a bit offset
- * into that element, bearing in mind that the table
- * can wrap around from V31 to V0.
- */
- int elt = (rn * 2 + (index >> 3)) % 64;
- int bitidx = (index & 7) * 8;
- uint64_t *q = aa64_vfp_qreg(env, elt >> 1);
- uint64_t val = extract64(q[elt & 1], bitidx, 8);
-
- result = deposit64(result, shift, 8, val);
- }
- }
- return result;
-}
-
/* 64bit/double versions of the neon float compare functions */
uint64_t HELPER(neon_ceq_f64)(float64 a, float64 b, void *fpstp)
{
diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h
index 7bd6aed659..c139fa81f9 100644
--- a/target/arm/helper-a64.h
+++ b/target/arm/helper-a64.h
@@ -28,7 +28,7 @@ DEF_HELPER_3(vfp_cmps_a64, i64, f32, f32, ptr)
DEF_HELPER_3(vfp_cmpes_a64, i64, f32, f32, ptr)
DEF_HELPER_3(vfp_cmpd_a64, i64, f64, f64, ptr)
DEF_HELPER_3(vfp_cmped_a64, i64, f64, f64, ptr)
-DEF_HELPER_FLAGS_5(simd_tbl, TCG_CALL_NO_RWG_SE, i64, env, i64, i64, i32, i32)
+DEF_HELPER_FLAGS_4(simd_tblx, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_3(vfp_mulxs, TCG_CALL_NO_RWG, f32, f32, f32, ptr)
DEF_HELPER_FLAGS_3(vfp_mulxd, TCG_CALL_NO_RWG, f64, f64, f64, ptr)
DEF_HELPER_FLAGS_3(neon_ceq_f64, TCG_CALL_NO_RWG, i64, i64, i64, ptr)
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 0e1a3b9421..904b0927cd 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -4450,6 +4450,24 @@ static const ARMCPRegInfo dit_reginfo = {
.readfn = aa64_dit_read, .writefn = aa64_dit_write
};
+static uint64_t aa64_ssbs_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ return env->pstate & PSTATE_SSBS;
+}
+
+static void aa64_ssbs_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ env->pstate = (env->pstate & ~PSTATE_SSBS) | (value & PSTATE_SSBS);
+}
+
+static const ARMCPRegInfo ssbs_reginfo = {
+ .name = "SSBS", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 6,
+ .type = ARM_CP_NO_RAW, .access = PL0_RW,
+ .readfn = aa64_ssbs_read, .writefn = aa64_ssbs_write
+};
+
static CPAccessResult aa64_cacheop_poc_access(CPUARMState *env,
const ARMCPRegInfo *ri,
bool isread)
@@ -8244,6 +8262,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (cpu_isar_feature(aa64_dit, cpu)) {
define_one_arm_cp_reg(cpu, &dit_reginfo);
}
+ if (cpu_isar_feature(aa64_ssbs, cpu)) {
+ define_one_arm_cp_reg(cpu, &ssbs_reginfo);
+ }
if (arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu)) {
define_arm_cp_regs(cpu, vhe_reginfo);
@@ -9463,6 +9484,14 @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
env->uncached_cpsr &= ~(CPSR_IL | CPSR_J);
env->daif |= mask;
+ if (cpu_isar_feature(aa32_ssbs, env_archcpu(env))) {
+ if (env->cp15.sctlr_el[new_el] & SCTLR_DSSBS_32) {
+ env->uncached_cpsr |= CPSR_SSBS;
+ } else {
+ env->uncached_cpsr &= ~CPSR_SSBS;
+ }
+ }
+
if (new_mode == ARM_CPU_MODE_HYP) {
env->thumb = (env->cp15.sctlr_el[2] & SCTLR_TE) != 0;
env->elr_el[2] = env->regs[15];
@@ -9973,6 +10002,14 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
new_mode |= PSTATE_TCO;
}
+ if (cpu_isar_feature(aa64_ssbs, cpu)) {
+ if (env->cp15.sctlr_el[new_el] & SCTLR_DSSBS_64) {
+ new_mode |= PSTATE_SSBS;
+ } else {
+ new_mode &= ~PSTATE_SSBS;
+ }
+ }
+
pstate_write(env, PSTATE_DAIF | new_mode);
env->aarch64 = 1;
aarch64_restore_sp(env, new_el);
@@ -13133,7 +13170,7 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
if (FIELD_EX32(flags, TBFLAG_A64, UNPRIV)
&& tbid
&& !(env->pstate & PSTATE_TCO)
- && (sctlr & SCTLR_TCF)
+ && (sctlr & SCTLR_TCF0)
&& allocation_tag_access_enabled(env, 0, sctlr)) {
flags = FIELD_DP32(flags, TBFLAG_A64, MTE0_ACTIVE, 1);
}
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 05cebc8597..f11bd32696 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -987,6 +987,9 @@ static inline uint32_t aarch32_cpsr_valid_mask(uint64_t features,
if (isar_feature_aa32_dit(id)) {
valid |= CPSR_DIT;
}
+ if (isar_feature_aa32_ssbs(id)) {
+ valid |= CPSR_SSBS;
+ }
return valid;
}
@@ -1008,6 +1011,9 @@ static inline uint32_t aarch64_pstate_valid_mask(const ARMISARegisters *id)
if (isar_feature_aa64_dit(id)) {
valid |= PSTATE_DIT;
}
+ if (isar_feature_aa64_ssbs(id)) {
+ valid |= PSTATE_SSBS;
+ }
if (isar_feature_aa64_mte(id)) {
valid |= PSTATE_TCO;
}
diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c
index 1c569336ea..0bbb9ec346 100644
--- a/target/arm/mte_helper.c
+++ b/target/arm/mte_helper.c
@@ -550,10 +550,14 @@ static void mte_check_fail(CPUARMState *env, uint32_t desc,
reg_el = regime_el(env, arm_mmu_idx);
sctlr = env->cp15.sctlr_el[reg_el];
- el = arm_current_el(env);
- if (el == 0) {
+ switch (arm_mmu_idx) {
+ case ARMMMUIdx_E10_0:
+ case ARMMMUIdx_E20_0:
+ el = 0;
tcf = extract64(sctlr, 38, 2);
- } else {
+ break;
+ default:
+ el = reg_el;
tcf = extract64(sctlr, 40, 2);
}
@@ -570,7 +574,8 @@ static void mte_check_fail(CPUARMState *env, uint32_t desc,
env->exception.vaddress = dirty_ptr;
is_write = FIELD_EX32(desc, MTEDESC, WRITE);
- syn = syn_data_abort_no_iss(el != 0, 0, 0, 0, 0, is_write, 0x11);
+ syn = syn_data_abort_no_iss(arm_current_el(env) != 0, 0, 0, 0, 0,
+ is_write, 0x11);
raise_exception(env, EXCP_DATA_ABORT, syn, exception_target_el(env));
/* noreturn, but fall through to the assert anyway */
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index b23a8975d5..b591f096df 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -1703,6 +1703,18 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
tcg_temp_free_i32(t1);
break;
+ case 0x19: /* SSBS */
+ if (!dc_isar_feature(aa64_ssbs, s)) {
+ goto do_unallocated;
+ }
+ if (crm & 1) {
+ set_pstate_bits(PSTATE_SSBS);
+ } else {
+ clear_pstate_bits(PSTATE_SSBS);
+ }
+ /* Don't need to rebuild hflags since SSBS is a nop */
+ break;
+
case 0x1a: /* DIT */
if (!dc_isar_feature(aa64_dit, s)) {
goto do_unallocated;
@@ -7520,10 +7532,8 @@ static void disas_simd_tb(DisasContext *s, uint32_t insn)
int rm = extract32(insn, 16, 5);
int rn = extract32(insn, 5, 5);
int rd = extract32(insn, 0, 5);
- int is_tblx = extract32(insn, 12, 1);
- int len = extract32(insn, 13, 2);
- TCGv_i64 tcg_resl, tcg_resh, tcg_idx;
- TCGv_i32 tcg_regno, tcg_numregs;
+ int is_tbx = extract32(insn, 12, 1);
+ int len = (extract32(insn, 13, 2) + 1) * 16;
if (op2 != 0) {
unallocated_encoding(s);
@@ -7534,53 +7544,11 @@ static void disas_simd_tb(DisasContext *s, uint32_t insn)
return;
}
- /* This does a table lookup: for every byte element in the input
- * we index into a table formed from up to four vector registers,
- * and then the output is the result of the lookups. Our helper
- * function does the lookup operation for a single 64 bit part of
- * the input.
- */
- tcg_resl = tcg_temp_new_i64();
- tcg_resh = NULL;
-
- if (is_tblx) {
- read_vec_element(s, tcg_resl, rd, 0, MO_64);
- } else {
- tcg_gen_movi_i64(tcg_resl, 0);
- }
-
- if (is_q) {
- tcg_resh = tcg_temp_new_i64();
- if (is_tblx) {
- read_vec_element(s, tcg_resh, rd, 1, MO_64);
- } else {
- tcg_gen_movi_i64(tcg_resh, 0);
- }
- }
-
- tcg_idx = tcg_temp_new_i64();
- tcg_regno = tcg_const_i32(rn);
- tcg_numregs = tcg_const_i32(len + 1);
- read_vec_element(s, tcg_idx, rm, 0, MO_64);
- gen_helper_simd_tbl(tcg_resl, cpu_env, tcg_resl, tcg_idx,
- tcg_regno, tcg_numregs);
- if (is_q) {
- read_vec_element(s, tcg_idx, rm, 1, MO_64);
- gen_helper_simd_tbl(tcg_resh, cpu_env, tcg_resh, tcg_idx,
- tcg_regno, tcg_numregs);
- }
- tcg_temp_free_i64(tcg_idx);
- tcg_temp_free_i32(tcg_regno);
- tcg_temp_free_i32(tcg_numregs);
-
- write_vec_element(s, tcg_resl, rd, 0, MO_64);
- tcg_temp_free_i64(tcg_resl);
-
- if (is_q) {
- write_vec_element(s, tcg_resh, rd, 1, MO_64);
- tcg_temp_free_i64(tcg_resh);
- }
- clear_vec_high(s, is_q, rd);
+ tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, rd),
+ vec_full_reg_offset(s, rm), cpu_env,
+ is_q ? 16 : 8, vec_full_reg_size(s),
+ (len << 6) | (is_tbx << 5) | rn,
+ gen_helper_simd_tblx);
}
/* ZIP/UZP/TRN
diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c
index 7174030377..3fbeae87cb 100644
--- a/target/arm/vec_helper.c
+++ b/target/arm/vec_helper.c
@@ -1937,3 +1937,51 @@ DO_VRINT_RMODE(gvec_vrint_rm_h, helper_rinth, uint16_t)
DO_VRINT_RMODE(gvec_vrint_rm_s, helper_rints, uint32_t)
#undef DO_VRINT_RMODE
+
+#ifdef TARGET_AARCH64
+void HELPER(simd_tblx)(void *vd, void *vm, void *venv, uint32_t desc)
+{
+ const uint8_t *indices = vm;
+ CPUARMState *env = venv;
+ size_t oprsz = simd_oprsz(desc);
+ uint32_t rn = extract32(desc, SIMD_DATA_SHIFT, 5);
+ bool is_tbx = extract32(desc, SIMD_DATA_SHIFT + 5, 1);
+ uint32_t table_len = desc >> (SIMD_DATA_SHIFT + 6);
+ union {
+ uint8_t b[16];
+ uint64_t d[2];
+ } result;
+
+ /*
+ * We must construct the final result in a temp, lest the output
+ * overlaps the input table. For TBL, begin with zero; for TBX,
+ * begin with the original register contents. Note that we always
+ * copy 16 bytes here to avoid an extra branch; clearing the high
+ * bits of the register for oprsz == 8 is handled below.
+ */
+ if (is_tbx) {
+ memcpy(&result, vd, 16);
+ } else {
+ memset(&result, 0, 16);
+ }
+
+ for (size_t i = 0; i < oprsz; ++i) {
+ uint32_t index = indices[H1(i)];
+
+ if (index < table_len) {
+ /*
+ * Convert index (a byte offset into the virtual table
+ * which is a series of 128-bit vectors concatenated)
+ * into the correct register element, bearing in mind
+ * that the table can wrap around from V31 to V0.
+ */
+ const uint8_t *table = (const uint8_t *)
+ aa64_vfp_qreg(env, (rn + (index >> 4)) % 32);
+ result.b[H1(i)] = table[H1(index % 16)];
+ }
+ }
+
+ memcpy(vd, &result, 16);
+ clear_tail(vd, oprsz, simd_maxsz(desc));
+}
+#endif
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 0b5755e42b..c8d61daf68 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -4352,8 +4352,13 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
{
uint8_t int3;
- if (cpu_memory_rw_debug(cs, bp->pc, &int3, 1, 0) || int3 != 0xcc ||
- cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
+ if (cpu_memory_rw_debug(cs, bp->pc, &int3, 1, 0)) {
+ return -EINVAL;
+ }
+ if (int3 != 0xcc) {
+ return 0;
+ }
+ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
return -EINVAL;
}
return 0;
diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h
index 714e3b5641..01c4344082 100644
--- a/target/sh4/cpu.h
+++ b/target/sh4/cpu.h
@@ -271,17 +271,6 @@ typedef SuperHCPU ArchCPU;
#include "exec/cpu-all.h"
-/* Memory access type */
-enum {
- /* Privilege */
- ACCESS_PRIV = 0x01,
- /* Direction */
- ACCESS_WRITE = 0x02,
- /* Type of instruction */
- ACCESS_CODE = 0x10,
- ACCESS_INT = 0x20
-};
-
/* MMU control register */
#define MMUCR 0x1F000010
#define MMUCR_AT (1<<0)
diff --git a/target/sh4/helper.c b/target/sh4/helper.c
index 408478ce5d..bd8e034f17 100644
--- a/target/sh4/helper.c
+++ b/target/sh4/helper.c
@@ -330,22 +330,22 @@ static int find_utlb_entry(CPUSH4State * env, target_ulong address, int use_asid
MMU_IADDR_ERROR, MMU_DADDR_ERROR_READ, MMU_DADDR_ERROR_WRITE.
*/
static int get_mmu_address(CPUSH4State * env, target_ulong * physical,
- int *prot, target_ulong address,
- int rw, int access_type)
+ int *prot, target_ulong address,
+ MMUAccessType access_type)
{
int use_asid, n;
tlb_t *matching = NULL;
use_asid = !(env->mmucr & MMUCR_SV) || !(env->sr & (1u << SR_MD));
- if (rw == 2) {
+ if (access_type == MMU_INST_FETCH) {
n = find_itlb_entry(env, address, use_asid);
- if (n >= 0) {
- matching = &env->itlb[n];
+ if (n >= 0) {
+ matching = &env->itlb[n];
if (!(env->sr & (1u << SR_MD)) && !(matching->pr & 2)) {
- n = MMU_ITLB_VIOLATION;
+ n = MMU_ITLB_VIOLATION;
} else {
- *prot = PAGE_EXEC;
+ *prot = PAGE_EXEC;
}
} else {
n = find_utlb_entry(env, address, use_asid);
@@ -365,17 +365,17 @@ static int get_mmu_address(CPUSH4State * env, target_ulong * physical,
} else if (n == MMU_DTLB_MISS) {
n = MMU_ITLB_MISS;
}
- }
+ }
} else {
- n = find_utlb_entry(env, address, use_asid);
- if (n >= 0) {
- matching = &env->utlb[n];
+ n = find_utlb_entry(env, address, use_asid);
+ if (n >= 0) {
+ matching = &env->utlb[n];
if (!(env->sr & (1u << SR_MD)) && !(matching->pr & 2)) {
- n = (rw == 1) ? MMU_DTLB_VIOLATION_WRITE :
- MMU_DTLB_VIOLATION_READ;
- } else if ((rw == 1) && !(matching->pr & 1)) {
+ n = (access_type == MMU_DATA_STORE)
+ ? MMU_DTLB_VIOLATION_WRITE : MMU_DTLB_VIOLATION_READ;
+ } else if ((access_type == MMU_DATA_STORE) && !(matching->pr & 1)) {
n = MMU_DTLB_VIOLATION_WRITE;
- } else if ((rw == 1) && !matching->d) {
+ } else if ((access_type == MMU_DATA_STORE) && !matching->d) {
n = MMU_DTLB_INITIAL_WRITE;
} else {
*prot = PAGE_READ;
@@ -383,56 +383,56 @@ static int get_mmu_address(CPUSH4State * env, target_ulong * physical,
*prot |= PAGE_WRITE;
}
}
- } else if (n == MMU_DTLB_MISS) {
- n = (rw == 1) ? MMU_DTLB_MISS_WRITE :
- MMU_DTLB_MISS_READ;
- }
+ } else if (n == MMU_DTLB_MISS) {
+ n = (access_type == MMU_DATA_STORE)
+ ? MMU_DTLB_MISS_WRITE : MMU_DTLB_MISS_READ;
+ }
}
if (n >= 0) {
- n = MMU_OK;
- *physical = ((matching->ppn << 10) & ~(matching->size - 1)) |
- (address & (matching->size - 1));
+ n = MMU_OK;
+ *physical = ((matching->ppn << 10) & ~(matching->size - 1))
+ | (address & (matching->size - 1));
}
return n;
}
static int get_physical_address(CPUSH4State * env, target_ulong * physical,
int *prot, target_ulong address,
- int rw, int access_type)
+ MMUAccessType access_type)
{
/* P1, P2 and P4 areas do not use translation */
- if ((address >= 0x80000000 && address < 0xc0000000) ||
- address >= 0xe0000000) {
+ if ((address >= 0x80000000 && address < 0xc0000000) || address >= 0xe0000000) {
if (!(env->sr & (1u << SR_MD))
- && (address < 0xe0000000 || address >= 0xe4000000)) {
- /* Unauthorized access in user mode (only store queues are available) */
+ && (address < 0xe0000000 || address >= 0xe4000000)) {
+ /* Unauthorized access in user mode (only store queues are available) */
qemu_log_mask(LOG_GUEST_ERROR, "Unauthorized access\n");
- if (rw == 0)
- return MMU_DADDR_ERROR_READ;
- else if (rw == 1)
- return MMU_DADDR_ERROR_WRITE;
- else
- return MMU_IADDR_ERROR;
- }
- if (address >= 0x80000000 && address < 0xc0000000) {
- /* Mask upper 3 bits for P1 and P2 areas */
- *physical = address & 0x1fffffff;
- } else {
- *physical = address;
- }
- *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return MMU_OK;
+ if (access_type == MMU_DATA_LOAD) {
+ return MMU_DADDR_ERROR_READ;
+ } else if (access_type == MMU_DATA_STORE) {
+ return MMU_DADDR_ERROR_WRITE;
+ } else {
+ return MMU_IADDR_ERROR;
+ }
+ }
+ if (address >= 0x80000000 && address < 0xc0000000) {
+ /* Mask upper 3 bits for P1 and P2 areas */
+ *physical = address & 0x1fffffff;
+ } else {
+ *physical = address;
+ }
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return MMU_OK;
}
/* If MMU is disabled, return the corresponding physical page */
if (!(env->mmucr & MMUCR_AT)) {
- *physical = address & 0x1FFFFFFF;
- *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return MMU_OK;
+ *physical = address & 0x1FFFFFFF;
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return MMU_OK;
}
/* We need to resort to the MMU */
- return get_mmu_address(env, physical, prot, address, rw, access_type);
+ return get_mmu_address(env, physical, prot, address, access_type);
}
hwaddr superh_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
@@ -441,7 +441,8 @@ hwaddr superh_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
target_ulong physical;
int prot;
- get_physical_address(&cpu->env, &physical, &prot, addr, 0, 0);
+ get_physical_address(&cpu->env, &physical, &prot, addr, MMU_DATA_LOAD);
+
return physical;
}
@@ -813,11 +814,9 @@ bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMU_DTLB_VIOLATION_READ);
#else
target_ulong physical;
- int prot, sh_access_type;
+ int prot;
- sh_access_type = ACCESS_INT;
- ret = get_physical_address(env, &physical, &prot, address,
- access_type, sh_access_type);
+ ret = get_physical_address(env, &physical, &prot, address, access_type);
if (ret == MMU_OK) {
address &= TARGET_PAGE_MASK;
diff --git a/tests/fp/meson.build b/tests/fp/meson.build
index 8d739c4d59..1c3eee9955 100644
--- a/tests/fp/meson.build
+++ b/tests/fp/meson.build
@@ -624,7 +624,7 @@ test('fp-test-mulAdd', fptest,
# no fptest_rounding_args
args: fptest_args +
['f16_mulAdd', 'f32_mulAdd', 'f64_mulAdd', 'f128_mulAdd'],
- suite: ['softfloat-slow', 'softfloat-ops-slow'], timeout: 60)
+ suite: ['softfloat-slow', 'softfloat-ops-slow'], timeout: 90)
fpbench = executable(
'fp-bench',
diff --git a/tests/meson.build b/tests/meson.build
index 7d7da6a636..656d211e25 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -237,6 +237,11 @@ test_env = environment()
test_env.set('G_TEST_SRCDIR', meson.current_source_dir())
test_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
+slow_tests = {
+ 'test-crypto-tlscredsx509': 45,
+ 'test-crypto-tlssession': 45
+}
+
foreach test_name, extra: tests
src = [test_name + '.c']
deps = [qemuutil]
@@ -254,6 +259,8 @@ foreach test_name, extra: tests
env: test_env,
args: ['--tap', '-k'],
protocol: 'tap',
+ timeout: slow_tests.get(test_name, 30),
+ priority: slow_tests.get(test_name, 30),
suite: ['unit'])
endforeach
@@ -263,6 +270,7 @@ foreach bench_name, deps: benchs
benchmark(bench_name, exe,
args: ['--tap', '-k'],
protocol: 'tap',
+ timeout: 0,
suite: ['speed'])
endforeach
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index ba6ecaed32..58efc46144 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -4,6 +4,19 @@ if not config_host.has_key('CONFIG_POSIX')
subdir_done()
endif
+slow_qtests = {
+ 'ahci-test' : 60,
+ 'bios-tables-test' : 120,
+ 'boot-serial-test' : 60,
+ 'migration-test' : 150,
+ 'npcm7xx_pwm-test': 150,
+ 'prom-env-test' : 60,
+ 'pxe-test' : 60,
+ 'qos-test' : 60,
+ 'qom-test' : 300,
+ 'test-hmp' : 120,
+}
+
qtests_generic = [
'cdrom-test',
'device-introspect-test',
@@ -141,7 +154,8 @@ qtests_npcm7xx = \
'npcm7xx_rng-test',
'npcm7xx_smbus-test',
'npcm7xx_timer-test',
- 'npcm7xx_watchdog_timer-test']
+ 'npcm7xx_watchdog_timer-test'] + \
+ (slirp.found() ? ['npcm7xx_emc-test'] : [])
qtests_arm = \
(config_all_devices.has_key('CONFIG_CMSDK_APB_DUALTIMER') ? ['cmsdk-apb-dualtimer-test'] : []) + \
(config_all_devices.has_key('CONFIG_CMSDK_APB_TIMER') ? ['cmsdk-apb-timer-test'] : []) + \
@@ -273,6 +287,8 @@ foreach dir : target_dirs
env: qtest_env,
args: ['--tap', '-k'],
protocol: 'tap',
+ timeout: slow_qtests.get(test, 30),
+ priority: slow_qtests.get(test, 30),
suite: ['qtest', 'qtest-' + target_base])
endforeach
endforeach
diff --git a/tests/qtest/npcm7xx_emc-test.c b/tests/qtest/npcm7xx_emc-test.c
new file mode 100644
index 0000000000..7a28173195
--- /dev/null
+++ b/tests/qtest/npcm7xx_emc-test.c
@@ -0,0 +1,862 @@
+/*
+ * QTests for Nuvoton NPCM7xx EMC Modules.
+ *
+ * Copyright 2020 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "libqos/libqos.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qnum.h"
+#include "qemu/bitops.h"
+#include "qemu/iov.h"
+
+/* Name of the emc device. */
+#define TYPE_NPCM7XX_EMC "npcm7xx-emc"
+
+/* Timeout for various operations, in seconds. */
+#define TIMEOUT_SECONDS 10
+
+/* Address in memory of the descriptor. */
+#define DESC_ADDR (1 << 20) /* 1 MiB */
+
+/* Address in memory of the data packet. */
+#define DATA_ADDR (DESC_ADDR + 4096)
+
+#define CRC_LENGTH 4
+
+#define NUM_TX_DESCRIPTORS 3
+#define NUM_RX_DESCRIPTORS 2
+
+/* Size of tx,rx test buffers. */
+#define TX_DATA_LEN 64
+#define RX_DATA_LEN 64
+
+#define TX_STEP_COUNT 10000
+#define RX_STEP_COUNT 10000
+
+/* 32-bit register indices. */
+typedef enum NPCM7xxPWMRegister {
+ /* Control registers. */
+ REG_CAMCMR,
+ REG_CAMEN,
+
+ /* There are 16 CAMn[ML] registers. */
+ REG_CAMM_BASE,
+ REG_CAML_BASE,
+
+ REG_TXDLSA = 0x22,
+ REG_RXDLSA,
+ REG_MCMDR,
+ REG_MIID,
+ REG_MIIDA,
+ REG_FFTCR,
+ REG_TSDR,
+ REG_RSDR,
+ REG_DMARFC,
+ REG_MIEN,
+
+ /* Status registers. */
+ REG_MISTA,
+ REG_MGSTA,
+ REG_MPCNT,
+ REG_MRPC,
+ REG_MRPCC,
+ REG_MREPC,
+ REG_DMARFS,
+ REG_CTXDSA,
+ REG_CTXBSA,
+ REG_CRXDSA,
+ REG_CRXBSA,
+
+ NPCM7XX_NUM_EMC_REGS,
+} NPCM7xxPWMRegister;
+
+enum { NUM_CAMML_REGS = 16 };
+
+/* REG_CAMCMR fields */
+/* Enable CAM Compare */
+#define REG_CAMCMR_ECMP (1 << 4)
+/* Accept Unicast Packet */
+#define REG_CAMCMR_AUP (1 << 0)
+
+/* REG_MCMDR fields */
+/* Software Reset */
+#define REG_MCMDR_SWR (1 << 24)
+/* Frame Transmission On */
+#define REG_MCMDR_TXON (1 << 8)
+/* Accept Long Packet */
+#define REG_MCMDR_ALP (1 << 1)
+/* Frame Reception On */
+#define REG_MCMDR_RXON (1 << 0)
+
+/* REG_MIEN fields */
+/* Enable Transmit Completion Interrupt */
+#define REG_MIEN_ENTXCP (1 << 18)
+/* Enable Transmit Interrupt */
+#define REG_MIEN_ENTXINTR (1 << 16)
+/* Enable Receive Good Interrupt */
+#define REG_MIEN_ENRXGD (1 << 4)
+/* ENable Receive Interrupt */
+#define REG_MIEN_ENRXINTR (1 << 0)
+
+/* REG_MISTA fields */
+/* Transmit Bus Error Interrupt */
+#define REG_MISTA_TXBERR (1 << 24)
+/* Transmit Descriptor Unavailable Interrupt */
+#define REG_MISTA_TDU (1 << 23)
+/* Transmit Completion Interrupt */
+#define REG_MISTA_TXCP (1 << 18)
+/* Transmit Interrupt */
+#define REG_MISTA_TXINTR (1 << 16)
+/* Receive Bus Error Interrupt */
+#define REG_MISTA_RXBERR (1 << 11)
+/* Receive Descriptor Unavailable Interrupt */
+#define REG_MISTA_RDU (1 << 10)
+/* DMA Early Notification Interrupt */
+#define REG_MISTA_DENI (1 << 9)
+/* Maximum Frame Length Interrupt */
+#define REG_MISTA_DFOI (1 << 8)
+/* Receive Good Interrupt */
+#define REG_MISTA_RXGD (1 << 4)
+/* Packet Too Long Interrupt */
+#define REG_MISTA_PTLE (1 << 3)
+/* Receive Interrupt */
+#define REG_MISTA_RXINTR (1 << 0)
+
+typedef struct NPCM7xxEMCTxDesc NPCM7xxEMCTxDesc;
+typedef struct NPCM7xxEMCRxDesc NPCM7xxEMCRxDesc;
+
+struct NPCM7xxEMCTxDesc {
+ uint32_t flags;
+ uint32_t txbsa;
+ uint32_t status_and_length;
+ uint32_t ntxdsa;
+};
+
+struct NPCM7xxEMCRxDesc {
+ uint32_t status_and_length;
+ uint32_t rxbsa;
+ uint32_t reserved;
+ uint32_t nrxdsa;
+};
+
+/* NPCM7xxEMCTxDesc.flags values */
+/* Owner: 0 = cpu, 1 = emc */
+#define TX_DESC_FLAG_OWNER_MASK (1 << 31)
+/* Transmit interrupt enable */
+#define TX_DESC_FLAG_INTEN (1 << 2)
+
+/* NPCM7xxEMCTxDesc.status_and_length values */
+/* Transmission complete */
+#define TX_DESC_STATUS_TXCP (1 << 19)
+/* Transmit interrupt */
+#define TX_DESC_STATUS_TXINTR (1 << 16)
+
+/* NPCM7xxEMCRxDesc.status_and_length values */
+/* Owner: 0b00 = cpu, 0b10 = emc */
+#define RX_DESC_STATUS_OWNER_SHIFT 30
+#define RX_DESC_STATUS_OWNER_MASK 0xc0000000
+/* Frame Reception Complete */
+#define RX_DESC_STATUS_RXGD (1 << 20)
+/* Packet too long */
+#define RX_DESC_STATUS_PTLE (1 << 19)
+/* Receive Interrupt */
+#define RX_DESC_STATUS_RXINTR (1 << 16)
+
+#define RX_DESC_PKT_LEN(word) ((uint32_t) (word) & 0xffff)
+
+typedef struct EMCModule {
+ int rx_irq;
+ int tx_irq;
+ uint64_t base_addr;
+} EMCModule;
+
+typedef struct TestData {
+ const EMCModule *module;
+} TestData;
+
+static const EMCModule emc_module_list[] = {
+ {
+ .rx_irq = 15,
+ .tx_irq = 16,
+ .base_addr = 0xf0825000
+ },
+ {
+ .rx_irq = 114,
+ .tx_irq = 115,
+ .base_addr = 0xf0826000
+ }
+};
+
+/* Returns the index of the EMC module. */
+static int emc_module_index(const EMCModule *mod)
+{
+ ptrdiff_t diff = mod - emc_module_list;
+
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(emc_module_list));
+
+ return diff;
+}
+
+static void packet_test_clear(void *sockets)
+{
+ int *test_sockets = sockets;
+
+ close(test_sockets[0]);
+ g_free(test_sockets);
+}
+
+static int *packet_test_init(int module_num, GString *cmd_line)
+{
+ int *test_sockets = g_new(int, 2);
+ int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, test_sockets);
+ g_assert_cmpint(ret, != , -1);
+
+ /*
+ * KISS and use -nic. We specify two nics (both emc{0,1}) because there's
+ * currently no way to specify only emc1: The driver implicitly relies on
+ * emc[i] == nd_table[i].
+ */
+ if (module_num == 0) {
+ g_string_append_printf(cmd_line,
+ " -nic socket,fd=%d,model=" TYPE_NPCM7XX_EMC " "
+ " -nic user,model=" TYPE_NPCM7XX_EMC " ",
+ test_sockets[1]);
+ } else {
+ g_string_append_printf(cmd_line,
+ " -nic user,model=" TYPE_NPCM7XX_EMC " "
+ " -nic socket,fd=%d,model=" TYPE_NPCM7XX_EMC " ",
+ test_sockets[1]);
+ }
+
+ g_test_queue_destroy(packet_test_clear, test_sockets);
+ return test_sockets;
+}
+
+static uint32_t emc_read(QTestState *qts, const EMCModule *mod,
+ NPCM7xxPWMRegister regno)
+{
+ return qtest_readl(qts, mod->base_addr + regno * sizeof(uint32_t));
+}
+
+static void emc_write(QTestState *qts, const EMCModule *mod,
+ NPCM7xxPWMRegister regno, uint32_t value)
+{
+ qtest_writel(qts, mod->base_addr + regno * sizeof(uint32_t), value);
+}
+
+static void emc_read_tx_desc(QTestState *qts, uint32_t addr,
+ NPCM7xxEMCTxDesc *desc)
+{
+ qtest_memread(qts, addr, desc, sizeof(*desc));
+ desc->flags = le32_to_cpu(desc->flags);
+ desc->txbsa = le32_to_cpu(desc->txbsa);
+ desc->status_and_length = le32_to_cpu(desc->status_and_length);
+ desc->ntxdsa = le32_to_cpu(desc->ntxdsa);
+}
+
+static void emc_write_tx_desc(QTestState *qts, const NPCM7xxEMCTxDesc *desc,
+ uint32_t addr)
+{
+ NPCM7xxEMCTxDesc le_desc;
+
+ le_desc.flags = cpu_to_le32(desc->flags);
+ le_desc.txbsa = cpu_to_le32(desc->txbsa);
+ le_desc.status_and_length = cpu_to_le32(desc->status_and_length);
+ le_desc.ntxdsa = cpu_to_le32(desc->ntxdsa);
+ qtest_memwrite(qts, addr, &le_desc, sizeof(le_desc));
+}
+
+static void emc_read_rx_desc(QTestState *qts, uint32_t addr,
+ NPCM7xxEMCRxDesc *desc)
+{
+ qtest_memread(qts, addr, desc, sizeof(*desc));
+ desc->status_and_length = le32_to_cpu(desc->status_and_length);
+ desc->rxbsa = le32_to_cpu(desc->rxbsa);
+ desc->reserved = le32_to_cpu(desc->reserved);
+ desc->nrxdsa = le32_to_cpu(desc->nrxdsa);
+}
+
+static void emc_write_rx_desc(QTestState *qts, const NPCM7xxEMCRxDesc *desc,
+ uint32_t addr)
+{
+ NPCM7xxEMCRxDesc le_desc;
+
+ le_desc.status_and_length = cpu_to_le32(desc->status_and_length);
+ le_desc.rxbsa = cpu_to_le32(desc->rxbsa);
+ le_desc.reserved = cpu_to_le32(desc->reserved);
+ le_desc.nrxdsa = cpu_to_le32(desc->nrxdsa);
+ qtest_memwrite(qts, addr, &le_desc, sizeof(le_desc));
+}
+
+/*
+ * Reset the EMC module.
+ * The module must be reset before, e.g., TXDLSA,RXDLSA are changed.
+ */
+static bool emc_soft_reset(QTestState *qts, const EMCModule *mod)
+{
+ uint32_t val;
+ uint64_t end_time;
+
+ emc_write(qts, mod, REG_MCMDR, REG_MCMDR_SWR);
+
+ /*
+ * Wait for device to reset as the linux driver does.
+ * During reset the AHB reads 0 for all registers. So first wait for
+ * something that resets to non-zero, and then wait for SWR becoming 0.
+ */
+ end_time = g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
+
+ do {
+ qtest_clock_step(qts, 100);
+ val = emc_read(qts, mod, REG_FFTCR);
+ } while (val == 0 && g_get_monotonic_time() < end_time);
+ if (val != 0) {
+ do {
+ qtest_clock_step(qts, 100);
+ val = emc_read(qts, mod, REG_MCMDR);
+ if ((val & REG_MCMDR_SWR) == 0) {
+ /*
+ * N.B. The CAMs have been reset here, so macaddr matching of
+ * incoming packets will not work.
+ */
+ return true;
+ }
+ } while (g_get_monotonic_time() < end_time);
+ }
+
+ g_message("%s: Timeout expired", __func__);
+ return false;
+}
+
+/* Check emc registers are reset to default value. */
+static void test_init(gconstpointer test_data)
+{
+ const TestData *td = test_data;
+ const EMCModule *mod = td->module;
+ QTestState *qts = qtest_init("-machine quanta-gsj");
+ int i;
+
+#define CHECK_REG(regno, value) \
+ do { \
+ g_assert_cmphex(emc_read(qts, mod, (regno)), ==, (value)); \
+ } while (0)
+
+ CHECK_REG(REG_CAMCMR, 0);
+ CHECK_REG(REG_CAMEN, 0);
+ CHECK_REG(REG_TXDLSA, 0xfffffffc);
+ CHECK_REG(REG_RXDLSA, 0xfffffffc);
+ CHECK_REG(REG_MCMDR, 0);
+ CHECK_REG(REG_MIID, 0);
+ CHECK_REG(REG_MIIDA, 0x00900000);
+ CHECK_REG(REG_FFTCR, 0x0101);
+ CHECK_REG(REG_DMARFC, 0x0800);
+ CHECK_REG(REG_MIEN, 0);
+ CHECK_REG(REG_MISTA, 0);
+ CHECK_REG(REG_MGSTA, 0);
+ CHECK_REG(REG_MPCNT, 0x7fff);
+ CHECK_REG(REG_MRPC, 0);
+ CHECK_REG(REG_MRPCC, 0);
+ CHECK_REG(REG_MREPC, 0);
+ CHECK_REG(REG_DMARFS, 0);
+ CHECK_REG(REG_CTXDSA, 0);
+ CHECK_REG(REG_CTXBSA, 0);
+ CHECK_REG(REG_CRXDSA, 0);
+ CHECK_REG(REG_CRXBSA, 0);
+
+#undef CHECK_REG
+
+ for (i = 0; i < NUM_CAMML_REGS; ++i) {
+ g_assert_cmpuint(emc_read(qts, mod, REG_CAMM_BASE + i * 2), ==,
+ 0);
+ g_assert_cmpuint(emc_read(qts, mod, REG_CAML_BASE + i * 2), ==,
+ 0);
+ }
+
+ qtest_quit(qts);
+}
+
+static bool emc_wait_irq(QTestState *qts, const EMCModule *mod, int step,
+ bool is_tx)
+{
+ uint64_t end_time =
+ g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
+
+ do {
+ if (qtest_get_irq(qts, is_tx ? mod->tx_irq : mod->rx_irq)) {
+ return true;
+ }
+ qtest_clock_step(qts, step);
+ } while (g_get_monotonic_time() < end_time);
+
+ g_message("%s: Timeout expired", __func__);
+ return false;
+}
+
+static bool emc_wait_mista(QTestState *qts, const EMCModule *mod, int step,
+ uint32_t flag)
+{
+ uint64_t end_time =
+ g_get_monotonic_time() + TIMEOUT_SECONDS * G_TIME_SPAN_SECOND;
+
+ do {
+ uint32_t mista = emc_read(qts, mod, REG_MISTA);
+ if (mista & flag) {
+ return true;
+ }
+ qtest_clock_step(qts, step);
+ } while (g_get_monotonic_time() < end_time);
+
+ g_message("%s: Timeout expired", __func__);
+ return false;
+}
+
+static bool wait_socket_readable(int fd)
+{
+ fd_set read_fds;
+ struct timeval tv;
+ int rv;
+
+ FD_ZERO(&read_fds);
+ FD_SET(fd, &read_fds);
+ tv.tv_sec = TIMEOUT_SECONDS;
+ tv.tv_usec = 0;
+ rv = select(fd + 1, &read_fds, NULL, NULL, &tv);
+ if (rv == -1) {
+ perror("select");
+ } else if (rv == 0) {
+ g_message("%s: Timeout expired", __func__);
+ }
+ return rv == 1;
+}
+
+/* Initialize *desc (in host endian format). */
+static void init_tx_desc(NPCM7xxEMCTxDesc *desc, size_t count,
+ uint32_t desc_addr)
+{
+ g_assert(count >= 2);
+ memset(&desc[0], 0, sizeof(*desc) * count);
+ /* Leave the last one alone, owned by the cpu -> stops transmission. */
+ for (size_t i = 0; i < count - 1; ++i) {
+ desc[i].flags =
+ (TX_DESC_FLAG_OWNER_MASK | /* owner = 1: emc */
+ TX_DESC_FLAG_INTEN |
+ 0 | /* crc append = 0 */
+ 0 /* padding enable = 0 */);
+ desc[i].status_and_length =
+ (0 | /* collision count = 0 */
+ 0 | /* SQE = 0 */
+ 0 | /* PAU = 0 */
+ 0 | /* TXHA = 0 */
+ 0 | /* LC = 0 */
+ 0 | /* TXABT = 0 */
+ 0 | /* NCS = 0 */
+ 0 | /* EXDEF = 0 */
+ 0 | /* TXCP = 0 */
+ 0 | /* DEF = 0 */
+ 0 | /* TXINTR = 0 */
+ 0 /* length filled in later */);
+ desc[i].ntxdsa = desc_addr + (i + 1) * sizeof(*desc);
+ }
+}
+
+static void enable_tx(QTestState *qts, const EMCModule *mod,
+ const NPCM7xxEMCTxDesc *desc, size_t count,
+ uint32_t desc_addr, uint32_t mien_flags)
+{
+ /* Write the descriptors to guest memory. */
+ for (size_t i = 0; i < count; ++i) {
+ emc_write_tx_desc(qts, desc + i, desc_addr + i * sizeof(*desc));
+ }
+
+ /* Trigger sending the packet. */
+ /* The module must be reset before changing TXDLSA. */
+ g_assert(emc_soft_reset(qts, mod));
+ emc_write(qts, mod, REG_TXDLSA, desc_addr);
+ emc_write(qts, mod, REG_CTXDSA, ~0);
+ emc_write(qts, mod, REG_MIEN, REG_MIEN_ENTXCP | mien_flags);
+ {
+ uint32_t mcmdr = emc_read(qts, mod, REG_MCMDR);
+ mcmdr |= REG_MCMDR_TXON;
+ emc_write(qts, mod, REG_MCMDR, mcmdr);
+ }
+
+ /* Prod the device to send the packet. */
+ emc_write(qts, mod, REG_TSDR, 1);
+}
+
+static void emc_send_verify1(QTestState *qts, const EMCModule *mod, int fd,
+ bool with_irq, uint32_t desc_addr,
+ uint32_t next_desc_addr,
+ const char *test_data, int test_size)
+{
+ NPCM7xxEMCTxDesc result_desc;
+ uint32_t expected_mask, expected_value, recv_len;
+ int ret;
+ char buffer[TX_DATA_LEN];
+
+ g_assert(wait_socket_readable(fd));
+
+ /* Read the descriptor back. */
+ emc_read_tx_desc(qts, desc_addr, &result_desc);
+ /* Descriptor should be owned by cpu now. */
+ g_assert((result_desc.flags & TX_DESC_FLAG_OWNER_MASK) == 0);
+ /* Test the status bits, ignoring the length field. */
+ expected_mask = 0xffff << 16;
+ expected_value = TX_DESC_STATUS_TXCP;
+ if (with_irq) {
+ expected_value |= TX_DESC_STATUS_TXINTR;
+ }
+ g_assert_cmphex((result_desc.status_and_length & expected_mask), ==,
+ expected_value);
+
+ /* Check data sent to the backend. */
+ recv_len = ~0;
+ ret = qemu_recv(fd, &recv_len, sizeof(recv_len), MSG_DONTWAIT);
+ g_assert_cmpint(ret, == , sizeof(recv_len));
+
+ g_assert(wait_socket_readable(fd));
+ memset(buffer, 0xff, sizeof(buffer));
+ ret = qemu_recv(fd, buffer, test_size, MSG_DONTWAIT);
+ g_assert_cmpmem(buffer, ret, test_data, test_size);
+}
+
+static void emc_send_verify(QTestState *qts, const EMCModule *mod, int fd,
+ bool with_irq)
+{
+ NPCM7xxEMCTxDesc desc[NUM_TX_DESCRIPTORS];
+ uint32_t desc_addr = DESC_ADDR;
+ static const char test1_data[] = "TEST1";
+ static const char test2_data[] = "Testing 1 2 3 ...";
+ uint32_t data1_addr = DATA_ADDR;
+ uint32_t data2_addr = data1_addr + sizeof(test1_data);
+ bool got_tdu;
+ uint32_t end_desc_addr;
+
+ /* Prepare test data buffer. */
+ qtest_memwrite(qts, data1_addr, test1_data, sizeof(test1_data));
+ qtest_memwrite(qts, data2_addr, test2_data, sizeof(test2_data));
+
+ init_tx_desc(&desc[0], NUM_TX_DESCRIPTORS, desc_addr);
+ desc[0].txbsa = data1_addr;
+ desc[0].status_and_length |= sizeof(test1_data);
+ desc[1].txbsa = data2_addr;
+ desc[1].status_and_length |= sizeof(test2_data);
+
+ enable_tx(qts, mod, &desc[0], NUM_TX_DESCRIPTORS, desc_addr,
+ with_irq ? REG_MIEN_ENTXINTR : 0);
+
+ /*
+ * It's problematic to observe the interrupt for each packet.
+ * Instead just wait until all the packets go out.
+ */
+ got_tdu = false;
+ while (!got_tdu) {
+ if (with_irq) {
+ g_assert_true(emc_wait_irq(qts, mod, TX_STEP_COUNT,
+ /*is_tx=*/true));
+ } else {
+ g_assert_true(emc_wait_mista(qts, mod, TX_STEP_COUNT,
+ REG_MISTA_TXINTR));
+ }
+ got_tdu = !!(emc_read(qts, mod, REG_MISTA) & REG_MISTA_TDU);
+ /* If we don't have TDU yet, reset the interrupt. */
+ if (!got_tdu) {
+ emc_write(qts, mod, REG_MISTA,
+ emc_read(qts, mod, REG_MISTA) & 0xffff0000);
+ }
+ }
+
+ end_desc_addr = desc_addr + 2 * sizeof(desc[0]);
+ g_assert_cmphex(emc_read(qts, mod, REG_CTXDSA), ==, end_desc_addr);
+ g_assert_cmphex(emc_read(qts, mod, REG_MISTA), ==,
+ REG_MISTA_TXCP | REG_MISTA_TXINTR | REG_MISTA_TDU);
+
+ emc_send_verify1(qts, mod, fd, with_irq,
+ desc_addr, end_desc_addr,
+ test1_data, sizeof(test1_data));
+ emc_send_verify1(qts, mod, fd, with_irq,
+ desc_addr + sizeof(desc[0]), end_desc_addr,
+ test2_data, sizeof(test2_data));
+}
+
+/* Initialize *desc (in host endian format). */
+static void init_rx_desc(NPCM7xxEMCRxDesc *desc, size_t count,
+ uint32_t desc_addr, uint32_t data_addr)
+{
+ g_assert_true(count >= 2);
+ memset(desc, 0, sizeof(*desc) * count);
+ desc[0].rxbsa = data_addr;
+ desc[0].status_and_length =
+ (0b10 << RX_DESC_STATUS_OWNER_SHIFT | /* owner = 10: emc */
+ 0 | /* RP = 0 */
+ 0 | /* ALIE = 0 */
+ 0 | /* RXGD = 0 */
+ 0 | /* PTLE = 0 */
+ 0 | /* CRCE = 0 */
+ 0 | /* RXINTR = 0 */
+ 0 /* length (filled in later) */);
+ /* Leave the last one alone, owned by the cpu -> stops transmission. */
+ desc[0].nrxdsa = desc_addr + sizeof(*desc);
+}
+
+static void enable_rx(QTestState *qts, const EMCModule *mod,
+ const NPCM7xxEMCRxDesc *desc, size_t count,
+ uint32_t desc_addr, uint32_t mien_flags,
+ uint32_t mcmdr_flags)
+{
+ /*
+ * Write the descriptor to guest memory.
+ * FWIW, IWBN if the docs said the buffer needs to be at least DMARFC
+ * bytes.
+ */
+ for (size_t i = 0; i < count; ++i) {
+ emc_write_rx_desc(qts, desc + i, desc_addr + i * sizeof(*desc));
+ }
+
+ /* Trigger receiving the packet. */
+ /* The module must be reset before changing RXDLSA. */
+ g_assert(emc_soft_reset(qts, mod));
+ emc_write(qts, mod, REG_RXDLSA, desc_addr);
+ emc_write(qts, mod, REG_MIEN, REG_MIEN_ENRXGD | mien_flags);
+
+ /*
+ * We don't know what the device's macaddr is, so just accept all
+ * unicast packets (AUP).
+ */
+ emc_write(qts, mod, REG_CAMCMR, REG_CAMCMR_AUP);
+ emc_write(qts, mod, REG_CAMEN, 1 << 0);
+ {
+ uint32_t mcmdr = emc_read(qts, mod, REG_MCMDR);
+ mcmdr |= REG_MCMDR_RXON | mcmdr_flags;
+ emc_write(qts, mod, REG_MCMDR, mcmdr);
+ }
+
+ /* Prod the device to accept a packet. */
+ emc_write(qts, mod, REG_RSDR, 1);
+}
+
+static void emc_recv_verify(QTestState *qts, const EMCModule *mod, int fd,
+ bool with_irq)
+{
+ NPCM7xxEMCRxDesc desc[NUM_RX_DESCRIPTORS];
+ uint32_t desc_addr = DESC_ADDR;
+ uint32_t data_addr = DATA_ADDR;
+ int ret;
+ uint32_t expected_mask, expected_value;
+ NPCM7xxEMCRxDesc result_desc;
+
+ /* Prepare test data buffer. */
+ const char test[RX_DATA_LEN] = "TEST";
+ int len = htonl(sizeof(test));
+ const struct iovec iov[] = {
+ {
+ .iov_base = &len,
+ .iov_len = sizeof(len),
+ },{
+ .iov_base = (char *) test,
+ .iov_len = sizeof(test),
+ },
+ };
+
+ /*
+ * Reset the device BEFORE sending a test packet, otherwise the packet
+ * may get swallowed by an active device of an earlier test.
+ */
+ init_rx_desc(&desc[0], NUM_RX_DESCRIPTORS, desc_addr, data_addr);
+ enable_rx(qts, mod, &desc[0], NUM_RX_DESCRIPTORS, desc_addr,
+ with_irq ? REG_MIEN_ENRXINTR : 0, 0);
+
+ /* Send test packet to device's socket. */
+ ret = iov_send(fd, iov, 2, 0, sizeof(len) + sizeof(test));
+ g_assert_cmpint(ret, == , sizeof(test) + sizeof(len));
+
+ /* Wait for RX interrupt. */
+ if (with_irq) {
+ g_assert_true(emc_wait_irq(qts, mod, RX_STEP_COUNT, /*is_tx=*/false));
+ } else {
+ g_assert_true(emc_wait_mista(qts, mod, RX_STEP_COUNT, REG_MISTA_RXGD));
+ }
+
+ g_assert_cmphex(emc_read(qts, mod, REG_CRXDSA), ==,
+ desc_addr + sizeof(desc[0]));
+
+ expected_mask = 0xffff;
+ expected_value = (REG_MISTA_DENI |
+ REG_MISTA_RXGD |
+ REG_MISTA_RXINTR);
+ g_assert_cmphex((emc_read(qts, mod, REG_MISTA) & expected_mask),
+ ==, expected_value);
+
+ /* Read the descriptor back. */
+ emc_read_rx_desc(qts, desc_addr, &result_desc);
+ /* Descriptor should be owned by cpu now. */
+ g_assert((result_desc.status_and_length & RX_DESC_STATUS_OWNER_MASK) == 0);
+ /* Test the status bits, ignoring the length field. */
+ expected_mask = 0xffff << 16;
+ expected_value = RX_DESC_STATUS_RXGD;
+ if (with_irq) {
+ expected_value |= RX_DESC_STATUS_RXINTR;
+ }
+ g_assert_cmphex((result_desc.status_and_length & expected_mask), ==,
+ expected_value);
+ g_assert_cmpint(RX_DESC_PKT_LEN(result_desc.status_and_length), ==,
+ RX_DATA_LEN + CRC_LENGTH);
+
+ {
+ char buffer[RX_DATA_LEN];
+ qtest_memread(qts, data_addr, buffer, sizeof(buffer));
+ g_assert_cmpstr(buffer, == , "TEST");
+ }
+}
+
+static void emc_test_ptle(QTestState *qts, const EMCModule *mod, int fd)
+{
+ NPCM7xxEMCRxDesc desc[NUM_RX_DESCRIPTORS];
+ uint32_t desc_addr = DESC_ADDR;
+ uint32_t data_addr = DATA_ADDR;
+ int ret;
+ NPCM7xxEMCRxDesc result_desc;
+ uint32_t expected_mask, expected_value;
+
+ /* Prepare test data buffer. */
+#define PTLE_DATA_LEN 1600
+ char test_data[PTLE_DATA_LEN];
+ int len = htonl(sizeof(test_data));
+ const struct iovec iov[] = {
+ {
+ .iov_base = &len,
+ .iov_len = sizeof(len),
+ },{
+ .iov_base = (char *) test_data,
+ .iov_len = sizeof(test_data),
+ },
+ };
+ memset(test_data, 42, sizeof(test_data));
+
+ /*
+ * Reset the device BEFORE sending a test packet, otherwise the packet
+ * may get swallowed by an active device of an earlier test.
+ */
+ init_rx_desc(&desc[0], NUM_RX_DESCRIPTORS, desc_addr, data_addr);
+ enable_rx(qts, mod, &desc[0], NUM_RX_DESCRIPTORS, desc_addr,
+ REG_MIEN_ENRXINTR, REG_MCMDR_ALP);
+
+ /* Send test packet to device's socket. */
+ ret = iov_send(fd, iov, 2, 0, sizeof(len) + sizeof(test_data));
+ g_assert_cmpint(ret, == , sizeof(test_data) + sizeof(len));
+
+ /* Wait for RX interrupt. */
+ g_assert_true(emc_wait_irq(qts, mod, RX_STEP_COUNT, /*is_tx=*/false));
+
+ /* Read the descriptor back. */
+ emc_read_rx_desc(qts, desc_addr, &result_desc);
+ /* Descriptor should be owned by cpu now. */
+ g_assert((result_desc.status_and_length & RX_DESC_STATUS_OWNER_MASK) == 0);
+ /* Test the status bits, ignoring the length field. */
+ expected_mask = 0xffff << 16;
+ expected_value = (RX_DESC_STATUS_RXGD |
+ RX_DESC_STATUS_PTLE |
+ RX_DESC_STATUS_RXINTR);
+ g_assert_cmphex((result_desc.status_and_length & expected_mask), ==,
+ expected_value);
+ g_assert_cmpint(RX_DESC_PKT_LEN(result_desc.status_and_length), ==,
+ PTLE_DATA_LEN + CRC_LENGTH);
+
+ {
+ char buffer[PTLE_DATA_LEN];
+ qtest_memread(qts, data_addr, buffer, sizeof(buffer));
+ g_assert(memcmp(buffer, test_data, PTLE_DATA_LEN) == 0);
+ }
+}
+
+static void test_tx(gconstpointer test_data)
+{
+ const TestData *td = test_data;
+ GString *cmd_line = g_string_new("-machine quanta-gsj");
+ int *test_sockets = packet_test_init(emc_module_index(td->module),
+ cmd_line);
+ QTestState *qts = qtest_init(cmd_line->str);
+
+ /*
+ * TODO: For pedantic correctness test_sockets[0] should be closed after
+ * the fork and before the exec, but that will require some harness
+ * improvements.
+ */
+ close(test_sockets[1]);
+ /* Defensive programming */
+ test_sockets[1] = -1;
+
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
+
+ emc_send_verify(qts, td->module, test_sockets[0], /*with_irq=*/false);
+ emc_send_verify(qts, td->module, test_sockets[0], /*with_irq=*/true);
+
+ qtest_quit(qts);
+}
+
+static void test_rx(gconstpointer test_data)
+{
+ const TestData *td = test_data;
+ GString *cmd_line = g_string_new("-machine quanta-gsj");
+ int *test_sockets = packet_test_init(emc_module_index(td->module),
+ cmd_line);
+ QTestState *qts = qtest_init(cmd_line->str);
+
+ /*
+ * TODO: For pedantic correctness test_sockets[0] should be closed after
+ * the fork and before the exec, but that will require some harness
+ * improvements.
+ */
+ close(test_sockets[1]);
+ /* Defensive programming */
+ test_sockets[1] = -1;
+
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
+
+ emc_recv_verify(qts, td->module, test_sockets[0], /*with_irq=*/false);
+ emc_recv_verify(qts, td->module, test_sockets[0], /*with_irq=*/true);
+ emc_test_ptle(qts, td->module, test_sockets[0]);
+
+ qtest_quit(qts);
+}
+
+static void emc_add_test(const char *name, const TestData* td,
+ GTestDataFunc fn)
+{
+ g_autofree char *full_name = g_strdup_printf(
+ "npcm7xx_emc/emc[%d]/%s", emc_module_index(td->module), name);
+ qtest_add_data_func(full_name, td, fn);
+}
+#define add_test(name, td) emc_add_test(#name, td, test_##name)
+
+int main(int argc, char **argv)
+{
+ TestData test_data_list[ARRAY_SIZE(emc_module_list)];
+
+ g_test_init(&argc, &argv, NULL);
+
+ for (int i = 0; i < ARRAY_SIZE(emc_module_list); ++i) {
+ TestData *td = &test_data_list[i];
+
+ td->module = &emc_module_list[i];
+
+ add_test(init, td);
+ add_test(tx, td);
+ add_test(rx, td);
+ }
+
+ return g_test_run();
+}
diff --git a/trace/control.c b/trace/control.c
index cd04dd4e0c..4be38e1af2 100644
--- a/trace/control.c
+++ b/trace/control.c
@@ -40,6 +40,7 @@ static size_t nevent_groups;
static uint32_t next_id;
static uint32_t next_vcpu_id;
static bool init_trace_on_startup;
+static char *trace_opts_file;
QemuOptsList qemu_trace_opts = {
.name = "trace",
@@ -224,10 +225,8 @@ static void trace_init_events(const char *fname)
void trace_init_file(void)
{
- QemuOpts *opts = qemu_find_opts_singleton("trace");
- const char *file = qemu_opt_get(opts, "file");
#ifdef CONFIG_TRACE_SIMPLE
- st_set_trace_file(file);
+ st_set_trace_file(trace_opts_file);
if (init_trace_on_startup) {
st_set_trace_file_enabled(true);
}
@@ -238,11 +237,11 @@ void trace_init_file(void)
* backend. However we should only override -D if we actually have
* something to override it with.
*/
- if (file) {
- qemu_set_log_filename(file, &error_fatal);
+ if (trace_opts_file) {
+ qemu_set_log_filename(trace_opts_file, &error_fatal);
}
#else
- if (file) {
+ if (trace_opts_file) {
fprintf(stderr, "error: --trace file=...: "
"option not supported by the selected tracing backends\n");
exit(1);
@@ -303,6 +302,8 @@ void trace_opt_parse(const char *optarg)
}
trace_init_events(qemu_opt_get(opts, "events"));
init_trace_on_startup = true;
+ g_free(trace_opts_file);
+ trace_opts_file = g_strdup(qemu_opt_get(opts, "file"));
qemu_opts_del(opts);
}
diff --git a/util/qemu-config.c b/util/qemu-config.c
index e2a700b284..670bd6ebca 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -350,7 +350,7 @@ void qemu_config_write(FILE *fp)
}
/* Returns number of config groups on success, -errno on error */
-int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
{
char line[1024], group[64], id[64], arg[64], value[1024];
Location loc;
@@ -375,7 +375,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
/* group with id */
list = find_list(lists, group, &local_err);
if (local_err) {
- error_report_err(local_err);
+ error_propagate(errp, local_err);
goto out;
}
opts = qemu_opts_create(list, id, 1, NULL);
@@ -386,7 +386,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
/* group without id */
list = find_list(lists, group, &local_err);
if (local_err) {
- error_report_err(local_err);
+ error_propagate(errp, local_err);
goto out;
}
opts = qemu_opts_create(list, NULL, 0, &error_abort);
@@ -398,21 +398,21 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
sscanf(line, " %63s = \"\"", arg) == 1) {
/* arg = value */
if (opts == NULL) {
- error_report("no group defined");
+ error_setg(errp, "no group defined");
goto out;
}
- if (!qemu_opt_set(opts, arg, value, &local_err)) {
- error_report_err(local_err);
+ if (!qemu_opt_set(opts, arg, value, errp)) {
goto out;
}
continue;
}
- error_report("parse error");
+ error_setg(errp, "parse error");
goto out;
}
if (ferror(fp)) {
- error_report("error reading file");
- goto out;
+ loc_pop(&loc);
+ error_setg_errno(errp, errno, "Cannot read config file");
+ return res;
}
res = count;
out:
@@ -420,16 +420,17 @@ out:
return res;
}
-int qemu_read_config_file(const char *filename)
+int qemu_read_config_file(const char *filename, Error **errp)
{
FILE *f = fopen(filename, "r");
int ret;
if (f == NULL) {
+ error_setg_file_open(errp, errno, filename);
return -errno;
}
- ret = qemu_config_parse(f, vm_config_groups, filename);
+ ret = qemu_config_parse(f, vm_config_groups, filename, errp);
fclose(f);
return ret;
}
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 40564a12eb..9678d5b682 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -785,7 +785,11 @@ static const char *get_opt_name_value(const char *params,
}
if (!is_help && warn_on_flag) {
warn_report("short-form boolean option '%s%s' deprecated", prefix, *name);
- error_printf("Please use %s=%s instead\n", *name, *value);
+ if (g_str_equal(*name, "delay")) {
+ error_printf("Please use nodelay=%s instead\n", prefix[0] ? "on" : "off");
+ } else {
+ error_printf("Please use %s=%s instead\n", *name, *value);
+ }
}
}
} else {