target-arm queue:

* docs: fix link in sbsa description
  * linux-user/aarch64: Enable hwcap for RND, BTI, and MTE
  * target/arm: Fix tlbbits calculation in tlbi_aa64_vae2is_write()
  * target/arm: Split neon and vfp translation to their own
    compilation units
  * target/arm: Make WFI a NOP for userspace emulators
  * hw/sd/omap_mmc: Use device_cold_reset() instead of
    device_legacy_reset()
  * include: More fixes for 'extern "C"' block use
  * hw/arm/imx25_pdk: Fix error message for invalid RAM size
  * hw/arm/mps2-tz: Implement AN524 memory remapping via machine property
  * hw/arm/xlnx: Fix PHY address for xilinx-zynq-a9
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmCZXs8ZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3iDKD/4+RmKuaIRgbeyLT6hyfSKi
 iWgYbfQsvc99awdKqIWMgmsJx5YQLoeleKkjkFMjqYH5ehRk4qtKp1/FXH3DsVYk
 D1NBheiL7wfsublDCugIFBRQEtOB0sHlLJtUdhvKCgjO0+8HNasehXhHppD/RhnW
 RNfFSTDvLyQNS8DyAOfIcsmwtcILgsfDQmkrQiHTYTVZi8Hlg8WbemgPAEjS0yCB
 ngVZCeZLIgNiq5Xtq/rK39v89QT1CnWjOOtZYDGKV/hmPm5ge/oofPA/O0dYSwPf
 8y0htonR0cM/qO4tv7vfEW9zqAu+6MYoJsH3JT221sCqX5gsAGBAjyUgPsamMcdc
 J+yMg0PFFOTIJ2GQUnE2mSDuwRvo4F0kWzrm0c3S7+jfRc7/FCOmpo8F0S3rs/IH
 SdhkMucDvCdjoLbXE5slr2Nz2HrWXKOsUaBnTxzzOF5lSu4MXix+Zpaj+7crBVIj
 NB6ooeTqaM6X1cE7bwwnTKdZT0rv01uj8IcU/H74UGCfLc+I/6fophMzUCwy7p4S
 6BrhnGzAfQrmPCk2JPlVR40Z2C8E6yAwX35OihZGhFEXBLvO9SbyAXY5yXlolxsV
 w/ryagSkPoU/O0ZIWwuu6sF3szvXXvPEtT5+6oM/wlxgUvIEHqZ0YrVNniIh1n/S
 y6FtY/BXwkjp1bwNeOcpqQ==
 =E7yJ
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210510-1' into staging

target-arm queue:
 * docs: fix link in sbsa description
 * linux-user/aarch64: Enable hwcap for RND, BTI, and MTE
 * target/arm: Fix tlbbits calculation in tlbi_aa64_vae2is_write()
 * target/arm: Split neon and vfp translation to their own
   compilation units
 * target/arm: Make WFI a NOP for userspace emulators
 * hw/sd/omap_mmc: Use device_cold_reset() instead of
   device_legacy_reset()
 * include: More fixes for 'extern "C"' block use
 * hw/arm/imx25_pdk: Fix error message for invalid RAM size
 * hw/arm/mps2-tz: Implement AN524 memory remapping via machine property
 * hw/arm/xlnx: Fix PHY address for xilinx-zynq-a9

# gpg: Signature made Mon 10 May 2021 17:26:55 BST
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20210510-1: (26 commits)
  hw/arm/xlnx: Fix PHY address for xilinx-zynq-a9
  hw/arm/mps2-tz: Implement AN524 memory remapping via machine property
  hw/misc/mps2-scc: Support using CFG0 bit 0 for remapping
  hw/misc/mps2-scc: Add "QEMU interface" comment
  hw/arm/imx25_pdk: Fix error message for invalid RAM size
  include/disas/dis-asm.h: Handle being included outside 'extern "C"'
  include/qemu/bswap.h: Handle being included outside extern "C" block
  osdep: Make os-win32.h and os-posix.h handle 'extern "C"' themselves
  hw/sd/omap_mmc: Use device_cold_reset() instead of device_legacy_reset()
  target/arm: Make WFI a NOP for userspace emulators
  target/arm: Make translate-neon.c.inc its own compilation unit
  target/arm: Make functions used by translate-neon global
  target/arm: Move NeonGenThreeOpEnvFn typedef to translate.h
  target/arm: Delete unused typedef
  target/arm: Move vfp_reg_ptr() to translate-neon.c.inc
  target/arm: Make translate-vfp.c.inc its own compilation unit
  target/arm: Make functions used by translate-vfp global
  target/arm: Move vfp_{load, store}_reg{32, 64} to translate-vfp.c.inc
  target/arm: Move gen_aa32 functions to translate-a32.h
  target/arm: Split m-nocp trans functions into their own file
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-05-10 17:28:11 +01:00
commit e58c7a3bba
27 changed files with 720 additions and 413 deletions

View File

@ -18,9 +18,7 @@
*/
#include "qemu/osdep.h"
extern "C" {
#include "disas/dis-asm.h"
}
#include "vixl/a64/disasm-a64.h"

View File

@ -28,9 +28,7 @@
*/
#include "qemu/osdep.h"
extern "C" {
#include "disas/dis-asm.h"
}
#include <cstring>
#include <stdexcept>

View File

@ -45,3 +45,13 @@ Differences between QEMU and real hardware:
flash, but only as simple ROM, so attempting to rewrite the flash
from the guest will fail
- QEMU does not model the USB controller in MPS3 boards
Machine-specific options
""""""""""""""""""""""""
The following machine-specific options are supported:
remap
Supported for ``mps3-an524`` only.
Set ``BRAM``/``QSPI`` to select the initial memory mapping. The
default is ``BRAM``.

View File

@ -4,7 +4,7 @@ Arm Server Base System Architecture Reference board (``sbsa-ref``)
While the `virt` board is a generic board platform that doesn't match
any real hardware the `sbsa-ref` board intends to look like real
hardware. The `Server Base System Architecture
<https://developer.arm.com/documentation/den0029/latest>` defines a
<https://developer.arm.com/documentation/den0029/latest>`_ defines a
minimum base line of hardware support and importantly how the firmware
reports that to any operating system. It is a static system that
reports a very minimal DT to the firmware for non-discoverable

View File

@ -65,7 +65,6 @@ static struct arm_boot_info imx25_pdk_binfo;
static void imx25_pdk_init(MachineState *machine)
{
MachineClass *mc = MACHINE_GET_CLASS(machine);
IMX25PDK *s = g_new0(IMX25PDK, 1);
unsigned int ram_size;
unsigned int alias_offset;
@ -77,8 +76,8 @@ static void imx25_pdk_init(MachineState *machine)
/* We need to initialize our memory */
if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) {
char *sz = size_to_str(mc->default_ram_size);
error_report("Invalid RAM size, should be %s", sz);
char *sz = size_to_str(FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE);
error_report("RAM size more than %s is not supported", sz);
g_free(sz);
exit(EXIT_FAILURE);
}

