Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9027aa6395 | ||
|
|
b1efa5c236 | ||
|
|
df9168b019 | ||
|
|
3cdd1f45aa | ||
|
|
7f5f3e5acd | ||
|
|
154ed561b3 | ||
|
|
3e7d8d2233 | ||
|
|
6726d4874b | ||
|
|
64e16e3886 | ||
|
|
73768dae4a | ||
|
|
d83b61f59c | ||
|
|
803a6864ef | ||
|
|
68a90134c0 | ||
|
|
9c3273c16e | ||
|
|
bcf9282f53 | ||
|
|
cda37a6bd7 | ||
|
|
bb50cc9e75 | ||
|
|
d08e538de8 | ||
|
|
a75e415ca5 | ||
|
|
cf8bd64d4f | ||
|
|
0c85c9746f | ||
|
|
490c737bc7 | ||
|
|
704eaf8219 | ||
|
|
6620335418 | ||
|
|
e8fd97fc1e | ||
|
|
e9f6c32339 | ||
|
|
f3da6934cd | ||
|
|
c96b8c0e39 | ||
|
|
aeade0a251 | ||
|
|
9e00d74a9a | ||
|
|
5cf3b48094 | ||
|
|
ec36d522ce | ||
|
|
f72e697f24 | ||
|
|
3c84a63e2c | ||
|
|
472a420761 | ||
|
|
ab37d6bd89 | ||
|
|
739dabb1ad | ||
|
|
69b4ed0259 | ||
|
|
b692aea803 | ||
|
|
033367d0af | ||
|
|
cefb009762 | ||
|
|
413f7ba6a8 | ||
|
|
80f66f3d22 | ||
|
|
007ea6d6ed | ||
|
|
56e190d73e | ||
|
|
426beec96a | ||
|
|
1408266d1c | ||
|
|
1fc0a58a98 | ||
|
|
39408f6f14 | ||
|
|
16549930bb | ||
|
|
576338eea1 | ||
|
|
44a7e0aaf7 | ||
|
|
7f667fc7fe | ||
|
|
dc203a5987 | ||
|
|
298340c152 | ||
|
|
9b878bd927 | ||
|
|
d1b8423fb8 | ||
|
|
84858471e6 | ||
|
|
ecaf555439 | ||
|
|
1e4ce3dd87 | ||
|
|
4f5adbe697 | ||
|
|
437999ae81 | ||
|
|
3ffbdc3e12 | ||
|
|
37600704dd | ||
|
|
7a9fa39856 | ||
|
|
68b115ddae | ||
|
|
a98c7cee17 | ||
|
|
41945c6bbb | ||
|
|
7988e7c6ba | ||
|
|
4a4426275b |
@@ -207,10 +207,10 @@ clean: recurse-clean
|
||||
|
||||
VERSION = $(shell cat $(SRC_PATH)/VERSION)
|
||||
|
||||
dist: qemu-$(VERSION).tar.bz2
|
||||
dist: qemu-$(VERSION).tar.xz
|
||||
|
||||
qemu-%.tar.bz2:
|
||||
$(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.bz2,%,$@)"
|
||||
qemu-%.tar.xz:
|
||||
$(SRC_PATH)/scripts/make-release "$(SRC_PATH)" "$(patsubst qemu-%.tar.xz,%,$@)"
|
||||
|
||||
distclean: clean recurse-distclean
|
||||
-$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || :
|
||||
|
||||
@@ -53,7 +53,7 @@ cryptodev_vhost_init(
|
||||
CryptoDevBackendVhost *crypto;
|
||||
Error *local_err = NULL;
|
||||
|
||||
crypto = g_new(CryptoDevBackendVhost, 1);
|
||||
crypto = g_new0(CryptoDevBackendVhost, 1);
|
||||
crypto->dev.max_queues = 1;
|
||||
crypto->dev.nvqs = 1;
|
||||
crypto->dev.vqs = crypto->vqs;
|
||||
|
||||
@@ -353,6 +353,7 @@ static void bdrv_qed_detach_aio_context(BlockDriverState *bs)
|
||||
|
||||
qed_cancel_need_check_timer(s);
|
||||
timer_free(s->need_check_timer);
|
||||
s->need_check_timer = NULL;
|
||||
}
|
||||
|
||||
static void bdrv_qed_attach_aio_context(BlockDriverState *bs,
|
||||
|
||||
@@ -296,6 +296,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||
bdrv_graph_wrunlock();
|
||||
|
||||
ret = bdrv_snapshot_goto(fallback_bs, snapshot_id, errp);
|
||||
memset(bs->opaque, 0, drv->instance_size);
|
||||
open_ret = drv->bdrv_open(bs, options, bs->open_flags, &local_err);
|
||||
qobject_unref(options);
|
||||
if (open_ret < 0) {
|
||||
|
||||
@@ -98,7 +98,7 @@ Python runtime
|
||||
option of the ``configure`` script to point QEMU to a supported
|
||||
version of the Python runtime.
|
||||
|
||||
As of QEMU |version|, the minimum supported version of Python is 3.7.
|
||||
As of QEMU |version|, the minimum supported version of Python is 3.8.
|
||||
|
||||
Python build dependencies
|
||||
Some of QEMU's build dependencies are written in Python. Usually these
|
||||
|
||||
@@ -171,7 +171,7 @@ for that architecture.
|
||||
- Unified Hosting Interface (MD01069)
|
||||
* - RISC-V
|
||||
- System and User-mode
|
||||
- https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc
|
||||
- https://github.com/riscv-non-isa/riscv-semihosting/blob/main/riscv-semihosting.adoc
|
||||
* - Xtensa
|
||||
- System
|
||||
- Tensilica ISS SIMCALL
|
||||
|
||||
@@ -260,7 +260,7 @@ Target-dependent emulator sourcesets:
|
||||
Each emulator also includes sources for files in the ``hw/`` and ``target/``
|
||||
subdirectories. The subdirectory used for each emulator comes
|
||||
from the target's definition of ``TARGET_BASE_ARCH`` or (if missing)
|
||||
``TARGET_ARCH``, as found in ``default-configs/targets/*.mak``.
|
||||
``TARGET_ARCH``, as found in ``configs/targets/*.mak``.
|
||||
|
||||
Each subdirectory in ``hw/`` adds one sourceset to the ``hw_arch`` dictionary,
|
||||
for example::
|
||||
@@ -317,8 +317,8 @@ Utility sourcesets:
|
||||
The following files concur in the definition of which files are linked
|
||||
into each emulator:
|
||||
|
||||
``default-configs/devices/*.mak``
|
||||
The files under ``default-configs/devices/`` control the boards and devices
|
||||
``configs/devices/*.mak``
|
||||
The files under ``configs/devices/`` control the boards and devices
|
||||
that are built into each QEMU system emulation targets. They merely contain
|
||||
a list of config variable definitions such as::
|
||||
|
||||
@@ -327,11 +327,11 @@ into each emulator:
|
||||
CONFIG_XLNX_VERSAL=y
|
||||
|
||||
``*/Kconfig``
|
||||
These files are processed together with ``default-configs/devices/*.mak`` and
|
||||
These files are processed together with ``configs/devices/*.mak`` and
|
||||
describe the dependencies between various features, subsystems and
|
||||
device models. They are described in :ref:`kconfig`
|
||||
|
||||
``default-configs/targets/*.mak``
|
||||
``configs/targets/*.mak``
|
||||
These files mostly define symbols that appear in the ``*-config-target.h``
|
||||
file for each emulator\ [#cfgtarget]_. However, the ``TARGET_ARCH``
|
||||
and ``TARGET_BASE_ARCH`` will also be used to select the ``hw/`` and
|
||||
|
||||
@@ -38,7 +38,7 @@ originated in the Linux kernel, though it was heavily simplified and
|
||||
the handling of dependencies is stricter in QEMU.
|
||||
|
||||
Unlike Linux, there is no user interface to edit the configuration, which
|
||||
is instead specified in per-target files under the ``default-configs/``
|
||||
is instead specified in per-target files under the ``configs/``
|
||||
directory of the QEMU source tree. This is because, unlike Linux,
|
||||
configuration and dependencies can be treated as a black box when building
|
||||
QEMU; the default configuration that QEMU ships with should be okay in
|
||||
@@ -103,7 +103,7 @@ directives can be included:
|
||||
**default value**: ``default <value> [if <expr>]``
|
||||
|
||||
Default values are assigned to the config symbol if no other value was
|
||||
set by the user via ``default-configs/*.mak`` files, and only if
|
||||
set by the user via ``configs/*.mak`` files, and only if
|
||||
``select`` or ``depends on`` directives do not force the value to true
|
||||
or false respectively. ``<value>`` can be ``y`` or ``n``; it cannot
|
||||
be an arbitrary Boolean expression. However, a condition for applying
|
||||
@@ -119,7 +119,7 @@ directives can be included:
|
||||
This is similar to ``select`` as it applies a lower limit of ``y``
|
||||
to another symbol. However, the lower limit is only a default
|
||||
and the "implied" symbol's value may still be set to ``n`` from a
|
||||
``default-configs/*.mak`` files. The following two examples are
|
||||
``configs/*.mak`` files. The following two examples are
|
||||
equivalent::
|
||||
|
||||
config FOO
|
||||
@@ -146,7 +146,7 @@ declares its dependencies in different ways:
|
||||
bool
|
||||
|
||||
Subsystems always default to false (they have no ``default`` directive)
|
||||
and are never visible in ``default-configs/*.mak`` files. It's
|
||||
and are never visible in ``configs/*.mak`` files. It's
|
||||
up to other symbols to ``select`` whatever subsystems they require.
|
||||
|
||||
They sometimes have ``select`` directives to bring in other required
|
||||
@@ -238,7 +238,7 @@ declares its dependencies in different ways:
|
||||
include libraries (such as ``FDT``) or ``TARGET_BIG_ENDIAN``
|
||||
(possibly negated).
|
||||
|
||||
Boards are listed for convenience in the ``default-configs/*.mak``
|
||||
Boards are listed for convenience in the ``configs/*.mak``
|
||||
for the target they apply to.
|
||||
|
||||
**internal elements**
|
||||
@@ -251,18 +251,18 @@ declares its dependencies in different ways:
|
||||
|
||||
Internal elements group code that is useful in several boards or
|
||||
devices. They are usually enabled with ``select`` and in turn select
|
||||
other elements; they are never visible in ``default-configs/*.mak``
|
||||
other elements; they are never visible in ``configs/*.mak``
|
||||
files, and often not even in the Makefile.
|
||||
|
||||
Writing and modifying default configurations
|
||||
--------------------------------------------
|
||||
|
||||
In addition to the Kconfig files under hw/, each target also includes
|
||||
a file called ``default-configs/TARGETNAME-softmmu.mak``. These files
|
||||
a file called ``configs/TARGETNAME-softmmu.mak``. These files
|
||||
initialize some Kconfig variables to non-default values and provide the
|
||||
starting point to turn on devices and subsystems.
|
||||
|
||||
A file in ``default-configs/`` looks like the following example::
|
||||
A file in ``configs/`` looks like the following example::
|
||||
|
||||
# Default configuration for alpha-softmmu
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ static inline Int128 atomic16_read_ro(const Int128 *ptr)
|
||||
asm("vld $vr0, %2, 0\n\t"
|
||||
"vpickve2gr.d %0, $vr0, 0\n\t"
|
||||
"vpickve2gr.d %1, $vr0, 1"
|
||||
: "=r"(l), "=r"(h) : "r"(ptr), "m"(*ptr) : "f0");
|
||||
: "=r"(l), "=r"(h) : "r"(ptr), "m"(*ptr) : "$f0");
|
||||
|
||||
return int128_make128(l, h);
|
||||
}
|
||||
@@ -46,7 +46,7 @@ static inline void atomic16_set(Int128 *ptr, Int128 val)
|
||||
asm("vinsgr2vr.d $vr0, %1, 0\n\t"
|
||||
"vinsgr2vr.d $vr0, %2, 1\n\t"
|
||||
"vst $vr0, %3, 0"
|
||||
: "=m"(*ptr) : "r"(l), "r"(h), "r"(ptr) : "f0");
|
||||
: "=m"(*ptr) : "r"(l), "r"(h), "r"(ptr) : "$f0");
|
||||
}
|
||||
|
||||
#endif /* LOONGARCH_ATOMIC128_LDST_H */
|
||||
|
||||
@@ -61,7 +61,8 @@ static bool buffer_is_zero_lsx(const void *buf, size_t len)
|
||||
"2:"
|
||||
: "=&r"(ret), "+r"(p)
|
||||
: "r"(buf), "r"(e), "r"(l)
|
||||
: "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "fcc0");
|
||||
: "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8",
|
||||
"$fcc0");
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -119,7 +120,8 @@ static bool buffer_is_zero_lasx(const void *buf, size_t len)
|
||||
"3:"
|
||||
: "=&r"(ret), "+r"(p)
|
||||
: "r"(buf), "r"(e), "r"(l)
|
||||
: "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "fcc0");
|
||||
: "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8",
|
||||
"$fcc0");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ static inline uint64_t load_atom_extract_al16_or_al8(void *pv, int s)
|
||||
asm("vld $vr0, %2, 0\n\t"
|
||||
"vpickve2gr.d %0, $vr0, 0\n\t"
|
||||
"vpickve2gr.d %1, $vr0, 1"
|
||||
: "=r"(l), "=r"(h) : "r"(ptr_align), "m"(*ptr_align) : "f0");
|
||||
: "=r"(l), "=r"(h) : "r"(ptr_align), "m"(*ptr_align) : "$f0");
|
||||
|
||||
return (l >> shr) | (h << (-shr & 63));
|
||||
}
|
||||
|
||||
+5
-1
@@ -303,7 +303,7 @@ config ZYNQ
|
||||
select PL330
|
||||
select SDHCI
|
||||
select SSI_M25P80
|
||||
select USB_EHCI_SYSBUS
|
||||
select USB_CHIPIDEA
|
||||
select XILINX # UART
|
||||
select XILINX_AXI
|
||||
select XILINX_SPI
|
||||
@@ -489,6 +489,7 @@ config FSL_IMX25
|
||||
select IMX
|
||||
select IMX_FEC
|
||||
select IMX_I2C
|
||||
select USB_CHIPIDEA
|
||||
select WDT_IMX2
|
||||
select SDHCI
|
||||
|
||||
@@ -516,6 +517,7 @@ config FSL_IMX6
|
||||
select PL310 # cache controller
|
||||
select PCI_EXPRESS_DESIGNWARE
|
||||
select SDHCI
|
||||
select USB_CHIPIDEA
|
||||
|
||||
config ASPEED_SOC
|
||||
bool
|
||||
@@ -574,6 +576,7 @@ config FSL_IMX7
|
||||
select PCI_EXPRESS_DESIGNWARE
|
||||
select SDHCI
|
||||
select UNIMP
|
||||
select USB_CHIPIDEA
|
||||
|
||||
config ARM_SMMUV3
|
||||
bool
|
||||
@@ -589,6 +592,7 @@ config FSL_IMX6UL
|
||||
select IMX_I2C
|
||||
select WDT_IMX2
|
||||
select SDHCI
|
||||
select USB_CHIPIDEA
|
||||
select UNIMP
|
||||
|
||||
config MICROBIT
|
||||
|
||||
@@ -484,6 +484,8 @@ static void create_gic(SBSAMachineState *sms, MemoryRegion *mem)
|
||||
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
|
||||
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
|
||||
[GTIMER_HYPVIRT] = ARCH_TIMER_NS_EL2_VIRT_IRQ,
|
||||
[GTIMER_S_EL2_PHYS] = ARCH_TIMER_S_EL2_IRQ,
|
||||
[GTIMER_S_EL2_VIRT] = ARCH_TIMER_S_EL2_VIRT_IRQ,
|
||||
};
|
||||
|
||||
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
|
||||
|
||||
@@ -873,6 +873,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
|
||||
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
|
||||
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
|
||||
[GTIMER_HYPVIRT] = ARCH_TIMER_NS_EL2_VIRT_IRQ,
|
||||
[GTIMER_S_EL2_PHYS] = ARCH_TIMER_S_EL2_IRQ,
|
||||
[GTIMER_S_EL2_VIRT] = ARCH_TIMER_S_EL2_VIRT_IRQ,
|
||||
};
|
||||
|
||||
for (unsigned irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
|
||||
|
||||
@@ -220,8 +220,6 @@ static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
|
||||
return;
|
||||
}
|
||||
|
||||
diff = s->regs[reg] ^ value;
|
||||
|
||||
switch (reg) {
|
||||
case NPCM7XX_GPIO_TLOCK1:
|
||||
case NPCM7XX_GPIO_TLOCK2:
|
||||
@@ -242,6 +240,7 @@ static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
|
||||
case NPCM7XX_GPIO_PU:
|
||||
case NPCM7XX_GPIO_PD:
|
||||
case NPCM7XX_GPIO_IEM:
|
||||
diff = s->regs[reg] ^ value;
|
||||
s->regs[reg] = value;
|
||||
npcm7xx_gpio_update_pins(s, diff);
|
||||
break;
|
||||
|
||||
+5
-5
@@ -1309,15 +1309,15 @@ static int amdvi_int_remap_msi(AMDVIState *iommu,
|
||||
ret = -AMDVI_IR_ERR;
|
||||
break;
|
||||
case AMDVI_IOAPIC_INT_TYPE_NMI:
|
||||
pass = dte[3] & AMDVI_DEV_NMI_PASS_MASK;
|
||||
pass = dte[2] & AMDVI_DEV_NMI_PASS_MASK;
|
||||
trace_amdvi_ir_delivery_mode("nmi");
|
||||
break;
|
||||
case AMDVI_IOAPIC_INT_TYPE_INIT:
|
||||
pass = dte[3] & AMDVI_DEV_INT_PASS_MASK;
|
||||
pass = dte[2] & AMDVI_DEV_INT_PASS_MASK;
|
||||
trace_amdvi_ir_delivery_mode("init");
|
||||
break;
|
||||
case AMDVI_IOAPIC_INT_TYPE_EINT:
|
||||
pass = dte[3] & AMDVI_DEV_EINT_PASS_MASK;
|
||||
pass = dte[2] & AMDVI_DEV_EINT_PASS_MASK;
|
||||
trace_amdvi_ir_delivery_mode("eint");
|
||||
break;
|
||||
default:
|
||||
@@ -1593,9 +1593,9 @@ static void amdvi_pci_realize(PCIDevice *pdev, Error **errp)
|
||||
/* reset AMDVI specific capabilities, all r/o */
|
||||
pci_set_long(pdev->config + s->capab_offset, AMDVI_CAPAB_FEATURES);
|
||||
pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_BAR_LOW,
|
||||
AMDVI_BASE_ADDR & ~(0xffff0000));
|
||||
AMDVI_BASE_ADDR & MAKE_64BIT_MASK(14, 18));
|
||||
pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_BAR_HIGH,
|
||||
(AMDVI_BASE_ADDR & ~(0xffff)) >> 16);
|
||||
AMDVI_BASE_ADDR >> 32);
|
||||
pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_RANGE,
|
||||
0xff000000);
|
||||
pci_set_long(pdev->config + s->capab_offset + AMDVI_CAPAB_MISC, 0);
|
||||
|
||||
+1
-1
@@ -187,7 +187,7 @@
|
||||
AMDVI_CAPAB_FLAG_HTTUNNEL | AMDVI_CAPAB_EFR_SUP)
|
||||
|
||||
/* AMDVI default address */
|
||||
#define AMDVI_BASE_ADDR 0xfed80000
|
||||
#define AMDVI_BASE_ADDR 0xfed80000ULL
|
||||
|
||||
/* page management constants */
|
||||
#define AMDVI_PAGE_SHIFT 12
|
||||
|
||||
+33
-33
@@ -451,11 +451,44 @@ static HotplugHandler *microvm_get_hotplug_handler(MachineState *machine,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void microvm_machine_done(Notifier *notifier, void *data)
|
||||
{
|
||||
MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
|
||||
machine_done);
|
||||
X86MachineState *x86ms = X86_MACHINE(mms);
|
||||
|
||||
acpi_setup_microvm(mms);
|
||||
dt_setup_microvm(mms);
|
||||
fw_cfg_add_e820(x86ms->fw_cfg);
|
||||
}
|
||||
|
||||
static void microvm_powerdown_req(Notifier *notifier, void *data)
|
||||
{
|
||||
MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
|
||||
powerdown_req);
|
||||
X86MachineState *x86ms = X86_MACHINE(mms);
|
||||
|
||||
if (x86ms->acpi_dev) {
|
||||
Object *obj = OBJECT(x86ms->acpi_dev);
|
||||
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
|
||||
adevc->send_event(ACPI_DEVICE_IF(x86ms->acpi_dev),
|
||||
ACPI_POWER_DOWN_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
static void microvm_machine_state_init(MachineState *machine)
|
||||
{
|
||||
MicrovmMachineState *mms = MICROVM_MACHINE(machine);
|
||||
X86MachineState *x86ms = X86_MACHINE(machine);
|
||||
|
||||
/* State */
|
||||
mms->kernel_cmdline_fixed = false;
|
||||
|
||||
mms->machine_done.notify = microvm_machine_done;
|
||||
qemu_add_machine_init_done_notifier(&mms->machine_done);
|
||||
mms->powerdown_req.notify = microvm_powerdown_req;
|
||||
qemu_register_powerdown_notifier(&mms->powerdown_req);
|
||||
|
||||
microvm_memory_init(mms);
|
||||
|
||||
x86_cpus_init(x86ms, CPU_VERSION_LATEST);
|
||||
@@ -581,31 +614,6 @@ static void microvm_machine_set_auto_kernel_cmdline(Object *obj, bool value,
|
||||
mms->auto_kernel_cmdline = value;
|
||||
}
|
||||
|
||||
static void microvm_machine_done(Notifier *notifier, void *data)
|
||||
{
|
||||
MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
|
||||
machine_done);
|
||||
X86MachineState *x86ms = X86_MACHINE(mms);
|
||||
|
||||
acpi_setup_microvm(mms);
|
||||
dt_setup_microvm(mms);
|
||||
fw_cfg_add_e820(x86ms->fw_cfg);
|
||||
}
|
||||
|
||||
static void microvm_powerdown_req(Notifier *notifier, void *data)
|
||||
{
|
||||
MicrovmMachineState *mms = container_of(notifier, MicrovmMachineState,
|
||||
powerdown_req);
|
||||
X86MachineState *x86ms = X86_MACHINE(mms);
|
||||
|
||||
if (x86ms->acpi_dev) {
|
||||
Object *obj = OBJECT(x86ms->acpi_dev);
|
||||
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_GET_CLASS(obj);
|
||||
adevc->send_event(ACPI_DEVICE_IF(x86ms->acpi_dev),
|
||||
ACPI_POWER_DOWN_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
static void microvm_machine_initfn(Object *obj)
|
||||
{
|
||||
MicrovmMachineState *mms = MICROVM_MACHINE(obj);
|
||||
@@ -617,14 +625,6 @@ static void microvm_machine_initfn(Object *obj)
|
||||
mms->isa_serial = true;
|
||||
mms->option_roms = true;
|
||||
mms->auto_kernel_cmdline = true;
|
||||
|
||||
/* State */
|
||||
mms->kernel_cmdline_fixed = false;
|
||||
|
||||
mms->machine_done.notify = microvm_machine_done;
|
||||
qemu_add_machine_init_done_notifier(&mms->machine_done);
|
||||
mms->powerdown_req.notify = microvm_powerdown_req;
|
||||
qemu_register_powerdown_notifier(&mms->powerdown_req);
|
||||
}
|
||||
|
||||
GlobalProperty microvm_properties[] = {
|
||||
|
||||
+3
-3
@@ -1236,6 +1236,9 @@ void pc_basic_device_init(struct PCMachineState *pcms,
|
||||
/* Super I/O */
|
||||
pc_superio_init(isa_bus, create_fdctrl, pcms->i8042_enabled,
|
||||
pcms->vmport != ON_OFF_AUTO_ON, &error_fatal);
|
||||
|
||||
pcms->machine_done.notify = pc_machine_done;
|
||||
qemu_add_machine_init_done_notifier(&pcms->machine_done);
|
||||
}
|
||||
|
||||
void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus)
|
||||
@@ -1709,9 +1712,6 @@ static void pc_machine_initfn(Object *obj)
|
||||
if (pcmc->pci_enabled) {
|
||||
cxl_machine_init(obj, &pcms->cxl_devices_state);
|
||||
}
|
||||
|
||||
pcms->machine_done.notify = pc_machine_done;
|
||||
qemu_add_machine_init_done_notifier(&pcms->machine_done);
|
||||
}
|
||||
|
||||
static void pc_machine_reset(MachineState *machine, ResetType type)
|
||||
|
||||
@@ -2300,9 +2300,6 @@ static CPAccessResult gicv3_irqfiq_access(CPUARMState *env,
|
||||
}
|
||||
}
|
||||
|
||||
if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
|
||||
r = CP_ACCESS_TRAP;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -2365,9 +2362,6 @@ static CPAccessResult gicv3_fiq_access(CPUARMState *env,
|
||||
}
|
||||
}
|
||||
|
||||
if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
|
||||
r = CP_ACCESS_TRAP;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -2404,9 +2398,6 @@ static CPAccessResult gicv3_irq_access(CPUARMState *env,
|
||||
}
|
||||
}
|
||||
|
||||
if (r == CP_ACCESS_TRAP_EL3 && !arm_el_is_aa64(env, 3)) {
|
||||
r = CP_ACCESS_TRAP;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ static void aspeed_intc_set_irq(void *opaque, int irq, int level)
|
||||
|
||||
trace_aspeed_intc_select(select);
|
||||
|
||||
if (s->mask[irq] || s->regs[status_addr]) {
|
||||
if ((s->mask[irq] & select) || (s->regs[status_addr] & select)) {
|
||||
/*
|
||||
* a. mask is not 0 means in ISR mode
|
||||
* sources interrupt routine are executing.
|
||||
|
||||
@@ -124,6 +124,11 @@ static bool has_padding(AspeedHACEState *s, struct iovec *iov,
|
||||
if (*total_msg_len <= s->total_req_len) {
|
||||
uint32_t padding_size = s->total_req_len - *total_msg_len;
|
||||
uint8_t *padding = iov->iov_base;
|
||||
|
||||
if (padding_size > req_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*pad_offset = req_len - padding_size;
|
||||
if (padding[*pad_offset] == 0x80) {
|
||||
return true;
|
||||
|
||||
+125
-15
@@ -13,6 +13,7 @@
|
||||
#include "net/net.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/net/smc91c111.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
@@ -22,6 +23,13 @@
|
||||
|
||||
/* Number of 2k memory pages available. */
|
||||
#define NUM_PACKETS 4
|
||||
/*
|
||||
* Maximum size of a data frame, including the leading status word
|
||||
* and byte count fields and the trailing CRC, last data byte
|
||||
* and control byte (per figure 8-1 in the Microchip Technology
|
||||
* LAN91C111 datasheet).
|
||||
*/
|
||||
#define MAX_PACKET_SIZE 2048
|
||||
|
||||
#define TYPE_SMC91C111 "smc91c111"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(smc91c111_state, SMC91C111)
|
||||
@@ -118,6 +126,18 @@ static const VMStateDescription vmstate_smc91c111 = {
|
||||
#define RS_TOOSHORT 0x0400
|
||||
#define RS_MULTICAST 0x0001
|
||||
|
||||
FIELD(PTR, PTR, 0, 11)
|
||||
FIELD(PTR, NOT_EMPTY, 11, 1)
|
||||
FIELD(PTR, RESERVED, 12, 1)
|
||||
FIELD(PTR, READ, 13, 1)
|
||||
FIELD(PTR, AUTOINCR, 14, 1)
|
||||
FIELD(PTR, RCV, 15, 1)
|
||||
|
||||
static inline bool packetnum_valid(int packet_num)
|
||||
{
|
||||
return packet_num >= 0 && packet_num < NUM_PACKETS;
|
||||
}
|
||||
|
||||
/* Update interrupt status. */
|
||||
static void smc91c111_update(smc91c111_state *s)
|
||||
{
|
||||
@@ -218,12 +238,33 @@ static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
|
||||
/* Release the memory allocated to a packet. */
|
||||
static void smc91c111_release_packet(smc91c111_state *s, int packet)
|
||||
{
|
||||
if (!packetnum_valid(packet)) {
|
||||
/*
|
||||
* Data sheet doesn't document behaviour in this guest error
|
||||
* case, and there is no error status register to report it.
|
||||
* Log and ignore the attempt.
|
||||
*/
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"smc91c111: attempt to release invalid packet %d\n",
|
||||
packet);
|
||||
return;
|
||||
}
|
||||
s->allocated &= ~(1 << packet);
|
||||
if (s->tx_alloc == 0x80)
|
||||
smc91c111_tx_alloc(s);
|
||||
smc91c111_flush_queued_packets(s);
|
||||
}
|
||||
|
||||
static void smc91c111_complete_tx_packet(smc91c111_state *s, int packetnum)
|
||||
{
|
||||
if (s->ctr & CTR_AUTO_RELEASE) {
|
||||
/* Race? */
|
||||
smc91c111_release_packet(s, packetnum);
|
||||
} else if (s->tx_fifo_done_len < NUM_PACKETS) {
|
||||
s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush the TX FIFO. */
|
||||
static void smc91c111_do_tx(smc91c111_state *s)
|
||||
{
|
||||
@@ -239,12 +280,25 @@ static void smc91c111_do_tx(smc91c111_state *s)
|
||||
return;
|
||||
for (i = 0; i < s->tx_fifo_len; i++) {
|
||||
packetnum = s->tx_fifo[i];
|
||||
/* queue_tx checked the packet number was valid */
|
||||
assert(packetnum_valid(packetnum));
|
||||
p = &s->data[packetnum][0];
|
||||
/* Set status word. */
|
||||
*(p++) = 0x01;
|
||||
*(p++) = 0x40;
|
||||
len = *(p++);
|
||||
len |= ((int)*(p++)) << 8;
|
||||
if (len > MAX_PACKET_SIZE) {
|
||||
/*
|
||||
* Datasheet doesn't say what to do here, and there is no
|
||||
* relevant tx error condition listed. Log, and drop the packet.
|
||||
*/
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"smc91c111: tx packet with bad length %d, dropping\n",
|
||||
len);
|
||||
smc91c111_complete_tx_packet(s, packetnum);
|
||||
continue;
|
||||
}
|
||||
len -= 6;
|
||||
control = p[len + 1];
|
||||
if (control & 0x20)
|
||||
@@ -273,11 +327,7 @@ static void smc91c111_do_tx(smc91c111_state *s)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (s->ctr & CTR_AUTO_RELEASE)
|
||||
/* Race? */
|
||||
smc91c111_release_packet(s, packetnum);
|
||||
else if (s->tx_fifo_done_len < NUM_PACKETS)
|
||||
s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
|
||||
smc91c111_complete_tx_packet(s, packetnum);
|
||||
qemu_send_packet(qemu_get_queue(s->nic), p, len);
|
||||
}
|
||||
s->tx_fifo_len = 0;
|
||||
@@ -287,6 +337,17 @@ static void smc91c111_do_tx(smc91c111_state *s)
|
||||
/* Add a packet to the TX FIFO. */
|
||||
static void smc91c111_queue_tx(smc91c111_state *s, int packet)
|
||||
{
|
||||
if (!packetnum_valid(packet)) {
|
||||
/*
|
||||
* Datasheet doesn't document behaviour in this error case, and
|
||||
* there's no error status register we could report it in.
|
||||
* Log and ignore.
|
||||
*/
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"smc91c111: attempt to queue invalid packet %d\n",
|
||||
packet);
|
||||
return;
|
||||
}
|
||||
if (s->tx_fifo_len == NUM_PACKETS)
|
||||
return;
|
||||
s->tx_fifo[s->tx_fifo_len++] = packet;
|
||||
@@ -318,6 +379,49 @@ static void smc91c111_reset(DeviceState *dev)
|
||||
#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
|
||||
#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
|
||||
|
||||
/*
|
||||
* The pointer register's pointer is an 11 bit value (so it exactly
|
||||
* indexes a 2048-byte data frame). Add the specified offset to it,
|
||||
* wrapping around at the 2048 byte mark, and return the resulting
|
||||
* wrapped value. There are flag bits in the top part of the register,
|
||||
* but we can ignore them here as the mask will mask them out.
|
||||
*/
|
||||
static int ptr_reg_add(smc91c111_state *s, int offset)
|
||||
{
|
||||
return (s->ptr + offset) & R_PTR_PTR_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* For an access to the Data Register at @offset, return the
|
||||
* required offset into the packet's data frame. This will
|
||||
* perform the pointer register autoincrement if required, and
|
||||
* guarantees to return an in-bounds offset.
|
||||
*/
|
||||
static int data_reg_ptr(smc91c111_state *s, int offset)
|
||||
{
|
||||
int p;
|
||||
|
||||
if (s->ptr & R_PTR_AUTOINCR_MASK) {
|
||||
/*
|
||||
* Autoincrement: use the current pointer value, and
|
||||
* increment the pointer register's pointer field.
|
||||
*/
|
||||
p = FIELD_EX32(s->ptr, PTR, PTR);
|
||||
s->ptr = FIELD_DP32(s->ptr, PTR, PTR, ptr_reg_add(s, 1));
|
||||
} else {
|
||||
/*
|
||||
* No autoincrement: register offset determines which
|
||||
* byte we're addressing. Setting the pointer to the top
|
||||
* of the data buffer and then using the pointer wrapping
|
||||
* to read the bottom byte of the buffer is not something
|
||||
* sensible guest software will do, but the datasheet
|
||||
* doesn't say what the behaviour is, so we don't forbid it.
|
||||
*/
|
||||
p = ptr_reg_add(s, offset & 3);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static void smc91c111_writeb(void *opaque, hwaddr offset,
|
||||
uint32_t value)
|
||||
{
|
||||
@@ -457,12 +561,14 @@ static void smc91c111_writeb(void *opaque, hwaddr offset,
|
||||
n = s->rx_fifo[0];
|
||||
else
|
||||
n = s->packet_num;
|
||||
p = s->ptr & 0x07ff;
|
||||
if (s->ptr & 0x4000) {
|
||||
s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
|
||||
} else {
|
||||
p += (offset & 3);
|
||||
if (!packetnum_valid(n)) {
|
||||
/* Datasheet doesn't document what to do here */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"smc91c111: attempt to write data to invalid packet %d\n",
|
||||
n);
|
||||
return;
|
||||
}
|
||||
p = data_reg_ptr(s, offset);
|
||||
s->data[n][p] = value;
|
||||
}
|
||||
return;
|
||||
@@ -605,12 +711,14 @@ static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
|
||||
n = s->rx_fifo[0];
|
||||
else
|
||||
n = s->packet_num;
|
||||
p = s->ptr & 0x07ff;
|
||||
if (s->ptr & 0x4000) {
|
||||
s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
|
||||
} else {
|
||||
p += (offset & 3);
|
||||
if (!packetnum_valid(n)) {
|
||||
/* Datasheet doesn't document what to do here */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"smc91c111: attempt to read data from invalid packet %d\n",
|
||||
n);
|
||||
return 0;
|
||||
}
|
||||
p = data_reg_ptr(s, offset);
|
||||
return s->data[n][p];
|
||||
}
|
||||
case 12: /* Interrupt status. */
|
||||
@@ -713,6 +821,8 @@ static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t
|
||||
return -1;
|
||||
s->rx_fifo[s->rx_fifo_len++] = packetnum;
|
||||
|
||||
/* allocate_packet() will not hand us back an invalid packet number */
|
||||
assert(packetnum_valid(packetnum));
|
||||
p = &s->data[packetnum][0];
|
||||
/* ??? Multicast packets? */
|
||||
status = 0;
|
||||
|
||||
+18
-27
@@ -1352,18 +1352,25 @@ exit:
|
||||
|
||||
static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
|
||||
trace_virtio_net_rss_load(n, n->nr_ebpf_rss_fds, n->ebpf_rss_fds);
|
||||
if (n->ebpf_rss_fds) {
|
||||
ret = virtio_net_load_ebpf_fds(n, errp);
|
||||
} else {
|
||||
ret = ebpf_rss_load(&n->ebpf_rss, errp);
|
||||
}
|
||||
if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
trace_virtio_net_rss_load(n, n->nr_ebpf_rss_fds, n->ebpf_rss_fds);
|
||||
|
||||
/*
|
||||
* If user explicitly gave QEMU RSS FDs to use, then
|
||||
* failing to use them must be considered a fatal
|
||||
* error. If no RSS FDs were provided, QEMU is trying
|
||||
* eBPF on a "best effort" basis only, so report a
|
||||
* warning and allow fallback to software RSS.
|
||||
*/
|
||||
if (n->ebpf_rss_fds) {
|
||||
return virtio_net_load_ebpf_fds(n, errp);
|
||||
}
|
||||
|
||||
ebpf_rss_load(&n->ebpf_rss, &error_warn);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void virtio_net_unload_ebpf(VirtIONet *n)
|
||||
@@ -3801,23 +3808,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
|
||||
net_rx_pkt_init(&n->rx_pkt);
|
||||
|
||||
if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
|
||||
Error *err = NULL;
|
||||
if (!virtio_net_load_ebpf(n, &err)) {
|
||||
/*
|
||||
* If user explicitly gave QEMU RSS FDs to use, then
|
||||
* failing to use them must be considered a fatal
|
||||
* error. If no RSS FDs were provided, QEMU is trying
|
||||
* eBPF on a "best effort" basis only, so report a
|
||||
* warning and allow fallback to software RSS.
|
||||
*/
|
||||
if (n->ebpf_rss_fds) {
|
||||
error_propagate(errp, err);
|
||||
} else {
|
||||
warn_report("unable to load eBPF RSS: %s",
|
||||
error_get_pretty(err));
|
||||
error_free(err);
|
||||
}
|
||||
}
|
||||
virtio_net_load_ebpf(n, errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-18
@@ -32,22 +32,21 @@
|
||||
#define OCB_OCI_OCCMISC_OR 0x4022
|
||||
|
||||
/* OCC sensors */
|
||||
#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x580000
|
||||
#define OCC_SENSOR_DATA_VALID 0x580001
|
||||
#define OCC_SENSOR_DATA_VERSION 0x580002
|
||||
#define OCC_SENSOR_DATA_READING_VERSION 0x580004
|
||||
#define OCC_SENSOR_DATA_NR_SENSORS 0x580008
|
||||
#define OCC_SENSOR_DATA_NAMES_OFFSET 0x580010
|
||||
#define OCC_SENSOR_DATA_READING_PING_OFFSET 0x580014
|
||||
#define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x58000c
|
||||
#define OCC_SENSOR_DATA_NAME_LENGTH 0x58000d
|
||||
#define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x580023
|
||||
#define OCC_SENSOR_LOC_CORE 0x580022
|
||||
#define OCC_SENSOR_LOC_GPU 0x580020
|
||||
#define OCC_SENSOR_TYPE_POWER 0x580003
|
||||
#define OCC_SENSOR_NAME 0x580005
|
||||
#define HWMON_SENSORS_MASK 0x58001e
|
||||
#define SLW_IMAGE_BASE 0x0
|
||||
#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x0000
|
||||
#define OCC_SENSOR_DATA_VALID 0x0001
|
||||
#define OCC_SENSOR_DATA_VERSION 0x0002
|
||||
#define OCC_SENSOR_DATA_READING_VERSION 0x0004
|
||||
#define OCC_SENSOR_DATA_NR_SENSORS 0x0008
|
||||
#define OCC_SENSOR_DATA_NAMES_OFFSET 0x0010
|
||||
#define OCC_SENSOR_DATA_READING_PING_OFFSET 0x0014
|
||||
#define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x000c
|
||||
#define OCC_SENSOR_DATA_NAME_LENGTH 0x000d
|
||||
#define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x0023
|
||||
#define OCC_SENSOR_LOC_CORE 0x0022
|
||||
#define OCC_SENSOR_LOC_GPU 0x0020
|
||||
#define OCC_SENSOR_TYPE_POWER 0x0003
|
||||
#define OCC_SENSOR_NAME 0x0005
|
||||
#define HWMON_SENSORS_MASK 0x001e
|
||||
|
||||
static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
|
||||
{
|
||||
@@ -129,8 +128,6 @@ static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr,
|
||||
case HWMON_SENSORS_MASK:
|
||||
case OCC_SENSOR_LOC_GPU:
|
||||
return 0x8e00;
|
||||
case SLW_IMAGE_BASE:
|
||||
return 0x1000000000000000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4771,6 +4771,7 @@ static void spapr_machine_8_2_class_options(MachineClass *mc)
|
||||
{
|
||||
spapr_machine_9_0_class_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_8_2, hw_compat_8_2_len);
|
||||
mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power9_v2.2");
|
||||
}
|
||||
|
||||
DEFINE_SPAPR_MACHINE(8, 2);
|
||||
|
||||
+13
-30
@@ -178,38 +178,21 @@ static void goldfish_rtc_write(void *opaque, hwaddr offset,
|
||||
trace_goldfish_rtc_write(offset, value);
|
||||
}
|
||||
|
||||
static int goldfish_rtc_pre_save(void *opaque)
|
||||
{
|
||||
uint64_t delta;
|
||||
GoldfishRTCState *s = opaque;
|
||||
|
||||
/*
|
||||
* We want to migrate this offset, which sounds straightforward.
|
||||
* Unfortunately, we cannot directly pass tick_offset because
|
||||
* rtc_clock on destination Host might not be same source Host.
|
||||
*
|
||||
* To tackle, this we pass tick_offset relative to vm_clock from
|
||||
* source Host and make it relative to rtc_clock at destination Host.
|
||||
*/
|
||||
delta = qemu_clock_get_ns(rtc_clock) -
|
||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
s->tick_offset_vmstate = s->tick_offset + delta;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int goldfish_rtc_post_load(void *opaque, int version_id)
|
||||
{
|
||||
uint64_t delta;
|
||||
GoldfishRTCState *s = opaque;
|
||||
|
||||
/*
|
||||
* We extract tick_offset from tick_offset_vmstate by doing
|
||||
* reverse math compared to pre_save() function.
|
||||
*/
|
||||
delta = qemu_clock_get_ns(rtc_clock) -
|
||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
s->tick_offset = s->tick_offset_vmstate - delta;
|
||||
if (version_id < 3) {
|
||||
/*
|
||||
* Previous versions didn't migrate tick_offset directly. Instead, they
|
||||
* migrated tick_offset_vmstate, which is a recalculation based on
|
||||
* QEMU_CLOCK_VIRTUAL. We use tick_offset_vmstate when migrating from
|
||||
* older versions.
|
||||
*/
|
||||
uint64_t delta = qemu_clock_get_ns(rtc_clock) -
|
||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
s->tick_offset = s->tick_offset_vmstate - delta;
|
||||
}
|
||||
|
||||
goldfish_rtc_set_alarm(s);
|
||||
|
||||
@@ -239,8 +222,7 @@ static const MemoryRegionOps goldfish_rtc_ops[2] = {
|
||||
|
||||
static const VMStateDescription goldfish_rtc_vmstate = {
|
||||
.name = TYPE_GOLDFISH_RTC,
|
||||
.version_id = 2,
|
||||
.pre_save = goldfish_rtc_pre_save,
|
||||
.version_id = 3,
|
||||
.post_load = goldfish_rtc_post_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT64(tick_offset_vmstate, GoldfishRTCState),
|
||||
@@ -249,6 +231,7 @@ static const VMStateDescription goldfish_rtc_vmstate = {
|
||||
VMSTATE_UINT32(irq_pending, GoldfishRTCState),
|
||||
VMSTATE_UINT32(irq_enabled, GoldfishRTCState),
|
||||
VMSTATE_UINT32(time_high, GoldfishRTCState),
|
||||
VMSTATE_UINT64_V(tick_offset, GoldfishRTCState, 3),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -143,3 +143,7 @@ config USB_DWC3
|
||||
config XLNX_USB_SUBSYS
|
||||
bool
|
||||
select USB_DWC3
|
||||
|
||||
config USB_CHIPIDEA
|
||||
bool
|
||||
select USB_EHCI_SYSBUS
|
||||
|
||||
+1
-1
@@ -25,8 +25,8 @@ system_ss.add(when: 'CONFIG_USB_XHCI_SYSBUS', if_true: files('hcd-xhci-sysbus.c'
|
||||
system_ss.add(when: 'CONFIG_USB_XHCI_NEC', if_true: files('hcd-xhci-nec.c'))
|
||||
system_ss.add(when: 'CONFIG_USB_DWC2', if_true: files('hcd-dwc2.c'))
|
||||
system_ss.add(when: 'CONFIG_USB_DWC3', if_true: files('hcd-dwc3.c'))
|
||||
system_ss.add(when: 'CONFIG_USB_CHIPIDEA', if_true: files('chipidea.c'))
|
||||
|
||||
system_ss.add(when: 'CONFIG_IMX', if_true: files('chipidea.c'))
|
||||
system_ss.add(when: 'CONFIG_IMX_USBPHY', if_true: files('imx-usb-phy.c'))
|
||||
system_ss.add(when: 'CONFIG_VT82C686', if_true: files('vt82c686-uhci-pci.c'))
|
||||
system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-usb2-ctrl-regs.c'))
|
||||
|
||||
@@ -165,10 +165,10 @@ static bool vhost_svq_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg,
|
||||
descs[i].len = cpu_to_le32(iovec[n].iov_len);
|
||||
|
||||
last = i;
|
||||
i = cpu_to_le16(svq->desc_next[i]);
|
||||
i = svq->desc_next[i];
|
||||
}
|
||||
|
||||
svq->free_head = le16_to_cpu(svq->desc_next[last]);
|
||||
svq->free_head = svq->desc_next[last];
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -228,10 +228,12 @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq)
|
||||
smp_mb();
|
||||
|
||||
if (virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
uint16_t avail_event = *(uint16_t *)(&svq->vring.used->ring[svq->vring.num]);
|
||||
uint16_t avail_event = le16_to_cpu(
|
||||
*(uint16_t *)(&svq->vring.used->ring[svq->vring.num]));
|
||||
needs_kick = vring_need_event(avail_event, svq->shadow_avail_idx, svq->shadow_avail_idx - 1);
|
||||
} else {
|
||||
needs_kick = !(svq->vring.used->flags & VRING_USED_F_NO_NOTIFY);
|
||||
needs_kick =
|
||||
!(svq->vring.used->flags & cpu_to_le16(VRING_USED_F_NO_NOTIFY));
|
||||
}
|
||||
|
||||
if (!needs_kick) {
|
||||
@@ -365,7 +367,7 @@ static bool vhost_svq_more_used(VhostShadowVirtqueue *svq)
|
||||
return true;
|
||||
}
|
||||
|
||||
svq->shadow_used_idx = cpu_to_le16(*(volatile uint16_t *)used_idx);
|
||||
svq->shadow_used_idx = le16_to_cpu(*(volatile uint16_t *)used_idx);
|
||||
|
||||
return svq->last_used_idx != svq->shadow_used_idx;
|
||||
}
|
||||
@@ -383,7 +385,7 @@ static bool vhost_svq_enable_notification(VhostShadowVirtqueue *svq)
|
||||
{
|
||||
if (virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
uint16_t *used_event = (uint16_t *)&svq->vring.avail->ring[svq->vring.num];
|
||||
*used_event = svq->shadow_used_idx;
|
||||
*used_event = cpu_to_le16(svq->shadow_used_idx);
|
||||
} else {
|
||||
svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT);
|
||||
}
|
||||
@@ -408,7 +410,7 @@ static uint16_t vhost_svq_last_desc_of_chain(const VhostShadowVirtqueue *svq,
|
||||
uint16_t num, uint16_t i)
|
||||
{
|
||||
for (uint16_t j = 0; j < (num - 1); ++j) {
|
||||
i = le16_to_cpu(svq->desc_next[i]);
|
||||
i = svq->desc_next[i];
|
||||
}
|
||||
|
||||
return i;
|
||||
@@ -683,7 +685,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
|
||||
svq->desc_state = g_new0(SVQDescState, svq->vring.num);
|
||||
svq->desc_next = g_new0(uint16_t, svq->vring.num);
|
||||
for (unsigned i = 0; i < svq->vring.num - 1; i++) {
|
||||
svq->desc_next[i] = cpu_to_le16(i + 1);
|
||||
svq->desc_next[i] = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,18 @@
|
||||
#include "standard-headers/linux/virtio_ids.h"
|
||||
#include "standard-headers/linux/virtio_snd.h"
|
||||
|
||||
static const VirtIOFeature feature_sizes[] = {
|
||||
{.flags = 1ULL << VIRTIO_SND_F_CTLS,
|
||||
.end = endof(struct virtio_snd_config, controls)},
|
||||
{}
|
||||
};
|
||||
|
||||
static const VirtIOConfigSizeParams cfg_size_params = {
|
||||
.min_size = endof(struct virtio_snd_config, chmaps),
|
||||
.max_size = sizeof(struct virtio_snd_config),
|
||||
.feature_sizes = feature_sizes
|
||||
};
|
||||
|
||||
static const VMStateDescription vu_snd_vmstate = {
|
||||
.name = "vhost-user-snd",
|
||||
.unmigratable = 1,
|
||||
@@ -23,6 +35,8 @@ static const VMStateDescription vu_snd_vmstate = {
|
||||
|
||||
static Property vsnd_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", VHostUserBase, chardev),
|
||||
DEFINE_PROP_BIT64("controls", VHostUserBase,
|
||||
parent_obj.host_features, VIRTIO_SND_F_CTLS, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -30,10 +44,12 @@ static void vu_snd_base_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VHostUserBase *vub = VHOST_USER_BASE(dev);
|
||||
VHostUserBaseClass *vubs = VHOST_USER_BASE_GET_CLASS(dev);
|
||||
VirtIODevice *vdev = &vub->parent_obj;
|
||||
|
||||
vub->virtio_id = VIRTIO_ID_SOUND;
|
||||
vub->num_vqs = 4;
|
||||
vub->config_size = sizeof(struct virtio_snd_config);
|
||||
vub->config_size = virtio_get_config_size(&cfg_size_params,
|
||||
vdev->host_features);
|
||||
vub->vq_size = 64;
|
||||
|
||||
vubs->parent_realize(dev, errp);
|
||||
|
||||
@@ -1589,7 +1589,7 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
|
||||
g_free(req.iov_base);
|
||||
g_free(res.iov_base);
|
||||
virtqueue_push(vq, out_elem, 0);
|
||||
virtqueue_push(vq, in_elem, in_elem->in_sg->iov_len);
|
||||
virtqueue_push(vq, in_elem, sz);
|
||||
virtio_notify(vdev, vq);
|
||||
return;
|
||||
|
||||
|
||||
@@ -700,7 +700,6 @@ void xen_invalidate_map_cache(void)
|
||||
bdrv_drain_all();
|
||||
|
||||
xen_invalidate_map_cache_single(mapcache);
|
||||
xen_invalidate_map_cache_single(mapcache_grants);
|
||||
}
|
||||
|
||||
static uint8_t *xen_replace_cache_entry_unlocked(MapCache *mc,
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#define QEMU_ARM_BSA_H
|
||||
|
||||
/* These are architectural INTID values */
|
||||
#define ARCH_TIMER_S_EL2_VIRT_IRQ 19
|
||||
#define ARCH_TIMER_S_EL2_IRQ 20
|
||||
#define VIRTUAL_PMU_IRQ 23
|
||||
#define ARCH_GIC_MAINT_IRQ 25
|
||||
#define ARCH_TIMER_NS_EL2_IRQ 26
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#if defined(TARGET_I386) || defined(TARGET_X86_64)
|
||||
#include "hw/i386/xen_arch_hvm.h"
|
||||
#elif defined(TARGET_ARM) || defined(TARGET_ARM_64)
|
||||
#elif defined(TARGET_ARM) || defined(TARGET_AARCH64)
|
||||
#include "hw/arm/xen_arch_hvm.h"
|
||||
#endif
|
||||
|
||||
+29
-26
@@ -9097,35 +9097,38 @@ static void risc_hwprobe_fill_pairs(CPURISCVState *env,
|
||||
}
|
||||
}
|
||||
|
||||
static int cpu_set_valid(abi_long arg3, abi_long arg4)
|
||||
/*
|
||||
* If the cpumask_t of (target_cpus, cpusetsize) cannot be read: -EFAULT.
|
||||
* If the cpumast_t has no bits set: -EINVAL.
|
||||
* Otherwise the cpumask_t contains some bit set: 0.
|
||||
* Unlike the kernel, we do not mask cpumask_t by the set of online cpus,
|
||||
* nor bound the search by cpumask_size().
|
||||
*/
|
||||
static int nonempty_cpu_set(abi_ulong cpusetsize, abi_ptr target_cpus)
|
||||
{
|
||||
int ret, i, tmp;
|
||||
size_t host_mask_size, target_mask_size;
|
||||
unsigned long *host_mask;
|
||||
unsigned char *p = lock_user(VERIFY_READ, target_cpus, cpusetsize, 1);
|
||||
int ret = -TARGET_EFAULT;
|
||||
|
||||
/*
|
||||
* cpu_set_t represent CPU masks as bit masks of type unsigned long *.
|
||||
* arg3 contains the cpu count.
|
||||
*/
|
||||
tmp = (8 * sizeof(abi_ulong));
|
||||
target_mask_size = ((arg3 + tmp - 1) / tmp) * sizeof(abi_ulong);
|
||||
host_mask_size = (target_mask_size + (sizeof(*host_mask) - 1)) &
|
||||
~(sizeof(*host_mask) - 1);
|
||||
|
||||
host_mask = alloca(host_mask_size);
|
||||
|
||||
ret = target_to_host_cpu_mask(host_mask, host_mask_size,
|
||||
arg4, target_mask_size);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0 ; i < host_mask_size / sizeof(*host_mask); i++) {
|
||||
if (host_mask[i] != 0) {
|
||||
return 0;
|
||||
if (p) {
|
||||
ret = -TARGET_EINVAL;
|
||||
/*
|
||||
* Since we only care about the empty/non-empty state of the cpumask_t
|
||||
* not the individual bits, we do not need to repartition the bits
|
||||
* from target abi_ulong to host unsigned long.
|
||||
*
|
||||
* Note that the kernel does not round up cpusetsize to a multiple of
|
||||
* sizeof(abi_ulong). After bounding cpusetsize by cpumask_size(),
|
||||
* it copies exactly cpusetsize bytes into a zeroed buffer.
|
||||
*/
|
||||
for (abi_ulong i = 0; i < cpusetsize; ++i) {
|
||||
if (p[i]) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlock_user(p, target_cpus, 0);
|
||||
}
|
||||
return -TARGET_EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static abi_long do_riscv_hwprobe(CPUArchState *cpu_env, abi_long arg1,
|
||||
@@ -9142,7 +9145,7 @@ static abi_long do_riscv_hwprobe(CPUArchState *cpu_env, abi_long arg1,
|
||||
|
||||
/* check cpu_set */
|
||||
if (arg3 != 0) {
|
||||
ret = cpu_set_valid(arg3, arg4);
|
||||
ret = nonempty_cpu_set(arg3, arg4);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -381,9 +381,12 @@ NetClientState *qemu_get_peer(NetClientState *nc, int queue_index)
|
||||
return ncs->peer;
|
||||
}
|
||||
|
||||
static void qemu_cleanup_net_client(NetClientState *nc)
|
||||
static void qemu_cleanup_net_client(NetClientState *nc,
|
||||
bool remove_from_net_clients)
|
||||
{
|
||||
QTAILQ_REMOVE(&net_clients, nc, next);
|
||||
if (remove_from_net_clients) {
|
||||
QTAILQ_REMOVE(&net_clients, nc, next);
|
||||
}
|
||||
|
||||
if (nc->info->cleanup) {
|
||||
nc->info->cleanup(nc);
|
||||
@@ -425,7 +428,13 @@ void qemu_del_net_client(NetClientState *nc)
|
||||
object_unparent(OBJECT(nf));
|
||||
}
|
||||
|
||||
/* If there is a peer NIC, delete and cleanup client, but do not free. */
|
||||
/*
|
||||
* If there is a peer NIC, transfer ownership to it. Delete the client
|
||||
* from net_client list but do not cleanup nor free. This way NIC can
|
||||
* still access to members of the backend.
|
||||
*
|
||||
* The cleanup and free will be done when the NIC is free.
|
||||
*/
|
||||
if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
|
||||
NICState *nic = qemu_get_nic(nc->peer);
|
||||
if (nic->peer_deleted) {
|
||||
@@ -435,21 +444,18 @@ void qemu_del_net_client(NetClientState *nc)
|
||||
|
||||
for (i = 0; i < queues; i++) {
|
||||
ncs[i]->peer->link_down = true;
|
||||
QTAILQ_REMOVE(&net_clients, ncs[i], next);
|
||||
}
|
||||
|
||||
if (nc->peer->info->link_status_changed) {
|
||||
nc->peer->info->link_status_changed(nc->peer);
|
||||
}
|
||||
|
||||
for (i = 0; i < queues; i++) {
|
||||
qemu_cleanup_net_client(ncs[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < queues; i++) {
|
||||
qemu_cleanup_net_client(ncs[i]);
|
||||
qemu_cleanup_net_client(ncs[i], true);
|
||||
qemu_free_net_client(ncs[i]);
|
||||
}
|
||||
}
|
||||
@@ -462,8 +468,12 @@ void qemu_del_nic(NICState *nic)
|
||||
|
||||
for (i = 0; i < queues; i++) {
|
||||
NetClientState *nc = qemu_get_subqueue(nic, i);
|
||||
/* If this is a peer NIC and peer has already been deleted, free it now. */
|
||||
/*
|
||||
* If this is a peer NIC and peer has already been deleted, clean it up
|
||||
* and free it now.
|
||||
*/
|
||||
if (nic->peer_deleted) {
|
||||
qemu_cleanup_net_client(nc->peer, false);
|
||||
qemu_free_net_client(nc->peer);
|
||||
} else if (nc->peer) {
|
||||
/* if there are RX packets pending, complete them */
|
||||
@@ -474,7 +484,7 @@ void qemu_del_nic(NICState *nic)
|
||||
for (i = queues - 1; i >= 0; i--) {
|
||||
NetClientState *nc = qemu_get_subqueue(nic, i);
|
||||
|
||||
qemu_cleanup_net_client(nc);
|
||||
qemu_cleanup_net_client(nc, true);
|
||||
qemu_free_net_client(nc);
|
||||
}
|
||||
|
||||
@@ -1678,6 +1688,9 @@ void net_cleanup(void)
|
||||
* of the latest NET_CLIENT_DRIVER_NIC, and operate on *p as we walk
|
||||
* the list.
|
||||
*
|
||||
* However, the NIC may have peers that trust to be clean beyond this
|
||||
* point. For example, if they have been removed with device_del.
|
||||
*
|
||||
* The 'nc' variable isn't part of the list traversal; it's purely
|
||||
* for convenience as too much '(*p)->' has a tendency to make the
|
||||
* readers' eyes bleed.
|
||||
@@ -1685,6 +1698,17 @@ void net_cleanup(void)
|
||||
while (*p) {
|
||||
nc = *p;
|
||||
if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
|
||||
NICState *nic = qemu_get_nic(nc);
|
||||
|
||||
if (nic->peer_deleted) {
|
||||
int queues = MAX(nic->conf->peers.queues, 1);
|
||||
|
||||
for (int i = 0; i < queues; i++) {
|
||||
nc = qemu_get_subqueue(nic, i);
|
||||
qemu_cleanup_net_client(nc->peer, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip NET_CLIENT_DRIVER_NIC entries */
|
||||
p = &QTAILQ_NEXT(nc, next);
|
||||
} else {
|
||||
|
||||
+13
-8
@@ -224,14 +224,6 @@ static void vhost_vdpa_cleanup(NetClientState *nc)
|
||||
{
|
||||
VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
|
||||
|
||||
/*
|
||||
* If a peer NIC is attached, do not cleanup anything.
|
||||
* Cleanup will happen as a part of qemu_cleanup() -> net_cleanup()
|
||||
* when the guest is shutting down.
|
||||
*/
|
||||
if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_NIC) {
|
||||
return;
|
||||
}
|
||||
munmap(s->cvq_cmd_out_buffer, vhost_vdpa_net_cvq_cmd_page_len());
|
||||
munmap(s->status, vhost_vdpa_net_cvq_cmd_page_len());
|
||||
if (s->vhost_net) {
|
||||
@@ -270,6 +262,18 @@ static bool vhost_vdpa_has_ufo(NetClientState *nc)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: vhost_vdpa doesn't have an API to "set h/w endianness". But it's
|
||||
* reasonable to assume that h/w is LE by default, because LE is what
|
||||
* virtio 1.0 and later ask for. So, this function just says "yes, the h/w is
|
||||
* LE". Otherwise, on a BE machine, higher-level code would mistakely think
|
||||
* the h/w is BE and can't support VDPA for a virtio 1.0 client.
|
||||
*/
|
||||
static int vhost_vdpa_set_vnet_le(NetClientState *nc, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool vhost_vdpa_check_peer_type(NetClientState *nc, ObjectClass *oc,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -437,6 +441,7 @@ static NetClientInfo net_vhost_vdpa_info = {
|
||||
.cleanup = vhost_vdpa_cleanup,
|
||||
.has_vnet_hdr = vhost_vdpa_has_vnet_hdr,
|
||||
.has_ufo = vhost_vdpa_has_ufo,
|
||||
.set_vnet_le = vhost_vdpa_set_vnet_le,
|
||||
.check_peer_type = vhost_vdpa_check_peer_type,
|
||||
.set_steering_ebpf = vhost_vdpa_set_steering_ebpf,
|
||||
};
|
||||
|
||||
+5
-1
@@ -1868,7 +1868,11 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
|
||||
if (new_block->flags & RAM_GUEST_MEMFD) {
|
||||
int ret;
|
||||
|
||||
assert(kvm_enabled());
|
||||
if (!kvm_enabled()) {
|
||||
error_setg(errp, "cannot set up private guest memory for %s: KVM required",
|
||||
object_get_typename(OBJECT(current_machine->cgs)));
|
||||
goto out_free;
|
||||
}
|
||||
assert(new_block->guest_memfd < 0);
|
||||
|
||||
ret = ram_block_discard_require(true);
|
||||
|
||||
@@ -2078,6 +2078,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
arm_gt_stimer_cb, cpu);
|
||||
cpu->gt_timer[GTIMER_HYPVIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
|
||||
arm_gt_hvtimer_cb, cpu);
|
||||
cpu->gt_timer[GTIMER_S_EL2_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
|
||||
arm_gt_sel2timer_cb, cpu);
|
||||
cpu->gt_timer[GTIMER_S_EL2_VIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
|
||||
arm_gt_sel2vtimer_cb, cpu);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
#define EXCP_NMI 26
|
||||
#define EXCP_VINMI 27
|
||||
#define EXCP_VFNMI 28
|
||||
#define EXCP_MON_TRAP 29 /* AArch32 trap to Monitor mode */
|
||||
/* NB: add new EXCP_ defines to the array in arm_log_exception() too */
|
||||
|
||||
#define ARMV7M_EXCP_RESET 1
|
||||
@@ -1139,6 +1140,8 @@ void arm_gt_vtimer_cb(void *opaque);
|
||||
void arm_gt_htimer_cb(void *opaque);
|
||||
void arm_gt_stimer_cb(void *opaque);
|
||||
void arm_gt_hvtimer_cb(void *opaque);
|
||||
void arm_gt_sel2timer_cb(void *opaque);
|
||||
void arm_gt_sel2vtimer_cb(void *opaque);
|
||||
|
||||
unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
|
||||
void gt_rme_post_el_change(ARMCPU *cpu, void *opaque);
|
||||
@@ -2561,6 +2564,11 @@ static inline bool arm_is_secure_below_el3(CPUARMState *env)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool arm_is_el3_or_mon(CPUARMState *env)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline ARMSecuritySpace arm_security_space(CPUARMState *env)
|
||||
{
|
||||
return ARMSS_NonSecure;
|
||||
|
||||
@@ -880,7 +880,8 @@ static CPAccessResult access_tdcc(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
if (el < 2 && (mdcr_el2_tda || mdcr_el2_tdcc)) {
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
}
|
||||
if (el < 3 && ((env->cp15.mdcr_el3 & MDCR_TDA) || mdcr_el3_tdcc)) {
|
||||
if (!arm_is_el3_or_mon(env) &&
|
||||
((env->cp15.mdcr_el3 & MDCR_TDA) || mdcr_el3_tdcc)) {
|
||||
return CP_ACCESS_TRAP_EL3;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
|
||||
+3
-1
@@ -15,7 +15,9 @@ enum {
|
||||
GTIMER_HYP = 2,
|
||||
GTIMER_SEC = 3,
|
||||
GTIMER_HYPVIRT = 4,
|
||||
#define NUM_GTIMERS 5
|
||||
GTIMER_S_EL2_PHYS = 5, /* CNTHPS_* ; only if FEAT_SEL2 */
|
||||
GTIMER_S_EL2_VIRT = 6, /* CNTHVS_* ; only if FEAT_SEL2 */
|
||||
#define NUM_GTIMERS 7
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+284
-65
@@ -2652,7 +2652,10 @@ static CPAccessResult gt_stimer_access(CPUARMState *env,
|
||||
switch (arm_current_el(env)) {
|
||||
case 1:
|
||||
if (!arm_is_secure(env)) {
|
||||
return CP_ACCESS_TRAP;
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
}
|
||||
if (arm_is_el2_enabled(env)) {
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
}
|
||||
if (!(env->cp15.scr_el3 & SCR_ST)) {
|
||||
return CP_ACCESS_TRAP_EL3;
|
||||
@@ -2660,7 +2663,7 @@ static CPAccessResult gt_stimer_access(CPUARMState *env,
|
||||
return CP_ACCESS_OK;
|
||||
case 0:
|
||||
case 2:
|
||||
return CP_ACCESS_TRAP;
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
case 3:
|
||||
return CP_ACCESS_OK;
|
||||
default:
|
||||
@@ -2668,6 +2671,45 @@ static CPAccessResult gt_stimer_access(CPUARMState *env,
|
||||
}
|
||||
}
|
||||
|
||||
static CPAccessResult gt_sel2timer_access(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/*
|
||||
* The AArch64 register view of the secure EL2 timers are mostly
|
||||
* accessible from EL3 and EL2 although can also be trapped to EL2
|
||||
* from EL1 depending on nested virt config.
|
||||
*/
|
||||
switch (arm_current_el(env)) {
|
||||
case 0: /* UNDEFINED */
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
case 1:
|
||||
if (!arm_is_secure(env)) {
|
||||
/* UNDEFINED */
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
} else if (arm_hcr_el2_eff(env) & HCR_NV) {
|
||||
/* Aarch64.SystemAccessTrap(EL2, 0x18) */
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
}
|
||||
/* UNDEFINED */
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
case 2:
|
||||
if (!arm_is_secure(env)) {
|
||||
/* UNDEFINED */
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
case 3:
|
||||
if (env->cp15.scr_el3 & SCR_EEL2) {
|
||||
return CP_ACCESS_OK;
|
||||
} else {
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t gt_get_countervalue(CPUARMState *env)
|
||||
{
|
||||
ARMCPU *cpu = env_archcpu(env);
|
||||
@@ -2719,12 +2761,80 @@ static uint64_t gt_phys_raw_cnt_offset(CPUARMState *env)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t gt_phys_cnt_offset(CPUARMState *env)
|
||||
static uint64_t gt_indirect_access_timer_offset(CPUARMState *env, int timeridx)
|
||||
{
|
||||
if (arm_current_el(env) >= 2) {
|
||||
/*
|
||||
* Return the timer offset to use for indirect accesses to the timer.
|
||||
* This is the Offset value as defined in D12.2.4.1 "Operation of the
|
||||
* CompareValue views of the timers".
|
||||
*
|
||||
* The condition here is not always the same as the condition for
|
||||
* whether to apply an offset register when doing a direct read of
|
||||
* the counter sysreg; those conditions are described in the
|
||||
* access pseudocode for each counter register.
|
||||
*/
|
||||
switch (timeridx) {
|
||||
case GTIMER_PHYS:
|
||||
return gt_phys_raw_cnt_offset(env);
|
||||
case GTIMER_VIRT:
|
||||
return env->cp15.cntvoff_el2;
|
||||
case GTIMER_HYP:
|
||||
case GTIMER_SEC:
|
||||
case GTIMER_HYPVIRT:
|
||||
case GTIMER_S_EL2_PHYS:
|
||||
case GTIMER_S_EL2_VIRT:
|
||||
return 0;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t gt_direct_access_timer_offset(CPUARMState *env, int timeridx)
|
||||
{
|
||||
/*
|
||||
* Return the timer offset to use for direct accesses to the
|
||||
* counter registers CNTPCT and CNTVCT, and for direct accesses
|
||||
* to the CNT*_TVAL registers.
|
||||
*
|
||||
* This isn't exactly the same as the indirect-access offset,
|
||||
* because here we also care about what EL the register access
|
||||
* is being made from.
|
||||
*
|
||||
* This corresponds to the access pseudocode for the registers.
|
||||
*/
|
||||
uint64_t hcr;
|
||||
|
||||
switch (timeridx) {
|
||||
case GTIMER_PHYS:
|
||||
if (arm_current_el(env) >= 2) {
|
||||
return 0;
|
||||
}
|
||||
return gt_phys_raw_cnt_offset(env);
|
||||
case GTIMER_VIRT:
|
||||
switch (arm_current_el(env)) {
|
||||
case 2:
|
||||
hcr = arm_hcr_el2_eff(env);
|
||||
if (hcr & HCR_E2H) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
hcr = arm_hcr_el2_eff(env);
|
||||
if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return env->cp15.cntvoff_el2;
|
||||
case GTIMER_HYP:
|
||||
case GTIMER_SEC:
|
||||
case GTIMER_HYPVIRT:
|
||||
case GTIMER_S_EL2_PHYS:
|
||||
case GTIMER_S_EL2_VIRT:
|
||||
return 0;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return gt_phys_raw_cnt_offset(env);
|
||||
}
|
||||
|
||||
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
||||
@@ -2736,8 +2846,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
|
||||
* Timer enabled: calculate and set current ISTATUS, irq, and
|
||||
* reset timer to when ISTATUS next has to change
|
||||
*/
|
||||
uint64_t offset = timeridx == GTIMER_VIRT ?
|
||||
cpu->env.cp15.cntvoff_el2 : gt_phys_raw_cnt_offset(&cpu->env);
|
||||
uint64_t offset = gt_indirect_access_timer_offset(&cpu->env, timeridx);
|
||||
uint64_t count = gt_get_countervalue(&cpu->env);
|
||||
/* Note that this must be unsigned 64 bit arithmetic: */
|
||||
int istatus = count - offset >= gt->cval;
|
||||
@@ -2800,34 +2909,14 @@ static void gt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
|
||||
static uint64_t gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
return gt_get_countervalue(env) - gt_phys_cnt_offset(env);
|
||||
}
|
||||
|
||||
uint64_t gt_virt_cnt_offset(CPUARMState *env)
|
||||
{
|
||||
uint64_t hcr;
|
||||
|
||||
switch (arm_current_el(env)) {
|
||||
case 2:
|
||||
hcr = arm_hcr_el2_eff(env);
|
||||
if (hcr & HCR_E2H) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
hcr = arm_hcr_el2_eff(env);
|
||||
if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return env->cp15.cntvoff_el2;
|
||||
uint64_t offset = gt_direct_access_timer_offset(env, GTIMER_PHYS);
|
||||
return gt_get_countervalue(env) - offset;
|
||||
}
|
||||
|
||||
static uint64_t gt_virt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
return gt_get_countervalue(env) - gt_virt_cnt_offset(env);
|
||||
uint64_t offset = gt_direct_access_timer_offset(env, GTIMER_VIRT);
|
||||
return gt_get_countervalue(env) - offset;
|
||||
}
|
||||
|
||||
static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
@@ -2839,45 +2928,36 @@ static void gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
gt_recalc_timer(env_archcpu(env), timeridx);
|
||||
}
|
||||
|
||||
static uint64_t do_tval_read(CPUARMState *env, int timeridx, uint64_t offset)
|
||||
{
|
||||
return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
|
||||
(gt_get_countervalue(env) - offset));
|
||||
}
|
||||
|
||||
static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
int timeridx)
|
||||
{
|
||||
uint64_t offset = 0;
|
||||
uint64_t offset = gt_direct_access_timer_offset(env, timeridx);
|
||||
|
||||
switch (timeridx) {
|
||||
case GTIMER_VIRT:
|
||||
case GTIMER_HYPVIRT:
|
||||
offset = gt_virt_cnt_offset(env);
|
||||
break;
|
||||
case GTIMER_PHYS:
|
||||
offset = gt_phys_cnt_offset(env);
|
||||
break;
|
||||
}
|
||||
return do_tval_read(env, timeridx, offset);
|
||||
}
|
||||
|
||||
return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
|
||||
(gt_get_countervalue(env) - offset));
|
||||
static void do_tval_write(CPUARMState *env, int timeridx, uint64_t value,
|
||||
uint64_t offset)
|
||||
{
|
||||
trace_arm_gt_tval_write(timeridx, value);
|
||||
env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) - offset +
|
||||
sextract64(value, 0, 32);
|
||||
gt_recalc_timer(env_archcpu(env), timeridx);
|
||||
}
|
||||
|
||||
static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
int timeridx,
|
||||
uint64_t value)
|
||||
{
|
||||
uint64_t offset = 0;
|
||||
uint64_t offset = gt_direct_access_timer_offset(env, timeridx);
|
||||
|
||||
switch (timeridx) {
|
||||
case GTIMER_VIRT:
|
||||
case GTIMER_HYPVIRT:
|
||||
offset = gt_virt_cnt_offset(env);
|
||||
break;
|
||||
case GTIMER_PHYS:
|
||||
offset = gt_phys_cnt_offset(env);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_arm_gt_tval_write(timeridx, value);
|
||||
env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) - offset +
|
||||
sextract64(value, 0, 32);
|
||||
gt_recalc_timer(env_archcpu(env), timeridx);
|
||||
do_tval_write(env, timeridx, value, offset);
|
||||
}
|
||||
|
||||
static void gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
@@ -3009,13 +3089,21 @@ static void gt_virt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
|
||||
static uint64_t gt_virt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
return gt_tval_read(env, ri, GTIMER_VIRT);
|
||||
/*
|
||||
* This is CNTV_TVAL_EL02; unlike the underlying CNTV_TVAL_EL0
|
||||
* we always apply CNTVOFF_EL2. Special case that here rather
|
||||
* than going into the generic gt_tval_read() and then having
|
||||
* to re-detect that it's this register.
|
||||
* Note that the accessfn/perms mean we know we're at EL2 or EL3 here.
|
||||
*/
|
||||
return do_tval_read(env, GTIMER_VIRT, env->cp15.cntvoff_el2);
|
||||
}
|
||||
|
||||
static void gt_virt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_tval_write(env, ri, GTIMER_VIRT, value);
|
||||
/* Similarly for writes to CNTV_TVAL_EL02 */
|
||||
do_tval_write(env, GTIMER_VIRT, value, env->cp15.cntvoff_el2);
|
||||
}
|
||||
|
||||
static void gt_virt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
@@ -3175,6 +3263,62 @@ static void gt_sec_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
gt_ctl_write(env, ri, GTIMER_SEC, value);
|
||||
}
|
||||
|
||||
static void gt_sec_pel2_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
gt_timer_reset(env, ri, GTIMER_S_EL2_PHYS);
|
||||
}
|
||||
|
||||
static void gt_sec_pel2_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_cval_write(env, ri, GTIMER_S_EL2_PHYS, value);
|
||||
}
|
||||
|
||||
static uint64_t gt_sec_pel2_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
return gt_tval_read(env, ri, GTIMER_S_EL2_PHYS);
|
||||
}
|
||||
|
||||
static void gt_sec_pel2_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_tval_write(env, ri, GTIMER_S_EL2_PHYS, value);
|
||||
}
|
||||
|
||||
static void gt_sec_pel2_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_ctl_write(env, ri, GTIMER_S_EL2_PHYS, value);
|
||||
}
|
||||
|
||||
static void gt_sec_vel2_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
gt_timer_reset(env, ri, GTIMER_S_EL2_VIRT);
|
||||
}
|
||||
|
||||
static void gt_sec_vel2_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_cval_write(env, ri, GTIMER_S_EL2_VIRT, value);
|
||||
}
|
||||
|
||||
static uint64_t gt_sec_vel2_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
return gt_tval_read(env, ri, GTIMER_S_EL2_VIRT);
|
||||
}
|
||||
|
||||
static void gt_sec_vel2_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_tval_write(env, ri, GTIMER_S_EL2_VIRT, value);
|
||||
}
|
||||
|
||||
static void gt_sec_vel2_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
gt_ctl_write(env, ri, GTIMER_S_EL2_VIRT, value);
|
||||
}
|
||||
|
||||
static void gt_hv_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
gt_timer_reset(env, ri, GTIMER_HYPVIRT);
|
||||
@@ -3231,6 +3375,20 @@ void arm_gt_stimer_cb(void *opaque)
|
||||
gt_recalc_timer(cpu, GTIMER_SEC);
|
||||
}
|
||||
|
||||
void arm_gt_sel2timer_cb(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
gt_recalc_timer(cpu, GTIMER_S_EL2_PHYS);
|
||||
}
|
||||
|
||||
void arm_gt_sel2vtimer_cb(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
|
||||
gt_recalc_timer(cpu, GTIMER_S_EL2_VIRT);
|
||||
}
|
||||
|
||||
void arm_gt_hvtimer_cb(void *opaque)
|
||||
{
|
||||
ARMCPU *cpu = opaque;
|
||||
@@ -3868,7 +4026,7 @@ static CPAccessResult at_e012_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
* scr_write() ensures that the NSE bit is not set otherwise.
|
||||
*/
|
||||
if ((env->cp15.scr_el3 & (SCR_NSE | SCR_NS)) == SCR_NSE) {
|
||||
return CP_ACCESS_TRAP;
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
@@ -3878,7 +4036,7 @@ static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
{
|
||||
if (arm_current_el(env) == 3 &&
|
||||
!(env->cp15.scr_el3 & (SCR_NS | SCR_EEL2))) {
|
||||
return CP_ACCESS_TRAP;
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
}
|
||||
return at_e012_access(env, ri, isread);
|
||||
}
|
||||
@@ -6613,6 +6771,56 @@ static const ARMCPRegInfo el2_sec_cp_reginfo[] = {
|
||||
.access = PL2_RW, .accessfn = sel2_access,
|
||||
.nv2_redirect_offset = 0x48,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.vstcr_el2) },
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Secure EL2 Physical Timer */
|
||||
{ .name = "CNTHPS_TVAL_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 5, .opc2 = 0,
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL2_RW,
|
||||
.accessfn = gt_sel2timer_access,
|
||||
.readfn = gt_sec_pel2_tval_read,
|
||||
.writefn = gt_sec_pel2_tval_write,
|
||||
.resetfn = gt_sec_pel2_timer_reset,
|
||||
},
|
||||
{ .name = "CNTHPS_CTL_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 5, .opc2 = 1,
|
||||
.type = ARM_CP_IO, .access = PL2_RW,
|
||||
.accessfn = gt_sel2timer_access,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_PHYS].ctl),
|
||||
.resetvalue = 0,
|
||||
.writefn = gt_sec_pel2_ctl_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTHPS_CVAL_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 5, .opc2 = 2,
|
||||
.type = ARM_CP_IO, .access = PL2_RW,
|
||||
.accessfn = gt_sel2timer_access,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_PHYS].cval),
|
||||
.writefn = gt_sec_pel2_cval_write, .raw_writefn = raw_write,
|
||||
},
|
||||
/* Secure EL2 Virtual Timer */
|
||||
{ .name = "CNTHVS_TVAL_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 4, .opc2 = 0,
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL2_RW,
|
||||
.accessfn = gt_sel2timer_access,
|
||||
.readfn = gt_sec_vel2_tval_read,
|
||||
.writefn = gt_sec_vel2_tval_write,
|
||||
.resetfn = gt_sec_vel2_timer_reset,
|
||||
},
|
||||
{ .name = "CNTHVS_CTL_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 4, .opc2 = 1,
|
||||
.type = ARM_CP_IO, .access = PL2_RW,
|
||||
.accessfn = gt_sel2timer_access,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_VIRT].ctl),
|
||||
.resetvalue = 0,
|
||||
.writefn = gt_sec_vel2_ctl_write, .raw_writefn = raw_write,
|
||||
},
|
||||
{ .name = "CNTHVS_CVAL_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 14, .crm = 4, .opc2 = 2,
|
||||
.type = ARM_CP_IO, .access = PL2_RW,
|
||||
.accessfn = gt_sel2timer_access,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_VIRT].cval),
|
||||
.writefn = gt_sec_vel2_cval_write, .raw_writefn = raw_write,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
@@ -7052,7 +7260,7 @@ static CPAccessResult access_terr(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
if (el < 2 && (arm_hcr_el2_eff(env) & HCR_TERR)) {
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
}
|
||||
if (el < 3 && (env->cp15.scr_el3 & SCR_TERR)) {
|
||||
if (!arm_is_el3_or_mon(env) && (env->cp15.scr_el3 & SCR_TERR)) {
|
||||
return CP_ACCESS_TRAP_EL3;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
@@ -7737,8 +7945,8 @@ static CPAccessResult access_lor_other(CPUARMState *env,
|
||||
const ARMCPRegInfo *ri, bool isread)
|
||||
{
|
||||
if (arm_is_secure_below_el3(env)) {
|
||||
/* Access denied in secure mode. */
|
||||
return CP_ACCESS_TRAP;
|
||||
/* UNDEF if SCR_EL3.NS == 0 */
|
||||
return CP_ACCESS_TRAP_UNCATEGORIZED;
|
||||
}
|
||||
return access_lor_ns(env, ri, isread);
|
||||
}
|
||||
@@ -10858,6 +11066,7 @@ void arm_log_exception(CPUState *cs)
|
||||
[EXCP_NMI] = "NMI",
|
||||
[EXCP_VINMI] = "Virtual IRQ NMI",
|
||||
[EXCP_VFNMI] = "Virtual FIQ NMI",
|
||||
[EXCP_MON_TRAP] = "Monitor Trap",
|
||||
};
|
||||
|
||||
if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
|
||||
@@ -11424,6 +11633,16 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
|
||||
mask = CPSR_A | CPSR_I | CPSR_F;
|
||||
offset = 0;
|
||||
break;
|
||||
case EXCP_MON_TRAP:
|
||||
new_mode = ARM_CPU_MODE_MON;
|
||||
addr = 0x04;
|
||||
mask = CPSR_A | CPSR_I | CPSR_F;
|
||||
if (env->thumb) {
|
||||
offset = 2;
|
||||
} else {
|
||||
offset = 4;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
|
||||
return; /* Never happens. Keep compiler happy. */
|
||||
|
||||
@@ -897,6 +897,18 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
||||
|
||||
clamp_id_aa64mmfr0_parange_to_ipa_size(&host_isar.id_aa64mmfr0);
|
||||
|
||||
/*
|
||||
* Disable SME, which is not properly handled by QEMU hvf yet.
|
||||
* To allow this through we would need to:
|
||||
* - make sure that the SME state is correctly handled in the
|
||||
* get_registers/put_registers functions
|
||||
* - get the SME-specific CPU properties to work with accelerators
|
||||
* other than TCG
|
||||
* - fix any assumptions we made that SME implies SVE (since
|
||||
* on the M4 there is SME but not SVE)
|
||||
*/
|
||||
host_isar.id_aa64pfr1 &= ~R_ID_AA64PFR1_SME_MASK;
|
||||
|
||||
ahcf->isar = host_isar;
|
||||
|
||||
/*
|
||||
@@ -1962,6 +1974,7 @@ int hvf_vcpu_exec(CPUState *cpu)
|
||||
bool isv = syndrome & ARM_EL_ISV;
|
||||
bool iswrite = (syndrome >> 6) & 1;
|
||||
bool s1ptw = (syndrome >> 7) & 1;
|
||||
bool sse = (syndrome >> 21) & 1;
|
||||
uint32_t sas = (syndrome >> 22) & 3;
|
||||
uint32_t len = 1 << sas;
|
||||
uint32_t srt = (syndrome >> 16) & 0x1f;
|
||||
@@ -1989,6 +2002,9 @@ int hvf_vcpu_exec(CPUState *cpu)
|
||||
address_space_read(&address_space_memory,
|
||||
hvf_exit->exception.physical_address,
|
||||
MEMTXATTRS_UNSPECIFIED, &val, len);
|
||||
if (sse) {
|
||||
val = sextract64(val, 0, len * 8);
|
||||
}
|
||||
hvf_set_reg(cpu, srt, val);
|
||||
}
|
||||
|
||||
|
||||
@@ -1814,7 +1814,8 @@ int delete_hw_watchpoint(target_ulong addr, target_ulong len, int type);
|
||||
uint64_t gt_get_countervalue(CPUARMState *env);
|
||||
/*
|
||||
* Return the currently applicable offset between the system counter
|
||||
* and CNTVCT_EL0 (this will be either 0 or the value of CNTVOFF_EL2).
|
||||
* and the counter for the specified timer, as used for direct register
|
||||
* accesses.
|
||||
*/
|
||||
uint64_t gt_virt_cnt_offset(CPUARMState *env);
|
||||
uint64_t gt_direct_access_timer_offset(CPUARMState *env, int timeridx);
|
||||
#endif
|
||||
|
||||
+37
-21
@@ -313,15 +313,19 @@ void HELPER(check_bxj_trap)(CPUARMState *env, uint32_t rm)
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Function checks whether WFx (WFI/WFE) instructions are set up to be trapped.
|
||||
/*
|
||||
* Function checks whether WFx (WFI/WFE) instructions are set up to be trapped.
|
||||
* The function returns the target EL (1-3) if the instruction is to be trapped;
|
||||
* otherwise it returns 0 indicating it is not trapped.
|
||||
* For a trap, *excp is updated with the EXCP_* trap type to use.
|
||||
*/
|
||||
static inline int check_wfx_trap(CPUARMState *env, bool is_wfe)
|
||||
static inline int check_wfx_trap(CPUARMState *env, bool is_wfe, uint32_t *excp)
|
||||
{
|
||||
int cur_el = arm_current_el(env);
|
||||
uint64_t mask;
|
||||
|
||||
*excp = EXCP_UDEF;
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
/* M profile cores can never trap WFI/WFE. */
|
||||
return 0;
|
||||
@@ -331,18 +335,9 @@ static inline int check_wfx_trap(CPUARMState *env, bool is_wfe)
|
||||
* WFx instructions being trapped to EL1. These trap bits don't exist in v7.
|
||||
*/
|
||||
if (cur_el < 1 && arm_feature(env, ARM_FEATURE_V8)) {
|
||||
int target_el;
|
||||
|
||||
mask = is_wfe ? SCTLR_nTWE : SCTLR_nTWI;
|
||||
if (arm_is_secure_below_el3(env) && !arm_el_is_aa64(env, 3)) {
|
||||
/* Secure EL0 and Secure PL1 is at EL3 */
|
||||
target_el = 3;
|
||||
} else {
|
||||
target_el = 1;
|
||||
}
|
||||
|
||||
if (!(env->cp15.sctlr_el[target_el] & mask)) {
|
||||
return target_el;
|
||||
if (!(arm_sctlr(env, cur_el) & mask)) {
|
||||
return exception_target_el(env);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,9 +353,12 @@ static inline int check_wfx_trap(CPUARMState *env, bool is_wfe)
|
||||
}
|
||||
|
||||
/* We are not trapping to EL1 or EL2; trap to EL3 if SCR_EL3 requires it */
|
||||
if (cur_el < 3) {
|
||||
if (arm_feature(env, ARM_FEATURE_V8) && !arm_is_el3_or_mon(env)) {
|
||||
mask = (is_wfe) ? SCR_TWE : SCR_TWI;
|
||||
if (env->cp15.scr_el3 & mask) {
|
||||
if (!arm_el_is_aa64(env, 3)) {
|
||||
*excp = EXCP_MON_TRAP;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
@@ -383,7 +381,8 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
|
||||
return;
|
||||
#else
|
||||
CPUState *cs = env_cpu(env);
|
||||
int target_el = check_wfx_trap(env, false);
|
||||
uint32_t excp;
|
||||
int target_el = check_wfx_trap(env, false, &excp);
|
||||
|
||||
if (cpu_has_work(cs)) {
|
||||
/* Don't bother to go into our "low power state" if
|
||||
@@ -399,7 +398,7 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
|
||||
env->regs[15] -= insn_len;
|
||||
}
|
||||
|
||||
raise_exception(env, EXCP_UDEF, syn_wfx(1, 0xe, 0, insn_len == 2),
|
||||
raise_exception(env, excp, syn_wfx(1, 0xe, 0, insn_len == 2),
|
||||
target_el);
|
||||
}
|
||||
|
||||
@@ -424,10 +423,17 @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout)
|
||||
#else
|
||||
ARMCPU *cpu = env_archcpu(env);
|
||||
CPUState *cs = env_cpu(env);
|
||||
int target_el = check_wfx_trap(env, false);
|
||||
uint32_t excp;
|
||||
int target_el = check_wfx_trap(env, false, &excp);
|
||||
/* The WFIT should time out when CNTVCT_EL0 >= the specified value. */
|
||||
uint64_t cntval = gt_get_countervalue(env);
|
||||
uint64_t offset = gt_virt_cnt_offset(env);
|
||||
/*
|
||||
* We want the value that we would get if we read CNTVCT_EL0 from
|
||||
* the current exception level, so the direct_access offset, not
|
||||
* the indirect_access one. Compare the pseudocode LocalTimeoutEvent(),
|
||||
* which calls VirtualCounterTimer().
|
||||
*/
|
||||
uint64_t offset = gt_direct_access_timer_offset(env, GTIMER_VIRT);
|
||||
uint64_t cntvct = cntval - offset;
|
||||
uint64_t nexttick;
|
||||
|
||||
@@ -441,8 +447,7 @@ void HELPER(wfit)(CPUARMState *env, uint64_t timeout)
|
||||
|
||||
if (target_el) {
|
||||
env->pc -= 4;
|
||||
raise_exception(env, EXCP_UDEF, syn_wfx(1, 0xe, 0, false),
|
||||
target_el);
|
||||
raise_exception(env, excp, syn_wfx(1, 0xe, 0, false), target_el);
|
||||
}
|
||||
|
||||
if (uadd64_overflow(timeout, offset, &nexttick)) {
|
||||
@@ -758,6 +763,7 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
|
||||
const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, key);
|
||||
CPAccessResult res = CP_ACCESS_OK;
|
||||
int target_el;
|
||||
uint32_t excp;
|
||||
|
||||
assert(ri != NULL);
|
||||
|
||||
@@ -842,8 +848,18 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
|
||||
}
|
||||
|
||||
fail:
|
||||
excp = EXCP_UDEF;
|
||||
switch (res & ~CP_ACCESS_EL_MASK) {
|
||||
case CP_ACCESS_TRAP:
|
||||
/*
|
||||
* If EL3 is AArch32 then there's no syndrome register; the cases
|
||||
* where we would raise a SystemAccessTrap to AArch64 EL3 all become
|
||||
* raising a Monitor trap exception. (Because there's no visible
|
||||
* syndrome it doesn't matter what we pass to raise_exception().)
|
||||
*/
|
||||
if ((res & CP_ACCESS_EL_MASK) == 3 && !arm_el_is_aa64(env, 3)) {
|
||||
excp = EXCP_MON_TRAP;
|
||||
}
|
||||
break;
|
||||
case CP_ACCESS_TRAP_UNCATEGORIZED:
|
||||
/* Only CP_ACCESS_TRAP traps are direct to a specified EL */
|
||||
@@ -879,7 +895,7 @@ const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
raise_exception(env, EXCP_UDEF, syndrome, target_el);
|
||||
raise_exception(env, excp, syndrome, target_el);
|
||||
}
|
||||
|
||||
const void *HELPER(lookup_cp_reg)(CPUARMState *env, uint32_t key)
|
||||
|
||||
@@ -1215,14 +1215,14 @@ static bool fp_access_check_only(DisasContext *s)
|
||||
{
|
||||
if (s->fp_excp_el) {
|
||||
assert(!s->fp_access_checked);
|
||||
s->fp_access_checked = true;
|
||||
s->fp_access_checked = -1;
|
||||
|
||||
gen_exception_insn_el(s, 0, EXCP_UDEF,
|
||||
syn_fp_access_trap(1, 0xe, false, 0),
|
||||
s->fp_excp_el);
|
||||
return false;
|
||||
}
|
||||
s->fp_access_checked = true;
|
||||
s->fp_access_checked = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1247,23 +1247,23 @@ static bool fp_access_check(DisasContext *s)
|
||||
bool sve_access_check(DisasContext *s)
|
||||
{
|
||||
if (s->pstate_sm || !dc_isar_feature(aa64_sve, s)) {
|
||||
bool ret;
|
||||
|
||||
assert(dc_isar_feature(aa64_sme, s));
|
||||
if (!sme_sm_enabled_check(s)) {
|
||||
goto fail_exit;
|
||||
}
|
||||
} else if (s->sve_excp_el) {
|
||||
ret = sme_sm_enabled_check(s);
|
||||
s->sve_access_checked = (ret ? 1 : -1);
|
||||
return ret;
|
||||
}
|
||||
if (s->sve_excp_el) {
|
||||
/* Assert that we only raise one exception per instruction. */
|
||||
assert(!s->sve_access_checked);
|
||||
gen_exception_insn_el(s, 0, EXCP_UDEF,
|
||||
syn_sve_access_trap(), s->sve_excp_el);
|
||||
goto fail_exit;
|
||||
s->sve_access_checked = -1;
|
||||
return false;
|
||||
}
|
||||
s->sve_access_checked = true;
|
||||
s->sve_access_checked = 1;
|
||||
return fp_access_check(s);
|
||||
|
||||
fail_exit:
|
||||
/* Assert that we only raise one exception per instruction. */
|
||||
assert(!s->sve_access_checked);
|
||||
s->sve_access_checked = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1291,8 +1291,9 @@ bool sme_enabled_check(DisasContext *s)
|
||||
* sme_excp_el by itself for cpregs access checks.
|
||||
*/
|
||||
if (!s->fp_excp_el || s->sme_excp_el < s->fp_excp_el) {
|
||||
s->fp_access_checked = true;
|
||||
return sme_access_check(s);
|
||||
bool ret = sme_access_check(s);
|
||||
s->fp_access_checked = (ret ? 1 : -1);
|
||||
return ret;
|
||||
}
|
||||
return fp_access_check_only(s);
|
||||
}
|
||||
@@ -11825,8 +11826,8 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
||||
s->insn = insn;
|
||||
s->base.pc_next = pc + 4;
|
||||
|
||||
s->fp_access_checked = false;
|
||||
s->sve_access_checked = false;
|
||||
s->fp_access_checked = 0;
|
||||
s->sve_access_checked = 0;
|
||||
|
||||
if (s->pstate_il) {
|
||||
/*
|
||||
|
||||
@@ -65,7 +65,7 @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
|
||||
static inline void assert_fp_access_checked(DisasContext *s)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_TCG
|
||||
if (unlikely(!s->fp_access_checked || s->fp_excp_el)) {
|
||||
if (unlikely(s->fp_access_checked <= 0)) {
|
||||
fprintf(stderr, "target-arm: FP access check missing for "
|
||||
"instruction 0x%08x\n", s->insn);
|
||||
abort();
|
||||
|
||||
+85
-44
@@ -5003,10 +5003,49 @@ static bool op_store_rr(DisasContext *s, arg_ldst_rr *a,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void do_ldrd_load(DisasContext *s, TCGv_i32 addr, int rt, int rt2)
|
||||
{
|
||||
/*
|
||||
* LDRD is required to be an atomic 64-bit access if the
|
||||
* address is 8-aligned, two atomic 32-bit accesses if
|
||||
* it's only 4-aligned, and to give an alignment fault
|
||||
* if it's not 4-aligned. This is MO_ALIGN_4 | MO_ATOM_SUBALIGN.
|
||||
* Rt is always the word from the lower address, and Rt2 the
|
||||
* data from the higher address, regardless of endianness.
|
||||
* So (like gen_load_exclusive) we avoid gen_aa32_ld_i64()
|
||||
* so we don't get its SCTLR_B check, and instead do a 64-bit access
|
||||
* using MO_BE if appropriate and then split the two halves.
|
||||
*
|
||||
* For M-profile, and for A-profile before LPAE, the 64-bit
|
||||
* atomicity is not required. We could model that using
|
||||
* the looser MO_ATOM_IFALIGN_PAIR, but providing a higher
|
||||
* level of atomicity than required is harmless (we would not
|
||||
* currently generate better code for IFALIGN_PAIR here).
|
||||
*
|
||||
* This also gives us the correct behaviour of not updating
|
||||
* rt if the load of rt2 faults; this is required for cases
|
||||
* like "ldrd r2, r3, [r2]" where rt is also the base register.
|
||||
*/
|
||||
int mem_idx = get_mem_index(s);
|
||||
MemOp opc = MO_64 | MO_ALIGN_4 | MO_ATOM_SUBALIGN | s->be_data;
|
||||
TCGv taddr = gen_aa32_addr(s, addr, opc);
|
||||
TCGv_i64 t64 = tcg_temp_new_i64();
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
TCGv_i32 tmp2 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_qemu_ld_i64(t64, taddr, mem_idx, opc);
|
||||
if (s->be_data == MO_BE) {
|
||||
tcg_gen_extr_i64_i32(tmp2, tmp, t64);
|
||||
} else {
|
||||
tcg_gen_extr_i64_i32(tmp, tmp2, t64);
|
||||
}
|
||||
store_reg(s, rt, tmp);
|
||||
store_reg(s, rt2, tmp2);
|
||||
}
|
||||
|
||||
static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a)
|
||||
{
|
||||
int mem_idx = get_mem_index(s);
|
||||
TCGv_i32 addr, tmp;
|
||||
TCGv_i32 addr;
|
||||
|
||||
if (!ENABLE_ARCH_5TE) {
|
||||
return false;
|
||||
@@ -5017,25 +5056,49 @@ static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a)
|
||||
}
|
||||
addr = op_addr_rr_pre(s, a);
|
||||
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
|
||||
store_reg(s, a->rt, tmp);
|
||||
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
|
||||
store_reg(s, a->rt + 1, tmp);
|
||||
do_ldrd_load(s, addr, a->rt, a->rt + 1);
|
||||
|
||||
/* LDRD w/ base writeback is undefined if the registers overlap. */
|
||||
op_addr_rr_post(s, a, addr, -4);
|
||||
op_addr_rr_post(s, a, addr, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void do_strd_store(DisasContext *s, TCGv_i32 addr, int rt, int rt2)
|
||||
{
|
||||
/*
|
||||
* STRD is required to be an atomic 64-bit access if the
|
||||
* address is 8-aligned, two atomic 32-bit accesses if
|
||||
* it's only 4-aligned, and to give an alignment fault
|
||||
* if it's not 4-aligned.
|
||||
* Rt is always the word from the lower address, and Rt2 the
|
||||
* data from the higher address, regardless of endianness.
|
||||
* So (like gen_store_exclusive) we avoid gen_aa32_ld_i64()
|
||||
* so we don't get its SCTLR_B check, and instead do a 64-bit access
|
||||
* using MO_BE if appropriate, using a value constructed
|
||||
* by putting the two halves together in the right order.
|
||||
*
|
||||
* As with LDRD, the 64-bit atomicity is not required for
|
||||
* M-profile, or for A-profile before LPAE, and we provide
|
||||
* the higher guarantee always for simplicity.
|
||||
*/
|
||||
int mem_idx = get_mem_index(s);
|
||||
MemOp opc = MO_64 | MO_ALIGN_4 | MO_ATOM_SUBALIGN | s->be_data;
|
||||
TCGv taddr = gen_aa32_addr(s, addr, opc);
|
||||
TCGv_i32 t1 = load_reg(s, rt);
|
||||
TCGv_i32 t2 = load_reg(s, rt2);
|
||||
TCGv_i64 t64 = tcg_temp_new_i64();
|
||||
|
||||
if (s->be_data == MO_BE) {
|
||||
tcg_gen_concat_i32_i64(t64, t2, t1);
|
||||
} else {
|
||||
tcg_gen_concat_i32_i64(t64, t1, t2);
|
||||
}
|
||||
tcg_gen_qemu_st_i64(t64, taddr, mem_idx, opc);
|
||||
}
|
||||
|
||||
static bool trans_STRD_rr(DisasContext *s, arg_ldst_rr *a)
|
||||
{
|
||||
int mem_idx = get_mem_index(s);
|
||||
TCGv_i32 addr, tmp;
|
||||
TCGv_i32 addr;
|
||||
|
||||
if (!ENABLE_ARCH_5TE) {
|
||||
return false;
|
||||
@@ -5046,15 +5109,9 @@ static bool trans_STRD_rr(DisasContext *s, arg_ldst_rr *a)
|
||||
}
|
||||
addr = op_addr_rr_pre(s, a);
|
||||
|
||||
tmp = load_reg(s, a->rt);
|
||||
gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
|
||||
do_strd_store(s, addr, a->rt, a->rt + 1);
|
||||
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
|
||||
tmp = load_reg(s, a->rt + 1);
|
||||
gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
|
||||
|
||||
op_addr_rr_post(s, a, addr, -4);
|
||||
op_addr_rr_post(s, a, addr, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5152,23 +5209,14 @@ static bool op_store_ri(DisasContext *s, arg_ldst_ri *a,
|
||||
|
||||
static bool op_ldrd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
|
||||
{
|
||||
int mem_idx = get_mem_index(s);
|
||||
TCGv_i32 addr, tmp;
|
||||
TCGv_i32 addr;
|
||||
|
||||
addr = op_addr_ri_pre(s, a);
|
||||
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
|
||||
store_reg(s, a->rt, tmp);
|
||||
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
|
||||
store_reg(s, rt2, tmp);
|
||||
do_ldrd_load(s, addr, a->rt, rt2);
|
||||
|
||||
/* LDRD w/ base writeback is undefined if the registers overlap. */
|
||||
op_addr_ri_post(s, a, addr, -4);
|
||||
op_addr_ri_post(s, a, addr, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5191,20 +5239,13 @@ static bool trans_LDRD_ri_t32(DisasContext *s, arg_ldst_ri2 *a)
|
||||
|
||||
static bool op_strd_ri(DisasContext *s, arg_ldst_ri *a, int rt2)
|
||||
{
|
||||
int mem_idx = get_mem_index(s);
|
||||
TCGv_i32 addr, tmp;
|
||||
TCGv_i32 addr;
|
||||
|
||||
addr = op_addr_ri_pre(s, a);
|
||||
|
||||
tmp = load_reg(s, a->rt);
|
||||
gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
|
||||
do_strd_store(s, addr, a->rt, rt2);
|
||||
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
|
||||
tmp = load_reg(s, rt2);
|
||||
gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN);
|
||||
|
||||
op_addr_ri_post(s, a, addr, -4);
|
||||
op_addr_ri_post(s, a, addr, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,15 +91,19 @@ typedef struct DisasContext {
|
||||
bool aarch64;
|
||||
bool thumb;
|
||||
bool lse2;
|
||||
/* Because unallocated encodings generate different exception syndrome
|
||||
/*
|
||||
* Because unallocated encodings generate different exception syndrome
|
||||
* information from traps due to FP being disabled, we can't do a single
|
||||
* "is fp access disabled" check at a high level in the decode tree.
|
||||
* To help in catching bugs where the access check was forgotten in some
|
||||
* code path, we set this flag when the access check is done, and assert
|
||||
* that it is set at the point where we actually touch the FP regs.
|
||||
* 0: not checked,
|
||||
* 1: checked, access ok
|
||||
* -1: checked, access denied
|
||||
*/
|
||||
bool fp_access_checked;
|
||||
bool sve_access_checked;
|
||||
int8_t fp_access_checked;
|
||||
int8_t sve_access_checked;
|
||||
/* ARMv8 single-step state (this is distinct from the QEMU gdbstub
|
||||
* single-step support).
|
||||
*/
|
||||
|
||||
@@ -63,23 +63,24 @@ int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
{
|
||||
CPULoongArchState *env = cpu_env(cs);
|
||||
target_ulong tmp;
|
||||
int read_length;
|
||||
int length = 0;
|
||||
|
||||
if (n < 0 || n > 34) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_la64(env)) {
|
||||
tmp = ldq_le_p(mem_buf);
|
||||
read_length = 8;
|
||||
length = 8;
|
||||
} else {
|
||||
tmp = ldl_le_p(mem_buf);
|
||||
read_length = 4;
|
||||
length = 4;
|
||||
}
|
||||
|
||||
if (0 <= n && n < 32) {
|
||||
env->gpr[n] = tmp;
|
||||
length = read_length;
|
||||
} else if (n == 33) {
|
||||
set_pc(env, tmp);
|
||||
length = read_length;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
@@ -3480,7 +3480,7 @@ static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm)
|
||||
break;
|
||||
case 1:
|
||||
/* data: {2{16'0, imm[7:0], 8'0}} */
|
||||
data = (t << 24) | (t << 8);
|
||||
data = (t << 40) | (t << 8);
|
||||
break;
|
||||
case 2:
|
||||
/* data: {2{8'0, imm[7:0], 16'0}} */
|
||||
|
||||
@@ -2732,14 +2732,6 @@ static void init_proc_e200(CPUPPCState *env)
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000); /* TOFIX */
|
||||
spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_BOOKE_DSRR1, "DSRR1",
|
||||
SPR_NOACCESS, SPR_NOACCESS,
|
||||
&spr_read_generic, &spr_write_generic,
|
||||
0x00000000);
|
||||
|
||||
init_tlbs_emb(env);
|
||||
init_excp_e200(env, 0xFFFF0000UL);
|
||||
|
||||
@@ -994,8 +994,8 @@ static bool do_vector_rotl_quad(DisasContext *ctx, arg_VX *a, bool mask,
|
||||
{
|
||||
TCGv_i64 ah, al, vrb, n, t0, t1, zero = tcg_constant_i64(0);
|
||||
|
||||
REQUIRE_VECTOR(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA310);
|
||||
REQUIRE_VECTOR(ctx);
|
||||
|
||||
ah = tcg_temp_new_i64();
|
||||
al = tcg_temp_new_i64();
|
||||
|
||||
@@ -61,8 +61,8 @@ static bool trans_LXVD2X(DisasContext *ctx, arg_LXVD2X *a)
|
||||
TCGv EA;
|
||||
TCGv_i64 t0;
|
||||
|
||||
REQUIRE_VSX(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, VSX);
|
||||
REQUIRE_VSX(ctx);
|
||||
|
||||
t0 = tcg_temp_new_i64();
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
@@ -80,8 +80,8 @@ static bool trans_LXVW4X(DisasContext *ctx, arg_LXVW4X *a)
|
||||
TCGv EA;
|
||||
TCGv_i64 xth, xtl;
|
||||
|
||||
REQUIRE_VSX(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, VSX);
|
||||
REQUIRE_VSX(ctx);
|
||||
|
||||
xth = tcg_temp_new_i64();
|
||||
xtl = tcg_temp_new_i64();
|
||||
@@ -113,12 +113,12 @@ static bool trans_LXVWSX(DisasContext *ctx, arg_LXVWSX *a)
|
||||
TCGv EA;
|
||||
TCGv_i32 data;
|
||||
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
|
||||
if (a->rt < 32) {
|
||||
REQUIRE_VSX(ctx);
|
||||
} else {
|
||||
REQUIRE_VECTOR(ctx);
|
||||
}
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
|
||||
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
|
||||
@@ -133,8 +133,8 @@ static bool trans_LXVDSX(DisasContext *ctx, arg_LXVDSX *a)
|
||||
TCGv EA;
|
||||
TCGv_i64 data;
|
||||
|
||||
REQUIRE_VSX(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, VSX);
|
||||
REQUIRE_VSX(ctx);
|
||||
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
EA = do_ea_calc(ctx, a->ra, cpu_gpr[a->rb]);
|
||||
@@ -185,8 +185,8 @@ static bool trans_LXVH8X(DisasContext *ctx, arg_LXVH8X *a)
|
||||
TCGv EA;
|
||||
TCGv_i64 xth, xtl;
|
||||
|
||||
REQUIRE_VSX(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
|
||||
REQUIRE_VSX(ctx);
|
||||
|
||||
xth = tcg_temp_new_i64();
|
||||
xtl = tcg_temp_new_i64();
|
||||
@@ -208,8 +208,8 @@ static bool trans_LXVB16X(DisasContext *ctx, arg_LXVB16X *a)
|
||||
TCGv EA;
|
||||
TCGv_i128 data;
|
||||
|
||||
REQUIRE_VSX(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
|
||||
REQUIRE_VSX(ctx);
|
||||
|
||||
data = tcg_temp_new_i128();
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
@@ -312,8 +312,8 @@ static bool trans_STXVD2X(DisasContext *ctx, arg_STXVD2X *a)
|
||||
TCGv EA;
|
||||
TCGv_i64 t0;
|
||||
|
||||
REQUIRE_VSX(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, VSX);
|
||||
REQUIRE_VSX(ctx);
|
||||
|
||||
t0 = tcg_temp_new_i64();
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
@@ -331,8 +331,8 @@ static bool trans_STXVW4X(DisasContext *ctx, arg_STXVW4X *a)
|
||||
TCGv EA;
|
||||
TCGv_i64 xsh, xsl;
|
||||
|
||||
REQUIRE_VSX(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, VSX);
|
||||
REQUIRE_VSX(ctx);
|
||||
|
||||
xsh = tcg_temp_new_i64();
|
||||
xsl = tcg_temp_new_i64();
|
||||
@@ -364,8 +364,8 @@ static bool trans_STXVH8X(DisasContext *ctx, arg_STXVH8X *a)
|
||||
TCGv EA;
|
||||
TCGv_i64 xsh, xsl;
|
||||
|
||||
REQUIRE_VSX(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
|
||||
REQUIRE_VSX(ctx);
|
||||
|
||||
xsh = tcg_temp_new_i64();
|
||||
xsl = tcg_temp_new_i64();
|
||||
@@ -394,8 +394,8 @@ static bool trans_STXVB16X(DisasContext *ctx, arg_STXVB16X *a)
|
||||
TCGv EA;
|
||||
TCGv_i128 data;
|
||||
|
||||
REQUIRE_VSX(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
|
||||
REQUIRE_VSX(ctx);
|
||||
|
||||
data = tcg_temp_new_i128();
|
||||
gen_set_access_type(ctx, ACCESS_INT);
|
||||
|
||||
+3
-2
@@ -1897,6 +1897,7 @@ static void prop_vlen_set(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
RISCVCPU *cpu = RISCV_CPU(obj);
|
||||
uint16_t cpu_vlen = cpu->cfg.vlenb << 3;
|
||||
uint16_t value;
|
||||
|
||||
if (!visit_type_uint16(v, name, &value, errp)) {
|
||||
@@ -1908,10 +1909,10 @@ static void prop_vlen_set(Object *obj, Visitor *v, const char *name,
|
||||
return;
|
||||
}
|
||||
|
||||
if (value != cpu->cfg.vlenb && riscv_cpu_is_vendor(obj)) {
|
||||
if (value != cpu_vlen && riscv_cpu_is_vendor(obj)) {
|
||||
cpu_set_prop_err(cpu, name, errp);
|
||||
error_append_hint(errp, "Current '%s' val: %u\n",
|
||||
name, cpu->cfg.vlenb << 3);
|
||||
name, cpu_vlen);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "exec/page-protection.h"
|
||||
#include "instmap.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
#include "trace.h"
|
||||
#include "semihosting/common-semi.h"
|
||||
#include "sysemu/cpu-timers.h"
|
||||
@@ -1550,6 +1551,23 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
} else if (probe) {
|
||||
return false;
|
||||
} else {
|
||||
int wp_access = 0;
|
||||
|
||||
if (access_type == MMU_DATA_LOAD) {
|
||||
wp_access |= BP_MEM_READ;
|
||||
} else if (access_type == MMU_DATA_STORE) {
|
||||
wp_access |= BP_MEM_WRITE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a watchpoint isn't found for 'addr' this will
|
||||
* be a no-op and we'll resume the mmu_exception path.
|
||||
* Otherwise we'll throw a debug exception and execution
|
||||
* will continue elsewhere.
|
||||
*/
|
||||
cpu_check_watchpoint(cs, address, size, MEMTXATTRS_UNSPECIFIED,
|
||||
wp_access, retaddr);
|
||||
|
||||
raise_mmu_exception(env, address, access_type, pmp_violation,
|
||||
first_stage_error, two_stage_lookup,
|
||||
two_stage_indirect_error);
|
||||
|
||||
@@ -190,6 +190,11 @@ static RISCVException cfi_ss(CPURISCVState *env, int csrno)
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
|
||||
/* If ext implemented, M-mode always have access to SSP CSR */
|
||||
if (env->priv == PRV_M) {
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
/* if bcfi not active for current env, access to csr is illegal */
|
||||
if (!cpu_get_bcfien(env)) {
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
@@ -478,7 +478,7 @@ static void type2_breakpoint_insert(CPURISCVState *env, target_ulong index)
|
||||
bool enabled = type2_breakpoint_enabled(ctrl);
|
||||
CPUState *cs = env_cpu(env);
|
||||
int flags = BP_CPU | BP_STOP_BEFORE_ACCESS;
|
||||
uint32_t size;
|
||||
uint32_t size, def_size;
|
||||
|
||||
if (!enabled) {
|
||||
return;
|
||||
@@ -501,7 +501,9 @@ static void type2_breakpoint_insert(CPURISCVState *env, target_ulong index)
|
||||
cpu_watchpoint_insert(cs, addr, size, flags,
|
||||
&env->cpu_watchpoint[index]);
|
||||
} else {
|
||||
cpu_watchpoint_insert(cs, addr, 8, flags,
|
||||
def_size = riscv_cpu_mxl(env) == MXL_RV64 ? 8 : 4;
|
||||
|
||||
cpu_watchpoint_insert(cs, addr, def_size, flags,
|
||||
&env->cpu_watchpoint[index]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,13 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define REQUIRE_ZICFISS(ctx) do { \
|
||||
if (!ctx->cfg_ptr->ext_zicfiss) { \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static bool trans_sspopchk(DisasContext *ctx, arg_sspopchk *a)
|
||||
{
|
||||
if (!ctx->bcfi_enabled) {
|
||||
@@ -77,6 +84,11 @@ static bool trans_ssrdp(DisasContext *ctx, arg_ssrdp *a)
|
||||
static bool trans_ssamoswap_w(DisasContext *ctx, arg_amoswap_w *a)
|
||||
{
|
||||
REQUIRE_A_OR_ZAAMO(ctx);
|
||||
REQUIRE_ZICFISS(ctx);
|
||||
if (ctx->priv == PRV_M) {
|
||||
generate_exception(ctx, RISCV_EXCP_STORE_AMO_ACCESS_FAULT);
|
||||
}
|
||||
|
||||
if (!ctx->bcfi_enabled) {
|
||||
return false;
|
||||
}
|
||||
@@ -97,6 +109,11 @@ static bool trans_ssamoswap_d(DisasContext *ctx, arg_amoswap_w *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_A_OR_ZAAMO(ctx);
|
||||
REQUIRE_ZICFISS(ctx);
|
||||
if (ctx->priv == PRV_M) {
|
||||
generate_exception(ctx, RISCV_EXCP_STORE_AMO_ACCESS_FAULT);
|
||||
}
|
||||
|
||||
if (!ctx->bcfi_enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ static inline void xor_round_key(AESState *round_state, AESState *round_key)
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { \
|
||||
AESState round_key; \
|
||||
@@ -248,7 +248,7 @@ static inline void xor_round_key(AESState *round_state, AESState *round_key)
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4); \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { \
|
||||
AESState round_key; \
|
||||
@@ -309,7 +309,7 @@ void HELPER(vaeskf1_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm,
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl);
|
||||
|
||||
uimm &= 0b1111;
|
||||
if (uimm > 10 || uimm == 0) {
|
||||
@@ -357,7 +357,7 @@ void HELPER(vaeskf2_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm,
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl);
|
||||
|
||||
uimm &= 0b1111;
|
||||
if (uimm > 14 || uimm < 2) {
|
||||
@@ -465,7 +465,7 @@ void HELPER(vsha2ms_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
if (sew == MO_32) {
|
||||
@@ -582,7 +582,7 @@ void HELPER(vsha2ch32_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_32(((uint32_t *)vs2) + 4 * i, ((uint32_t *)vd) + 4 * i,
|
||||
@@ -602,7 +602,7 @@ void HELPER(vsha2ch64_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_64(((uint64_t *)vs2) + 4 * i, ((uint64_t *)vd) + 4 * i,
|
||||
@@ -622,7 +622,7 @@ void HELPER(vsha2cl32_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_32(((uint32_t *)vs2) + 4 * i, ((uint32_t *)vd) + 4 * i,
|
||||
@@ -642,7 +642,7 @@ void HELPER(vsha2cl64_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env,
|
||||
uint32_t total_elems;
|
||||
uint32_t vta = vext_vta(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
vsha2c_64(((uint64_t *)vs2) + 4 * i, ((uint64_t *)vd) + 4 * i,
|
||||
@@ -676,7 +676,7 @@ void HELPER(vsm3me_vv)(void *vd_vptr, void *vs1_vptr, void *vs2_vptr,
|
||||
uint32_t *vs1 = vs1_vptr;
|
||||
uint32_t *vs2 = vs2_vptr;
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (int i = env->vstart / 8; i < env->vl / 8; i++) {
|
||||
uint32_t w[24];
|
||||
@@ -777,7 +777,7 @@ void HELPER(vsm3c_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm,
|
||||
uint32_t *vs2 = vs2_vptr;
|
||||
uint32_t v1[8], v2[8], v3[8];
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (int i = env->vstart / 8; i < env->vl / 8; i++) {
|
||||
for (int k = 0; k < 8; k++) {
|
||||
@@ -802,7 +802,7 @@ void HELPER(vghsh_vv)(void *vd_vptr, void *vs1_vptr, void *vs2_vptr,
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
uint64_t Y[2] = {vd[i * 2 + 0], vd[i * 2 + 1]};
|
||||
@@ -841,7 +841,7 @@ void HELPER(vgmul_vv)(void *vd_vptr, void *vs2_vptr, CPURISCVState *env,
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, 4);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) {
|
||||
uint64_t Y[2] = {brev8(vd[i * 2 + 0]), brev8(vd[i * 2 + 1])};
|
||||
@@ -879,7 +879,7 @@ void HELPER(vsm4k_vi)(void *vd, void *vs2, uint32_t uimm5, CPURISCVState *env,
|
||||
uint32_t esz = sizeof(uint32_t);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (uint32_t i = group_start; i < group_end; ++i) {
|
||||
uint32_t vstart = i * egs;
|
||||
@@ -937,7 +937,7 @@ void HELPER(vsm4r_vv)(void *vd, void *vs2, CPURISCVState *env, uint32_t desc)
|
||||
uint32_t esz = sizeof(uint32_t);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (uint32_t i = group_start; i < group_end; ++i) {
|
||||
uint32_t vstart = i * egs;
|
||||
@@ -973,7 +973,7 @@ void HELPER(vsm4r_vs)(void *vd, void *vs2, CPURISCVState *env, uint32_t desc)
|
||||
uint32_t esz = sizeof(uint32_t);
|
||||
uint32_t total_elems = vext_get_total_elems(env, desc, esz);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (uint32_t i = group_start; i < group_end; ++i) {
|
||||
uint32_t vstart = i * egs;
|
||||
|
||||
@@ -265,7 +265,7 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base, target_ulong stride,
|
||||
uint32_t esz = 1 << log2_esz;
|
||||
uint32_t vma = vext_vma(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
for (i = env->vstart; i < env->vl; env->vstart = ++i) {
|
||||
k = 0;
|
||||
@@ -388,10 +388,7 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc,
|
||||
uint32_t msize = nf * esz;
|
||||
int mmu_index = riscv_env_mmu_index(env, false);
|
||||
|
||||
if (env->vstart >= evl) {
|
||||
env->vstart = 0;
|
||||
return;
|
||||
}
|
||||
VSTART_CHECK_EARLY_EXIT(env, evl);
|
||||
|
||||
/* Calculate the page range of first page */
|
||||
addr = base + ((env->vstart * nf) << log2_esz);
|
||||
@@ -533,7 +530,7 @@ vext_ldst_index(void *vd, void *v0, target_ulong base,
|
||||
uint32_t esz = 1 << log2_esz;
|
||||
uint32_t vma = vext_vma(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
/* load bytes from guest memory */
|
||||
for (i = env->vstart; i < env->vl; env->vstart = ++i) {
|
||||
@@ -625,7 +622,7 @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env,
|
||||
target_ulong addr, offset, remain, page_split, elems;
|
||||
int mmu_index = riscv_env_mmu_index(env, false);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, env->vl);
|
||||
|
||||
/* probe every access */
|
||||
for (i = env->vstart; i < env->vl; i++) {
|
||||
@@ -1092,7 +1089,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
@@ -1126,7 +1123,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
@@ -1163,7 +1160,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
@@ -1203,7 +1200,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
|
||||
uint32_t vta_all_1s = vext_vta_all_1s(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
@@ -1301,7 +1298,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -1350,7 +1347,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -1414,7 +1411,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
@@ -1481,7 +1478,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
@@ -2030,7 +2027,7 @@ void HELPER(NAME)(void *vd, void *vs1, CPURISCVState *env, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
@@ -2056,7 +2053,7 @@ void HELPER(NAME)(void *vd, uint64_t s1, CPURISCVState *env, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
*((ETYPE *)vd + H(i)) = (ETYPE)s1; \
|
||||
@@ -2081,7 +2078,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE *vt = (!vext_elem_mask(v0, i) ? vs2 : vs1); \
|
||||
@@ -2107,7 +2104,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
@@ -2154,8 +2151,6 @@ vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2,
|
||||
uint32_t vl, uint32_t vm, int vxrm,
|
||||
opivv2_rm_fn *fn, uint32_t vma, uint32_t esz)
|
||||
{
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
@@ -2179,6 +2174,8 @@ vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2,
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl);
|
||||
|
||||
switch (env->vxrm) {
|
||||
case 0: /* rnu */
|
||||
vext_vv_rm_1(vd, v0, vs1, vs2,
|
||||
@@ -2281,8 +2278,6 @@ vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2,
|
||||
uint32_t vl, uint32_t vm, int vxrm,
|
||||
opivx2_rm_fn *fn, uint32_t vma, uint32_t esz)
|
||||
{
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
|
||||
for (uint32_t i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
@@ -2306,6 +2301,8 @@ vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2,
|
||||
uint32_t vta = vext_vta(desc);
|
||||
uint32_t vma = vext_vma(desc);
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl);
|
||||
|
||||
switch (env->vxrm) {
|
||||
case 0: /* rnu */
|
||||
vext_vx_rm_1(vd, v0, s1, vs2,
|
||||
@@ -3080,7 +3077,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -3125,7 +3122,7 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -3713,7 +3710,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
if (vl == 0) { \
|
||||
return; \
|
||||
@@ -4236,7 +4233,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s1 = *((ETYPE *)vs1 + H(i)); \
|
||||
@@ -4278,7 +4275,7 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
@@ -4473,7 +4470,7 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
ETYPE s2 = *((ETYPE *)vs2 + H(i)); \
|
||||
@@ -4641,6 +4638,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
uint32_t i; \
|
||||
TD s1 = *((TD *)vs1 + HD(0)); \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
TS2 s2 = *((TS2 *)vs2 + HS2(i)); \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -4648,7 +4647,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
} \
|
||||
s1 = OP(s1, (TD)s2); \
|
||||
} \
|
||||
*((TD *)vd + HD(0)) = s1; \
|
||||
if (vl > 0) { \
|
||||
*((TD *)vd + HD(0)) = s1; \
|
||||
} \
|
||||
env->vstart = 0; \
|
||||
/* set tail elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vta, esz, vlenb); \
|
||||
@@ -4727,6 +4728,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
uint32_t i; \
|
||||
TD s1 = *((TD *)vs1 + HD(0)); \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
TS2 s2 = *((TS2 *)vs2 + HS2(i)); \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -4734,7 +4737,9 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
} \
|
||||
s1 = OP(s1, (TD)s2, &env->fp_status); \
|
||||
} \
|
||||
*((TD *)vd + HD(0)) = s1; \
|
||||
if (vl > 0) { \
|
||||
*((TD *)vd + HD(0)) = s1; \
|
||||
} \
|
||||
env->vstart = 0; \
|
||||
/* set tail elements to 1s */ \
|
||||
vext_set_elems_1s(vd, vta, esz, vlenb); \
|
||||
@@ -4799,7 +4804,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \
|
||||
uint32_t i; \
|
||||
int a, b; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
a = vext_elem_mask(vs1, i); \
|
||||
@@ -4889,6 +4894,8 @@ static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env,
|
||||
int i;
|
||||
bool first_mask_bit = false;
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl);
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
/* set masked-off elements to 1s */
|
||||
@@ -4961,6 +4968,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \
|
||||
uint32_t sum = 0; \
|
||||
int i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
/* set masked-off elements to 1s */ \
|
||||
@@ -4994,7 +5003,7 @@ void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
int i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -5031,7 +5040,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
target_ulong offset = s1, i_min, i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
i_min = MAX(env->vstart, offset); \
|
||||
for (i = i_min; i < vl; i++) { \
|
||||
@@ -5066,7 +5075,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
target_ulong i_max, i_min, i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
i_min = MIN(s1 < vlmax ? vlmax - s1 : 0, vl); \
|
||||
i_max = MAX(i_min, env->vstart); \
|
||||
@@ -5110,7 +5119,7 @@ static void vslide1up_##BITWIDTH(void *vd, void *v0, uint64_t s1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -5161,7 +5170,7 @@ static void vslide1down_##BITWIDTH(void *vd, void *v0, uint64_t s1, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -5238,7 +5247,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint64_t index; \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -5283,7 +5292,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \
|
||||
uint64_t index = s1; \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
@@ -5319,6 +5328,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \
|
||||
uint32_t vta = vext_vta(desc); \
|
||||
uint32_t num = 0, i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vext_elem_mask(vs1, i)) { \
|
||||
continue; \
|
||||
@@ -5379,7 +5390,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
|
||||
@@ -66,7 +66,7 @@ void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2,
|
||||
uint32_t vma = vext_vma(desc);
|
||||
uint32_t i;
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl);
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
@@ -92,7 +92,7 @@ void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2,
|
||||
uint32_t vma = vext_vma(desc);
|
||||
uint32_t i;
|
||||
|
||||
VSTART_CHECK_EARLY_EXIT(env);
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl);
|
||||
|
||||
for (i = env->vstart; i < vl; i++) {
|
||||
if (!vm && !vext_elem_mask(v0, i)) {
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
#include "tcg/tcg-gvec-desc.h"
|
||||
#include "internals.h"
|
||||
|
||||
#define VSTART_CHECK_EARLY_EXIT(env) do { \
|
||||
if (env->vstart >= env->vl) { \
|
||||
env->vstart = 0; \
|
||||
return; \
|
||||
} \
|
||||
#define VSTART_CHECK_EARLY_EXIT(env, vl) do { \
|
||||
if (env->vstart >= vl) { \
|
||||
env->vstart = 0; \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline uint32_t vext_nf(uint32_t desc)
|
||||
@@ -158,7 +158,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \
|
||||
uint32_t vma = vext_vma(desc); \
|
||||
uint32_t i; \
|
||||
\
|
||||
VSTART_CHECK_EARLY_EXIT(env); \
|
||||
VSTART_CHECK_EARLY_EXIT(env, vl); \
|
||||
\
|
||||
for (i = env->vstart; i < vl; i++) { \
|
||||
if (!vm && !vext_elem_mask(v0, i)) { \
|
||||
|
||||
+3
-1
@@ -279,9 +279,11 @@ void flush_idcache_range(uintptr_t rx, uintptr_t rw, size_t len)
|
||||
for (p = rw & -dcache_lsize; p < rw + len; p += dcache_lsize) {
|
||||
asm volatile("dc\tcvau, %0" : : "r" (p) : "memory");
|
||||
}
|
||||
asm volatile("dsb\tish" : : : "memory");
|
||||
}
|
||||
|
||||
/* DSB unconditionally to ensure any outstanding writes are committed. */
|
||||
asm volatile("dsb\tish" : : : "memory");
|
||||
|
||||
/*
|
||||
* If CTR_EL0.DIC is enabled, Instruction cache cleaning to the Point
|
||||
* of Unification is not required for instruction to data coherence.
|
||||
|
||||
@@ -409,10 +409,6 @@ static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
|
||||
|
||||
static void timerlist_rearm(QEMUTimerList *timer_list)
|
||||
{
|
||||
/* Interrupt execution to force deadline recalculation. */
|
||||
if (icount_enabled() && timer_list->clock->type == QEMU_CLOCK_VIRTUAL) {
|
||||
icount_start_warp_timer();
|
||||
}
|
||||
timerlist_notify(timer_list);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user