mirror of https://github.com/xemu-project/xemu.git
target-arm queue:
* Widen cnthctl_el2 to uint64_t * Unify checking for M Main Extension in MRS/MSR * bitbang_i2c, versatile_i2c: code cleanups * SME: refactor SME SM/ZA handling * Fix physical address resolution for MTE * Fix in_debug path in S1_ptw_translate * Don't set EXC_RETURN.ES if Security Extension not present * Implement DBGCLAIM registers * Provide stubs for more external debug registers * Look up ARMCPRegInfo at runtime, not translate time -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmPOjQQZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3vreD/sGr7outToY4FSZ4GGpC1L6 ZwF6kjmwED/8EVaGZxWOaL2/oNoEav2YSpzUbqCa79jUx5zFBE145zYknL/bZyjS VLX9G2vFFCtwFQ9rc2wV/3JmTmMmSCnHqOZPMSVy5vrQKH6d41WFYZEvGpJmCgh6 YWK4gnMqkuIHmSvxw+S6q9p/3jzPk7c3vy8eRcxp+AMnfSBkYu0kFXmr7yOwscRS adT8GFrkj0our/HtYqvzclVzrxcCVF1pWrtrHK7ZSddmElIcztel+1/yQH3T6onj aOyRj1WC3+0t9uKwUNTFSHkRUqMqr6XYvRF+cvpe5N7lbfVn57u2TwmPgUwYbZcg 8Mbz+LRYENzTYZa59ACxJXXcG0BivXiTwyrFR8Ck0vakcWFAjDzxHOw9CgHkDwPs Dd93b04esehIN7MY8/5CSkbx+8ey+YK+o7sofiDCMKcYwooM1Y+Ls21ZcjA5GH+n SsXp93SgagndCydD0ftRUlDTtGL7dhzaGpRmYArjeWzOKBbAmv/WfQeH47p3bpaP CB2RUjHzYobMGLO0yp9droOaVKqKKLtc7wGzxgJGx6j5FrN0lnCEMRrKrZJ57Q/q z4VoRoo0I6Q994/mVanGqXx8cSucyl0Z3HbC633WvrnZXzoM7+7HlQLhpF+yd9+s 4lHiw0rPgqXtwEfeMaESSQ== =ubIU -----END PGP SIGNATURE----- Merge tag 'pull-target-arm-20230123' of https://git.linaro.org/people/pmaydell/qemu-arm into staging target-arm queue: * Widen cnthctl_el2 to uint64_t * Unify checking for M Main Extension in MRS/MSR * bitbang_i2c, versatile_i2c: code cleanups * SME: refactor SME SM/ZA handling * Fix physical address resolution for MTE * Fix in_debug path in S1_ptw_translate * Don't set EXC_RETURN.ES if Security Extension not present * Implement DBGCLAIM registers * Provide stubs for more external debug registers * Look up ARMCPRegInfo at runtime, not translate time # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmPOjQQZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3vreD/sGr7outToY4FSZ4GGpC1L6 # ZwF6kjmwED/8EVaGZxWOaL2/oNoEav2YSpzUbqCa79jUx5zFBE145zYknL/bZyjS # VLX9G2vFFCtwFQ9rc2wV/3JmTmMmSCnHqOZPMSVy5vrQKH6d41WFYZEvGpJmCgh6 # YWK4gnMqkuIHmSvxw+S6q9p/3jzPk7c3vy8eRcxp+AMnfSBkYu0kFXmr7yOwscRS # adT8GFrkj0our/HtYqvzclVzrxcCVF1pWrtrHK7ZSddmElIcztel+1/yQH3T6onj # aOyRj1WC3+0t9uKwUNTFSHkRUqMqr6XYvRF+cvpe5N7lbfVn57u2TwmPgUwYbZcg # 8Mbz+LRYENzTYZa59ACxJXXcG0BivXiTwyrFR8Ck0vakcWFAjDzxHOw9CgHkDwPs # Dd93b04esehIN7MY8/5CSkbx+8ey+YK+o7sofiDCMKcYwooM1Y+Ls21ZcjA5GH+n # SsXp93SgagndCydD0ftRUlDTtGL7dhzaGpRmYArjeWzOKBbAmv/WfQeH47p3bpaP # CB2RUjHzYobMGLO0yp9droOaVKqKKLtc7wGzxgJGx6j5FrN0lnCEMRrKrZJ57Q/q # z4VoRoo0I6Q994/mVanGqXx8cSucyl0Z3HbC633WvrnZXzoM7+7HlQLhpF+yd9+s # 4lHiw0rPgqXtwEfeMaESSQ== # =ubIU # -----END PGP SIGNATURE----- # gpg: Signature made Mon 23 Jan 2023 13:35:00 GMT # 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] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * tag 'pull-target-arm-20230123' of https://git.linaro.org/people/pmaydell/qemu-arm: (26 commits) target/arm: Look up ARMCPRegInfo at runtime target/arm: Reorg do_coproc_insn target/arm: provide stubs for more external debug registers target/arm: implement DBGCLAIM registers target/arm: Don't set EXC_RETURN.ES if Security Extension not present target/arm: Fix in_debug path in S1_ptw_translate target/arm: Fix physical address resolution for MTE target/arm/sme: Unify set_pstate() SM/ZA helpers as set_svcr() target/arm/sme: Rebuild hflags in aarch64_set_svcr() target/arm/sme: Reset ZA state in aarch64_set_svcr() target/arm/sme: Reset SVE state in aarch64_set_svcr() target/arm/sme: Introduce aarch64_set_svcr() target/arm/sme: Rebuild hflags in set_pstate() helpers target/arm/sme: Reorg SME access handling in handle_msr_i() hw/i2c/versatile_i2c: Rename versatile_i2c -> arm_sbcon_i2c hw/i2c/versatile_i2c: Use ARM_SBCON_I2C() macro hw/i2c/versatile_i2c: Replace TYPE_VERSATILE_I2C -> TYPE_ARM_SBCON_I2C hw/i2c/versatile_i2c: Replace VersatileI2CState -> ArmSbconI2CState hw/i2c/versatile_i2c: Drop useless casts from void * to pointer hw/i2c/bitbang_i2c: Convert DPRINTF() to trace events ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
00b1faea41
|
@ -942,6 +942,7 @@ M: Peter Maydell <peter.maydell@linaro.org>
|
||||||
L: qemu-arm@nongnu.org
|
L: qemu-arm@nongnu.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/*/versatile*
|
F: hw/*/versatile*
|
||||||
|
F: hw/i2c/arm_sbcon_i2c.c
|
||||||
F: include/hw/i2c/arm_sbcon_i2c.h
|
F: include/hw/i2c/arm_sbcon_i2c.h
|
||||||
F: hw/misc/arm_sysctl.c
|
F: hw/misc/arm_sysctl.c
|
||||||
F: docs/system/arm/versatile.rst
|
F: docs/system/arm/versatile.rst
|
||||||
|
|
|
@ -211,7 +211,7 @@ config REALVIEW
|
||||||
select PL110
|
select PL110
|
||||||
select PL181 # display
|
select PL181 # display
|
||||||
select PL310 # cache controller
|
select PL310 # cache controller
|
||||||
select VERSATILE_I2C
|
select ARM_SBCON_I2C
|
||||||
select DS1338 # I2C RTC+NVRAM
|
select DS1338 # I2C RTC+NVRAM
|
||||||
select USB_OHCI
|
select USB_OHCI
|
||||||
|
|
||||||
|
@ -481,7 +481,7 @@ config MPS2
|
||||||
select SPLIT_IRQ
|
select SPLIT_IRQ
|
||||||
select UNIMP
|
select UNIMP
|
||||||
select CMSDK_APB_WATCHDOG
|
select CMSDK_APB_WATCHDOG
|
||||||
select VERSATILE_I2C
|
select ARM_SBCON_I2C
|
||||||
|
|
||||||
config FSL_IMX7
|
config FSL_IMX7
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "hw/block/flash.h"
|
#include "hw/block/flash.h"
|
||||||
#include "ui/console.h"
|
#include "ui/console.h"
|
||||||
#include "hw/i2c/i2c.h"
|
#include "hw/i2c/i2c.h"
|
||||||
|
#include "hw/i2c/bitbang_i2c.h"
|
||||||
#include "hw/irq.h"
|
#include "hw/irq.h"
|
||||||
#include "hw/or-irq.h"
|
#include "hw/or-irq.h"
|
||||||
#include "hw/audio/wm8750.h"
|
#include "hw/audio/wm8750.h"
|
||||||
|
@ -1303,7 +1304,7 @@ static void musicpal_init(MachineState *machine)
|
||||||
|
|
||||||
dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE,
|
dev = sysbus_create_simple(TYPE_MUSICPAL_GPIO, MP_GPIO_BASE,
|
||||||
qdev_get_gpio_in(pic, MP_GPIO_IRQ));
|
qdev_get_gpio_in(pic, MP_GPIO_IRQ));
|
||||||
i2c_dev = sysbus_create_simple("gpio_i2c", -1, NULL);
|
i2c_dev = sysbus_create_simple(TYPE_GPIO_I2C, -1, NULL);
|
||||||
i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c");
|
i2c = (I2CBus *)qdev_get_child_bus(i2c_dev, "i2c");
|
||||||
|
|
||||||
lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL);
|
lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL);
|
||||||
|
|
|
@ -309,7 +309,7 @@ static void realview_init(MachineState *machine,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL);
|
dev = sysbus_create_simple(TYPE_ARM_SBCON_I2C, 0x10002000, NULL);
|
||||||
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
|
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
|
||||||
i2c_slave_create_simple(i2c, "ds1338", 0x68);
|
i2c_slave_create_simple(i2c, "ds1338", 0x68);
|
||||||
|
|
||||||
|
|
|
@ -336,7 +336,7 @@ static void versatile_init(MachineState *machine, int board_id)
|
||||||
/* Add PL031 Real Time Clock. */
|
/* Add PL031 Real Time Clock. */
|
||||||
sysbus_create_simple("pl031", 0x101e8000, pic[10]);
|
sysbus_create_simple("pl031", 0x101e8000, pic[10]);
|
||||||
|
|
||||||
dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL);
|
dev = sysbus_create_simple(TYPE_ARM_SBCON_I2C, 0x10002000, NULL);
|
||||||
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
|
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
|
||||||
i2c_slave_create_simple(i2c, "ds1338", 0x68);
|
i2c_slave_create_simple(i2c, "ds1338", 0x68);
|
||||||
|
|
||||||
|
|
|
@ -646,7 +646,7 @@ static void vexpress_common_init(MachineState *machine)
|
||||||
sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]);
|
sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]);
|
||||||
sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]);
|
sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]);
|
||||||
|
|
||||||
dev = sysbus_create_simple(TYPE_VERSATILE_I2C, map[VE_SERIALDVI], NULL);
|
dev = sysbus_create_simple(TYPE_ARM_SBCON_I2C, map[VE_SERIALDVI], NULL);
|
||||||
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
|
i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
|
||||||
i2c_slave_create_simple(i2c, "sii9022", 0x39);
|
i2c_slave_create_simple(i2c, "sii9022", 0x39);
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ config SMBUS_EEPROM
|
||||||
bool
|
bool
|
||||||
select SMBUS
|
select SMBUS
|
||||||
|
|
||||||
config VERSATILE_I2C
|
config ARM_SBCON_I2C
|
||||||
bool
|
bool
|
||||||
select BITBANG_I2C
|
select BITBANG_I2C
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,6 @@
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
|
|
||||||
typedef ArmSbconI2CState VersatileI2CState;
|
|
||||||
DECLARE_INSTANCE_CHECKER(VersatileI2CState, VERSATILE_I2C,
|
|
||||||
TYPE_VERSATILE_I2C)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
REG32(CONTROL_GET, 0)
|
REG32(CONTROL_GET, 0)
|
||||||
REG32(CONTROL_SET, 0)
|
REG32(CONTROL_SET, 0)
|
||||||
|
@ -42,10 +37,10 @@ REG32(CONTROL_CLR, 4)
|
||||||
#define SCL BIT(0)
|
#define SCL BIT(0)
|
||||||
#define SDA BIT(1)
|
#define SDA BIT(1)
|
||||||
|
|
||||||
static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
|
static uint64_t arm_sbcon_i2c_read(void *opaque, hwaddr offset,
|
||||||
unsigned size)
|
unsigned size)
|
||||||
{
|
{
|
||||||
VersatileI2CState *s = (VersatileI2CState *)opaque;
|
ArmSbconI2CState *s = opaque;
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case A_CONTROL_SET:
|
case A_CONTROL_SET:
|
||||||
|
@ -57,10 +52,10 @@ static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void versatile_i2c_write(void *opaque, hwaddr offset,
|
static void arm_sbcon_i2c_write(void *opaque, hwaddr offset,
|
||||||
uint64_t value, unsigned size)
|
uint64_t value, unsigned size)
|
||||||
{
|
{
|
||||||
VersatileI2CState *s = (VersatileI2CState *)opaque;
|
ArmSbconI2CState *s = opaque;
|
||||||
|
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case A_CONTROL_SET:
|
case A_CONTROL_SET:
|
||||||
|
@ -77,36 +72,36 @@ static void versatile_i2c_write(void *opaque, hwaddr offset,
|
||||||
s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & SDA) != 0);
|
s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & SDA) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const MemoryRegionOps versatile_i2c_ops = {
|
static const MemoryRegionOps arm_sbcon_i2c_ops = {
|
||||||
.read = versatile_i2c_read,
|
.read = arm_sbcon_i2c_read,
|
||||||
.write = versatile_i2c_write,
|
.write = arm_sbcon_i2c_write,
|
||||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void versatile_i2c_init(Object *obj)
|
static void arm_sbcon_i2c_init(Object *obj)
|
||||||
{
|
{
|
||||||
DeviceState *dev = DEVICE(obj);
|
DeviceState *dev = DEVICE(obj);
|
||||||
VersatileI2CState *s = VERSATILE_I2C(obj);
|
ArmSbconI2CState *s = ARM_SBCON_I2C(obj);
|
||||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||||
I2CBus *bus;
|
I2CBus *bus;
|
||||||
|
|
||||||
bus = i2c_init_bus(dev, "i2c");
|
bus = i2c_init_bus(dev, "i2c");
|
||||||
bitbang_i2c_init(&s->bitbang, bus);
|
bitbang_i2c_init(&s->bitbang, bus);
|
||||||
memory_region_init_io(&s->iomem, obj, &versatile_i2c_ops, s,
|
memory_region_init_io(&s->iomem, obj, &arm_sbcon_i2c_ops, s,
|
||||||
"arm_sbcon_i2c", 0x1000);
|
"arm_sbcon_i2c", 0x1000);
|
||||||
sysbus_init_mmio(sbd, &s->iomem);
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo versatile_i2c_info = {
|
static const TypeInfo arm_sbcon_i2c_info = {
|
||||||
.name = TYPE_VERSATILE_I2C,
|
.name = TYPE_ARM_SBCON_I2C,
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
.instance_size = sizeof(VersatileI2CState),
|
.instance_size = sizeof(ArmSbconI2CState),
|
||||||
.instance_init = versatile_i2c_init,
|
.instance_init = arm_sbcon_i2c_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void versatile_i2c_register_types(void)
|
static void arm_sbcon_i2c_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&versatile_i2c_info);
|
type_register_static(&arm_sbcon_i2c_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(versatile_i2c_register_types)
|
type_init(arm_sbcon_i2c_register_types)
|
|
@ -16,30 +16,57 @@
|
||||||
#include "hw/sysbus.h"
|
#include "hw/sysbus.h"
|
||||||
#include "qemu/module.h"
|
#include "qemu/module.h"
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
//#define DEBUG_BITBANG_I2C
|
|
||||||
|
|
||||||
#ifdef DEBUG_BITBANG_I2C
|
/* bitbang_i2c_state enum to name */
|
||||||
#define DPRINTF(fmt, ...) \
|
static const char * const sname[] = {
|
||||||
do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0)
|
#define NAME(e) [e] = stringify(e)
|
||||||
#else
|
NAME(STOPPED),
|
||||||
#define DPRINTF(fmt, ...) do {} while(0)
|
[SENDING_BIT7] = "SENDING_BIT7 (START)",
|
||||||
#endif
|
NAME(SENDING_BIT6),
|
||||||
|
NAME(SENDING_BIT5),
|
||||||
|
NAME(SENDING_BIT4),
|
||||||
|
NAME(SENDING_BIT3),
|
||||||
|
NAME(SENDING_BIT2),
|
||||||
|
NAME(SENDING_BIT1),
|
||||||
|
NAME(SENDING_BIT0),
|
||||||
|
NAME(WAITING_FOR_ACK),
|
||||||
|
[RECEIVING_BIT7] = "RECEIVING_BIT7 (ACK)",
|
||||||
|
NAME(RECEIVING_BIT6),
|
||||||
|
NAME(RECEIVING_BIT5),
|
||||||
|
NAME(RECEIVING_BIT4),
|
||||||
|
NAME(RECEIVING_BIT3),
|
||||||
|
NAME(RECEIVING_BIT2),
|
||||||
|
NAME(RECEIVING_BIT1),
|
||||||
|
NAME(RECEIVING_BIT0),
|
||||||
|
NAME(SENDING_ACK),
|
||||||
|
NAME(SENT_NACK)
|
||||||
|
#undef NAME
|
||||||
|
};
|
||||||
|
|
||||||
|
static void bitbang_i2c_set_state(bitbang_i2c_interface *i2c,
|
||||||
|
bitbang_i2c_state state)
|
||||||
|
{
|
||||||
|
trace_bitbang_i2c_state(sname[i2c->state], sname[state]);
|
||||||
|
i2c->state = state;
|
||||||
|
}
|
||||||
|
|
||||||
static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c)
|
static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c)
|
||||||
{
|
{
|
||||||
DPRINTF("STOP\n");
|
|
||||||
if (i2c->current_addr >= 0)
|
if (i2c->current_addr >= 0)
|
||||||
i2c_end_transfer(i2c->bus);
|
i2c_end_transfer(i2c->bus);
|
||||||
i2c->current_addr = -1;
|
i2c->current_addr = -1;
|
||||||
i2c->state = STOPPED;
|
bitbang_i2c_set_state(i2c, STOPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set device data pin. */
|
/* Set device data pin. */
|
||||||
static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level)
|
static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level)
|
||||||
{
|
{
|
||||||
|
trace_bitbang_i2c_data(i2c->last_clock, i2c->last_data,
|
||||||
|
i2c->device_out, level);
|
||||||
i2c->device_out = level;
|
i2c->device_out = level;
|
||||||
//DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out);
|
|
||||||
return level & i2c->last_data;
|
return level & i2c->last_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,9 +94,8 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
|
||||||
return bitbang_i2c_nop(i2c);
|
return bitbang_i2c_nop(i2c);
|
||||||
}
|
}
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
DPRINTF("START\n");
|
|
||||||
/* START condition. */
|
/* START condition. */
|
||||||
i2c->state = SENDING_BIT7;
|
bitbang_i2c_set_state(i2c, SENDING_BIT7);
|
||||||
i2c->current_addr = -1;
|
i2c->current_addr = -1;
|
||||||
} else {
|
} else {
|
||||||
/* STOP condition. */
|
/* STOP condition. */
|
||||||
|
@ -96,7 +122,7 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
|
||||||
case SENDING_BIT7 ... SENDING_BIT0:
|
case SENDING_BIT7 ... SENDING_BIT0:
|
||||||
i2c->buffer = (i2c->buffer << 1) | data;
|
i2c->buffer = (i2c->buffer << 1) | data;
|
||||||
/* will end up in WAITING_FOR_ACK */
|
/* will end up in WAITING_FOR_ACK */
|
||||||
i2c->state++;
|
bitbang_i2c_set_state(i2c, i2c->state + 1);
|
||||||
return bitbang_i2c_ret(i2c, 1);
|
return bitbang_i2c_ret(i2c, 1);
|
||||||
|
|
||||||
case WAITING_FOR_ACK:
|
case WAITING_FOR_ACK:
|
||||||
|
@ -105,47 +131,45 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
|
||||||
|
|
||||||
if (i2c->current_addr < 0) {
|
if (i2c->current_addr < 0) {
|
||||||
i2c->current_addr = i2c->buffer;
|
i2c->current_addr = i2c->buffer;
|
||||||
DPRINTF("Address 0x%02x\n", i2c->current_addr);
|
trace_bitbang_i2c_addr(i2c->current_addr);
|
||||||
ret = i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
|
ret = i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
|
||||||
i2c->current_addr & 1);
|
i2c->current_addr & 1);
|
||||||
} else {
|
} else {
|
||||||
DPRINTF("Sent 0x%02x\n", i2c->buffer);
|
trace_bitbang_i2c_send(i2c->buffer);
|
||||||
ret = i2c_send(i2c->bus, i2c->buffer);
|
ret = i2c_send(i2c->bus, i2c->buffer);
|
||||||
}
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/* NACK (either addressing a nonexistent device, or the
|
/* NACK (either addressing a nonexistent device, or the
|
||||||
* device we were sending to decided to NACK us).
|
* device we were sending to decided to NACK us).
|
||||||
*/
|
*/
|
||||||
DPRINTF("Got NACK\n");
|
bitbang_i2c_set_state(i2c, SENT_NACK);
|
||||||
bitbang_i2c_enter_stop(i2c);
|
bitbang_i2c_enter_stop(i2c);
|
||||||
return bitbang_i2c_ret(i2c, 1);
|
return bitbang_i2c_ret(i2c, 1);
|
||||||
}
|
}
|
||||||
if (i2c->current_addr & 1) {
|
if (i2c->current_addr & 1) {
|
||||||
i2c->state = RECEIVING_BIT7;
|
bitbang_i2c_set_state(i2c, RECEIVING_BIT7);
|
||||||
} else {
|
} else {
|
||||||
i2c->state = SENDING_BIT7;
|
bitbang_i2c_set_state(i2c, SENDING_BIT7);
|
||||||
}
|
}
|
||||||
return bitbang_i2c_ret(i2c, 0);
|
return bitbang_i2c_ret(i2c, 0);
|
||||||
}
|
}
|
||||||
case RECEIVING_BIT7:
|
case RECEIVING_BIT7:
|
||||||
i2c->buffer = i2c_recv(i2c->bus);
|
i2c->buffer = i2c_recv(i2c->bus);
|
||||||
DPRINTF("RX byte 0x%02x\n", i2c->buffer);
|
trace_bitbang_i2c_recv(i2c->buffer);
|
||||||
/* Fall through... */
|
/* Fall through... */
|
||||||
case RECEIVING_BIT6 ... RECEIVING_BIT0:
|
case RECEIVING_BIT6 ... RECEIVING_BIT0:
|
||||||
data = i2c->buffer >> 7;
|
data = i2c->buffer >> 7;
|
||||||
/* will end up in SENDING_ACK */
|
/* will end up in SENDING_ACK */
|
||||||
i2c->state++;
|
bitbang_i2c_set_state(i2c, i2c->state + 1);
|
||||||
i2c->buffer <<= 1;
|
i2c->buffer <<= 1;
|
||||||
return bitbang_i2c_ret(i2c, data);
|
return bitbang_i2c_ret(i2c, data);
|
||||||
|
|
||||||
case SENDING_ACK:
|
case SENDING_ACK:
|
||||||
i2c->state = RECEIVING_BIT7;
|
|
||||||
if (data != 0) {
|
if (data != 0) {
|
||||||
DPRINTF("NACKED\n");
|
bitbang_i2c_set_state(i2c, SENT_NACK);
|
||||||
i2c->state = SENT_NACK;
|
|
||||||
i2c_nack(i2c->bus);
|
i2c_nack(i2c->bus);
|
||||||
} else {
|
} else {
|
||||||
DPRINTF("ACKED\n");
|
bitbang_i2c_set_state(i2c, RECEIVING_BIT7);
|
||||||
}
|
}
|
||||||
return bitbang_i2c_ret(i2c, 1);
|
return bitbang_i2c_ret(i2c, 1);
|
||||||
}
|
}
|
||||||
|
@ -162,13 +186,13 @@ void bitbang_i2c_init(bitbang_i2c_interface *s, I2CBus *bus)
|
||||||
|
|
||||||
/* GPIO interface. */
|
/* GPIO interface. */
|
||||||
|
|
||||||
#define TYPE_GPIO_I2C "gpio_i2c"
|
|
||||||
OBJECT_DECLARE_SIMPLE_TYPE(GPIOI2CState, GPIO_I2C)
|
OBJECT_DECLARE_SIMPLE_TYPE(GPIOI2CState, GPIO_I2C)
|
||||||
|
|
||||||
struct GPIOI2CState {
|
struct GPIOI2CState {
|
||||||
|
/*< private >*/
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
|
/*< public >*/
|
||||||
|
|
||||||
MemoryRegion dummy_iomem;
|
|
||||||
bitbang_i2c_interface bitbang;
|
bitbang_i2c_interface bitbang;
|
||||||
int last_level;
|
int last_level;
|
||||||
qemu_irq out;
|
qemu_irq out;
|
||||||
|
@ -189,12 +213,8 @@ static void gpio_i2c_init(Object *obj)
|
||||||
{
|
{
|
||||||
DeviceState *dev = DEVICE(obj);
|
DeviceState *dev = DEVICE(obj);
|
||||||
GPIOI2CState *s = GPIO_I2C(obj);
|
GPIOI2CState *s = GPIO_I2C(obj);
|
||||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
|
||||||
I2CBus *bus;
|
I2CBus *bus;
|
||||||
|
|
||||||
memory_region_init(&s->dummy_iomem, obj, "gpio_i2c", 0);
|
|
||||||
sysbus_init_mmio(sbd, &s->dummy_iomem);
|
|
||||||
|
|
||||||
bus = i2c_init_bus(dev, "i2c");
|
bus = i2c_init_bus(dev, "i2c");
|
||||||
bitbang_i2c_init(&s->bitbang, bus);
|
bitbang_i2c_init(&s->bitbang, bus);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ i2c_ss.add(when: 'CONFIG_ALLWINNER_I2C', if_true: files('allwinner-i2c.c'))
|
||||||
i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c'))
|
i2c_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('microbit_i2c.c'))
|
||||||
i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c'))
|
i2c_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_smbus.c'))
|
||||||
i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c'))
|
i2c_ss.add(when: 'CONFIG_SMBUS_EEPROM', if_true: files('smbus_eeprom.c'))
|
||||||
i2c_ss.add(when: 'CONFIG_VERSATILE_I2C', if_true: files('versatile_i2c.c'))
|
i2c_ss.add(when: 'CONFIG_ARM_SBCON_I2C', if_true: files('arm_sbcon_i2c.c'))
|
||||||
i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c'))
|
i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c'))
|
||||||
i2c_ss.add(when: 'CONFIG_PPC4XX', if_true: files('ppc4xx_i2c.c'))
|
i2c_ss.add(when: 'CONFIG_PPC4XX', if_true: files('ppc4xx_i2c.c'))
|
||||||
i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c'))
|
i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c'))
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
# See docs/devel/tracing.rst for syntax documentation.
|
# See docs/devel/tracing.rst for syntax documentation.
|
||||||
|
|
||||||
|
# bitbang_i2c.c
|
||||||
|
bitbang_i2c_state(const char *old_state, const char *new_state) "state %s -> %s"
|
||||||
|
bitbang_i2c_addr(uint8_t addr) "Address 0x%02x"
|
||||||
|
bitbang_i2c_send(uint8_t byte) "TX byte 0x%02x"
|
||||||
|
bitbang_i2c_recv(uint8_t byte) "RX byte 0x%02x"
|
||||||
|
bitbang_i2c_data(unsigned dat, unsigned clk, unsigned old_out, unsigned new_out) "dat %u clk %u out %u -> %u"
|
||||||
|
|
||||||
# core.c
|
# core.c
|
||||||
|
|
||||||
i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)"
|
i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)"
|
||||||
|
|
|
@ -17,12 +17,10 @@
|
||||||
#include "hw/i2c/bitbang_i2c.h"
|
#include "hw/i2c/bitbang_i2c.h"
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
|
|
||||||
#define TYPE_VERSATILE_I2C "versatile_i2c"
|
#define TYPE_ARM_SBCON_I2C "versatile_i2c"
|
||||||
#define TYPE_ARM_SBCON_I2C TYPE_VERSATILE_I2C
|
|
||||||
|
|
||||||
typedef struct ArmSbconI2CState ArmSbconI2CState;
|
typedef struct ArmSbconI2CState ArmSbconI2CState;
|
||||||
DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, ARM_SBCON_I2C,
|
DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, ARM_SBCON_I2C, TYPE_ARM_SBCON_I2C)
|
||||||
TYPE_ARM_SBCON_I2C)
|
|
||||||
|
|
||||||
struct ArmSbconI2CState {
|
struct ArmSbconI2CState {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "hw/i2c/i2c.h"
|
#include "hw/i2c/i2c.h"
|
||||||
|
|
||||||
|
#define TYPE_GPIO_I2C "gpio_i2c"
|
||||||
|
|
||||||
typedef struct bitbang_i2c_interface bitbang_i2c_interface;
|
typedef struct bitbang_i2c_interface bitbang_i2c_interface;
|
||||||
|
|
||||||
#define BITBANG_I2C_SDA 0
|
#define BITBANG_I2C_SDA 0
|
||||||
|
|
|
@ -89,15 +89,8 @@ void cpu_loop(CPUARMState *env)
|
||||||
|
|
||||||
switch (trapnr) {
|
switch (trapnr) {
|
||||||
case EXCP_SWI:
|
case EXCP_SWI:
|
||||||
/*
|
/* On syscall, PSTATE.ZA is preserved, PSTATE.SM is cleared. */
|
||||||
* On syscall, PSTATE.ZA is preserved, along with the ZA matrix.
|
aarch64_set_svcr(env, 0, R_SVCR_SM_MASK);
|
||||||
* PSTATE.SM is cleared, per SMSTOP, which does ResetSVEState.
|
|
||||||
*/
|
|
||||||
if (FIELD_EX64(env->svcr, SVCR, SM)) {
|
|
||||||
env->svcr = FIELD_DP64(env->svcr, SVCR, SM, 0);
|
|
||||||
arm_rebuild_hflags(env);
|
|
||||||
arm_reset_sve_state(env);
|
|
||||||
}
|
|
||||||
ret = do_syscall(env,
|
ret = do_syscall(env,
|
||||||
env->xregs[8],
|
env->xregs[8],
|
||||||
env->xregs[0],
|
env->xregs[0],
|
||||||
|
|
|
@ -665,17 +665,8 @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
|
||||||
env->btype = 2;
|
env->btype = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Invoke the signal handler with both SM and ZA disabled. */
|
||||||
* Invoke the signal handler with both SM and ZA disabled.
|
aarch64_set_svcr(env, 0, R_SVCR_SM_MASK | R_SVCR_ZA_MASK);
|
||||||
* When clearing SM, ResetSVEState, per SMSTOP.
|
|
||||||
*/
|
|
||||||
if (FIELD_EX64(env->svcr, SVCR, SM)) {
|
|
||||||
arm_reset_sve_state(env);
|
|
||||||
}
|
|
||||||
if (env->svcr) {
|
|
||||||
env->svcr = 0;
|
|
||||||
arm_rebuild_hflags(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info) {
|
if (info) {
|
||||||
tswap_siginfo(&frame->info, info);
|
tswap_siginfo(&frame->info, info);
|
||||||
|
|
|
@ -479,7 +479,7 @@ typedef struct CPUArchState {
|
||||||
};
|
};
|
||||||
uint64_t c14_cntfrq; /* Counter Frequency register */
|
uint64_t c14_cntfrq; /* Counter Frequency register */
|
||||||
uint64_t c14_cntkctl; /* Timer Control register */
|
uint64_t c14_cntkctl; /* Timer Control register */
|
||||||
uint32_t cnthctl_el2; /* Counter/Timer Hyp Control register */
|
uint64_t cnthctl_el2; /* Counter/Timer Hyp Control register */
|
||||||
uint64_t cntvoff_el2; /* Counter Virtual Offset register */
|
uint64_t cntvoff_el2; /* Counter Virtual Offset register */
|
||||||
ARMGenericTimer c14_timer[NUM_GTIMERS];
|
ARMGenericTimer c14_timer[NUM_GTIMERS];
|
||||||
uint32_t c15_cpar; /* XScale Coprocessor Access Register */
|
uint32_t c15_cpar; /* XScale Coprocessor Access Register */
|
||||||
|
@ -495,6 +495,7 @@ typedef struct CPUArchState {
|
||||||
uint64_t dbgbcr[16]; /* breakpoint control registers */
|
uint64_t dbgbcr[16]; /* breakpoint control registers */
|
||||||
uint64_t dbgwvr[16]; /* watchpoint value registers */
|
uint64_t dbgwvr[16]; /* watchpoint value registers */
|
||||||
uint64_t dbgwcr[16]; /* watchpoint control registers */
|
uint64_t dbgwcr[16]; /* watchpoint control registers */
|
||||||
|
uint64_t dbgclaim; /* DBGCLAIM bits */
|
||||||
uint64_t mdscr_el1;
|
uint64_t mdscr_el1;
|
||||||
uint64_t oslsr_el1; /* OS Lock Status */
|
uint64_t oslsr_el1; /* OS Lock Status */
|
||||||
uint64_t osdlr_el1; /* OS DoubleLock status */
|
uint64_t osdlr_el1; /* OS DoubleLock status */
|
||||||
|
@ -1123,7 +1124,7 @@ int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq);
|
void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq);
|
||||||
void aarch64_sve_change_el(CPUARMState *env, int old_el,
|
void aarch64_sve_change_el(CPUARMState *env, int old_el,
|
||||||
int new_el, bool el0_a64);
|
int new_el, bool el0_a64);
|
||||||
void arm_reset_sve_state(CPUARMState *env);
|
void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SVE registers are encoded in KVM's memory in an endianness-invariant format.
|
* SVE registers are encoded in KVM's memory in an endianness-invariant format.
|
||||||
|
|
|
@ -632,6 +632,24 @@ static void osdlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dbgclaimset_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
env->cp15.dbgclaim |= (value & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t dbgclaimset_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
|
{
|
||||||
|
/* CLAIM bits are RAO */
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dbgclaimclr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
uint64_t value)
|
||||||
|
{
|
||||||
|
env->cp15.dbgclaim &= ~(value & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
static const ARMCPRegInfo debug_cp_reginfo[] = {
|
static const ARMCPRegInfo debug_cp_reginfo[] = {
|
||||||
/*
|
/*
|
||||||
* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped
|
* DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped
|
||||||
|
@ -664,6 +682,27 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
|
||||||
.opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0,
|
.opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0,
|
||||||
.access = PL0_R, .accessfn = access_tda,
|
.access = PL0_R, .accessfn = access_tda,
|
||||||
.type = ARM_CP_CONST, .resetvalue = 0 },
|
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
|
/*
|
||||||
|
* OSDTRRX_EL1/OSDTRTX_EL1 are used for save and restore of DBGDTRRX_EL0.
|
||||||
|
* It is a component of the Debug Communications Channel, which is not implemented.
|
||||||
|
*/
|
||||||
|
{ .name = "OSDTRRX_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14,
|
||||||
|
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 2,
|
||||||
|
.access = PL1_RW, .accessfn = access_tda,
|
||||||
|
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
|
{ .name = "OSDTRTX_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14,
|
||||||
|
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 2,
|
||||||
|
.access = PL1_RW, .accessfn = access_tda,
|
||||||
|
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
|
/*
|
||||||
|
* OSECCR_EL1 provides a mechanism for an operating system
|
||||||
|
* to access the contents of EDECCR. EDECCR is not implemented though,
|
||||||
|
* as is the rest of external device mechanism.
|
||||||
|
*/
|
||||||
|
{ .name = "OSECCR_EL1", .state = ARM_CP_STATE_BOTH, .cp = 14,
|
||||||
|
.opc0 = 2, .opc1 = 0, .crn = 0, .crm = 6, .opc2 = 2,
|
||||||
|
.access = PL1_RW, .accessfn = access_tda,
|
||||||
|
.type = ARM_CP_CONST, .resetvalue = 0 },
|
||||||
/*
|
/*
|
||||||
* DBGDSCRint[15,12,5:2] map to MDSCR_EL1[15,12,5:2]. Map all bits as
|
* DBGDSCRint[15,12,5:2] map to MDSCR_EL1[15,12,5:2]. Map all bits as
|
||||||
* it is unlikely a guest will care.
|
* it is unlikely a guest will care.
|
||||||
|
@ -715,6 +754,21 @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
|
||||||
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0,
|
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0,
|
||||||
.access = PL1_RW, .accessfn = access_tda,
|
.access = PL1_RW, .accessfn = access_tda,
|
||||||
.type = ARM_CP_NOP },
|
.type = ARM_CP_NOP },
|
||||||
|
/*
|
||||||
|
* Dummy DBGCLAIM registers.
|
||||||
|
* "The architecture does not define any functionality for the CLAIM tag bits.",
|
||||||
|
* so we only keep the raw bits
|
||||||
|
*/
|
||||||
|
{ .name = "DBGCLAIMSET_EL1", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 6,
|
||||||
|
.type = ARM_CP_ALIAS,
|
||||||
|
.access = PL1_RW, .accessfn = access_tda,
|
||||||
|
.writefn = dbgclaimset_write, .readfn = dbgclaimset_read },
|
||||||
|
{ .name = "DBGCLAIMCLR_EL1", .state = ARM_CP_STATE_BOTH,
|
||||||
|
.cp = 14, .opc0 = 2, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 6,
|
||||||
|
.access = PL1_RW, .accessfn = access_tda,
|
||||||
|
.writefn = dbgclaimclr_write, .raw_writefn = raw_write,
|
||||||
|
.fieldoffset = offsetof(CPUARMState, cp15.dbgclaim) },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const ARMCPRegInfo debug_lpae_cp_reginfo[] = {
|
static const ARMCPRegInfo debug_lpae_cp_reginfo[] = {
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEF_HELPER_FLAGS_2(set_pstate_sm, TCG_CALL_NO_RWG, void, env, i32)
|
DEF_HELPER_FLAGS_3(set_svcr, TCG_CALL_NO_RWG, void, env, i32, i32)
|
||||||
DEF_HELPER_FLAGS_2(set_pstate_za, TCG_CALL_NO_RWG, void, env, i32)
|
|
||||||
|
|
||||||
DEF_HELPER_FLAGS_3(sme_zero, TCG_CALL_NO_RWG, void, env, i32, i32)
|
DEF_HELPER_FLAGS_3(sme_zero, TCG_CALL_NO_RWG, void, env, i32, i32)
|
||||||
|
|
||||||
|
|
|
@ -6725,12 +6725,47 @@ static CPAccessResult access_esm(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
return CP_ACCESS_OK;
|
return CP_ACCESS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ResetSVEState */
|
||||||
|
static void arm_reset_sve_state(CPUARMState *env)
|
||||||
|
{
|
||||||
|
memset(env->vfp.zregs, 0, sizeof(env->vfp.zregs));
|
||||||
|
/* Recall that FFR is stored as pregs[16]. */
|
||||||
|
memset(env->vfp.pregs, 0, sizeof(env->vfp.pregs));
|
||||||
|
vfp_set_fpcr(env, 0x0800009f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void aarch64_set_svcr(CPUARMState *env, uint64_t new, uint64_t mask)
|
||||||
|
{
|
||||||
|
uint64_t change = (env->svcr ^ new) & mask;
|
||||||
|
|
||||||
|
if (change == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
env->svcr ^= change;
|
||||||
|
|
||||||
|
if (change & R_SVCR_SM_MASK) {
|
||||||
|
arm_reset_sve_state(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ResetSMEState.
|
||||||
|
*
|
||||||
|
* SetPSTATE_ZA zeros on enable and disable. We can zero this only
|
||||||
|
* on enable: while disabled, the storage is inaccessible and the
|
||||||
|
* value does not matter. We're not saving the storage in vmstate
|
||||||
|
* when disabled either.
|
||||||
|
*/
|
||||||
|
if (change & new & R_SVCR_ZA_MASK) {
|
||||||
|
memset(env->zarray, 0, sizeof(env->zarray));
|
||||||
|
}
|
||||||
|
|
||||||
|
arm_rebuild_hflags(env);
|
||||||
|
}
|
||||||
|
|
||||||
static void svcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void svcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
uint64_t value)
|
uint64_t value)
|
||||||
{
|
{
|
||||||
helper_set_pstate_sm(env, FIELD_EX64(value, SVCR, SM));
|
aarch64_set_svcr(env, value, -1);
|
||||||
helper_set_pstate_za(env, FIELD_EX64(value, SVCR, ZA));
|
|
||||||
arm_rebuild_hflags(env);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void smcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
static void smcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
|
|
|
@ -79,11 +79,12 @@ DEF_HELPER_2(v8m_stackcheck, void, env, i32)
|
||||||
|
|
||||||
DEF_HELPER_FLAGS_2(check_bxj_trap, TCG_CALL_NO_WG, void, env, i32)
|
DEF_HELPER_FLAGS_2(check_bxj_trap, TCG_CALL_NO_WG, void, env, i32)
|
||||||
|
|
||||||
DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32)
|
DEF_HELPER_4(access_check_cp_reg, cptr, env, i32, i32, i32)
|
||||||
DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
|
DEF_HELPER_FLAGS_2(lookup_cp_reg, TCG_CALL_NO_RWG_SE, cptr, env, i32)
|
||||||
DEF_HELPER_2(get_cp_reg, i32, env, ptr)
|
DEF_HELPER_3(set_cp_reg, void, env, cptr, i32)
|
||||||
DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
|
DEF_HELPER_2(get_cp_reg, i32, env, cptr)
|
||||||
DEF_HELPER_2(get_cp_reg64, i64, env, ptr)
|
DEF_HELPER_3(set_cp_reg64, void, env, cptr, i64)
|
||||||
|
DEF_HELPER_2(get_cp_reg64, i64, env, cptr)
|
||||||
|
|
||||||
DEF_HELPER_2(get_r13_banked, i32, env, i32)
|
DEF_HELPER_2(get_r13_banked, i32, env, i32)
|
||||||
DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
|
DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
|
||||||
|
|
|
@ -879,7 +879,7 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
|
||||||
}
|
}
|
||||||
|
|
||||||
lr &= ~R_V7M_EXCRET_ES_MASK;
|
lr &= ~R_V7M_EXCRET_ES_MASK;
|
||||||
if (targets_secure || !arm_feature(env, ARM_FEATURE_M_SECURITY)) {
|
if (targets_secure) {
|
||||||
lr |= R_V7M_EXCRET_ES_MASK;
|
lr |= R_V7M_EXCRET_ES_MASK;
|
||||||
}
|
}
|
||||||
lr &= ~R_V7M_EXCRET_SPSEL_MASK;
|
lr &= ~R_V7M_EXCRET_SPSEL_MASK;
|
||||||
|
@ -2465,11 +2465,17 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
||||||
}
|
}
|
||||||
return env->v7m.primask[M_REG_NS];
|
return env->v7m.primask[M_REG_NS];
|
||||||
case 0x91: /* BASEPRI_NS */
|
case 0x91: /* BASEPRI_NS */
|
||||||
|
if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
|
||||||
|
goto bad_reg;
|
||||||
|
}
|
||||||
if (!env->v7m.secure) {
|
if (!env->v7m.secure) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return env->v7m.basepri[M_REG_NS];
|
return env->v7m.basepri[M_REG_NS];
|
||||||
case 0x93: /* FAULTMASK_NS */
|
case 0x93: /* FAULTMASK_NS */
|
||||||
|
if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
|
||||||
|
goto bad_reg;
|
||||||
|
}
|
||||||
if (!env->v7m.secure) {
|
if (!env->v7m.secure) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2515,8 +2521,14 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
|
||||||
return env->v7m.primask[env->v7m.secure];
|
return env->v7m.primask[env->v7m.secure];
|
||||||
case 17: /* BASEPRI */
|
case 17: /* BASEPRI */
|
||||||
case 18: /* BASEPRI_MAX */
|
case 18: /* BASEPRI_MAX */
|
||||||
|
if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
|
||||||
|
goto bad_reg;
|
||||||
|
}
|
||||||
return env->v7m.basepri[env->v7m.secure];
|
return env->v7m.basepri[env->v7m.secure];
|
||||||
case 19: /* FAULTMASK */
|
case 19: /* FAULTMASK */
|
||||||
|
if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
|
||||||
|
goto bad_reg;
|
||||||
|
}
|
||||||
return env->v7m.faultmask[env->v7m.secure];
|
return env->v7m.faultmask[env->v7m.secure];
|
||||||
default:
|
default:
|
||||||
bad_reg:
|
bad_reg:
|
||||||
|
@ -2581,13 +2593,19 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
|
||||||
env->v7m.primask[M_REG_NS] = val & 1;
|
env->v7m.primask[M_REG_NS] = val & 1;
|
||||||
return;
|
return;
|
||||||
case 0x91: /* BASEPRI_NS */
|
case 0x91: /* BASEPRI_NS */
|
||||||
if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
|
if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
|
||||||
|
goto bad_reg;
|
||||||
|
}
|
||||||
|
if (!env->v7m.secure) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
env->v7m.basepri[M_REG_NS] = val & 0xff;
|
env->v7m.basepri[M_REG_NS] = val & 0xff;
|
||||||
return;
|
return;
|
||||||
case 0x93: /* FAULTMASK_NS */
|
case 0x93: /* FAULTMASK_NS */
|
||||||
if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
|
if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
|
||||||
|
goto bad_reg;
|
||||||
|
}
|
||||||
|
if (!env->v7m.secure) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
env->v7m.faultmask[M_REG_NS] = val & 1;
|
env->v7m.faultmask[M_REG_NS] = val & 1;
|
||||||
|
|
|
@ -142,7 +142,7 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
|
||||||
* Remember these values across the second lookup below,
|
* Remember these values across the second lookup below,
|
||||||
* which may invalidate this pointer via tlb resize.
|
* which may invalidate this pointer via tlb resize.
|
||||||
*/
|
*/
|
||||||
ptr_paddr = full->phys_addr;
|
ptr_paddr = full->phys_addr | (ptr & ~TARGET_PAGE_MASK);
|
||||||
attrs = full->attrs;
|
attrs = full->attrs;
|
||||||
full = NULL;
|
full = NULL;
|
||||||
|
|
||||||
|
|
|
@ -624,14 +624,16 @@ uint32_t HELPER(mrs_banked)(CPUARMState *env, uint32_t tgtmode, uint32_t regno)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
|
const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key,
|
||||||
uint32_t isread)
|
uint32_t syndrome, uint32_t isread)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = env_archcpu(env);
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
const ARMCPRegInfo *ri = rip;
|
const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, key);
|
||||||
CPAccessResult res = CP_ACCESS_OK;
|
CPAccessResult res = CP_ACCESS_OK;
|
||||||
int target_el;
|
int target_el;
|
||||||
|
|
||||||
|
assert(ri != NULL);
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14
|
if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14
|
||||||
&& extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) {
|
&& extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) {
|
||||||
res = CP_ACCESS_TRAP;
|
res = CP_ACCESS_TRAP;
|
||||||
|
@ -663,7 +665,7 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
|
||||||
res = ri->accessfn(env, ri, isread);
|
res = ri->accessfn(env, ri, isread);
|
||||||
}
|
}
|
||||||
if (likely(res == CP_ACCESS_OK)) {
|
if (likely(res == CP_ACCESS_OK)) {
|
||||||
return;
|
return ri;
|
||||||
}
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
@ -705,7 +707,16 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
|
||||||
raise_exception(env, EXCP_UDEF, syndrome, target_el);
|
raise_exception(env, EXCP_UDEF, syndrome, target_el);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
|
const void *HELPER(lookup_cp_reg)(CPUARMState *env, uint32_t key)
|
||||||
|
{
|
||||||
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
|
const ARMCPRegInfo *ri = get_arm_cp_reginfo(cpu->cp_regs, key);
|
||||||
|
|
||||||
|
assert(ri != NULL);
|
||||||
|
return ri;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HELPER(set_cp_reg)(CPUARMState *env, const void *rip, uint32_t value)
|
||||||
{
|
{
|
||||||
const ARMCPRegInfo *ri = rip;
|
const ARMCPRegInfo *ri = rip;
|
||||||
|
|
||||||
|
@ -718,7 +729,7 @@ void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
|
uint32_t HELPER(get_cp_reg)(CPUARMState *env, const void *rip)
|
||||||
{
|
{
|
||||||
const ARMCPRegInfo *ri = rip;
|
const ARMCPRegInfo *ri = rip;
|
||||||
uint32_t res;
|
uint32_t res;
|
||||||
|
@ -734,7 +745,7 @@ uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
|
void HELPER(set_cp_reg64)(CPUARMState *env, const void *rip, uint64_t value)
|
||||||
{
|
{
|
||||||
const ARMCPRegInfo *ri = rip;
|
const ARMCPRegInfo *ri = rip;
|
||||||
|
|
||||||
|
@ -747,7 +758,7 @@ void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
|
uint64_t HELPER(get_cp_reg64)(CPUARMState *env, const void *rip)
|
||||||
{
|
{
|
||||||
const ARMCPRegInfo *ri = rip;
|
const ARMCPRegInfo *ri = rip;
|
||||||
uint64_t res;
|
uint64_t res;
|
||||||
|
|
|
@ -238,8 +238,8 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
|
||||||
};
|
};
|
||||||
GetPhysAddrResult s2 = { };
|
GetPhysAddrResult s2 = { };
|
||||||
|
|
||||||
if (!get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD,
|
if (get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD,
|
||||||
false, &s2, fi)) {
|
false, &s2, fi)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
ptw->out_phys = s2.f.phys_addr;
|
ptw->out_phys = s2.f.phys_addr;
|
||||||
|
|
|
@ -29,42 +29,9 @@
|
||||||
#include "vec_internal.h"
|
#include "vec_internal.h"
|
||||||
#include "sve_ldst_internal.h"
|
#include "sve_ldst_internal.h"
|
||||||
|
|
||||||
/* ResetSVEState */
|
void helper_set_svcr(CPUARMState *env, uint32_t val, uint32_t mask)
|
||||||
void arm_reset_sve_state(CPUARMState *env)
|
|
||||||
{
|
{
|
||||||
memset(env->vfp.zregs, 0, sizeof(env->vfp.zregs));
|
aarch64_set_svcr(env, val, mask);
|
||||||
/* Recall that FFR is stored as pregs[16]. */
|
|
||||||
memset(env->vfp.pregs, 0, sizeof(env->vfp.pregs));
|
|
||||||
vfp_set_fpcr(env, 0x0800009f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void helper_set_pstate_sm(CPUARMState *env, uint32_t i)
|
|
||||||
{
|
|
||||||
if (i == FIELD_EX64(env->svcr, SVCR, SM)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
env->svcr ^= R_SVCR_SM_MASK;
|
|
||||||
arm_reset_sve_state(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
void helper_set_pstate_za(CPUARMState *env, uint32_t i)
|
|
||||||
{
|
|
||||||
if (i == FIELD_EX64(env->svcr, SVCR, ZA)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
env->svcr ^= R_SVCR_ZA_MASK;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ResetSMEState.
|
|
||||||
*
|
|
||||||
* SetPSTATE_ZA zeros on enable and disable. We can zero this only
|
|
||||||
* on enable: while disabled, the storage is inaccessible and the
|
|
||||||
* value does not matter. We're not saving the storage in vmstate
|
|
||||||
* when disabled either.
|
|
||||||
*/
|
|
||||||
if (i) {
|
|
||||||
memset(env->zarray, 0, sizeof(env->zarray));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_sme_zero(CPUARMState *env, uint32_t imm, uint32_t svl)
|
void helper_sme_zero(CPUARMState *env, uint32_t imm, uint32_t svl)
|
||||||
|
|
|
@ -1841,19 +1841,14 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
|
||||||
goto do_unallocated;
|
goto do_unallocated;
|
||||||
}
|
}
|
||||||
if (sme_access_check(s)) {
|
if (sme_access_check(s)) {
|
||||||
bool i = crm & 1;
|
int old = s->pstate_sm | (s->pstate_za << 1);
|
||||||
bool changed = false;
|
int new = (crm & 1) * 3;
|
||||||
|
int msk = (crm >> 1) & 3;
|
||||||
|
|
||||||
if ((crm & 2) && i != s->pstate_sm) {
|
if ((old ^ new) & msk) {
|
||||||
gen_helper_set_pstate_sm(cpu_env, tcg_constant_i32(i));
|
/* At least one bit changes. */
|
||||||
changed = true;
|
gen_helper_set_svcr(cpu_env, tcg_constant_i32(new),
|
||||||
}
|
tcg_constant_i32(msk));
|
||||||
if ((crm & 4) && i != s->pstate_za) {
|
|
||||||
gen_helper_set_pstate_za(cpu_env, tcg_constant_i32(i));
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
if (changed) {
|
|
||||||
gen_rebuild_hflags(s);
|
|
||||||
} else {
|
} else {
|
||||||
s->base.is_jmp = DISAS_NEXT;
|
s->base.is_jmp = DISAS_NEXT;
|
||||||
}
|
}
|
||||||
|
@ -1944,13 +1939,12 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
||||||
unsigned int op0, unsigned int op1, unsigned int op2,
|
unsigned int op0, unsigned int op1, unsigned int op2,
|
||||||
unsigned int crn, unsigned int crm, unsigned int rt)
|
unsigned int crn, unsigned int crm, unsigned int rt)
|
||||||
{
|
{
|
||||||
const ARMCPRegInfo *ri;
|
uint32_t key = ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
|
||||||
|
crn, crm, op0, op1, op2);
|
||||||
|
const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
|
||||||
|
TCGv_ptr tcg_ri = NULL;
|
||||||
TCGv_i64 tcg_rt;
|
TCGv_i64 tcg_rt;
|
||||||
|
|
||||||
ri = get_arm_cp_reginfo(s->cp_regs,
|
|
||||||
ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
|
|
||||||
crn, crm, op0, op1, op2));
|
|
||||||
|
|
||||||
if (!ri) {
|
if (!ri) {
|
||||||
/* Unknown register; this might be a guest error or a QEMU
|
/* Unknown register; this might be a guest error or a QEMU
|
||||||
* unimplemented feature.
|
* unimplemented feature.
|
||||||
|
@ -1976,8 +1970,9 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
||||||
|
|
||||||
syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
|
syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
|
||||||
gen_a64_update_pc(s, 0);
|
gen_a64_update_pc(s, 0);
|
||||||
gen_helper_access_check_cp_reg(cpu_env,
|
tcg_ri = tcg_temp_new_ptr();
|
||||||
tcg_constant_ptr(ri),
|
gen_helper_access_check_cp_reg(tcg_ri, cpu_env,
|
||||||
|
tcg_constant_i32(key),
|
||||||
tcg_constant_i32(syndrome),
|
tcg_constant_i32(syndrome),
|
||||||
tcg_constant_i32(isread));
|
tcg_constant_i32(isread));
|
||||||
} else if (ri->type & ARM_CP_RAISES_EXC) {
|
} else if (ri->type & ARM_CP_RAISES_EXC) {
|
||||||
|
@ -1993,7 +1988,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
case ARM_CP_NOP:
|
case ARM_CP_NOP:
|
||||||
return;
|
goto exit;
|
||||||
case ARM_CP_NZCV:
|
case ARM_CP_NZCV:
|
||||||
tcg_rt = cpu_reg(s, rt);
|
tcg_rt = cpu_reg(s, rt);
|
||||||
if (isread) {
|
if (isread) {
|
||||||
|
@ -2001,14 +1996,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
||||||
} else {
|
} else {
|
||||||
gen_set_nzcv(tcg_rt);
|
gen_set_nzcv(tcg_rt);
|
||||||
}
|
}
|
||||||
return;
|
goto exit;
|
||||||
case ARM_CP_CURRENTEL:
|
case ARM_CP_CURRENTEL:
|
||||||
/* Reads as current EL value from pstate, which is
|
/* Reads as current EL value from pstate, which is
|
||||||
* guaranteed to be constant by the tb flags.
|
* guaranteed to be constant by the tb flags.
|
||||||
*/
|
*/
|
||||||
tcg_rt = cpu_reg(s, rt);
|
tcg_rt = cpu_reg(s, rt);
|
||||||
tcg_gen_movi_i64(tcg_rt, s->current_el << 2);
|
tcg_gen_movi_i64(tcg_rt, s->current_el << 2);
|
||||||
return;
|
goto exit;
|
||||||
case ARM_CP_DC_ZVA:
|
case ARM_CP_DC_ZVA:
|
||||||
/* Writes clear the aligned block of memory which rt points into. */
|
/* Writes clear the aligned block of memory which rt points into. */
|
||||||
if (s->mte_active[0]) {
|
if (s->mte_active[0]) {
|
||||||
|
@ -2025,7 +2020,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
||||||
tcg_rt = clean_data_tbi(s, cpu_reg(s, rt));
|
tcg_rt = clean_data_tbi(s, cpu_reg(s, rt));
|
||||||
}
|
}
|
||||||
gen_helper_dc_zva(cpu_env, tcg_rt);
|
gen_helper_dc_zva(cpu_env, tcg_rt);
|
||||||
return;
|
goto exit;
|
||||||
case ARM_CP_DC_GVA:
|
case ARM_CP_DC_GVA:
|
||||||
{
|
{
|
||||||
TCGv_i64 clean_addr, tag;
|
TCGv_i64 clean_addr, tag;
|
||||||
|
@ -2046,7 +2041,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
||||||
tcg_temp_free_i64(tag);
|
tcg_temp_free_i64(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
goto exit;
|
||||||
case ARM_CP_DC_GZVA:
|
case ARM_CP_DC_GZVA:
|
||||||
{
|
{
|
||||||
TCGv_i64 clean_addr, tag;
|
TCGv_i64 clean_addr, tag;
|
||||||
|
@ -2064,16 +2059,16 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
||||||
tcg_temp_free_i64(tag);
|
tcg_temp_free_i64(tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
goto exit;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) {
|
if ((ri->type & ARM_CP_FPU) && !fp_access_check_only(s)) {
|
||||||
return;
|
goto exit;
|
||||||
} else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) {
|
} else if ((ri->type & ARM_CP_SVE) && !sve_access_check(s)) {
|
||||||
return;
|
goto exit;
|
||||||
} else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) {
|
} else if ((ri->type & ARM_CP_SME) && !sme_access_check(s)) {
|
||||||
return;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
||||||
|
@ -2086,16 +2081,22 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
||||||
if (ri->type & ARM_CP_CONST) {
|
if (ri->type & ARM_CP_CONST) {
|
||||||
tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
|
tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
|
||||||
} else if (ri->readfn) {
|
} else if (ri->readfn) {
|
||||||
gen_helper_get_cp_reg64(tcg_rt, cpu_env, tcg_constant_ptr(ri));
|
if (!tcg_ri) {
|
||||||
|
tcg_ri = gen_lookup_cp_reg(key);
|
||||||
|
}
|
||||||
|
gen_helper_get_cp_reg64(tcg_rt, cpu_env, tcg_ri);
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset);
|
tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ri->type & ARM_CP_CONST) {
|
if (ri->type & ARM_CP_CONST) {
|
||||||
/* If not forbidden by access permissions, treat as WI */
|
/* If not forbidden by access permissions, treat as WI */
|
||||||
return;
|
goto exit;
|
||||||
} else if (ri->writefn) {
|
} else if (ri->writefn) {
|
||||||
gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri), tcg_rt);
|
if (!tcg_ri) {
|
||||||
|
tcg_ri = gen_lookup_cp_reg(key);
|
||||||
|
}
|
||||||
|
gen_helper_set_cp_reg64(cpu_env, tcg_ri, tcg_rt);
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset);
|
tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset);
|
||||||
}
|
}
|
||||||
|
@ -2118,6 +2119,11 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
|
||||||
*/
|
*/
|
||||||
s->base.is_jmp = DISAS_UPDATE_EXIT;
|
s->base.is_jmp = DISAS_UPDATE_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (tcg_ri) {
|
||||||
|
tcg_temp_free_ptr(tcg_ri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* System
|
/* System
|
||||||
|
|
|
@ -4714,221 +4714,237 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64,
|
||||||
int opc1, int crn, int crm, int opc2,
|
int opc1, int crn, int crm, int opc2,
|
||||||
bool isread, int rt, int rt2)
|
bool isread, int rt, int rt2)
|
||||||
{
|
{
|
||||||
const ARMCPRegInfo *ri;
|
uint32_t key = ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2);
|
||||||
|
const ARMCPRegInfo *ri = get_arm_cp_reginfo(s->cp_regs, key);
|
||||||
|
TCGv_ptr tcg_ri = NULL;
|
||||||
|
bool need_exit_tb;
|
||||||
|
|
||||||
ri = get_arm_cp_reginfo(s->cp_regs,
|
if (!ri) {
|
||||||
ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2));
|
/*
|
||||||
if (ri) {
|
* Unknown register; this might be a guest error or a QEMU
|
||||||
bool need_exit_tb;
|
* unimplemented feature.
|
||||||
|
*/
|
||||||
/* Check access permissions */
|
if (is64) {
|
||||||
if (!cp_access_ok(s->current_el, ri, isread)) {
|
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
|
||||||
unallocated_encoding(s);
|
"64 bit system register cp:%d opc1: %d crm:%d "
|
||||||
return;
|
"(%s)\n",
|
||||||
}
|
isread ? "read" : "write", cpnum, opc1, crm,
|
||||||
|
s->ns ? "non-secure" : "secure");
|
||||||
if (s->hstr_active || ri->accessfn ||
|
|
||||||
(arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) {
|
|
||||||
/* Emit code to perform further access permissions checks at
|
|
||||||
* runtime; this may result in an exception.
|
|
||||||
* Note that on XScale all cp0..c13 registers do an access check
|
|
||||||
* call in order to handle c15_cpar.
|
|
||||||
*/
|
|
||||||
uint32_t syndrome;
|
|
||||||
|
|
||||||
/* Note that since we are an implementation which takes an
|
|
||||||
* exception on a trapped conditional instruction only if the
|
|
||||||
* instruction passes its condition code check, we can take
|
|
||||||
* advantage of the clause in the ARM ARM that allows us to set
|
|
||||||
* the COND field in the instruction to 0xE in all cases.
|
|
||||||
* We could fish the actual condition out of the insn (ARM)
|
|
||||||
* or the condexec bits (Thumb) but it isn't necessary.
|
|
||||||
*/
|
|
||||||
switch (cpnum) {
|
|
||||||
case 14:
|
|
||||||
if (is64) {
|
|
||||||
syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
|
|
||||||
isread, false);
|
|
||||||
} else {
|
|
||||||
syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
|
|
||||||
rt, isread, false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 15:
|
|
||||||
if (is64) {
|
|
||||||
syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
|
|
||||||
isread, false);
|
|
||||||
} else {
|
|
||||||
syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
|
|
||||||
rt, isread, false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* ARMv8 defines that only coprocessors 14 and 15 exist,
|
|
||||||
* so this can only happen if this is an ARMv7 or earlier CPU,
|
|
||||||
* in which case the syndrome information won't actually be
|
|
||||||
* guest visible.
|
|
||||||
*/
|
|
||||||
assert(!arm_dc_feature(s, ARM_FEATURE_V8));
|
|
||||||
syndrome = syn_uncategorized();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
gen_set_condexec(s);
|
|
||||||
gen_update_pc(s, 0);
|
|
||||||
gen_helper_access_check_cp_reg(cpu_env,
|
|
||||||
tcg_constant_ptr(ri),
|
|
||||||
tcg_constant_i32(syndrome),
|
|
||||||
tcg_constant_i32(isread));
|
|
||||||
} else if (ri->type & ARM_CP_RAISES_EXC) {
|
|
||||||
/*
|
|
||||||
* The readfn or writefn might raise an exception;
|
|
||||||
* synchronize the CPU state in case it does.
|
|
||||||
*/
|
|
||||||
gen_set_condexec(s);
|
|
||||||
gen_update_pc(s, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle special cases first */
|
|
||||||
switch (ri->type & ARM_CP_SPECIAL_MASK) {
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
case ARM_CP_NOP:
|
|
||||||
return;
|
|
||||||
case ARM_CP_WFI:
|
|
||||||
if (isread) {
|
|
||||||
unallocated_encoding(s);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gen_update_pc(s, curr_insn_len(s));
|
|
||||||
s->base.is_jmp = DISAS_WFI;
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
g_assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
|
||||||
gen_io_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isread) {
|
|
||||||
/* Read */
|
|
||||||
if (is64) {
|
|
||||||
TCGv_i64 tmp64;
|
|
||||||
TCGv_i32 tmp;
|
|
||||||
if (ri->type & ARM_CP_CONST) {
|
|
||||||
tmp64 = tcg_constant_i64(ri->resetvalue);
|
|
||||||
} else if (ri->readfn) {
|
|
||||||
tmp64 = tcg_temp_new_i64();
|
|
||||||
gen_helper_get_cp_reg64(tmp64, cpu_env,
|
|
||||||
tcg_constant_ptr(ri));
|
|
||||||
} else {
|
|
||||||
tmp64 = tcg_temp_new_i64();
|
|
||||||
tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset);
|
|
||||||
}
|
|
||||||
tmp = tcg_temp_new_i32();
|
|
||||||
tcg_gen_extrl_i64_i32(tmp, tmp64);
|
|
||||||
store_reg(s, rt, tmp);
|
|
||||||
tmp = tcg_temp_new_i32();
|
|
||||||
tcg_gen_extrh_i64_i32(tmp, tmp64);
|
|
||||||
tcg_temp_free_i64(tmp64);
|
|
||||||
store_reg(s, rt2, tmp);
|
|
||||||
} else {
|
|
||||||
TCGv_i32 tmp;
|
|
||||||
if (ri->type & ARM_CP_CONST) {
|
|
||||||
tmp = tcg_constant_i32(ri->resetvalue);
|
|
||||||
} else if (ri->readfn) {
|
|
||||||
tmp = tcg_temp_new_i32();
|
|
||||||
gen_helper_get_cp_reg(tmp, cpu_env, tcg_constant_ptr(ri));
|
|
||||||
} else {
|
|
||||||
tmp = load_cpu_offset(ri->fieldoffset);
|
|
||||||
}
|
|
||||||
if (rt == 15) {
|
|
||||||
/* Destination register of r15 for 32 bit loads sets
|
|
||||||
* the condition codes from the high 4 bits of the value
|
|
||||||
*/
|
|
||||||
gen_set_nzcv(tmp);
|
|
||||||
tcg_temp_free_i32(tmp);
|
|
||||||
} else {
|
|
||||||
store_reg(s, rt, tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* Write */
|
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
|
||||||
if (ri->type & ARM_CP_CONST) {
|
"system register cp:%d opc1:%d crn:%d crm:%d "
|
||||||
/* If not forbidden by access permissions, treat as WI */
|
"opc2:%d (%s)\n",
|
||||||
return;
|
isread ? "read" : "write", cpnum, opc1, crn,
|
||||||
}
|
crm, opc2, s->ns ? "non-secure" : "secure");
|
||||||
|
|
||||||
if (is64) {
|
|
||||||
TCGv_i32 tmplo, tmphi;
|
|
||||||
TCGv_i64 tmp64 = tcg_temp_new_i64();
|
|
||||||
tmplo = load_reg(s, rt);
|
|
||||||
tmphi = load_reg(s, rt2);
|
|
||||||
tcg_gen_concat_i32_i64(tmp64, tmplo, tmphi);
|
|
||||||
tcg_temp_free_i32(tmplo);
|
|
||||||
tcg_temp_free_i32(tmphi);
|
|
||||||
if (ri->writefn) {
|
|
||||||
gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri),
|
|
||||||
tmp64);
|
|
||||||
} else {
|
|
||||||
tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset);
|
|
||||||
}
|
|
||||||
tcg_temp_free_i64(tmp64);
|
|
||||||
} else {
|
|
||||||
TCGv_i32 tmp = load_reg(s, rt);
|
|
||||||
if (ri->writefn) {
|
|
||||||
gen_helper_set_cp_reg(cpu_env, tcg_constant_ptr(ri), tmp);
|
|
||||||
tcg_temp_free_i32(tmp);
|
|
||||||
} else {
|
|
||||||
store_cpu_offset(tmp, ri->fieldoffset, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
unallocated_encoding(s);
|
||||||
/* I/O operations must end the TB here (whether read or write) */
|
|
||||||
need_exit_tb = ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) &&
|
|
||||||
(ri->type & ARM_CP_IO));
|
|
||||||
|
|
||||||
if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
|
|
||||||
/*
|
|
||||||
* A write to any coprocessor register that ends a TB
|
|
||||||
* must rebuild the hflags for the next TB.
|
|
||||||
*/
|
|
||||||
gen_rebuild_hflags(s, ri->type & ARM_CP_NEWEL);
|
|
||||||
/*
|
|
||||||
* We default to ending the TB on a coprocessor register write,
|
|
||||||
* but allow this to be suppressed by the register definition
|
|
||||||
* (usually only necessary to work around guest bugs).
|
|
||||||
*/
|
|
||||||
need_exit_tb = true;
|
|
||||||
}
|
|
||||||
if (need_exit_tb) {
|
|
||||||
gen_lookup_tb(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unknown register; this might be a guest error or a QEMU
|
/* Check access permissions */
|
||||||
* unimplemented feature.
|
if (!cp_access_ok(s->current_el, ri, isread)) {
|
||||||
*/
|
unallocated_encoding(s);
|
||||||
if (is64) {
|
return;
|
||||||
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
|
|
||||||
"64 bit system register cp:%d opc1: %d crm:%d "
|
|
||||||
"(%s)\n",
|
|
||||||
isread ? "read" : "write", cpnum, opc1, crm,
|
|
||||||
s->ns ? "non-secure" : "secure");
|
|
||||||
} else {
|
|
||||||
qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
|
|
||||||
"system register cp:%d opc1:%d crn:%d crm:%d opc2:%d "
|
|
||||||
"(%s)\n",
|
|
||||||
isread ? "read" : "write", cpnum, opc1, crn, crm, opc2,
|
|
||||||
s->ns ? "non-secure" : "secure");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unallocated_encoding(s);
|
if (s->hstr_active || ri->accessfn ||
|
||||||
return;
|
(arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) {
|
||||||
|
/*
|
||||||
|
* Emit code to perform further access permissions checks at
|
||||||
|
* runtime; this may result in an exception.
|
||||||
|
* Note that on XScale all cp0..c13 registers do an access check
|
||||||
|
* call in order to handle c15_cpar.
|
||||||
|
*/
|
||||||
|
uint32_t syndrome;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that since we are an implementation which takes an
|
||||||
|
* exception on a trapped conditional instruction only if the
|
||||||
|
* instruction passes its condition code check, we can take
|
||||||
|
* advantage of the clause in the ARM ARM that allows us to set
|
||||||
|
* the COND field in the instruction to 0xE in all cases.
|
||||||
|
* We could fish the actual condition out of the insn (ARM)
|
||||||
|
* or the condexec bits (Thumb) but it isn't necessary.
|
||||||
|
*/
|
||||||
|
switch (cpnum) {
|
||||||
|
case 14:
|
||||||
|
if (is64) {
|
||||||
|
syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
|
||||||
|
isread, false);
|
||||||
|
} else {
|
||||||
|
syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
|
||||||
|
rt, isread, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
if (is64) {
|
||||||
|
syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
|
||||||
|
isread, false);
|
||||||
|
} else {
|
||||||
|
syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
|
||||||
|
rt, isread, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* ARMv8 defines that only coprocessors 14 and 15 exist,
|
||||||
|
* so this can only happen if this is an ARMv7 or earlier CPU,
|
||||||
|
* in which case the syndrome information won't actually be
|
||||||
|
* guest visible.
|
||||||
|
*/
|
||||||
|
assert(!arm_dc_feature(s, ARM_FEATURE_V8));
|
||||||
|
syndrome = syn_uncategorized();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gen_set_condexec(s);
|
||||||
|
gen_update_pc(s, 0);
|
||||||
|
tcg_ri = tcg_temp_new_ptr();
|
||||||
|
gen_helper_access_check_cp_reg(tcg_ri, cpu_env,
|
||||||
|
tcg_constant_i32(key),
|
||||||
|
tcg_constant_i32(syndrome),
|
||||||
|
tcg_constant_i32(isread));
|
||||||
|
} else if (ri->type & ARM_CP_RAISES_EXC) {
|
||||||
|
/*
|
||||||
|
* The readfn or writefn might raise an exception;
|
||||||
|
* synchronize the CPU state in case it does.
|
||||||
|
*/
|
||||||
|
gen_set_condexec(s);
|
||||||
|
gen_update_pc(s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle special cases first */
|
||||||
|
switch (ri->type & ARM_CP_SPECIAL_MASK) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case ARM_CP_NOP:
|
||||||
|
goto exit;
|
||||||
|
case ARM_CP_WFI:
|
||||||
|
if (isread) {
|
||||||
|
unallocated_encoding(s);
|
||||||
|
} else {
|
||||||
|
gen_update_pc(s, curr_insn_len(s));
|
||||||
|
s->base.is_jmp = DISAS_WFI;
|
||||||
|
}
|
||||||
|
goto exit;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
|
||||||
|
gen_io_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isread) {
|
||||||
|
/* Read */
|
||||||
|
if (is64) {
|
||||||
|
TCGv_i64 tmp64;
|
||||||
|
TCGv_i32 tmp;
|
||||||
|
if (ri->type & ARM_CP_CONST) {
|
||||||
|
tmp64 = tcg_constant_i64(ri->resetvalue);
|
||||||
|
} else if (ri->readfn) {
|
||||||
|
if (!tcg_ri) {
|
||||||
|
tcg_ri = gen_lookup_cp_reg(key);
|
||||||
|
}
|
||||||
|
tmp64 = tcg_temp_new_i64();
|
||||||
|
gen_helper_get_cp_reg64(tmp64, cpu_env, tcg_ri);
|
||||||
|
} else {
|
||||||
|
tmp64 = tcg_temp_new_i64();
|
||||||
|
tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset);
|
||||||
|
}
|
||||||
|
tmp = tcg_temp_new_i32();
|
||||||
|
tcg_gen_extrl_i64_i32(tmp, tmp64);
|
||||||
|
store_reg(s, rt, tmp);
|
||||||
|
tmp = tcg_temp_new_i32();
|
||||||
|
tcg_gen_extrh_i64_i32(tmp, tmp64);
|
||||||
|
tcg_temp_free_i64(tmp64);
|
||||||
|
store_reg(s, rt2, tmp);
|
||||||
|
} else {
|
||||||
|
TCGv_i32 tmp;
|
||||||
|
if (ri->type & ARM_CP_CONST) {
|
||||||
|
tmp = tcg_constant_i32(ri->resetvalue);
|
||||||
|
} else if (ri->readfn) {
|
||||||
|
if (!tcg_ri) {
|
||||||
|
tcg_ri = gen_lookup_cp_reg(key);
|
||||||
|
}
|
||||||
|
tmp = tcg_temp_new_i32();
|
||||||
|
gen_helper_get_cp_reg(tmp, cpu_env, tcg_ri);
|
||||||
|
} else {
|
||||||
|
tmp = load_cpu_offset(ri->fieldoffset);
|
||||||
|
}
|
||||||
|
if (rt == 15) {
|
||||||
|
/* Destination register of r15 for 32 bit loads sets
|
||||||
|
* the condition codes from the high 4 bits of the value
|
||||||
|
*/
|
||||||
|
gen_set_nzcv(tmp);
|
||||||
|
tcg_temp_free_i32(tmp);
|
||||||
|
} else {
|
||||||
|
store_reg(s, rt, tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Write */
|
||||||
|
if (ri->type & ARM_CP_CONST) {
|
||||||
|
/* If not forbidden by access permissions, treat as WI */
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is64) {
|
||||||
|
TCGv_i32 tmplo, tmphi;
|
||||||
|
TCGv_i64 tmp64 = tcg_temp_new_i64();
|
||||||
|
tmplo = load_reg(s, rt);
|
||||||
|
tmphi = load_reg(s, rt2);
|
||||||
|
tcg_gen_concat_i32_i64(tmp64, tmplo, tmphi);
|
||||||
|
tcg_temp_free_i32(tmplo);
|
||||||
|
tcg_temp_free_i32(tmphi);
|
||||||
|
if (ri->writefn) {
|
||||||
|
if (!tcg_ri) {
|
||||||
|
tcg_ri = gen_lookup_cp_reg(key);
|
||||||
|
}
|
||||||
|
gen_helper_set_cp_reg64(cpu_env, tcg_ri, tmp64);
|
||||||
|
} else {
|
||||||
|
tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset);
|
||||||
|
}
|
||||||
|
tcg_temp_free_i64(tmp64);
|
||||||
|
} else {
|
||||||
|
TCGv_i32 tmp = load_reg(s, rt);
|
||||||
|
if (ri->writefn) {
|
||||||
|
if (!tcg_ri) {
|
||||||
|
tcg_ri = gen_lookup_cp_reg(key);
|
||||||
|
}
|
||||||
|
gen_helper_set_cp_reg(cpu_env, tcg_ri, tmp);
|
||||||
|
tcg_temp_free_i32(tmp);
|
||||||
|
} else {
|
||||||
|
store_cpu_offset(tmp, ri->fieldoffset, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* I/O operations must end the TB here (whether read or write) */
|
||||||
|
need_exit_tb = ((tb_cflags(s->base.tb) & CF_USE_ICOUNT) &&
|
||||||
|
(ri->type & ARM_CP_IO));
|
||||||
|
|
||||||
|
if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
|
||||||
|
/*
|
||||||
|
* A write to any coprocessor register that ends a TB
|
||||||
|
* must rebuild the hflags for the next TB.
|
||||||
|
*/
|
||||||
|
gen_rebuild_hflags(s, ri->type & ARM_CP_NEWEL);
|
||||||
|
/*
|
||||||
|
* We default to ending the TB on a coprocessor register write,
|
||||||
|
* but allow this to be suppressed by the register definition
|
||||||
|
* (usually only necessary to work around guest bugs).
|
||||||
|
*/
|
||||||
|
need_exit_tb = true;
|
||||||
|
}
|
||||||
|
if (need_exit_tb) {
|
||||||
|
gen_lookup_tb(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (tcg_ri) {
|
||||||
|
tcg_temp_free_ptr(tcg_ri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode XScale DSP or iWMMXt insn (in the copro space, cp=0 or 1) */
|
/* Decode XScale DSP or iWMMXt insn (in the copro space, cp=0 or 1) */
|
||||||
|
|
|
@ -610,6 +610,13 @@ static inline void set_disas_label(DisasContext *s, DisasLabel l)
|
||||||
s->pc_save = l.pc_save;
|
s->pc_save = l.pc_save;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline TCGv_ptr gen_lookup_cp_reg(uint32_t key)
|
||||||
|
{
|
||||||
|
TCGv_ptr ret = tcg_temp_new_ptr();
|
||||||
|
gen_helper_lookup_cp_reg(ret, cpu_env, tcg_constant_i32(key));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helpers for implementing sets of trans_* functions.
|
* Helpers for implementing sets of trans_* functions.
|
||||||
* Defer the implementation of NAME to FUNC, with optional extra arguments.
|
* Defer the implementation of NAME to FUNC, with optional extra arguments.
|
||||||
|
|
Loading…
Reference in New Issue