View File

@ -55,6 +55,7 @@
#include "hw/boards.h"
#include "exec/address-spaces.h"
#include "sysemu/sysemu.h"
#include "sysemu/reset.h"
#include "hw/misc/unimp.h"
#include "hw/char/cmsdk-apb-uart.h"
#include "hw/timer/cmsdk-apb-timer.h"
@ -72,6 +73,7 @@
#include "hw/core/split-irq.h"
#include "hw/qdev-clock.h"
#include "qom/object.h"
#include "hw/irq.h"
#define MPS2TZ_NUMIRQ_MAX 96
#define MPS2TZ_RAM_MAX 5
@ -153,6 +155,9 @@ struct MPS2TZMachineState {
SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ_MAX];
Clock *sysclk;
Clock *s32kclk;
bool remap;
qemu_irq remap_irq;
};
#define TYPE_MPS2TZ_MACHINE "mps2tz"
@ -228,6 +233,10 @@ static const RAMInfo an505_raminfo[] = { {
},
};
/*
* Note that the addresses and MPC numbering here should match up
* with those used in remap_memory(), which can swap the BRAM and QSPI.
*/
static const RAMInfo an524_raminfo[] = { {
.name = "bram",
.base = 0x00000000,
@ -457,6 +466,7 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC);
sccdev = DEVICE(scc);
qdev_prop_set_uint32(sccdev, "scc-cfg0", mms->remap ? 1 : 0);
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
@ -573,6 +583,52 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
}
static hwaddr boot_mem_base(MPS2TZMachineState *mms)
{
/*
* Return the canonical address of the block which will be mapped
* at address 0x0 (i.e. where the vector table is).
* This is usually 0, but if the AN524 alternate memory map is
* enabled it will be the base address of the QSPI block.
*/
return mms->remap ? 0x28000000 : 0;
}
static void remap_memory(MPS2TZMachineState *mms, int map)
{
/*
* Remap the memory for the AN524. 'map' is the value of
* SCC CFG_REG0 bit 0, i.e. 0 for the default map and 1
* for the "option 1" mapping where QSPI is at address 0.
*
* Effectively we need to swap around the "upstream" ends of
* MPC 0 and MPC 1.
*/
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
int i;
if (mmc->fpga_type != FPGA_AN524) {
return;
}
memory_region_transaction_begin();
for (i = 0; i < 2; i++) {
TZMPC *mpc = &mms->mpc[i];
MemoryRegion *upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1);
hwaddr addr = (i ^ map) ? 0x28000000 : 0;
memory_region_set_address(upstream, addr);
}
memory_region_transaction_commit();
}
static void remap_irq_fn(void *opaque, int n, int level)
{
MPS2TZMachineState *mms = opaque;
remap_memory(mms, level);
}
static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
const char *name, hwaddr size,
const int *irqs)
@ -711,7 +767,7 @@ static uint32_t boot_ram_size(MPS2TZMachineState *mms)
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
for (p = mmc->raminfo; p->name; p++) {
if (p->base == 0) {
if (p->base == boot_mem_base(mms)) {
return p->size;
}
}
@ -1095,6 +1151,16 @@ static void mps2tz_common_init(MachineState *machine)
create_non_mpc_ram(mms);
if (mmc->fpga_type == FPGA_AN524) {
/*
* Connect the line from the SCC so that we can remap when the
* guest updates that register.
*/
mms->remap_irq = qemu_allocate_irq(remap_irq_fn, mms, 0);
qdev_connect_gpio_out_named(DEVICE(&mms->scc), "remap", 0,
mms->remap_irq);
}
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
boot_ram_size(mms));
}
@ -1117,12 +1183,47 @@ static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address,
*iregion = region;
}
static char *mps2_get_remap(Object *obj, Error **errp)
{
MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj);
const char *val = mms->remap ? "QSPI" : "BRAM";
return g_strdup(val);
}
static void mps2_set_remap(Object *obj, const char *value, Error **errp)
{
MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj);
if (!strcmp(value, "BRAM")) {
mms->remap = false;
} else if (!strcmp(value, "QSPI")) {
mms->remap = true;
} else {
error_setg(errp, "Invalid remap value");
error_append_hint(errp, "Valid values are BRAM and QSPI.\n");
}
}
static void mps2_machine_reset(MachineState *machine)
{
MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
/*
* Set the initial memory mapping before triggering the reset of
* the rest of the system, so that the guest image loader and CPU
* reset see the correct mapping.
*/
remap_memory(mms, mms->remap);
qemu_devices_reset();
}
static void mps2tz_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc);
mc->init = mps2tz_common_init;
mc->reset = mps2_machine_reset;
iic->check = mps2_tz_idau_check;
}
@ -1225,6 +1326,11 @@ static void mps3tz_an524_class_init(ObjectClass *oc, void *data)
mmc->raminfo = an524_raminfo;
mmc->armsse_type = TYPE_SSE200;
mps2tz_set_default_ram_info(mmc);
object_class_property_add_str(oc, "remap", mps2_get_remap, mps2_set_remap);
object_class_property_set_description(oc, "remap",
"Set memory mapping. Valid values "
"are BRAM (default) and QSPI.");
}
static void mps3tz_an547_class_init(ObjectClass *oc, void *data)

View File

@ -118,7 +118,7 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
qdev_set_nic_properties(dev, nd);
}
object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
object_property_set_int(OBJECT(dev), "phy-addr", 7, &error_abort);
s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal);
sysbus_mmio_map(s, 0, base);

View File

