diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2023-01-23 13:40:28 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2023-01-23 13:40:28 +0000 |
commit | 00b1faea41d283e931256aa78aa975a369ec3ae6 (patch) | |
tree | 11bf566db142db5e6c3ab8e7a333f21ff252ba73 | |
parent | 65cc5ccf06a74c98de73ec683d9a543baa302a12 (diff) | |
parent | 3b07a936d3bfe97b07ddffcfbb532985a88033dd (diff) |
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>
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | hw/arm/Kconfig | 4 | ||||
-rw-r--r-- | hw/arm/musicpal.c | 3 | ||||
-rw-r--r-- | hw/arm/realview.c | 2 | ||||
-rw-r--r-- | hw/arm/versatilepb.c | 2 | ||||
-rw-r--r-- | hw/arm/vexpress.c | 2 | ||||
-rw-r--r-- | hw/i2c/Kconfig | 2 | ||||
-rw-r--r-- | hw/i2c/arm_sbcon_i2c.c (renamed from hw/i2c/versatile_i2c.c) | 39 | ||||
-rw-r--r-- | hw/i2c/bitbang_i2c.c | 82 | ||||
-rw-r--r-- | hw/i2c/meson.build | 2 | ||||
-rw-r--r-- | hw/i2c/trace-events | 7 | ||||
-rw-r--r-- | include/hw/i2c/arm_sbcon_i2c.h | 6 | ||||
-rw-r--r-- | include/hw/i2c/bitbang_i2c.h | 2 | ||||
-rw-r--r-- | linux-user/aarch64/cpu_loop.c | 11 | ||||
-rw-r--r-- | linux-user/aarch64/signal.c | 13 | ||||
-rw-r--r-- | target/arm/cpu.h | 5 | ||||
-rw-r--r-- | target/arm/debug_helper.c | 54 | ||||
-rw-r--r-- | target/arm/helper-sme.h | 3 | ||||
-rw-r--r-- | target/arm/helper.c | 41 | ||||
-rw-r--r-- | target/arm/helper.h | 11 | ||||
-rw-r--r-- | target/arm/m_helper.c | 24 | ||||
-rw-r--r-- | target/arm/mte_helper.c | 2 | ||||
-rw-r--r-- | target/arm/op_helper.c | 27 | ||||
-rw-r--r-- | target/arm/ptw.c | 4 | ||||
-rw-r--r-- | target/arm/sme_helper.c | 37 | ||||
-rw-r--r-- | target/arm/translate-a64.c | 70 | ||||
-rw-r--r-- | target/arm/translate.c | 386 | ||||
-rw-r--r-- | target/arm/translate.h | 7 |
28 files changed, 486 insertions, 363 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 08ad1e5341..c581c11a64 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -942,6 +942,7 @@ M: Peter Maydell <peter.maydell@linaro.org> L: qemu-arm@nongnu.org S: Maintained F: hw/*/versatile* +F: hw/i2c/arm_sbcon_i2c.c F: include/hw/i2c/arm_sbcon_i2c.h F: hw/misc/arm_sysctl.c F: docs/system/arm/versatile.rst diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 19d6b9d95f..2d157de9b8 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -211,7 +211,7 @@ config REALVIEW select PL110 select PL181 # display select PL310 # cache controller - select VERSATILE_I2C + select ARM_SBCON_I2C select DS1338 # I2C RTC+NVRAM select USB_OHCI @@ -481,7 +481,7 @@ config MPS2 select SPLIT_IRQ select UNIMP select CMSDK_APB_WATCHDOG - select VERSATILE_I2C + select ARM_SBCON_I2C config FSL_IMX7 bool diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 73e2b7e4ce..89b66606c3 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -26,6 +26,7 @@ #include "hw/block/flash.h" #include "ui/console.h" #include "hw/i2c/i2c.h" +#include "hw/i2c/bitbang_i2c.h" #include "hw/irq.h" #include "hw/or-irq.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, 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"); lcd_dev = sysbus_create_simple(TYPE_MUSICPAL_LCD, MP_LCD_BASE, NULL); diff --git a/hw/arm/realview.c b/hw/arm/realview.c index d2dc8a8952..a5aa2f046a 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -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_slave_create_simple(i2c, "ds1338", 0x68); diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 43172d72ea..05b9462a5b 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -336,7 +336,7 @@ static void versatile_init(MachineState *machine, int board_id) /* Add PL031 Real Time Clock. */ 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_slave_create_simple(i2c, "ds1338", 0x68); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 757236767b..34b012b528 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -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_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_slave_create_simple(i2c, "sii9022", 0x39); diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index f8ec461be3..14886b35da 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -14,7 +14,7 @@ config SMBUS_EEPROM bool select SMBUS -config VERSATILE_I2C +config ARM_SBCON_I2C bool select BITBANG_I2C diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/arm_sbcon_i2c.c index 3a04ba3969..979ccbe0ed 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/arm_sbcon_i2c.c @@ -29,11 +29,6 @@ #include "qemu/module.h" #include "qom/object.h" -typedef ArmSbconI2CState VersatileI2CState; -DECLARE_INSTANCE_CHECKER(VersatileI2CState, VERSATILE_I2C, - TYPE_VERSATILE_I2C) - - REG32(CONTROL_GET, 0) REG32(CONTROL_SET, 0) @@ -42,10 +37,10 @@ REG32(CONTROL_CLR, 4) #define SCL BIT(0) #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) { - VersatileI2CState *s = (VersatileI2CState *)opaque; + ArmSbconI2CState *s = opaque; switch (offset) { 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) { - VersatileI2CState *s = (VersatileI2CState *)opaque; + ArmSbconI2CState *s = opaque; switch (offset) { 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); } -static const MemoryRegionOps versatile_i2c_ops = { - .read = versatile_i2c_read, - .write = versatile_i2c_write, +static const MemoryRegionOps arm_sbcon_i2c_ops = { + .read = arm_sbcon_i2c_read, + .write = arm_sbcon_i2c_write, .endianness = DEVICE_NATIVE_ENDIAN, }; -static void versatile_i2c_init(Object *obj) +static void arm_sbcon_i2c_init(Object *obj) { DeviceState *dev = DEVICE(obj); - VersatileI2CState *s = VERSATILE_I2C(obj); + ArmSbconI2CState *s = ARM_SBCON_I2C(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); I2CBus *bus; bus = i2c_init_bus(dev, "i2c"); 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); sysbus_init_mmio(sbd, &s->iomem); } -static const TypeInfo versatile_i2c_info = { - .name = TYPE_VERSATILE_I2C, +static const TypeInfo arm_sbcon_i2c_info = { + .name = TYPE_ARM_SBCON_I2C, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(VersatileI2CState), - .instance_init = versatile_i2c_init, + .instance_size = sizeof(ArmSbconI2CState), + .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) diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c index e9a0612a04..bb18954765 100644 --- a/hw/i2c/bitbang_i2c.c +++ b/hw/i2c/bitbang_i2c.c @@ -16,30 +16,57 @@ #include "hw/sysbus.h" #include "qemu/module.h" #include "qom/object.h" +#include "trace.h" + + +/* bitbang_i2c_state enum to name */ +static const char * const sname[] = { +#define NAME(e) [e] = stringify(e) + NAME(STOPPED), + [SENDING_BIT7] = "SENDING_BIT7 (START)", + 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 +}; -//#define DEBUG_BITBANG_I2C - -#ifdef DEBUG_BITBANG_I2C -#define DPRINTF(fmt, ...) \ -do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#endif +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) { - DPRINTF("STOP\n"); if (i2c->current_addr >= 0) i2c_end_transfer(i2c->bus); i2c->current_addr = -1; - i2c->state = STOPPED; + bitbang_i2c_set_state(i2c, STOPPED); } /* Set device data pin. */ 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; - //DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out); + 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); } if (level == 0) { - DPRINTF("START\n"); /* START condition. */ - i2c->state = SENDING_BIT7; + bitbang_i2c_set_state(i2c, SENDING_BIT7); i2c->current_addr = -1; } else { /* STOP condition. */ @@ -96,7 +122,7 @@ int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) case SENDING_BIT7 ... SENDING_BIT0: i2c->buffer = (i2c->buffer << 1) | data; /* will end up in WAITING_FOR_ACK */ - i2c->state++; + bitbang_i2c_set_state(i2c, i2c->state + 1); return bitbang_i2c_ret(i2c, 1); 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) { 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, i2c->current_addr & 1); } else { - DPRINTF("Sent 0x%02x\n", i2c->buffer); + trace_bitbang_i2c_send(i2c->buffer); ret = i2c_send(i2c->bus, i2c->buffer); } if (ret) { /* NACK (either addressing a nonexistent device, or the * 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); return bitbang_i2c_ret(i2c, 1); } if (i2c->current_addr & 1) { - i2c->state = RECEIVING_BIT7; + bitbang_i2c_set_state(i2c, RECEIVING_BIT7); } else { - i2c->state = SENDING_BIT7; + bitbang_i2c_set_state(i2c, SENDING_BIT7); } return bitbang_i2c_ret(i2c, 0); } case RECEIVING_BIT7: i2c->buffer = i2c_recv(i2c->bus); - DPRINTF("RX byte 0x%02x\n", i2c->buffer); + trace_bitbang_i2c_recv(i2c->buffer); /* Fall through... */ case RECEIVING_BIT6 ... RECEIVING_BIT0: data = i2c->buffer >> 7; /* will end up in SENDING_ACK */ - i2c->state++; + bitbang_i2c_set_state(i2c, i2c->state + 1); i2c->buffer <<= 1; return bitbang_i2c_ret(i2c, data); case SENDING_ACK: - i2c->state = RECEIVING_BIT7; if (data != 0) { - DPRINTF("NACKED\n"); - i2c->state = SENT_NACK; + bitbang_i2c_set_state(i2c, SENT_NACK); i2c_nack(i2c->bus); } else { - DPRINTF("ACKED\n"); + bitbang_i2c_set_state(i2c, RECEIVING_BIT7); } return bitbang_i2c_ret(i2c, 1); } @@ -162,13 +186,13 @@ void bitbang_i2c_init(bitbang_i2c_interface *s, I2CBus *bus) /* GPIO interface. */ -#define TYPE_GPIO_I2C "gpio_i2c" OBJECT_DECLARE_SIMPLE_TYPE(GPIOI2CState, GPIO_I2C) struct GPIOI2CState { + /*< private >*/ SysBusDevice parent_obj; + /*< public >*/ - MemoryRegion dummy_iomem; bitbang_i2c_interface bitbang; int last_level; qemu_irq out; @@ -189,12 +213,8 @@ static void gpio_i2c_init(Object *obj) { DeviceState *dev = DEVICE(obj); GPIOI2CState *s = GPIO_I2C(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 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"); bitbang_i2c_init(&s->bitbang, bus); diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index e4c8e14a52..3996564c25 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -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_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_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_PPC4XX', if_true: files('ppc4xx_i2c.c')) i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c')) diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index 52dbd53a23..8e88aa24c1 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -1,5 +1,12 @@ # 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 i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)" diff --git a/include/hw/i2c/arm_sbcon_i2c.h b/include/hw/i2c/arm_sbcon_i2c.h index f54d1e5413..da9b5e8f83 100644 --- a/include/hw/i2c/arm_sbcon_i2c.h +++ b/include/hw/i2c/arm_sbcon_i2c.h @@ -17,12 +17,10 @@ #include "hw/i2c/bitbang_i2c.h" #include "qom/object.h" -#define TYPE_VERSATILE_I2C "versatile_i2c" -#define TYPE_ARM_SBCON_I2C TYPE_VERSATILE_I2C +#define TYPE_ARM_SBCON_I2C "versatile_i2c" typedef struct ArmSbconI2CState ArmSbconI2CState; -DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, ARM_SBCON_I2C, - TYPE_ARM_SBCON_I2C) +DECLARE_INSTANCE_CHECKER(ArmSbconI2CState, ARM_SBCON_I2C, TYPE_ARM_SBCON_I2C) struct ArmSbconI2CState { /*< private >*/ diff --git a/include/hw/i2c/bitbang_i2c.h b/include/hw/i2c/bitbang_i2c.h index 92334e9016..a079e6d70f 100644 --- a/include/hw/i2c/bitbang_i2c.h +++ b/include/hw/i2c/bitbang_i2c.h @@ -3,6 +3,8 @@ #include "hw/i2c/i2c.h" +#define TYPE_GPIO_I2C "gpio_i2c" + typedef struct bitbang_i2c_interface bitbang_i2c_interface; #define BITBANG_I2C_SDA 0 diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 9875d609a9..2e2f7cf218 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -89,15 +89,8 @@ void cpu_loop(CPUARMState *env) switch (trapnr) { case EXCP_SWI: - /* - * On syscall, PSTATE.ZA is preserved, along with the ZA matrix. - * 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); - } + /* On syscall, PSTATE.ZA is preserved, PSTATE.SM is cleared. */ + aarch64_set_svcr(env, 0, R_SVCR_SM_MASK); ret = do_syscall(env, env->xregs[8], env->xregs[0], diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index 6a2c6e06d2..b265cfd470 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -665,17 +665,8 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, env->btype = 2; } - /* - * Invoke the signal handler with both SM and ZA disabled. - * 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); - } + /* Invoke the signal handler with both SM and ZA disabled. */ + aarch64_set_svcr(env, 0, R_SVCR_SM_MASK | R_SVCR_ZA_MASK); if (info) { tswap_siginfo(&frame->info, info); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index bf2bce046d..8cf70693be 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -479,7 +479,7 @@ typedef struct CPUArchState { }; uint64_t c14_cntfrq; /* Counter Frequency 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 */ ARMGenericTimer c14_timer[NUM_GTIMERS]; uint32_t c15_cpar; /* XScale Coprocessor Access Register */ @@ -495,6 +495,7 @@ typedef struct CPUArchState { uint64_t dbgbcr[16]; /* breakpoint control registers */ uint64_t dbgwvr[16]; /* watchpoint value registers */ uint64_t dbgwcr[16]; /* watchpoint control registers */ + uint64_t dbgclaim; /* DBGCLAIM bits */ uint64_t mdscr_el1; uint64_t oslsr_el1; /* OS Lock 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_change_el(CPUARMState *env, int old_el, 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. diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index 2f6ddc0da5..cced3f168d 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -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[] = { /* * DBGDRAR, DBGDSAR: always RAZ since we don't implement memory mapped @@ -665,6 +683,27 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .access = PL0_R, .accessfn = access_tda, .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 * it is unlikely a guest will care. * We don't implement the configurable EL0 access. @@ -715,6 +754,21 @@ static const ARMCPRegInfo debug_cp_reginfo[] = { .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 2, .opc2 = 0, .access = PL1_RW, .accessfn = access_tda, .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[] = { diff --git a/target/arm/helper-sme.h b/target/arm/helper-sme.h index d2d544a696..27eef49a11 100644 --- a/target/arm/helper-sme.h +++ b/target/arm/helper-sme.h @@ -17,8 +17,7 @@ * 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_2(set_pstate_za, TCG_CALL_NO_RWG, void, env, i32) +DEF_HELPER_FLAGS_3(set_svcr, TCG_CALL_NO_RWG, void, env, i32, i32) DEF_HELPER_FLAGS_3(sme_zero, TCG_CALL_NO_RWG, void, env, i32, i32) diff --git a/target/arm/helper.c b/target/arm/helper.c index 22ea8fbe36..72b37b7cf1 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6725,12 +6725,47 @@ static CPAccessResult access_esm(CPUARMState *env, const ARMCPRegInfo *ri, 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, uint64_t value) { - helper_set_pstate_sm(env, FIELD_EX64(value, SVCR, SM)); - helper_set_pstate_za(env, FIELD_EX64(value, SVCR, ZA)); - arm_rebuild_hflags(env); + aarch64_set_svcr(env, value, -1); } static void smcr_write(CPUARMState *env, const ARMCPRegInfo *ri, diff --git a/target/arm/helper.h b/target/arm/helper.h index 92f36d9dbb..018b00ea75 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -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_4(access_check_cp_reg, void, env, ptr, i32, i32) -DEF_HELPER_3(set_cp_reg, void, env, ptr, i32) -DEF_HELPER_2(get_cp_reg, i32, env, ptr) -DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64) -DEF_HELPER_2(get_cp_reg64, i64, env, ptr) +DEF_HELPER_4(access_check_cp_reg, cptr, env, i32, i32, i32) +DEF_HELPER_FLAGS_2(lookup_cp_reg, TCG_CALL_NO_RWG_SE, cptr, env, i32) +DEF_HELPER_3(set_cp_reg, void, env, cptr, i32) +DEF_HELPER_2(get_cp_reg, i32, env, cptr) +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_3(set_r13_banked, void, env, i32, i32) diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 033a4d9261..e7e746ea18 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -879,7 +879,7 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain, } 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_SPSEL_MASK; @@ -2465,11 +2465,17 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) } return env->v7m.primask[M_REG_NS]; case 0x91: /* BASEPRI_NS */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } if (!env->v7m.secure) { return 0; } return env->v7m.basepri[M_REG_NS]; case 0x93: /* FAULTMASK_NS */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } if (!env->v7m.secure) { return 0; } @@ -2515,8 +2521,14 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) return env->v7m.primask[env->v7m.secure]; case 17: /* BASEPRI */ case 18: /* BASEPRI_MAX */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } return env->v7m.basepri[env->v7m.secure]; case 19: /* FAULTMASK */ + if (!arm_feature(env, ARM_FEATURE_M_MAIN)) { + goto bad_reg; + } return env->v7m.faultmask[env->v7m.secure]; default: 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; return; 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; } env->v7m.basepri[M_REG_NS] = val & 0xff; return; 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; } env->v7m.faultmask[M_REG_NS] = val & 1; diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 86b3754838..98bcf59c22 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -142,7 +142,7 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, * Remember these values across the second lookup below, * 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; full = NULL; diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 70672bcd9f..31f89db899 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -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, - uint32_t isread) +const void *HELPER(access_check_cp_reg)(CPUARMState *env, uint32_t key, + uint32_t syndrome, uint32_t isread) { 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; int target_el; + assert(ri != NULL); + if (arm_feature(env, ARM_FEATURE_XSCALE) && ri->cp < 14 && extract32(env->cp15.c15_cpar, ri->cp, 1) == 0) { 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); } if (likely(res == CP_ACCESS_OK)) { - return; + return ri; } 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); } -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; @@ -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; uint32_t res; @@ -734,7 +745,7 @@ uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip) 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; @@ -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; uint64_t res; diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 4bda0590c7..57f3615a66 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -238,8 +238,8 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw, }; GetPhysAddrResult s2 = { }; - if (!get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD, - false, &s2, fi)) { + if (get_phys_addr_lpae(env, &s2ptw, addr, MMU_DATA_LOAD, + false, &s2, fi)) { goto fail; } ptw->out_phys = s2.f.phys_addr; diff --git a/target/arm/sme_helper.c b/target/arm/sme_helper.c index f891306bb9..1e67fcac30 100644 --- a/target/arm/sme_helper.c +++ b/target/arm/sme_helper.c @@ -29,42 +29,9 @@ #include "vec_internal.h" #include "sve_ldst_internal.h" -/* ResetSVEState */ -void arm_reset_sve_state(CPUARMState *env) +void helper_set_svcr(CPUARMState *env, uint32_t val, uint32_t mask) { - 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 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)); - } + aarch64_set_svcr(env, val, mask); } void helper_sme_zero(CPUARMState *env, uint32_t imm, uint32_t svl) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 2ee171f249..52b1b8a1f0 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1841,19 +1841,14 @@ static void handle_msr_i(DisasContext *s, uint32_t insn, goto do_unallocated; } if (sme_access_check(s)) { - bool i = crm & 1; - bool changed = false; - - if ((crm & 2) && i != s->pstate_sm) { - gen_helper_set_pstate_sm(cpu_env, tcg_constant_i32(i)); - changed = true; - } - 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); + int old = s->pstate_sm | (s->pstate_za << 1); + int new = (crm & 1) * 3; + int msk = (crm >> 1) & 3; + + if ((old ^ new) & msk) { + /* At least one bit changes. */ + gen_helper_set_svcr(cpu_env, tcg_constant_i32(new), + tcg_constant_i32(msk)); } else { 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 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; - ri = get_arm_cp_reginfo(s->cp_regs, - ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, - crn, crm, op0, op1, op2)); - if (!ri) { /* Unknown register; this might be a guest error or a QEMU * 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); gen_a64_update_pc(s, 0); - gen_helper_access_check_cp_reg(cpu_env, - tcg_constant_ptr(ri), + 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) { @@ -1993,7 +1988,7 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, case 0: break; case ARM_CP_NOP: - return; + goto exit; case ARM_CP_NZCV: tcg_rt = cpu_reg(s, rt); if (isread) { @@ -2001,14 +1996,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, } else { gen_set_nzcv(tcg_rt); } - return; + goto exit; case ARM_CP_CURRENTEL: /* Reads as current EL value from pstate, which is * guaranteed to be constant by the tb flags. */ tcg_rt = cpu_reg(s, rt); tcg_gen_movi_i64(tcg_rt, s->current_el << 2); - return; + goto exit; case ARM_CP_DC_ZVA: /* Writes clear the aligned block of memory which rt points into. */ 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)); } gen_helper_dc_zva(cpu_env, tcg_rt); - return; + goto exit; case ARM_CP_DC_GVA: { 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); } } - return; + goto exit; case ARM_CP_DC_GZVA: { 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); } } - return; + goto exit; default: g_assert_not_reached(); } 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)) { - return; + goto exit; } 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)) { @@ -2086,16 +2081,22 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, if (ri->type & ARM_CP_CONST) { tcg_gen_movi_i64(tcg_rt, ri->resetvalue); } 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 { tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset); } } else { if (ri->type & ARM_CP_CONST) { /* If not forbidden by access permissions, treat as WI */ - return; + goto exit; } 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 { 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; } + + exit: + if (tcg_ri) { + tcg_temp_free_ptr(tcg_ri); + } } /* System diff --git a/target/arm/translate.c b/target/arm/translate.c index 1dcaefb8e7..365e02fb0b 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4714,221 +4714,237 @@ static void do_coproc_insn(DisasContext *s, int cpnum, int is64, int opc1, int crn, int crm, int opc2, 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, - ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2)); - if (ri) { - bool need_exit_tb; - - /* Check access permissions */ - if (!cp_access_ok(s->current_el, ri, isread)) { - unallocated_encoding(s); - return; + if (!ri) { + /* + * Unknown register; this might be a guest error or a QEMU + * unimplemented feature. + */ + if (is64) { + 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); + return; + } - 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; - } + /* Check access permissions */ + if (!cp_access_ok(s->current_el, ri, isread)) { + unallocated_encoding(s); + return; + } + + 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; - 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) { + /* + * 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: /* - * The readfn or writefn might raise an exception; - * synchronize the CPU state in case it does. + * 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. */ - gen_set_condexec(s); - gen_update_pc(s, 0); + assert(!arm_dc_feature(s, ARM_FEATURE_V8)); + syndrome = syn_uncategorized(); + break; } - /* 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_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; - return; - default: - g_assert_not_reached(); } + 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 ((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); + 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); } - 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); + tmp64 = tcg_temp_new_i64(); + gen_helper_get_cp_reg64(tmp64, cpu_env, tcg_ri); } 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); - } + 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 { - /* Write */ + TCGv_i32 tmp; if (ri->type & ARM_CP_CONST) { - /* If not forbidden by access permissions, treat as WI */ - return; + 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) { - gen_helper_set_cp_reg64(cpu_env, tcg_constant_ptr(ri), - tmp64); - } else { - tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset); + 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); } - tcg_temp_free_i64(tmp64); + gen_helper_set_cp_reg64(cpu_env, tcg_ri, 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); + 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)); + /* 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; + 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; } - - /* Unknown register; this might be a guest error or a QEMU - * unimplemented feature. - */ - if (is64) { - 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"); + if (need_exit_tb) { + gen_lookup_tb(s); } - unallocated_encoding(s); - return; + exit: + if (tcg_ri) { + tcg_temp_free_ptr(tcg_ri); + } } /* Decode XScale DSP or iWMMXt insn (in the copro space, cp=0 or 1) */ diff --git a/target/arm/translate.h b/target/arm/translate.h index 3cdc7dbc2f..f17f095cbe 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -610,6 +610,13 @@ static inline void set_disas_label(DisasContext *s, DisasLabel l) 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. * Defer the implementation of NAME to FUNC, with optional extra arguments. |