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:
Peter Maydell 2023-01-23 13:40:28 +00:00
commit 00b1faea41
28 changed files with 506 additions and 383 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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'))

View File

@ -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)"

View File

@ -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 >*/

View File

@ -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

View File

@ -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],

View File

@ -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);

View File

@ -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.

View File

@ -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[] = {

View File

@ -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)

View File

@ -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,

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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) */

View File

@ -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.