@ -23,6 +23,7 @@
#include "qemu/bitops.h"
#include "trace.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
#include "hw/registerfields.h"
#include "hw/misc/mps2-scc.h"
@ -186,10 +187,13 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value,
switch (offset) {
case A_CFG0:
/*
* TODO on some boards bit 0 controls RAM remapping;
* on others bit 1 is CPU_WAIT.
* On some boards bit 0 controls board-specific remapping;
* we always reflect bit 0 in the 'remap' GPIO output line,
* and let the board wire it up or not as it chooses.
* TODO on some boards bit 1 is CPU_WAIT.
*/
s->cfg0 = value;
qemu_set_irq(s->remap, s->cfg0 & 1);
break;
case A_CFG1:
s->cfg1 = value;
@ -283,7 +287,7 @@ static void mps2_scc_reset(DeviceState *dev)
int i;
trace_mps2_scc_reset();
s->cfg0 = 0;
s->cfg0 = s->cfg0_reset;
s->cfg1 = 0;
s->cfg2 = 0;
s->cfg5 = 0;
@ -308,6 +312,7 @@ static void mps2_scc_init(Object *obj)
memory_region_init_io(&s->iomem, obj, &mps2_scc_ops, s, "mps2-scc", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
qdev_init_gpio_out_named(DEVICE(obj), &s->remap, "remap", 1);
}
static void mps2_scc_realize(DeviceState *dev, Error **errp)
@ -353,6 +358,8 @@ static Property mps2_scc_properties[] = {
DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0),
DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0),
DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0),
/* Reset value for CFG0 register */
DEFINE_PROP_UINT32("scc-cfg0", MPS2SCC, cfg0_reset, 0),
/*
* These are the initial settings for the source clocks on the board.
* In hardware they can be configured via a config file read by the

View File

@ -318,7 +318,7 @@ void omap_mmc_reset(struct omap_mmc_s *host)
* into any bus, and we must reset it manually. When omap_mmc is
* QOMified this must move into the QOM reset function.
*/
device_legacy_reset(DEVICE(host->card));
device_cold_reset(DEVICE(host->card));
}
static uint64_t omap_mmc_read(void *opaque, hwaddr offset,

View File

@ -9,6 +9,12 @@
#ifndef DISAS_DIS_ASM_H
#define DISAS_DIS_ASM_H
#include "qemu/bswap.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void *PTR;
typedef uint64_t bfd_vma;
typedef int64_t bfd_signed_vma;
@ -479,8 +485,6 @@ bool cap_disas_plugin(disassemble_info *info, uint64_t pc, size_t size);
/* from libbfd */
#include "qemu/bswap.h"
static inline bfd_vma bfd_getl64(const bfd_byte *addr)
{
return ldq_le_p(addr);
@ -508,4 +512,8 @@ static inline bfd_vma bfd_getb16(const bfd_byte *addr)
typedef bool bfd_boolean;
#ifdef __cplusplus
}
#endif
#endif /* DISAS_DIS_ASM_H */

View File

@ -9,6 +9,24 @@
* (at your option) any later version.
*/
/*
* This is a model of the Serial Communication Controller (SCC)
* block found in most MPS FPGA images.
*
* QEMU interface:
* + sysbus MMIO region 0: the register bank
* + QOM property "scc-cfg4": value of the read-only CFG4 register
* + QOM property "scc-aid": value of the read-only SCC_AID register
* + QOM property "scc-id": value of the read-only SCC_ID register
* + QOM property "scc-cfg0": reset value of the CFG0 register
* + QOM property array "oscclk": reset values of the OSCCLK registers
* (which are accessed via the SYS_CFG channel provided by this device)
* + named GPIO output "remap": this tracks the value of CFG0 register
* bit 0. Boards where this bit controls memory remapping should
* connect this GPIO line to a function performing that mapping.
* Boards where bit 0 has no special function should leave the GPIO
* output disconnected.
*/
#ifndef MPS2_SCC_H
#define MPS2_SCC_H
@ -43,6 +61,9 @@ struct MPS2SCC {
uint32_t num_oscclk;
uint32_t *oscclk;
uint32_t *oscclk_reset;
uint32_t cfg0_reset;
qemu_irq remap;
};
#endif

View File

@ -1,8 +1,6 @@
#ifndef BSWAP_H
#define BSWAP_H
#include "fpu/softfloat-types.h"
#ifdef CONFIG_MACHINE_BSWAP_H
# include <sys/endian.h>
# include <machine/bswap.h>
@ -12,7 +10,18 @@
# include <endian.h>
#elif defined(CONFIG_BYTESWAP_H)
# include <byteswap.h>
#define BSWAP_FROM_BYTESWAP
# else
#define BSWAP_FROM_FALLBACKS
#endif /* ! CONFIG_MACHINE_BSWAP_H */
#ifdef __cplusplus
extern "C" {
#endif
#include "fpu/softfloat-types.h"
#ifdef BSWAP_FROM_BYTESWAP
static inline uint16_t bswap16(uint16_t x)
{
return bswap_16(x);
@ -27,7 +36,9 @@ static inline uint64_t bswap64(uint64_t x)
{
return bswap_64(x);
}
# else
#endif
#ifdef BSWAP_FROM_FALLBACKS
static inline uint16_t bswap16(uint16_t x)
{
return (((x & 0x00ff) << 8) |
@ -53,7 +64,10 @@ static inline uint64_t bswap64(uint64_t x)
((x & 0x00ff000000000000ULL) >> 40) |
((x & 0xff00000000000000ULL) >> 56));
}
#endif /* ! CONFIG_MACHINE_BSWAP_H */
#endif
#undef BSWAP_FROM_BYTESWAP
#undef BSWAP_FROM_FALLBACKS
static inline void bswap16s(uint16_t *s)
{
@ -494,4 +508,8 @@ DO_STN_LDN_P(be)
#undef le_bswaps
#undef be_bswaps
#ifdef __cplusplus
}
#endif
#endif /* BSWAP_H */

View File

@ -131,10 +131,6 @@ QEMU_EXTERN_C int daemon(int, int);
*/
#include "glib-compat.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#include "sysemu/os-win32.h"
#endif
@ -143,6 +139,10 @@ extern "C" {
#include "sysemu/os-posix.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include "qemu/typedefs.h"
/*

View File

@ -38,6 +38,10 @@
#include <sys/sysmacros.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
void os_set_line_buffering(void);
void os_set_proc_name(const char *s);
void os_setup_signal_handling(void);
@ -92,4 +96,8 @@ static inline void qemu_funlockfile(FILE *f)
funlockfile(f);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -30,6 +30,10 @@
#include <windows.h>
#include <ws2tcpip.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_WIN64)
/* On w64, setjmp is implemented by _setjmp which needs a second parameter.
* If this parameter is NULL, longjump does no stack unwinding.
@ -194,4 +198,8 @@ ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags);
ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *addr, socklen_t *addrlen);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -586,6 +586,16 @@ enum {
ARM_HWCAP2_A64_SVESM4 = 1 << 6,
ARM_HWCAP2_A64_FLAGM2 = 1 << 7,
ARM_HWCAP2_A64_FRINT = 1 << 8,
ARM_HWCAP2_A64_SVEI8MM = 1 << 9,
ARM_HWCAP2_A64_SVEF32MM = 1 << 10,
ARM_HWCAP2_A64_SVEF64MM = 1 << 11,
ARM_HWCAP2_A64_SVEBF16 = 1 << 12,
ARM_HWCAP2_A64_I8MM = 1 << 13,
ARM_HWCAP2_A64_BF16 = 1 << 14,
ARM_HWCAP2_A64_DGH = 1 << 15,
ARM_HWCAP2_A64_RNG = 1 << 16,
ARM_HWCAP2_A64_BTI = 1 << 17,
ARM_HWCAP2_A64_MTE = 1 << 18,
};
#define ELF_HWCAP get_elf_hwcap()
@ -640,6 +650,9 @@ static uint32_t get_elf_hwcap2(void)
GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);
GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG);
GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI);
GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE);
return hwcaps;
}

View File

@ -4742,7 +4742,7 @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t pageaddr = sextract64(value << 12, 0, 56);
bool secure = arm_is_secure_below_el3(env);
int mask = secure ? ARMMMUIdxBit_SE2 : ARMMMUIdxBit_E2;
int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_E2 : ARMMMUIdx_SE2,
int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_SE2 : ARMMMUIdx_E2,
pageaddr);
tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);

View File

@ -1,11 +1,11 @@
gen = [
decodetree.process('sve.decode', extra_args: '--decode=disas_sve'),
decodetree.process('neon-shared.decode', extra_args: '--static-decode=disas_neon_shared'),
decodetree.process('neon-dp.decode', extra_args: '--static-decode=disas_neon_dp'),
decodetree.process('neon-ls.decode', extra_args: '--static-decode=disas_neon_ls'),
decodetree.process('vfp.decode', extra_args: '--static-decode=disas_vfp'),
decodetree.process('vfp-uncond.decode', extra_args: '--static-decode=disas_vfp_uncond'),
decodetree.process('m-nocp.decode', extra_args: '--static-decode=disas_m_nocp'),
decodetree.process('neon-shared.decode', extra_args: '--decode=disas_neon_shared'),
decodetree.process('neon-dp.decode', extra_args: '--decode=disas_neon_dp'),
decodetree.process('neon-ls.decode', extra_args: '--decode=disas_neon_ls'),
decodetree.process('vfp.decode', extra_args: '--decode=disas_vfp'),
decodetree.process('vfp-uncond.decode', extra_args: '--decode=disas_vfp_uncond'),
decodetree.process('m-nocp.decode', extra_args: '--decode=disas_m_nocp'),
decodetree.process('a32.decode', extra_args: '--static-decode=disas_a32'),
decodetree.process('a32-uncond.decode', extra_args: '--static-decode=disas_a32_uncond'),
decodetree.process('t32.decode', extra_args: '--static-decode=disas_t32'),
@ -26,6 +26,9 @@ arm_ss.add(files(
'op_helper.c',
'tlb_helper.c',
'translate.c',
'translate-m-nocp.c',
'translate-neon.c',
'translate-vfp.c',
'vec_helper.c',
'vfp_helper.c',
'cpu_tcg.c',

View File

@ -228,6 +228,7 @@ void HELPER(setend)(CPUARMState *env)
arm_rebuild_hflags(env);
}
#ifndef CONFIG_USER_ONLY
/* 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.
@ -282,9 +283,21 @@ static inline int check_wfx_trap(CPUARMState *env, bool is_wfe)
return 0;
}
#endif
void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
{
#ifdef CONFIG_USER_ONLY
/*
* WFI in the user-mode emulator is technically permitted but not
* something any real-world code would do. AArch64 Linux kernels
* trap it via SCTRL_EL1.nTWI and make it an (expensive) NOP;
* AArch32 kernels don't trap it so it will delay a bit.
* For QEMU, make it NOP here, because trying to raise EXCP_HLT
* would trigger an abort.
*/
return;
#else
CPUState *cs = env_cpu(env);
int target_el = check_wfx_trap(env, false);
@ -309,6 +322,7 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len)
cs->exception_index = EXCP_HLT;
cs->halted = 1;
cpu_loop_exit(cs);
#endif
}
void HELPER(wfe)(CPUARMState *env)

144
target/arm/translate-a32.h Normal file
View File

@ -0,0 +1,144 @@
/*
* AArch32 translation, common definitions.
*
* Copyright (c) 2021 Linaro, Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TARGET_ARM_TRANSLATE_A64_H
#define TARGET_ARM_TRANSLATE_A64_H
/* Prototypes for autogenerated disassembler functions */
bool disas_m_nocp(DisasContext *dc, uint32_t insn);
bool disas_vfp(DisasContext *s, uint32_t insn);
bool disas_vfp_uncond(DisasContext *s, uint32_t insn);
bool disas_neon_dp(DisasContext *s, uint32_t insn);
bool disas_neon_ls(DisasContext *s, uint32_t insn);
bool disas_neon_shared(DisasContext *s, uint32_t insn);
void load_reg_var(DisasContext *s, TCGv_i32 var, int reg);
void arm_gen_condlabel(DisasContext *s);
bool vfp_access_check(DisasContext *s);
void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop);
void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop);
void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop);
void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop);
TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs);
void gen_set_cpsr(TCGv_i32 var, uint32_t mask);
void gen_set_condexec(DisasContext *s);
void gen_set_pc_im(DisasContext *s, target_ulong val);
void gen_lookup_tb(DisasContext *s);
long vfp_reg_offset(bool dp, unsigned reg);
long neon_full_reg_offset(unsigned reg);
long neon_element_offset(int reg, int element, MemOp memop);
void gen_rev16(TCGv_i32 dest, TCGv_i32 var);
static inline TCGv_i32 load_cpu_offset(int offset)
{
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_ld_i32(tmp, cpu_env, offset);
return tmp;
}
#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name))
static inline void store_cpu_offset(TCGv_i32 var, int offset)
{
tcg_gen_st_i32(var, cpu_env, offset);
tcg_temp_free_i32(var);
}
#define store_cpu_field(var, name) \
store_cpu_offset(var, offsetof(CPUARMState, name))
/* Create a new temporary and set it to the value of a CPU register. */
static inline TCGv_i32 load_reg(DisasContext *s, int reg)
{
TCGv_i32 tmp = tcg_temp_new_i32();
load_reg_var(s, tmp, reg);
return tmp;
}
void store_reg(DisasContext *s, int reg, TCGv_i32 var);
void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val,
TCGv_i32 a32, int index, MemOp opc);
void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val,
TCGv_i32 a32, int index, MemOp opc);
void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index, MemOp opc);
void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index, MemOp opc);
void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
int index, MemOp opc);
void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
int index, MemOp opc);
void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
int index, MemOp opc);
void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
int index, MemOp opc);
#define DO_GEN_LD(SUFF, OPC) \
static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \
TCGv_i32 a32, int index) \
{ \
gen_aa32_ld_i32(s, val, a32, index, OPC); \
}
#define DO_GEN_ST(SUFF, OPC) \
static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \
TCGv_i32 a32, int index) \
{ \
gen_aa32_st_i32(s, val, a32, index, OPC); \
}
static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index)
{
gen_aa32_ld_i64(s, val, a32, index, MO_Q);
}
static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index)
{
gen_aa32_st_i64(s, val, a32, index, MO_Q);
}
DO_GEN_LD(8u, MO_UB)
DO_GEN_LD(16u, MO_UW)
DO_GEN_LD(32u, MO_UL)
DO_GEN_ST(8, MO_UB)
DO_GEN_ST(16, MO_UW)
DO_GEN_ST(32, MO_UL)
#undef DO_GEN_LD
#undef DO_GEN_ST
#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1
#else
#define IS_USER(s) (s->user)
#endif
/* Set NZCV flags from the high 4 bits of var. */
#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
/* Swap low and high halfwords. */
static inline void gen_swap_half(TCGv_i32 dest, TCGv_i32 var)
{
tcg_gen_rotri_i32(dest, var, 16);
}
#endif

View File

@ -359,14 +359,6 @@ static void gen_exception_internal_insn(DisasContext *s, uint64_t pc, int excp)
s->base.is_jmp = DISAS_NORETURN;
}
static void gen_exception_insn(DisasContext *s, uint64_t pc, int excp,
uint32_t syndrome, uint32_t target_el)
{
gen_a64_set_pc_im(pc);
gen_exception(excp, syndrome, target_el);
s->base.is_jmp = DISAS_NORETURN;
}
static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome)
{
TCGv_i32 tcg_syn;
@ -437,13 +429,6 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
}
}
void unallocated_encoding(DisasContext *s)
{
/* Unallocated and reserved encodings are uncategorized */
gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(),
default_exception_el(s));
}
static void init_tmp_a64_array(DisasContext *s)
{
#ifdef CONFIG_DEBUG_TCG

View File

@ -18,8 +18,6 @@
#ifndef TARGET_ARM_TRANSLATE_A64_H
#define TARGET_ARM_TRANSLATE_A64_H
void unallocated_encoding(DisasContext *s);
#define unsupported_encoding(s, insn) \
do { \
qemu_log_mask(LOG_UNIMP, \

View File

@ -0,0 +1,221 @@
/*
* ARM translation: M-profile NOCP special-case instructions
*
* Copyright (c) 2020 Linaro, Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "tcg/tcg-op.h"
#include "translate.h"
#include "translate-a32.h"
#include "decode-m-nocp.c.inc"
/*
* Decode VLLDM and VLSTM are nonstandard because:
* * if there is no FPU then these insns must NOP in
* Secure state and UNDEF in Nonsecure state
* * if there is an FPU then these insns do not have
* the usual behaviour that vfp_access_check() provides of
* being controlled by CPACR/NSACR enable bits or the
* lazy-stacking logic.
*/
static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
{
TCGv_i32 fptr;
if (!arm_dc_feature(s, ARM_FEATURE_M) ||
!arm_dc_feature(s, ARM_FEATURE_V8)) {
return false;
}
if (a->op) {
/*
* T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not
* to take the IMPDEF option to make memory accesses to the stack
* slots that correspond to the D16-D31 registers (discarding
* read data and writing UNKNOWN values), so for us the T2
* encoding behaves identically to the T1 encoding.
*/
if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
return false;
}
} else {
/*
* T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs.
* This is currently architecturally impossible, but we add the
* check to stay in line with the pseudocode. Note that we must
* emit code for the UNDEF so it takes precedence over the NOCP.
*/
if (dc_isar_feature(aa32_simd_r32, s)) {
unallocated_encoding(s);
return true;
}
}
/*
* If not secure, UNDEF. We must emit code for this
* rather than returning false so that this takes
* precedence over the m-nocp.decode NOCP fallback.
*/
if (!s->v8m_secure) {
unallocated_encoding(s);
return true;
}
/* If no fpu, NOP. */
if (!dc_isar_feature(aa32_vfp, s)) {
return true;
}
fptr = load_reg(s, a->rn);
if (a->l) {
gen_helper_v7m_vlldm(cpu_env, fptr);
} else {
gen_helper_v7m_vlstm(cpu_env, fptr);
}
tcg_temp_free_i32(fptr);
/* End the TB, because we have updated FP control bits */
s->base.is_jmp = DISAS_UPDATE_EXIT;
return true;
}
static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a)
{
int btmreg, topreg;
TCGv_i64 zero;
TCGv_i32 aspen, sfpa;
if (!dc_isar_feature(aa32_m_sec_state, s)) {
/* Before v8.1M, fall through in decode to NOCP check */
return false;
}
/* Explicitly UNDEF because this takes precedence over NOCP */
if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) {
unallocated_encoding(s);
return true;
}
if (!dc_isar_feature(aa32_vfp_simd, s)) {
/* NOP if we have neither FP nor MVE */
return true;
}
/*
* If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no
* active floating point context so we must NOP (without doing
* any lazy state preservation or the NOCP check).
*/
aspen = load_cpu_field(v7m.fpccr[M_REG_S]);
sfpa = load_cpu_field(v7m.control[M_REG_S]);
tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK);
tcg_gen_or_i32(sfpa, sfpa, aspen);
arm_gen_condlabel(s);
tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel);
if (s->fp_excp_el != 0) {
gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
syn_uncategorized(), s->fp_excp_el);
return true;
}
topreg = a->vd + a->imm - 1;
btmreg = a->vd;
/* Convert to Sreg numbers if the insn specified in Dregs */
if (a->size == 3) {
topreg = topreg * 2 + 1;
btmreg *= 2;
}
if (topreg > 63 || (topreg > 31 && !(topreg & 1))) {
/* UNPREDICTABLE: we choose to undef */
unallocated_encoding(s);
return true;
}
/* Silently ignore requests to clear D16-D31 if they don't exist */
if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) {
topreg = 31;
}
if (!vfp_access_check(s)) {
return true;
}
/* Zero the Sregs from btmreg to topreg inclusive. */
zero = tcg_const_i64(0);
if (btmreg & 1) {
write_neon_element64(zero, btmreg >> 1, 1, MO_32);
btmreg++;
}
for (; btmreg + 1 <= topreg; btmreg += 2) {
write_neon_element64(zero, btmreg >> 1, 0, MO_64);
}
if (btmreg == topreg) {
write_neon_element64(zero, btmreg >> 1, 0, MO_32);
btmreg++;
}
assert(btmreg == topreg + 1);
/* TODO: when MVE is implemented, zero VPR here */
return true;
}
static bool trans_NOCP(DisasContext *s, arg_nocp *a)
{
/*
* Handle M-profile early check for disabled coprocessor:
* all we need to do here is emit the NOCP exception if
* the coprocessor is disabled. Otherwise we return false
* and the real VFP/etc decode will handle the insn.
*/
assert(arm_dc_feature(s, ARM_FEATURE_M));
if (a->cp == 11) {
a->cp = 10;
}
if (arm_dc_feature(s, ARM_FEATURE_V8_1M) &&
(a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) {
/* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
a->cp = 10;
}
if (a->cp != 10) {
gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
syn_uncategorized(), default_exception_el(s));
return true;
}
if (s->fp_excp_el != 0) {
gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
syn_uncategorized(), s->fp_excp_el);
return true;
}
return false;
}
static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a)
{
/* This range needs a coprocessor check for v8.1M and later only */
if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
return false;
}
return trans_NOCP(s, a);
}

View File

@ -20,11 +20,13 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is intended to be included from translate.c; it uses
* some macros and definitions provided by that file.
* It might be possible to convert it to a standalone .c file eventually.
*/
#include "qemu/osdep.h"
#include "tcg/tcg-op.h"
#include "tcg/tcg-op-gvec.h"
#include "exec/exec-all.h"
#include "exec/gen-icount.h"
#include "translate.h"
#include "translate-a32.h"
static inline int plus1(DisasContext *s, int x)
{
@ -60,6 +62,13 @@ static inline int neon_3same_fp_size(DisasContext *s, int x)
#include "decode-neon-ls.c.inc"
#include "decode-neon-shared.c.inc"
static TCGv_ptr vfp_reg_ptr(bool dp, int reg)
{
TCGv_ptr ret = tcg_temp_new_ptr();
tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg));
return ret;
}
static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop)
{
long offset = neon_element_offset(reg, ele, mop & MO_SIZE);

View File

@ -20,16 +20,38 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* This file is intended to be included from translate.c; it uses
* some macros and definitions provided by that file.
* It might be possible to convert it to a standalone .c file eventually.
*/
#include "qemu/osdep.h"
#include "tcg/tcg-op.h"
#include "tcg/tcg-op-gvec.h"
#include "exec/exec-all.h"
#include "exec/gen-icount.h"
#include "translate.h"
#include "translate-a32.h"
/* Include the generated VFP decoder */
#include "decode-vfp.c.inc"
#include "decode-vfp-uncond.c.inc"
static inline void vfp_load_reg64(TCGv_i64 var, int reg)
{
tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(true, reg));
}
static inline void vfp_store_reg64(TCGv_i64 var, int reg)
{
tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(true, reg));
}
static inline void vfp_load_reg32(TCGv_i32 var, int reg)
{
tcg_gen_ld_i32(var, cpu_env, vfp_reg_offset(false, reg));
}
static inline void vfp_store_reg32(TCGv_i32 var, int reg)
{
tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg));
}
/*
* The imm8 encodes the sign bit, enough bits to represent an exponent in
* the range 01....1xx to 10....0xx, and the most significant 4 bits of
@ -191,7 +213,7 @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled)
* The most usual kind of VFP access check, for everything except
* FMXR/FMRX to the always-available special registers.
*/
static bool vfp_access_check(DisasContext *s)
bool vfp_access_check(DisasContext *s)
{
return full_vfp_access_check(s, false);
}
@ -3800,202 +3822,6 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
return true;
}
/*
* Decode VLLDM and VLSTM are nonstandard because:
* * if there is no FPU then these insns must NOP in
* Secure state and UNDEF in Nonsecure state
* * if there is an FPU then these insns do not have
* the usual behaviour that vfp_access_check() provides of
* being controlled by CPACR/NSACR enable bits or the
* lazy-stacking logic.
*/
static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
{
TCGv_i32 fptr;
if (!arm_dc_feature(s, ARM_FEATURE_M) ||
!arm_dc_feature(s, ARM_FEATURE_V8)) {
return false;
}
if (a->op) {
/*
* T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not
* to take the IMPDEF option to make memory accesses to the stack
* slots that correspond to the D16-D31 registers (discarding
* read data and writing UNKNOWN values), so for us the T2
* encoding behaves identically to the T1 encoding.
*/
if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
return false;
}
} else {
/*
* T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs.
* This is currently architecturally impossible, but we add the
* check to stay in line with the pseudocode. Note that we must
* emit code for the UNDEF so it takes precedence over the NOCP.
*/
if (dc_isar_feature(aa32_simd_r32, s)) {
unallocated_encoding(s);
return true;
}
}
/*
* If not secure, UNDEF. We must emit code for this
* rather than returning false so that this takes
* precedence over the m-nocp.decode NOCP fallback.
*/
if (!s->v8m_secure) {
unallocated_encoding(s);
return true;
}
/* If no fpu, NOP. */
if (!dc_isar_feature(aa32_vfp, s)) {
return true;
}
fptr = load_reg(s, a->rn);
if (a->l) {
gen_helper_v7m_vlldm(cpu_env, fptr);
} else {
gen_helper_v7m_vlstm(cpu_env, fptr);
}
tcg_temp_free_i32(fptr);
/* End the TB, because we have updated FP control bits */
s->base.is_jmp = DISAS_UPDATE_EXIT;
return true;
}
static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a)
{
int btmreg, topreg;
TCGv_i64 zero;
TCGv_i32 aspen, sfpa;
if (!dc_isar_feature(aa32_m_sec_state, s)) {
/* Before v8.1M, fall through in decode to NOCP check */
return false;
}
/* Explicitly UNDEF because this takes precedence over NOCP */
if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) {
unallocated_encoding(s);
return true;
}
if (!dc_isar_feature(aa32_vfp_simd, s)) {
/* NOP if we have neither FP nor MVE */
return true;
}
/*
* If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no
* active floating point context so we must NOP (without doing
* any lazy state preservation or the NOCP check).
*/
aspen = load_cpu_field(v7m.fpccr[M_REG_S]);
sfpa = load_cpu_field(v7m.control[M_REG_S]);
tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK);
tcg_gen_or_i32(sfpa, sfpa, aspen);
arm_gen_condlabel(s);
tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel);
if (s->fp_excp_el != 0) {
gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
syn_uncategorized(), s->fp_excp_el);
return true;
}
topreg = a->vd + a->imm - 1;
btmreg = a->vd;
/* Convert to Sreg numbers if the insn specified in Dregs */
if (a->size == 3) {
topreg = topreg * 2 + 1;
btmreg *= 2;
}
if (topreg > 63 || (topreg > 31 && !(topreg & 1))) {
/* UNPREDICTABLE: we choose to undef */
unallocated_encoding(s);
return true;
}
/* Silently ignore requests to clear D16-D31 if they don't exist */
if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) {
topreg = 31;
}
if (!vfp_access_check(s)) {
return true;
}
/* Zero the Sregs from btmreg to topreg inclusive. */
zero = tcg_const_i64(0);
if (btmreg & 1) {
write_neon_element64(zero, btmreg >> 1, 1, MO_32);
btmreg++;
}
for (; btmreg + 1 <= topreg; btmreg += 2) {
write_neon_element64(zero, btmreg >> 1, 0, MO_64);
}
if (btmreg == topreg) {
write_neon_element64(zero, btmreg >> 1, 0, MO_32);
btmreg++;
}
assert(btmreg == topreg + 1);
/* TODO: when MVE is implemented, zero VPR here */
return true;
}
static bool trans_NOCP(DisasContext *s, arg_nocp *a)
{
/*
* Handle M-profile early check for disabled coprocessor:
* all we need to do here is emit the NOCP exception if
* the coprocessor is disabled. Otherwise we return false
* and the real VFP/etc decode will handle the insn.
*/
assert(arm_dc_feature(s, ARM_FEATURE_M));
if (a->cp == 11) {
a->cp = 10;
}
if (arm_dc_feature(s, ARM_FEATURE_V8_1M) &&
(a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) {
/* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
a->cp = 10;
}
if (a->cp != 10) {
gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
syn_uncategorized(), default_exception_el(s));
return true;
}
if (s->fp_excp_el != 0) {
gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
syn_uncategorized(), s->fp_excp_el);
return true;
}
return false;
}
static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a)
{
/* This range needs a coprocessor check for v8.1M and later only */
if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) {
return false;
}
return trans_NOCP(s, a);
}
static bool trans_VINS(DisasContext *s, arg_VINS *a)
{
TCGv_i32 rd, rm;

View File

@ -50,12 +50,7 @@
#define ENABLE_ARCH_8 arm_dc_feature(s, ARM_FEATURE_V8)
#include "translate.h"
#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1
#else
#define IS_USER(s) (s->user)
#endif
#include "translate-a32.h"
/* These are TCG temporaries used only by the legacy iwMMXt decoder */
static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
@ -71,11 +66,6 @@ static const char * const regnames[] =
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" };
/* Function prototypes for gen_ functions calling Neon helpers. */
typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32,
TCGv_i32, TCGv_i32);
/* Function prototypes for gen_ functions for fix point conversions */
typedef void VFPGenFixPointFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
/* initialize TCG globals. */
void arm_translate_init(void)
@ -101,7 +91,7 @@ void arm_translate_init(void)
}
/* Generate a label used for skipping this instruction */
static void arm_gen_condlabel(DisasContext *s)
void arm_gen_condlabel(DisasContext *s)
{
if (!s->condjmp) {
s->condlabel = gen_new_label();
@ -109,30 +99,6 @@ static void arm_gen_condlabel(DisasContext *s)
}
}
/*
* Constant expanders for the decoders.
*/
static int negate(DisasContext *s, int x)
{
return -x;
}
static int plus_2(DisasContext *s, int x)
{
return x + 2;
}
static int times_2(DisasContext *s, int x)
{
return x * 2;
}
static int times_4(DisasContext *s, int x)
{
return x * 4;
}
/* Flags for the disas_set_da_iss info argument:
* lower bits hold the Rt register number, higher bits are flags.
*/
@ -211,24 +177,6 @@ static inline int get_a32_user_mem_index(DisasContext *s)
}
}
static inline TCGv_i32 load_cpu_offset(int offset)
{
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_ld_i32(tmp, cpu_env, offset);
return tmp;
}
#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name))
static inline void store_cpu_offset(TCGv_i32 var, int offset)
{
tcg_gen_st_i32(var, cpu_env, offset);
tcg_temp_free_i32(var);
}
#define store_cpu_field(var, name) \
store_cpu_offset(var, offsetof(CPUARMState, name))
/* The architectural value of PC. */
static uint32_t read_pc(DisasContext *s)
{
@ -236,7 +184,7 @@ static uint32_t read_pc(DisasContext *s)
}
/* Set a variable to the value of a CPU register. */
static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
{
if (reg == 15) {
tcg_gen_movi_i32(var, read_pc(s));
@ -245,20 +193,12 @@ static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
}
}
/* Create a new temporary and set it to the value of a CPU register. */
static inline TCGv_i32 load_reg(DisasContext *s, int reg)
{
TCGv_i32 tmp = tcg_temp_new_i32();
load_reg_var(s, tmp, reg);
return tmp;
}
/*
* Create a new temp, REG + OFS, except PC is ALIGN(PC, 4).
* This is used for load/store for which use of PC implies (literal),
* or ADD that implies ADR.
*/
static TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
{
TCGv_i32 tmp = tcg_temp_new_i32();
@ -272,7 +212,7 @@ static TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs)
/* Set a CPU register. The source must be a temporary and will be
marked as dead. */
static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
void store_reg(DisasContext *s, int reg, TCGv_i32 var)
{
if (reg == 15) {
/* In Thumb mode, we must ignore bit 0.
@ -313,15 +253,12 @@ static void store_sp_checked(DisasContext *s, TCGv_i32 var)
#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
{
TCGv_i32 tmp_mask = tcg_const_i32(mask);
gen_helper_cpsr_write(cpu_env, var, tmp_mask);
tcg_temp_free_i32(tmp_mask);
}
/* Set NZCV flags from the high 4 bits of var. */
#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
static void gen_exception_internal(int excp)
{
@ -388,7 +325,7 @@ static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
}
/* Byteswap each halfword. */
static void gen_rev16(TCGv_i32 dest, TCGv_i32 var)
void gen_rev16(TCGv_i32 dest, TCGv_i32 var)
{
TCGv_i32 tmp = tcg_temp_new_i32();
TCGv_i32 mask = tcg_const_i32(0x00ff00ff);
@ -409,12 +346,6 @@ static void gen_revsh(TCGv_i32 dest, TCGv_i32 var)
tcg_gen_ext16s_i32(dest, var);
}
/* Swap low and high halfwords. */
static void gen_swap_half(TCGv_i32 dest, TCGv_i32 var)
{
tcg_gen_rotri_i32(dest, var, 16);
}
/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead.
tmp = (t0 ^ t1) & 0x8000;
t0 &= ~0x8000;
@ -746,7 +677,7 @@ void arm_gen_test_cc(int cc, TCGLabel *label)
arm_free_cc(&cmp);
}
static inline void gen_set_condexec(DisasContext *s)
void gen_set_condexec(DisasContext *s)
{
if (s->condexec_mask) {
uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
@ -756,7 +687,7 @@ static inline void gen_set_condexec(DisasContext *s)
}
}
static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
void gen_set_pc_im(DisasContext *s, target_ulong val)
{
tcg_gen_movi_i32(cpu_R[15], val);
}
@ -948,24 +879,24 @@ static TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op)
* Internal routines are used for NEON cases where the endianness
* and/or alignment has already been taken into account and manipulated.
*/
static void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val,
TCGv_i32 a32, int index, MemOp opc)
void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val,
TCGv_i32 a32, int index, MemOp opc)
{
TCGv addr = gen_aa32_addr(s, a32, opc);
tcg_gen_qemu_ld_i32(val, addr, index, opc);
tcg_temp_free(addr);
}
static void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val,
TCGv_i32 a32, int index, MemOp opc)
void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val,
TCGv_i32 a32, int index, MemOp opc)
{
TCGv addr = gen_aa32_addr(s, a32, opc);
tcg_gen_qemu_st_i32(val, addr, index, opc);
tcg_temp_free(addr);
}
static void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index, MemOp opc)
void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index, MemOp opc)
{
TCGv addr = gen_aa32_addr(s, a32, opc);
@ -978,8 +909,8 @@ static void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val,
tcg_temp_free(addr);
}
static void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index, MemOp opc)
void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index, MemOp opc)
{
TCGv addr = gen_aa32_addr(s, a32, opc);
@ -995,26 +926,26 @@ static void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val,
tcg_temp_free(addr);
}
static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
int index, MemOp opc)
void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
int index, MemOp opc)
{
gen_aa32_ld_internal_i32(s, val, a32, index, finalize_memop(s, opc));
}
static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
int index, MemOp opc)
void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
int index, MemOp opc)
{
gen_aa32_st_internal_i32(s, val, a32, index, finalize_memop(s, opc));
}
static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
int index, MemOp opc)
void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
int index, MemOp opc)
{
gen_aa32_ld_internal_i64(s, val, a32, index, finalize_memop(s, opc));
}
static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
int index, MemOp opc)
void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
int index, MemOp opc)
{
gen_aa32_st_internal_i64(s, val, a32, index, finalize_memop(s, opc));
}
@ -1033,25 +964,6 @@ static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
gen_aa32_st_i32(s, val, a32, index, OPC); \
}
static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index)
{
gen_aa32_ld_i64(s, val, a32, index, MO_Q);
}
static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val,
TCGv_i32 a32, int index)
{
gen_aa32_st_i64(s, val, a32, index, MO_Q);
}
DO_GEN_LD(8u, MO_UB)
DO_GEN_LD(16u, MO_UW)
DO_GEN_LD(32u, MO_UL)
DO_GEN_ST(8, MO_UB)
DO_GEN_ST(16, MO_UW)
DO_GEN_ST(32, MO_UL)
static inline void gen_hvc(DisasContext *s, int imm16)
{
/* The pre HVC helper handles cases when HVC gets trapped
@ -1093,11 +1005,15 @@ static void gen_exception_internal_insn(DisasContext *s, uint32_t pc, int excp)
s->base.is_jmp = DISAS_NORETURN;
}
static void gen_exception_insn(DisasContext *s, uint32_t pc, int excp,
int syn, uint32_t target_el)
void gen_exception_insn(DisasContext *s, uint64_t pc, int excp,
uint32_t syn, uint32_t target_el)
{
gen_set_condexec(s);
gen_set_pc_im(s, pc);
if (s->aarch64) {
gen_a64_set_pc_im(pc);
} else {
gen_set_condexec(s);
gen_set_pc_im(s, pc);
}
gen_exception(excp, syn, target_el);
s->base.is_jmp = DISAS_NORETURN;
}
@ -1114,7 +1030,7 @@ static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn)
s->base.is_jmp = DISAS_NORETURN;
}
static void unallocated_encoding(DisasContext *s)
void unallocated_encoding(DisasContext *s)
{
/* Unallocated and reserved encodings are uncategorized */
gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(),
@ -1138,7 +1054,7 @@ static void gen_exception_el(DisasContext *s, int excp, uint32_t syn,
}
/* Force a TB lookup after an instruction that changes the CPU state. */
static inline void gen_lookup_tb(DisasContext *s)
void gen_lookup_tb(DisasContext *s)
{
tcg_gen_movi_i32(cpu_R[15], s->base.pc_next);
s->base.is_jmp = DISAS_EXIT;
@ -1173,7 +1089,7 @@ static inline void gen_hlt(DisasContext *s, int imm)
/*
* Return the offset of a "full" NEON Dreg.
*/
static long neon_full_reg_offset(unsigned reg)
long neon_full_reg_offset(unsigned reg)
{
return offsetof(CPUARMState, vfp.zregs[reg >> 1].d[reg & 1]);
}
@ -1182,7 +1098,7 @@ static long neon_full_reg_offset(unsigned reg)
* Return the offset of a 2**SIZE piece of a NEON register, at index ELE,
* where 0 is the least significant end of the register.
*/
static long neon_element_offset(int reg, int element, MemOp memop)
long neon_element_offset(int reg, int element, MemOp memop)
{
int element_size = 1 << (memop & MO_SIZE);
int ofs = element * element_size;
@ -1199,7 +1115,7 @@ static long neon_element_offset(int reg, int element, MemOp memop)
}
/* Return the offset of a VFP Dreg (dp = true) or VFP Sreg (dp = false). */
static long vfp_reg_offset(bool dp, unsigned reg)
long vfp_reg_offset(bool dp, unsigned reg)
{
if (dp) {
return neon_element_offset(reg, 0, MO_64);
@ -1208,27 +1124,7 @@ static long vfp_reg_offset(bool dp, unsigned reg)
}
}
static inline void vfp_load_reg64(TCGv_i64 var, int reg)
{
tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(true, reg));
}
static inline void vfp_store_reg64(TCGv_i64 var, int reg)
{
tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(true, reg));
}
static inline void vfp_load_reg32(TCGv_i32 var, int reg)
{
tcg_gen_ld_i32(var, cpu_env, vfp_reg_offset(false, reg));
}
static inline void vfp_store_reg32(TCGv_i32 var, int reg)
{
tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg));
}
static void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop)
void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop)
{
long off = neon_element_offset(reg, ele, memop);
@ -1254,7 +1150,7 @@ static void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop)
}
}
static void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop)
void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop)
{
long off = neon_element_offset(reg, ele, memop);
@ -1273,7 +1169,7 @@ static void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop)
}
}
static void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop)
void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop)
{
long off = neon_element_offset(reg, ele, memop);
@ -1292,7 +1188,7 @@ static void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop)
}
}
static void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop)
void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop)
{
long off = neon_element_offset(reg, ele, memop);
@ -1308,20 +1204,8 @@ static void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop)
}
}
static TCGv_ptr vfp_reg_ptr(bool dp, int reg)
{
TCGv_ptr ret = tcg_temp_new_ptr();
tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg));
return ret;
}
#define ARM_CP_RW_BIT (1 << 20)
/* Include the VFP and Neon decoders */
#include "decode-m-nocp.c.inc"
#include "translate-vfp.c.inc"
#include "translate-neon.c.inc"
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
{
tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));

View File

@ -118,6 +118,30 @@ extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
extern TCGv_i64 cpu_exclusive_addr;
extern TCGv_i64 cpu_exclusive_val;
/*
* Constant expanders for the decoders.
*/
static inline int negate(DisasContext *s, int x)
{
return -x;
}
static inline int plus_2(DisasContext *s, int x)
{
return x + 2;
}
static inline int times_2(DisasContext *s, int x)
{
return x * 2;
}
static inline int times_4(DisasContext *s, int x)
{
return x * 4;
}
static inline int arm_dc_feature(DisasContext *dc, int feature)
{
return (dc->features & (1ULL << feature)) != 0;
@ -205,6 +229,9 @@ void arm_free_cc(DisasCompare *cmp);
void arm_jump_cc(DisasCompare *cmp, TCGLabel *label);
void arm_gen_test_cc(int cc, TCGLabel *label);
MemOp pow2_align(unsigned i);
void unallocated_encoding(DisasContext *s);
void gen_exception_insn(DisasContext *s, uint64_t pc, int excp,
uint32_t syn, uint32_t target_el);
/* Return state of Alternate Half-precision flag, caller frees result */
static inline TCGv_i32 get_ahp_flag(void)
@ -382,6 +409,8 @@ typedef void NeonGenOneOpFn(TCGv_i32, TCGv_i32);
typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32);
typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32);
typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32);
typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32,
TCGv_i32, TCGv_i32);
typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64);
typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64);
typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64);