From b98ec6896ee88f1dcdd7098af25bcb6ee0fc50f0 Mon Sep 17 00:00:00 2001 From: Patrick Venture Date: Mon, 12 Apr 2021 12:45:19 -0700 Subject: [PATCH 0001/3028] hw/i2c: name I2CNode list in I2CBus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To enable passing the current_devs field as a parameter, we need to use a named struct type. Tested: BMC firmware with i2c devices booted to userspace. Signed-off-by: Patrick Venture Reviewed-by: Hao Wu Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210412194522.664594-2-venture@google.com> Signed-off-by: Corey Minyard --- include/hw/i2c/i2c.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index 277dd9f2d6..1f7c268c86 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -58,9 +58,11 @@ struct I2CNode { QLIST_ENTRY(I2CNode) next; }; +typedef QLIST_HEAD(I2CNodeList, I2CNode) I2CNodeList; + struct I2CBus { BusState qbus; - QLIST_HEAD(, I2CNode) current_devs; + I2CNodeList current_devs; uint8_t saved_address; bool broadcast; }; From 513ca82d8982463aca98aa01dcf584e0b4fc0982 Mon Sep 17 00:00:00 2001 From: Patrick Venture Date: Mon, 12 Apr 2021 12:45:20 -0700 Subject: [PATCH 0002/3028] hw/i2c: add match method for device search At the start of an i2c transaction, the i2c bus searches its list of children to identify which devices correspond to the address (or broadcast). Now the I2CSlave device has a method "match" that encapsulates the lookup behavior. This allows the behavior to be changed to support devices, such as i2c muxes. Tested: A BMC firmware was booted to userspace and i2c devices were detected. Signed-off-by: Patrick Venture Reviewed-by: Hao Wu Message-Id: <20210412194522.664594-3-venture@google.com> Signed-off-by: Corey Minyard --- hw/i2c/core.c | 23 +++++++++++++++++++---- include/hw/i2c/i2c.h | 11 +++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 21ec52ac5a..d03b0eea5c 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -118,10 +118,9 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { DeviceState *qdev = kid->child; I2CSlave *candidate = I2C_SLAVE(qdev); - if ((candidate->address == address) || (bus->broadcast)) { - node = g_malloc(sizeof(struct I2CNode)); - node->elt = candidate; - QLIST_INSERT_HEAD(&bus->current_devs, node, next); + sc = I2C_SLAVE_GET_CLASS(candidate); + if (sc->match_and_add(candidate, address, bus->broadcast, + &bus->current_devs)) { if (!bus->broadcast) { break; } @@ -290,12 +289,28 @@ I2CSlave *i2c_slave_create_simple(I2CBus *bus, const char *name, uint8_t addr) return dev; } +static bool i2c_slave_match(I2CSlave *candidate, uint8_t address, + bool broadcast, I2CNodeList *current_devs) +{ + if ((candidate->address == address) || (broadcast)) { + I2CNode *node = g_malloc(sizeof(struct I2CNode)); + node->elt = candidate; + QLIST_INSERT_HEAD(current_devs, node, next); + return true; + } + + /* Not found and not broadcast. */ + return false; +} + static void i2c_slave_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); set_bit(DEVICE_CATEGORY_MISC, k->categories); k->bus_type = TYPE_I2C_BUS; device_class_set_props(k, i2c_props); + sc->match_and_add = i2c_slave_match; } static const TypeInfo i2c_slave_type_info = { diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index 1f7c268c86..9b8b95ff4a 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -16,6 +16,7 @@ enum i2c_event { I2C_NACK /* Masker NACKed a receive byte. */ }; +typedef struct I2CNodeList I2CNodeList; #define TYPE_I2C_SLAVE "i2c-slave" OBJECT_DECLARE_TYPE(I2CSlave, I2CSlaveClass, @@ -39,6 +40,16 @@ struct I2CSlaveClass { * return code is not used and should be zero. */ int (*event)(I2CSlave *s, enum i2c_event event); + + /* + * Check if this device matches the address provided. Returns bool of + * true if it matches (or broadcast), and updates the device list, false + * otherwise. + * + * If broadcast is true, match should add the device and return true. + */ + bool (*match_and_add)(I2CSlave *candidate, uint8_t address, bool broadcast, + I2CNodeList *current_devs); }; struct I2CSlave { From 3f9b32595e785c79720ed174198472c3d4d32c03 Mon Sep 17 00:00:00 2001 From: Patrick Venture Date: Mon, 12 Apr 2021 12:45:21 -0700 Subject: [PATCH 0003/3028] hw/i2c: move search to i2c_scan_bus method Moves the search for matching devices on an i2c bus into a separate method. This allows for an object that owns an I2CBus can avoid duplicating this method. Tested: A BMC firmware was booted to userspace and i2c devices were detected. Signed-off-by: Patrick Venture Reviewed-by: Hao Wu Message-Id: <20210412194522.664594-4-venture@google.com> Signed-off-by: Corey Minyard --- hw/i2c/core.c | 38 ++++++++++++++++++++++++++------------ include/hw/i2c/i2c.h | 2 ++ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/hw/i2c/core.c b/hw/i2c/core.c index d03b0eea5c..3a7bae311d 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -77,6 +77,30 @@ int i2c_bus_busy(I2CBus *bus) return !QLIST_EMPTY(&bus->current_devs); } +bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast, + I2CNodeList *current_devs) +{ + BusChild *kid; + + QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { + DeviceState *qdev = kid->child; + I2CSlave *candidate = I2C_SLAVE(qdev); + I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(candidate); + + if (sc->match_and_add(candidate, address, broadcast, current_devs)) { + if (!broadcast) { + return true; + } + } + } + + /* + * If broadcast was true, and the list was full or empty, return true. If + * broadcast was false, return false. + */ + return broadcast; +} + /* TODO: Make this handle multiple masters. */ /* * Start or continue an i2c transaction. When this is called for the @@ -93,7 +117,6 @@ int i2c_bus_busy(I2CBus *bus) */ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) { - BusChild *kid; I2CSlaveClass *sc; I2CNode *node; bool bus_scanned = false; @@ -115,17 +138,8 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) * terminating the previous transaction. */ if (QLIST_EMPTY(&bus->current_devs)) { - QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { - DeviceState *qdev = kid->child; - I2CSlave *candidate = I2C_SLAVE(qdev); - sc = I2C_SLAVE_GET_CLASS(candidate); - if (sc->match_and_add(candidate, address, bus->broadcast, - &bus->current_devs)) { - if (!bus->broadcast) { - break; - } - } - } + /* Disregard whether devices were found. */ + (void)i2c_scan_bus(bus, address, bus->broadcast, &bus->current_devs); bus_scanned = true; } diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index 9b8b95ff4a..ff4129ea70 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -87,6 +87,8 @@ void i2c_nack(I2CBus *bus); int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send); int i2c_send(I2CBus *bus, uint8_t data); uint8_t i2c_recv(I2CBus *bus); +bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast, + I2CNodeList *current_devs); /** * Create an I2C slave device on the heap. From 065177eeceff552a5316bff9435188b50a2da1b6 Mon Sep 17 00:00:00 2001 From: Patrick Venture Date: Mon, 12 Apr 2021 12:45:22 -0700 Subject: [PATCH 0004/3028] hw/i2c: add pca954x i2c-mux switch The pca954x is an i2c mux, and this adds support for two variants of this device: the pca9546 and pca9548. This device is very common on BMCs to route a different channel to each PCIe i2c bus downstream from the BMC. Signed-off-by: Patrick Venture Reviewed-by: Hao Wu Reviewed-by: Havard Skinnemoen Message-Id: <20210412194522.664594-5-venture@google.com> Signed-off-by: Corey Minyard --- MAINTAINERS | 6 + hw/i2c/Kconfig | 4 + hw/i2c/i2c_mux_pca954x.c | 290 +++++++++++++++++++++++++++++++ hw/i2c/meson.build | 1 + hw/i2c/trace-events | 5 + include/hw/i2c/i2c_mux_pca954x.h | 19 ++ 6 files changed, 325 insertions(+) create mode 100644 hw/i2c/i2c_mux_pca954x.c create mode 100644 include/hw/i2c/i2c_mux_pca954x.h diff --git a/MAINTAINERS b/MAINTAINERS index 36055f14c5..34452de9b4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2040,6 +2040,12 @@ S: Maintained F: hw/net/tulip.c F: hw/net/tulip.h +pca954x +M: Patrick Venture +S: Maintained +F: hw/i2c/i2c_mux_pca954x.c +F: include/hw/i2c/i2c_mux_pca954x.h + Generic Loader M: Alistair Francis S: Maintained diff --git a/hw/i2c/Kconfig b/hw/i2c/Kconfig index 09642a6dcb..8d120a25d5 100644 --- a/hw/i2c/Kconfig +++ b/hw/i2c/Kconfig @@ -28,3 +28,7 @@ config IMX_I2C config MPC_I2C bool select I2C + +config PCA954X + bool + select I2C diff --git a/hw/i2c/i2c_mux_pca954x.c b/hw/i2c/i2c_mux_pca954x.c new file mode 100644 index 0000000000..847c59921c --- /dev/null +++ b/hw/i2c/i2c_mux_pca954x.c @@ -0,0 +1,290 @@ +/* + * I2C multiplexer for PCA954x series of I2C multiplexer/switch chips. + * + * Copyright 2021 Google LLC + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/i2c/i2c.h" +#include "hw/i2c/i2c_mux_pca954x.h" +#include "hw/i2c/smbus_slave.h" +#include "hw/qdev-core.h" +#include "hw/sysbus.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/queue.h" +#include "qom/object.h" +#include "trace.h" + +#define PCA9548_CHANNEL_COUNT 8 +#define PCA9546_CHANNEL_COUNT 4 + +/* + * struct Pca954xChannel - The i2c mux device will have N of these states + * that own the i2c channel bus. + * @bus: The owned channel bus. + * @enabled: Is this channel active? + */ +typedef struct Pca954xChannel { + SysBusDevice parent; + + I2CBus *bus; + + bool enabled; +} Pca954xChannel; + +#define TYPE_PCA954X_CHANNEL "pca954x-channel" +#define PCA954X_CHANNEL(obj) \ + OBJECT_CHECK(Pca954xChannel, (obj), TYPE_PCA954X_CHANNEL) + +/* + * struct Pca954xState - The pca954x state object. + * @control: The value written to the mux control. + * @channel: The set of i2c channel buses that act as channels which own the + * i2c children. + */ +typedef struct Pca954xState { + SMBusDevice parent; + + uint8_t control; + + /* The channel i2c buses. */ + Pca954xChannel channel[PCA9548_CHANNEL_COUNT]; +} Pca954xState; + +/* + * struct Pca954xClass - The pca954x class object. + * @nchans: The number of i2c channels this device has. + */ +typedef struct Pca954xClass { + SMBusDeviceClass parent; + + uint8_t nchans; +} Pca954xClass; + +#define TYPE_PCA954X "pca954x" +OBJECT_DECLARE_TYPE(Pca954xState, Pca954xClass, PCA954X) + +/* + * For each channel, if it's enabled, recursively call match on those children. + */ +static bool pca954x_match(I2CSlave *candidate, uint8_t address, + bool broadcast, + I2CNodeList *current_devs) +{ + Pca954xState *mux = PCA954X(candidate); + Pca954xClass *mc = PCA954X_GET_CLASS(mux); + int i; + + /* They are talking to the mux itself (or all devices enabled). */ + if ((candidate->address == address) || broadcast) { + I2CNode *node = g_malloc(sizeof(struct I2CNode)); + node->elt = candidate; + QLIST_INSERT_HEAD(current_devs, node, next); + if (!broadcast) { + return true; + } + } + + for (i = 0; i < mc->nchans; i++) { + if (!mux->channel[i].enabled) { + continue; + } + + if (i2c_scan_bus(mux->channel[i].bus, address, broadcast, + current_devs)) { + if (!broadcast) { + return true; + } + } + } + + /* If we arrived here we didn't find a match, return broadcast. */ + return broadcast; +} + +static void pca954x_enable_channel(Pca954xState *s, uint8_t enable_mask) +{ + Pca954xClass *mc = PCA954X_GET_CLASS(s); + int i; + + /* + * For each channel, check if their bit is set in enable_mask and if yes, + * enable it, otherwise disable, hide it. + */ + for (i = 0; i < mc->nchans; i++) { + if (enable_mask & (1 << i)) { + s->channel[i].enabled = true; + } else { + s->channel[i].enabled = false; + } + } +} + +static void pca954x_write(Pca954xState *s, uint8_t data) +{ + s->control = data; + pca954x_enable_channel(s, data); + + trace_pca954x_write_bytes(data); +} + +static int pca954x_write_data(SMBusDevice *d, uint8_t *buf, uint8_t len) +{ + Pca954xState *s = PCA954X(d); + + if (len == 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__); + return -1; + } + + /* + * len should be 1, because they write one byte to enable/disable channels. + */ + if (len > 1) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: extra data after channel selection mask\n", + __func__); + return -1; + } + + pca954x_write(s, buf[0]); + return 0; +} + +static uint8_t pca954x_read_byte(SMBusDevice *d) +{ + Pca954xState *s = PCA954X(d); + uint8_t data = s->control; + trace_pca954x_read_data(data); + return data; +} + +static void pca954x_enter_reset(Object *obj, ResetType type) +{ + Pca954xState *s = PCA954X(obj); + /* Reset will disable all channels. */ + pca954x_write(s, 0); +} + +I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel) +{ + Pca954xClass *pc = PCA954X_GET_CLASS(mux); + Pca954xState *pca954x = PCA954X(mux); + + g_assert(channel < pc->nchans); + return I2C_BUS(qdev_get_child_bus(DEVICE(&pca954x->channel[channel]), + "i2c-bus")); +} + +static void pca954x_channel_init(Object *obj) +{ + Pca954xChannel *s = PCA954X_CHANNEL(obj); + s->bus = i2c_init_bus(DEVICE(s), "i2c-bus"); + + /* Start all channels as disabled. */ + s->enabled = false; +} + +static void pca954x_channel_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->desc = "Pca954x Channel"; +} + +static void pca9546_class_init(ObjectClass *klass, void *data) +{ + Pca954xClass *s = PCA954X_CLASS(klass); + s->nchans = PCA9546_CHANNEL_COUNT; +} + +static void pca9548_class_init(ObjectClass *klass, void *data) +{ + Pca954xClass *s = PCA954X_CLASS(klass); + s->nchans = PCA9548_CHANNEL_COUNT; +} + +static void pca954x_realize(DeviceState *dev, Error **errp) +{ + Pca954xState *s = PCA954X(dev); + Pca954xClass *c = PCA954X_GET_CLASS(s); + int i; + + /* SMBus modules. Cannot fail. */ + for (i = 0; i < c->nchans; i++) { + sysbus_realize(SYS_BUS_DEVICE(&s->channel[i]), &error_abort); + } +} + +static void pca954x_init(Object *obj) +{ + Pca954xState *s = PCA954X(obj); + Pca954xClass *c = PCA954X_GET_CLASS(obj); + int i; + + /* Only initialize the children we expect. */ + for (i = 0; i < c->nchans; i++) { + object_initialize_child(obj, "channel[*]", &s->channel[i], + TYPE_PCA954X_CHANNEL); + } +} + +static void pca954x_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + SMBusDeviceClass *k = SMBUS_DEVICE_CLASS(klass); + + sc->match_and_add = pca954x_match; + + rc->phases.enter = pca954x_enter_reset; + + dc->desc = "Pca954x i2c-mux"; + dc->realize = pca954x_realize; + + k->write_data = pca954x_write_data; + k->receive_byte = pca954x_read_byte; +} + +static const TypeInfo pca954x_info[] = { + { + .name = TYPE_PCA954X, + .parent = TYPE_SMBUS_DEVICE, + .instance_size = sizeof(Pca954xState), + .instance_init = pca954x_init, + .class_size = sizeof(Pca954xClass), + .class_init = pca954x_class_init, + .abstract = true, + }, + { + .name = TYPE_PCA9546, + .parent = TYPE_PCA954X, + .class_init = pca9546_class_init, + }, + { + .name = TYPE_PCA9548, + .parent = TYPE_PCA954X, + .class_init = pca9548_class_init, + }, + { + .name = TYPE_PCA954X_CHANNEL, + .parent = TYPE_SYS_BUS_DEVICE, + .class_init = pca954x_channel_class_init, + .instance_size = sizeof(Pca954xChannel), + .instance_init = pca954x_channel_init, + } +}; + +DEFINE_TYPES(pca954x_info) diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index cdcd694a7f..dd3aef02b2 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -14,4 +14,5 @@ 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_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')) softmmu_ss.add_all(when: 'CONFIG_I2C', if_true: i2c_ss) diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events index 82fe6f965f..82f19e6a2d 100644 --- a/hw/i2c/trace-events +++ b/hw/i2c/trace-events @@ -26,3 +26,8 @@ npcm7xx_smbus_recv_byte(const char *id, uint8_t value) "%s recv byte: 0x%02x" npcm7xx_smbus_stop(const char *id) "%s stopping" npcm7xx_smbus_nack(const char *id) "%s nacking" npcm7xx_smbus_recv_fifo(const char *id, uint8_t received, uint8_t expected) "%s recv fifo: received %u, expected %u" + +# i2c-mux-pca954x.c + +pca954x_write_bytes(uint8_t value) "PCA954X write data: 0x%02x" +pca954x_read_data(uint8_t value) "PCA954X read data: 0x%02x" diff --git a/include/hw/i2c/i2c_mux_pca954x.h b/include/hw/i2c/i2c_mux_pca954x.h new file mode 100644 index 0000000000..8aaf9bbc39 --- /dev/null +++ b/include/hw/i2c/i2c_mux_pca954x.h @@ -0,0 +1,19 @@ +#ifndef QEMU_I2C_MUX_PCA954X +#define QEMU_I2C_MUX_PCA954X + +#include "hw/i2c/i2c.h" + +#define TYPE_PCA9546 "pca9546" +#define TYPE_PCA9548 "pca9548" + +/** + * Retrieves the i2c bus associated with the specified channel on this i2c + * mux. + * @mux: an i2c mux device. + * @channel: the i2c channel requested + * + * Returns: a pointer to the associated i2c bus. + */ +I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel); + +#endif From 609d7596524ab204ccd71ef42c9eee4c7c338ea4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 29 Apr 2021 18:05:29 +0100 Subject: [PATCH 0005/3028] Update version for v6.0.0 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e479d55a5e..09b254e90c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.2.95 +6.0.0 From ccdf06c1db192152ac70a1dd974c624f566cb7d4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 11:15:40 +0100 Subject: [PATCH 0006/3028] Open 6.1 development tree Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 09b254e90c..cc94f6b803 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.0 +6.0.50 From bf559ee4025adaf9713e22def862d31f1db5994e Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Wed, 31 Mar 2021 14:47:13 +0800 Subject: [PATCH 0007/3028] hw/arm/smmuv3: Support 16K translation granule The driver can query some bits in SMMUv3 IDR5 to learn which translation granules are supported. Arm recommends that SMMUv3 implementations support at least 4K and 64K granules. But in the vSMMUv3, there seems to be no reason not to support 16K translation granule. In addition, if 16K is not supported, vSVA will failed to be enabled in the future for 16K guest kernel. So it'd better to support it. Signed-off-by: Kunkun Jiang Reviewed-by: Eric Auger Tested-by: Eric Auger Signed-off-by: Peter Maydell --- hw/arm/smmuv3.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 8705612535..228dc54b0b 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -259,8 +259,9 @@ static void smmuv3_init_regs(SMMUv3State *s) s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1); s->idr[3] = FIELD_DP32(s->idr[3], IDR3, HAD, 1); - /* 4K and 64K granule support */ + /* 4K, 16K and 64K granule support */ s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1); + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, 1); s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN64K, 1); s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */ @@ -503,7 +504,8 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event) tg = CD_TG(cd, i); tt->granule_sz = tg2granule(tg, i); - if ((tt->granule_sz != 12 && tt->granule_sz != 16) || CD_ENDI(cd)) { + if ((tt->granule_sz != 12 && tt->granule_sz != 14 && + tt->granule_sz != 16) || CD_ENDI(cd)) { goto bad_cd; } From 8196fe9d83d6519128b514f332418bae06513970 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 8 Apr 2021 17:24:02 +0100 Subject: [PATCH 0008/3028] target/arm: Make Thumb store insns UNDEF for Rn==1111 The Arm ARM specifies that for Thumb encodings of the various plain store insns, if the Rn field is 1111 then we must UNDEF. This is different from the Arm encodings, where this case is either UNPREDICTABLE or has well-defined behaviour. The exclusive stores, store-release and STRD do not have this UNDEF case for any encoding. Enforce the UNDEF for this case in the Thumb plain store insns. Fixes: https://bugs.launchpad.net/qemu/+bug/1922887 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210408162402.5822-1-peter.maydell@linaro.org --- target/arm/translate.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/target/arm/translate.c b/target/arm/translate.c index 7103da2d7a..68809e08f0 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -6476,6 +6476,14 @@ static bool op_store_rr(DisasContext *s, arg_ldst_rr *a, ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w) | ISSIsWrite; TCGv_i32 addr, tmp; + /* + * In Thumb encodings of stores Rn=1111 is UNDEF; for Arm it + * is either UNPREDICTABLE or has defined behaviour + */ + if (s->thumb && a->rn == 15) { + return false; + } + addr = op_addr_rr_pre(s, a); tmp = load_reg(s, a->rt); @@ -6620,6 +6628,14 @@ static bool op_store_ri(DisasContext *s, arg_ldst_ri *a, ISSInfo issinfo = make_issinfo(s, a->rt, a->p, a->w) | ISSIsWrite; TCGv_i32 addr, tmp; + /* + * In Thumb encodings of stores Rn=1111 is UNDEF; for Arm it + * is either UNPREDICTABLE or has defined behaviour + */ + if (s->thumb && a->rn == 15) { + return false; + } + addr = op_addr_ri_pre(s, a); tmp = load_reg(s, a->rt); From 98f96050aacb1f48956413832ae36392169801a1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Apr 2021 11:30:58 -0700 Subject: [PATCH 0009/3028] target/arm: Fix mte_checkN We were incorrectly assuming that only the first byte of an MTE access is checked against the tags. But per the ARM, unaligned accesses are pre-decomposed into single-byte accesses. So by the time we reach the actual MTE check in the ARM pseudocode, all accesses are aligned. Therefore, the first failure is always either the first byte of the access, or the first byte of the granule. In addition, some of the arithmetic is off for last-first -> count. This does not become directly visible until a later patch that passes single bytes into this function, so ptr == ptr_last. Buglink: https://bugs.launchpad.net/bugs/1921948 Signed-off-by: Richard Henderson Message-id: 20210416183106.1516563-2-richard.henderson@linaro.org Reviewed-by: Peter Maydell [PMM: tweaked a comment] Signed-off-by: Peter Maydell --- target/arm/mte_helper.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 8be17e1b70..010d1c2e99 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -757,10 +757,10 @@ uint64_t mte_checkN(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra) { int mmu_idx, ptr_tag, bit55; - uint64_t ptr_last, ptr_end, prev_page, next_page; - uint64_t tag_first, tag_end; - uint64_t tag_byte_first, tag_byte_end; - uint32_t esize, total, tag_count, tag_size, n, c; + uint64_t ptr_last, prev_page, next_page; + uint64_t tag_first, tag_last; + uint64_t tag_byte_first, tag_byte_last; + uint32_t total, tag_count, tag_size, n, c; uint8_t *mem1, *mem2; MMUAccessType type; @@ -779,29 +779,27 @@ uint64_t mte_checkN(CPUARMState *env, uint32_t desc, mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX); type = FIELD_EX32(desc, MTEDESC, WRITE) ? MMU_DATA_STORE : MMU_DATA_LOAD; - esize = FIELD_EX32(desc, MTEDESC, ESIZE); total = FIELD_EX32(desc, MTEDESC, TSIZE); - /* Find the addr of the end of the access, and of the last element. */ - ptr_end = ptr + total; - ptr_last = ptr_end - esize; + /* Find the addr of the end of the access */ + ptr_last = ptr + total - 1; /* Round the bounds to the tag granule, and compute the number of tags. */ tag_first = QEMU_ALIGN_DOWN(ptr, TAG_GRANULE); - tag_end = QEMU_ALIGN_UP(ptr_last, TAG_GRANULE); - tag_count = (tag_end - tag_first) / TAG_GRANULE; + tag_last = QEMU_ALIGN_DOWN(ptr_last, TAG_GRANULE); + tag_count = ((tag_last - tag_first) / TAG_GRANULE) + 1; /* Round the bounds to twice the tag granule, and compute the bytes. */ tag_byte_first = QEMU_ALIGN_DOWN(ptr, 2 * TAG_GRANULE); - tag_byte_end = QEMU_ALIGN_UP(ptr_last, 2 * TAG_GRANULE); + tag_byte_last = QEMU_ALIGN_DOWN(ptr_last, 2 * TAG_GRANULE); /* Locate the page boundaries. */ prev_page = ptr & TARGET_PAGE_MASK; next_page = prev_page + TARGET_PAGE_SIZE; - if (likely(tag_end - prev_page <= TARGET_PAGE_SIZE)) { + if (likely(tag_last - prev_page <= TARGET_PAGE_SIZE)) { /* Memory access stays on one page. */ - tag_size = (tag_byte_end - tag_byte_first) / (2 * TAG_GRANULE); + tag_size = ((tag_byte_last - tag_byte_first) / (2 * TAG_GRANULE)) + 1; mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, total, MMU_DATA_LOAD, tag_size, ra); if (!mem1) { @@ -815,9 +813,9 @@ uint64_t mte_checkN(CPUARMState *env, uint32_t desc, mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, next_page - ptr, MMU_DATA_LOAD, tag_size, ra); - tag_size = (tag_byte_end - next_page) / (2 * TAG_GRANULE); + tag_size = ((tag_byte_last - next_page) / (2 * TAG_GRANULE)) + 1; mem2 = allocation_tag_mem(env, mmu_idx, next_page, type, - ptr_end - next_page, + ptr_last - next_page + 1, MMU_DATA_LOAD, tag_size, ra); /* @@ -838,15 +836,13 @@ uint64_t mte_checkN(CPUARMState *env, uint32_t desc, } /* - * If we failed, we know which granule. Compute the element that - * is first in that granule, and signal failure on that element. + * If we failed, we know which granule. For the first granule, the + * failure address is @ptr, the first byte accessed. Otherwise the + * failure address is the first byte of the nth granule. */ if (unlikely(n < tag_count)) { - uint64_t fail_ofs; - - fail_ofs = tag_first + n * TAG_GRANULE - ptr; - fail_ofs = ROUND_UP(fail_ofs, esize); - mte_check_fail(env, desc, ptr + fail_ofs, ra); + uint64_t fault = (n == 0 ? ptr : tag_first + n * TAG_GRANULE); + mte_check_fail(env, desc, fault, ra); } done: From f8c8a8606071b2966f83ebaccc69714ac3cad548 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Apr 2021 11:30:59 -0700 Subject: [PATCH 0010/3028] target/arm: Split out mte_probe_int MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split out a helper function from mte_checkN to perform all of the checking and address manpulation. So far, just use this in mte_checkN itself. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20210416183106.1516563-3-richard.henderson@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target/arm/mte_helper.c | 52 +++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 010d1c2e99..2b5331f8db 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -753,33 +753,45 @@ static int checkN(uint8_t *mem, int odd, int cmp, int count) return n; } -uint64_t mte_checkN(CPUARMState *env, uint32_t desc, - uint64_t ptr, uintptr_t ra) +/** + * mte_probe_int() - helper for mte_probe and mte_check + * @env: CPU environment + * @desc: MTEDESC descriptor + * @ptr: virtual address of the base of the access + * @fault: return virtual address of the first check failure + * + * Internal routine for both mte_probe and mte_check. + * Return zero on failure, filling in *fault. + * Return negative on trivial success for tbi disabled. + * Return positive on success with tbi enabled. + */ +static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr, + uintptr_t ra, uint32_t total, uint64_t *fault) { int mmu_idx, ptr_tag, bit55; uint64_t ptr_last, prev_page, next_page; uint64_t tag_first, tag_last; uint64_t tag_byte_first, tag_byte_last; - uint32_t total, tag_count, tag_size, n, c; + uint32_t tag_count, tag_size, n, c; uint8_t *mem1, *mem2; MMUAccessType type; bit55 = extract64(ptr, 55, 1); + *fault = ptr; /* If TBI is disabled, the access is unchecked, and ptr is not dirty. */ if (unlikely(!tbi_check(desc, bit55))) { - return ptr; + return -1; } ptr_tag = allocation_tag_from_addr(ptr); if (tcma_check(desc, bit55, ptr_tag)) { - goto done; + return 1; } mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX); type = FIELD_EX32(desc, MTEDESC, WRITE) ? MMU_DATA_STORE : MMU_DATA_LOAD; - total = FIELD_EX32(desc, MTEDESC, TSIZE); /* Find the addr of the end of the access */ ptr_last = ptr + total - 1; @@ -803,7 +815,7 @@ uint64_t mte_checkN(CPUARMState *env, uint32_t desc, mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, total, MMU_DATA_LOAD, tag_size, ra); if (!mem1) { - goto done; + return 1; } /* Perform all of the comparisons. */ n = checkN(mem1, ptr & TAG_GRANULE, ptr_tag, tag_count); @@ -829,23 +841,39 @@ uint64_t mte_checkN(CPUARMState *env, uint32_t desc, } if (n == c) { if (!mem2) { - goto done; + return 1; } n += checkN(mem2, 0, ptr_tag, tag_count - c); } } + if (likely(n == tag_count)) { + return 1; + } + /* * If we failed, we know which granule. For the first granule, the * failure address is @ptr, the first byte accessed. Otherwise the * failure address is the first byte of the nth granule. */ - if (unlikely(n < tag_count)) { - uint64_t fault = (n == 0 ? ptr : tag_first + n * TAG_GRANULE); - mte_check_fail(env, desc, fault, ra); + if (n > 0) { + *fault = tag_first + n * TAG_GRANULE; } + return 0; +} - done: +uint64_t mte_checkN(CPUARMState *env, uint32_t desc, + uint64_t ptr, uintptr_t ra) +{ + uint64_t fault; + uint32_t total = FIELD_EX32(desc, MTEDESC, TSIZE); + int ret = mte_probe_int(env, desc, ptr, ra, total, &fault); + + if (unlikely(ret == 0)) { + mte_check_fail(env, desc, fault, ra); + } else if (ret < 0) { + return ptr; + } return useronly_clean_ptr(ptr); } From 4a09a21345e8adb4734ecb5be59bac9c4d82aa85 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Apr 2021 11:31:00 -0700 Subject: [PATCH 0011/3028] target/arm: Fix unaligned checks for mte_check1, mte_probe1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were incorrectly assuming that only the first byte of an MTE access is checked against the tags. But per the ARM, unaligned accesses are pre-decomposed into single-byte accesses. So by the time we reach the actual MTE check in the ARM pseudocode, all accesses are aligned. We cannot tell a priori whether or not a given scalar access is aligned, therefore we must at least check. Use mte_probe_int, which is already set up for checking multiple granules. Buglink: https://bugs.launchpad.net/bugs/1921948 Tested-by: Alex Bennée Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20210416183106.1516563-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/mte_helper.c | 109 +++++++++++++--------------------------- 1 file changed, 35 insertions(+), 74 deletions(-) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 2b5331f8db..0ee0397eb2 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -617,80 +617,6 @@ static void mte_check_fail(CPUARMState *env, uint32_t desc, } } -/* - * Perform an MTE checked access for a single logical or atomic access. - */ -static bool mte_probe1_int(CPUARMState *env, uint32_t desc, uint64_t ptr, - uintptr_t ra, int bit55) -{ - int mem_tag, mmu_idx, ptr_tag, size; - MMUAccessType type; - uint8_t *mem; - - ptr_tag = allocation_tag_from_addr(ptr); - - if (tcma_check(desc, bit55, ptr_tag)) { - return true; - } - - mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX); - type = FIELD_EX32(desc, MTEDESC, WRITE) ? MMU_DATA_STORE : MMU_DATA_LOAD; - size = FIELD_EX32(desc, MTEDESC, ESIZE); - - mem = allocation_tag_mem(env, mmu_idx, ptr, type, size, - MMU_DATA_LOAD, 1, ra); - if (!mem) { - return true; - } - - mem_tag = load_tag1(ptr, mem); - return ptr_tag == mem_tag; -} - -/* - * No-fault version of mte_check1, to be used by SVE for MemSingleNF. - * Returns false if the access is Checked and the check failed. This - * is only intended to probe the tag -- the validity of the page must - * be checked beforehand. - */ -bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr) -{ - int bit55 = extract64(ptr, 55, 1); - - /* If TBI is disabled, the access is unchecked. */ - if (unlikely(!tbi_check(desc, bit55))) { - return true; - } - - return mte_probe1_int(env, desc, ptr, 0, bit55); -} - -uint64_t mte_check1(CPUARMState *env, uint32_t desc, - uint64_t ptr, uintptr_t ra) -{ - int bit55 = extract64(ptr, 55, 1); - - /* If TBI is disabled, the access is unchecked, and ptr is not dirty. */ - if (unlikely(!tbi_check(desc, bit55))) { - return ptr; - } - - if (unlikely(!mte_probe1_int(env, desc, ptr, ra, bit55))) { - mte_check_fail(env, desc, ptr, ra); - } - - return useronly_clean_ptr(ptr); -} - -uint64_t HELPER(mte_check1)(CPUARMState *env, uint32_t desc, uint64_t ptr) -{ - return mte_check1(env, desc, ptr, GETPC()); -} - -/* - * Perform an MTE checked access for multiple logical accesses. - */ - /** * checkN: * @tag: tag memory to test @@ -882,6 +808,41 @@ uint64_t HELPER(mte_checkN)(CPUARMState *env, uint32_t desc, uint64_t ptr) return mte_checkN(env, desc, ptr, GETPC()); } +uint64_t mte_check1(CPUARMState *env, uint32_t desc, + uint64_t ptr, uintptr_t ra) +{ + uint64_t fault; + uint32_t total = FIELD_EX32(desc, MTEDESC, ESIZE); + int ret = mte_probe_int(env, desc, ptr, ra, total, &fault); + + if (unlikely(ret == 0)) { + mte_check_fail(env, desc, fault, ra); + } else if (ret < 0) { + return ptr; + } + return useronly_clean_ptr(ptr); +} + +uint64_t HELPER(mte_check1)(CPUARMState *env, uint32_t desc, uint64_t ptr) +{ + return mte_check1(env, desc, ptr, GETPC()); +} + +/* + * No-fault version of mte_check1, to be used by SVE for MemSingleNF. + * Returns false if the access is Checked and the check failed. This + * is only intended to probe the tag -- the validity of the page must + * be checked beforehand. + */ +bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr) +{ + uint64_t fault; + uint32_t total = FIELD_EX32(desc, MTEDESC, ESIZE); + int ret = mte_probe_int(env, desc, ptr, 0, total, &fault); + + return ret != 0; +} + /* * Perform an MTE checked access for DC_ZVA. */ From 09641ef93112c45bc32cf86a4999d0e0532909c3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Apr 2021 11:31:01 -0700 Subject: [PATCH 0012/3028] test/tcg/aarch64: Add mte-5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Buglink: https://bugs.launchpad.net/bugs/1921948 Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20210416183106.1516563-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- tests/tcg/aarch64/Makefile.target | 2 +- tests/tcg/aarch64/mte-5.c | 44 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/aarch64/mte-5.c diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 05b2622bfc..928357b10a 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -37,7 +37,7 @@ AARCH64_TESTS += bti-2 # MTE Tests ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_MTE),) -AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-6 +AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-%: CFLAGS += -march=armv8.5-a+memtag endif diff --git a/tests/tcg/aarch64/mte-5.c b/tests/tcg/aarch64/mte-5.c new file mode 100644 index 0000000000..6dbd6ab3ea --- /dev/null +++ b/tests/tcg/aarch64/mte-5.c @@ -0,0 +1,44 @@ +/* + * Memory tagging, faulting unaligned access. + * + * Copyright (c) 2021 Linaro Ltd + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "mte.h" + +void pass(int sig, siginfo_t *info, void *uc) +{ + assert(info->si_code == SEGV_MTESERR); + exit(0); +} + +int main(int ac, char **av) +{ + struct sigaction sa; + void *p0, *p1, *p2; + long excl = 1; + + enable_mte(PR_MTE_TCF_SYNC); + p0 = alloc_mte_mem(sizeof(*p0)); + + /* Create two differently tagged pointers. */ + asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl)); + asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1)); + assert(excl != 1); + asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl)); + assert(p1 != p2); + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = pass; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &sa, NULL); + + /* Store store two different tags in sequential granules. */ + asm("stg %0, [%0]" : : "r"(p1)); + asm("stg %0, [%0]" : : "r"(p2 + 16)); + + /* Perform an unaligned load crossing the granules. */ + asm volatile("ldr %0, [%1]" : "=r"(p0) : "r"(p1 + 12)); + abort(); +} From 28f3250306e52ae94df9faab93b9d0167fe6b587 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Apr 2021 11:31:02 -0700 Subject: [PATCH 0013/3028] target/arm: Replace MTEDESC ESIZE+TSIZE with SIZEM1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After recent changes, mte_checkN does not use ESIZE, and mte_check1 never used TSIZE. We can combine the two into a single field: SIZEM1. Choose to pass size - 1 because size == 0 is never used, our immediate need in mte_probe_int is for the address of the last byte (ptr + size - 1), and since almost all operations are powers of 2, this makes the immediate constant one bit smaller. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20210416183106.1516563-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/internals.h | 4 ++-- target/arm/mte_helper.c | 18 ++++++++---------- target/arm/translate-a64.c | 5 ++--- target/arm/translate-sve.c | 5 ++--- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index f11bd32696..2c77f2d50f 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -26,6 +26,7 @@ #define TARGET_ARM_INTERNALS_H #include "hw/registerfields.h" +#include "tcg/tcg-gvec-desc.h" #include "syndrome.h" /* register banks for CPU modes */ @@ -1142,8 +1143,7 @@ FIELD(MTEDESC, MIDX, 0, 4) FIELD(MTEDESC, TBI, 4, 2) FIELD(MTEDESC, TCMA, 6, 2) FIELD(MTEDESC, WRITE, 8, 1) -FIELD(MTEDESC, ESIZE, 9, 5) -FIELD(MTEDESC, TSIZE, 14, 10) /* mte_checkN only */ +FIELD(MTEDESC, SIZEM1, 9, SIMD_DATA_BITS - 9) /* size - 1 */ bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr); uint64_t mte_check1(CPUARMState *env, uint32_t desc, diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 0ee0397eb2..804057d3f6 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -692,13 +692,13 @@ static int checkN(uint8_t *mem, int odd, int cmp, int count) * Return positive on success with tbi enabled. */ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr, - uintptr_t ra, uint32_t total, uint64_t *fault) + uintptr_t ra, uint64_t *fault) { int mmu_idx, ptr_tag, bit55; uint64_t ptr_last, prev_page, next_page; uint64_t tag_first, tag_last; uint64_t tag_byte_first, tag_byte_last; - uint32_t tag_count, tag_size, n, c; + uint32_t sizem1, tag_count, tag_size, n, c; uint8_t *mem1, *mem2; MMUAccessType type; @@ -718,9 +718,10 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr, mmu_idx = FIELD_EX32(desc, MTEDESC, MIDX); type = FIELD_EX32(desc, MTEDESC, WRITE) ? MMU_DATA_STORE : MMU_DATA_LOAD; + sizem1 = FIELD_EX32(desc, MTEDESC, SIZEM1); /* Find the addr of the end of the access */ - ptr_last = ptr + total - 1; + ptr_last = ptr + sizem1; /* Round the bounds to the tag granule, and compute the number of tags. */ tag_first = QEMU_ALIGN_DOWN(ptr, TAG_GRANULE); @@ -738,7 +739,7 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr, if (likely(tag_last - prev_page <= TARGET_PAGE_SIZE)) { /* Memory access stays on one page. */ tag_size = ((tag_byte_last - tag_byte_first) / (2 * TAG_GRANULE)) + 1; - mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, total, + mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, sizem1 + 1, MMU_DATA_LOAD, tag_size, ra); if (!mem1) { return 1; @@ -792,8 +793,7 @@ uint64_t mte_checkN(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra) { uint64_t fault; - uint32_t total = FIELD_EX32(desc, MTEDESC, TSIZE); - int ret = mte_probe_int(env, desc, ptr, ra, total, &fault); + int ret = mte_probe_int(env, desc, ptr, ra, &fault); if (unlikely(ret == 0)) { mte_check_fail(env, desc, fault, ra); @@ -812,8 +812,7 @@ uint64_t mte_check1(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra) { uint64_t fault; - uint32_t total = FIELD_EX32(desc, MTEDESC, ESIZE); - int ret = mte_probe_int(env, desc, ptr, ra, total, &fault); + int ret = mte_probe_int(env, desc, ptr, ra, &fault); if (unlikely(ret == 0)) { mte_check_fail(env, desc, fault, ra); @@ -837,8 +836,7 @@ uint64_t HELPER(mte_check1)(CPUARMState *env, uint32_t desc, uint64_t ptr) bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr) { uint64_t fault; - uint32_t total = FIELD_EX32(desc, MTEDESC, ESIZE); - int ret = mte_probe_int(env, desc, ptr, 0, total, &fault); + int ret = mte_probe_int(env, desc, ptr, 0, &fault); return ret != 0; } diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 0b42e53500..3af00ae90e 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -272,7 +272,7 @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr, desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); - desc = FIELD_DP32(desc, MTEDESC, ESIZE, 1 << log2_size); + desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (1 << log2_size) - 1); tcg_desc = tcg_const_i32(desc); ret = new_tmp_a64(s); @@ -306,8 +306,7 @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); - desc = FIELD_DP32(desc, MTEDESC, ESIZE, 1 << log2_esize); - desc = FIELD_DP32(desc, MTEDESC, TSIZE, total_size); + desc = FIELD_DP32(desc, MTEDESC, SIZEM1, total_size - 1); tcg_desc = tcg_const_i32(desc); ret = new_tmp_a64(s); diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 0eefb61214..5179c1f836 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4509,8 +4509,7 @@ static void do_mem_zpa(DisasContext *s, int zt, int pg, TCGv_i64 addr, desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); - desc = FIELD_DP32(desc, MTEDESC, ESIZE, 1 << msz); - desc = FIELD_DP32(desc, MTEDESC, TSIZE, mte_n << msz); + desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (mte_n << msz) - 1); desc <<= SVE_MTEDESC_SHIFT; } else { addr = clean_data_tbi(s, addr); @@ -5189,7 +5188,7 @@ static void do_mem_zpz(DisasContext *s, int zt, int pg, int zm, desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); - desc = FIELD_DP32(desc, MTEDESC, ESIZE, 1 << msz); + desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (1 << msz) - 1); desc <<= SVE_MTEDESC_SHIFT; } desc = simd_desc(vsz, vsz, desc | scale); From bd47b61c5ebc8c5f696910644125a28115d3f6ea Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Apr 2021 11:31:03 -0700 Subject: [PATCH 0014/3028] target/arm: Merge mte_check1, mte_checkN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mte_check1 and mte_checkN functions are now identical. Drop mte_check1 and rename mte_checkN to mte_check. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20210416183106.1516563-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper-a64.h | 3 +-- target/arm/internals.h | 5 +---- target/arm/mte_helper.c | 26 +++----------------------- target/arm/sve_helper.c | 14 +++++++------- target/arm/translate-a64.c | 4 ++-- 5 files changed, 14 insertions(+), 38 deletions(-) diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h index c139fa81f9..7b706571bb 100644 --- a/target/arm/helper-a64.h +++ b/target/arm/helper-a64.h @@ -104,8 +104,7 @@ DEF_HELPER_FLAGS_3(autdb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_2(xpaci, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64) -DEF_HELPER_FLAGS_3(mte_check1, TCG_CALL_NO_WG, i64, env, i32, i64) -DEF_HELPER_FLAGS_3(mte_checkN, TCG_CALL_NO_WG, i64, env, i32, i64) +DEF_HELPER_FLAGS_3(mte_check, TCG_CALL_NO_WG, i64, env, i32, i64) DEF_HELPER_FLAGS_3(mte_check_zva, TCG_CALL_NO_WG, i64, env, i32, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_4(addsubg, TCG_CALL_NO_RWG_SE, i64, env, i64, s32, i32) diff --git a/target/arm/internals.h b/target/arm/internals.h index 2c77f2d50f..af1db2cd9c 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1146,10 +1146,7 @@ FIELD(MTEDESC, WRITE, 8, 1) FIELD(MTEDESC, SIZEM1, 9, SIMD_DATA_BITS - 9) /* size - 1 */ bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr); -uint64_t mte_check1(CPUARMState *env, uint32_t desc, - uint64_t ptr, uintptr_t ra); -uint64_t mte_checkN(CPUARMState *env, uint32_t desc, - uint64_t ptr, uintptr_t ra); +uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra); static inline int allocation_tag_from_addr(uint64_t ptr) { diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 804057d3f6..c91d561ce3 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -789,8 +789,7 @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr, return 0; } -uint64_t mte_checkN(CPUARMState *env, uint32_t desc, - uint64_t ptr, uintptr_t ra) +uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra) { uint64_t fault; int ret = mte_probe_int(env, desc, ptr, ra, &fault); @@ -803,28 +802,9 @@ uint64_t mte_checkN(CPUARMState *env, uint32_t desc, return useronly_clean_ptr(ptr); } -uint64_t HELPER(mte_checkN)(CPUARMState *env, uint32_t desc, uint64_t ptr) +uint64_t HELPER(mte_check)(CPUARMState *env, uint32_t desc, uint64_t ptr) { - return mte_checkN(env, desc, ptr, GETPC()); -} - -uint64_t mte_check1(CPUARMState *env, uint32_t desc, - uint64_t ptr, uintptr_t ra) -{ - uint64_t fault; - int ret = mte_probe_int(env, desc, ptr, ra, &fault); - - if (unlikely(ret == 0)) { - mte_check_fail(env, desc, fault, ra); - } else if (ret < 0) { - return ptr; - } - return useronly_clean_ptr(ptr); -} - -uint64_t HELPER(mte_check1)(CPUARMState *env, uint32_t desc, uint64_t ptr) -{ - return mte_check1(env, desc, ptr, GETPC()); + return mte_check(env, desc, ptr, GETPC()); } /* diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index fd6c58f96a..b63ddfc7f9 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4442,7 +4442,7 @@ static void sve_cont_ldst_mte_check1(SVEContLdSt *info, CPUARMState *env, uintptr_t ra) { sve_cont_ldst_mte_check_int(info, env, vg, addr, esize, msize, - mtedesc, ra, mte_check1); + mtedesc, ra, mte_check); } static void sve_cont_ldst_mte_checkN(SVEContLdSt *info, CPUARMState *env, @@ -4451,7 +4451,7 @@ static void sve_cont_ldst_mte_checkN(SVEContLdSt *info, CPUARMState *env, uintptr_t ra) { sve_cont_ldst_mte_check_int(info, env, vg, addr, esize, msize, - mtedesc, ra, mte_checkN); + mtedesc, ra, mte_check); } @@ -4826,7 +4826,7 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, if (fault == FAULT_FIRST) { /* Trapping mte check for the first-fault element. */ if (mtedesc) { - mte_check1(env, mtedesc, addr + mem_off, retaddr); + mte_check(env, mtedesc, addr + mem_off, retaddr); } /* @@ -5373,7 +5373,7 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, info.attrs, BP_MEM_READ, retaddr); } if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) { - mte_check1(env, mtedesc, addr, retaddr); + mte_check(env, mtedesc, addr, retaddr); } host_fn(&scratch, reg_off, info.host); } else { @@ -5386,7 +5386,7 @@ void sve_ld1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, BP_MEM_READ, retaddr); } if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) { - mte_check1(env, mtedesc, addr, retaddr); + mte_check(env, mtedesc, addr, retaddr); } tlb_fn(env, &scratch, reg_off, addr, retaddr); } @@ -5552,7 +5552,7 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, */ addr = base + (off_fn(vm, reg_off) << scale); if (mtedesc) { - mte_check1(env, mtedesc, addr, retaddr); + mte_check(env, mtedesc, addr, retaddr); } tlb_fn(env, vd, reg_off, addr, retaddr); @@ -5773,7 +5773,7 @@ void sve_st1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, } if (mtedesc && arm_tlb_mte_tagged(&info.attrs)) { - mte_check1(env, mtedesc, addr, retaddr); + mte_check(env, mtedesc, addr, retaddr); } } i += 1; diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 3af00ae90e..a68d5dd5d1 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -276,7 +276,7 @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr, tcg_desc = tcg_const_i32(desc); ret = new_tmp_a64(s); - gen_helper_mte_check1(ret, cpu_env, tcg_desc, addr); + gen_helper_mte_check(ret, cpu_env, tcg_desc, addr); tcg_temp_free_i32(tcg_desc); return ret; @@ -310,7 +310,7 @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, tcg_desc = tcg_const_i32(desc); ret = new_tmp_a64(s); - gen_helper_mte_checkN(ret, cpu_env, tcg_desc, addr); + gen_helper_mte_check(ret, cpu_env, tcg_desc, addr); tcg_temp_free_i32(tcg_desc); return ret; From d304d280b3167289323f3f2c6c2fbfa1dfe8d1d7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Apr 2021 11:31:04 -0700 Subject: [PATCH 0015/3028] target/arm: Rename mte_probe1 to mte_probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency with the mte_check1 + mte_checkN merge to mte_check, rename the probe function as well. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20210416183106.1516563-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/internals.h | 2 +- target/arm/mte_helper.c | 6 +++--- target/arm/sve_helper.c | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index af1db2cd9c..886db56b58 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1145,7 +1145,7 @@ FIELD(MTEDESC, TCMA, 6, 2) FIELD(MTEDESC, WRITE, 8, 1) FIELD(MTEDESC, SIZEM1, 9, SIMD_DATA_BITS - 9) /* size - 1 */ -bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr); +bool mte_probe(CPUARMState *env, uint32_t desc, uint64_t ptr); uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra); static inline int allocation_tag_from_addr(uint64_t ptr) diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index c91d561ce3..a6fccc6e69 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -121,7 +121,7 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, * exception for inaccessible pages, and resolves the virtual address * into the softmmu tlb. * - * When RA == 0, this is for mte_probe1. The page is expected to be + * When RA == 0, this is for mte_probe. The page is expected to be * valid. Indicate to probe_access_flags no-fault, then assert that * we received a valid page. */ @@ -808,12 +808,12 @@ uint64_t HELPER(mte_check)(CPUARMState *env, uint32_t desc, uint64_t ptr) } /* - * No-fault version of mte_check1, to be used by SVE for MemSingleNF. + * No-fault version of mte_check, to be used by SVE for MemSingleNF. * Returns false if the access is Checked and the check failed. This * is only intended to probe the tag -- the validity of the page must * be checked beforehand. */ -bool mte_probe1(CPUARMState *env, uint32_t desc, uint64_t ptr) +bool mte_probe(CPUARMState *env, uint32_t desc, uint64_t ptr) { uint64_t fault; int ret = mte_probe_int(env, desc, ptr, 0, &fault); diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index b63ddfc7f9..982240d104 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4869,7 +4869,7 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, /* Watchpoint hit, see below. */ goto do_fault; } - if (mtedesc && !mte_probe1(env, mtedesc, addr + mem_off)) { + if (mtedesc && !mte_probe(env, mtedesc, addr + mem_off)) { goto do_fault; } /* @@ -4919,7 +4919,7 @@ void sve_ldnfff1_r(CPUARMState *env, void *vg, const target_ulong addr, & BP_MEM_READ)) { goto do_fault; } - if (mtedesc && !mte_probe1(env, mtedesc, addr + mem_off)) { + if (mtedesc && !mte_probe(env, mtedesc, addr + mem_off)) { goto do_fault; } host_fn(vd, reg_off, host + mem_off); @@ -5588,7 +5588,7 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm, } if (mtedesc && arm_tlb_mte_tagged(&info.attrs) && - !mte_probe1(env, mtedesc, addr)) { + !mte_probe(env, mtedesc, addr)) { goto fault; } From 4c3310c73f7349f1aabae55a7babd6419eeb1d04 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Apr 2021 11:31:05 -0700 Subject: [PATCH 0016/3028] target/arm: Simplify sve mte checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that mte_check1 and mte_checkN have been merged, we can merge sve_cont_ldst_mte_check1 and sve_cont_ldst_mte_checkN. Which means that we can eliminate the function pointer into sve_ldN_r and sve_stN_r, calling sve_cont_ldst_mte_check directly. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20210416183106.1516563-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/sve_helper.c | 84 +++++++++++++---------------------------- 1 file changed, 26 insertions(+), 58 deletions(-) diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c index 982240d104..c068dfa0d5 100644 --- a/target/arm/sve_helper.c +++ b/target/arm/sve_helper.c @@ -4382,13 +4382,9 @@ static void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, #endif } -typedef uint64_t mte_check_fn(CPUARMState *, uint32_t, uint64_t, uintptr_t); - -static inline QEMU_ALWAYS_INLINE -void sve_cont_ldst_mte_check_int(SVEContLdSt *info, CPUARMState *env, - uint64_t *vg, target_ulong addr, int esize, - int msize, uint32_t mtedesc, uintptr_t ra, - mte_check_fn *check) +static void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env, + uint64_t *vg, target_ulong addr, int esize, + int msize, uint32_t mtedesc, uintptr_t ra) { intptr_t mem_off, reg_off, reg_last; @@ -4405,7 +4401,7 @@ void sve_cont_ldst_mte_check_int(SVEContLdSt *info, CPUARMState *env, uint64_t pg = vg[reg_off >> 6]; do { if ((pg >> (reg_off & 63)) & 1) { - check(env, mtedesc, addr, ra); + mte_check(env, mtedesc, addr, ra); } reg_off += esize; mem_off += msize; @@ -4422,7 +4418,7 @@ void sve_cont_ldst_mte_check_int(SVEContLdSt *info, CPUARMState *env, uint64_t pg = vg[reg_off >> 6]; do { if ((pg >> (reg_off & 63)) & 1) { - check(env, mtedesc, addr, ra); + mte_check(env, mtedesc, addr, ra); } reg_off += esize; mem_off += msize; @@ -4431,30 +4427,6 @@ void sve_cont_ldst_mte_check_int(SVEContLdSt *info, CPUARMState *env, } } -typedef void sve_cont_ldst_mte_check_fn(SVEContLdSt *info, CPUARMState *env, - uint64_t *vg, target_ulong addr, - int esize, int msize, uint32_t mtedesc, - uintptr_t ra); - -static void sve_cont_ldst_mte_check1(SVEContLdSt *info, CPUARMState *env, - uint64_t *vg, target_ulong addr, - int esize, int msize, uint32_t mtedesc, - uintptr_t ra) -{ - sve_cont_ldst_mte_check_int(info, env, vg, addr, esize, msize, - mtedesc, ra, mte_check); -} - -static void sve_cont_ldst_mte_checkN(SVEContLdSt *info, CPUARMState *env, - uint64_t *vg, target_ulong addr, - int esize, int msize, uint32_t mtedesc, - uintptr_t ra) -{ - sve_cont_ldst_mte_check_int(info, env, vg, addr, esize, msize, - mtedesc, ra, mte_check); -} - - /* * Common helper for all contiguous 1,2,3,4-register predicated stores. */ @@ -4463,8 +4435,7 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, uint32_t desc, const uintptr_t retaddr, const int esz, const int msz, const int N, uint32_t mtedesc, sve_ldst1_host_fn *host_fn, - sve_ldst1_tlb_fn *tlb_fn, - sve_cont_ldst_mte_check_fn *mte_check_fn) + sve_ldst1_tlb_fn *tlb_fn) { const unsigned rd = simd_data(desc); const intptr_t reg_max = simd_oprsz(desc); @@ -4493,9 +4464,9 @@ void sve_ldN_r(CPUARMState *env, uint64_t *vg, const target_ulong addr, * Handle mte checks for all active elements. * Since TBI must be set for MTE, !mtedesc => !mte_active. */ - if (mte_check_fn && mtedesc) { - mte_check_fn(&info, env, vg, addr, 1 << esz, N << msz, - mtedesc, retaddr); + if (mtedesc) { + sve_cont_ldst_mte_check(&info, env, vg, addr, 1 << esz, N << msz, + mtedesc, retaddr); } flags = info.page[0].flags | info.page[1].flags; @@ -4621,8 +4592,7 @@ void sve_ldN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr, mtedesc = 0; } - sve_ldN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn, - N == 1 ? sve_cont_ldst_mte_check1 : sve_cont_ldst_mte_checkN); + sve_ldN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn); } #define DO_LD1_1(NAME, ESZ) \ @@ -4630,7 +4600,7 @@ void HELPER(sve_##NAME##_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, 1, 0, \ - sve_##NAME##_host, sve_##NAME##_tlb, NULL); \ + sve_##NAME##_host, sve_##NAME##_tlb); \ } \ void HELPER(sve_##NAME##_r_mte)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ @@ -4644,22 +4614,22 @@ void HELPER(sve_##NAME##_le_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, 0, \ - sve_##NAME##_le_host, sve_##NAME##_le_tlb, NULL); \ + sve_##NAME##_le_host, sve_##NAME##_le_tlb); \ } \ void HELPER(sve_##NAME##_be_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, 0, \ - sve_##NAME##_be_host, sve_##NAME##_be_tlb, NULL); \ + sve_##NAME##_be_host, sve_##NAME##_be_tlb); \ } \ void HELPER(sve_##NAME##_le_r_mte)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ + target_ulong addr, uint32_t desc) \ { \ sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \ sve_##NAME##_le_host, sve_##NAME##_le_tlb); \ } \ void HELPER(sve_##NAME##_be_r_mte)(CPUARMState *env, void *vg, \ - target_ulong addr, uint32_t desc) \ + target_ulong addr, uint32_t desc) \ { \ sve_ldN_r_mte(env, vg, addr, desc, GETPC(), ESZ, MSZ, 1, \ sve_##NAME##_be_host, sve_##NAME##_be_tlb); \ @@ -4693,7 +4663,7 @@ void HELPER(sve_ld##N##bb_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ sve_ldN_r(env, vg, addr, desc, GETPC(), MO_8, MO_8, N, 0, \ - sve_ld1bb_host, sve_ld1bb_tlb, NULL); \ + sve_ld1bb_host, sve_ld1bb_tlb); \ } \ void HELPER(sve_ld##N##bb_r_mte)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ @@ -4707,13 +4677,13 @@ void HELPER(sve_ld##N##SUFF##_le_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, 0, \ - sve_ld1##SUFF##_le_host, sve_ld1##SUFF##_le_tlb, NULL); \ + sve_ld1##SUFF##_le_host, sve_ld1##SUFF##_le_tlb); \ } \ void HELPER(sve_ld##N##SUFF##_be_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ sve_ldN_r(env, vg, addr, desc, GETPC(), ESZ, ESZ, N, 0, \ - sve_ld1##SUFF##_be_host, sve_ld1##SUFF##_be_tlb, NULL); \ + sve_ld1##SUFF##_be_host, sve_ld1##SUFF##_be_tlb); \ } \ void HELPER(sve_ld##N##SUFF##_le_r_mte)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ @@ -5090,8 +5060,7 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, uint32_t desc, const uintptr_t retaddr, const int esz, const int msz, const int N, uint32_t mtedesc, sve_ldst1_host_fn *host_fn, - sve_ldst1_tlb_fn *tlb_fn, - sve_cont_ldst_mte_check_fn *mte_check_fn) + sve_ldst1_tlb_fn *tlb_fn) { const unsigned rd = simd_data(desc); const intptr_t reg_max = simd_oprsz(desc); @@ -5117,9 +5086,9 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, * Handle mte checks for all active elements. * Since TBI must be set for MTE, !mtedesc => !mte_active. */ - if (mte_check_fn && mtedesc) { - mte_check_fn(&info, env, vg, addr, 1 << esz, N << msz, - mtedesc, retaddr); + if (mtedesc) { + sve_cont_ldst_mte_check(&info, env, vg, addr, 1 << esz, N << msz, + mtedesc, retaddr); } flags = info.page[0].flags | info.page[1].flags; @@ -5233,8 +5202,7 @@ void sve_stN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr, mtedesc = 0; } - sve_stN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn, - N == 1 ? sve_cont_ldst_mte_check1 : sve_cont_ldst_mte_checkN); + sve_stN_r(env, vg, addr, desc, ra, esz, msz, N, mtedesc, host_fn, tlb_fn); } #define DO_STN_1(N, NAME, ESZ) \ @@ -5242,7 +5210,7 @@ void HELPER(sve_st##N##NAME##_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MO_8, N, 0, \ - sve_st1##NAME##_host, sve_st1##NAME##_tlb, NULL); \ + sve_st1##NAME##_host, sve_st1##NAME##_tlb); \ } \ void HELPER(sve_st##N##NAME##_r_mte)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ @@ -5256,13 +5224,13 @@ void HELPER(sve_st##N##NAME##_le_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, 0, \ - sve_st1##NAME##_le_host, sve_st1##NAME##_le_tlb, NULL); \ + sve_st1##NAME##_le_host, sve_st1##NAME##_le_tlb); \ } \ void HELPER(sve_st##N##NAME##_be_r)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ { \ sve_stN_r(env, vg, addr, desc, GETPC(), ESZ, MSZ, N, 0, \ - sve_st1##NAME##_be_host, sve_st1##NAME##_be_tlb, NULL); \ + sve_st1##NAME##_be_host, sve_st1##NAME##_be_tlb); \ } \ void HELPER(sve_st##N##NAME##_le_r_mte)(CPUARMState *env, void *vg, \ target_ulong addr, uint32_t desc) \ From 33e74c3172defc841692b4281d2dbd8f8a966e17 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 16 Apr 2021 11:31:06 -0700 Subject: [PATCH 0017/3028] target/arm: Remove log2_esize parameter to gen_mte_checkN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The log2_esize parameter is not used except trivially. Drop the parameter and the deferral to gen_mte_check1. This fixes a bug in that the parameters as documented in the header file were the reverse from those in the implementation. Which meant that translate-sve.c was passing the parameters in the wrong order. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson Message-id: 20210416183106.1516563-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 15 +++++++-------- target/arm/translate-a64.h | 2 +- target/arm/translate-sve.c | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index a68d5dd5d1..f35a5e8174 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -295,9 +295,9 @@ TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write, * For MTE, check multiple logical sequential accesses. */ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, - bool tag_checked, int log2_esize, int total_size) + bool tag_checked, int size) { - if (tag_checked && s->mte_active[0] && total_size != (1 << log2_esize)) { + if (tag_checked && s->mte_active[0]) { TCGv_i32 tcg_desc; TCGv_i64 ret; int desc = 0; @@ -306,7 +306,7 @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); - desc = FIELD_DP32(desc, MTEDESC, SIZEM1, total_size - 1); + desc = FIELD_DP32(desc, MTEDESC, SIZEM1, size - 1); tcg_desc = tcg_const_i32(desc); ret = new_tmp_a64(s); @@ -315,7 +315,7 @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, return ret; } - return gen_mte_check1(s, addr, is_write, tag_checked, log2_esize); + return clean_data_tbi(s, addr); } typedef struct DisasCompare64 { @@ -2965,8 +2965,7 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) } clean_addr = gen_mte_checkN(s, dirty_addr, !is_load, - (wback || rn != 31) && !set_tag, - size, 2 << size); + (wback || rn != 31) && !set_tag, 2 << size); if (is_vector) { if (is_load) { @@ -3713,7 +3712,7 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) * promote consecutive little-endian elements below. */ clean_addr = gen_mte_checkN(s, tcg_rn, is_store, is_postidx || rn != 31, - size, total); + total); /* * Consecutive little-endian elements from a single register @@ -3866,7 +3865,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) tcg_rn = cpu_reg_sp(s, rn); clean_addr = gen_mte_checkN(s, tcg_rn, !is_load, is_postidx || rn != 31, - scale, total); + total); tcg_ebytes = tcg_const_i64(1 << scale); for (xs = 0; xs < selem; xs++) { diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index 3668b671dd..868d355048 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -44,7 +44,7 @@ TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr); TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write, bool tag_checked, int log2_size); TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, - bool tag_checked, int count, int log2_esize); + bool tag_checked, int size); /* We should have at some point before trying to access an FP register * done the necessary access check, so assert that diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 5179c1f836..584c4d047c 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -4264,7 +4264,7 @@ static void do_ldr(DisasContext *s, uint32_t vofs, int len, int rn, int imm) dirty_addr = tcg_temp_new_i64(); tcg_gen_addi_i64(dirty_addr, cpu_reg_sp(s, rn), imm); - clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len, MO_8); + clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len); tcg_temp_free_i64(dirty_addr); /* @@ -4352,7 +4352,7 @@ static void do_str(DisasContext *s, uint32_t vofs, int len, int rn, int imm) dirty_addr = tcg_temp_new_i64(); tcg_gen_addi_i64(dirty_addr, cpu_reg_sp(s, rn), imm); - clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len, MO_8); + clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len); tcg_temp_free_i64(dirty_addr); /* Note that unpredicated load/store of vector/predicate registers From a736cbc303f3c3f79b7b0b09e0dd4e18c8bcf94c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:27 -0700 Subject: [PATCH 0018/3028] target/arm: Fix decode of align in VLDST_single The encoding of size = 2 and size = 3 had the incorrect decode for align, overlapping the stride field. This error was hidden by what should have been unnecessary masking in translate. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/neon-ls.decode | 4 ++-- target/arm/translate-neon.c.inc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/arm/neon-ls.decode b/target/arm/neon-ls.decode index c17f5019e3..0a2a0e15db 100644 --- a/target/arm/neon-ls.decode +++ b/target/arm/neon-ls.decode @@ -46,7 +46,7 @@ VLD_all_lanes 1111 0100 1 . 1 0 rn:4 .... 11 n:2 size:2 t:1 a:1 rm:4 \ VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 00 n:2 reg_idx:3 align:1 rm:4 \ vd=%vd_dp size=0 stride=1 -VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 01 n:2 reg_idx:2 align:2 rm:4 \ +VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 01 n:2 reg_idx:2 . align:1 rm:4 \ vd=%vd_dp size=1 stride=%imm1_5_p1 -VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 10 n:2 reg_idx:1 align:3 rm:4 \ +VLDST_single 1111 0100 1 . l:1 0 rn:4 .... 10 n:2 reg_idx:1 . align:2 rm:4 \ vd=%vd_dp size=2 stride=%imm1_6_p1 diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c.inc index f6c68e30ab..0e5828744b 100644 --- a/target/arm/translate-neon.c.inc +++ b/target/arm/translate-neon.c.inc @@ -606,7 +606,7 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) switch (nregs) { case 1: if (((a->align & (1 << a->size)) != 0) || - (a->size == 2 && ((a->align & 3) == 1 || (a->align & 3) == 2))) { + (a->size == 2 && (a->align == 1 || a->align == 2))) { return false; } break; @@ -621,7 +621,7 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) } break; case 4: - if ((a->size == 2) && ((a->align & 3) == 3)) { + if (a->size == 2 && a->align == 3) { return false; } break; From 6a01eab7d823d8ae7430015e27922370f4bf9107 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:28 -0700 Subject: [PATCH 0019/3028] target/arm: Rename TBFLAG_A32, SCTLR_B We're about to rearrange the macro expansion surrounding tbflags, and this field name will be expanded using the bit definition of the same name, resulting in a token pasting error. So SCTLR_B -> SCTLR__B in the 3 uses, and document it. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 2 +- target/arm/helper.c | 2 +- target/arm/translate.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 193a49ec7f..304e0a6af3 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3423,7 +3423,7 @@ FIELD(TBFLAG_A32, VECSTRIDE, 12, 2) /* Not cached. */ */ FIELD(TBFLAG_A32, XSCALE_CPAR, 12, 2) FIELD(TBFLAG_A32, VFPEN, 14, 1) /* Partially cached, minus FPEXC. */ -FIELD(TBFLAG_A32, SCTLR_B, 15, 1) +FIELD(TBFLAG_A32, SCTLR__B, 15, 1) /* Cannot overlap with SCTLR_B */ FIELD(TBFLAG_A32, HSTR_ACTIVE, 16, 1) /* * Indicates whether cp register reads and writes by guest code should access diff --git a/target/arm/helper.c b/target/arm/helper.c index d9220be7c5..556b9d4f0a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -13003,7 +13003,7 @@ static uint32_t rebuild_hflags_common_32(CPUARMState *env, int fp_el, bool sctlr_b = arm_sctlr_b(env); if (sctlr_b) { - flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR_B, 1); + flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR__B, 1); } if (arm_cpu_data_is_big_endian_a32(env, sctlr_b)) { flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1); diff --git a/target/arm/translate.c b/target/arm/translate.c index 68809e08f0..2de4252953 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8895,7 +8895,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE; dc->debug_target_el = FIELD_EX32(tb_flags, TBFLAG_ANY, DEBUG_TARGET_EL); - dc->sctlr_b = FIELD_EX32(tb_flags, TBFLAG_A32, SCTLR_B); + dc->sctlr_b = FIELD_EX32(tb_flags, TBFLAG_A32, SCTLR__B); dc->hstr_active = FIELD_EX32(tb_flags, TBFLAG_A32, HSTR_ACTIVE); dc->ns = FIELD_EX32(tb_flags, TBFLAG_A32, NS); dc->vfp_enabled = FIELD_EX32(tb_flags, TBFLAG_A32, VFPEN); From ae6eb1e9b3ccc211d96261a5c650e6650b508aa6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:29 -0700 Subject: [PATCH 0020/3028] target/arm: Rename TBFLAG_ANY, PSTATE_SS We're about to rearrange the macro expansion surrounding tbflags, and this field name will be expanded using the bit definition of the same name, resulting in a token pasting error. So PSTATE_SS -> PSTATE__SS in the uses, and document it. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-4-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 2 +- target/arm/helper.c | 4 ++-- target/arm/translate-a64.c | 2 +- target/arm/translate.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 304e0a6af3..4cbf2db3e3 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3396,7 +3396,7 @@ typedef ARMCPU ArchCPU; */ FIELD(TBFLAG_ANY, AARCH64_STATE, 31, 1) FIELD(TBFLAG_ANY, SS_ACTIVE, 30, 1) -FIELD(TBFLAG_ANY, PSTATE_SS, 29, 1) /* Not cached. */ +FIELD(TBFLAG_ANY, PSTATE__SS, 29, 1) /* Not cached. */ FIELD(TBFLAG_ANY, BE_DATA, 28, 1) FIELD(TBFLAG_ANY, MMUIDX, 24, 4) /* Target EL if we take a floating-point-disabled exception */ diff --git a/target/arm/helper.c b/target/arm/helper.c index 556b9d4f0a..cd8dec126f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -13333,11 +13333,11 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, * 0 x Inactive (the TB flag for SS is always 0) * 1 0 Active-pending * 1 1 Active-not-pending - * SS_ACTIVE is set in hflags; PSTATE_SS is computed every TB. + * SS_ACTIVE is set in hflags; PSTATE__SS is computed every TB. */ if (FIELD_EX32(flags, TBFLAG_ANY, SS_ACTIVE) && (env->pstate & PSTATE_SS)) { - flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE_SS, 1); + flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE__SS, 1); } *pflags = flags; diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index f35a5e8174..64b3a5200c 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14733,7 +14733,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, * end the TB */ dc->ss_active = FIELD_EX32(tb_flags, TBFLAG_ANY, SS_ACTIVE); - dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE_SS); + dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE__SS); dc->is_ldex = false; dc->debug_target_el = FIELD_EX32(tb_flags, TBFLAG_ANY, DEBUG_TARGET_EL); diff --git a/target/arm/translate.c b/target/arm/translate.c index 2de4252953..271c53dadb 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8925,7 +8925,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) * end the TB */ dc->ss_active = FIELD_EX32(tb_flags, TBFLAG_ANY, SS_ACTIVE); - dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE_SS); + dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE__SS); dc->is_ldex = false; dc->page_start = dc->base.pc_first & TARGET_PAGE_MASK; From a729a46b05ab09e473cd757ee7a62373a175fa62 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:30 -0700 Subject: [PATCH 0021/3028] target/arm: Add wrapper macros for accessing tbflags We're about to split tbflags into two parts. These macros will ensure that the correct part is used with the correct set of bits. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 22 +++++++++- target/arm/helper-a64.c | 2 +- target/arm/helper.c | 85 +++++++++++++++++--------------------- target/arm/translate-a64.c | 36 ++++++++-------- target/arm/translate.c | 48 ++++++++++----------- 5 files changed, 101 insertions(+), 92 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 4cbf2db3e3..b798ff8115 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3462,6 +3462,26 @@ FIELD(TBFLAG_A64, TCMA, 16, 2) FIELD(TBFLAG_A64, MTE_ACTIVE, 18, 1) FIELD(TBFLAG_A64, MTE0_ACTIVE, 19, 1) +/* + * Helpers for using the above. + */ +#define DP_TBFLAG_ANY(DST, WHICH, VAL) \ + (DST = FIELD_DP32(DST, TBFLAG_ANY, WHICH, VAL)) +#define DP_TBFLAG_A64(DST, WHICH, VAL) \ + (DST = FIELD_DP32(DST, TBFLAG_A64, WHICH, VAL)) +#define DP_TBFLAG_A32(DST, WHICH, VAL) \ + (DST = FIELD_DP32(DST, TBFLAG_A32, WHICH, VAL)) +#define DP_TBFLAG_M32(DST, WHICH, VAL) \ + (DST = FIELD_DP32(DST, TBFLAG_M32, WHICH, VAL)) +#define DP_TBFLAG_AM32(DST, WHICH, VAL) \ + (DST = FIELD_DP32(DST, TBFLAG_AM32, WHICH, VAL)) + +#define EX_TBFLAG_ANY(IN, WHICH) FIELD_EX32(IN, TBFLAG_ANY, WHICH) +#define EX_TBFLAG_A64(IN, WHICH) FIELD_EX32(IN, TBFLAG_A64, WHICH) +#define EX_TBFLAG_A32(IN, WHICH) FIELD_EX32(IN, TBFLAG_A32, WHICH) +#define EX_TBFLAG_M32(IN, WHICH) FIELD_EX32(IN, TBFLAG_M32, WHICH) +#define EX_TBFLAG_AM32(IN, WHICH) FIELD_EX32(IN, TBFLAG_AM32, WHICH) + /** * cpu_mmu_index: * @env: The cpu environment @@ -3472,7 +3492,7 @@ FIELD(TBFLAG_A64, MTE0_ACTIVE, 19, 1) */ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch) { - return FIELD_EX32(env->hflags, TBFLAG_ANY, MMUIDX); + return EX_TBFLAG_ANY(env->hflags, MMUIDX); } static inline bool bswap_code(bool sctlr_b) diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index 061c8ff846..9cc3b066e2 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -1020,7 +1020,7 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc) * the hflags rebuild, since we can pull the composite TBII field * from there. */ - tbii = FIELD_EX32(env->hflags, TBFLAG_A64, TBII); + tbii = EX_TBFLAG_A64(env->hflags, TBII); if ((tbii >> extract64(new_pc, 55, 1)) & 1) { /* TBI is enabled. */ int core_mmu_idx = cpu_mmu_index(env, false); diff --git a/target/arm/helper.c b/target/arm/helper.c index cd8dec126f..2769e6fd35 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12987,12 +12987,11 @@ ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env) static uint32_t rebuild_hflags_common(CPUARMState *env, int fp_el, ARMMMUIdx mmu_idx, uint32_t flags) { - flags = FIELD_DP32(flags, TBFLAG_ANY, FPEXC_EL, fp_el); - flags = FIELD_DP32(flags, TBFLAG_ANY, MMUIDX, - arm_to_core_mmu_idx(mmu_idx)); + DP_TBFLAG_ANY(flags, FPEXC_EL, fp_el); + DP_TBFLAG_ANY(flags, MMUIDX, arm_to_core_mmu_idx(mmu_idx)); if (arm_singlestep_active(env)) { - flags = FIELD_DP32(flags, TBFLAG_ANY, SS_ACTIVE, 1); + DP_TBFLAG_ANY(flags, SS_ACTIVE, 1); } return flags; } @@ -13003,12 +13002,12 @@ static uint32_t rebuild_hflags_common_32(CPUARMState *env, int fp_el, bool sctlr_b = arm_sctlr_b(env); if (sctlr_b) { - flags = FIELD_DP32(flags, TBFLAG_A32, SCTLR__B, 1); + DP_TBFLAG_A32(flags, SCTLR__B, 1); } if (arm_cpu_data_is_big_endian_a32(env, sctlr_b)) { - flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1); + DP_TBFLAG_ANY(flags, BE_DATA, 1); } - flags = FIELD_DP32(flags, TBFLAG_A32, NS, !access_secure_reg(env)); + DP_TBFLAG_A32(flags, NS, !access_secure_reg(env)); return rebuild_hflags_common(env, fp_el, mmu_idx, flags); } @@ -13019,7 +13018,7 @@ static uint32_t rebuild_hflags_m32(CPUARMState *env, int fp_el, uint32_t flags = 0; if (arm_v7m_is_handler_mode(env)) { - flags = FIELD_DP32(flags, TBFLAG_M32, HANDLER, 1); + DP_TBFLAG_M32(flags, HANDLER, 1); } /* @@ -13030,7 +13029,7 @@ static uint32_t rebuild_hflags_m32(CPUARMState *env, int fp_el, if (arm_feature(env, ARM_FEATURE_V8) && !((mmu_idx & ARM_MMU_IDX_M_NEGPRI) && (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKOFHFNMIGN_MASK))) { - flags = FIELD_DP32(flags, TBFLAG_M32, STACKCHECK, 1); + DP_TBFLAG_M32(flags, STACKCHECK, 1); } return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); @@ -13040,8 +13039,7 @@ static uint32_t rebuild_hflags_aprofile(CPUARMState *env) { int flags = 0; - flags = FIELD_DP32(flags, TBFLAG_ANY, DEBUG_TARGET_EL, - arm_debug_target_el(env)); + DP_TBFLAG_ANY(flags, DEBUG_TARGET_EL, arm_debug_target_el(env)); return flags; } @@ -13051,12 +13049,12 @@ static uint32_t rebuild_hflags_a32(CPUARMState *env, int fp_el, uint32_t flags = rebuild_hflags_aprofile(env); if (arm_el_is_aa64(env, 1)) { - flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1); + DP_TBFLAG_A32(flags, VFPEN, 1); } if (arm_current_el(env) < 2 && env->cp15.hstr_el2 && (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { - flags = FIELD_DP32(flags, TBFLAG_A32, HSTR_ACTIVE, 1); + DP_TBFLAG_A32(flags, HSTR_ACTIVE, 1); } return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); @@ -13071,14 +13069,14 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, uint64_t sctlr; int tbii, tbid; - flags = FIELD_DP32(flags, TBFLAG_ANY, AARCH64_STATE, 1); + DP_TBFLAG_ANY(flags, AARCH64_STATE, 1); /* Get control bits for tagged addresses. */ tbid = aa64_va_parameter_tbi(tcr, mmu_idx); tbii = tbid & ~aa64_va_parameter_tbid(tcr, mmu_idx); - flags = FIELD_DP32(flags, TBFLAG_A64, TBII, tbii); - flags = FIELD_DP32(flags, TBFLAG_A64, TBID, tbid); + DP_TBFLAG_A64(flags, TBII, tbii); + DP_TBFLAG_A64(flags, TBID, tbid); if (cpu_isar_feature(aa64_sve, env_archcpu(env))) { int sve_el = sve_exception_el(env, el); @@ -13093,14 +13091,14 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, } else { zcr_len = sve_zcr_len_for_el(env, el); } - flags = FIELD_DP32(flags, TBFLAG_A64, SVEEXC_EL, sve_el); - flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len); + DP_TBFLAG_A64(flags, SVEEXC_EL, sve_el); + DP_TBFLAG_A64(flags, ZCR_LEN, zcr_len); } sctlr = regime_sctlr(env, stage1); if (arm_cpu_data_is_big_endian_a64(el, sctlr)) { - flags = FIELD_DP32(flags, TBFLAG_ANY, BE_DATA, 1); + DP_TBFLAG_ANY(flags, BE_DATA, 1); } if (cpu_isar_feature(aa64_pauth, env_archcpu(env))) { @@ -13111,14 +13109,14 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, * The decision of which action to take is left to a helper. */ if (sctlr & (SCTLR_EnIA | SCTLR_EnIB | SCTLR_EnDA | SCTLR_EnDB)) { - flags = FIELD_DP32(flags, TBFLAG_A64, PAUTH_ACTIVE, 1); + DP_TBFLAG_A64(flags, PAUTH_ACTIVE, 1); } } if (cpu_isar_feature(aa64_bti, env_archcpu(env))) { /* Note that SCTLR_EL[23].BT == SCTLR_BT1. */ if (sctlr & (el == 0 ? SCTLR_BT0 : SCTLR_BT1)) { - flags = FIELD_DP32(flags, TBFLAG_A64, BT, 1); + DP_TBFLAG_A64(flags, BT, 1); } } @@ -13130,7 +13128,7 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, case ARMMMUIdx_SE10_1: case ARMMMUIdx_SE10_1_PAN: /* TODO: ARMv8.3-NV */ - flags = FIELD_DP32(flags, TBFLAG_A64, UNPRIV, 1); + DP_TBFLAG_A64(flags, UNPRIV, 1); break; case ARMMMUIdx_E20_2: case ARMMMUIdx_E20_2_PAN: @@ -13141,7 +13139,7 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, * gated by HCR_EL2. == '11', and so is LDTR. */ if (env->cp15.hcr_el2 & HCR_TGE) { - flags = FIELD_DP32(flags, TBFLAG_A64, UNPRIV, 1); + DP_TBFLAG_A64(flags, UNPRIV, 1); } break; default: @@ -13159,24 +13157,23 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, * 4) If no Allocation Tag Access, then all accesses are Unchecked. */ if (allocation_tag_access_enabled(env, el, sctlr)) { - flags = FIELD_DP32(flags, TBFLAG_A64, ATA, 1); + DP_TBFLAG_A64(flags, ATA, 1); if (tbid && !(env->pstate & PSTATE_TCO) && (sctlr & (el == 0 ? SCTLR_TCF0 : SCTLR_TCF))) { - flags = FIELD_DP32(flags, TBFLAG_A64, MTE_ACTIVE, 1); + DP_TBFLAG_A64(flags, MTE_ACTIVE, 1); } } /* And again for unprivileged accesses, if required. */ - if (FIELD_EX32(flags, TBFLAG_A64, UNPRIV) + if (EX_TBFLAG_A64(flags, UNPRIV) && tbid && !(env->pstate & PSTATE_TCO) && (sctlr & SCTLR_TCF0) && allocation_tag_access_enabled(env, 0, sctlr)) { - flags = FIELD_DP32(flags, TBFLAG_A64, MTE0_ACTIVE, 1); + DP_TBFLAG_A64(flags, MTE0_ACTIVE, 1); } /* Cache TCMA as well as TBI. */ - flags = FIELD_DP32(flags, TBFLAG_A64, TCMA, - aa64_va_parameter_tcma(tcr, mmu_idx)); + DP_TBFLAG_A64(flags, TCMA, aa64_va_parameter_tcma(tcr, mmu_idx)); } return rebuild_hflags_common(env, fp_el, mmu_idx, flags); @@ -13272,10 +13269,10 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, *cs_base = 0; assert_hflags_rebuild_correctly(env); - if (FIELD_EX32(flags, TBFLAG_ANY, AARCH64_STATE)) { + if (EX_TBFLAG_ANY(flags, AARCH64_STATE)) { *pc = env->pc; if (cpu_isar_feature(aa64_bti, env_archcpu(env))) { - flags = FIELD_DP32(flags, TBFLAG_A64, BTYPE, env->btype); + DP_TBFLAG_A64(flags, BTYPE, env->btype); } } else { *pc = env->regs[15]; @@ -13284,7 +13281,7 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, if (arm_feature(env, ARM_FEATURE_M_SECURITY) && FIELD_EX32(env->v7m.fpccr[M_REG_S], V7M_FPCCR, S) != env->v7m.secure) { - flags = FIELD_DP32(flags, TBFLAG_M32, FPCCR_S_WRONG, 1); + DP_TBFLAG_M32(flags, FPCCR_S_WRONG, 1); } if ((env->v7m.fpccr[env->v7m.secure] & R_V7M_FPCCR_ASPEN_MASK) && @@ -13296,12 +13293,12 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, * active FP context; we must create a new FP context before * executing any FP insn. */ - flags = FIELD_DP32(flags, TBFLAG_M32, NEW_FP_CTXT_NEEDED, 1); + DP_TBFLAG_M32(flags, NEW_FP_CTXT_NEEDED, 1); } bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; if (env->v7m.fpccr[is_secure] & R_V7M_FPCCR_LSPACT_MASK) { - flags = FIELD_DP32(flags, TBFLAG_M32, LSPACT, 1); + DP_TBFLAG_M32(flags, LSPACT, 1); } } else { /* @@ -13309,21 +13306,18 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, * Note that VECLEN+VECSTRIDE are RES0 for M-profile. */ if (arm_feature(env, ARM_FEATURE_XSCALE)) { - flags = FIELD_DP32(flags, TBFLAG_A32, - XSCALE_CPAR, env->cp15.c15_cpar); + DP_TBFLAG_A32(flags, XSCALE_CPAR, env->cp15.c15_cpar); } else { - flags = FIELD_DP32(flags, TBFLAG_A32, VECLEN, - env->vfp.vec_len); - flags = FIELD_DP32(flags, TBFLAG_A32, VECSTRIDE, - env->vfp.vec_stride); + DP_TBFLAG_A32(flags, VECLEN, env->vfp.vec_len); + DP_TBFLAG_A32(flags, VECSTRIDE, env->vfp.vec_stride); } if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) { - flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1); + DP_TBFLAG_A32(flags, VFPEN, 1); } } - flags = FIELD_DP32(flags, TBFLAG_AM32, THUMB, env->thumb); - flags = FIELD_DP32(flags, TBFLAG_AM32, CONDEXEC, env->condexec_bits); + DP_TBFLAG_AM32(flags, THUMB, env->thumb); + DP_TBFLAG_AM32(flags, CONDEXEC, env->condexec_bits); } /* @@ -13335,9 +13329,8 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, * 1 1 Active-not-pending * SS_ACTIVE is set in hflags; PSTATE__SS is computed every TB. */ - if (FIELD_EX32(flags, TBFLAG_ANY, SS_ACTIVE) && - (env->pstate & PSTATE_SS)) { - flags = FIELD_DP32(flags, TBFLAG_ANY, PSTATE__SS, 1); + if (EX_TBFLAG_ANY(flags, SS_ACTIVE) && (env->pstate & PSTATE_SS)) { + DP_TBFLAG_ANY(flags, PSTATE__SS, 1); } *pflags = flags; diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 64b3a5200c..05d83a5f7a 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14684,28 +14684,28 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, !arm_el_is_aa64(env, 3); dc->thumb = 0; dc->sctlr_b = 0; - dc->be_data = FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE; + dc->be_data = EX_TBFLAG_ANY(tb_flags, BE_DATA) ? MO_BE : MO_LE; dc->condexec_mask = 0; dc->condexec_cond = 0; - core_mmu_idx = FIELD_EX32(tb_flags, TBFLAG_ANY, MMUIDX); + core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX); dc->mmu_idx = core_to_aa64_mmu_idx(core_mmu_idx); - dc->tbii = FIELD_EX32(tb_flags, TBFLAG_A64, TBII); - dc->tbid = FIELD_EX32(tb_flags, TBFLAG_A64, TBID); - dc->tcma = FIELD_EX32(tb_flags, TBFLAG_A64, TCMA); + dc->tbii = EX_TBFLAG_A64(tb_flags, TBII); + dc->tbid = EX_TBFLAG_A64(tb_flags, TBID); + dc->tcma = EX_TBFLAG_A64(tb_flags, TCMA); dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx); #if !defined(CONFIG_USER_ONLY) dc->user = (dc->current_el == 0); #endif - dc->fp_excp_el = FIELD_EX32(tb_flags, TBFLAG_ANY, FPEXC_EL); - dc->sve_excp_el = FIELD_EX32(tb_flags, TBFLAG_A64, SVEEXC_EL); - dc->sve_len = (FIELD_EX32(tb_flags, TBFLAG_A64, ZCR_LEN) + 1) * 16; - dc->pauth_active = FIELD_EX32(tb_flags, TBFLAG_A64, PAUTH_ACTIVE); - dc->bt = FIELD_EX32(tb_flags, TBFLAG_A64, BT); - dc->btype = FIELD_EX32(tb_flags, TBFLAG_A64, BTYPE); - dc->unpriv = FIELD_EX32(tb_flags, TBFLAG_A64, UNPRIV); - dc->ata = FIELD_EX32(tb_flags, TBFLAG_A64, ATA); - dc->mte_active[0] = FIELD_EX32(tb_flags, TBFLAG_A64, MTE_ACTIVE); - dc->mte_active[1] = FIELD_EX32(tb_flags, TBFLAG_A64, MTE0_ACTIVE); + dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL); + dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); + dc->sve_len = (EX_TBFLAG_A64(tb_flags, ZCR_LEN) + 1) * 16; + dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE); + dc->bt = EX_TBFLAG_A64(tb_flags, BT); + dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE); + dc->unpriv = EX_TBFLAG_A64(tb_flags, UNPRIV); + dc->ata = EX_TBFLAG_A64(tb_flags, ATA); + dc->mte_active[0] = EX_TBFLAG_A64(tb_flags, MTE_ACTIVE); + dc->mte_active[1] = EX_TBFLAG_A64(tb_flags, MTE0_ACTIVE); dc->vec_len = 0; dc->vec_stride = 0; dc->cp_regs = arm_cpu->cp_regs; @@ -14732,10 +14732,10 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, * emit code to generate a software step exception * end the TB */ - dc->ss_active = FIELD_EX32(tb_flags, TBFLAG_ANY, SS_ACTIVE); - dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE__SS); + dc->ss_active = EX_TBFLAG_ANY(tb_flags, SS_ACTIVE); + dc->pstate_ss = EX_TBFLAG_ANY(tb_flags, PSTATE__SS); dc->is_ldex = false; - dc->debug_target_el = FIELD_EX32(tb_flags, TBFLAG_ANY, DEBUG_TARGET_EL); + dc->debug_target_el = EX_TBFLAG_ANY(tb_flags, DEBUG_TARGET_EL); /* Bound the number of insns to execute to those left on the page. */ bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; diff --git a/target/arm/translate.c b/target/arm/translate.c index 271c53dadb..5c21e98d24 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8864,46 +8864,42 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) */ dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) && !arm_el_is_aa64(env, 3); - dc->thumb = FIELD_EX32(tb_flags, TBFLAG_AM32, THUMB); - dc->be_data = FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE; - condexec = FIELD_EX32(tb_flags, TBFLAG_AM32, CONDEXEC); + dc->thumb = EX_TBFLAG_AM32(tb_flags, THUMB); + dc->be_data = EX_TBFLAG_ANY(tb_flags, BE_DATA) ? MO_BE : MO_LE; + condexec = EX_TBFLAG_AM32(tb_flags, CONDEXEC); dc->condexec_mask = (condexec & 0xf) << 1; dc->condexec_cond = condexec >> 4; - core_mmu_idx = FIELD_EX32(tb_flags, TBFLAG_ANY, MMUIDX); + core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX); dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx); dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx); #if !defined(CONFIG_USER_ONLY) dc->user = (dc->current_el == 0); #endif - dc->fp_excp_el = FIELD_EX32(tb_flags, TBFLAG_ANY, FPEXC_EL); + dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL); if (arm_feature(env, ARM_FEATURE_M)) { dc->vfp_enabled = 1; dc->be_data = MO_TE; - dc->v7m_handler_mode = FIELD_EX32(tb_flags, TBFLAG_M32, HANDLER); + dc->v7m_handler_mode = EX_TBFLAG_M32(tb_flags, HANDLER); dc->v8m_secure = arm_feature(env, ARM_FEATURE_M_SECURITY) && regime_is_secure(env, dc->mmu_idx); - dc->v8m_stackcheck = FIELD_EX32(tb_flags, TBFLAG_M32, STACKCHECK); - dc->v8m_fpccr_s_wrong = - FIELD_EX32(tb_flags, TBFLAG_M32, FPCCR_S_WRONG); + dc->v8m_stackcheck = EX_TBFLAG_M32(tb_flags, STACKCHECK); + dc->v8m_fpccr_s_wrong = EX_TBFLAG_M32(tb_flags, FPCCR_S_WRONG); dc->v7m_new_fp_ctxt_needed = - FIELD_EX32(tb_flags, TBFLAG_M32, NEW_FP_CTXT_NEEDED); - dc->v7m_lspact = FIELD_EX32(tb_flags, TBFLAG_M32, LSPACT); + EX_TBFLAG_M32(tb_flags, NEW_FP_CTXT_NEEDED); + dc->v7m_lspact = EX_TBFLAG_M32(tb_flags, LSPACT); } else { - dc->be_data = - FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE; - dc->debug_target_el = - FIELD_EX32(tb_flags, TBFLAG_ANY, DEBUG_TARGET_EL); - dc->sctlr_b = FIELD_EX32(tb_flags, TBFLAG_A32, SCTLR__B); - dc->hstr_active = FIELD_EX32(tb_flags, TBFLAG_A32, HSTR_ACTIVE); - dc->ns = FIELD_EX32(tb_flags, TBFLAG_A32, NS); - dc->vfp_enabled = FIELD_EX32(tb_flags, TBFLAG_A32, VFPEN); + dc->debug_target_el = EX_TBFLAG_ANY(tb_flags, DEBUG_TARGET_EL); + dc->sctlr_b = EX_TBFLAG_A32(tb_flags, SCTLR__B); + dc->hstr_active = EX_TBFLAG_A32(tb_flags, HSTR_ACTIVE); + dc->ns = EX_TBFLAG_A32(tb_flags, NS); + dc->vfp_enabled = EX_TBFLAG_A32(tb_flags, VFPEN); if (arm_feature(env, ARM_FEATURE_XSCALE)) { - dc->c15_cpar = FIELD_EX32(tb_flags, TBFLAG_A32, XSCALE_CPAR); + dc->c15_cpar = EX_TBFLAG_A32(tb_flags, XSCALE_CPAR); } else { - dc->vec_len = FIELD_EX32(tb_flags, TBFLAG_A32, VECLEN); - dc->vec_stride = FIELD_EX32(tb_flags, TBFLAG_A32, VECSTRIDE); + dc->vec_len = EX_TBFLAG_A32(tb_flags, VECLEN); + dc->vec_stride = EX_TBFLAG_A32(tb_flags, VECSTRIDE); } } dc->cp_regs = cpu->cp_regs; @@ -8924,8 +8920,8 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) * emit code to generate a software step exception * end the TB */ - dc->ss_active = FIELD_EX32(tb_flags, TBFLAG_ANY, SS_ACTIVE); - dc->pstate_ss = FIELD_EX32(tb_flags, TBFLAG_ANY, PSTATE__SS); + dc->ss_active = EX_TBFLAG_ANY(tb_flags, SS_ACTIVE); + dc->pstate_ss = EX_TBFLAG_ANY(tb_flags, PSTATE__SS); dc->is_ldex = false; dc->page_start = dc->base.pc_first & TARGET_PAGE_MASK; @@ -9364,11 +9360,11 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) DisasContext dc = { }; const TranslatorOps *ops = &arm_translator_ops; - if (FIELD_EX32(tb->flags, TBFLAG_AM32, THUMB)) { + if (EX_TBFLAG_AM32(tb->flags, THUMB)) { ops = &thumb_translator_ops; } #ifdef TARGET_AARCH64 - if (FIELD_EX32(tb->flags, TBFLAG_ANY, AARCH64_STATE)) { + if (EX_TBFLAG_ANY(tb->flags, AARCH64_STATE)) { ops = &aarch64_translator_ops; } #endif From 3902bfc6f06144016b8b25f5b6fb2211e85406fc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:31 -0700 Subject: [PATCH 0022/3028] target/arm: Introduce CPUARMTBFlags In preparation for splitting tb->flags across multiple fields, introduce a structure to hold the value(s). So far this only migrates the one uint32_t and fixes all of the places that require adjustment to match. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 26 ++++++++++++--------- target/arm/helper.c | 48 +++++++++++++++++++++----------------- target/arm/translate-a64.c | 2 +- target/arm/translate.c | 7 +++--- target/arm/translate.h | 11 +++++++++ 5 files changed, 57 insertions(+), 37 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index b798ff8115..79af9a7c62 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -225,6 +225,10 @@ typedef struct ARMPACKey { } ARMPACKey; #endif +/* See the commentary above the TBFLAG field definitions. */ +typedef struct CPUARMTBFlags { + uint32_t flags; +} CPUARMTBFlags; typedef struct CPUARMState { /* Regs for current mode. */ @@ -253,7 +257,7 @@ typedef struct CPUARMState { uint32_t aarch64; /* 1 if CPU is in aarch64 state; inverse of PSTATE.nRW */ /* Cached TBFLAGS state. See below for which bits are included. */ - uint32_t hflags; + CPUARMTBFlags hflags; /* Frequently accessed CPSR bits are stored separately for efficiency. This contains all the other bits. Use cpsr_{read,write} to access @@ -3466,21 +3470,21 @@ FIELD(TBFLAG_A64, MTE0_ACTIVE, 19, 1) * Helpers for using the above. */ #define DP_TBFLAG_ANY(DST, WHICH, VAL) \ - (DST = FIELD_DP32(DST, TBFLAG_ANY, WHICH, VAL)) + (DST.flags = FIELD_DP32(DST.flags, TBFLAG_ANY, WHICH, VAL)) #define DP_TBFLAG_A64(DST, WHICH, VAL) \ - (DST = FIELD_DP32(DST, TBFLAG_A64, WHICH, VAL)) + (DST.flags = FIELD_DP32(DST.flags, TBFLAG_A64, WHICH, VAL)) #define DP_TBFLAG_A32(DST, WHICH, VAL) \ - (DST = FIELD_DP32(DST, TBFLAG_A32, WHICH, VAL)) + (DST.flags = FIELD_DP32(DST.flags, TBFLAG_A32, WHICH, VAL)) #define DP_TBFLAG_M32(DST, WHICH, VAL) \ - (DST = FIELD_DP32(DST, TBFLAG_M32, WHICH, VAL)) + (DST.flags = FIELD_DP32(DST.flags, TBFLAG_M32, WHICH, VAL)) #define DP_TBFLAG_AM32(DST, WHICH, VAL) \ - (DST = FIELD_DP32(DST, TBFLAG_AM32, WHICH, VAL)) + (DST.flags = FIELD_DP32(DST.flags, TBFLAG_AM32, WHICH, VAL)) -#define EX_TBFLAG_ANY(IN, WHICH) FIELD_EX32(IN, TBFLAG_ANY, WHICH) -#define EX_TBFLAG_A64(IN, WHICH) FIELD_EX32(IN, TBFLAG_A64, WHICH) -#define EX_TBFLAG_A32(IN, WHICH) FIELD_EX32(IN, TBFLAG_A32, WHICH) -#define EX_TBFLAG_M32(IN, WHICH) FIELD_EX32(IN, TBFLAG_M32, WHICH) -#define EX_TBFLAG_AM32(IN, WHICH) FIELD_EX32(IN, TBFLAG_AM32, WHICH) +#define EX_TBFLAG_ANY(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_ANY, WHICH) +#define EX_TBFLAG_A64(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_A64, WHICH) +#define EX_TBFLAG_A32(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_A32, WHICH) +#define EX_TBFLAG_M32(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_M32, WHICH) +#define EX_TBFLAG_AM32(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_AM32, WHICH) /** * cpu_mmu_index: diff --git a/target/arm/helper.c b/target/arm/helper.c index 2769e6fd35..f564e59084 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12984,8 +12984,9 @@ ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env) } #endif -static uint32_t rebuild_hflags_common(CPUARMState *env, int fp_el, - ARMMMUIdx mmu_idx, uint32_t flags) +static CPUARMTBFlags rebuild_hflags_common(CPUARMState *env, int fp_el, + ARMMMUIdx mmu_idx, + CPUARMTBFlags flags) { DP_TBFLAG_ANY(flags, FPEXC_EL, fp_el); DP_TBFLAG_ANY(flags, MMUIDX, arm_to_core_mmu_idx(mmu_idx)); @@ -12996,8 +12997,9 @@ static uint32_t rebuild_hflags_common(CPUARMState *env, int fp_el, return flags; } -static uint32_t rebuild_hflags_common_32(CPUARMState *env, int fp_el, - ARMMMUIdx mmu_idx, uint32_t flags) +static CPUARMTBFlags rebuild_hflags_common_32(CPUARMState *env, int fp_el, + ARMMMUIdx mmu_idx, + CPUARMTBFlags flags) { bool sctlr_b = arm_sctlr_b(env); @@ -13012,10 +13014,10 @@ static uint32_t rebuild_hflags_common_32(CPUARMState *env, int fp_el, return rebuild_hflags_common(env, fp_el, mmu_idx, flags); } -static uint32_t rebuild_hflags_m32(CPUARMState *env, int fp_el, - ARMMMUIdx mmu_idx) +static CPUARMTBFlags rebuild_hflags_m32(CPUARMState *env, int fp_el, + ARMMMUIdx mmu_idx) { - uint32_t flags = 0; + CPUARMTBFlags flags = {}; if (arm_v7m_is_handler_mode(env)) { DP_TBFLAG_M32(flags, HANDLER, 1); @@ -13035,18 +13037,18 @@ static uint32_t rebuild_hflags_m32(CPUARMState *env, int fp_el, return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); } -static uint32_t rebuild_hflags_aprofile(CPUARMState *env) +static CPUARMTBFlags rebuild_hflags_aprofile(CPUARMState *env) { - int flags = 0; + CPUARMTBFlags flags = {}; DP_TBFLAG_ANY(flags, DEBUG_TARGET_EL, arm_debug_target_el(env)); return flags; } -static uint32_t rebuild_hflags_a32(CPUARMState *env, int fp_el, - ARMMMUIdx mmu_idx) +static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, + ARMMMUIdx mmu_idx) { - uint32_t flags = rebuild_hflags_aprofile(env); + CPUARMTBFlags flags = rebuild_hflags_aprofile(env); if (arm_el_is_aa64(env, 1)) { DP_TBFLAG_A32(flags, VFPEN, 1); @@ -13060,10 +13062,10 @@ static uint32_t rebuild_hflags_a32(CPUARMState *env, int fp_el, return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags); } -static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, - ARMMMUIdx mmu_idx) +static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, + ARMMMUIdx mmu_idx) { - uint32_t flags = rebuild_hflags_aprofile(env); + CPUARMTBFlags flags = rebuild_hflags_aprofile(env); ARMMMUIdx stage1 = stage_1_mmu_idx(mmu_idx); uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr; uint64_t sctlr; @@ -13179,7 +13181,7 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, return rebuild_hflags_common(env, fp_el, mmu_idx, flags); } -static uint32_t rebuild_hflags_internal(CPUARMState *env) +static CPUARMTBFlags rebuild_hflags_internal(CPUARMState *env) { int el = arm_current_el(env); int fp_el = fp_exception_el(env, el); @@ -13208,6 +13210,7 @@ void HELPER(rebuild_hflags_m32_newel)(CPUARMState *env) int el = arm_current_el(env); int fp_el = fp_exception_el(env, el); ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, el); + env->hflags = rebuild_hflags_m32(env, fp_el, mmu_idx); } @@ -13250,12 +13253,12 @@ void HELPER(rebuild_hflags_a64)(CPUARMState *env, int el) static inline void assert_hflags_rebuild_correctly(CPUARMState *env) { #ifdef CONFIG_DEBUG_TCG - uint32_t env_flags_current = env->hflags; - uint32_t env_flags_rebuilt = rebuild_hflags_internal(env); + CPUARMTBFlags c = env->hflags; + CPUARMTBFlags r = rebuild_hflags_internal(env); - if (unlikely(env_flags_current != env_flags_rebuilt)) { + if (unlikely(c.flags != r.flags)) { fprintf(stderr, "TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n", - env_flags_current, env_flags_rebuilt); + c.flags, r.flags); abort(); } #endif @@ -13264,10 +13267,11 @@ static inline void assert_hflags_rebuild_correctly(CPUARMState *env) void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *pflags) { - uint32_t flags = env->hflags; + CPUARMTBFlags flags; *cs_base = 0; assert_hflags_rebuild_correctly(env); + flags = env->hflags; if (EX_TBFLAG_ANY(flags, AARCH64_STATE)) { *pc = env->pc; @@ -13333,7 +13337,7 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, DP_TBFLAG_ANY(flags, PSTATE__SS, 1); } - *pflags = flags; + *pflags = flags.flags; } #ifdef TARGET_AARCH64 diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 05d83a5f7a..b32ff56666 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14670,7 +14670,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, DisasContext *dc = container_of(dcbase, DisasContext, base); CPUARMState *env = cpu->env_ptr; ARMCPU *arm_cpu = env_archcpu(env); - uint32_t tb_flags = dc->base.tb->flags; + CPUARMTBFlags tb_flags = arm_tbflags_from_tb(dc->base.tb); int bound, core_mmu_idx; dc->isar = &arm_cpu->isar; diff --git a/target/arm/translate.c b/target/arm/translate.c index 5c21e98d24..6a15e5d16c 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8852,7 +8852,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) DisasContext *dc = container_of(dcbase, DisasContext, base); CPUARMState *env = cs->env_ptr; ARMCPU *cpu = env_archcpu(env); - uint32_t tb_flags = dc->base.tb->flags; + CPUARMTBFlags tb_flags = arm_tbflags_from_tb(dc->base.tb); uint32_t condexec, core_mmu_idx; dc->isar = &cpu->isar; @@ -9359,12 +9359,13 @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns) { DisasContext dc = { }; const TranslatorOps *ops = &arm_translator_ops; + CPUARMTBFlags tb_flags = arm_tbflags_from_tb(tb); - if (EX_TBFLAG_AM32(tb->flags, THUMB)) { + if (EX_TBFLAG_AM32(tb_flags, THUMB)) { ops = &thumb_translator_ops; } #ifdef TARGET_AARCH64 - if (EX_TBFLAG_ANY(tb->flags, AARCH64_STATE)) { + if (EX_TBFLAG_ANY(tb_flags, AARCH64_STATE)) { ops = &aarch64_translator_ops; } #endif diff --git a/target/arm/translate.h b/target/arm/translate.h index 423b0e08df..f30287e554 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -394,6 +394,17 @@ typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32); typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, MemOp); +/** + * arm_tbflags_from_tb: + * @tb: the TranslationBlock + * + * Extract the flag values from @tb. + */ +static inline CPUARMTBFlags arm_tbflags_from_tb(const TranslationBlock *tb) +{ + return (CPUARMTBFlags){ tb->flags }; +} + /* * Enum for argument to fpstatus_ptr(). */ From a378206a205a65c182854a961d99acbce00cda86 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:32 -0700 Subject: [PATCH 0023/3028] target/arm: Move mode specific TB flags to tb->cs_base Now that we have all of the proper macros defined, expanding the CPUARMTBFlags structure and populating the two TB fields is relatively simple. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 49 ++++++++++++++++++++++++------------------ target/arm/helper.c | 10 +++++---- target/arm/translate.h | 2 +- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 79af9a7c62..a8da7c55a6 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -228,6 +228,7 @@ typedef struct ARMPACKey { /* See the commentary above the TBFLAG field definitions. */ typedef struct CPUARMTBFlags { uint32_t flags; + target_ulong flags2; } CPUARMTBFlags; typedef struct CPUARMState { @@ -3381,20 +3382,26 @@ typedef ARMCPU ArchCPU; #include "exec/cpu-all.h" /* - * Bit usage in the TB flags field: bit 31 indicates whether we are - * in 32 or 64 bit mode. The meaning of the other bits depends on that. - * We put flags which are shared between 32 and 64 bit mode at the top - * of the word, and flags which apply to only one mode at the bottom. + * We have more than 32-bits worth of state per TB, so we split the data + * between tb->flags and tb->cs_base, which is otherwise unused for ARM. + * We collect these two parts in CPUARMTBFlags where they are named + * flags and flags2 respectively. * - * 31 20 18 14 9 0 - * +--------------+-----+-----+----------+--------------+ - * | | | TBFLAG_A32 | | - * | | +-----+----------+ TBFLAG_AM32 | - * | TBFLAG_ANY | |TBFLAG_M32| | - * | +-----------+----------+--------------| - * | | TBFLAG_A64 | - * +--------------+-------------------------------------+ - * 31 20 0 + * The flags that are shared between all execution modes, TBFLAG_ANY, + * are stored in flags. The flags that are specific to a given mode + * are stores in flags2. Since cs_base is sized on the configured + * address size, flags2 always has 64-bits for A64, and a minimum of + * 32-bits for A32 and M32. + * + * The bits for 32-bit A-profile and M-profile partially overlap: + * + * 18 9 0 + * +----------------+--------------+ + * | TBFLAG_A32 | | + * +-----+----------+ TBFLAG_AM32 | + * | |TBFLAG_M32| | + * +-----+----------+--------------+ + * 14 9 0 * * Unless otherwise noted, these bits are cached in env->hflags. */ @@ -3472,19 +3479,19 @@ FIELD(TBFLAG_A64, MTE0_ACTIVE, 19, 1) #define DP_TBFLAG_ANY(DST, WHICH, VAL) \ (DST.flags = FIELD_DP32(DST.flags, TBFLAG_ANY, WHICH, VAL)) #define DP_TBFLAG_A64(DST, WHICH, VAL) \ - (DST.flags = FIELD_DP32(DST.flags, TBFLAG_A64, WHICH, VAL)) + (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A64, WHICH, VAL)) #define DP_TBFLAG_A32(DST, WHICH, VAL) \ - (DST.flags = FIELD_DP32(DST.flags, TBFLAG_A32, WHICH, VAL)) + (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_A32, WHICH, VAL)) #define DP_TBFLAG_M32(DST, WHICH, VAL) \ - (DST.flags = FIELD_DP32(DST.flags, TBFLAG_M32, WHICH, VAL)) + (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_M32, WHICH, VAL)) #define DP_TBFLAG_AM32(DST, WHICH, VAL) \ - (DST.flags = FIELD_DP32(DST.flags, TBFLAG_AM32, WHICH, VAL)) + (DST.flags2 = FIELD_DP32(DST.flags2, TBFLAG_AM32, WHICH, VAL)) #define EX_TBFLAG_ANY(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_ANY, WHICH) -#define EX_TBFLAG_A64(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_A64, WHICH) -#define EX_TBFLAG_A32(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_A32, WHICH) -#define EX_TBFLAG_M32(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_M32, WHICH) -#define EX_TBFLAG_AM32(IN, WHICH) FIELD_EX32(IN.flags, TBFLAG_AM32, WHICH) +#define EX_TBFLAG_A64(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_A64, WHICH) +#define EX_TBFLAG_A32(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_A32, WHICH) +#define EX_TBFLAG_M32(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_M32, WHICH) +#define EX_TBFLAG_AM32(IN, WHICH) FIELD_EX32(IN.flags2, TBFLAG_AM32, WHICH) /** * cpu_mmu_index: diff --git a/target/arm/helper.c b/target/arm/helper.c index f564e59084..4aa7650d3a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -13256,9 +13256,11 @@ static inline void assert_hflags_rebuild_correctly(CPUARMState *env) CPUARMTBFlags c = env->hflags; CPUARMTBFlags r = rebuild_hflags_internal(env); - if (unlikely(c.flags != r.flags)) { - fprintf(stderr, "TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n", - c.flags, r.flags); + if (unlikely(c.flags != r.flags || c.flags2 != r.flags2)) { + fprintf(stderr, "TCG hflags mismatch " + "(current:(0x%08x,0x" TARGET_FMT_lx ")" + " rebuilt:(0x%08x,0x" TARGET_FMT_lx ")\n", + c.flags, c.flags2, r.flags, r.flags2); abort(); } #endif @@ -13269,7 +13271,6 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, { CPUARMTBFlags flags; - *cs_base = 0; assert_hflags_rebuild_correctly(env); flags = env->hflags; @@ -13338,6 +13339,7 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc, } *pflags = flags.flags; + *cs_base = flags.flags2; } #ifdef TARGET_AARCH64 diff --git a/target/arm/translate.h b/target/arm/translate.h index f30287e554..50c2aba066 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -402,7 +402,7 @@ typedef void AtomicThreeOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGArg, MemOp); */ static inline CPUARMTBFlags arm_tbflags_from_tb(const TranslationBlock *tb) { - return (CPUARMTBFlags){ tb->flags }; + return (CPUARMTBFlags){ tb->flags, tb->cs_base }; } /* From 5896f39253ead37f65a2c13a9b0066f56c282d4c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:34 -0700 Subject: [PATCH 0024/3028] target/arm: Move TBFLAG_AM32 bits to the top Now that these bits have been moved out of tb->flags, where TBFLAG_ANY was filling from the top, move AM32 to fill from the top, and A32 and M32 to fill from the bottom. This means fewer changes when adding new bits. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a8da7c55a6..15104e1440 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3395,13 +3395,13 @@ typedef ARMCPU ArchCPU; * * The bits for 32-bit A-profile and M-profile partially overlap: * - * 18 9 0 - * +----------------+--------------+ - * | TBFLAG_A32 | | - * +-----+----------+ TBFLAG_AM32 | - * | |TBFLAG_M32| | - * +-----+----------+--------------+ - * 14 9 0 + * 31 23 11 10 0 + * +-------------+----------+----------------+ + * | | | TBFLAG_A32 | + * | TBFLAG_AM32 | +-----+----------+ + * | | |TBFLAG_M32| + * +-------------+----------------+----------+ + * 31 23 5 4 0 * * Unless otherwise noted, these bits are cached in env->hflags. */ @@ -3418,44 +3418,44 @@ FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 20, 2) /* * Bit usage when in AArch32 state, both A- and M-profile. */ -FIELD(TBFLAG_AM32, CONDEXEC, 0, 8) /* Not cached. */ -FIELD(TBFLAG_AM32, THUMB, 8, 1) /* Not cached. */ +FIELD(TBFLAG_AM32, CONDEXEC, 24, 8) /* Not cached. */ +FIELD(TBFLAG_AM32, THUMB, 23, 1) /* Not cached. */ /* * Bit usage when in AArch32 state, for A-profile only. */ -FIELD(TBFLAG_A32, VECLEN, 9, 3) /* Not cached. */ -FIELD(TBFLAG_A32, VECSTRIDE, 12, 2) /* Not cached. */ +FIELD(TBFLAG_A32, VECLEN, 0, 3) /* Not cached. */ +FIELD(TBFLAG_A32, VECSTRIDE, 3, 2) /* Not cached. */ /* * We store the bottom two bits of the CPAR as TB flags and handle * checks on the other bits at runtime. This shares the same bits as * VECSTRIDE, which is OK as no XScale CPU has VFP. * Not cached, because VECLEN+VECSTRIDE are not cached. */ -FIELD(TBFLAG_A32, XSCALE_CPAR, 12, 2) -FIELD(TBFLAG_A32, VFPEN, 14, 1) /* Partially cached, minus FPEXC. */ -FIELD(TBFLAG_A32, SCTLR__B, 15, 1) /* Cannot overlap with SCTLR_B */ -FIELD(TBFLAG_A32, HSTR_ACTIVE, 16, 1) +FIELD(TBFLAG_A32, XSCALE_CPAR, 5, 2) +FIELD(TBFLAG_A32, VFPEN, 7, 1) /* Partially cached, minus FPEXC. */ +FIELD(TBFLAG_A32, SCTLR__B, 8, 1) /* Cannot overlap with SCTLR_B */ +FIELD(TBFLAG_A32, HSTR_ACTIVE, 9, 1) /* * Indicates whether cp register reads and writes by guest code should access * the secure or nonsecure bank of banked registers; note that this is not * the same thing as the current security state of the processor! */ -FIELD(TBFLAG_A32, NS, 17, 1) +FIELD(TBFLAG_A32, NS, 10, 1) /* * Bit usage when in AArch32 state, for M-profile only. */ /* Handler (ie not Thread) mode */ -FIELD(TBFLAG_M32, HANDLER, 9, 1) +FIELD(TBFLAG_M32, HANDLER, 0, 1) /* Whether we should generate stack-limit checks */ -FIELD(TBFLAG_M32, STACKCHECK, 10, 1) +FIELD(TBFLAG_M32, STACKCHECK, 1, 1) /* Set if FPCCR.LSPACT is set */ -FIELD(TBFLAG_M32, LSPACT, 11, 1) /* Not cached. */ +FIELD(TBFLAG_M32, LSPACT, 2, 1) /* Not cached. */ /* Set if we must create a new FP context */ -FIELD(TBFLAG_M32, NEW_FP_CTXT_NEEDED, 12, 1) /* Not cached. */ +FIELD(TBFLAG_M32, NEW_FP_CTXT_NEEDED, 3, 1) /* Not cached. */ /* Set if FPCCR.S does not match current security state */ -FIELD(TBFLAG_M32, FPCCR_S_WRONG, 13, 1) /* Not cached. */ +FIELD(TBFLAG_M32, FPCCR_S_WRONG, 4, 1) /* Not cached. */ /* * Bit usage when in AArch64 state From eee81d41ec4c5bf9bbde4e4d35648e29e2244f3f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:35 -0700 Subject: [PATCH 0025/3028] target/arm: Move TBFLAG_ANY bits to the bottom Now that other bits have been moved out of tb->flags, there's no point in filling from the top. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 15104e1440..5e0131be1a 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3405,15 +3405,15 @@ typedef ARMCPU ArchCPU; * * Unless otherwise noted, these bits are cached in env->hflags. */ -FIELD(TBFLAG_ANY, AARCH64_STATE, 31, 1) -FIELD(TBFLAG_ANY, SS_ACTIVE, 30, 1) -FIELD(TBFLAG_ANY, PSTATE__SS, 29, 1) /* Not cached. */ -FIELD(TBFLAG_ANY, BE_DATA, 28, 1) -FIELD(TBFLAG_ANY, MMUIDX, 24, 4) +FIELD(TBFLAG_ANY, AARCH64_STATE, 0, 1) +FIELD(TBFLAG_ANY, SS_ACTIVE, 1, 1) +FIELD(TBFLAG_ANY, PSTATE__SS, 2, 1) /* Not cached. */ +FIELD(TBFLAG_ANY, BE_DATA, 3, 1) +FIELD(TBFLAG_ANY, MMUIDX, 4, 4) /* Target EL if we take a floating-point-disabled exception */ -FIELD(TBFLAG_ANY, FPEXC_EL, 22, 2) +FIELD(TBFLAG_ANY, FPEXC_EL, 8, 2) /* For A-profile only, target EL for debug exceptions. */ -FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 20, 2) +FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 10, 2) /* * Bit usage when in AArch32 state, both A- and M-profile. From 4479ec30c9c4d2399b6e5bf4e77d136cfd27aebd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:36 -0700 Subject: [PATCH 0026/3028] target/arm: Add ALIGN_MEM to TBFLAG_ANY Use this to signal when memory access alignment is required. This value comes from the CCR register for M-profile, and from the SCTLR register for A-profile. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.h | 2 ++ target/arm/helper.c | 19 +++++++++++++++++-- target/arm/translate-a64.c | 1 + target/arm/translate.c | 7 +++---- target/arm/translate.h | 2 ++ 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 5e0131be1a..616b393253 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3414,6 +3414,8 @@ FIELD(TBFLAG_ANY, MMUIDX, 4, 4) FIELD(TBFLAG_ANY, FPEXC_EL, 8, 2) /* For A-profile only, target EL for debug exceptions. */ FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 10, 2) +/* Memory operations require alignment: SCTLR_ELx.A or CCR.UNALIGN_TRP */ +FIELD(TBFLAG_ANY, ALIGN_MEM, 12, 1) /* * Bit usage when in AArch32 state, both A- and M-profile. diff --git a/target/arm/helper.c b/target/arm/helper.c index 4aa7650d3a..9b1b98705f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -13018,6 +13018,12 @@ static CPUARMTBFlags rebuild_hflags_m32(CPUARMState *env, int fp_el, ARMMMUIdx mmu_idx) { CPUARMTBFlags flags = {}; + uint32_t ccr = env->v7m.ccr[env->v7m.secure]; + + /* Without HaveMainExt, CCR.UNALIGN_TRP is RES1. */ + if (ccr & R_V7M_CCR_UNALIGN_TRP_MASK) { + DP_TBFLAG_ANY(flags, ALIGN_MEM, 1); + } if (arm_v7m_is_handler_mode(env)) { DP_TBFLAG_M32(flags, HANDLER, 1); @@ -13030,7 +13036,7 @@ static CPUARMTBFlags rebuild_hflags_m32(CPUARMState *env, int fp_el, */ if (arm_feature(env, ARM_FEATURE_V8) && !((mmu_idx & ARM_MMU_IDX_M_NEGPRI) && - (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKOFHFNMIGN_MASK))) { + (ccr & R_V7M_CCR_STKOFHFNMIGN_MASK))) { DP_TBFLAG_M32(flags, STACKCHECK, 1); } @@ -13049,12 +13055,17 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, ARMMMUIdx mmu_idx) { CPUARMTBFlags flags = rebuild_hflags_aprofile(env); + int el = arm_current_el(env); + + if (arm_sctlr(env, el) & SCTLR_A) { + DP_TBFLAG_ANY(flags, ALIGN_MEM, 1); + } if (arm_el_is_aa64(env, 1)) { DP_TBFLAG_A32(flags, VFPEN, 1); } - if (arm_current_el(env) < 2 && env->cp15.hstr_el2 && + if (el < 2 && env->cp15.hstr_el2 && (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) { DP_TBFLAG_A32(flags, HSTR_ACTIVE, 1); } @@ -13099,6 +13110,10 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, sctlr = regime_sctlr(env, stage1); + if (sctlr & SCTLR_A) { + DP_TBFLAG_ANY(flags, ALIGN_MEM, 1); + } + if (arm_cpu_data_is_big_endian_a64(el, sctlr)) { DP_TBFLAG_ANY(flags, BE_DATA, 1); } diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index b32ff56666..92a62b1a75 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -14697,6 +14697,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->user = (dc->current_el == 0); #endif dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL); + dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); dc->sve_len = (EX_TBFLAG_A64(tb_flags, ZCR_LEN) + 1) * 16; dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE); diff --git a/target/arm/translate.c b/target/arm/translate.c index 6a15e5d16c..970e537eae 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -933,8 +933,7 @@ static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, { TCGv addr; - if (arm_dc_feature(s, ARM_FEATURE_M) && - !arm_dc_feature(s, ARM_FEATURE_M_MAIN)) { + if (s->align_mem) { opc |= MO_ALIGN; } @@ -948,8 +947,7 @@ static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, { TCGv addr; - if (arm_dc_feature(s, ARM_FEATURE_M) && - !arm_dc_feature(s, ARM_FEATURE_M_MAIN)) { + if (s->align_mem) { opc |= MO_ALIGN; } @@ -8877,6 +8875,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->user = (dc->current_el == 0); #endif dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL); + dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); if (arm_feature(env, ARM_FEATURE_M)) { dc->vfp_enabled = 1; diff --git a/target/arm/translate.h b/target/arm/translate.h index 50c2aba066..b185c14a03 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -87,6 +87,8 @@ typedef struct DisasContext { bool bt; /* True if any CP15 access is trapped by HSTR_EL2 */ bool hstr_active; + /* True if memory operations require alignment */ + bool align_mem; /* * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. * < 0, set by the current instruction. From 9d486b40e895b0e4cfaf47a0bdbd9144547b66d5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:37 -0700 Subject: [PATCH 0027/3028] target/arm: Adjust gen_aa32_{ld, st}_i32 for align+endianness Create a finalize_memop function that computes alignment and endianness and returns the final MemOp for the operation. Split out gen_aa32_{ld,st}_internal_i32 which bypasses any special handling of endianness or alignment. Adjust gen_aa32_{ld,st}_i32 so that s->be_data is not added by the callers. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-neon.c.inc | 9 +-- target/arm/translate.c | 100 +++++++++++++++++--------------- target/arm/translate.h | 24 ++++++++ 3 files changed, 79 insertions(+), 54 deletions(-) diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c.inc index 0e5828744b..c82aa1412e 100644 --- a/target/arm/translate-neon.c.inc +++ b/target/arm/translate-neon.c.inc @@ -559,8 +559,7 @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) addr = tcg_temp_new_i32(); load_reg_var(s, addr, a->rn); for (reg = 0; reg < nregs; reg++) { - gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), - s->be_data | size); + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), size); if ((vd & 1) && vec_size == 16) { /* * We cannot write 16 bytes at once because the @@ -650,13 +649,11 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) */ for (reg = 0; reg < nregs; reg++) { if (a->l) { - gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), - s->be_data | a->size); + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), a->size); neon_store_element(vd, a->reg_idx, a->size, tmp); } else { /* Store */ neon_load_element(tmp, vd, a->reg_idx, a->size); - gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), - s->be_data | a->size); + gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), a->size); } vd += a->stride; tcg_gen_addi_i32(addr, addr, 1 << a->size); diff --git a/target/arm/translate.c b/target/arm/translate.c index 970e537eae..5bf68b782a 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -908,7 +908,8 @@ static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var) #define IS_USER_ONLY 0 #endif -/* Abstractions of "generate code to do a guest load/store for +/* + * Abstractions of "generate code to do a guest load/store for * AArch32", where a vaddr is always 32 bits (and is zero * extended if we're a 64 bit core) and data is also * 32 bits unless specifically doing a 64 bit access. @@ -916,7 +917,7 @@ static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var) * that the address argument is TCGv_i32 rather than TCGv. */ -static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op) +static TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op) { TCGv addr = tcg_temp_new(); tcg_gen_extu_i32_tl(addr, a32); @@ -928,47 +929,51 @@ static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op) return addr; } +/* + * Internal routines are used for NEON cases where the endianness + * and/or alignment has already been taken into account and manipulated. + */ +static void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val, + TCGv_i32 a32, int index, MemOp opc) +{ + TCGv addr = gen_aa32_addr(s, a32, opc); + tcg_gen_qemu_ld_i32(val, addr, index, opc); + tcg_temp_free(addr); +} + +static void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, + TCGv_i32 a32, int index, MemOp opc) +{ + TCGv addr = gen_aa32_addr(s, a32, opc); + tcg_gen_qemu_st_i32(val, addr, index, opc); + tcg_temp_free(addr); +} + static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, int index, MemOp opc) { - TCGv addr; - - if (s->align_mem) { - opc |= MO_ALIGN; - } - - addr = gen_aa32_addr(s, a32, opc); - tcg_gen_qemu_ld_i32(val, addr, index, opc); - tcg_temp_free(addr); + gen_aa32_ld_internal_i32(s, val, a32, index, finalize_memop(s, opc)); } static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, int index, MemOp opc) { - TCGv addr; + gen_aa32_st_internal_i32(s, val, a32, index, finalize_memop(s, opc)); +} - if (s->align_mem) { - opc |= MO_ALIGN; +#define DO_GEN_LD(SUFF, OPC) \ + static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \ + TCGv_i32 a32, int index) \ + { \ + gen_aa32_ld_i32(s, val, a32, index, OPC); \ } - addr = gen_aa32_addr(s, a32, opc); - tcg_gen_qemu_st_i32(val, addr, index, opc); - tcg_temp_free(addr); -} - -#define DO_GEN_LD(SUFF, OPC) \ -static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \ - TCGv_i32 a32, int index) \ -{ \ - gen_aa32_ld_i32(s, val, a32, index, OPC | s->be_data); \ -} - -#define DO_GEN_ST(SUFF, OPC) \ -static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \ - TCGv_i32 a32, int index) \ -{ \ - gen_aa32_st_i32(s, val, a32, index, OPC | s->be_data); \ -} +#define DO_GEN_ST(SUFF, OPC) \ + static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \ + TCGv_i32 a32, int index) \ + { \ + gen_aa32_st_i32(s, val, a32, index, OPC); \ + } static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val) { @@ -6456,7 +6461,7 @@ static bool op_load_rr(DisasContext *s, arg_ldst_rr *a, addr = op_addr_rr_pre(s, a); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, mem_idx, mop | s->be_data); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, mop); disas_set_da_iss(s, mop, issinfo); /* @@ -6485,7 +6490,7 @@ static bool op_store_rr(DisasContext *s, arg_ldst_rr *a, addr = op_addr_rr_pre(s, a); tmp = load_reg(s, a->rt); - gen_aa32_st_i32(s, tmp, addr, mem_idx, mop | s->be_data); + gen_aa32_st_i32(s, tmp, addr, mem_idx, mop); disas_set_da_iss(s, mop, issinfo); tcg_temp_free_i32(tmp); @@ -6508,13 +6513,13 @@ static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a) addr = op_addr_rr_pre(s, a); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL); store_reg(s, a->rt, tmp); tcg_gen_addi_i32(addr, addr, 4); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL); store_reg(s, a->rt + 1, tmp); /* LDRD w/ base writeback is undefined if the registers overlap. */ @@ -6537,13 +6542,13 @@ static bool trans_STRD_rr(DisasContext *s, arg_ldst_rr *a) addr = op_addr_rr_pre(s, a); tmp = load_reg(s, a->rt); - gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL); tcg_temp_free_i32(tmp); tcg_gen_addi_i32(addr, addr, 4); tmp = load_reg(s, a->rt + 1); - gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL); tcg_temp_free_i32(tmp); op_addr_rr_post(s, a, addr, -4); @@ -6608,7 +6613,7 @@ static bool op_load_ri(DisasContext *s, arg_ldst_ri *a, addr = op_addr_ri_pre(s, a); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, mem_idx, mop | s->be_data); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, mop); disas_set_da_iss(s, mop, issinfo); /* @@ -6637,7 +6642,7 @@ static bool op_store_ri(DisasContext *s, arg_ldst_ri *a, addr = op_addr_ri_pre(s, a); tmp = load_reg(s, a->rt); - gen_aa32_st_i32(s, tmp, addr, mem_idx, mop | s->be_data); + gen_aa32_st_i32(s, tmp, addr, mem_idx, mop); disas_set_da_iss(s, mop, issinfo); tcg_temp_free_i32(tmp); @@ -6653,13 +6658,13 @@ static bool op_ldrd_ri(DisasContext *s, arg_ldst_ri *a, int rt2) addr = op_addr_ri_pre(s, a); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL); store_reg(s, a->rt, tmp); tcg_gen_addi_i32(addr, addr, 4); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL); store_reg(s, rt2, tmp); /* LDRD w/ base writeback is undefined if the registers overlap. */ @@ -6692,13 +6697,13 @@ static bool op_strd_ri(DisasContext *s, arg_ldst_ri *a, int rt2) addr = op_addr_ri_pre(s, a); tmp = load_reg(s, a->rt); - gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL); tcg_temp_free_i32(tmp); tcg_gen_addi_i32(addr, addr, 4); tmp = load_reg(s, rt2); - gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | s->be_data); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL); tcg_temp_free_i32(tmp); op_addr_ri_post(s, a, addr, -4); @@ -6924,7 +6929,7 @@ static bool op_stl(DisasContext *s, arg_STL *a, MemOp mop) addr = load_reg(s, a->rn); tmp = load_reg(s, a->rt); tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); - gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), mop | s->be_data); + gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), mop); disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel | ISSIsWrite); tcg_temp_free_i32(tmp); @@ -7080,7 +7085,7 @@ static bool op_lda(DisasContext *s, arg_LDA *a, MemOp mop) addr = load_reg(s, a->rn); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop | s->be_data); + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop); disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel); tcg_temp_free_i32(addr); @@ -8264,8 +8269,7 @@ static bool op_tbranch(DisasContext *s, arg_tbranch *a, bool half) addr = load_reg(s, a->rn); tcg_gen_add_i32(addr, addr, tmp); - gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), - half ? MO_UW | s->be_data : MO_UB); + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), half ? MO_UW : MO_UB); tcg_temp_free_i32(addr); tcg_gen_add_i32(tmp, tmp, tmp); diff --git a/target/arm/translate.h b/target/arm/translate.h index b185c14a03..0c60b83b3d 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -459,4 +459,28 @@ static inline TCGv_ptr fpstatus_ptr(ARMFPStatusFlavour flavour) return statusptr; } +/** + * finalize_memop: + * @s: DisasContext + * @opc: size+sign+align of the memory operation + * + * Build the complete MemOp for a memory operation, including alignment + * and endianness. + * + * If (op & MO_AMASK) then the operation already contains the required + * alignment, e.g. for AccType_ATOMIC. Otherwise, this an optionally + * unaligned operation, e.g. for AccType_NORMAL. + * + * In the latter case, there are configuration bits that require alignment, + * and this is applied here. Note that there is no way to indicate that + * no alignment should ever be enforced; this must be handled manually. + */ +static inline MemOp finalize_memop(DisasContext *s, MemOp opc) +{ + if (s->align_mem && !(opc & MO_AMASK)) { + opc |= MO_ALIGN; + } + return opc | s->be_data; +} + #endif /* TARGET_ARM_TRANSLATE_H */ From 37bf7a055f6b26a398dd0e953bf73d44e2312b33 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:38 -0700 Subject: [PATCH 0028/3028] target/arm: Merge gen_aa32_frob64 into gen_aa32_ld_i64 This is the only caller. Adjust some commentary to talk about SCTLR_B instead of the vanishing function. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 5bf68b782a..2f2a6d76b4 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -975,20 +975,17 @@ static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, gen_aa32_st_i32(s, val, a32, index, OPC); \ } -static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val) -{ - /* Not needed for user-mode BE32, where we use MO_BE instead. */ - if (!IS_USER_ONLY && s->sctlr_b) { - tcg_gen_rotri_i64(val, val, 32); - } -} - static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); tcg_gen_qemu_ld_i64(val, addr, index, opc); - gen_aa32_frob64(s, val); + + /* Not needed for user-mode BE32, where we use MO_BE instead. */ + if (!IS_USER_ONLY && s->sctlr_b) { + tcg_gen_rotri_i64(val, val, 32); + } + tcg_temp_free(addr); } @@ -4987,16 +4984,13 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, TCGv_i32 tmp2 = tcg_temp_new_i32(); TCGv_i64 t64 = tcg_temp_new_i64(); - /* For AArch32, architecturally the 32-bit word at the lowest + /* + * For AArch32, architecturally the 32-bit word at the lowest * address is always Rt and the one at addr+4 is Rt2, even if * the CPU is big-endian. That means we don't want to do a - * gen_aa32_ld_i64(), which invokes gen_aa32_frob64() as if - * for an architecturally 64-bit access, but instead do a - * 64-bit access using MO_BE if appropriate and then split - * the two halves. - * This only makes a difference for BE32 user-mode, where - * frob64() must not flip the two halves of the 64-bit data - * but this code must treat BE32 user-mode like BE32 system. + * gen_aa32_ld_i64(), which checks SCTLR_B as if for an + * architecturally 64-bit access, but instead do a 64-bit access + * using MO_BE if appropriate and then split the two halves. */ TCGv taddr = gen_aa32_addr(s, addr, opc); @@ -5056,14 +5050,15 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, TCGv_i64 n64 = tcg_temp_new_i64(); t2 = load_reg(s, rt2); - /* For AArch32, architecturally the 32-bit word at the lowest + + /* + * For AArch32, architecturally the 32-bit word at the lowest * address is always Rt and the one at addr+4 is Rt2, even if * the CPU is big-endian. Since we're going to treat this as a * single 64-bit BE store, we need to put the two halves in the * opposite order for BE to LE, so that they end up in the right - * places. - * We don't want gen_aa32_frob64() because that does the wrong - * thing for BE32 usermode. + * places. We don't want gen_aa32_st_i64, because that checks + * SCTLR_B as if for an architectural 64-bit access. */ if (s->be_data == MO_BE) { tcg_gen_concat_i32_i64(n64, t2, t1); From 9565ac4cc7e1d1aaccf3d8c6aed423b776e7995f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:39 -0700 Subject: [PATCH 0029/3028] target/arm: Fix SCTLR_B test for TCGv_i64 load/store Just because operating on a TCGv_i64 temporary does not mean that we're performing a 64-bit operation. Restrict the frobbing to actual 64-bit operations. This bug is not currently visible because all current users of these two functions always pass MO_64. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 2f2a6d76b4..e99c0ab5cb 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -982,7 +982,7 @@ static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, tcg_gen_qemu_ld_i64(val, addr, index, opc); /* Not needed for user-mode BE32, where we use MO_BE instead. */ - if (!IS_USER_ONLY && s->sctlr_b) { + if (!IS_USER_ONLY && s->sctlr_b && (opc & MO_SIZE) == MO_64) { tcg_gen_rotri_i64(val, val, 32); } @@ -1001,7 +1001,7 @@ static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, TCGv addr = gen_aa32_addr(s, a32, opc); /* Not needed for user-mode BE32, where we use MO_BE instead. */ - if (!IS_USER_ONLY && s->sctlr_b) { + if (!IS_USER_ONLY && s->sctlr_b && (opc & MO_SIZE) == MO_64) { TCGv_i64 tmp = tcg_temp_new_i64(); tcg_gen_rotri_i64(tmp, val, 32); tcg_gen_qemu_st_i64(tmp, addr, index, opc); From abe66294e1d4899b312c296e93abcd3b88f2492e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:40 -0700 Subject: [PATCH 0030/3028] target/arm: Adjust gen_aa32_{ld, st}_i64 for align+endianness Adjust the interface to match what has been done to the TCGv_i32 load/store functions. This is less obvious, because at present the only user of these functions, trans_VLDST_multiple, also wants to manipulate the endianness to speed up loading multiple bytes. Thus we retain an "internal" interface which is identical to the current gen_aa32_{ld,st}_i64 interface. The "new" interface will gain users as we remove the legacy interfaces, gen_aa32_ld64 and gen_aa32_st64. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-neon.c.inc | 6 ++- target/arm/translate.c | 78 +++++++++++++++++++-------------- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c.inc index c82aa1412e..18d9042130 100644 --- a/target/arm/translate-neon.c.inc +++ b/target/arm/translate-neon.c.inc @@ -494,11 +494,13 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) int tt = a->vd + reg + spacing * xs; if (a->l) { - gen_aa32_ld_i64(s, tmp64, addr, mmu_idx, endian | size); + gen_aa32_ld_internal_i64(s, tmp64, addr, mmu_idx, + endian | size); neon_store_element64(tt, n, size, tmp64); } else { neon_load_element64(tmp64, tt, n, size); - gen_aa32_st_i64(s, tmp64, addr, mmu_idx, endian | size); + gen_aa32_st_internal_i64(s, tmp64, addr, mmu_idx, + endian | size); } tcg_gen_add_i32(addr, addr, tmp); } diff --git a/target/arm/translate.c b/target/arm/translate.c index e99c0ab5cb..21b241b1ce 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -949,6 +949,37 @@ static void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, tcg_temp_free(addr); } +static void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index, MemOp opc) +{ + TCGv addr = gen_aa32_addr(s, a32, opc); + + tcg_gen_qemu_ld_i64(val, addr, index, opc); + + /* Not needed for user-mode BE32, where we use MO_BE instead. */ + if (!IS_USER_ONLY && s->sctlr_b && (opc & MO_SIZE) == MO_64) { + tcg_gen_rotri_i64(val, val, 32); + } + tcg_temp_free(addr); +} + +static void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index, MemOp opc) +{ + TCGv addr = gen_aa32_addr(s, a32, opc); + + /* Not needed for user-mode BE32, where we use MO_BE instead. */ + if (!IS_USER_ONLY && s->sctlr_b && (opc & MO_SIZE) == MO_64) { + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_rotri_i64(tmp, val, 32); + tcg_gen_qemu_st_i64(tmp, addr, index, opc); + tcg_temp_free_i64(tmp); + } else { + tcg_gen_qemu_st_i64(val, addr, index, opc); + } + tcg_temp_free(addr); +} + static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, int index, MemOp opc) { @@ -961,6 +992,18 @@ static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, gen_aa32_st_internal_i32(s, val, a32, index, finalize_memop(s, opc)); } +static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, + int index, MemOp opc) +{ + gen_aa32_ld_internal_i64(s, val, a32, index, finalize_memop(s, opc)); +} + +static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, + int index, MemOp opc) +{ + gen_aa32_st_internal_i64(s, val, a32, index, finalize_memop(s, opc)); +} + #define DO_GEN_LD(SUFF, OPC) \ static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \ TCGv_i32 a32, int index) \ @@ -975,47 +1018,16 @@ static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, gen_aa32_st_i32(s, val, a32, index, OPC); \ } -static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, - int index, MemOp opc) -{ - TCGv addr = gen_aa32_addr(s, a32, opc); - tcg_gen_qemu_ld_i64(val, addr, index, opc); - - /* Not needed for user-mode BE32, where we use MO_BE instead. */ - if (!IS_USER_ONLY && s->sctlr_b && (opc & MO_SIZE) == MO_64) { - tcg_gen_rotri_i64(val, val, 32); - } - - tcg_temp_free(addr); -} - static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, int index) { - gen_aa32_ld_i64(s, val, a32, index, MO_Q | s->be_data); -} - -static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, - int index, MemOp opc) -{ - TCGv addr = gen_aa32_addr(s, a32, opc); - - /* Not needed for user-mode BE32, where we use MO_BE instead. */ - if (!IS_USER_ONLY && s->sctlr_b && (opc & MO_SIZE) == MO_64) { - TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_rotri_i64(tmp, val, 32); - tcg_gen_qemu_st_i64(tmp, addr, index, opc); - tcg_temp_free_i64(tmp); - } else { - tcg_gen_qemu_st_i64(val, addr, index, opc); - } - tcg_temp_free(addr); + gen_aa32_ld_i64(s, val, a32, index, MO_Q); } static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, int index) { - gen_aa32_st_i64(s, val, a32, index, MO_Q | s->be_data); + gen_aa32_st_i64(s, val, a32, index, MO_Q); } DO_GEN_LD(8u, MO_UB) From 4d753eb5fb03ee7bc71ecd453a650b7546be81da Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:41 -0700 Subject: [PATCH 0031/3028] target/arm: Enforce word alignment for LDRD/STRD Buglink: https://bugs.launchpad.net/qemu/+bug/1905356 Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 21b241b1ce..4b0dba9e77 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -6520,13 +6520,13 @@ static bool trans_LDRD_rr(DisasContext *s, arg_ldst_rr *a) addr = op_addr_rr_pre(s, a); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); store_reg(s, a->rt, tmp); tcg_gen_addi_i32(addr, addr, 4); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); store_reg(s, a->rt + 1, tmp); /* LDRD w/ base writeback is undefined if the registers overlap. */ @@ -6549,13 +6549,13 @@ static bool trans_STRD_rr(DisasContext *s, arg_ldst_rr *a) addr = op_addr_rr_pre(s, a); tmp = load_reg(s, a->rt); - gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); tcg_temp_free_i32(tmp); tcg_gen_addi_i32(addr, addr, 4); tmp = load_reg(s, a->rt + 1); - gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); tcg_temp_free_i32(tmp); op_addr_rr_post(s, a, addr, -4); @@ -6665,13 +6665,13 @@ static bool op_ldrd_ri(DisasContext *s, arg_ldst_ri *a, int rt2) addr = op_addr_ri_pre(s, a); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); store_reg(s, a->rt, tmp); tcg_gen_addi_i32(addr, addr, 4); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); store_reg(s, rt2, tmp); /* LDRD w/ base writeback is undefined if the registers overlap. */ @@ -6704,13 +6704,13 @@ static bool op_strd_ri(DisasContext *s, arg_ldst_ri *a, int rt2) addr = op_addr_ri_pre(s, a); tmp = load_reg(s, a->rt); - gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); tcg_temp_free_i32(tmp); tcg_gen_addi_i32(addr, addr, 4); tmp = load_reg(s, rt2); - gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); tcg_temp_free_i32(tmp); op_addr_ri_post(s, a, addr, -4); From 824efdf5256399c9830941ddd78c28e3aa4618d8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:42 -0700 Subject: [PATCH 0032/3028] target/arm: Enforce alignment for LDA/LDAH/STL/STLH Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 4b0dba9e77..f5a214e35e 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -6936,7 +6936,7 @@ static bool op_stl(DisasContext *s, arg_STL *a, MemOp mop) addr = load_reg(s, a->rn); tmp = load_reg(s, a->rt); tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); - gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), mop); + gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), mop | MO_ALIGN); disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel | ISSIsWrite); tcg_temp_free_i32(tmp); @@ -7092,7 +7092,7 @@ static bool op_lda(DisasContext *s, arg_LDA *a, MemOp mop) addr = load_reg(s, a->rn); tmp = tcg_temp_new_i32(); - gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop); + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop | MO_ALIGN); disas_set_da_iss(s, mop, a->rt | ISSIsAcqRel); tcg_temp_free_i32(addr); From 2e1f39e29bf9a6b28eaee9fc0949aab50dbad94a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:43 -0700 Subject: [PATCH 0033/3028] target/arm: Enforce alignment for LDM/STM Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-18-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index f5a214e35e..9095c4a86f 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -7884,7 +7884,7 @@ static bool op_stm(DisasContext *s, arg_ldst_block *a, int min_n) } else { tmp = load_reg(s, i); } - gen_aa32_st32(s, tmp, addr, mem_idx); + gen_aa32_st_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); tcg_temp_free_i32(tmp); /* No need to add after the last transfer. */ @@ -7959,7 +7959,7 @@ static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) } tmp = tcg_temp_new_i32(); - gen_aa32_ld32u(s, tmp, addr, mem_idx); + gen_aa32_ld_i32(s, tmp, addr, mem_idx, MO_UL | MO_ALIGN); if (user) { tmp2 = tcg_const_i32(i); gen_helper_set_user_reg(cpu_env, tmp2, tmp); From c0c7f66087b193303bf9afe6e5e675fd02a17e12 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:44 -0700 Subject: [PATCH 0034/3028] target/arm: Enforce alignment for RFE Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-19-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 9095c4a86f..b8704d2504 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8357,10 +8357,10 @@ static bool trans_RFE(DisasContext *s, arg_RFE *a) /* Load PC into tmp and CPSR into tmp2. */ t1 = tcg_temp_new_i32(); - gen_aa32_ld32u(s, t1, addr, get_mem_index(s)); + gen_aa32_ld_i32(s, t1, addr, get_mem_index(s), MO_UL | MO_ALIGN); tcg_gen_addi_i32(addr, addr, 4); t2 = tcg_temp_new_i32(); - gen_aa32_ld32u(s, t2, addr, get_mem_index(s)); + gen_aa32_ld_i32(s, t2, addr, get_mem_index(s), MO_UL | MO_ALIGN); if (a->w) { /* Base writeback. */ From 2fd0800c68b48c5402eea0f88bd68aadfdc15004 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:45 -0700 Subject: [PATCH 0035/3028] target/arm: Enforce alignment for SRS Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-20-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index b8704d2504..3b071012ca 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5200,11 +5200,11 @@ static void gen_srs(DisasContext *s, } tcg_gen_addi_i32(addr, addr, offset); tmp = load_reg(s, 14); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); + gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN); tcg_temp_free_i32(tmp); tmp = load_cpu_field(spsr); tcg_gen_addi_i32(addr, addr, 4); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); + gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN); tcg_temp_free_i32(tmp); if (writeback) { switch (amode) { From ad9aeae1a9bbb3498bb8acfc13799f9e1cd86c97 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:46 -0700 Subject: [PATCH 0036/3028] target/arm: Enforce alignment for VLDM/VSTM Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-21-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-vfp.c.inc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c.inc index 10766f210c..f50afb23e7 100644 --- a/target/arm/translate-vfp.c.inc +++ b/target/arm/translate-vfp.c.inc @@ -1503,12 +1503,12 @@ static bool trans_VLDM_VSTM_sp(DisasContext *s, arg_VLDM_VSTM_sp *a) for (i = 0; i < n; i++) { if (a->l) { /* load */ - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN); vfp_store_reg32(tmp, a->vd + i); } else { /* store */ vfp_load_reg32(tmp, a->vd + i); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); + gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN); } tcg_gen_addi_i32(addr, addr, offset); } @@ -1586,12 +1586,12 @@ static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a) for (i = 0; i < n; i++) { if (a->l) { /* load */ - gen_aa32_ld64(s, tmp, addr, get_mem_index(s)); + gen_aa32_ld_i64(s, tmp, addr, get_mem_index(s), MO_Q | MO_ALIGN_4); vfp_store_reg64(tmp, a->vd + i); } else { /* store */ vfp_load_reg64(tmp, a->vd + i); - gen_aa32_st64(s, tmp, addr, get_mem_index(s)); + gen_aa32_st_i64(s, tmp, addr, get_mem_index(s), MO_Q | MO_ALIGN_4); } tcg_gen_addi_i32(addr, addr, offset); } From 6cd623d166025c8299f76ba0389fd7e879f82779 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:47 -0700 Subject: [PATCH 0037/3028] target/arm: Enforce alignment for VLDR/VSTR Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-22-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-vfp.c.inc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c.inc index f50afb23e7..e20d9c7ba6 100644 --- a/target/arm/translate-vfp.c.inc +++ b/target/arm/translate-vfp.c.inc @@ -1364,11 +1364,11 @@ static bool trans_VLDR_VSTR_hp(DisasContext *s, arg_VLDR_VSTR_sp *a) addr = add_reg_for_lit(s, a->rn, offset); tmp = tcg_temp_new_i32(); if (a->l) { - gen_aa32_ld16u(s, tmp, addr, get_mem_index(s)); + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), MO_UW | MO_ALIGN); vfp_store_reg32(tmp, a->vd); } else { vfp_load_reg32(tmp, a->vd); - gen_aa32_st16(s, tmp, addr, get_mem_index(s)); + gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), MO_UW | MO_ALIGN); } tcg_temp_free_i32(tmp); tcg_temp_free_i32(addr); @@ -1398,11 +1398,11 @@ static bool trans_VLDR_VSTR_sp(DisasContext *s, arg_VLDR_VSTR_sp *a) addr = add_reg_for_lit(s, a->rn, offset); tmp = tcg_temp_new_i32(); if (a->l) { - gen_aa32_ld32u(s, tmp, addr, get_mem_index(s)); + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN); vfp_store_reg32(tmp, a->vd); } else { vfp_load_reg32(tmp, a->vd); - gen_aa32_st32(s, tmp, addr, get_mem_index(s)); + gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), MO_UL | MO_ALIGN); } tcg_temp_free_i32(tmp); tcg_temp_free_i32(addr); @@ -1439,11 +1439,11 @@ static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a) addr = add_reg_for_lit(s, a->rn, offset); tmp = tcg_temp_new_i64(); if (a->l) { - gen_aa32_ld64(s, tmp, addr, get_mem_index(s)); + gen_aa32_ld_i64(s, tmp, addr, get_mem_index(s), MO_Q | MO_ALIGN_4); vfp_store_reg64(tmp, a->vd); } else { vfp_load_reg64(tmp, a->vd); - gen_aa32_st64(s, tmp, addr, get_mem_index(s)); + gen_aa32_st_i64(s, tmp, addr, get_mem_index(s), MO_Q | MO_ALIGN_4); } tcg_temp_free_i64(tmp); tcg_temp_free_i32(addr); From a8502b37f69f256456ee6599a7850db38e5cc90a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:48 -0700 Subject: [PATCH 0038/3028] target/arm: Enforce alignment for VLDn (all lanes) Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-23-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-neon.c.inc | 37 +++++++++++++++++++++++++-------- target/arm/translate.c | 15 +++++++++++++ target/arm/translate.h | 1 + 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c.inc index 18d9042130..9c2b076027 100644 --- a/target/arm/translate-neon.c.inc +++ b/target/arm/translate-neon.c.inc @@ -522,6 +522,7 @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) int size = a->size; int nregs = a->n + 1; TCGv_i32 addr, tmp; + MemOp mop, align; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { return false; @@ -532,18 +533,33 @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) return false; } + align = 0; if (size == 3) { if (nregs != 4 || a->a == 0) { return false; } /* For VLD4 size == 3 a == 1 means 32 bits at 16 byte alignment */ - size = 2; - } - if (nregs == 1 && a->a == 1 && size == 0) { - return false; - } - if (nregs == 3 && a->a == 1) { - return false; + size = MO_32; + align = MO_ALIGN_16; + } else if (a->a) { + switch (nregs) { + case 1: + if (size == 0) { + return false; + } + align = MO_ALIGN; + break; + case 2: + align = pow2_align(size + 1); + break; + case 3: + return false; + case 4: + align = pow2_align(size + 2); + break; + default: + g_assert_not_reached(); + } } if (!vfp_access_check(s)) { @@ -556,12 +572,12 @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) */ stride = a->t ? 2 : 1; vec_size = nregs == 1 ? stride * 8 : 8; - + mop = size | align; tmp = tcg_temp_new_i32(); addr = tcg_temp_new_i32(); load_reg_var(s, addr, a->rn); for (reg = 0; reg < nregs; reg++) { - gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), size); + gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), mop); if ((vd & 1) && vec_size == 16) { /* * We cannot write 16 bytes at once because the @@ -577,6 +593,9 @@ static bool trans_VLD_all_lanes(DisasContext *s, arg_VLD_all_lanes *a) } tcg_gen_addi_i32(addr, addr, 1 << size); vd += stride; + + /* Subsequent memory operations inherit alignment */ + mop &= ~MO_AMASK; } tcg_temp_free_i32(tmp); tcg_temp_free_i32(addr); diff --git a/target/arm/translate.c b/target/arm/translate.c index 3b071012ca..43ff0d4b8a 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -908,6 +908,21 @@ static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var) #define IS_USER_ONLY 0 #endif +MemOp pow2_align(unsigned i) +{ + static const MemOp mop_align[] = { + 0, MO_ALIGN_2, MO_ALIGN_4, MO_ALIGN_8, MO_ALIGN_16, + /* + * FIXME: TARGET_PAGE_BITS_MIN affects TLB_FLAGS_MASK such + * that 256-bit alignment (MO_ALIGN_32) cannot be supported: + * see get_alignment_bits(). Enforce only 128-bit alignment for now. + */ + MO_ALIGN_16 + }; + g_assert(i < ARRAY_SIZE(mop_align)); + return mop_align[i]; +} + /* * Abstractions of "generate code to do a guest load/store for * AArch32", where a vaddr is always 32 bits (and is zero diff --git a/target/arm/translate.h b/target/arm/translate.h index 0c60b83b3d..ccf60c96d8 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -204,6 +204,7 @@ void arm_test_cc(DisasCompare *cmp, int cc); void arm_free_cc(DisasCompare *cmp); void arm_jump_cc(DisasCompare *cmp, TCGLabel *label); void arm_gen_test_cc(int cc, TCGLabel *label); +MemOp pow2_align(unsigned i); /* Return state of Alternate Half-precision flag, caller frees result */ static inline TCGv_i32 get_ahp_flag(void) From 7c68c196cf693e6098a04bd24985004db5983914 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:49 -0700 Subject: [PATCH 0039/3028] target/arm: Enforce alignment for VLDn/VSTn (multiple) Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-24-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-neon.c.inc | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c.inc index 9c2b076027..e706c37c80 100644 --- a/target/arm/translate-neon.c.inc +++ b/target/arm/translate-neon.c.inc @@ -429,7 +429,7 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) { /* Neon load/store multiple structures */ int nregs, interleave, spacing, reg, n; - MemOp endian = s->be_data; + MemOp mop, align, endian; int mmu_idx = get_mem_index(s); int size = a->size; TCGv_i64 tmp64; @@ -473,20 +473,36 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) } /* For our purposes, bytes are always little-endian. */ + endian = s->be_data; if (size == 0) { endian = MO_LE; } + + /* Enforce alignment requested by the instruction */ + if (a->align) { + align = pow2_align(a->align + 2); /* 4 ** a->align */ + } else { + align = s->align_mem ? MO_ALIGN : 0; + } + /* * Consecutive little-endian elements from a single register * can be promoted to a larger little-endian operation. */ if (interleave == 1 && endian == MO_LE) { + /* Retain any natural alignment. */ + if (align == MO_ALIGN) { + align = pow2_align(size); + } size = 3; } + tmp64 = tcg_temp_new_i64(); addr = tcg_temp_new_i32(); tmp = tcg_const_i32(1 << size); load_reg_var(s, addr, a->rn); + + mop = endian | size | align; for (reg = 0; reg < nregs; reg++) { for (n = 0; n < 8 >> size; n++) { int xs; @@ -494,15 +510,16 @@ static bool trans_VLDST_multiple(DisasContext *s, arg_VLDST_multiple *a) int tt = a->vd + reg + spacing * xs; if (a->l) { - gen_aa32_ld_internal_i64(s, tmp64, addr, mmu_idx, - endian | size); + gen_aa32_ld_internal_i64(s, tmp64, addr, mmu_idx, mop); neon_store_element64(tt, n, size, tmp64); } else { neon_load_element64(tmp64, tt, n, size); - gen_aa32_st_internal_i64(s, tmp64, addr, mmu_idx, - endian | size); + gen_aa32_st_internal_i64(s, tmp64, addr, mmu_idx, mop); } tcg_gen_add_i32(addr, addr, tmp); + + /* Subsequent memory operations inherit alignment */ + mop &= ~MO_AMASK; } } } From 88976ff0a4a8b27046df6fd05fb7be70a2f987da Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:50 -0700 Subject: [PATCH 0040/3028] target/arm: Enforce alignment for VLDn/VSTn (single) Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-25-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-neon.c.inc | 48 ++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c.inc index e706c37c80..a02b8369a1 100644 --- a/target/arm/translate-neon.c.inc +++ b/target/arm/translate-neon.c.inc @@ -629,6 +629,7 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) int nregs = a->n + 1; int vd = a->vd; TCGv_i32 addr, tmp; + MemOp mop; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { return false; @@ -678,23 +679,58 @@ static bool trans_VLDST_single(DisasContext *s, arg_VLDST_single *a) return true; } + /* Pick up SCTLR settings */ + mop = finalize_memop(s, a->size); + + if (a->align) { + MemOp align_op; + + switch (nregs) { + case 1: + /* For VLD1, use natural alignment. */ + align_op = MO_ALIGN; + break; + case 2: + /* For VLD2, use double alignment. */ + align_op = pow2_align(a->size + 1); + break; + case 4: + if (a->size == MO_32) { + /* + * For VLD4.32, align = 1 is double alignment, align = 2 is + * quad alignment; align = 3 is rejected above. + */ + align_op = pow2_align(a->size + a->align); + } else { + /* For VLD4.8 and VLD.16, we want quad alignment. */ + align_op = pow2_align(a->size + 2); + } + break; + default: + /* For VLD3, the alignment field is zero and rejected above. */ + g_assert_not_reached(); + } + + mop = (mop & ~MO_AMASK) | align_op; + } + tmp = tcg_temp_new_i32(); addr = tcg_temp_new_i32(); load_reg_var(s, addr, a->rn); - /* - * TODO: if we implemented alignment exceptions, we should check - * addr against the alignment encoded in a->align here. - */ + for (reg = 0; reg < nregs; reg++) { if (a->l) { - gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), a->size); + gen_aa32_ld_internal_i32(s, tmp, addr, get_mem_index(s), mop); neon_store_element(vd, a->reg_idx, a->size, tmp); } else { /* Store */ neon_load_element(tmp, vd, a->reg_idx, a->size); - gen_aa32_st_i32(s, tmp, addr, get_mem_index(s), a->size); + gen_aa32_st_internal_i32(s, tmp, addr, get_mem_index(s), mop); } vd += a->stride; tcg_gen_addi_i32(addr, addr, 1 << a->size); + + /* Subsequent memory operations inherit alignment */ + mop &= ~MO_AMASK; } tcg_temp_free_i32(addr); tcg_temp_free_i32(tmp); From dc821642296ad0307ae6c0220e4b9ba1ae165d9e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:51 -0700 Subject: [PATCH 0041/3028] target/arm: Use finalize_memop for aa64 gpr load/store In the case of gpr load, merge the size and is_signed arguments; otherwise, simply convert size to memop. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-26-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 78 ++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 92a62b1a75..f2995d2b74 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -886,19 +886,19 @@ static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1) * Store from GPR register to memory. */ static void do_gpr_st_memidx(DisasContext *s, TCGv_i64 source, - TCGv_i64 tcg_addr, int size, int memidx, + TCGv_i64 tcg_addr, MemOp memop, int memidx, bool iss_valid, unsigned int iss_srt, bool iss_sf, bool iss_ar) { - g_assert(size <= 3); - tcg_gen_qemu_st_i64(source, tcg_addr, memidx, s->be_data + size); + memop = finalize_memop(s, memop); + tcg_gen_qemu_st_i64(source, tcg_addr, memidx, memop); if (iss_valid) { uint32_t syn; syn = syn_data_abort_with_iss(0, - size, + (memop & MO_SIZE), false, iss_srt, iss_sf, @@ -909,37 +909,28 @@ static void do_gpr_st_memidx(DisasContext *s, TCGv_i64 source, } static void do_gpr_st(DisasContext *s, TCGv_i64 source, - TCGv_i64 tcg_addr, int size, + TCGv_i64 tcg_addr, MemOp memop, bool iss_valid, unsigned int iss_srt, bool iss_sf, bool iss_ar) { - do_gpr_st_memidx(s, source, tcg_addr, size, get_mem_index(s), + do_gpr_st_memidx(s, source, tcg_addr, memop, get_mem_index(s), iss_valid, iss_srt, iss_sf, iss_ar); } /* * Load from memory to GPR register */ -static void do_gpr_ld_memidx(DisasContext *s, - TCGv_i64 dest, TCGv_i64 tcg_addr, - int size, bool is_signed, - bool extend, int memidx, +static void do_gpr_ld_memidx(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr, + MemOp memop, bool extend, int memidx, bool iss_valid, unsigned int iss_srt, bool iss_sf, bool iss_ar) { - MemOp memop = s->be_data + size; - - g_assert(size <= 3); - - if (is_signed) { - memop += MO_SIGN; - } - + memop = finalize_memop(s, memop); tcg_gen_qemu_ld_i64(dest, tcg_addr, memidx, memop); - if (extend && is_signed) { - g_assert(size < 3); + if (extend && (memop & MO_SIGN)) { + g_assert((memop & MO_SIZE) <= MO_32); tcg_gen_ext32u_i64(dest, dest); } @@ -947,8 +938,8 @@ static void do_gpr_ld_memidx(DisasContext *s, uint32_t syn; syn = syn_data_abort_with_iss(0, - size, - is_signed, + (memop & MO_SIZE), + (memop & MO_SIGN) != 0, iss_srt, iss_sf, iss_ar, @@ -957,14 +948,12 @@ static void do_gpr_ld_memidx(DisasContext *s, } } -static void do_gpr_ld(DisasContext *s, - TCGv_i64 dest, TCGv_i64 tcg_addr, - int size, bool is_signed, bool extend, +static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr, + MemOp memop, bool extend, bool iss_valid, unsigned int iss_srt, bool iss_sf, bool iss_ar) { - do_gpr_ld_memidx(s, dest, tcg_addr, size, is_signed, extend, - get_mem_index(s), + do_gpr_ld_memidx(s, dest, tcg_addr, memop, extend, get_mem_index(s), iss_valid, iss_srt, iss_sf, iss_ar); } @@ -2717,7 +2706,7 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) } clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), false, rn != 31, size); - do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, false, true, rt, + do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, true, rt, disas_ldst_compute_iss_sf(size, false, 0), is_lasr); tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); return; @@ -2830,8 +2819,8 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn) /* Only unsigned 32bit loads target 32bit registers. */ bool iss_sf = opc != 0; - do_gpr_ld(s, tcg_rt, clean_addr, size, is_signed, false, - true, rt, iss_sf, false); + do_gpr_ld(s, tcg_rt, clean_addr, size + is_signed * MO_SIGN, + false, true, rt, iss_sf, false); } tcg_temp_free_i64(clean_addr); } @@ -2989,11 +2978,11 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn) /* Do not modify tcg_rt before recognizing any exception * from the second load. */ - do_gpr_ld(s, tmp, clean_addr, size, is_signed, false, - false, 0, false, false); + do_gpr_ld(s, tmp, clean_addr, size + is_signed * MO_SIGN, + false, false, 0, false, false); tcg_gen_addi_i64(clean_addr, clean_addr, 1 << size); - do_gpr_ld(s, tcg_rt2, clean_addr, size, is_signed, false, - false, 0, false, false); + do_gpr_ld(s, tcg_rt2, clean_addr, size + is_signed * MO_SIGN, + false, false, 0, false, false); tcg_gen_mov_i64(tcg_rt, tmp); tcg_temp_free_i64(tmp); @@ -3124,8 +3113,8 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn, do_gpr_st_memidx(s, tcg_rt, clean_addr, size, memidx, iss_valid, rt, iss_sf, false); } else { - do_gpr_ld_memidx(s, tcg_rt, clean_addr, size, - is_signed, is_extended, memidx, + do_gpr_ld_memidx(s, tcg_rt, clean_addr, size + is_signed * MO_SIGN, + is_extended, memidx, iss_valid, rt, iss_sf, false); } } @@ -3229,9 +3218,8 @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn, do_gpr_st(s, tcg_rt, clean_addr, size, true, rt, iss_sf, false); } else { - do_gpr_ld(s, tcg_rt, clean_addr, size, - is_signed, is_extended, - true, rt, iss_sf, false); + do_gpr_ld(s, tcg_rt, clean_addr, size + is_signed * MO_SIGN, + is_extended, true, rt, iss_sf, false); } } } @@ -3314,8 +3302,8 @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn, do_gpr_st(s, tcg_rt, clean_addr, size, true, rt, iss_sf, false); } else { - do_gpr_ld(s, tcg_rt, clean_addr, size, is_signed, is_extended, - true, rt, iss_sf, false); + do_gpr_ld(s, tcg_rt, clean_addr, size + is_signed * MO_SIGN, + is_extended, true, rt, iss_sf, false); } } } @@ -3402,7 +3390,7 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn, * full load-acquire (we only need "load-acquire processor consistent"), * but we choose to implement them as full LDAQ. */ - do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, false, + do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, true, rt, disas_ldst_compute_iss_sf(size, false, 0), true); tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); return; @@ -3475,7 +3463,7 @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn, is_wback || rn != 31, size); tcg_rt = cpu_reg(s, rt); - do_gpr_ld(s, tcg_rt, clean_addr, size, /* is_signed */ false, + do_gpr_ld(s, tcg_rt, clean_addr, size, /* extend */ false, /* iss_valid */ !is_wback, /* iss_srt */ rt, /* iss_sf */ true, /* iss_ar */ false); @@ -3560,8 +3548,8 @@ static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn) * Load-AcquirePC semantics; we implement as the slightly more * restrictive Load-Acquire. */ - do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, is_signed, extend, - true, rt, iss_sf, true); + do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size + is_signed * MO_SIGN, + extend, true, rt, iss_sf, true); tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); } } From 4044a3cd1cdf07503b1fe896ca145328dceba435 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:52 -0700 Subject: [PATCH 0042/3028] target/arm: Use finalize_memop for aa64 fpr load/store For 128-bit load/store, use 16-byte alignment. This requires that we perform the two operations in the correct order so that we generate the alignment fault before modifying memory. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-27-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 42 +++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index f2995d2b74..b90d6880e7 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -963,25 +963,33 @@ static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr, static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size) { /* This writes the bottom N bits of a 128 bit wide vector to memory */ - TCGv_i64 tmp = tcg_temp_new_i64(); - tcg_gen_ld_i64(tmp, cpu_env, fp_reg_offset(s, srcidx, MO_64)); + TCGv_i64 tmplo = tcg_temp_new_i64(); + MemOp mop; + + tcg_gen_ld_i64(tmplo, cpu_env, fp_reg_offset(s, srcidx, MO_64)); + if (size < 4) { - tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), - s->be_data + size); + mop = finalize_memop(s, size); + tcg_gen_qemu_st_i64(tmplo, tcg_addr, get_mem_index(s), mop); } else { bool be = s->be_data == MO_BE; TCGv_i64 tcg_hiaddr = tcg_temp_new_i64(); + TCGv_i64 tmphi = tcg_temp_new_i64(); + tcg_gen_ld_i64(tmphi, cpu_env, fp_reg_hi_offset(s, srcidx)); + + mop = s->be_data | MO_Q; + tcg_gen_qemu_st_i64(be ? tmphi : tmplo, tcg_addr, get_mem_index(s), + mop | (s->align_mem ? MO_ALIGN_16 : 0)); tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8); - tcg_gen_qemu_st_i64(tmp, be ? tcg_hiaddr : tcg_addr, get_mem_index(s), - s->be_data | MO_Q); - tcg_gen_ld_i64(tmp, cpu_env, fp_reg_hi_offset(s, srcidx)); - tcg_gen_qemu_st_i64(tmp, be ? tcg_addr : tcg_hiaddr, get_mem_index(s), - s->be_data | MO_Q); + tcg_gen_qemu_st_i64(be ? tmplo : tmphi, tcg_hiaddr, + get_mem_index(s), mop); + tcg_temp_free_i64(tcg_hiaddr); + tcg_temp_free_i64(tmphi); } - tcg_temp_free_i64(tmp); + tcg_temp_free_i64(tmplo); } /* @@ -992,10 +1000,11 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size) /* This always zero-extends and writes to a full 128 bit wide vector */ TCGv_i64 tmplo = tcg_temp_new_i64(); TCGv_i64 tmphi = NULL; + MemOp mop; if (size < 4) { - MemOp memop = s->be_data + size; - tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop); + mop = finalize_memop(s, size); + tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), mop); } else { bool be = s->be_data == MO_BE; TCGv_i64 tcg_hiaddr; @@ -1003,11 +1012,12 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size) tmphi = tcg_temp_new_i64(); tcg_hiaddr = tcg_temp_new_i64(); + mop = s->be_data | MO_Q; + tcg_gen_qemu_ld_i64(be ? tmphi : tmplo, tcg_addr, get_mem_index(s), + mop | (s->align_mem ? MO_ALIGN_16 : 0)); tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8); - tcg_gen_qemu_ld_i64(tmplo, be ? tcg_hiaddr : tcg_addr, get_mem_index(s), - s->be_data | MO_Q); - tcg_gen_qemu_ld_i64(tmphi, be ? tcg_addr : tcg_hiaddr, get_mem_index(s), - s->be_data | MO_Q); + tcg_gen_qemu_ld_i64(be ? tmplo : tmphi, tcg_hiaddr, + get_mem_index(s), mop); tcg_temp_free_i64(tcg_hiaddr); } From acb07e08d634bc36a18936dd5e2ebc318bcaf3db Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:53 -0700 Subject: [PATCH 0043/3028] target/arm: Enforce alignment for aa64 load-acq/store-rel Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-28-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index b90d6880e7..ac60dcf760 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2699,7 +2699,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, size); - do_gpr_st(s, cpu_reg(s, rt), clean_addr, size, true, rt, + /* TODO: ARMv8.4-LSE SCTLR.nAA */ + do_gpr_st(s, cpu_reg(s, rt), clean_addr, size | MO_ALIGN, true, rt, disas_ldst_compute_iss_sf(size, false, 0), is_lasr); return; @@ -2716,8 +2717,9 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn) } clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), false, rn != 31, size); - do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, true, rt, - disas_ldst_compute_iss_sf(size, false, 0), is_lasr); + /* TODO: ARMv8.4-LSE SCTLR.nAA */ + do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size | MO_ALIGN, false, true, + rt, disas_ldst_compute_iss_sf(size, false, 0), is_lasr); tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); return; @@ -3505,15 +3507,18 @@ static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn) int size = extract32(insn, 30, 2); TCGv_i64 clean_addr, dirty_addr; bool is_store = false; - bool is_signed = false; bool extend = false; bool iss_sf; + MemOp mop; if (!dc_isar_feature(aa64_rcpc_8_4, s)) { unallocated_encoding(s); return; } + /* TODO: ARMv8.4-LSE SCTLR.nAA */ + mop = size | MO_ALIGN; + switch (opc) { case 0: /* STLURB */ is_store = true; @@ -3525,21 +3530,21 @@ static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn) unallocated_encoding(s); return; } - is_signed = true; + mop |= MO_SIGN; break; case 3: /* LDAPURS* 32-bit variant */ if (size > 1) { unallocated_encoding(s); return; } - is_signed = true; + mop |= MO_SIGN; extend = true; /* zero-extend 32->64 after signed load */ break; default: g_assert_not_reached(); } - iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc); + iss_sf = disas_ldst_compute_iss_sf(size, (mop & MO_SIGN) != 0, opc); if (rn == 31) { gen_check_sp_alignment(s); @@ -3552,13 +3557,13 @@ static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn) if (is_store) { /* Store-Release semantics */ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); - do_gpr_st(s, cpu_reg(s, rt), clean_addr, size, true, rt, iss_sf, true); + do_gpr_st(s, cpu_reg(s, rt), clean_addr, mop, true, rt, iss_sf, true); } else { /* * Load-AcquirePC semantics; we implement as the slightly more * restrictive Load-Acquire. */ - do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size + is_signed * MO_SIGN, + do_gpr_ld(s, cpu_reg(s, rt), clean_addr, mop, extend, true, rt, iss_sf, true); tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); } From a9e89e539ec3a67f5257ce055a8ed38bd58fc89f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:54 -0700 Subject: [PATCH 0044/3028] target/arm: Use MemOp for size + endian in aa64 vector ld/st Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-29-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index ac60dcf760..d3bda16ecd 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -1146,24 +1146,24 @@ static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src, /* Store from vector register to memory */ static void do_vec_st(DisasContext *s, int srcidx, int element, - TCGv_i64 tcg_addr, int size, MemOp endian) + TCGv_i64 tcg_addr, MemOp mop) { TCGv_i64 tcg_tmp = tcg_temp_new_i64(); - read_vec_element(s, tcg_tmp, srcidx, element, size); - tcg_gen_qemu_st_i64(tcg_tmp, tcg_addr, get_mem_index(s), endian | size); + read_vec_element(s, tcg_tmp, srcidx, element, mop & MO_SIZE); + tcg_gen_qemu_st_i64(tcg_tmp, tcg_addr, get_mem_index(s), mop); tcg_temp_free_i64(tcg_tmp); } /* Load from memory to vector register */ static void do_vec_ld(DisasContext *s, int destidx, int element, - TCGv_i64 tcg_addr, int size, MemOp endian) + TCGv_i64 tcg_addr, MemOp mop) { TCGv_i64 tcg_tmp = tcg_temp_new_i64(); - tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr, get_mem_index(s), endian | size); - write_vec_element(s, tcg_tmp, destidx, element, size); + tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr, get_mem_index(s), mop); + write_vec_element(s, tcg_tmp, destidx, element, mop & MO_SIZE); tcg_temp_free_i64(tcg_tmp); } @@ -3734,9 +3734,9 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) for (xs = 0; xs < selem; xs++) { int tt = (rt + r + xs) % 32; if (is_store) { - do_vec_st(s, tt, e, clean_addr, size, endian); + do_vec_st(s, tt, e, clean_addr, size | endian); } else { - do_vec_ld(s, tt, e, clean_addr, size, endian); + do_vec_ld(s, tt, e, clean_addr, size | endian); } tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes); } @@ -3885,9 +3885,9 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) } else { /* Load/store one element per register */ if (is_load) { - do_vec_ld(s, rt, index, clean_addr, scale, s->be_data); + do_vec_ld(s, rt, index, clean_addr, scale | s->be_data); } else { - do_vec_st(s, rt, index, clean_addr, scale, s->be_data); + do_vec_st(s, rt, index, clean_addr, scale | s->be_data); } } tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes); From c8f638d99aaf8284b9ba81fb49ad6985d109794f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:55 -0700 Subject: [PATCH 0045/3028] target/arm: Enforce alignment for aa64 vector LDn/STn (multiple) Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-30-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index d3bda16ecd..2a82dbbd6d 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -3635,7 +3635,7 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) bool is_postidx = extract32(insn, 23, 1); bool is_q = extract32(insn, 30, 1); TCGv_i64 clean_addr, tcg_rn, tcg_ebytes; - MemOp endian = s->be_data; + MemOp endian, align, mop; int total; /* total bytes */ int elements; /* elements per vector */ @@ -3703,6 +3703,7 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) } /* For our purposes, bytes are always little-endian. */ + endian = s->be_data; if (size == 0) { endian = MO_LE; } @@ -3721,11 +3722,17 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) * Consecutive little-endian elements from a single register * can be promoted to a larger little-endian operation. */ + align = MO_ALIGN; if (selem == 1 && endian == MO_LE) { + align = pow2_align(size); size = 3; } - elements = (is_q ? 16 : 8) >> size; + if (!s->align_mem) { + align = 0; + } + mop = endian | size | align; + elements = (is_q ? 16 : 8) >> size; tcg_ebytes = tcg_const_i64(1 << size); for (r = 0; r < rpt; r++) { int e; @@ -3734,9 +3741,9 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn) for (xs = 0; xs < selem; xs++) { int tt = (rt + r + xs) % 32; if (is_store) { - do_vec_st(s, tt, e, clean_addr, size | endian); + do_vec_st(s, tt, e, clean_addr, mop); } else { - do_vec_ld(s, tt, e, clean_addr, size | endian); + do_vec_ld(s, tt, e, clean_addr, mop); } tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes); } From 37abe399df6a8b7006a19f3378715b650599e8fa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:56 -0700 Subject: [PATCH 0046/3028] target/arm: Enforce alignment for aa64 vector LDn/STn (single) Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-31-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 2a82dbbd6d..95897e63af 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -3815,6 +3815,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) int index = is_q << 3 | S << 2 | size; int xs, total; TCGv_i64 clean_addr, tcg_rn, tcg_ebytes; + MemOp mop; if (extract32(insn, 31, 1)) { unallocated_encoding(s); @@ -3876,6 +3877,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) clean_addr = gen_mte_checkN(s, tcg_rn, !is_load, is_postidx || rn != 31, total); + mop = finalize_memop(s, scale); tcg_ebytes = tcg_const_i64(1 << scale); for (xs = 0; xs < selem; xs++) { @@ -3883,8 +3885,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) /* Load and replicate to all elements */ TCGv_i64 tcg_tmp = tcg_temp_new_i64(); - tcg_gen_qemu_ld_i64(tcg_tmp, clean_addr, - get_mem_index(s), s->be_data + scale); + tcg_gen_qemu_ld_i64(tcg_tmp, clean_addr, get_mem_index(s), mop); tcg_gen_gvec_dup_i64(scale, vec_full_reg_offset(s, rt), (is_q + 1) * 8, vec_full_reg_size(s), tcg_tmp); @@ -3892,9 +3893,9 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn) } else { /* Load/store one element per register */ if (is_load) { - do_vec_ld(s, rt, index, clean_addr, scale | s->be_data); + do_vec_ld(s, rt, index, clean_addr, mop); } else { - do_vec_st(s, rt, index, clean_addr, scale | s->be_data); + do_vec_st(s, rt, index, clean_addr, mop); } } tcg_gen_add_i64(clean_addr, clean_addr, tcg_ebytes); From 0ca0f8720a424a643d33cce802a4b769fbb62836 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 19 Apr 2021 13:22:57 -0700 Subject: [PATCH 0047/3028] target/arm: Enforce alignment for sve LD1R Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210419202257.161730-32-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-sve.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c index 584c4d047c..864ed669c4 100644 --- a/target/arm/translate-sve.c +++ b/target/arm/translate-sve.c @@ -5001,7 +5001,7 @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a) clean_addr = gen_mte_check1(s, temp, false, true, msz); tcg_gen_qemu_ld_i64(temp, clean_addr, get_mem_index(s), - s->be_data | dtype_mop[a->dtype]); + finalize_memop(s, dtype_mop[a->dtype])); /* Broadcast to *all* elements. */ tcg_gen_gvec_dup_i64(esz, vec_full_reg_offset(s, a->rd), From da7e13c00b5962016b9c72079bef5e0a5398db0d Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 31 Mar 2021 13:19:00 +0200 Subject: [PATCH 0048/3028] hw: add compat machines for 6.1 Add 6.1 machine types for arm/i440fx/q35/s390x/spapr. Signed-off-by: Cornelia Huck Acked-by: Greg Kurz Message-id: 20210331111900.118274-1-cohuck@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 7 ++++++- hw/core/machine.c | 3 +++ hw/i386/pc.c | 3 +++ hw/i386/pc_piix.c | 14 +++++++++++++- hw/i386/pc_q35.c | 13 ++++++++++++- hw/ppc/spapr.c | 17 ++++++++++++++--- hw/s390x/s390-virtio-ccw.c | 14 +++++++++++++- include/hw/boards.h | 3 +++ include/hw/i386/pc.h | 3 +++ 9 files changed, 70 insertions(+), 7 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 9f01d9041b..fee696fb0e 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2757,10 +2757,15 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); +static void virt_machine_6_1_options(MachineClass *mc) +{ +} +DEFINE_VIRT_MACHINE_AS_LATEST(6, 1) + static void virt_machine_6_0_options(MachineClass *mc) { } -DEFINE_VIRT_MACHINE_AS_LATEST(6, 0) +DEFINE_VIRT_MACHINE(6, 0) static void virt_machine_5_2_options(MachineClass *mc) { diff --git a/hw/core/machine.c b/hw/core/machine.c index 40def78183..cebcdcc351 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -36,6 +36,9 @@ #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-pci.h" +GlobalProperty hw_compat_6_0[] = {}; +const size_t hw_compat_6_0_len = G_N_ELEMENTS(hw_compat_6_0); + GlobalProperty hw_compat_5_2[] = { { "ICH9-LPC", "smm-compat", "on"}, { "PIIX4_PM", "smm-compat", "on"}, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 8a84b25a03..364816efc9 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -96,6 +96,9 @@ #include "trace.h" #include CONFIG_DEVICES +GlobalProperty pc_compat_6_0[] = {}; +const size_t pc_compat_6_0_len = G_N_ELEMENTS(pc_compat_6_0); + GlobalProperty pc_compat_5_2[] = { { "ICH9-LPC", "x-smi-cpu-hotunplug", "off" }, }; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 46cc951073..4e8edffeaf 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -415,7 +415,7 @@ static void pc_i440fx_machine_options(MachineClass *m) machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE); } -static void pc_i440fx_6_0_machine_options(MachineClass *m) +static void pc_i440fx_6_1_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_i440fx_machine_options(m); @@ -424,6 +424,18 @@ static void pc_i440fx_6_0_machine_options(MachineClass *m) pcmc->default_cpu_version = 1; } +DEFINE_I440FX_MACHINE(v6_1, "pc-i440fx-6.1", NULL, + pc_i440fx_6_1_machine_options); + +static void pc_i440fx_6_0_machine_options(MachineClass *m) +{ + pc_i440fx_6_1_machine_options(m); + m->alias = NULL; + m->is_default = false; + compat_props_add(m->compat_props, hw_compat_6_0, hw_compat_6_0_len); + compat_props_add(m->compat_props, pc_compat_6_0, pc_compat_6_0_len); +} + DEFINE_I440FX_MACHINE(v6_0, "pc-i440fx-6.0", NULL, pc_i440fx_6_0_machine_options); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 53450190f5..458ed41c65 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -345,7 +345,7 @@ static void pc_q35_machine_options(MachineClass *m) m->max_cpus = 288; } -static void pc_q35_6_0_machine_options(MachineClass *m) +static void pc_q35_6_1_machine_options(MachineClass *m) { PCMachineClass *pcmc = PC_MACHINE_CLASS(m); pc_q35_machine_options(m); @@ -353,6 +353,17 @@ static void pc_q35_6_0_machine_options(MachineClass *m) pcmc->default_cpu_version = 1; } +DEFINE_Q35_MACHINE(v6_1, "pc-q35-6.1", NULL, + pc_q35_6_1_machine_options); + +static void pc_q35_6_0_machine_options(MachineClass *m) +{ + pc_q35_6_1_machine_options(m); + m->alias = NULL; + compat_props_add(m->compat_props, hw_compat_6_0, hw_compat_6_0_len); + compat_props_add(m->compat_props, pc_compat_6_0, pc_compat_6_0_len); +} + DEFINE_Q35_MACHINE(v6_0, "pc-q35-6.0", NULL, pc_q35_6_0_machine_options); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index e4be00b732..529ff056dd 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4605,14 +4605,25 @@ static void spapr_machine_latest_class_options(MachineClass *mc) type_init(spapr_machine_register_##suffix) /* - * pseries-6.0 + * pseries-6.1 */ -static void spapr_machine_6_0_class_options(MachineClass *mc) +static void spapr_machine_6_1_class_options(MachineClass *mc) { /* Defaults for the latest behaviour inherited from the base class */ } -DEFINE_SPAPR_MACHINE(6_0, "6.0", true); +DEFINE_SPAPR_MACHINE(6_1, "6.1", true); + +/* + * pseries-6.0 + */ +static void spapr_machine_6_0_class_options(MachineClass *mc) +{ + spapr_machine_6_1_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len); +} + +DEFINE_SPAPR_MACHINE(6_0, "6.0", false); /* * pseries-5.2 diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 2972b607f3..56b52d2d30 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -795,14 +795,26 @@ bool css_migration_enabled(void) } \ type_init(ccw_machine_register_##suffix) +static void ccw_machine_6_1_instance_options(MachineState *machine) +{ +} + +static void ccw_machine_6_1_class_options(MachineClass *mc) +{ +} +DEFINE_CCW_MACHINE(6_1, "6.1", true); + static void ccw_machine_6_0_instance_options(MachineState *machine) { + ccw_machine_6_1_instance_options(machine); } static void ccw_machine_6_0_class_options(MachineClass *mc) { + ccw_machine_6_1_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len); } -DEFINE_CCW_MACHINE(6_0, "6.0", true); +DEFINE_CCW_MACHINE(6_0, "6.0", false); static void ccw_machine_5_2_instance_options(MachineState *machine) { diff --git a/include/hw/boards.h b/include/hw/boards.h index ad6c8fd537..3d55d2bd62 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -353,6 +353,9 @@ struct MachineState { } \ type_init(machine_initfn##_register_types) +extern GlobalProperty hw_compat_6_0[]; +extern const size_t hw_compat_6_0_len; + extern GlobalProperty hw_compat_5_2[]; extern const size_t hw_compat_5_2_len; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index dcf060b791..1522a3359a 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -197,6 +197,9 @@ bool pc_system_ovmf_table_find(const char *entry, uint8_t **data, void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, const CPUArchIdList *apic_ids, GArray *entry); +extern GlobalProperty pc_compat_6_0[]; +extern const size_t pc_compat_6_0_len; + extern GlobalProperty pc_compat_5_2[]; extern const size_t pc_compat_5_2_len; From a6091108aa44e9017af4ca13c43f55a629e3744c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 25 Mar 2021 16:33:15 +0000 Subject: [PATCH 0049/3028] hw/pci-host/gpex: Don't fault for unmapped parts of MMIO and PIO windows Currently the gpex PCI controller implements no special behaviour for guest accesses to areas of the PIO and MMIO where it has not mapped any PCI devices, which means that for Arm you end up with a CPU exception due to a data abort. Most host OSes expect "like an x86 PC" behaviour, where bad accesses like this return -1 for reads and ignore writes. In the interests of not being surprising, make host CPU accesses to these windows behave as -1/discard where there's no mapped PCI device. The old behaviour generally didn't cause any problems, because almost always the guest OS will map the PCI devices and then only access where it has mapped them. One corner case where you will see this kind of access is if Linux attempts to probe legacy ISA devices via a PIO window access. So far the only case where we've seen this has been via the syzkaller fuzzer. Reported-by: Dmitry Vyukov Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Acked-by: Michael S. Tsirkin Message-id: 20210325163315.27724-1-peter.maydell@linaro.org Fixes: https://bugs.launchpad.net/qemu/+bug/1918917 Signed-off-by: Peter Maydell --- hw/core/machine.c | 4 ++- hw/pci-host/gpex.c | 56 ++++++++++++++++++++++++++++++++++++-- include/hw/pci-host/gpex.h | 4 +++ 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index cebcdcc351..0f5ce43d0c 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -36,7 +36,9 @@ #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-pci.h" -GlobalProperty hw_compat_6_0[] = {}; +GlobalProperty hw_compat_6_0[] = { + { "gpex-pcihost", "allow-unmapped-accesses", "false" }, +}; const size_t hw_compat_6_0_len = G_N_ELEMENTS(hw_compat_6_0); GlobalProperty hw_compat_5_2[] = { diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c index 2bdbe7b456..a6752fac5e 100644 --- a/hw/pci-host/gpex.c +++ b/hw/pci-host/gpex.c @@ -83,12 +83,51 @@ static void gpex_host_realize(DeviceState *dev, Error **errp) int i; pcie_host_mmcfg_init(pex, PCIE_MMCFG_SIZE_MAX); + sysbus_init_mmio(sbd, &pex->mmio); + + /* + * Note that the MemoryRegions io_mmio and io_ioport that we pass + * to pci_register_root_bus() are not the same as the + * MemoryRegions io_mmio_window and io_ioport_window that we + * expose as SysBus MRs. The difference is in the behaviour of + * accesses to addresses where no PCI device has been mapped. + * + * io_mmio and io_ioport are the underlying PCI view of the PCI + * address space, and when a PCI device does a bus master access + * to a bad address this is reported back to it as a transaction + * failure. + * + * io_mmio_window and io_ioport_window implement "unmapped + * addresses read as -1 and ignore writes"; this is traditional + * x86 PC behaviour, which is not mandated by the PCI spec proper + * but expected by much PCI-using guest software, including Linux. + * + * In the interests of not being unnecessarily surprising, we + * implement it in the gpex PCI host controller, by providing the + * _window MRs, which are containers with io ops that implement + * the 'background' behaviour and which hold the real PCI MRs as + * subregions. + */ memory_region_init(&s->io_mmio, OBJECT(s), "gpex_mmio", UINT64_MAX); memory_region_init(&s->io_ioport, OBJECT(s), "gpex_ioport", 64 * 1024); - sysbus_init_mmio(sbd, &pex->mmio); - sysbus_init_mmio(sbd, &s->io_mmio); - sysbus_init_mmio(sbd, &s->io_ioport); + if (s->allow_unmapped_accesses) { + memory_region_init_io(&s->io_mmio_window, OBJECT(s), + &unassigned_io_ops, OBJECT(s), + "gpex_mmio_window", UINT64_MAX); + memory_region_init_io(&s->io_ioport_window, OBJECT(s), + &unassigned_io_ops, OBJECT(s), + "gpex_ioport_window", 64 * 1024); + + memory_region_add_subregion(&s->io_mmio_window, 0, &s->io_mmio); + memory_region_add_subregion(&s->io_ioport_window, 0, &s->io_ioport); + sysbus_init_mmio(sbd, &s->io_mmio_window); + sysbus_init_mmio(sbd, &s->io_ioport_window); + } else { + sysbus_init_mmio(sbd, &s->io_mmio); + sysbus_init_mmio(sbd, &s->io_ioport); + } + for (i = 0; i < GPEX_NUM_IRQS; i++) { sysbus_init_irq(sbd, &s->irq[i]); s->irq_num[i] = -1; @@ -108,6 +147,16 @@ static const char *gpex_host_root_bus_path(PCIHostState *host_bridge, return "0000:00"; } +static Property gpex_host_properties[] = { + /* + * Permit CPU accesses to unmapped areas of the PIO and MMIO windows + * (discarding writes and returning -1 for reads) rather than aborting. + */ + DEFINE_PROP_BOOL("allow-unmapped-accesses", GPEXHost, + allow_unmapped_accesses, true), + DEFINE_PROP_END_OF_LIST(), +}; + static void gpex_host_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -117,6 +166,7 @@ static void gpex_host_class_init(ObjectClass *klass, void *data) dc->realize = gpex_host_realize; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->fw_name = "pci"; + device_class_set_props(dc, gpex_host_properties); } static void gpex_host_initfn(Object *obj) diff --git a/include/hw/pci-host/gpex.h b/include/hw/pci-host/gpex.h index d48a020a95..fcf8b63820 100644 --- a/include/hw/pci-host/gpex.h +++ b/include/hw/pci-host/gpex.h @@ -49,8 +49,12 @@ struct GPEXHost { MemoryRegion io_ioport; MemoryRegion io_mmio; + MemoryRegion io_ioport_window; + MemoryRegion io_mmio_window; qemu_irq irq[GPEX_NUM_IRQS]; int irq_num[GPEX_NUM_IRQS]; + + bool allow_unmapped_accesses; }; struct GPEXConfig { From d71cc67d6880c00ff45e8e26350233694aa4de72 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:29 +0300 Subject: [PATCH 0050/3028] tests/test-bdrv-graph-mod: add test_parallel_exclusive_write Add the test that shows that concept of ignore_children is incomplete. Actually, when we want to update something, ignoring permission of some existing BdrvChild, we should ignore also the propagated effect of this child to the other children. But that's not done. Better approach (update permissions on already updated graph) will be implemented later. Now the test fails, so it's added with -d argument to not break make check. Test fails with "Conflicts with use by fl1 as 'backing', which does not allow 'write' on base" because when updating permissions we can ignore original top->fl1 BdrvChild. But we don't ignore exclusive write permission in fl1->base BdrvChild, which is propagated. Correct thing to do is make graph change first and then do permission update from the top node. To run test do ./test-bdrv-graph-mod -d -p /bdrv-graph-mod/parallel-exclusive-write from /tests. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-2-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/unit/test-bdrv-graph-mod.c | 70 +++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c index c4f7d16039..80a9a20066 100644 --- a/tests/unit/test-bdrv-graph-mod.c +++ b/tests/unit/test-bdrv-graph-mod.c @@ -1,7 +1,7 @@ /* * Block node graph modifications tests * - * Copyright (c) 2019 Virtuozzo International GmbH. All rights reserved. + * Copyright (c) 2019-2021 Virtuozzo International GmbH. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,6 +44,21 @@ static BlockDriver bdrv_no_perm = { .bdrv_child_perm = no_perm_default_perms, }; +static void exclusive_write_perms(BlockDriverState *bs, BdrvChild *c, + BdrvChildRole role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared) +{ + *nperm = BLK_PERM_WRITE; + *nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE; +} + +static BlockDriver bdrv_exclusive_writer = { + .format_name = "exclusive-writer", + .bdrv_child_perm = exclusive_write_perms, +}; + static BlockDriverState *no_perm_node(const char *name) { return bdrv_new_open_driver(&bdrv_no_perm, name, BDRV_O_RDWR, &error_abort); @@ -55,6 +70,12 @@ static BlockDriverState *pass_through_node(const char *name) BDRV_O_RDWR, &error_abort); } +static BlockDriverState *exclusive_writer_node(const char *name) +{ + return bdrv_new_open_driver(&bdrv_exclusive_writer, name, + BDRV_O_RDWR, &error_abort); +} + /* * test_update_perm_tree * @@ -185,8 +206,50 @@ static void test_should_update_child(void) blk_unref(root); } +/* + * test_parallel_exclusive_write + * + * Check that when we replace node, old permissions of the node being removed + * doesn't break the replacement. + */ +static void test_parallel_exclusive_write(void) +{ + BlockDriverState *top = exclusive_writer_node("top"); + BlockDriverState *base = no_perm_node("base"); + BlockDriverState *fl1 = pass_through_node("fl1"); + BlockDriverState *fl2 = pass_through_node("fl2"); + + /* + * bdrv_attach_child() eats child bs reference, so we need two @base + * references for two filters: + */ + bdrv_ref(base); + + bdrv_attach_child(top, fl1, "backing", &child_of_bds, BDRV_CHILD_DATA, + &error_abort); + bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, + &error_abort); + bdrv_attach_child(fl2, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, + &error_abort); + + bdrv_replace_node(fl1, fl2, &error_abort); + + bdrv_unref(fl2); + bdrv_unref(top); +} + int main(int argc, char *argv[]) { + int i; + bool debug = false; + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-d")) { + debug = true; + break; + } + } + bdrv_init(); qemu_init_main_loop(&error_abort); @@ -196,5 +259,10 @@ int main(int argc, char *argv[]) g_test_add_func("/bdrv-graph-mod/should-update-child", test_should_update_child); + if (debug) { + g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write", + test_parallel_exclusive_write); + } + return g_test_run(); } From e6af4f0e9414d36c0f0baddfb274003c0e7d6ecb Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:30 +0300 Subject: [PATCH 0051/3028] tests/test-bdrv-graph-mod: add test_parallel_perm_update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add test to show that simple DFS recursion order is not correct for permission update. Correct order is topological-sort order, which will be introduced later. Consider the block driver which has two filter children: one active with exclusive write access and one inactive with no specific permissions. And, these two children has a common base child, like this: ┌─────┐ ┌──────┐ │ fl2 │ ◀── │ top │ └─────┘ └──────┘ │ │ │ │ w │ ▼ │ ┌──────┐ │ │ fl1 │ │ └──────┘ │ │ │ │ w │ ▼ │ ┌──────┐ └───────▶ │ base │ └──────┘ So, exclusive write is propagated. Assume, we want to make fl2 active instead of fl1. So, we set some option for top driver and do permission update. If permission update (remember, it's DFS) goes first through top->fl1->base branch it will succeed: it firstly drop exclusive write permissions and than apply them for another BdrvChildren. But if permission update goes first through top->fl2->base branch it will fail, as when we try to update fl2->base child, old not yet updated fl1->base child will be in conflict. Now test fails, so it runs only with -d flag. To run do ./test-bdrv-graph-mod -d -p /bdrv-graph-mod/parallel-perm-update from /tests. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-3-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/unit/test-bdrv-graph-mod.c | 116 +++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c index 80a9a20066..a8219b131e 100644 --- a/tests/unit/test-bdrv-graph-mod.c +++ b/tests/unit/test-bdrv-graph-mod.c @@ -238,6 +238,120 @@ static void test_parallel_exclusive_write(void) bdrv_unref(top); } +static void write_to_file_perms(BlockDriverState *bs, BdrvChild *c, + BdrvChildRole role, + BlockReopenQueue *reopen_queue, + uint64_t perm, uint64_t shared, + uint64_t *nperm, uint64_t *nshared) +{ + if (bs->file && c == bs->file) { + *nperm = BLK_PERM_WRITE; + *nshared = BLK_PERM_ALL & ~BLK_PERM_WRITE; + } else { + *nperm = 0; + *nshared = BLK_PERM_ALL; + } +} + +static BlockDriver bdrv_write_to_file = { + .format_name = "tricky-perm", + .bdrv_child_perm = write_to_file_perms, +}; + + +/* + * The following test shows that topological-sort order is required for + * permission update, simple DFS is not enough. + * + * Consider the block driver which has two filter children: one active + * with exclusive write access and one inactive with no specific + * permissions. + * + * And, these two children has a common base child, like this: + * + * ┌─────┐ ┌──────┐ + * │ fl2 │ ◀── │ top │ + * └─────┘ └──────┘ + * │ │ + * │ │ w + * │ ▼ + * │ ┌──────┐ + * │ │ fl1 │ + * │ └──────┘ + * │ │ + * │ │ w + * │ ▼ + * │ ┌──────┐ + * └───────▶ │ base │ + * └──────┘ + * + * So, exclusive write is propagated. + * + * Assume, we want to make fl2 active instead of fl1. + * So, we set some option for top driver and do permission update. + * + * With simple DFS, if permission update goes first through + * top->fl1->base branch it will succeed: it firstly drop exclusive write + * permissions and than apply them for another BdrvChildren. + * But if permission update goes first through top->fl2->base branch it + * will fail, as when we try to update fl2->base child, old not yet + * updated fl1->base child will be in conflict. + * + * With topological-sort order we always update parents before children, so fl1 + * and fl2 are both updated when we update base and there is no conflict. + */ +static void test_parallel_perm_update(void) +{ + BlockDriverState *top = no_perm_node("top"); + BlockDriverState *tricky = + bdrv_new_open_driver(&bdrv_write_to_file, "tricky", BDRV_O_RDWR, + &error_abort); + BlockDriverState *base = no_perm_node("base"); + BlockDriverState *fl1 = pass_through_node("fl1"); + BlockDriverState *fl2 = pass_through_node("fl2"); + BdrvChild *c_fl1, *c_fl2; + + /* + * bdrv_attach_child() eats child bs reference, so we need two @base + * references for two filters: + */ + bdrv_ref(base); + + bdrv_attach_child(top, tricky, "file", &child_of_bds, BDRV_CHILD_DATA, + &error_abort); + c_fl1 = bdrv_attach_child(tricky, fl1, "first", &child_of_bds, + BDRV_CHILD_FILTERED, &error_abort); + c_fl2 = bdrv_attach_child(tricky, fl2, "second", &child_of_bds, + BDRV_CHILD_FILTERED, &error_abort); + bdrv_attach_child(fl1, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, + &error_abort); + bdrv_attach_child(fl2, base, "backing", &child_of_bds, BDRV_CHILD_FILTERED, + &error_abort); + + /* Select fl1 as first child to be active */ + tricky->file = c_fl1; + bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort); + + assert(c_fl1->perm & BLK_PERM_WRITE); + assert(!(c_fl2->perm & BLK_PERM_WRITE)); + + /* Now, try to switch active child and update permissions */ + tricky->file = c_fl2; + bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort); + + assert(c_fl2->perm & BLK_PERM_WRITE); + assert(!(c_fl1->perm & BLK_PERM_WRITE)); + + /* Switch once more, to not care about real child order in the list */ + tricky->file = c_fl1; + bdrv_child_refresh_perms(top, top->children.lh_first, &error_abort); + + assert(c_fl1->perm & BLK_PERM_WRITE); + assert(!(c_fl2->perm & BLK_PERM_WRITE)); + + bdrv_unref(top); +} + int main(int argc, char *argv[]) { int i; @@ -262,6 +376,8 @@ int main(int argc, char *argv[]) if (debug) { g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write", test_parallel_exclusive_write); + g_test_add_func("/bdrv-graph-mod/parallel-perm-update", + test_parallel_perm_update); } return g_test_run(); From 397f7cc0c217cfe45f42ee21e2ad5b84f3333b67 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:31 +0300 Subject: [PATCH 0052/3028] tests/test-bdrv-graph-mod: add test_append_greedy_filter bdrv_append() is not quite good for inserting filters: it does extra permission update in intermediate state, where filter get it filtered child but is not yet replace it in a backing chain. Some filters (for example backup-top) may want permissions even when have no parents. And described intermediate state becomes invalid. That's (half a) reason, why we need "inactive" state for backup-top filter. bdrv_append() will be improved later, now let's add a unit test. Now test fails, so it runs only with -d flag. To run do ./test-bdrv-graph-mod -d -p /bdrv-graph-mod/append-greedy-filter from /tests. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-4-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- tests/unit/test-bdrv-graph-mod.c | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c index a8219b131e..5b6934e68b 100644 --- a/tests/unit/test-bdrv-graph-mod.c +++ b/tests/unit/test-bdrv-graph-mod.c @@ -352,6 +352,37 @@ static void test_parallel_perm_update(void) bdrv_unref(top); } +/* + * It's possible that filter required permissions allows to insert it to backing + * chain, like: + * + * 1. [top] -> [filter] -> [base] + * + * but doesn't allow to add it as a branch: + * + * 2. [filter] --\ + * v + * [top] -> [base] + * + * So, inserting such filter should do all graph modifications and only then + * update permissions. If we try to go through intermediate state [2] and update + * permissions on it we'll fail. + * + * Let's check that bdrv_append() can append such a filter. + */ +static void test_append_greedy_filter(void) +{ + BlockDriverState *top = exclusive_writer_node("top"); + BlockDriverState *base = no_perm_node("base"); + BlockDriverState *fl = exclusive_writer_node("fl1"); + + bdrv_attach_child(top, base, "backing", &child_of_bds, BDRV_CHILD_COW, + &error_abort); + + bdrv_append(fl, base, &error_abort); + bdrv_unref(top); +} + int main(int argc, char *argv[]) { int i; @@ -378,6 +409,8 @@ int main(int argc, char *argv[]) test_parallel_exclusive_write); g_test_add_func("/bdrv-graph-mod/parallel-perm-update", test_parallel_perm_update); + g_test_add_func("/bdrv-graph-mod/append-greedy-filter", + test_append_greedy_filter); } return g_test_run(); From ae9d441706d7b7d624a342b464136804b3b7bc3a Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:32 +0300 Subject: [PATCH 0053/3028] block: bdrv_append(): don't consume reference We have too much comments for this feature. It seems better just don't do it. Most of real users (tests don't count) have to create additional reference. Drop also comment in external_snapshot_prepare: - bdrv_append doesn't "remove" old bs in common sense, it sounds strange - the fact that bdrv_append can fail is obvious from the context - the fact that we must rollback all changes in transaction abort is known (it's the direct role of abort) Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-5-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 25 +++---------------------- block/backup-top.c | 1 - block/commit.c | 1 + block/mirror.c | 3 --- blockdev.c | 4 ---- tests/unit/test-bdrv-drain.c | 2 +- tests/unit/test-bdrv-graph-mod.c | 3 +++ 7 files changed, 8 insertions(+), 31 deletions(-) diff --git a/block.c b/block.c index c5b887cec1..1e7e8907e4 100644 --- a/block.c +++ b/block.c @@ -3213,11 +3213,6 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs, goto out; } - /* bdrv_append() consumes a strong reference to bs_snapshot - * (i.e. it will call bdrv_unref() on it) even on error, so in - * order to be able to return one, we have to increase - * bs_snapshot's refcount here */ - bdrv_ref(bs_snapshot); ret = bdrv_append(bs_snapshot, bs, errp); if (ret < 0) { bs_snapshot = NULL; @@ -4679,36 +4674,22 @@ int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, * bs_new must not be attached to a BlockBackend. * * This function does not create any image files. - * - * bdrv_append() takes ownership of a bs_new reference and unrefs it because - * that's what the callers commonly need. bs_new will be referenced by the old - * parents of bs_top after bdrv_append() returns. If the caller needs to keep a - * reference of its own, it must call bdrv_ref(). */ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, Error **errp) { int ret = bdrv_set_backing_hd(bs_new, bs_top, errp); if (ret < 0) { - goto out; + return ret; } ret = bdrv_replace_node(bs_top, bs_new, errp); if (ret < 0) { bdrv_set_backing_hd(bs_new, NULL, &error_abort); - goto out; + return ret; } - ret = 0; - -out: - /* - * bs_new is now referenced by its new parents, we don't need the - * additional reference any more. - */ - bdrv_unref(bs_new); - - return ret; + return 0; } static void bdrv_delete(BlockDriverState *bs) diff --git a/block/backup-top.c b/block/backup-top.c index 589e8b651d..62d09f213e 100644 --- a/block/backup-top.c +++ b/block/backup-top.c @@ -234,7 +234,6 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, bdrv_drained_begin(source); - bdrv_ref(top); ret = bdrv_append(top, source, errp); if (ret < 0) { error_prepend(errp, "Cannot append backup-top filter: "); diff --git a/block/commit.c b/block/commit.c index dd9ba87349..b89bb20b75 100644 --- a/block/commit.c +++ b/block/commit.c @@ -312,6 +312,7 @@ void commit_start(const char *job_id, BlockDriverState *bs, commit_top_bs->total_sectors = top->total_sectors; ret = bdrv_append(commit_top_bs, top, errp); + bdrv_unref(commit_top_bs); /* referenced by new parents or failed */ if (ret < 0) { commit_top_bs = NULL; goto fail; diff --git a/block/mirror.c b/block/mirror.c index 5a71bd8bbc..840b8e8c15 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1630,9 +1630,6 @@ static BlockJob *mirror_start_job( bs_opaque->is_commit = target_is_backing; - /* bdrv_append takes ownership of the mirror_top_bs reference, need to keep - * it alive until block_job_create() succeeds even if bs has no parent. */ - bdrv_ref(mirror_top_bs); bdrv_drained_begin(bs); ret = bdrv_append(mirror_top_bs, bs, errp); bdrv_drained_end(bs); diff --git a/blockdev.c b/blockdev.c index a57590aae4..834c2304a1 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1576,10 +1576,6 @@ static void external_snapshot_prepare(BlkActionState *common, goto out; } - /* This removes our old bs and adds the new bs. This is an operation that - * can fail, so we need to do it in .prepare; undoing it for abort is - * always possible. */ - bdrv_ref(state->new_bs); ret = bdrv_append(state->new_bs, state->old_bs, errp); if (ret < 0) { goto out; diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c index 8a29e33e00..892f7f47d8 100644 --- a/tests/unit/test-bdrv-drain.c +++ b/tests/unit/test-bdrv-drain.c @@ -1478,7 +1478,6 @@ static void test_append_to_drained(void) g_assert_cmpint(base_s->drain_count, ==, 1); g_assert_cmpint(base->in_flight, ==, 0); - /* Takes ownership of overlay, so we don't have to unref it later */ bdrv_append(overlay, base, &error_abort); g_assert_cmpint(base->in_flight, ==, 0); g_assert_cmpint(overlay->in_flight, ==, 0); @@ -1495,6 +1494,7 @@ static void test_append_to_drained(void) g_assert_cmpint(overlay->quiesce_counter, ==, 0); g_assert_cmpint(overlay_s->drain_count, ==, 0); + bdrv_unref(overlay); bdrv_unref(base); blk_unref(blk); } diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c index 5b6934e68b..a6064b1863 100644 --- a/tests/unit/test-bdrv-graph-mod.c +++ b/tests/unit/test-bdrv-graph-mod.c @@ -138,6 +138,7 @@ static void test_update_perm_tree(void) ret = bdrv_append(filter, bs, NULL); g_assert_cmpint(ret, <, 0); + bdrv_unref(filter); blk_unref(root); } @@ -202,6 +203,7 @@ static void test_should_update_child(void) bdrv_append(filter, bs, &error_abort); g_assert(target->backing->bs == bs); + bdrv_unref(filter); bdrv_unref(bs); blk_unref(root); } @@ -380,6 +382,7 @@ static void test_append_greedy_filter(void) &error_abort); bdrv_append(fl, base, &error_abort); + bdrv_unref(fl); bdrv_unref(top); } From 3ca1f3225727419ba573673b744edac10904276f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:33 +0300 Subject: [PATCH 0054/3028] block: BdrvChildClass: add .get_parent_aio_context handler Add new handler to get aio context and implement it in all child classes. Add corresponding public interface to be used soon. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-6-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 13 +++++++++++++ block/block-backend.c | 9 +++++++++ blockjob.c | 8 ++++++++ include/block/block.h | 2 ++ include/block/block_int.h | 2 ++ 5 files changed, 34 insertions(+) diff --git a/block.c b/block.c index 1e7e8907e4..2833912436 100644 --- a/block.c +++ b/block.c @@ -1394,6 +1394,13 @@ static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base, return 0; } +static AioContext *bdrv_child_cb_get_parent_aio_context(BdrvChild *c) +{ + BlockDriverState *bs = c->opaque; + + return bdrv_get_aio_context(bs); +} + const BdrvChildClass child_of_bds = { .parent_is_bds = true, .get_parent_desc = bdrv_child_get_parent_desc, @@ -1407,8 +1414,14 @@ const BdrvChildClass child_of_bds = { .can_set_aio_ctx = bdrv_child_cb_can_set_aio_ctx, .set_aio_ctx = bdrv_child_cb_set_aio_ctx, .update_filename = bdrv_child_cb_update_filename, + .get_parent_aio_context = bdrv_child_cb_get_parent_aio_context, }; +AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c) +{ + return c->klass->get_parent_aio_context(c); +} + static int bdrv_open_flags(BlockDriverState *bs, int flags) { int open_flags = flags; diff --git a/block/block-backend.c b/block/block-backend.c index 413af51f3b..3f656ef361 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -298,6 +298,13 @@ static void blk_root_detach(BdrvChild *child) } } +static AioContext *blk_root_get_parent_aio_context(BdrvChild *c) +{ + BlockBackend *blk = c->opaque; + + return blk_get_aio_context(blk); +} + static const BdrvChildClass child_root = { .inherit_options = blk_root_inherit_options, @@ -318,6 +325,8 @@ static const BdrvChildClass child_root = { .can_set_aio_ctx = blk_root_can_set_aio_ctx, .set_aio_ctx = blk_root_set_aio_ctx, + + .get_parent_aio_context = blk_root_get_parent_aio_context, }; /* diff --git a/blockjob.c b/blockjob.c index 207e8c7fd9..160bf38b19 100644 --- a/blockjob.c +++ b/blockjob.c @@ -163,6 +163,13 @@ static void child_job_set_aio_ctx(BdrvChild *c, AioContext *ctx, job->job.aio_context = ctx; } +static AioContext *child_job_get_parent_aio_context(BdrvChild *c) +{ + BlockJob *job = c->opaque; + + return job->job.aio_context; +} + static const BdrvChildClass child_job = { .get_parent_desc = child_job_get_parent_desc, .drained_begin = child_job_drained_begin, @@ -171,6 +178,7 @@ static const BdrvChildClass child_job = { .can_set_aio_ctx = child_job_can_set_aio_ctx, .set_aio_ctx = child_job_set_aio_ctx, .stay_at_node = true, + .get_parent_aio_context = child_job_get_parent_aio_context, }; void block_job_remove_all_bdrv(BlockJob *job) diff --git a/include/block/block.h b/include/block/block.h index b3f6e509d4..54279baa95 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -702,6 +702,8 @@ bool bdrv_child_can_set_aio_context(BdrvChild *c, AioContext *ctx, GSList **ignore, Error **errp); bool bdrv_can_set_aio_context(BlockDriverState *bs, AioContext *ctx, GSList **ignore, Error **errp); +AioContext *bdrv_child_get_parent_aio_context(BdrvChild *c); + int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz); int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); diff --git a/include/block/block_int.h b/include/block/block_int.h index 88e4111939..737ec632c4 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -789,6 +789,8 @@ struct BdrvChildClass { bool (*can_set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore, Error **errp); void (*set_aio_ctx)(BdrvChild *child, AioContext *ctx, GSList **ignore); + + AioContext *(*get_parent_aio_context)(BdrvChild *child); }; extern const BdrvChildClass child_of_bds; From 228ca37e12f97788e05bd0c92f89b3e5e4019607 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:34 +0300 Subject: [PATCH 0055/3028] block: drop ctx argument from bdrv_root_attach_child Passing parent aio context is redundant, as child_class and parent opaque pointer are enough to retrieve it. Drop the argument and use new bdrv_child_get_parent_aio_context() interface. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-7-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 8 +++++--- block/block-backend.c | 4 ++-- blockjob.c | 3 +-- include/block/block_int.h | 1 - 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/block.c b/block.c index 2833912436..54436c951e 100644 --- a/block.c +++ b/block.c @@ -2700,13 +2700,13 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, const char *child_name, const BdrvChildClass *child_class, BdrvChildRole child_role, - AioContext *ctx, uint64_t perm, uint64_t shared_perm, void *opaque, Error **errp) { BdrvChild *child; Error *local_err = NULL; int ret; + AioContext *ctx; ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp); if (ret < 0) { @@ -2726,6 +2726,8 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, .opaque = opaque, }; + ctx = bdrv_child_get_parent_aio_context(child); + /* If the AioContexts don't match, first try to move the subtree of * child_bs into the AioContext of the new parent. If this doesn't work, * try moving the parent into the AioContext of child_bs instead. */ @@ -2786,8 +2788,8 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, perm, shared_perm, &perm, &shared_perm); child = bdrv_root_attach_child(child_bs, child_name, child_class, - child_role, bdrv_get_aio_context(parent_bs), - perm, shared_perm, parent_bs, errp); + child_role, perm, shared_perm, parent_bs, + errp); if (child == NULL) { return NULL; } diff --git a/block/block-backend.c b/block/block-backend.c index 3f656ef361..e4892fd6a5 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -435,7 +435,7 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, blk->root = bdrv_root_attach_child(bs, "root", &child_root, BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - blk->ctx, perm, BLK_PERM_ALL, blk, errp); + perm, BLK_PERM_ALL, blk, errp); if (!blk->root) { blk_unref(blk); return NULL; @@ -849,7 +849,7 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp) bdrv_ref(bs); blk->root = bdrv_root_attach_child(bs, "root", &child_root, BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - blk->ctx, blk->perm, blk->shared_perm, + blk->perm, blk->shared_perm, blk, errp); if (blk->root == NULL) { return -EPERM; diff --git a/blockjob.c b/blockjob.c index 160bf38b19..2fe1d788ba 100644 --- a/blockjob.c +++ b/blockjob.c @@ -229,8 +229,7 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs, if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) { aio_context_release(job->job.aio_context); } - c = bdrv_root_attach_child(bs, name, &child_job, 0, - job->job.aio_context, perm, shared_perm, job, + c = bdrv_root_attach_child(bs, name, &child_job, 0, perm, shared_perm, job, errp); if (need_context_ops && job->job.aio_context != qemu_get_aio_context()) { aio_context_acquire(job->job.aio_context); diff --git a/include/block/block_int.h b/include/block/block_int.h index 737ec632c4..dd2de6bd1d 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -1308,7 +1308,6 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, const char *child_name, const BdrvChildClass *child_class, BdrvChildRole child_role, - AioContext *ctx, uint64_t perm, uint64_t shared_perm, void *opaque, Error **errp); void bdrv_root_unref_child(BdrvChild *child); From 53e96d1e9f95606410d66bf6449214088970bbf8 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:35 +0300 Subject: [PATCH 0056/3028] block: make bdrv_reopen_{prepare,commit,abort} private These functions are called only from bdrv_reopen_multiple() in block.c. No reason to publish them. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-8-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 13 +++++++++---- include/block/block.h | 4 ---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/block.c b/block.c index 54436c951e..34c728d7e4 100644 --- a/block.c +++ b/block.c @@ -82,6 +82,11 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, BdrvChildRole child_role, Error **errp); +static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue + *queue, Error **errp); +static void bdrv_reopen_commit(BDRVReopenState *reopen_state); +static void bdrv_reopen_abort(BDRVReopenState *reopen_state); + /* If non-zero, use only whitelisted block drivers */ static int use_bdrv_whitelist; @@ -4153,8 +4158,8 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state, * commit() for any other BDS that have been left in a prepare() state * */ -int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, - Error **errp) +static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, + BlockReopenQueue *queue, Error **errp) { int ret = -1; int old_flags; @@ -4369,7 +4374,7 @@ error: * makes them final by swapping the staging BlockDriverState contents into * the active BlockDriverState contents. */ -void bdrv_reopen_commit(BDRVReopenState *reopen_state) +static void bdrv_reopen_commit(BDRVReopenState *reopen_state) { BlockDriver *drv; BlockDriverState *bs; @@ -4429,7 +4434,7 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) * Abort the reopen, and delete and free the staged changes in * reopen_state */ -void bdrv_reopen_abort(BDRVReopenState *reopen_state) +static void bdrv_reopen_abort(BDRVReopenState *reopen_state) { BlockDriver *drv; diff --git a/include/block/block.h b/include/block/block.h index 54279baa95..16e496a5c4 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -387,10 +387,6 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp); int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only, Error **errp); -int bdrv_reopen_prepare(BDRVReopenState *reopen_state, - BlockReopenQueue *queue, Error **errp); -void bdrv_reopen_commit(BDRVReopenState *reopen_state); -void bdrv_reopen_abort(BDRVReopenState *reopen_state); int bdrv_pwrite_zeroes(BdrvChild *child, int64_t offset, int64_t bytes, BdrvRequestFlags flags); int bdrv_make_zero(BdrvChild *child, BdrvRequestFlags flags); From 8cad15b1561ee6a1dd473d3f03c982b4dde574a3 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:36 +0300 Subject: [PATCH 0057/3028] util: add transactions.c Add simple transaction API to use in further update of block graph operations. Supposed usage is: - "prepare" is main function of the action and it should make the main effect of the action to be visible for the following actions, keeping possibility of roll-back, saving necessary things in action state, which is prepended to the action list (to do that, prepare func should call tran_add()). So, driver struct doesn't include "prepare" field, as it is supposed to be called directly. - commit/rollback is supposed to be called for the list of action states, to commit/rollback all the actions in reverse order - When possible "commit" should not make visible effect for other actions, which make possible transparent logical interaction between actions. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-9-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- MAINTAINERS | 6 +++ include/qemu/transactions.h | 63 ++++++++++++++++++++++++ util/meson.build | 1 + util/transactions.c | 96 +++++++++++++++++++++++++++++++++++++ 4 files changed, 166 insertions(+) create mode 100644 include/qemu/transactions.h create mode 100644 util/transactions.c diff --git a/MAINTAINERS b/MAINTAINERS index 36055f14c5..4c05ff8bba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2532,6 +2532,12 @@ M: Vladimir Sementsov-Ogievskiy S: Maintained F: scripts/simplebench/ +Transactions helper +M: Vladimir Sementsov-Ogievskiy +S: Maintained +F: include/qemu/transactions.h +F: util/transactions.c + QAPI M: Markus Armbruster M: Michael Roth diff --git a/include/qemu/transactions.h b/include/qemu/transactions.h new file mode 100644 index 0000000000..92c5965235 --- /dev/null +++ b/include/qemu/transactions.h @@ -0,0 +1,63 @@ +/* + * Simple transactions API + * + * Copyright (c) 2021 Virtuozzo International GmbH. + * + * Author: + * Vladimir Sementsov-Ogievskiy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + * = Generic transaction API = + * + * The intended usage is the following: you create "prepare" functions, which + * represents the actions. They will usually have Transaction* argument, and + * call tran_add() to register finalization callbacks. For finalization + * callbacks, prepare corresponding TransactionActionDrv structures. + * + * Then, when you need to make a transaction, create an empty Transaction by + * tran_create(), call your "prepare" functions on it, and finally call + * tran_abort() or tran_commit() to finalize the transaction by corresponding + * finalization actions in reverse order. + */ + +#ifndef QEMU_TRANSACTIONS_H +#define QEMU_TRANSACTIONS_H + +#include + +typedef struct TransactionActionDrv { + void (*abort)(void *opaque); + void (*commit)(void *opaque); + void (*clean)(void *opaque); +} TransactionActionDrv; + +typedef struct Transaction Transaction; + +Transaction *tran_new(void); +void tran_add(Transaction *tran, TransactionActionDrv *drv, void *opaque); +void tran_abort(Transaction *tran); +void tran_commit(Transaction *tran); + +static inline void tran_finalize(Transaction *tran, int ret) +{ + if (ret < 0) { + tran_abort(tran); + } else { + tran_commit(tran); + } +} + +#endif /* QEMU_TRANSACTIONS_H */ diff --git a/util/meson.build b/util/meson.build index 510765cde4..97fad44105 100644 --- a/util/meson.build +++ b/util/meson.build @@ -41,6 +41,7 @@ util_ss.add(files('qsp.c')) util_ss.add(files('range.c')) util_ss.add(files('stats64.c')) util_ss.add(files('systemd.c')) +util_ss.add(files('transactions.c')) util_ss.add(when: 'CONFIG_POSIX', if_true: files('drm.c')) util_ss.add(files('guest-random.c')) util_ss.add(files('yank.c')) diff --git a/util/transactions.c b/util/transactions.c new file mode 100644 index 0000000000..d0bc9a3e73 --- /dev/null +++ b/util/transactions.c @@ -0,0 +1,96 @@ +/* + * Simple transactions API + * + * Copyright (c) 2021 Virtuozzo International GmbH. + * + * Author: + * Sementsov-Ogievskiy Vladimir + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "qemu/osdep.h" + +#include "qemu/transactions.h" +#include "qemu/queue.h" + +typedef struct TransactionAction { + TransactionActionDrv *drv; + void *opaque; + QSLIST_ENTRY(TransactionAction) entry; +} TransactionAction; + +struct Transaction { + QSLIST_HEAD(, TransactionAction) actions; +}; + +Transaction *tran_new(void) +{ + Transaction *tran = g_new(Transaction, 1); + + QSLIST_INIT(&tran->actions); + + return tran; +} + +void tran_add(Transaction *tran, TransactionActionDrv *drv, void *opaque) +{ + TransactionAction *act; + + act = g_new(TransactionAction, 1); + *act = (TransactionAction) { + .drv = drv, + .opaque = opaque + }; + + QSLIST_INSERT_HEAD(&tran->actions, act, entry); +} + +void tran_abort(Transaction *tran) +{ + TransactionAction *act, *next; + + QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) { + if (act->drv->abort) { + act->drv->abort(act->opaque); + } + + if (act->drv->clean) { + act->drv->clean(act->opaque); + } + + g_free(act); + } + + g_free(tran); +} + +void tran_commit(Transaction *tran) +{ + TransactionAction *act, *next; + + QSLIST_FOREACH_SAFE(act, &tran->actions, entry, next) { + if (act->drv->commit) { + act->drv->commit(act->opaque); + } + + if (act->drv->clean) { + act->drv->clean(act->opaque); + } + + g_free(act); + } + + g_free(tran); +} From 3bf416ba0fdc0667e34ef912fbe1074ad259f533 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:37 +0300 Subject: [PATCH 0058/3028] block: bdrv_refresh_perms: check for parents permissions conflict Add additional check that node parents do not interfere with each other. This should not hurt existing callers and allows in further patch use bdrv_refresh_perms() to update a subtree of changed BdrvChild (check that change is correct). New check will substitute bdrv_check_update_perm() in following permissions refactoring, so keep error messages the same to avoid unit test result changes. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-10-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/block.c b/block.c index 34c728d7e4..fd621f0403 100644 --- a/block.c +++ b/block.c @@ -2026,6 +2026,57 @@ bool bdrv_is_writable(BlockDriverState *bs) return bdrv_is_writable_after_reopen(bs, NULL); } +static char *bdrv_child_user_desc(BdrvChild *c) +{ + if (c->klass->get_parent_desc) { + return c->klass->get_parent_desc(c); + } + + return g_strdup("another user"); +} + +static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp) +{ + g_autofree char *user = NULL; + g_autofree char *perm_names = NULL; + + if ((b->perm & a->shared_perm) == b->perm) { + return true; + } + + perm_names = bdrv_perm_names(b->perm & ~a->shared_perm); + user = bdrv_child_user_desc(a); + error_setg(errp, "Conflicts with use by %s as '%s', which does not " + "allow '%s' on %s", + user, a->name, perm_names, bdrv_get_node_name(b->bs)); + + return false; +} + +static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp) +{ + BdrvChild *a, *b; + + /* + * During the loop we'll look at each pair twice. That's correct because + * bdrv_a_allow_b() is asymmetric and we should check each pair in both + * directions. + */ + QLIST_FOREACH(a, &bs->parents, next_parent) { + QLIST_FOREACH(b, &bs->parents, next_parent) { + if (a == b) { + continue; + } + + if (!bdrv_a_allow_b(a, b, errp)) { + return true; + } + } + } + + return false; +} + static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, BdrvChild *c, BdrvChildRole role, BlockReopenQueue *reopen_queue, @@ -2203,15 +2254,6 @@ void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, *shared_perm = cumulative_shared_perms; } -static char *bdrv_child_user_desc(BdrvChild *c) -{ - if (c->klass->get_parent_desc) { - return c->klass->get_parent_desc(c); - } - - return g_strdup("another user"); -} - char *bdrv_perm_names(uint64_t perm) { struct perm_name { @@ -2355,6 +2397,9 @@ static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp) int ret; uint64_t perm, shared_perm; + if (bdrv_parent_perms_conflict(bs, errp)) { + return -EPERM; + } bdrv_get_cumulative_perm(bs, &perm, &shared_perm); ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, errp); if (ret < 0) { From b0defa83562dc904000679ea9eda46985c574d80 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:38 +0300 Subject: [PATCH 0059/3028] block: refactor bdrv_child* permission functions Split out non-recursive parts, and refactor as block graph transaction action. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-11-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 79 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/block.c b/block.c index fd621f0403..0ee0c2f29a 100644 --- a/block.c +++ b/block.c @@ -49,6 +49,7 @@ #include "qemu/timer.h" #include "qemu/cutils.h" #include "qemu/id.h" +#include "qemu/transactions.h" #include "block/coroutines.h" #ifdef CONFIG_BSD @@ -2093,6 +2094,61 @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, } } +static void bdrv_child_set_perm_commit(void *opaque) +{ + BdrvChild *c = opaque; + + c->has_backup_perm = false; +} + +static void bdrv_child_set_perm_abort(void *opaque) +{ + BdrvChild *c = opaque; + /* + * We may have child->has_backup_perm unset at this point, as in case of + * _check_ stage of permission update failure we may _check_ not the whole + * subtree. Still, _abort_ is called on the whole subtree anyway. + */ + if (c->has_backup_perm) { + c->perm = c->backup_perm; + c->shared_perm = c->backup_shared_perm; + c->has_backup_perm = false; + } +} + +static TransactionActionDrv bdrv_child_set_pem_drv = { + .abort = bdrv_child_set_perm_abort, + .commit = bdrv_child_set_perm_commit, +}; + +/* + * With tran=NULL needs to be followed by direct call to either + * bdrv_child_set_perm_commit() or bdrv_child_set_perm_abort(). + * + * With non-NULL tran needs to be followed by tran_abort() or tran_commit() + * instead. + */ +static void bdrv_child_set_perm_safe(BdrvChild *c, uint64_t perm, + uint64_t shared, Transaction *tran) +{ + if (!c->has_backup_perm) { + c->has_backup_perm = true; + c->backup_perm = c->perm; + c->backup_shared_perm = c->shared_perm; + } + /* + * Note: it's OK if c->has_backup_perm was already set, as we can find the + * same c twice during check_perm procedure + */ + + c->perm = perm; + c->shared_perm = shared; + + if (tran) { + tran_add(tran, &bdrv_child_set_pem_drv, c); + } +} + /* * Check whether permissions on this node can be changed in a way that * @cumulative_perms and @cumulative_shared_perms are the new cumulative @@ -2358,37 +2414,20 @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q, return ret; } - if (!c->has_backup_perm) { - c->has_backup_perm = true; - c->backup_perm = c->perm; - c->backup_shared_perm = c->shared_perm; - } - /* - * Note: it's OK if c->has_backup_perm was already set, as we can find the - * same child twice during check_perm procedure - */ - - c->perm = perm; - c->shared_perm = shared; + bdrv_child_set_perm_safe(c, perm, shared, NULL); return 0; } static void bdrv_child_set_perm(BdrvChild *c) { - c->has_backup_perm = false; - + bdrv_child_set_perm_commit(c); bdrv_set_perm(c->bs); } static void bdrv_child_abort_perm_update(BdrvChild *c) { - if (c->has_backup_perm) { - c->perm = c->backup_perm; - c->shared_perm = c->backup_shared_perm; - c->has_backup_perm = false; - } - + bdrv_child_set_perm_abort(c); bdrv_abort_perm_update(c->bs); } From 83928dc4968284c8c0c56c8186c5a789b794ef5a Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:39 +0300 Subject: [PATCH 0060/3028] block: rewrite bdrv_child_try_set_perm() using bdrv_refresh_perms() We are going to drop recursive bdrv_child_* functions, so stop use them in bdrv_child_try_set_perm() as a first step. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-12-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index 0ee0c2f29a..4511766825 100644 --- a/block.c +++ b/block.c @@ -2454,11 +2454,16 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, Error **errp) { Error *local_err = NULL; + Transaction *tran = tran_new(); int ret; - ret = bdrv_child_check_perm(c, NULL, perm, shared, NULL, &local_err); + bdrv_child_set_perm_safe(c, perm, shared, tran); + + ret = bdrv_refresh_perms(c->bs, &local_err); + + tran_finalize(tran, ret); + if (ret < 0) { - bdrv_child_abort_perm_update(c); if ((perm & ~c->perm) || (c->shared_perm & ~shared)) { /* tighten permissions */ error_propagate(errp, local_err); @@ -2472,12 +2477,9 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, error_free(local_err); ret = 0; } - return ret; } - bdrv_child_set_perm(c); - - return 0; + return ret; } int bdrv_child_refresh_perms(BlockDriverState *bs, BdrvChild *c, Error **errp) From 3ef45e0242671745a6e9921e200d9dc3299aa222 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:40 +0300 Subject: [PATCH 0061/3028] block: inline bdrv_child_*() permission functions calls Each of them has only one caller. Open-coding simplifies further pemission-update system changes. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Alberto Garcia Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-13-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 59 +++++++++++++++++---------------------------------------- 1 file changed, 17 insertions(+), 42 deletions(-) diff --git a/block.c b/block.c index 4511766825..e5af4cdae9 100644 --- a/block.c +++ b/block.c @@ -1974,11 +1974,11 @@ static int bdrv_fill_options(QDict **options, const char *filename, return 0; } -static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q, - uint64_t perm, uint64_t shared, - GSList *ignore_children, Error **errp); -static void bdrv_child_abort_perm_update(BdrvChild *c); -static void bdrv_child_set_perm(BdrvChild *c); +static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, + uint64_t new_used_perm, + uint64_t new_shared_perm, + GSList *ignore_children, + Error **errp); typedef struct BlockReopenQueueEntry { bool prepared; @@ -2226,15 +2226,21 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, /* Check all children */ QLIST_FOREACH(c, &bs->children, next) { uint64_t cur_perm, cur_shared; + GSList *cur_ignore_children; bdrv_child_perm(bs, c->bs, c, c->role, q, cumulative_perms, cumulative_shared_perms, &cur_perm, &cur_shared); - ret = bdrv_child_check_perm(c, q, cur_perm, cur_shared, ignore_children, - errp); + + cur_ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c); + ret = bdrv_check_update_perm(c->bs, q, cur_perm, cur_shared, + cur_ignore_children, errp); + g_slist_free(cur_ignore_children); if (ret < 0) { return ret; } + + bdrv_child_set_perm_safe(c, cur_perm, cur_shared, NULL); } return 0; @@ -2261,7 +2267,8 @@ static void bdrv_abort_perm_update(BlockDriverState *bs) } QLIST_FOREACH(c, &bs->children, next) { - bdrv_child_abort_perm_update(c); + bdrv_child_set_perm_abort(c); + bdrv_abort_perm_update(c->bs); } } @@ -2290,7 +2297,8 @@ static void bdrv_set_perm(BlockDriverState *bs) /* Update all children */ QLIST_FOREACH(c, &bs->children, next) { - bdrv_child_set_perm(c); + bdrv_child_set_perm_commit(c); + bdrv_set_perm(c->bs); } } @@ -2398,39 +2406,6 @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, ignore_children, errp); } -/* Needs to be followed by a call to either bdrv_child_set_perm() or - * bdrv_child_abort_perm_update(). */ -static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q, - uint64_t perm, uint64_t shared, - GSList *ignore_children, Error **errp) -{ - int ret; - - ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c); - ret = bdrv_check_update_perm(c->bs, q, perm, shared, ignore_children, errp); - g_slist_free(ignore_children); - - if (ret < 0) { - return ret; - } - - bdrv_child_set_perm_safe(c, perm, shared, NULL); - - return 0; -} - -static void bdrv_child_set_perm(BdrvChild *c) -{ - bdrv_child_set_perm_commit(c); - bdrv_set_perm(c->bs); -} - -static void bdrv_child_abort_perm_update(BdrvChild *c) -{ - bdrv_child_set_perm_abort(c); - bdrv_abort_perm_update(c->bs); -} - static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp) { int ret; From bd57f8f7f82822b76c55268593f3db49922be4dd Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:41 +0300 Subject: [PATCH 0062/3028] block: use topological sort for permission update Rewrite bdrv_check_perm(), bdrv_abort_perm_update() and bdrv_set_perm() to update nodes in topological sort order instead of simple DFS. With topologically sorted nodes, we update a node only when all its parents already updated. With DFS it's not so. Consider the following example: A -+ | | | v | B | | v | C<-+ A is parent for B and C, B is parent for C. Obviously, to update permissions, we should go in order A B C, so, when we update C, all parent permissions already updated. But with current approach (simple recursion) we can update in sequence A C B C (C is updated twice). On first update of C, we consider old B permissions, so doing wrong thing. If it succeed, all is OK, on second C update we will finish with correct graph. But if the wrong thing failed, we break the whole process for no reason (it's possible that updated B permission will be less strict, but we will never check it). Also new approach gives a way to simultaneously and correctly update several nodes, we just need to run bdrv_topological_dfs() several times to add all nodes and their subtrees into one topologically sorted list (next patch will update bdrv_replace_node() in this manner). Test test_parallel_perm_update() is now passing, so move it out of debugging "if". We also need to support ignore_children in bdrv_parent_perms_conflict() For test 283 order of conflicting parents check is changed. Note also that in bdrv_check_perm() we don't check for parents conflict at root bs, as we may be in the middle of permission update in bdrv_reopen_multiple(). bdrv_reopen_multiple() will be updated soon. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-14-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 116 +++++++++++++++++++++++++------ tests/qemu-iotests/283.out | 2 +- tests/unit/test-bdrv-graph-mod.c | 4 +- 3 files changed, 99 insertions(+), 23 deletions(-) diff --git a/block.c b/block.c index e5af4cdae9..cbcc4c15a0 100644 --- a/block.c +++ b/block.c @@ -2054,7 +2054,9 @@ static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp) return false; } -static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp) +static bool bdrv_parent_perms_conflict(BlockDriverState *bs, + GSList *ignore_children, + Error **errp) { BdrvChild *a, *b; @@ -2064,8 +2066,12 @@ static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp) * directions. */ QLIST_FOREACH(a, &bs->parents, next_parent) { + if (g_slist_find(ignore_children, a)) { + continue; + } + QLIST_FOREACH(b, &bs->parents, next_parent) { - if (a == b) { + if (a == b || g_slist_find(ignore_children, b)) { continue; } @@ -2094,6 +2100,40 @@ static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs, } } +/* + * Adds the whole subtree of @bs (including @bs itself) to the @list (except for + * nodes that are already in the @list, of course) so that final list is + * topologically sorted. Return the result (GSList @list object is updated, so + * don't use old reference after function call). + * + * On function start @list must be already topologically sorted and for any node + * in the @list the whole subtree of the node must be in the @list as well. The + * simplest way to satisfy this criteria: use only result of + * bdrv_topological_dfs() or NULL as @list parameter. + */ +static GSList *bdrv_topological_dfs(GSList *list, GHashTable *found, + BlockDriverState *bs) +{ + BdrvChild *child; + g_autoptr(GHashTable) local_found = NULL; + + if (!found) { + assert(!list); + found = local_found = g_hash_table_new(NULL, NULL); + } + + if (g_hash_table_contains(found, bs)) { + return list; + } + g_hash_table_add(found, bs); + + QLIST_FOREACH(child, &bs->children, next) { + list = bdrv_topological_dfs(list, found, child->bs); + } + + return g_slist_prepend(list, bs); +} + static void bdrv_child_set_perm_commit(void *opaque) { BdrvChild *c = opaque; @@ -2158,10 +2198,10 @@ static void bdrv_child_set_perm_safe(BdrvChild *c, uint64_t perm, * A call to this function must always be followed by a call to bdrv_set_perm() * or bdrv_abort_perm_update(). */ -static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, - uint64_t cumulative_perms, - uint64_t cumulative_shared_perms, - GSList *ignore_children, Error **errp) +static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q, + uint64_t cumulative_perms, + uint64_t cumulative_shared_perms, + GSList *ignore_children, Error **errp) { BlockDriver *drv = bs->drv; BdrvChild *c; @@ -2226,21 +2266,43 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, /* Check all children */ QLIST_FOREACH(c, &bs->children, next) { uint64_t cur_perm, cur_shared; - GSList *cur_ignore_children; bdrv_child_perm(bs, c->bs, c, c->role, q, cumulative_perms, cumulative_shared_perms, &cur_perm, &cur_shared); + bdrv_child_set_perm_safe(c, cur_perm, cur_shared, NULL); + } - cur_ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c); - ret = bdrv_check_update_perm(c->bs, q, cur_perm, cur_shared, - cur_ignore_children, errp); - g_slist_free(cur_ignore_children); + return 0; +} + +static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, + uint64_t cumulative_perms, + uint64_t cumulative_shared_perms, + GSList *ignore_children, Error **errp) +{ + int ret; + BlockDriverState *root = bs; + g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, root); + + for ( ; list; list = list->next) { + bs = list->data; + + if (bs != root) { + if (bdrv_parent_perms_conflict(bs, ignore_children, errp)) { + return -EINVAL; + } + + bdrv_get_cumulative_perm(bs, &cumulative_perms, + &cumulative_shared_perms); + } + + ret = bdrv_node_check_perm(bs, q, cumulative_perms, + cumulative_shared_perms, + ignore_children, errp); if (ret < 0) { return ret; } - - bdrv_child_set_perm_safe(c, cur_perm, cur_shared, NULL); } return 0; @@ -2250,10 +2312,8 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, * Notifies drivers that after a previous bdrv_check_perm() call, the * permission update is not performed and any preparations made for it (e.g. * taken file locks) need to be undone. - * - * This function recursively notifies all child nodes. */ -static void bdrv_abort_perm_update(BlockDriverState *bs) +static void bdrv_node_abort_perm_update(BlockDriverState *bs) { BlockDriver *drv = bs->drv; BdrvChild *c; @@ -2268,11 +2328,19 @@ static void bdrv_abort_perm_update(BlockDriverState *bs) QLIST_FOREACH(c, &bs->children, next) { bdrv_child_set_perm_abort(c); - bdrv_abort_perm_update(c->bs); } } -static void bdrv_set_perm(BlockDriverState *bs) +static void bdrv_abort_perm_update(BlockDriverState *bs) +{ + g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); + + for ( ; list; list = list->next) { + bdrv_node_abort_perm_update((BlockDriverState *)list->data); + } +} + +static void bdrv_node_set_perm(BlockDriverState *bs) { uint64_t cumulative_perms, cumulative_shared_perms; BlockDriver *drv = bs->drv; @@ -2298,7 +2366,15 @@ static void bdrv_set_perm(BlockDriverState *bs) /* Update all children */ QLIST_FOREACH(c, &bs->children, next) { bdrv_child_set_perm_commit(c); - bdrv_set_perm(c->bs); + } +} + +static void bdrv_set_perm(BlockDriverState *bs) +{ + g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); + + for ( ; list; list = list->next) { + bdrv_node_set_perm((BlockDriverState *)list->data); } } @@ -2411,7 +2487,7 @@ static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp) int ret; uint64_t perm, shared_perm; - if (bdrv_parent_perms_conflict(bs, errp)) { + if (bdrv_parent_perms_conflict(bs, NULL, errp)) { return -EPERM; } bdrv_get_cumulative_perm(bs, &perm, &shared_perm); diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out index 37c35058ae..73eb75102f 100644 --- a/tests/qemu-iotests/283.out +++ b/tests/qemu-iotests/283.out @@ -5,7 +5,7 @@ {"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": "base", "node-name": "other", "take-child-perms": ["write"]}} {"return": {}} {"execute": "blockdev-backup", "arguments": {"device": "source", "sync": "full", "target": "target"}} -{"error": {"class": "GenericError", "desc": "Cannot set permissions for backup-top filter: Conflicts with use by other as 'image', which uses 'write' on base"}} +{"error": {"class": "GenericError", "desc": "Cannot set permissions for backup-top filter: Conflicts with use by source as 'image', which does not allow 'write' on base"}} === backup-top should be gone after job-finalize === diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c index a6064b1863..e64e81a07c 100644 --- a/tests/unit/test-bdrv-graph-mod.c +++ b/tests/unit/test-bdrv-graph-mod.c @@ -406,12 +406,12 @@ int main(int argc, char *argv[]) g_test_add_func("/bdrv-graph-mod/update-perm-tree", test_update_perm_tree); g_test_add_func("/bdrv-graph-mod/should-update-child", test_should_update_child); + g_test_add_func("/bdrv-graph-mod/parallel-perm-update", + test_parallel_perm_update); if (debug) { g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write", test_parallel_exclusive_write); - g_test_add_func("/bdrv-graph-mod/parallel-perm-update", - test_parallel_perm_update); g_test_add_func("/bdrv-graph-mod/append-greedy-filter", test_append_greedy_filter); } From 2513ef5959a10fc4f2bd2d3f19864e64ea88405d Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:42 +0300 Subject: [PATCH 0063/3028] block: add bdrv_drv_set_perm transaction action Refactor calling driver callbacks to a separate transaction action to be used later. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-15-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 70 ++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/block.c b/block.c index cbcc4c15a0..ab7a4d13d8 100644 --- a/block.c +++ b/block.c @@ -2189,6 +2189,54 @@ static void bdrv_child_set_perm_safe(BdrvChild *c, uint64_t perm, } } +static void bdrv_drv_set_perm_commit(void *opaque) +{ + BlockDriverState *bs = opaque; + uint64_t cumulative_perms, cumulative_shared_perms; + + if (bs->drv->bdrv_set_perm) { + bdrv_get_cumulative_perm(bs, &cumulative_perms, + &cumulative_shared_perms); + bs->drv->bdrv_set_perm(bs, cumulative_perms, cumulative_shared_perms); + } +} + +static void bdrv_drv_set_perm_abort(void *opaque) +{ + BlockDriverState *bs = opaque; + + if (bs->drv->bdrv_abort_perm_update) { + bs->drv->bdrv_abort_perm_update(bs); + } +} + +TransactionActionDrv bdrv_drv_set_perm_drv = { + .abort = bdrv_drv_set_perm_abort, + .commit = bdrv_drv_set_perm_commit, +}; + +static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm, + uint64_t shared_perm, Transaction *tran, + Error **errp) +{ + if (!bs->drv) { + return 0; + } + + if (bs->drv->bdrv_check_perm) { + int ret = bs->drv->bdrv_check_perm(bs, perm, shared_perm, errp); + if (ret < 0) { + return ret; + } + } + + if (tran) { + tran_add(tran, &bdrv_drv_set_perm_drv, bs); + } + + return 0; +} + /* * Check whether permissions on this node can be changed in a way that * @cumulative_perms and @cumulative_shared_perms are the new cumulative @@ -2249,12 +2297,10 @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q, return 0; } - if (drv->bdrv_check_perm) { - ret = drv->bdrv_check_perm(bs, cumulative_perms, - cumulative_shared_perms, errp); - if (ret < 0) { - return ret; - } + ret = bdrv_drv_set_perm(bs, cumulative_perms, cumulative_shared_perms, NULL, + errp); + if (ret < 0) { + return ret; } /* Drivers that never have children can omit .bdrv_child_perm() */ @@ -2322,9 +2368,7 @@ static void bdrv_node_abort_perm_update(BlockDriverState *bs) return; } - if (drv->bdrv_abort_perm_update) { - drv->bdrv_abort_perm_update(bs); - } + bdrv_drv_set_perm_abort(bs); QLIST_FOREACH(c, &bs->children, next) { bdrv_child_set_perm_abort(c); @@ -2342,7 +2386,6 @@ static void bdrv_abort_perm_update(BlockDriverState *bs) static void bdrv_node_set_perm(BlockDriverState *bs) { - uint64_t cumulative_perms, cumulative_shared_perms; BlockDriver *drv = bs->drv; BdrvChild *c; @@ -2350,12 +2393,7 @@ static void bdrv_node_set_perm(BlockDriverState *bs) return; } - bdrv_get_cumulative_perm(bs, &cumulative_perms, &cumulative_shared_perms); - - /* Update this node */ - if (drv->bdrv_set_perm) { - drv->bdrv_set_perm(bs, cumulative_perms, cumulative_shared_perms); - } + bdrv_drv_set_perm_commit(bs); /* Drivers that never have children can omit .bdrv_child_perm() */ if (!drv->bdrv_child_perm) { From b1d2bbeb3aecdfe109134c9dfb43a431e5280f24 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:43 +0300 Subject: [PATCH 0064/3028] block: add bdrv_list_* permission update functions Add new interface, allowing use of existing node list. It will be used to fix bdrv_replace_node() in the further commit. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-16-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 126 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 45 deletions(-) diff --git a/block.c b/block.c index ab7a4d13d8..98b7bc179c 100644 --- a/block.c +++ b/block.c @@ -2249,7 +2249,8 @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm, static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q, uint64_t cumulative_perms, uint64_t cumulative_shared_perms, - GSList *ignore_children, Error **errp) + GSList *ignore_children, + Transaction *tran, Error **errp) { BlockDriver *drv = bs->drv; BdrvChild *c; @@ -2297,7 +2298,7 @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q, return 0; } - ret = bdrv_drv_set_perm(bs, cumulative_perms, cumulative_shared_perms, NULL, + ret = bdrv_drv_set_perm(bs, cumulative_perms, cumulative_shared_perms, tran, errp); if (ret < 0) { return ret; @@ -2316,7 +2317,56 @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q, bdrv_child_perm(bs, c->bs, c, c->role, q, cumulative_perms, cumulative_shared_perms, &cur_perm, &cur_shared); - bdrv_child_set_perm_safe(c, cur_perm, cur_shared, NULL); + bdrv_child_set_perm_safe(c, cur_perm, cur_shared, tran); + } + + return 0; +} + +/* + * If use_cumulative_perms is true, use cumulative_perms and + * cumulative_shared_perms for first element of the list. Otherwise just refresh + * all permissions. + */ +static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q, + bool use_cumulative_perms, + uint64_t cumulative_perms, + uint64_t cumulative_shared_perms, + GSList *ignore_children, + Transaction *tran, Error **errp) +{ + int ret; + BlockDriverState *bs; + + if (use_cumulative_perms) { + bs = list->data; + + ret = bdrv_node_check_perm(bs, q, cumulative_perms, + cumulative_shared_perms, + ignore_children, tran, errp); + if (ret < 0) { + return ret; + } + + list = list->next; + } + + for ( ; list; list = list->next) { + bs = list->data; + + if (bdrv_parent_perms_conflict(bs, ignore_children, errp)) { + return -EINVAL; + } + + bdrv_get_cumulative_perm(bs, &cumulative_perms, + &cumulative_shared_perms); + + ret = bdrv_node_check_perm(bs, q, cumulative_perms, + cumulative_shared_perms, + ignore_children, tran, errp); + if (ret < 0) { + return ret; + } } return 0; @@ -2327,31 +2377,16 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, uint64_t cumulative_shared_perms, GSList *ignore_children, Error **errp) { - int ret; - BlockDriverState *root = bs; - g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, root); + g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); + return bdrv_check_perm_common(list, q, true, cumulative_perms, + cumulative_shared_perms, ignore_children, + NULL, errp); +} - for ( ; list; list = list->next) { - bs = list->data; - - if (bs != root) { - if (bdrv_parent_perms_conflict(bs, ignore_children, errp)) { - return -EINVAL; - } - - bdrv_get_cumulative_perm(bs, &cumulative_perms, - &cumulative_shared_perms); - } - - ret = bdrv_node_check_perm(bs, q, cumulative_perms, - cumulative_shared_perms, - ignore_children, errp); - if (ret < 0) { - return ret; - } - } - - return 0; +static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, + Transaction *tran, Error **errp) +{ + return bdrv_check_perm_common(list, q, false, 0, 0, NULL, tran, errp); } /* @@ -2375,15 +2410,19 @@ static void bdrv_node_abort_perm_update(BlockDriverState *bs) } } -static void bdrv_abort_perm_update(BlockDriverState *bs) +static void bdrv_list_abort_perm_update(GSList *list) { - g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); - for ( ; list; list = list->next) { bdrv_node_abort_perm_update((BlockDriverState *)list->data); } } +static void bdrv_abort_perm_update(BlockDriverState *bs) +{ + g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); + return bdrv_list_abort_perm_update(list); +} + static void bdrv_node_set_perm(BlockDriverState *bs) { BlockDriver *drv = bs->drv; @@ -2407,15 +2446,19 @@ static void bdrv_node_set_perm(BlockDriverState *bs) } } -static void bdrv_set_perm(BlockDriverState *bs) +static void bdrv_list_set_perm(GSList *list) { - g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); - for ( ; list; list = list->next) { bdrv_node_set_perm((BlockDriverState *)list->data); } } +static void bdrv_set_perm(BlockDriverState *bs) +{ + g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); + return bdrv_list_set_perm(list); +} + void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, uint64_t *shared_perm) { @@ -2523,20 +2566,13 @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp) { int ret; - uint64_t perm, shared_perm; + Transaction *tran = tran_new(); + g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); - if (bdrv_parent_perms_conflict(bs, NULL, errp)) { - return -EPERM; - } - bdrv_get_cumulative_perm(bs, &perm, &shared_perm); - ret = bdrv_check_perm(bs, NULL, perm, shared_perm, NULL, errp); - if (ret < 0) { - bdrv_abort_perm_update(bs); - return ret; - } - bdrv_set_perm(bs); + ret = bdrv_list_refresh_perms(list, NULL, tran, errp); + tran_finalize(tran, ret); - return 0; + return ret; } int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, From 0978623e0f485266b015f533e76f2efab0769100 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:44 +0300 Subject: [PATCH 0065/3028] block: add bdrv_replace_child_safe() transaction action To be used in the following commit. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-17-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/block.c b/block.c index 98b7bc179c..a5305662dc 100644 --- a/block.c +++ b/block.c @@ -83,6 +83,9 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, BdrvChildRole child_role, Error **errp); +static void bdrv_replace_child_noperm(BdrvChild *child, + BlockDriverState *new_bs); + static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, Error **errp); static void bdrv_reopen_commit(BDRVReopenState *reopen_state); @@ -2237,6 +2240,57 @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm, return 0; } +typedef struct BdrvReplaceChildState { + BdrvChild *child; + BlockDriverState *old_bs; +} BdrvReplaceChildState; + +static void bdrv_replace_child_commit(void *opaque) +{ + BdrvReplaceChildState *s = opaque; + + bdrv_unref(s->old_bs); +} + +static void bdrv_replace_child_abort(void *opaque) +{ + BdrvReplaceChildState *s = opaque; + BlockDriverState *new_bs = s->child->bs; + + /* old_bs reference is transparently moved from @s to @s->child */ + bdrv_replace_child_noperm(s->child, s->old_bs); + bdrv_unref(new_bs); +} + +static TransactionActionDrv bdrv_replace_child_drv = { + .commit = bdrv_replace_child_commit, + .abort = bdrv_replace_child_abort, + .clean = g_free, +}; + +/* + * bdrv_replace_child_safe + * + * Note: real unref of old_bs is done only on commit. + */ +__attribute__((unused)) +static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs, + Transaction *tran) +{ + BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1); + *s = (BdrvReplaceChildState) { + .child = child, + .old_bs = child->bs, + }; + tran_add(tran, &bdrv_replace_child_drv, s); + + if (new_bs) { + bdrv_ref(new_bs); + } + bdrv_replace_child_noperm(child, new_bs); + /* old_bs reference is transparently moved from @child to @s */ +} + /* * Check whether permissions on this node can be changed in a way that * @cumulative_perms and @cumulative_shared_perms are the new cumulative From 3bb0e2980a96db6276e5032dcb2ccbf41f699b59 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:45 +0300 Subject: [PATCH 0066/3028] block: fix bdrv_replace_node_common inore_children thing doesn't help to track all propagated permissions of children we want to ignore. The simplest way to correctly update permissions is update graph first and then do permission update. In this case we just referesh permissions for the whole subgraph (in topological-sort defined order) and everything is correctly calculated automatically without any ignore_children. So, refactor bdrv_replace_node_common to first do graph update and then refresh the permissions. Test test_parallel_exclusive_write() now pass, so move it out of debugging "if". Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-18-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 43 +++++++++++++------------------- tests/unit/test-bdrv-graph-mod.c | 4 +-- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/block.c b/block.c index a5305662dc..6040b9dea0 100644 --- a/block.c +++ b/block.c @@ -2273,7 +2273,6 @@ static TransactionActionDrv bdrv_replace_child_drv = { * * Note: real unref of old_bs is done only on commit. */ -__attribute__((unused)) static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs, Transaction *tran) { @@ -4877,8 +4876,9 @@ static int bdrv_replace_node_common(BlockDriverState *from, bool auto_skip, Error **errp) { BdrvChild *c, *next; - GSList *list = NULL, *p; - uint64_t perm = 0, shared = BLK_PERM_ALL; + Transaction *tran = tran_new(); + g_autoptr(GHashTable) found = NULL; + g_autoptr(GSList) refresh_list = NULL; int ret; /* Make sure that @from doesn't go away until we have successfully attached @@ -4889,7 +4889,12 @@ static int bdrv_replace_node_common(BlockDriverState *from, assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to)); bdrv_drained_begin(from); - /* Put all parents into @list and calculate their cumulative permissions */ + /* + * Do the replacement without permission update. + * Replacement may influence the permissions, we should calculate new + * permissions based on new graph. If we fail, we'll roll-back the + * replacement. + */ QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { assert(c->bs == from); if (!should_update_child(c, to)) { @@ -4907,36 +4912,24 @@ static int bdrv_replace_node_common(BlockDriverState *from, c->name, from->node_name); goto out; } - list = g_slist_prepend(list, c); - perm |= c->perm; - shared &= c->shared_perm; + bdrv_replace_child_safe(c, to, tran); } - /* Check whether the required permissions can be granted on @to, ignoring - * all BdrvChild in @list so that they can't block themselves. */ - ret = bdrv_check_update_perm(to, NULL, perm, shared, list, errp); + found = g_hash_table_new(NULL, NULL); + + refresh_list = bdrv_topological_dfs(refresh_list, found, to); + refresh_list = bdrv_topological_dfs(refresh_list, found, from); + + ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp); if (ret < 0) { - bdrv_abort_perm_update(to); goto out; } - /* Now actually perform the change. We performed the permission check for - * all elements of @list at once, so set the permissions all at once at the - * very end. */ - for (p = list; p != NULL; p = p->next) { - c = p->data; - - bdrv_ref(to); - bdrv_replace_child_noperm(c, to); - bdrv_unref(from); - } - - bdrv_set_perm(to); - ret = 0; out: - g_slist_free(list); + tran_finalize(tran, ret); + bdrv_drained_end(from); bdrv_unref(from); diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c index e64e81a07c..7b3c8b437a 100644 --- a/tests/unit/test-bdrv-graph-mod.c +++ b/tests/unit/test-bdrv-graph-mod.c @@ -408,10 +408,10 @@ int main(int argc, char *argv[]) test_should_update_child); g_test_add_func("/bdrv-graph-mod/parallel-perm-update", test_parallel_perm_update); + g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write", + test_parallel_exclusive_write); if (debug) { - g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write", - test_parallel_exclusive_write); g_test_add_func("/bdrv-graph-mod/append-greedy-filter", test_append_greedy_filter); } From 548a74c0dbc858edd1a7ee3045b5f2fe710bd8b1 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:46 +0300 Subject: [PATCH 0067/3028] block: add bdrv_attach_child_common() transaction action Split out no-perm part of bdrv_root_attach_child() into separate transaction action. bdrv_root_attach_child() now moves to new permission update paradigm: first update graph relations then update permissions. qsd-jobs test output updated. Seems now permission update goes in another order. Still, the test comment say that we only want to check that command doesn't crash, and it's still so. Error message is a bit misleading as it looks like job was added first. But actually in new paradigm of graph update we can't distinguish such things. We should update the error message, but let's not do it now. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210428151804.439460-19-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 194 ++++++++++++++++++-------- tests/qemu-iotests/tests/qsd-jobs.out | 2 +- 2 files changed, 139 insertions(+), 57 deletions(-) diff --git a/block.c b/block.c index 6040b9dea0..4d5c60f2ae 100644 --- a/block.c +++ b/block.c @@ -2955,6 +2955,136 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) } } +static void bdrv_remove_empty_child(BdrvChild *child) +{ + assert(!child->bs); + QLIST_SAFE_REMOVE(child, next); + g_free(child->name); + g_free(child); +} + +typedef struct BdrvAttachChildCommonState { + BdrvChild **child; + AioContext *old_parent_ctx; + AioContext *old_child_ctx; +} BdrvAttachChildCommonState; + +static void bdrv_attach_child_common_abort(void *opaque) +{ + BdrvAttachChildCommonState *s = opaque; + BdrvChild *child = *s->child; + BlockDriverState *bs = child->bs; + + bdrv_replace_child_noperm(child, NULL); + + if (bdrv_get_aio_context(bs) != s->old_child_ctx) { + bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort); + } + + if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) { + GSList *ignore = g_slist_prepend(NULL, child); + + child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore, + &error_abort); + g_slist_free(ignore); + ignore = g_slist_prepend(NULL, child); + child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore); + + g_slist_free(ignore); + } + + bdrv_unref(bs); + bdrv_remove_empty_child(child); + *s->child = NULL; +} + +static TransactionActionDrv bdrv_attach_child_common_drv = { + .abort = bdrv_attach_child_common_abort, + .clean = g_free, +}; + +/* + * Common part of attaching bdrv child to bs or to blk or to job + */ +static int bdrv_attach_child_common(BlockDriverState *child_bs, + const char *child_name, + const BdrvChildClass *child_class, + BdrvChildRole child_role, + uint64_t perm, uint64_t shared_perm, + void *opaque, BdrvChild **child, + Transaction *tran, Error **errp) +{ + BdrvChild *new_child; + AioContext *parent_ctx; + AioContext *child_ctx = bdrv_get_aio_context(child_bs); + + assert(child); + assert(*child == NULL); + + new_child = g_new(BdrvChild, 1); + *new_child = (BdrvChild) { + .bs = NULL, + .name = g_strdup(child_name), + .klass = child_class, + .role = child_role, + .perm = perm, + .shared_perm = shared_perm, + .opaque = opaque, + }; + + /* + * If the AioContexts don't match, first try to move the subtree of + * child_bs into the AioContext of the new parent. If this doesn't work, + * try moving the parent into the AioContext of child_bs instead. + */ + parent_ctx = bdrv_child_get_parent_aio_context(new_child); + if (child_ctx != parent_ctx) { + Error *local_err = NULL; + int ret = bdrv_try_set_aio_context(child_bs, parent_ctx, &local_err); + + if (ret < 0 && child_class->can_set_aio_ctx) { + GSList *ignore = g_slist_prepend(NULL, new_child); + if (child_class->can_set_aio_ctx(new_child, child_ctx, &ignore, + NULL)) + { + error_free(local_err); + ret = 0; + g_slist_free(ignore); + ignore = g_slist_prepend(NULL, new_child); + child_class->set_aio_ctx(new_child, child_ctx, &ignore); + } + g_slist_free(ignore); + } + + if (ret < 0) { + error_propagate(errp, local_err); + bdrv_remove_empty_child(new_child); + return ret; + } + } + + bdrv_ref(child_bs); + bdrv_replace_child_noperm(new_child, child_bs); + + *child = new_child; + + BdrvAttachChildCommonState *s = g_new(BdrvAttachChildCommonState, 1); + *s = (BdrvAttachChildCommonState) { + .child = child, + .old_parent_ctx = parent_ctx, + .old_child_ctx = child_ctx, + }; + tran_add(tran, &bdrv_attach_child_common_drv, s); + + return 0; +} + +static void bdrv_detach_child(BdrvChild *child) +{ + bdrv_replace_child(child, NULL); + bdrv_remove_empty_child(child); +} + /* * This function steals the reference to child_bs from the caller. * That reference is later dropped by bdrv_root_unref_child(). @@ -2972,60 +3102,22 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, uint64_t perm, uint64_t shared_perm, void *opaque, Error **errp) { - BdrvChild *child; - Error *local_err = NULL; int ret; - AioContext *ctx; + BdrvChild *child = NULL; + Transaction *tran = tran_new(); - ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp); + ret = bdrv_attach_child_common(child_bs, child_name, child_class, + child_role, perm, shared_perm, opaque, + &child, tran, errp); if (ret < 0) { - bdrv_abort_perm_update(child_bs); bdrv_unref(child_bs); return NULL; } - child = g_new(BdrvChild, 1); - *child = (BdrvChild) { - .bs = NULL, - .name = g_strdup(child_name), - .klass = child_class, - .role = child_role, - .perm = perm, - .shared_perm = shared_perm, - .opaque = opaque, - }; - - ctx = bdrv_child_get_parent_aio_context(child); - - /* If the AioContexts don't match, first try to move the subtree of - * child_bs into the AioContext of the new parent. If this doesn't work, - * try moving the parent into the AioContext of child_bs instead. */ - if (bdrv_get_aio_context(child_bs) != ctx) { - ret = bdrv_try_set_aio_context(child_bs, ctx, &local_err); - if (ret < 0 && child_class->can_set_aio_ctx) { - GSList *ignore = g_slist_prepend(NULL, child); - ctx = bdrv_get_aio_context(child_bs); - if (child_class->can_set_aio_ctx(child, ctx, &ignore, NULL)) { - error_free(local_err); - ret = 0; - g_slist_free(ignore); - ignore = g_slist_prepend(NULL, child); - child_class->set_aio_ctx(child, ctx, &ignore); - } - g_slist_free(ignore); - } - if (ret < 0) { - error_propagate(errp, local_err); - g_free(child); - bdrv_abort_perm_update(child_bs); - bdrv_unref(child_bs); - return NULL; - } - } - - /* This performs the matching bdrv_set_perm() for the above check. */ - bdrv_replace_child(child, child_bs); + ret = bdrv_refresh_perms(child_bs, errp); + tran_finalize(tran, ret); + bdrv_unref(child_bs); return child; } @@ -3067,16 +3159,6 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, return child; } -static void bdrv_detach_child(BdrvChild *child) -{ - QLIST_SAFE_REMOVE(child, next); - - bdrv_replace_child(child, NULL); - - g_free(child->name); - g_free(child); -} - /* Callers must ensure that child->frozen is false. */ void bdrv_root_unref_child(BdrvChild *child) { diff --git a/tests/qemu-iotests/tests/qsd-jobs.out b/tests/qemu-iotests/tests/qsd-jobs.out index 5f41491e05..9f52255da8 100644 --- a/tests/qemu-iotests/tests/qsd-jobs.out +++ b/tests/qemu-iotests/tests/qsd-jobs.out @@ -16,7 +16,7 @@ QMP_VERSION {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}} -{"error": {"class": "GenericError", "desc": "Conflicts with use by a block device as 'root', which uses 'write' on fmt_base"}} +{"error": {"class": "GenericError", "desc": "Conflicts with use by stream job 'job0' as 'intermediate node', which does not allow 'write' on fmt_base"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export1"}} *** done From aa5a04c7db27eea6b36de32f241b155f0d9ce34d Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:47 +0300 Subject: [PATCH 0068/3028] block: add bdrv_attach_child_noperm() transaction action Split no-perm part of bdrv_attach_child as separate transaction action. It will be used in later commits. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-20-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 14 deletions(-) diff --git a/block.c b/block.c index 4d5c60f2ae..c74e6e7cc1 100644 --- a/block.c +++ b/block.c @@ -85,6 +85,14 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, static void bdrv_replace_child_noperm(BdrvChild *child, BlockDriverState *new_bs); +static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, + BlockDriverState *child_bs, + const char *child_name, + const BdrvChildClass *child_class, + BdrvChildRole child_role, + BdrvChild **child, + Transaction *tran, + Error **errp); static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, Error **errp); @@ -3079,6 +3087,40 @@ static int bdrv_attach_child_common(BlockDriverState *child_bs, return 0; } +static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, + BlockDriverState *child_bs, + const char *child_name, + const BdrvChildClass *child_class, + BdrvChildRole child_role, + BdrvChild **child, + Transaction *tran, + Error **errp) +{ + int ret; + uint64_t perm, shared_perm; + + assert(parent_bs->drv); + + bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); + bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, + perm, shared_perm, &perm, &shared_perm); + + ret = bdrv_attach_child_common(child_bs, child_name, child_class, + child_role, perm, shared_perm, parent_bs, + child, tran, errp); + if (ret < 0) { + return ret; + } + + QLIST_INSERT_HEAD(&parent_bs->children, *child, next); + /* + * child is removed in bdrv_attach_child_common_abort(), so don't care to + * abort this change separately. + */ + + return 0; +} + static void bdrv_detach_child(BdrvChild *child) { bdrv_replace_child(child, NULL); @@ -3139,23 +3181,26 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, BdrvChildRole child_role, Error **errp) { - BdrvChild *child; - uint64_t perm, shared_perm; + int ret; + BdrvChild *child = NULL; + Transaction *tran = tran_new(); - bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); - - assert(parent_bs->drv); - bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, - perm, shared_perm, &perm, &shared_perm); - - child = bdrv_root_attach_child(child_bs, child_name, child_class, - child_role, perm, shared_perm, parent_bs, - errp); - if (child == NULL) { - return NULL; + ret = bdrv_attach_child_noperm(parent_bs, child_bs, child_name, child_class, + child_role, &child, tran, errp); + if (ret < 0) { + goto out; } - QLIST_INSERT_HEAD(&parent_bs->children, child, next); + ret = bdrv_refresh_perms(parent_bs, errp); + if (ret < 0) { + goto out; + } + +out: + tran_finalize(tran, ret); + + bdrv_unref(child_bs); + return child; } From 117caba9fc58972d32d97147c1211027e661dc35 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:48 +0300 Subject: [PATCH 0069/3028] block: split out bdrv_replace_node_noperm() Split part of bdrv_replace_node_common() to be used separately. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-21-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 50 +++++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/block.c b/block.c index c74e6e7cc1..9283c8d97b 100644 --- a/block.c +++ b/block.c @@ -4991,6 +4991,34 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to) return ret; } +static int bdrv_replace_node_noperm(BlockDriverState *from, + BlockDriverState *to, + bool auto_skip, Transaction *tran, + Error **errp) +{ + BdrvChild *c, *next; + + QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { + assert(c->bs == from); + if (!should_update_child(c, to)) { + if (auto_skip) { + continue; + } + error_setg(errp, "Should not change '%s' link to '%s'", + c->name, from->node_name); + return -EINVAL; + } + if (c->frozen) { + error_setg(errp, "Cannot change '%s' link to '%s'", + c->name, from->node_name); + return -EPERM; + } + bdrv_replace_child_safe(c, to, tran); + } + + return 0; +} + /* * With auto_skip=true bdrv_replace_node_common skips updating from parents * if it creates a parent-child relation loop or if parent is block-job. @@ -5002,7 +5030,6 @@ static int bdrv_replace_node_common(BlockDriverState *from, BlockDriverState *to, bool auto_skip, Error **errp) { - BdrvChild *c, *next; Transaction *tran = tran_new(); g_autoptr(GHashTable) found = NULL; g_autoptr(GSList) refresh_list = NULL; @@ -5022,24 +5049,9 @@ static int bdrv_replace_node_common(BlockDriverState *from, * permissions based on new graph. If we fail, we'll roll-back the * replacement. */ - QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { - assert(c->bs == from); - if (!should_update_child(c, to)) { - if (auto_skip) { - continue; - } - ret = -EINVAL; - error_setg(errp, "Should not change '%s' link to '%s'", - c->name, from->node_name); - goto out; - } - if (c->frozen) { - ret = -EPERM; - error_setg(errp, "Cannot change '%s' link to '%s'", - c->name, from->node_name); - goto out; - } - bdrv_replace_child_safe(c, to, tran); + ret = bdrv_replace_node_noperm(from, to, auto_skip, tran, errp); + if (ret < 0) { + goto out; } found = g_hash_table_new(NULL, NULL); From 2272edcfffba659d0b49b98a9d5e65783b2c4e53 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:49 +0300 Subject: [PATCH 0070/3028] block: adapt bdrv_append() for inserting filters bdrv_append is not very good for inserting filters: it does extra permission update as part of bdrv_set_backing_hd(). During this update filter may conflict with other parents of top_bs. Instead, let's first do all graph modifications and after it update permissions. append-greedy-filter test-case in test-bdrv-graph-mod is now works, so move it out of debug option. Note: bdrv_append() is still only works for backing-child based filters. It's something to improve later. Note2: we use the fact that bdrv_append() is used to append new nodes, without backing child, so we don't need frozen check and inherits_from logic from bdrv_set_backing_hd(). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-22-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 27 ++++++++++++++++++++------- tests/unit/test-bdrv-graph-mod.c | 17 ++--------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/block.c b/block.c index 9283c8d97b..5bb6a2bef9 100644 --- a/block.c +++ b/block.c @@ -5088,25 +5088,38 @@ int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, * This will modify the BlockDriverState fields, and swap contents * between bs_new and bs_top. Both bs_new and bs_top are modified. * - * bs_new must not be attached to a BlockBackend. + * bs_new must not be attached to a BlockBackend and must not have backing + * child. * * This function does not create any image files. */ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, Error **errp) { - int ret = bdrv_set_backing_hd(bs_new, bs_top, errp); + int ret; + Transaction *tran = tran_new(); + + assert(!bs_new->backing); + + ret = bdrv_attach_child_noperm(bs_new, bs_top, "backing", + &child_of_bds, bdrv_backing_role(bs_new), + &bs_new->backing, tran, errp); if (ret < 0) { - return ret; + goto out; } - ret = bdrv_replace_node(bs_top, bs_new, errp); + ret = bdrv_replace_node_noperm(bs_top, bs_new, true, tran, errp); if (ret < 0) { - bdrv_set_backing_hd(bs_new, NULL, &error_abort); - return ret; + goto out; } - return 0; + ret = bdrv_refresh_perms(bs_new, errp); +out: + tran_finalize(tran, ret); + + bdrv_refresh_limits(bs_top, NULL); + + return ret; } static void bdrv_delete(BlockDriverState *bs) diff --git a/tests/unit/test-bdrv-graph-mod.c b/tests/unit/test-bdrv-graph-mod.c index 7b3c8b437a..88f25c0cdb 100644 --- a/tests/unit/test-bdrv-graph-mod.c +++ b/tests/unit/test-bdrv-graph-mod.c @@ -388,16 +388,6 @@ static void test_append_greedy_filter(void) int main(int argc, char *argv[]) { - int i; - bool debug = false; - - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-d")) { - debug = true; - break; - } - } - bdrv_init(); qemu_init_main_loop(&error_abort); @@ -410,11 +400,8 @@ int main(int argc, char *argv[]) test_parallel_perm_update); g_test_add_func("/bdrv-graph-mod/parallel-exclusive-write", test_parallel_exclusive_write); - - if (debug) { - g_test_add_func("/bdrv-graph-mod/append-greedy-filter", - test_append_greedy_filter); - } + g_test_add_func("/bdrv-graph-mod/append-greedy-filter", + test_append_greedy_filter); return g_test_run(); } From 46541ee579b134485376bf51cf85250877ca69ec Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:50 +0300 Subject: [PATCH 0071/3028] block: add bdrv_remove_filter_or_cow transaction action Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-23-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index 5bb6a2bef9..2ea9cc110d 100644 --- a/block.c +++ b/block.c @@ -2963,12 +2963,19 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) } } +static void bdrv_child_free(void *opaque) +{ + BdrvChild *c = opaque; + + g_free(c->name); + g_free(c); +} + static void bdrv_remove_empty_child(BdrvChild *child) { assert(!child->bs); QLIST_SAFE_REMOVE(child, next); - g_free(child->name); - g_free(child); + bdrv_child_free(child); } typedef struct BdrvAttachChildCommonState { @@ -4991,6 +4998,79 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to) return ret; } +typedef struct BdrvRemoveFilterOrCowChild { + BdrvChild *child; + bool is_backing; +} BdrvRemoveFilterOrCowChild; + +static void bdrv_remove_filter_or_cow_child_abort(void *opaque) +{ + BdrvRemoveFilterOrCowChild *s = opaque; + BlockDriverState *parent_bs = s->child->opaque; + + QLIST_INSERT_HEAD(&parent_bs->children, s->child, next); + if (s->is_backing) { + parent_bs->backing = s->child; + } else { + parent_bs->file = s->child; + } + + /* + * We don't have to restore child->bs here to undo bdrv_replace_child() + * because that function is transactionable and it registered own completion + * entries in @tran, so .abort() for bdrv_replace_child_safe() will be + * called automatically. + */ +} + +static void bdrv_remove_filter_or_cow_child_commit(void *opaque) +{ + BdrvRemoveFilterOrCowChild *s = opaque; + + bdrv_child_free(s->child); +} + +static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = { + .abort = bdrv_remove_filter_or_cow_child_abort, + .commit = bdrv_remove_filter_or_cow_child_commit, + .clean = g_free, +}; + +/* + * A function to remove backing-chain child of @bs if exists: cow child for + * format nodes (always .backing) and filter child for filters (may be .file or + * .backing) + */ +__attribute__((unused)) +static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs, + Transaction *tran) +{ + BdrvRemoveFilterOrCowChild *s; + BdrvChild *child = bdrv_filter_or_cow_child(bs); + + if (!child) { + return; + } + + if (child->bs) { + bdrv_replace_child_safe(child, NULL, tran); + } + + s = g_new(BdrvRemoveFilterOrCowChild, 1); + *s = (BdrvRemoveFilterOrCowChild) { + .child = child, + .is_backing = (child == bs->backing), + }; + tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s); + + QLIST_SAFE_REMOVE(child, next); + if (s->is_backing) { + bs->backing = NULL; + } else { + bs->file = NULL; + } +} + static int bdrv_replace_node_noperm(BlockDriverState *from, BlockDriverState *to, bool auto_skip, Transaction *tran, From 3108a15cf09865456d499b08fe14e3dbec4ccbb3 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:51 +0300 Subject: [PATCH 0072/3028] block: introduce bdrv_drop_filter() Using bdrv_replace_node() for removing filter is not good enough: it keeps child reference of the filter, which may conflict with original top node during permission update. Instead let's create new interface, which will do all graph modifications first and then update permissions. Let's modify bdrv_replace_node_common(), allowing it additionally drop backing chain child link pointing to new node. This is quite appropriate for bdrv_drop_intermediate() and makes possible to add new bdrv_drop_filter() as a simple wrapper. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-24-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 43 +++++++++++++++++++++++++++++++++++++++---- include/block/block.h | 1 + 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/block.c b/block.c index 2ea9cc110d..68dfd822dd 100644 --- a/block.c +++ b/block.c @@ -5041,7 +5041,6 @@ static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = { * format nodes (always .backing) and filter child for filters (may be .file or * .backing) */ -__attribute__((unused)) static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs, Transaction *tran) { @@ -5105,16 +5104,32 @@ static int bdrv_replace_node_noperm(BlockDriverState *from, * * With auto_skip=false the error is returned if from has a parent which should * not be updated. + * + * With @detach_subchain=true @to must be in a backing chain of @from. In this + * case backing link of the cow-parent of @to is removed. */ static int bdrv_replace_node_common(BlockDriverState *from, BlockDriverState *to, - bool auto_skip, Error **errp) + bool auto_skip, bool detach_subchain, + Error **errp) { Transaction *tran = tran_new(); g_autoptr(GHashTable) found = NULL; g_autoptr(GSList) refresh_list = NULL; + BlockDriverState *to_cow_parent; int ret; + if (detach_subchain) { + assert(bdrv_chain_contains(from, to)); + assert(from != to); + for (to_cow_parent = from; + bdrv_filter_or_cow_bs(to_cow_parent) != to; + to_cow_parent = bdrv_filter_or_cow_bs(to_cow_parent)) + { + ; + } + } + /* Make sure that @from doesn't go away until we have successfully attached * all of its parents to @to. */ bdrv_ref(from); @@ -5134,6 +5149,10 @@ static int bdrv_replace_node_common(BlockDriverState *from, goto out; } + if (detach_subchain) { + bdrv_remove_filter_or_cow_child(to_cow_parent, tran); + } + found = g_hash_table_new(NULL, NULL); refresh_list = bdrv_topological_dfs(refresh_list, found, to); @@ -5158,7 +5177,13 @@ out: int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, Error **errp) { - return bdrv_replace_node_common(from, to, true, errp); + return bdrv_replace_node_common(from, to, true, false, errp); +} + +int bdrv_drop_filter(BlockDriverState *bs, Error **errp) +{ + return bdrv_replace_node_common(bs, bdrv_filter_or_cow_bs(bs), true, true, + errp); } /* @@ -5493,7 +5518,17 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base, updated_children = g_slist_prepend(updated_children, c); } - bdrv_replace_node_common(top, base, false, &local_err); + /* + * It seems correct to pass detach_subchain=true here, but it triggers + * one more yet not fixed bug, when due to nested aio_poll loop we switch to + * another drained section, which modify the graph (for example, removing + * the child, which we keep in updated_children list). So, it's a TODO. + * + * Note, bug triggered if pass detach_subchain=true here and run + * test-bdrv-drain. test_drop_intermediate_poll() test-case will crash. + * That's a FIXME. + */ + bdrv_replace_node_common(top, base, false, false, &local_err); if (local_err) { error_report_err(local_err); goto exit; diff --git a/include/block/block.h b/include/block/block.h index 16e496a5c4..85481a05c6 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -362,6 +362,7 @@ int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, Error **errp); BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options, int flags, Error **errp); +int bdrv_drop_filter(BlockDriverState *bs, Error **errp); int bdrv_parse_aio(const char *mode, int *flags); int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough); From b75d64b329013613532baae1623a72c78bee9bbc Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:52 +0300 Subject: [PATCH 0073/3028] block/backup-top: drop .active We don't need this workaround anymore: bdrv_append is already smart enough and we can use new bdrv_drop_filter(). This commit efficiently reverts also recent 705dde27c6c53b73, which checked .active on io path. Still it said that the problem should be theoretical. And the logic of filter removement is changed anyway. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-25-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block/backup-top.c | 47 +------------------------------------- tests/qemu-iotests/283.out | 2 +- 2 files changed, 2 insertions(+), 47 deletions(-) diff --git a/block/backup-top.c b/block/backup-top.c index 62d09f213e..425e3778be 100644 --- a/block/backup-top.c +++ b/block/backup-top.c @@ -37,7 +37,6 @@ typedef struct BDRVBackupTopState { BlockCopyState *bcs; BdrvChild *target; - bool active; int64_t cluster_size; } BDRVBackupTopState; @@ -45,12 +44,6 @@ static coroutine_fn int backup_top_co_preadv( BlockDriverState *bs, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags) { - BDRVBackupTopState *s = bs->opaque; - - if (!s->active) { - return -EIO; - } - return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); } @@ -60,10 +53,6 @@ static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset, BDRVBackupTopState *s = bs->opaque; uint64_t off, end; - if (!s->active) { - return -EIO; - } - if (flags & BDRV_REQ_WRITE_UNCHANGED) { return 0; } @@ -137,21 +126,6 @@ static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - BDRVBackupTopState *s = bs->opaque; - - if (!s->active) { - /* - * The filter node may be in process of bdrv_append(), which firstly do - * bdrv_set_backing_hd() and then bdrv_replace_node(). This means that - * we can't unshare BLK_PERM_WRITE during bdrv_append() operation. So, - * let's require nothing during bdrv_append() and refresh permissions - * after it (see bdrv_backup_top_append()). - */ - *nperm = 0; - *nshared = BLK_PERM_ALL; - return; - } - if (!(role & BDRV_CHILD_FILTERED)) { /* * Target child @@ -241,17 +215,6 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, } appended = true; - /* - * bdrv_append() finished successfully, now we can require permissions - * we want. - */ - state->active = true; - ret = bdrv_child_refresh_perms(top, top->backing, errp); - if (ret < 0) { - error_prepend(errp, "Cannot set permissions for backup-top filter: "); - goto fail; - } - state->cluster_size = cluster_size; state->bcs = block_copy_state_new(top->backing, state->target, cluster_size, perf->use_copy_range, @@ -268,7 +231,6 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, fail: if (appended) { - state->active = false; bdrv_backup_top_drop(top); } else { bdrv_unref(top); @@ -283,16 +245,9 @@ void bdrv_backup_top_drop(BlockDriverState *bs) { BDRVBackupTopState *s = bs->opaque; - bdrv_drained_begin(bs); + bdrv_drop_filter(bs, &error_abort); block_copy_state_free(s->bcs); - s->active = false; - bdrv_child_refresh_perms(bs, bs->backing, &error_abort); - bdrv_replace_node(bs, bs->backing->bs, &error_abort); - bdrv_set_backing_hd(bs, NULL, &error_abort); - - bdrv_drained_end(bs); - bdrv_unref(bs); } diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out index 73eb75102f..97e62a4c94 100644 --- a/tests/qemu-iotests/283.out +++ b/tests/qemu-iotests/283.out @@ -5,7 +5,7 @@ {"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": "base", "node-name": "other", "take-child-perms": ["write"]}} {"return": {}} {"execute": "blockdev-backup", "arguments": {"device": "source", "sync": "full", "target": "target"}} -{"error": {"class": "GenericError", "desc": "Cannot set permissions for backup-top filter: Conflicts with use by source as 'image', which does not allow 'write' on base"}} +{"error": {"class": "GenericError", "desc": "Cannot append backup-top filter: Conflicts with use by source as 'image', which does not allow 'write' on base"}} === backup-top should be gone after job-finalize === From 9397c14fcb90edf235cee0d11ea12184ea1f601d Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:53 +0300 Subject: [PATCH 0074/3028] block: drop ignore_children for permission update functions This argument is always NULL. Drop it. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-26-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/block.c b/block.c index 68dfd822dd..46af5852ab 100644 --- a/block.c +++ b/block.c @@ -1988,7 +1988,6 @@ static int bdrv_fill_options(QDict **options, const char *filename, static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, uint64_t new_used_perm, uint64_t new_shared_perm, - GSList *ignore_children, Error **errp); typedef struct BlockReopenQueueEntry { @@ -2065,9 +2064,7 @@ static bool bdrv_a_allow_b(BdrvChild *a, BdrvChild *b, Error **errp) return false; } -static bool bdrv_parent_perms_conflict(BlockDriverState *bs, - GSList *ignore_children, - Error **errp) +static bool bdrv_parent_perms_conflict(BlockDriverState *bs, Error **errp) { BdrvChild *a, *b; @@ -2077,12 +2074,8 @@ static bool bdrv_parent_perms_conflict(BlockDriverState *bs, * directions. */ QLIST_FOREACH(a, &bs->parents, next_parent) { - if (g_slist_find(ignore_children, a)) { - continue; - } - QLIST_FOREACH(b, &bs->parents, next_parent) { - if (a == b || g_slist_find(ignore_children, b)) { + if (a == b) { continue; } @@ -2310,7 +2303,6 @@ static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs, static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q, uint64_t cumulative_perms, uint64_t cumulative_shared_perms, - GSList *ignore_children, Transaction *tran, Error **errp) { BlockDriver *drv = bs->drv; @@ -2393,7 +2385,6 @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q, bool use_cumulative_perms, uint64_t cumulative_perms, uint64_t cumulative_shared_perms, - GSList *ignore_children, Transaction *tran, Error **errp) { int ret; @@ -2404,7 +2395,7 @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q, ret = bdrv_node_check_perm(bs, q, cumulative_perms, cumulative_shared_perms, - ignore_children, tran, errp); + tran, errp); if (ret < 0) { return ret; } @@ -2415,7 +2406,7 @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q, for ( ; list; list = list->next) { bs = list->data; - if (bdrv_parent_perms_conflict(bs, ignore_children, errp)) { + if (bdrv_parent_perms_conflict(bs, errp)) { return -EINVAL; } @@ -2424,7 +2415,7 @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q, ret = bdrv_node_check_perm(bs, q, cumulative_perms, cumulative_shared_perms, - ignore_children, tran, errp); + tran, errp); if (ret < 0) { return ret; } @@ -2435,19 +2426,17 @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q, static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, uint64_t cumulative_perms, - uint64_t cumulative_shared_perms, - GSList *ignore_children, Error **errp) + uint64_t cumulative_shared_perms, Error **errp) { g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); return bdrv_check_perm_common(list, q, true, cumulative_perms, - cumulative_shared_perms, ignore_children, - NULL, errp); + cumulative_shared_perms, NULL, errp); } static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran, Error **errp) { - return bdrv_check_perm_common(list, q, false, 0, 0, NULL, tran, errp); + return bdrv_check_perm_common(list, q, false, 0, 0, tran, errp); } /* @@ -2576,7 +2565,6 @@ char *bdrv_perm_names(uint64_t perm) static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, uint64_t new_used_perm, uint64_t new_shared_perm, - GSList *ignore_children, Error **errp) { BdrvChild *c; @@ -2588,10 +2576,6 @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED); QLIST_FOREACH(c, &bs->parents, next_parent) { - if (g_slist_find(ignore_children, c)) { - continue; - } - if ((new_used_perm & c->shared_perm) != new_used_perm) { char *user = bdrv_child_user_desc(c); char *perm_names = bdrv_perm_names(new_used_perm & ~c->shared_perm); @@ -2621,7 +2605,7 @@ static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, } return bdrv_check_perm(bs, q, cumulative_perms, cumulative_shared_perms, - ignore_children, errp); + errp); } static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp) @@ -4244,7 +4228,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) QTAILQ_FOREACH(bs_entry, bs_queue, entry) { BDRVReopenState *state = &bs_entry->state; ret = bdrv_check_perm(state->bs, bs_queue, state->perm, - state->shared_perm, NULL, errp); + state->shared_perm, errp); if (ret < 0) { goto cleanup_perm; } @@ -4256,7 +4240,7 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) bs_queue, state->perm, state->shared_perm, &nperm, &nshared); ret = bdrv_check_update_perm(state->new_backing_bs, NULL, - nperm, nshared, NULL, errp); + nperm, nshared, errp); if (ret < 0) { goto cleanup_perm; } From 332b3a175f8cbd730cfe0a53a8e52326f8f98b8b Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:54 +0300 Subject: [PATCH 0075/3028] block: make bdrv_unset_inherits_from to be a transaction action To be used in the further commit. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-27-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/block.c b/block.c index 46af5852ab..1dc14908ac 100644 --- a/block.c +++ b/block.c @@ -3205,11 +3205,49 @@ void bdrv_root_unref_child(BdrvChild *child) bdrv_unref(child_bs); } +typedef struct BdrvSetInheritsFrom { + BlockDriverState *bs; + BlockDriverState *old_inherits_from; +} BdrvSetInheritsFrom; + +static void bdrv_set_inherits_from_abort(void *opaque) +{ + BdrvSetInheritsFrom *s = opaque; + + s->bs->inherits_from = s->old_inherits_from; +} + +static TransactionActionDrv bdrv_set_inherits_from_drv = { + .abort = bdrv_set_inherits_from_abort, + .clean = g_free, +}; + +/* @tran is allowed to be NULL. In this case no rollback is possible */ +static void bdrv_set_inherits_from(BlockDriverState *bs, + BlockDriverState *new_inherits_from, + Transaction *tran) +{ + if (tran) { + BdrvSetInheritsFrom *s = g_new(BdrvSetInheritsFrom, 1); + + *s = (BdrvSetInheritsFrom) { + .bs = bs, + .old_inherits_from = bs->inherits_from, + }; + + tran_add(tran, &bdrv_set_inherits_from_drv, s); + } + + bs->inherits_from = new_inherits_from; +} + /** * Clear all inherits_from pointers from children and grandchildren of * @root that point to @root, where necessary. + * @tran is allowed to be NULL. In this case no rollback is possible */ -static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child) +static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child, + Transaction *tran) { BdrvChild *c; @@ -3224,12 +3262,12 @@ static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child) } } if (c == NULL) { - child->bs->inherits_from = NULL; + bdrv_set_inherits_from(child->bs, NULL, tran); } } QLIST_FOREACH(c, &child->bs->children, next) { - bdrv_unset_inherits_from(root, c); + bdrv_unset_inherits_from(root, c, tran); } } @@ -3240,7 +3278,7 @@ void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child) return; } - bdrv_unset_inherits_from(parent, child); + bdrv_unset_inherits_from(parent, child, NULL); bdrv_root_unref_child(child); } From 1e4c797c759dea15a3d426f655532968d3973028 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:55 +0300 Subject: [PATCH 0076/3028] block: make bdrv_refresh_limits() to be a transaction action To be used in further commit. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-28-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 9 ++++----- block/io.c | 31 +++++++++++++++++++++++++++++-- include/block/block.h | 3 ++- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/block.c b/block.c index 1dc14908ac..9922943793 100644 --- a/block.c +++ b/block.c @@ -49,7 +49,6 @@ #include "qemu/timer.h" #include "qemu/cutils.h" #include "qemu/id.h" -#include "qemu/transactions.h" #include "block/coroutines.h" #ifdef CONFIG_BSD @@ -1577,7 +1576,7 @@ static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, return ret; } - bdrv_refresh_limits(bs, &local_err); + bdrv_refresh_limits(bs, NULL, &local_err); if (local_err) { error_propagate(errp, local_err); return -EINVAL; @@ -3363,7 +3362,7 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, } out: - bdrv_refresh_limits(bs, NULL); + bdrv_refresh_limits(bs, NULL, NULL); return ret; } @@ -4847,7 +4846,7 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state) bdrv_set_backing_hd(bs, reopen_state->new_backing_bs, &error_abort); } - bdrv_refresh_limits(bs, NULL); + bdrv_refresh_limits(bs, NULL, NULL); } /* @@ -5244,7 +5243,7 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, out: tran_finalize(tran, ret); - bdrv_refresh_limits(bs_top, NULL); + bdrv_refresh_limits(bs_top, NULL, NULL); return ret; } diff --git a/block/io.c b/block/io.c index ca2dca3007..35b6c56efc 100644 --- a/block/io.c +++ b/block/io.c @@ -133,13 +133,40 @@ static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src) dst->max_iov = MIN_NON_ZERO(dst->max_iov, src->max_iov); } -void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) +typedef struct BdrvRefreshLimitsState { + BlockDriverState *bs; + BlockLimits old_bl; +} BdrvRefreshLimitsState; + +static void bdrv_refresh_limits_abort(void *opaque) +{ + BdrvRefreshLimitsState *s = opaque; + + s->bs->bl = s->old_bl; +} + +static TransactionActionDrv bdrv_refresh_limits_drv = { + .abort = bdrv_refresh_limits_abort, + .clean = g_free, +}; + +/* @tran is allowed to be NULL, in this case no rollback is possible. */ +void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp) { ERRP_GUARD(); BlockDriver *drv = bs->drv; BdrvChild *c; bool have_limits; + if (tran) { + BdrvRefreshLimitsState *s = g_new(BdrvRefreshLimitsState, 1); + *s = (BdrvRefreshLimitsState) { + .bs = bs, + .old_bl = bs->bl, + }; + tran_add(tran, &bdrv_refresh_limits_drv, s); + } + memset(&bs->bl, 0, sizeof(bs->bl)); if (!drv) { @@ -156,7 +183,7 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp) QLIST_FOREACH(c, &bs->children, next) { if (c->role & (BDRV_CHILD_DATA | BDRV_CHILD_FILTERED | BDRV_CHILD_COW)) { - bdrv_refresh_limits(c->bs, errp); + bdrv_refresh_limits(c->bs, tran, errp); if (*errp) { return; } diff --git a/include/block/block.h b/include/block/block.h index 85481a05c6..ad38259c91 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -9,6 +9,7 @@ #include "block/dirty-bitmap.h" #include "block/blockjob.h" #include "qemu/hbitmap.h" +#include "qemu/transactions.h" /* * generated_co_wrapper @@ -421,7 +422,7 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs); BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, BlockDriverState *in_bs, Error **errp); void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); -void bdrv_refresh_limits(BlockDriverState *bs, Error **errp); +void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp); int bdrv_commit(BlockDriverState *bs); int bdrv_make_empty(BdrvChild *c, Error **errp); int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file, From 160333e1fef77ca6d4f7fde8f52bb0a944851104 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:56 +0300 Subject: [PATCH 0077/3028] block: add bdrv_set_backing_noperm() transaction action Split out no-perm part of bdrv_set_backing_hd() as a separate transaction action. Note the in case of existing BdrvChild we reuse it, not recreate, just to do less actions. We don't need to create extra reference to backing_hd as we don't lose it in bdrv_attach_child(). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-29-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 54 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/block.c b/block.c index 9922943793..bdfe59d94d 100644 --- a/block.c +++ b/block.c @@ -92,6 +92,8 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, BdrvChild **child, Transaction *tran, Error **errp); +static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs, + Transaction *tran); static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, Error **errp); @@ -3322,8 +3324,9 @@ static BdrvChildRole bdrv_backing_role(BlockDriverState *bs) * Sets the bs->backing link of a BDS. A new reference is created; callers * which don't need their own reference any more must call bdrv_unref(). */ -int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, - Error **errp) +static int bdrv_set_backing_noperm(BlockDriverState *bs, + BlockDriverState *backing_hd, + Transaction *tran, Error **errp) { int ret = 0; bool update_inherits_from = bdrv_chain_contains(bs, backing_hd) && @@ -3333,36 +3336,53 @@ int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, return -EPERM; } - if (backing_hd) { - bdrv_ref(backing_hd); - } - if (bs->backing) { /* Cannot be frozen, we checked that above */ - bdrv_unref_child(bs, bs->backing); - bs->backing = NULL; + bdrv_unset_inherits_from(bs, bs->backing, tran); + bdrv_remove_filter_or_cow_child(bs, tran); } if (!backing_hd) { goto out; } - bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_of_bds, - bdrv_backing_role(bs), errp); - if (!bs->backing) { - ret = -EPERM; - goto out; + ret = bdrv_attach_child_noperm(bs, backing_hd, "backing", + &child_of_bds, bdrv_backing_role(bs), + &bs->backing, tran, errp); + if (ret < 0) { + return ret; } - /* If backing_hd was already part of bs's backing chain, and + + /* + * If backing_hd was already part of bs's backing chain, and * inherits_from pointed recursively to bs then let's update it to - * point directly to bs (else it will become NULL). */ + * point directly to bs (else it will become NULL). + */ if (update_inherits_from) { - backing_hd->inherits_from = bs; + bdrv_set_inherits_from(backing_hd, bs, tran); } out: - bdrv_refresh_limits(bs, NULL, NULL); + bdrv_refresh_limits(bs, tran, NULL); + + return 0; +} + +int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, + Error **errp) +{ + int ret; + Transaction *tran = tran_new(); + + ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp); + if (ret < 0) { + goto out; + } + + ret = bdrv_refresh_perms(bs, errp); +out: + tran_finalize(tran, ret); return ret; } From a2aabf88958119ec7d3022287eff6bcc924c90a8 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:57 +0300 Subject: [PATCH 0078/3028] block: bdrv_reopen_multiple(): move bdrv_flush to separate pre-prepare During reopen we may add backing bs from other aio context, which may lead to changing original context of top bs. We are going to move graph modification to prepare stage. So, it will be possible that bdrv_flush() in bdrv_reopen_prepare called on bs in non-original aio context, which we didn't aquire which leads to crash. To avoid this problem move bdrv_flush() to be a separate reopen stage before bdrv_reopen_prepare(). This doesn't seem correct to acquire only one aio context and not all contexts participating in reopen. But it's not obvious how to do it correctly, keeping in mind: 1. rules of bdrv_set_aio_context_ignore() that requires new_context lock not being held 2. possible deadlocks because of holding all (or several?) AioContext locks Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-30-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index bdfe59d94d..357ec1be2c 100644 --- a/block.c +++ b/block.c @@ -4274,6 +4274,14 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) assert(bs_queue != NULL); + QTAILQ_FOREACH(bs_entry, bs_queue, entry) { + ret = bdrv_flush(bs_entry->state.bs); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error flushing drive"); + goto cleanup; + } + } + QTAILQ_FOREACH(bs_entry, bs_queue, entry) { assert(bs_entry->state.bs->quiesce_counter > 0); if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, errp)) { @@ -4669,12 +4677,6 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, bdrv_reopen_perm(queue, reopen_state->bs, &reopen_state->perm, &reopen_state->shared_perm); - ret = bdrv_flush(reopen_state->bs); - if (ret) { - error_setg_errno(errp, -ret, "Error flushing drive"); - goto error; - } - if (drv->bdrv_reopen_prepare) { /* * If a driver-specific option is missing, it means that we From 72373e40fbc7e4218061a8211384db362d3e7348 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:58 +0300 Subject: [PATCH 0079/3028] block: bdrv_reopen_multiple: refresh permissions on updated graph Move bdrv_reopen_multiple to new paradigm of permission update: first update graph relations, then do refresh the permissions. We have to modify reopen process in file-posix driver: with new scheme we don't have prepared permissions in raw_reopen_prepare(), so we should reconfigure fd in raw_check_perm(). Still this seems more native and simple anyway. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-31-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 193 +++++++++++++----------------------------- block/file-posix.c | 93 +++++++------------- include/block/block.h | 3 +- 3 files changed, 88 insertions(+), 201 deletions(-) diff --git a/block.c b/block.c index 357ec1be2c..ffaa367a1b 100644 --- a/block.c +++ b/block.c @@ -95,8 +95,9 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs, Transaction *tran); -static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue - *queue, Error **errp); +static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, + BlockReopenQueue *queue, + Transaction *set_backings_tran, Error **errp); static void bdrv_reopen_commit(BDRVReopenState *reopen_state); static void bdrv_reopen_abort(BDRVReopenState *reopen_state); @@ -2468,6 +2469,7 @@ static void bdrv_list_abort_perm_update(GSList *list) } } +__attribute__((unused)) static void bdrv_abort_perm_update(BlockDriverState *bs) { g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); @@ -2563,6 +2565,7 @@ char *bdrv_perm_names(uint64_t perm) * * Needs to be followed by a call to either bdrv_set_perm() or * bdrv_abort_perm_update(). */ +__attribute__((unused)) static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, uint64_t new_used_perm, uint64_t new_shared_perm, @@ -4183,10 +4186,6 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, bs_entry->state.explicit_options = explicit_options; bs_entry->state.flags = flags; - /* This needs to be overwritten in bdrv_reopen_prepare() */ - bs_entry->state.perm = UINT64_MAX; - bs_entry->state.shared_perm = 0; - /* * If keep_old_opts is false then it means that unspecified * options must be reset to their original value. We don't allow @@ -4271,6 +4270,9 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) { int ret = -1; BlockReopenQueueEntry *bs_entry, *next; + Transaction *tran = tran_new(); + g_autoptr(GHashTable) found = NULL; + g_autoptr(GSList) refresh_list = NULL; assert(bs_queue != NULL); @@ -4284,33 +4286,33 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) QTAILQ_FOREACH(bs_entry, bs_queue, entry) { assert(bs_entry->state.bs->quiesce_counter > 0); - if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, errp)) { - goto cleanup; + ret = bdrv_reopen_prepare(&bs_entry->state, bs_queue, tran, errp); + if (ret < 0) { + goto abort; } bs_entry->prepared = true; } + found = g_hash_table_new(NULL, NULL); QTAILQ_FOREACH(bs_entry, bs_queue, entry) { BDRVReopenState *state = &bs_entry->state; - ret = bdrv_check_perm(state->bs, bs_queue, state->perm, - state->shared_perm, errp); - if (ret < 0) { - goto cleanup_perm; + + refresh_list = bdrv_topological_dfs(refresh_list, found, state->bs); + if (state->old_backing_bs) { + refresh_list = bdrv_topological_dfs(refresh_list, found, + state->old_backing_bs); } - /* Check if new_backing_bs would accept the new permissions */ - if (state->replace_backing_bs && state->new_backing_bs) { - uint64_t nperm, nshared; - bdrv_child_perm(state->bs, state->new_backing_bs, - NULL, bdrv_backing_role(state->bs), - bs_queue, state->perm, state->shared_perm, - &nperm, &nshared); - ret = bdrv_check_update_perm(state->new_backing_bs, NULL, - nperm, nshared, errp); - if (ret < 0) { - goto cleanup_perm; - } - } - bs_entry->perms_checked = true; + } + + /* + * Note that file-posix driver rely on permission update done during reopen + * (even if no permission changed), because it wants "new" permissions for + * reconfiguring the fd and that's why it does it in raw_check_perm(), not + * in raw_reopen_prepare() which is called with "old" permissions. + */ + ret = bdrv_list_refresh_perms(refresh_list, bs_queue, tran, errp); + if (ret < 0) { + goto abort; } /* @@ -4326,51 +4328,31 @@ int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp) bdrv_reopen_commit(&bs_entry->state); } + tran_commit(tran); + + QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) { + BlockDriverState *bs = bs_entry->state.bs; + + if (bs->drv->bdrv_reopen_commit_post) { + bs->drv->bdrv_reopen_commit_post(&bs_entry->state); + } + } + ret = 0; -cleanup_perm: + goto cleanup; + +abort: + tran_abort(tran); QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) { - BDRVReopenState *state = &bs_entry->state; - - if (!bs_entry->perms_checked) { - continue; - } - - if (ret == 0) { - uint64_t perm, shared; - - bdrv_get_cumulative_perm(state->bs, &perm, &shared); - assert(perm == state->perm); - assert(shared == state->shared_perm); - - bdrv_set_perm(state->bs); - } else { - bdrv_abort_perm_update(state->bs); - if (state->replace_backing_bs && state->new_backing_bs) { - bdrv_abort_perm_update(state->new_backing_bs); - } + if (bs_entry->prepared) { + bdrv_reopen_abort(&bs_entry->state); } + qobject_unref(bs_entry->state.explicit_options); + qobject_unref(bs_entry->state.options); } - if (ret == 0) { - QTAILQ_FOREACH_REVERSE(bs_entry, bs_queue, entry) { - BlockDriverState *bs = bs_entry->state.bs; - - if (bs->drv->bdrv_reopen_commit_post) - bs->drv->bdrv_reopen_commit_post(&bs_entry->state); - } - } cleanup: QTAILQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) { - if (ret) { - if (bs_entry->prepared) { - bdrv_reopen_abort(&bs_entry->state); - } - qobject_unref(bs_entry->state.explicit_options); - qobject_unref(bs_entry->state.options); - } - if (bs_entry->state.new_backing_bs) { - bdrv_unref(bs_entry->state.new_backing_bs); - } g_free(bs_entry); } g_free(bs_queue); @@ -4395,53 +4377,6 @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only, return ret; } -static BlockReopenQueueEntry *find_parent_in_reopen_queue(BlockReopenQueue *q, - BdrvChild *c) -{ - BlockReopenQueueEntry *entry; - - QTAILQ_FOREACH(entry, q, entry) { - BlockDriverState *bs = entry->state.bs; - BdrvChild *child; - - QLIST_FOREACH(child, &bs->children, next) { - if (child == c) { - return entry; - } - } - } - - return NULL; -} - -static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs, - uint64_t *perm, uint64_t *shared) -{ - BdrvChild *c; - BlockReopenQueueEntry *parent; - uint64_t cumulative_perms = 0; - uint64_t cumulative_shared_perms = BLK_PERM_ALL; - - QLIST_FOREACH(c, &bs->parents, next_parent) { - parent = find_parent_in_reopen_queue(q, c); - if (!parent) { - cumulative_perms |= c->perm; - cumulative_shared_perms &= c->shared_perm; - } else { - uint64_t nperm, nshared; - - bdrv_child_perm(parent->state.bs, bs, c, c->role, q, - parent->state.perm, parent->state.shared_perm, - &nperm, &nshared); - - cumulative_perms |= nperm; - cumulative_shared_perms &= nshared; - } - } - *perm = cumulative_perms; - *shared = cumulative_shared_perms; -} - static bool bdrv_reopen_can_attach(BlockDriverState *parent, BdrvChild *child, BlockDriverState *new_child, @@ -4483,6 +4418,7 @@ static bool bdrv_reopen_can_attach(BlockDriverState *parent, * Return 0 on success, otherwise return < 0 and set @errp. */ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state, + Transaction *set_backings_tran, Error **errp) { BlockDriverState *bs = reopen_state->bs; @@ -4559,6 +4495,8 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state, /* If we want to replace the backing file we need some extra checks */ if (new_backing_bs != bdrv_filter_or_cow_bs(overlay_bs)) { + int ret; + /* Check for implicit nodes between bs and its backing file */ if (bs != overlay_bs) { error_setg(errp, "Cannot change backing link if '%s' has " @@ -4579,9 +4517,11 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state, return -EPERM; } reopen_state->replace_backing_bs = true; - if (new_backing_bs) { - bdrv_ref(new_backing_bs); - reopen_state->new_backing_bs = new_backing_bs; + reopen_state->old_backing_bs = bs->backing ? bs->backing->bs : NULL; + ret = bdrv_set_backing_noperm(bs, new_backing_bs, set_backings_tran, + errp); + if (ret < 0) { + return ret; } } @@ -4606,7 +4546,8 @@ static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state, * */ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, - BlockReopenQueue *queue, Error **errp) + BlockReopenQueue *queue, + Transaction *set_backings_tran, Error **errp) { int ret = -1; int old_flags; @@ -4673,10 +4614,6 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, goto error; } - /* Calculate required permissions after reopening */ - bdrv_reopen_perm(queue, reopen_state->bs, - &reopen_state->perm, &reopen_state->shared_perm); - if (drv->bdrv_reopen_prepare) { /* * If a driver-specific option is missing, it means that we @@ -4730,7 +4667,7 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, * either a reference to an existing node (using its node name) * or NULL to simply detach the current backing file. */ - ret = bdrv_reopen_parse_backing(reopen_state, errp); + ret = bdrv_reopen_parse_backing(reopen_state, set_backings_tran, errp); if (ret < 0) { goto error; } @@ -4852,22 +4789,6 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state) qdict_del(bs->explicit_options, child->name); qdict_del(bs->options, child->name); } - - /* - * Change the backing file if a new one was specified. We do this - * after updating bs->options, so bdrv_refresh_filename() (called - * from bdrv_set_backing_hd()) has the new values. - */ - if (reopen_state->replace_backing_bs) { - BlockDriverState *old_backing_bs = child_bs(bs->backing); - assert(!old_backing_bs || !old_backing_bs->implicit); - /* Abort the permission update on the backing bs we're detaching */ - if (old_backing_bs) { - bdrv_abort_perm_update(old_backing_bs); - } - bdrv_set_backing_hd(bs, reopen_state->new_backing_bs, &error_abort); - } - bdrv_refresh_limits(bs, NULL, NULL); } diff --git a/block/file-posix.c b/block/file-posix.c index 20e14f8e96..10b71d9a13 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -175,7 +175,6 @@ typedef struct BDRVRawState { } BDRVRawState; typedef struct BDRVRawReopenState { - int fd; int open_flags; bool drop_cache; bool check_cache_dropped; @@ -1075,7 +1074,6 @@ static int raw_reopen_prepare(BDRVReopenState *state, BDRVRawReopenState *rs; QemuOpts *opts; int ret; - Error *local_err = NULL; assert(state != NULL); assert(state->bs != NULL); @@ -1101,32 +1099,18 @@ static int raw_reopen_prepare(BDRVReopenState *state, * bdrv_reopen_prepare() will detect changes and complain. */ qemu_opts_to_qdict(opts, state->options); - rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags, - state->perm, true, &local_err); - if (local_err) { - error_propagate(errp, local_err); - ret = -1; - goto out; - } - - /* Fail already reopen_prepare() if we can't get a working O_DIRECT - * alignment with the new fd. */ - if (rs->fd != -1) { - raw_probe_alignment(state->bs, rs->fd, &local_err); - if (local_err) { - error_propagate(errp, local_err); - ret = -EINVAL; - goto out_fd; - } - } + /* + * As part of reopen prepare we also want to create new fd by + * raw_reconfigure_getfd(). But it wants updated "perm", when in + * bdrv_reopen_multiple() .bdrv_reopen_prepare() callback called prior to + * permission update. Happily, permission update is always a part (a seprate + * stage) of bdrv_reopen_multiple() so we can rely on this fact and + * reconfigure fd in raw_check_perm(). + */ s->reopen_state = state; ret = 0; -out_fd: - if (ret < 0) { - qemu_close(rs->fd); - rs->fd = -1; - } + out: qemu_opts_del(opts); return ret; @@ -1140,10 +1124,6 @@ static void raw_reopen_commit(BDRVReopenState *state) s->drop_cache = rs->drop_cache; s->check_cache_dropped = rs->check_cache_dropped; s->open_flags = rs->open_flags; - - qemu_close(s->fd); - s->fd = rs->fd; - g_free(state->opaque); state->opaque = NULL; @@ -1162,10 +1142,6 @@ static void raw_reopen_abort(BDRVReopenState *state) return; } - if (rs->fd >= 0) { - qemu_close(rs->fd); - rs->fd = -1; - } g_free(state->opaque); state->opaque = NULL; @@ -3073,39 +3049,30 @@ static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared, Error **errp) { BDRVRawState *s = bs->opaque; - BDRVRawReopenState *rs = NULL; + int input_flags = s->reopen_state ? s->reopen_state->flags : bs->open_flags; int open_flags; int ret; - if (s->perm_change_fd) { - /* - * In the context of reopen, this function may be called several times - * (directly and recursively while change permissions of the parent). - * This is even true for children that don't inherit from the original - * reopen node, so s->reopen_state is not set. - * - * Ignore all but the first call. - */ - return 0; - } + /* We may need a new fd if auto-read-only switches the mode */ + ret = raw_reconfigure_getfd(bs, input_flags, &open_flags, perm, + false, errp); + if (ret < 0) { + return ret; + } else if (ret != s->fd) { + Error *local_err = NULL; - if (s->reopen_state) { - /* We already have a new file descriptor to set permissions for */ - assert(s->reopen_state->perm == perm); - assert(s->reopen_state->shared_perm == shared); - rs = s->reopen_state->opaque; - s->perm_change_fd = rs->fd; - s->perm_change_flags = rs->open_flags; - } else { - /* We may need a new fd if auto-read-only switches the mode */ - ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags, perm, - false, errp); - if (ret < 0) { - return ret; - } else if (ret != s->fd) { - s->perm_change_fd = ret; - s->perm_change_flags = open_flags; + /* + * Fail already check_perm() if we can't get a working O_DIRECT + * alignment with the new fd. + */ + raw_probe_alignment(bs, ret, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return -EINVAL; } + + s->perm_change_fd = ret; + s->perm_change_flags = open_flags; } /* Prepare permissions on old fd to avoid conflicts between old and new, @@ -3127,7 +3094,7 @@ static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared, return 0; fail: - if (s->perm_change_fd && !s->reopen_state) { + if (s->perm_change_fd) { qemu_close(s->perm_change_fd); } s->perm_change_fd = 0; @@ -3158,7 +3125,7 @@ static void raw_abort_perm_update(BlockDriverState *bs) /* For reopen, .bdrv_reopen_abort is called afterwards and will close * the file descriptor. */ - if (s->perm_change_fd && !s->reopen_state) { + if (s->perm_change_fd) { qemu_close(s->perm_change_fd); } s->perm_change_fd = 0; diff --git a/include/block/block.h b/include/block/block.h index ad38259c91..8d5b3ecebd 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -208,8 +208,7 @@ typedef struct BDRVReopenState { BlockdevDetectZeroesOptions detect_zeroes; bool backing_missing; bool replace_backing_bs; /* new_backing_bs is ignored if this is false */ - BlockDriverState *new_backing_bs; /* If NULL then detach the current bs */ - uint64_t perm, shared_perm; + BlockDriverState *old_backing_bs; /* keep pointer for permissions update */ QDict *options; QDict *explicit_options; void *opaque; From 058acc470825e2df2b971877e1f030a8ac80713f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:17:59 +0300 Subject: [PATCH 0080/3028] block: drop unused permission update functions Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-32-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 103 -------------------------------------------------------- 1 file changed, 103 deletions(-) diff --git a/block.c b/block.c index ffaa367a1b..bf7c187435 100644 --- a/block.c +++ b/block.c @@ -1987,11 +1987,6 @@ static int bdrv_fill_options(QDict **options, const char *filename, return 0; } -static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, - uint64_t new_used_perm, - uint64_t new_shared_perm, - Error **errp); - typedef struct BlockReopenQueueEntry { bool prepared; bool perms_checked; @@ -2426,56 +2421,12 @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q, return 0; } -static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q, - uint64_t cumulative_perms, - uint64_t cumulative_shared_perms, Error **errp) -{ - g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); - return bdrv_check_perm_common(list, q, true, cumulative_perms, - cumulative_shared_perms, NULL, errp); -} - static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran, Error **errp) { return bdrv_check_perm_common(list, q, false, 0, 0, tran, errp); } -/* - * Notifies drivers that after a previous bdrv_check_perm() call, the - * permission update is not performed and any preparations made for it (e.g. - * taken file locks) need to be undone. - */ -static void bdrv_node_abort_perm_update(BlockDriverState *bs) -{ - BlockDriver *drv = bs->drv; - BdrvChild *c; - - if (!drv) { - return; - } - - bdrv_drv_set_perm_abort(bs); - - QLIST_FOREACH(c, &bs->children, next) { - bdrv_child_set_perm_abort(c); - } -} - -static void bdrv_list_abort_perm_update(GSList *list) -{ - for ( ; list; list = list->next) { - bdrv_node_abort_perm_update((BlockDriverState *)list->data); - } -} - -__attribute__((unused)) -static void bdrv_abort_perm_update(BlockDriverState *bs) -{ - g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); - return bdrv_list_abort_perm_update(list); -} - static void bdrv_node_set_perm(BlockDriverState *bs) { BlockDriver *drv = bs->drv; @@ -2557,60 +2508,6 @@ char *bdrv_perm_names(uint64_t perm) return g_string_free(result, FALSE); } -/* - * Checks whether a new reference to @bs can be added if the new user requires - * @new_used_perm/@new_shared_perm as its permissions. If @ignore_children is - * set, the BdrvChild objects in this list are ignored in the calculations; - * this allows checking permission updates for an existing reference. - * - * Needs to be followed by a call to either bdrv_set_perm() or - * bdrv_abort_perm_update(). */ -__attribute__((unused)) -static int bdrv_check_update_perm(BlockDriverState *bs, BlockReopenQueue *q, - uint64_t new_used_perm, - uint64_t new_shared_perm, - Error **errp) -{ - BdrvChild *c; - uint64_t cumulative_perms = new_used_perm; - uint64_t cumulative_shared_perms = new_shared_perm; - - - /* There is no reason why anyone couldn't tolerate write_unchanged */ - assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED); - - QLIST_FOREACH(c, &bs->parents, next_parent) { - if ((new_used_perm & c->shared_perm) != new_used_perm) { - char *user = bdrv_child_user_desc(c); - char *perm_names = bdrv_perm_names(new_used_perm & ~c->shared_perm); - - error_setg(errp, "Conflicts with use by %s as '%s', which does not " - "allow '%s' on %s", - user, c->name, perm_names, bdrv_get_node_name(c->bs)); - g_free(user); - g_free(perm_names); - return -EPERM; - } - - if ((c->perm & new_shared_perm) != c->perm) { - char *user = bdrv_child_user_desc(c); - char *perm_names = bdrv_perm_names(c->perm & ~new_shared_perm); - - error_setg(errp, "Conflicts with use by %s as '%s', which uses " - "'%s' on %s", - user, c->name, perm_names, bdrv_get_node_name(c->bs)); - g_free(user); - g_free(perm_names); - return -EPERM; - } - - cumulative_perms |= c->perm; - cumulative_shared_perms &= c->shared_perm; - } - - return bdrv_check_perm(bs, q, cumulative_perms, cumulative_shared_perms, - errp); -} static int bdrv_refresh_perms(BlockDriverState *bs, Error **errp) { From 25409807cfe3a961c8898b23de9eec61b068c6f8 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:18:00 +0300 Subject: [PATCH 0081/3028] block: inline bdrv_check_perm_common() bdrv_check_perm_common() has only one caller, so no more sense in "common". Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-33-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/block.c b/block.c index bf7c187435..38bd2ea32e 100644 --- a/block.c +++ b/block.c @@ -2373,33 +2373,13 @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q, return 0; } -/* - * If use_cumulative_perms is true, use cumulative_perms and - * cumulative_shared_perms for first element of the list. Otherwise just refresh - * all permissions. - */ -static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q, - bool use_cumulative_perms, - uint64_t cumulative_perms, - uint64_t cumulative_shared_perms, - Transaction *tran, Error **errp) +static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, + Transaction *tran, Error **errp) { int ret; + uint64_t cumulative_perms, cumulative_shared_perms; BlockDriverState *bs; - if (use_cumulative_perms) { - bs = list->data; - - ret = bdrv_node_check_perm(bs, q, cumulative_perms, - cumulative_shared_perms, - tran, errp); - if (ret < 0) { - return ret; - } - - list = list->next; - } - for ( ; list; list = list->next) { bs = list->data; @@ -2421,12 +2401,6 @@ static int bdrv_check_perm_common(GSList *list, BlockReopenQueue *q, return 0; } -static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, - Transaction *tran, Error **errp) -{ - return bdrv_check_perm_common(list, q, false, 0, 0, tran, errp); -} - static void bdrv_node_set_perm(BlockDriverState *bs) { BlockDriver *drv = bs->drv; From 4954aacea03884ff3880cafc0ad1eef435fdf73e Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:18:01 +0300 Subject: [PATCH 0082/3028] block: inline bdrv_replace_child() bdrv_replace_child() has only one caller, the second argument is unused. Inline it now. This triggers deletion of some more unused interfaces. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-34-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 101 ++++++++++---------------------------------------------- 1 file changed, 18 insertions(+), 83 deletions(-) diff --git a/block.c b/block.c index 38bd2ea32e..2362c934a4 100644 --- a/block.c +++ b/block.c @@ -2401,42 +2401,6 @@ static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, return 0; } -static void bdrv_node_set_perm(BlockDriverState *bs) -{ - BlockDriver *drv = bs->drv; - BdrvChild *c; - - if (!drv) { - return; - } - - bdrv_drv_set_perm_commit(bs); - - /* Drivers that never have children can omit .bdrv_child_perm() */ - if (!drv->bdrv_child_perm) { - assert(QLIST_EMPTY(&bs->children)); - return; - } - - /* Update all children */ - QLIST_FOREACH(c, &bs->children, next) { - bdrv_child_set_perm_commit(c); - } -} - -static void bdrv_list_set_perm(GSList *list) -{ - for ( ; list; list = list->next) { - bdrv_node_set_perm((BlockDriverState *)list->data); - } -} - -static void bdrv_set_perm(BlockDriverState *bs) -{ - g_autoptr(GSList) list = bdrv_topological_dfs(NULL, NULL, bs); - return bdrv_list_set_perm(list); -} - void bdrv_get_cumulative_perm(BlockDriverState *bs, uint64_t *perm, uint64_t *shared_perm) { @@ -2776,52 +2740,6 @@ static void bdrv_replace_child_noperm(BdrvChild *child, } } -/* - * Updates @child to change its reference to point to @new_bs, including - * checking and applying the necessary permission updates both to the old node - * and to @new_bs. - * - * NULL is passed as @new_bs for removing the reference before freeing @child. - * - * If @new_bs is not NULL, bdrv_check_perm() must be called beforehand, as this - * function uses bdrv_set_perm() to update the permissions according to the new - * reference that @new_bs gets. - * - * Callers must ensure that child->frozen is false. - */ -static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs) -{ - BlockDriverState *old_bs = child->bs; - - /* Asserts that child->frozen == false */ - bdrv_replace_child_noperm(child, new_bs); - - /* - * Start with the new node's permissions. If @new_bs is a (direct - * or indirect) child of @old_bs, we must complete the permission - * update on @new_bs before we loosen the restrictions on @old_bs. - * Otherwise, bdrv_check_perm() on @old_bs would re-initiate - * updating the permissions of @new_bs, and thus not purely loosen - * restrictions. - */ - if (new_bs) { - bdrv_set_perm(new_bs); - } - - if (old_bs) { - /* - * Update permissions for old node. We're just taking a parent away, so - * we're loosening restrictions. Errors of permission update are not - * fatal in this case, ignore them. - */ - bdrv_refresh_perms(old_bs, NULL); - - /* When the parent requiring a non-default AioContext is removed, the - * node moves back to the main AioContext */ - bdrv_try_set_aio_context(old_bs, qemu_get_aio_context(), NULL); - } -} - static void bdrv_child_free(void *opaque) { BdrvChild *c = opaque; @@ -2989,8 +2907,25 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs, static void bdrv_detach_child(BdrvChild *child) { - bdrv_replace_child(child, NULL); + BlockDriverState *old_bs = child->bs; + + bdrv_replace_child_noperm(child, NULL); bdrv_remove_empty_child(child); + + if (old_bs) { + /* + * Update permissions for old node. We're just taking a parent away, so + * we're loosening restrictions. Errors of permission update are not + * fatal in this case, ignore them. + */ + bdrv_refresh_perms(old_bs, NULL); + + /* + * When the parent requiring a non-default AioContext is removed, the + * node moves back to the main AioContext + */ + bdrv_try_set_aio_context(old_bs, qemu_get_aio_context(), NULL); + } } /* From ecb776bd93ae07299a109bb2c9d4dea7c5dc90dd Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:18:02 +0300 Subject: [PATCH 0083/3028] block: refactor bdrv_child_set_perm_safe() transaction action Old interfaces dropped, nobody directly calls bdrv_child_set_perm_abort() and bdrv_child_set_perm_commit(), so we can use personal state structure for the action and stop exploiting BdrvChild structure. Also, drop "_safe" suffix which is redundant now. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-35-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 63 ++++++++++++++------------------------- include/block/block_int.h | 5 ---- 2 files changed, 22 insertions(+), 46 deletions(-) diff --git a/block.c b/block.c index 2362c934a4..7b2a8844f6 100644 --- a/block.c +++ b/block.c @@ -2135,59 +2135,40 @@ static GSList *bdrv_topological_dfs(GSList *list, GHashTable *found, return g_slist_prepend(list, bs); } -static void bdrv_child_set_perm_commit(void *opaque) -{ - BdrvChild *c = opaque; - - c->has_backup_perm = false; -} +typedef struct BdrvChildSetPermState { + BdrvChild *child; + uint64_t old_perm; + uint64_t old_shared_perm; +} BdrvChildSetPermState; static void bdrv_child_set_perm_abort(void *opaque) { - BdrvChild *c = opaque; - /* - * We may have child->has_backup_perm unset at this point, as in case of - * _check_ stage of permission update failure we may _check_ not the whole - * subtree. Still, _abort_ is called on the whole subtree anyway. - */ - if (c->has_backup_perm) { - c->perm = c->backup_perm; - c->shared_perm = c->backup_shared_perm; - c->has_backup_perm = false; - } + BdrvChildSetPermState *s = opaque; + + s->child->perm = s->old_perm; + s->child->shared_perm = s->old_shared_perm; } static TransactionActionDrv bdrv_child_set_pem_drv = { .abort = bdrv_child_set_perm_abort, - .commit = bdrv_child_set_perm_commit, + .clean = g_free, }; -/* - * With tran=NULL needs to be followed by direct call to either - * bdrv_child_set_perm_commit() or bdrv_child_set_perm_abort(). - * - * With non-NULL tran needs to be followed by tran_abort() or tran_commit() - * instead. - */ -static void bdrv_child_set_perm_safe(BdrvChild *c, uint64_t perm, - uint64_t shared, Transaction *tran) +static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, + uint64_t shared, Transaction *tran) { - if (!c->has_backup_perm) { - c->has_backup_perm = true; - c->backup_perm = c->perm; - c->backup_shared_perm = c->shared_perm; - } - /* - * Note: it's OK if c->has_backup_perm was already set, as we can find the - * same c twice during check_perm procedure - */ + BdrvChildSetPermState *s = g_new(BdrvChildSetPermState, 1); + + *s = (BdrvChildSetPermState) { + .child = c, + .old_perm = c->perm, + .old_shared_perm = c->shared_perm, + }; c->perm = perm; c->shared_perm = shared; - if (tran) { - tran_add(tran, &bdrv_child_set_pem_drv, c); - } + tran_add(tran, &bdrv_child_set_pem_drv, s); } static void bdrv_drv_set_perm_commit(void *opaque) @@ -2367,7 +2348,7 @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q, bdrv_child_perm(bs, c->bs, c, c->role, q, cumulative_perms, cumulative_shared_perms, &cur_perm, &cur_shared); - bdrv_child_set_perm_safe(c, cur_perm, cur_shared, tran); + bdrv_child_set_perm(c, cur_perm, cur_shared, tran); } return 0; @@ -2466,7 +2447,7 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, Transaction *tran = tran_new(); int ret; - bdrv_child_set_perm_safe(c, perm, shared, tran); + bdrv_child_set_perm(c, perm, shared, tran); ret = bdrv_refresh_perms(c->bs, &local_err); diff --git a/include/block/block_int.h b/include/block/block_int.h index dd2de6bd1d..c823f5b1b3 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -813,11 +813,6 @@ struct BdrvChild { */ uint64_t shared_perm; - /* backup of permissions during permission update procedure */ - bool has_backup_perm; - uint64_t backup_perm; - uint64_t backup_shared_perm; - /* * This link is frozen: the child can neither be replaced nor * detached from the parent. From 2fe5ff56f130aa9b07ebcd749831cea31757c120 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:18:03 +0300 Subject: [PATCH 0084/3028] block: rename bdrv_replace_child_safe() to bdrv_replace_child() We don't have bdrv_replace_child(), so it's time for bdrv_replace_child_safe() to take its place. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-36-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/block.c b/block.c index 7b2a8844f6..df8fa6003c 100644 --- a/block.c +++ b/block.c @@ -2248,12 +2248,12 @@ static TransactionActionDrv bdrv_replace_child_drv = { }; /* - * bdrv_replace_child_safe + * bdrv_replace_child * * Note: real unref of old_bs is done only on commit. */ -static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs, - Transaction *tran) +static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs, + Transaction *tran) { BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1); *s = (BdrvReplaceChildState) { @@ -4803,7 +4803,7 @@ static void bdrv_remove_filter_or_cow_child(BlockDriverState *bs, } if (child->bs) { - bdrv_replace_child_safe(child, NULL, tran); + bdrv_replace_child(child, NULL, tran); } s = g_new(BdrvRemoveFilterOrCowChild, 1); @@ -4843,7 +4843,7 @@ static int bdrv_replace_node_noperm(BlockDriverState *from, c->name, from->node_name); return -EPERM; } - bdrv_replace_child_safe(c, to, tran); + bdrv_replace_child(c, to, tran); } return 0; From c20555e15fdb84172254dbbde393f07ee0f44af3 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 28 Apr 2021 18:18:04 +0300 Subject: [PATCH 0085/3028] block: refactor bdrv_node_check_perm() Now, bdrv_node_check_perm() is called only with fresh cumulative permissions, so its actually "refresh_perm". Move permission calculation to the function. Also, drop unreachable error message and rewrite the remaining one to be more generic (as now we don't know which node is added and which was already here). Add also Virtuozzo copyright, as big work is done at this point. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Kevin Wolf Message-Id: <20210428151804.439460-37-vsementsov@virtuozzo.com> Signed-off-by: Kevin Wolf --- block.c | 38 +++++++++++--------------------------- tests/qemu-iotests/245 | 2 +- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/block.c b/block.c index df8fa6003c..874c22c43e 100644 --- a/block.c +++ b/block.c @@ -2,6 +2,7 @@ * QEMU System Emulator block driver * * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2020 Virtuozzo International GmbH. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -2270,22 +2271,18 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs, } /* - * Check whether permissions on this node can be changed in a way that - * @cumulative_perms and @cumulative_shared_perms are the new cumulative - * permissions of all its parents. This involves checking whether all necessary - * permission changes to child nodes can be performed. - * - * A call to this function must always be followed by a call to bdrv_set_perm() - * or bdrv_abort_perm_update(). + * Refresh permissions in @bs subtree. The function is intended to be called + * after some graph modification that was done without permission update. */ -static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q, - uint64_t cumulative_perms, - uint64_t cumulative_shared_perms, - Transaction *tran, Error **errp) +static int bdrv_node_refresh_perm(BlockDriverState *bs, BlockReopenQueue *q, + Transaction *tran, Error **errp) { BlockDriver *drv = bs->drv; BdrvChild *c; int ret; + uint64_t cumulative_perms, cumulative_shared_perms; + + bdrv_get_cumulative_perm(bs, &cumulative_perms, &cumulative_shared_perms); /* Write permissions never work with read-only images */ if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) && @@ -2294,15 +2291,8 @@ static int bdrv_node_check_perm(BlockDriverState *bs, BlockReopenQueue *q, if (!bdrv_is_writable_after_reopen(bs, NULL)) { error_setg(errp, "Block node is read-only"); } else { - uint64_t current_perms, current_shared; - bdrv_get_cumulative_perm(bs, ¤t_perms, ¤t_shared); - if (current_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) { - error_setg(errp, "Cannot make block node read-only, there is " - "a writer on it"); - } else { - error_setg(errp, "Cannot make block node read-only and create " - "a writer on it"); - } + error_setg(errp, "Read-only block node '%s' cannot support " + "read-write users", bdrv_get_node_name(bs)); } return -EPERM; @@ -2358,7 +2348,6 @@ static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, Transaction *tran, Error **errp) { int ret; - uint64_t cumulative_perms, cumulative_shared_perms; BlockDriverState *bs; for ( ; list; list = list->next) { @@ -2368,12 +2357,7 @@ static int bdrv_list_refresh_perms(GSList *list, BlockReopenQueue *q, return -EINVAL; } - bdrv_get_cumulative_perm(bs, &cumulative_perms, - &cumulative_shared_perms); - - ret = bdrv_node_check_perm(bs, q, cumulative_perms, - cumulative_shared_perms, - tran, errp); + ret = bdrv_node_refresh_perm(bs, q, tran, errp); if (ret < 0) { return ret; } diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245 index 11104b9208..fc5297e268 100755 --- a/tests/qemu-iotests/245 +++ b/tests/qemu-iotests/245 @@ -905,7 +905,7 @@ class TestBlockdevReopen(iotests.QMPTestCase): # We can't reopen hd1 to read-only, as block-stream requires it to be # read-write self.reopen(opts['backing'], {'read-only': True}, - "Cannot make block node read-only, there is a writer on it") + "Read-only block node 'hd1' cannot support read-write users") # We can't remove hd2 while the stream job is ongoing opts['backing']['backing'] = None From 35b7f4abd5afe159f91ddeb4f2a40c20d2f48367 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 22 Apr 2021 18:43:43 +0200 Subject: [PATCH 0086/3028] block: Add BDRV_O_NO_SHARE for blk_new_open() Normally, blk_new_open() just shares all permissions. This was fine originally when permissions only protected against uses in the same process because no other part of the code would actually get to access the block nodes opened with blk_new_open(). However, since we use it for file locking now, unsharing permissions becomes desirable. Add a new BDRV_O_NO_SHARE flag that is used in blk_new_open() to unshare any permissions that can be unshared. Signed-off-by: Kevin Wolf Message-Id: <20210422164344.283389-2-kwolf@redhat.com> Reviewed-by: Eric Blake Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- block/block-backend.c | 19 +++++++++++++------ include/block/block.h | 1 + 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index e4892fd6a5..6fca9853e1 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -407,15 +407,19 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, BlockBackend *blk; BlockDriverState *bs; uint64_t perm = 0; + uint64_t shared = BLK_PERM_ALL; - /* blk_new_open() is mainly used in .bdrv_create implementations and the - * tools where sharing isn't a concern because the BDS stays private, so we - * just request permission according to the flags. + /* + * blk_new_open() is mainly used in .bdrv_create implementations and the + * tools where sharing isn't a major concern because the BDS stays private + * and the file is generally not supposed to be used by a second process, + * so we just request permission according to the flags. * * The exceptions are xen_disk and blockdev_init(); in these cases, the * caller of blk_new_open() doesn't make use of the permissions, but they * shouldn't hurt either. We can still share everything here because the - * guest devices will add their own blockers if they can't share. */ + * guest devices will add their own blockers if they can't share. + */ if ((flags & BDRV_O_NO_IO) == 0) { perm |= BLK_PERM_CONSISTENT_READ; if (flags & BDRV_O_RDWR) { @@ -425,8 +429,11 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, if (flags & BDRV_O_RESIZE) { perm |= BLK_PERM_RESIZE; } + if (flags & BDRV_O_NO_SHARE) { + shared = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED; + } - blk = blk_new(qemu_get_aio_context(), perm, BLK_PERM_ALL); + blk = blk_new(qemu_get_aio_context(), perm, shared); bs = bdrv_open(filename, reference, options, flags, errp); if (!bs) { blk_unref(blk); @@ -435,7 +442,7 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, blk->root = bdrv_root_attach_child(bs, "root", &child_root, BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, - perm, BLK_PERM_ALL, blk, errp); + perm, shared, blk, errp); if (!blk->root) { blk_unref(blk); return NULL; diff --git a/include/block/block.h b/include/block/block.h index 8d5b3ecebd..82185965ff 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -102,6 +102,7 @@ typedef struct HDGeometry { uint32_t cylinders; } HDGeometry; +#define BDRV_O_NO_SHARE 0x0001 /* don't share permissions */ #define BDRV_O_RDWR 0x0002 #define BDRV_O_RESIZE 0x0004 /* request permission for resizing the node */ #define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */ From 0b8fb55ce6398d7277b5ba0f19e39ec30a058191 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 22 Apr 2021 18:43:44 +0200 Subject: [PATCH 0087/3028] qemu-img convert: Unshare write permission for source For a successful conversion of an image, we must make sure that its content doesn't change during the conversion. A special case of this is using the same image file both as the source and as the destination. If both input and output format are raw, the operation would just be useless work, with other formats it is a sure way to destroy the image. This will now fail because the image file can't be opened a second time for the output when opening it for the input has already acquired file locks to unshare BLK_PERM_WRITE. Nevertheless, if there is some reason in a special case why it is actually okay to allow writes to the image while it is being converted, -U can still be used to force sharing all permissions. Note that for most image formats, BLK_PERM_WRITE would already be unshared by the format driver, so this only really makes a difference for raw source images (but any output format). Reported-by: Xueqiang Wei Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Message-Id: <20210422164344.283389-3-kwolf@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Kevin Wolf --- qemu-img.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-img.c b/qemu-img.c index babb5573ab..a5993682aa 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2146,7 +2146,7 @@ static void set_rate_limit(BlockBackend *blk, int64_t rate_limit) static int img_convert(int argc, char **argv) { - int c, bs_i, flags, src_flags = 0; + int c, bs_i, flags, src_flags = BDRV_O_NO_SHARE; const char *fmt = NULL, *out_fmt = NULL, *cache = "unsafe", *src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL, *out_filename, *out_baseimg_param, *snapshot_name = NULL; From 68bf7336533faa6aa90fdd4558edddbf5d8ef814 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 13 Apr 2021 18:56:54 +0200 Subject: [PATCH 0088/3028] vhost-user-blk: Fail gracefully on too large queue size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit virtio_add_queue() aborts when queue_size > VIRTQUEUE_MAX_SIZE, so vhost_user_blk_device_realize() should check this before calling it. Simple reproducer: qemu-system-x86_64 \ -chardev null,id=foo \ -device vhost-user-blk-pci,queue-size=4096,chardev=foo Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1935014 Signed-off-by: Kevin Wolf Message-Id: <20210413165654.50810-1-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Reviewed-by: Raphael Norwitz Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- hw/block/vhost-user-blk.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 0b5b9d44cd..f5e9682703 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -467,6 +467,11 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) error_setg(errp, "vhost-user-blk: queue size must be non-zero"); return; } + if (s->queue_size > VIRTQUEUE_MAX_SIZE) { + error_setg(errp, "vhost-user-blk: queue size must not exceed %d", + VIRTQUEUE_MAX_SIZE); + return; + } if (!vhost_user_init(&s->vhost_user, &s->chardev, errp)) { return; From d0a263cdd019116565682896d115ecd662515f78 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:16 -0400 Subject: [PATCH 0089/3028] qapi/expr: Comment cleanup The linter yaps after 0825f62c842. Fix this trivial issue to restore the linter baseline. (Yes, ideally -- and soon -- the linter will be part of CI so we don't clutter up the log with fixups. For now, though, the baseline is useful for testing intermediate commits as types are added to the QAPI library.) Signed-off-by: John Snow Message-Id: <20210421182032.3521476-2-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 540b3982b1..c207481f7e 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -241,7 +241,7 @@ def check_enum(expr, info): source = "%s '%s'" % (source, member_name) # Enum members may start with a digit if member_name[0].isdigit(): - member_name = 'd' + member_name # Hack: hide the digit + member_name = 'd' + member_name # Hack: hide the digit check_name_lower(member_name, info, source, permit_upper=permissive, permit_underscore=permissive) From b7341b89c9c0212fef7b38b04ffaf39ea73bfca9 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:17 -0400 Subject: [PATCH 0090/3028] qapi/expr.py: Remove 'info' argument from nested check_if_str The function can just use the argument from the scope above. Otherwise, we get shadowed argument errors because the parameter name clashes with the name of a variable already in-scope. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Message-Id: <20210421182032.3521476-3-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index c207481f7e..3fda5d5082 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -122,7 +122,7 @@ def check_flags(expr, info): def check_if(expr, info, source): - def check_if_str(ifcond, info): + def check_if_str(ifcond): if not isinstance(ifcond, str): raise QAPISemError( info, @@ -142,9 +142,9 @@ def check_if(expr, info, source): raise QAPISemError( info, "'if' condition [] of %s is useless" % source) for elt in ifcond: - check_if_str(elt, info) + check_if_str(elt) else: - check_if_str(ifcond, info) + check_if_str(ifcond) expr['if'] = [ifcond] From 0f231dcf2921fa8bc475d222a8ef81e67d4019e8 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:18 -0400 Subject: [PATCH 0091/3028] qapi/expr.py: Check for dict instead of OrderedDict OrderedDict is a subtype of dict, so we can check for a more general form. These functions do not themselves depend on it being any particular type. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Message-Id: <20210421182032.3521476-4-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 3fda5d5082..b4bbcd54c0 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -14,7 +14,6 @@ # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. -from collections import OrderedDict import re from .common import c_name @@ -149,7 +148,7 @@ def check_if(expr, info, source): def normalize_members(members): - if isinstance(members, OrderedDict): + if isinstance(members, dict): for key, arg in members.items(): if isinstance(arg, dict): continue @@ -180,7 +179,7 @@ def check_type(value, info, source, if not allow_dict: raise QAPISemError(info, "%s should be a type name" % source) - if not isinstance(value, OrderedDict): + if not isinstance(value, dict): raise QAPISemError(info, "%s should be an object or type name" % source) From 59b5556ce8c1d3dc1f2c6445ca32f2e515114a8e Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:19 -0400 Subject: [PATCH 0092/3028] qapi/expr.py: constrain incoming expression types mypy does not know the types of values stored in Dicts that masquerade as objects. Help the type checker out by constraining the type. Signed-off-by: John Snow Message-Id: <20210421182032.3521476-5-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index b4bbcd54c0..06a0081001 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -15,9 +15,20 @@ # See the COPYING file in the top-level directory. import re +from typing import Dict, Optional from .common import c_name from .error import QAPISemError +from .parser import QAPIDoc +from .source import QAPISourceInfo + + +# Deserialized JSON objects as returned by the parser. +# The values of this mapping are not necessary to exhaustively type +# here (and also not practical as long as mypy lacks recursive +# types), because the purpose of this module is to interrogate that +# type. +_JSONObject = Dict[str, object] # Names consist of letters, digits, -, and _, starting with a letter. @@ -315,9 +326,20 @@ def check_event(expr, info): def check_exprs(exprs): for expr_elem in exprs: - expr = expr_elem['expr'] - info = expr_elem['info'] - doc = expr_elem.get('doc') + # Expression + assert isinstance(expr_elem['expr'], dict) + for key in expr_elem['expr'].keys(): + assert isinstance(key, str) + expr: _JSONObject = expr_elem['expr'] + + # QAPISourceInfo + assert isinstance(expr_elem['info'], QAPISourceInfo) + info: QAPISourceInfo = expr_elem['info'] + + # Optional[QAPIDoc] + tmp = expr_elem.get('doc') + assert tmp is None or isinstance(tmp, QAPIDoc) + doc: Optional[QAPIDoc] = tmp if 'include' in expr: continue From b66c62a2d3318c5d968d5b95428efb74ca5d5702 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:20 -0400 Subject: [PATCH 0093/3028] qapi/expr.py: Add assertion for union type 'check_dict' mypy isn't fond of allowing you to check for bool membership in a collection of str elements. Guard this lookup for precisely when we were given a name. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Message-Id: <20210421182032.3521476-6-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 06a0081001..3ab78a555d 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -194,7 +194,9 @@ def check_type(value, info, source, raise QAPISemError(info, "%s should be an object or type name" % source) - permissive = allow_dict in info.pragma.member_name_exceptions + permissive = False + if isinstance(allow_dict, str): + permissive = allow_dict in info.pragma.member_name_exceptions # value is a dictionary, check that each member is okay for (key, arg) in value.items(): From 926bb8add7c549496c612fcd4a32f3cf37883c2a Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:21 -0400 Subject: [PATCH 0094/3028] qapi/expr.py: move string check upwards in check_type For readability purposes only, shimmy the early return upwards to the top of the function, so cases proceed in order from least to most complex. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Message-Id: <20210421182032.3521476-7-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 3ab78a555d..c0d18dcc01 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -171,6 +171,10 @@ def check_type(value, info, source, if value is None: return + # Type name + if isinstance(value, str): + return + # Array type if isinstance(value, list): if not allow_array: @@ -181,10 +185,6 @@ def check_type(value, info, source, source) return - # Type name - if isinstance(value, str): - return - # Anonymous type if not allow_dict: From 4918bb7defbdcb1e27cc2adf4e1604486d778ece Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:22 -0400 Subject: [PATCH 0095/3028] qapi/expr.py: Check type of union and alternate 'data' member Prior to this commit, specifying a non-object value here causes the QAPI parser to crash in expr.py with a stack trace with (likely) an AttributeError when we attempt to call that value's items() method. This member needs to be an object (Dict), and not anything else. Add a check for this with a nicer error message, and formalize that check with new test cases that exercise that error. Signed-off-by: John Snow Message-Id: <20210421182032.3521476-8-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 7 +++++++ tests/qapi-schema/alternate-data-invalid.err | 2 ++ tests/qapi-schema/alternate-data-invalid.json | 4 ++++ tests/qapi-schema/alternate-data-invalid.out | 0 tests/qapi-schema/meson.build | 2 ++ tests/qapi-schema/union-invalid-data.err | 2 ++ tests/qapi-schema/union-invalid-data.json | 6 ++++++ tests/qapi-schema/union-invalid-data.out | 0 8 files changed, 23 insertions(+) create mode 100644 tests/qapi-schema/alternate-data-invalid.err create mode 100644 tests/qapi-schema/alternate-data-invalid.json create mode 100644 tests/qapi-schema/alternate-data-invalid.out create mode 100644 tests/qapi-schema/union-invalid-data.err create mode 100644 tests/qapi-schema/union-invalid-data.json create mode 100644 tests/qapi-schema/union-invalid-data.out diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index c0d18dcc01..03624bdf3f 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -283,6 +283,9 @@ def check_union(expr, info): raise QAPISemError(info, "'discriminator' requires 'base'") check_name_is_str(discriminator, info, "'discriminator'") + if not isinstance(members, dict): + raise QAPISemError(info, "'data' must be an object") + for (key, value) in members.items(): source = "'data' member '%s'" % key if discriminator is None: @@ -298,6 +301,10 @@ def check_alternate(expr, info): if not members: raise QAPISemError(info, "'data' must not be empty") + + if not isinstance(members, dict): + raise QAPISemError(info, "'data' must be an object") + for (key, value) in members.items(): source = "'data' member '%s'" % key check_name_lower(key, info, source) diff --git a/tests/qapi-schema/alternate-data-invalid.err b/tests/qapi-schema/alternate-data-invalid.err new file mode 100644 index 0000000000..55f1033aef --- /dev/null +++ b/tests/qapi-schema/alternate-data-invalid.err @@ -0,0 +1,2 @@ +alternate-data-invalid.json: In alternate 'Alt': +alternate-data-invalid.json:2: 'data' must be an object diff --git a/tests/qapi-schema/alternate-data-invalid.json b/tests/qapi-schema/alternate-data-invalid.json new file mode 100644 index 0000000000..7d5d905581 --- /dev/null +++ b/tests/qapi-schema/alternate-data-invalid.json @@ -0,0 +1,4 @@ +# Alternate type requires an object for 'data' +{ 'alternate': 'Alt', + 'data': ['rubbish', 'nonsense'] +} diff --git a/tests/qapi-schema/alternate-data-invalid.out b/tests/qapi-schema/alternate-data-invalid.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index 8ba6917132..d7163e6601 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -14,6 +14,7 @@ schemas = [ 'alternate-conflict-string.json', 'alternate-conflict-bool-string.json', 'alternate-conflict-num-string.json', + 'alternate-data-invalid.json', 'alternate-empty.json', 'alternate-invalid-dict.json', 'alternate-nested.json', @@ -192,6 +193,7 @@ schemas = [ 'union-clash-branches.json', 'union-empty.json', 'union-invalid-base.json', + 'union-invalid-data.json', 'union-optional-branch.json', 'union-unknown.json', 'unknown-escape.json', diff --git a/tests/qapi-schema/union-invalid-data.err b/tests/qapi-schema/union-invalid-data.err new file mode 100644 index 0000000000..e26cf769a3 --- /dev/null +++ b/tests/qapi-schema/union-invalid-data.err @@ -0,0 +1,2 @@ +union-invalid-data.json: In union 'TestUnion': +union-invalid-data.json:2: 'data' must be an object diff --git a/tests/qapi-schema/union-invalid-data.json b/tests/qapi-schema/union-invalid-data.json new file mode 100644 index 0000000000..395ba24d39 --- /dev/null +++ b/tests/qapi-schema/union-invalid-data.json @@ -0,0 +1,6 @@ +# the union data type must be an object. +{ 'union': 'TestUnion', + 'base': 'int', + 'discriminator': 'int', + 'data': ['rubbish', 'nonsense'] +} diff --git a/tests/qapi-schema/union-invalid-data.out b/tests/qapi-schema/union-invalid-data.out new file mode 100644 index 0000000000..e69de29bb2 From 7a783ce5b5a3ac4762b866e22370dd4fb30b91bf Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:23 -0400 Subject: [PATCH 0096/3028] qapi/expr.py: Add casts in a few select cases Casts are instructions to the type checker only, they aren't "safe" and should probably be avoided in general. In this case, when we perform type checking on a nested structure, the type of each field does not "stick". (See PEP 647 for an example of "type narrowing" that does "stick". It is available in Python 3.10, so we can't use it yet.) We don't need to assert that something is a str if we've already checked or asserted that it is -- use a cast instead for these cases. Signed-off-by: John Snow Message-Id: <20210421182032.3521476-9-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 03624bdf3f..f3a4a8536e 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -15,7 +15,7 @@ # See the COPYING file in the top-level directory. import re -from typing import Dict, Optional +from typing import Dict, Optional, cast from .common import c_name from .error import QAPISemError @@ -261,7 +261,7 @@ def check_enum(expr, info): def check_struct(expr, info): - name = expr['struct'] + name = cast(str, expr['struct']) # Checked in check_exprs members = expr['data'] check_type(members, info, "'data'", allow_dict=name) @@ -269,7 +269,7 @@ def check_struct(expr, info): def check_union(expr, info): - name = expr['union'] + name = cast(str, expr['union']) # Checked in check_exprs base = expr.get('base') discriminator = expr.get('discriminator') members = expr['data'] @@ -368,8 +368,8 @@ def check_exprs(exprs): else: raise QAPISemError(info, "expression is missing metatype") - name = expr[meta] - check_name_is_str(name, info, "'%s'" % meta) + check_name_is_str(expr[meta], info, "'%s'" % meta) + name = cast(str, expr[meta]) info.set_defn(meta, name) check_defn_name_str(name, info, meta) From 538cd41065ae5e506a1a07e866b1fd40b4b53d07 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:24 -0400 Subject: [PATCH 0097/3028] qapi/expr.py: Modify check_keys to accept any Collection This is a minor adjustment that lets parameters @required and @optional take tuple arguments, in particular (). Later patches will make use of that. (Iterable would also have worked, but Iterable also includes things like generator expressions which are consumed upon iteration, which would require a rewrite to make sure that each input was only traversed once. Collection implies the "can re-iterate" property.) Signed-off-by: John Snow Message-Id: <20210421182032.3521476-10-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index f3a4a8536e..396c8126d6 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -102,7 +102,7 @@ def check_keys(value, info, source, required, optional): "%s misses key%s %s" % (source, 's' if len(missing) > 1 else '', pprint(missing))) - allowed = set(required + optional) + allowed = set(required) | set(optional) unknown = set(value) - allowed if unknown: raise QAPISemError( From b9ad358aa057e83f8039a1e222d6941d2bf1f70a Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:25 -0400 Subject: [PATCH 0098/3028] qapi/expr.py: add type hint annotations Annotations do not change runtime behavior. This commit *only* adds annotations. Signed-off-by: John Snow Message-Id: <20210421182032.3521476-11-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 68 +++++++++++++++++++++++++++---------------- scripts/qapi/mypy.ini | 5 ---- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 396c8126d6..4ebed4c488 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -15,7 +15,15 @@ # See the COPYING file in the top-level directory. import re -from typing import Dict, Optional, cast +from typing import ( + Collection, + Dict, + Iterable, + List, + Optional, + Union, + cast, +) from .common import c_name from .error import QAPISemError @@ -39,12 +47,14 @@ valid_name = re.compile(r'(__[a-z0-9.-]+_)?' r'([a-z][a-z0-9_-]*)$', re.IGNORECASE) -def check_name_is_str(name, info, source): +def check_name_is_str(name: object, + info: QAPISourceInfo, + source: str) -> None: if not isinstance(name, str): raise QAPISemError(info, "%s requires a string name" % source) -def check_name_str(name, info, source): +def check_name_str(name: str, info: QAPISourceInfo, source: str) -> str: # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty' # and 'q_obj_*' implicit type names. match = valid_name.match(name) @@ -53,16 +63,16 @@ def check_name_str(name, info, source): return match.group(3) -def check_name_upper(name, info, source): +def check_name_upper(name: str, info: QAPISourceInfo, source: str) -> None: stem = check_name_str(name, info, source) if re.search(r'[a-z-]', stem): raise QAPISemError( info, "name of %s must not use lowercase or '-'" % source) -def check_name_lower(name, info, source, - permit_upper=False, - permit_underscore=False): +def check_name_lower(name: str, info: QAPISourceInfo, source: str, + permit_upper: bool = False, + permit_underscore: bool = False) -> None: stem = check_name_str(name, info, source) if ((not permit_upper and re.search(r'[A-Z]', stem)) or (not permit_underscore and '_' in stem)): @@ -70,13 +80,13 @@ def check_name_lower(name, info, source, info, "name of %s must not use uppercase or '_'" % source) -def check_name_camel(name, info, source): +def check_name_camel(name: str, info: QAPISourceInfo, source: str) -> None: stem = check_name_str(name, info, source) if not re.match(r'[A-Z][A-Za-z0-9]*[a-z][A-Za-z0-9]*$', stem): raise QAPISemError(info, "name of %s must use CamelCase" % source) -def check_defn_name_str(name, info, meta): +def check_defn_name_str(name: str, info: QAPISourceInfo, meta: str) -> None: if meta == 'event': check_name_upper(name, info, meta) elif meta == 'command': @@ -90,9 +100,13 @@ def check_defn_name_str(name, info, meta): info, "%s name should not end in '%s'" % (meta, name[-4:])) -def check_keys(value, info, source, required, optional): +def check_keys(value: _JSONObject, + info: QAPISourceInfo, + source: str, + required: Collection[str], + optional: Collection[str]) -> None: - def pprint(elems): + def pprint(elems: Iterable[str]) -> str: return ', '.join("'" + e + "'" for e in sorted(elems)) missing = set(required) - set(value) @@ -112,7 +126,7 @@ def check_keys(value, info, source, required, optional): pprint(unknown), pprint(allowed))) -def check_flags(expr, info): +def check_flags(expr: _JSONObject, info: QAPISourceInfo) -> None: for key in ['gen', 'success-response']: if key in expr and expr[key] is not False: raise QAPISemError( @@ -130,9 +144,9 @@ def check_flags(expr, info): "are incompatible") -def check_if(expr, info, source): +def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None: - def check_if_str(ifcond): + def check_if_str(ifcond: object) -> None: if not isinstance(ifcond, str): raise QAPISemError( info, @@ -158,7 +172,7 @@ def check_if(expr, info, source): expr['if'] = [ifcond] -def normalize_members(members): +def normalize_members(members: object) -> None: if isinstance(members, dict): for key, arg in members.items(): if isinstance(arg, dict): @@ -166,8 +180,11 @@ def normalize_members(members): members[key] = {'type': arg} -def check_type(value, info, source, - allow_array=False, allow_dict=False): +def check_type(value: Optional[object], + info: QAPISourceInfo, + source: str, + allow_array: bool = False, + allow_dict: Union[bool, str] = False) -> None: if value is None: return @@ -214,7 +231,8 @@ def check_type(value, info, source, check_type(arg['type'], info, key_source, allow_array=True) -def check_features(features, info): +def check_features(features: Optional[object], + info: QAPISourceInfo) -> None: if features is None: return if not isinstance(features, list): @@ -231,7 +249,7 @@ def check_features(features, info): check_if(f, info, source) -def check_enum(expr, info): +def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None: name = expr['enum'] members = expr['data'] prefix = expr.get('prefix') @@ -260,7 +278,7 @@ def check_enum(expr, info): check_if(member, info, source) -def check_struct(expr, info): +def check_struct(expr: _JSONObject, info: QAPISourceInfo) -> None: name = cast(str, expr['struct']) # Checked in check_exprs members = expr['data'] @@ -268,7 +286,7 @@ def check_struct(expr, info): check_type(expr.get('base'), info, "'base'") -def check_union(expr, info): +def check_union(expr: _JSONObject, info: QAPISourceInfo) -> None: name = cast(str, expr['union']) # Checked in check_exprs base = expr.get('base') discriminator = expr.get('discriminator') @@ -296,7 +314,7 @@ def check_union(expr, info): check_type(value['type'], info, source, allow_array=not base) -def check_alternate(expr, info): +def check_alternate(expr: _JSONObject, info: QAPISourceInfo) -> None: members = expr['data'] if not members: @@ -313,7 +331,7 @@ def check_alternate(expr, info): check_type(value['type'], info, source) -def check_command(expr, info): +def check_command(expr: _JSONObject, info: QAPISourceInfo) -> None: args = expr.get('data') rets = expr.get('returns') boxed = expr.get('boxed', False) @@ -324,7 +342,7 @@ def check_command(expr, info): check_type(rets, info, "'returns'", allow_array=True) -def check_event(expr, info): +def check_event(expr: _JSONObject, info: QAPISourceInfo) -> None: args = expr.get('data') boxed = expr.get('boxed', False) @@ -333,7 +351,7 @@ def check_event(expr, info): check_type(args, info, "'data'", allow_dict=not boxed) -def check_exprs(exprs): +def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]: for expr_elem in exprs: # Expression assert isinstance(expr_elem['expr'], dict) diff --git a/scripts/qapi/mypy.ini b/scripts/qapi/mypy.ini index 0a000d58b3..7797c83432 100644 --- a/scripts/qapi/mypy.ini +++ b/scripts/qapi/mypy.ini @@ -8,11 +8,6 @@ disallow_untyped_defs = False disallow_incomplete_defs = False check_untyped_defs = False -[mypy-qapi.expr] -disallow_untyped_defs = False -disallow_incomplete_defs = False -check_untyped_defs = False - [mypy-qapi.parser] disallow_untyped_defs = False disallow_incomplete_defs = False From 210fd63104525b6e3154de529565258f19146f1a Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:26 -0400 Subject: [PATCH 0099/3028] qapi/expr.py: Consolidate check_if_str calls in check_if This is a small rewrite to address some minor style nits. Don't compare against the empty list to check for the empty condition, and move the normalization forward to unify the check on the now-normalized structure. With the check unified, the local nested function isn't needed anymore and can be brought down into the normal flow of the function. With the nesting level changed, shuffle the error strings around a bit to get them to fit in 79 columns. Note: although ifcond is typed as Sequence[str] elsewhere, we *know* that the parser will produce real, bona-fide lists. It's okay to check isinstance(ifcond, list) here. Signed-off-by: John Snow Message-Id: <20210421182032.3521476-12-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 4ebed4c488..de7fc16fac 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -146,30 +146,29 @@ def check_flags(expr: _JSONObject, info: QAPISourceInfo) -> None: def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None: - def check_if_str(ifcond: object) -> None: - if not isinstance(ifcond, str): + ifcond = expr.get('if') + if ifcond is None: + return + + if isinstance(ifcond, list): + if not ifcond: + raise QAPISemError( + info, "'if' condition [] of %s is useless" % source) + else: + # Normalize to a list + ifcond = expr['if'] = [ifcond] + + for elt in ifcond: + if not isinstance(elt, str): raise QAPISemError( info, "'if' condition of %s must be a string or a list of strings" % source) - if ifcond.strip() == '': + if not elt.strip(): raise QAPISemError( info, "'if' condition '%s' of %s makes no sense" - % (ifcond, source)) - - ifcond = expr.get('if') - if ifcond is None: - return - if isinstance(ifcond, list): - if ifcond == []: - raise QAPISemError( - info, "'if' condition [] of %s is useless" % source) - for elt in ifcond: - check_if_str(elt) - else: - check_if_str(ifcond) - expr['if'] = [ifcond] + % (elt, source)) def normalize_members(members: object) -> None: From e42648dccdd1defe8f35f247966cd7283f865cd6 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:27 -0400 Subject: [PATCH 0100/3028] qapi/expr.py: Remove single-letter variable Signed-off-by: John Snow Message-Id: <20210421182032.3521476-13-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index de7fc16fac..5e4d5f80aa 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -238,14 +238,14 @@ def check_features(features: Optional[object], raise QAPISemError(info, "'features' must be an array") features[:] = [f if isinstance(f, dict) else {'name': f} for f in features] - for f in features: + for feat in features: source = "'features' member" - assert isinstance(f, dict) - check_keys(f, info, source, ['name'], ['if']) - check_name_is_str(f['name'], info, source) - source = "%s '%s'" % (source, f['name']) - check_name_lower(f['name'], info, source) - check_if(f, info, source) + assert isinstance(feat, dict) + check_keys(feat, info, source, ['name'], ['if']) + check_name_is_str(feat['name'], info, source) + source = "%s '%s'" % (source, feat['name']) + check_name_str(feat['name'], info, source) + check_if(feat, info, source) def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None: From 328e8ca71abb9be7084ba16baad2a770c4e32d92 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:28 -0400 Subject: [PATCH 0101/3028] qapi/expr.py: enable pylint checks Signed-off-by: John Snow Tested-by: Eduardo Habkost Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa Message-Id: <20210421182032.3521476-14-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/pylintrc | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/qapi/pylintrc b/scripts/qapi/pylintrc index b9e077a164..fb0386d529 100644 --- a/scripts/qapi/pylintrc +++ b/scripts/qapi/pylintrc @@ -3,7 +3,6 @@ # Add files or directories matching the regex patterns to the ignore list. # The regex matches against base names, not paths. ignore-patterns=error.py, - expr.py, parser.py, schema.py, From 79e4fd14fb0f9e145413c6813dc541fdb50e3923 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:29 -0400 Subject: [PATCH 0102/3028] qapi/expr: Only explicitly prohibit 'Kind' nor 'List' for type names Per list review: qapi-code-gen.txt reserves suffixes Kind and List only for type names, but the code rejects them for events and commands, too. It turns out we reject them earlier anyway: In check_name_upper() for event names, and in check_name_lower() for command names. Still, adjust the code for clarity over what precisely we are guarding against. Signed-off-by: John Snow Message-Id: <20210421182032.3521476-15-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 5e4d5f80aa..c33caf00d9 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -95,9 +95,9 @@ def check_defn_name_str(name: str, info: QAPISourceInfo, meta: str) -> None: permit_underscore=name in info.pragma.command_name_exceptions) else: check_name_camel(name, info, meta) - if name.endswith('Kind') or name.endswith('List'): - raise QAPISemError( - info, "%s name should not end in '%s'" % (meta, name[-4:])) + if name.endswith('Kind') or name.endswith('List'): + raise QAPISemError( + info, "%s name should not end in '%s'" % (meta, name[-4:])) def check_keys(value: _JSONObject, From a48653638fab9c9a9356b41d6e11544b2a7b330f Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:30 -0400 Subject: [PATCH 0103/3028] qapi/expr.py: Add docstrings Now with more :words:! Signed-off-by: John Snow Message-Id: <20210421182032.3521476-16-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 256 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 251 insertions(+), 5 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index c33caf00d9..0b66d80842 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- # -# Check (context-free) QAPI schema expression structure -# # Copyright IBM, Corp. 2011 # Copyright (c) 2013-2019 Red Hat Inc. # @@ -14,6 +12,24 @@ # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. +""" +Normalize and validate (context-free) QAPI schema expression structures. + +`QAPISchemaParser` parses a QAPI schema into abstract syntax trees +consisting of dict, list, str, bool, and int nodes. This module ensures +that these nested structures have the correct type(s) and key(s) where +appropriate for the QAPI context-free grammar. + +The QAPI schema expression language allows for certain syntactic sugar; +this module also handles the normalization process of these nested +structures. + +See `check_exprs` for the main entry point. + +See `schema.QAPISchema` for processing into native Python data +structures and contextual semantic validation. +""" + import re from typing import ( Collection, @@ -39,9 +55,7 @@ from .source import QAPISourceInfo _JSONObject = Dict[str, object] -# Names consist of letters, digits, -, and _, starting with a letter. -# An experimental name is prefixed with x-. A name of a downstream -# extension is prefixed with __RFQDN_. The latter prefix goes first. +# See check_name_str(), below. valid_name = re.compile(r'(__[a-z0-9.-]+_)?' r'(x-)?' r'([a-z][a-z0-9_-]*)$', re.IGNORECASE) @@ -50,11 +64,33 @@ valid_name = re.compile(r'(__[a-z0-9.-]+_)?' def check_name_is_str(name: object, info: QAPISourceInfo, source: str) -> None: + """ + Ensure that ``name`` is a ``str``. + + :raise QAPISemError: When ``name`` fails validation. + """ if not isinstance(name, str): raise QAPISemError(info, "%s requires a string name" % source) def check_name_str(name: str, info: QAPISourceInfo, source: str) -> str: + """ + Ensure that ``name`` is a valid QAPI name. + + A valid name consists of ASCII letters, digits, ``-``, and ``_``, + starting with a letter. It may be prefixed by a downstream prefix + of the form __RFQDN_, or the experimental prefix ``x-``. If both + prefixes are present, the __RFDQN_ prefix goes first. + + A valid name cannot start with ``q_``, which is reserved. + + :param name: Name to check. + :param info: QAPI schema source file information. + :param source: Error string describing what ``name`` belongs to. + + :raise QAPISemError: When ``name`` fails validation. + :return: The stem of the valid name, with no prefixes. + """ # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty' # and 'q_obj_*' implicit type names. match = valid_name.match(name) @@ -64,6 +100,19 @@ def check_name_str(name: str, info: QAPISourceInfo, source: str) -> str: def check_name_upper(name: str, info: QAPISourceInfo, source: str) -> None: + """ + Ensure that ``name`` is a valid event name. + + This means it must be a valid QAPI name as checked by + `check_name_str()`, but where the stem prohibits lowercase + characters and ``-``. + + :param name: Name to check. + :param info: QAPI schema source file information. + :param source: Error string describing what ``name`` belongs to. + + :raise QAPISemError: When ``name`` fails validation. + """ stem = check_name_str(name, info, source) if re.search(r'[a-z-]', stem): raise QAPISemError( @@ -73,6 +122,21 @@ def check_name_upper(name: str, info: QAPISourceInfo, source: str) -> None: def check_name_lower(name: str, info: QAPISourceInfo, source: str, permit_upper: bool = False, permit_underscore: bool = False) -> None: + """ + Ensure that ``name`` is a valid command or member name. + + This means it must be a valid QAPI name as checked by + `check_name_str()`, but where the stem prohibits uppercase + characters and ``_``. + + :param name: Name to check. + :param info: QAPI schema source file information. + :param source: Error string describing what ``name`` belongs to. + :param permit_upper: Additionally permit uppercase. + :param permit_underscore: Additionally permit ``_``. + + :raise QAPISemError: When ``name`` fails validation. + """ stem = check_name_str(name, info, source) if ((not permit_upper and re.search(r'[A-Z]', stem)) or (not permit_underscore and '_' in stem)): @@ -81,12 +145,39 @@ def check_name_lower(name: str, info: QAPISourceInfo, source: str, def check_name_camel(name: str, info: QAPISourceInfo, source: str) -> None: + """ + Ensure that ``name`` is a valid user-defined type name. + + This means it must be a valid QAPI name as checked by + `check_name_str()`, but where the stem must be in CamelCase. + + :param name: Name to check. + :param info: QAPI schema source file information. + :param source: Error string describing what ``name`` belongs to. + + :raise QAPISemError: When ``name`` fails validation. + """ stem = check_name_str(name, info, source) if not re.match(r'[A-Z][A-Za-z0-9]*[a-z][A-Za-z0-9]*$', stem): raise QAPISemError(info, "name of %s must use CamelCase" % source) def check_defn_name_str(name: str, info: QAPISourceInfo, meta: str) -> None: + """ + Ensure that ``name`` is a valid definition name. + + Based on the value of ``meta``, this means that: + - 'event' names adhere to `check_name_upper()`. + - 'command' names adhere to `check_name_lower()`. + - Else, meta is a type, and must pass `check_name_camel()`. + These names must not end with ``Kind`` nor ``List``. + + :param name: Name to check. + :param info: QAPI schema source file information. + :param meta: Meta-type name of the QAPI expression. + + :raise QAPISemError: When ``name`` fails validation. + """ if meta == 'event': check_name_upper(name, info, meta) elif meta == 'command': @@ -105,6 +196,17 @@ def check_keys(value: _JSONObject, source: str, required: Collection[str], optional: Collection[str]) -> None: + """ + Ensure that a dict has a specific set of keys. + + :param value: The dict to check. + :param info: QAPI schema source file information. + :param source: Error string describing this ``value``. + :param required: Keys that *must* be present. + :param optional: Keys that *may* be present. + + :raise QAPISemError: When unknown keys are present. + """ def pprint(elems: Iterable[str]) -> str: return ', '.join("'" + e + "'" for e in sorted(elems)) @@ -127,6 +229,16 @@ def check_keys(value: _JSONObject, def check_flags(expr: _JSONObject, info: QAPISourceInfo) -> None: + """ + Ensure flag members (if present) have valid values. + + :param expr: The expression to validate. + :param info: QAPI schema source file information. + + :raise QAPISemError: + When certain flags have an invalid value, or when + incompatible flags are present. + """ for key in ['gen', 'success-response']: if key in expr and expr[key] is not False: raise QAPISemError( @@ -145,7 +257,25 @@ def check_flags(expr: _JSONObject, info: QAPISourceInfo) -> None: def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None: + """ + Normalize and validate the ``if`` member of an object. + The ``if`` member may be either a ``str`` or a ``List[str]``. + A ``str`` value will be normalized to ``List[str]``. + + :forms: + :sugared: ``Union[str, List[str]]`` + :canonical: ``List[str]`` + + :param expr: The expression containing the ``if`` member to validate. + :param info: QAPI schema source file information. + :param source: Error string describing ``expr``. + + :raise QAPISemError: + When the "if" member fails validation, or when there are no + non-empty conditions. + :return: None, ``expr`` is normalized in-place as needed. + """ ifcond = expr.get('if') if ifcond is None: return @@ -172,6 +302,21 @@ def check_if(expr: _JSONObject, info: QAPISourceInfo, source: str) -> None: def normalize_members(members: object) -> None: + """ + Normalize a "members" value. + + If ``members`` is a dict, for every value in that dict, if that + value is not itself already a dict, normalize it to + ``{'type': value}``. + + :forms: + :sugared: ``Dict[str, Union[str, TypeRef]]`` + :canonical: ``Dict[str, TypeRef]`` + + :param members: The members value to normalize. + + :return: None, ``members`` is normalized in-place as needed. + """ if isinstance(members, dict): for key, arg in members.items(): if isinstance(arg, dict): @@ -184,6 +329,26 @@ def check_type(value: Optional[object], source: str, allow_array: bool = False, allow_dict: Union[bool, str] = False) -> None: + """ + Normalize and validate the QAPI type of ``value``. + + Python types of ``str`` or ``None`` are always allowed. + + :param value: The value to check. + :param info: QAPI schema source file information. + :param source: Error string describing this ``value``. + :param allow_array: + Allow a ``List[str]`` of length 1, which indicates an array of + the type named by the list element. + :param allow_dict: + Allow a dict. Its members can be struct type members or union + branches. When the value of ``allow_dict`` is in pragma + ``member-name-exceptions``, the dict's keys may violate the + member naming rules. The dict members are normalized in place. + + :raise QAPISemError: When ``value`` fails validation. + :return: None, ``value`` is normalized in-place as needed. + """ if value is None: return @@ -232,6 +397,22 @@ def check_type(value: Optional[object], def check_features(features: Optional[object], info: QAPISourceInfo) -> None: + """ + Normalize and validate the ``features`` member. + + ``features`` may be a ``list`` of either ``str`` or ``dict``. + Any ``str`` element will be normalized to ``{'name': element}``. + + :forms: + :sugared: ``List[Union[str, Feature]]`` + :canonical: ``List[Feature]`` + + :param features: The features member value to validate. + :param info: QAPI schema source file information. + + :raise QAPISemError: When ``features`` fails validation. + :return: None, ``features`` is normalized in-place as needed. + """ if features is None: return if not isinstance(features, list): @@ -249,6 +430,15 @@ def check_features(features: Optional[object], def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None: + """ + Normalize and validate this expression as an ``enum`` definition. + + :param expr: The expression to validate. + :param info: QAPI schema source file information. + + :raise QAPISemError: When ``expr`` is not a valid ``enum``. + :return: None, ``expr`` is normalized in-place as needed. + """ name = expr['enum'] members = expr['data'] prefix = expr.get('prefix') @@ -278,6 +468,15 @@ def check_enum(expr: _JSONObject, info: QAPISourceInfo) -> None: def check_struct(expr: _JSONObject, info: QAPISourceInfo) -> None: + """ + Normalize and validate this expression as a ``struct`` definition. + + :param expr: The expression to validate. + :param info: QAPI schema source file information. + + :raise QAPISemError: When ``expr`` is not a valid ``struct``. + :return: None, ``expr`` is normalized in-place as needed. + """ name = cast(str, expr['struct']) # Checked in check_exprs members = expr['data'] @@ -286,6 +485,15 @@ def check_struct(expr: _JSONObject, info: QAPISourceInfo) -> None: def check_union(expr: _JSONObject, info: QAPISourceInfo) -> None: + """ + Normalize and validate this expression as a ``union`` definition. + + :param expr: The expression to validate. + :param info: QAPI schema source file information. + + :raise QAPISemError: when ``expr`` is not a valid ``union``. + :return: None, ``expr`` is normalized in-place as needed. + """ name = cast(str, expr['union']) # Checked in check_exprs base = expr.get('base') discriminator = expr.get('discriminator') @@ -314,6 +522,15 @@ def check_union(expr: _JSONObject, info: QAPISourceInfo) -> None: def check_alternate(expr: _JSONObject, info: QAPISourceInfo) -> None: + """ + Normalize and validate this expression as an ``alternate`` definition. + + :param expr: The expression to validate. + :param info: QAPI schema source file information. + + :raise QAPISemError: When ``expr`` is not a valid ``alternate``. + :return: None, ``expr`` is normalized in-place as needed. + """ members = expr['data'] if not members: @@ -331,6 +548,15 @@ def check_alternate(expr: _JSONObject, info: QAPISourceInfo) -> None: def check_command(expr: _JSONObject, info: QAPISourceInfo) -> None: + """ + Normalize and validate this expression as a ``command`` definition. + + :param expr: The expression to validate. + :param info: QAPI schema source file information. + + :raise QAPISemError: When ``expr`` is not a valid ``command``. + :return: None, ``expr`` is normalized in-place as needed. + """ args = expr.get('data') rets = expr.get('returns') boxed = expr.get('boxed', False) @@ -342,6 +568,15 @@ def check_command(expr: _JSONObject, info: QAPISourceInfo) -> None: def check_event(expr: _JSONObject, info: QAPISourceInfo) -> None: + """ + Normalize and validate this expression as an ``event`` definition. + + :param expr: The expression to validate. + :param info: QAPI schema source file information. + + :raise QAPISemError: When ``expr`` is not a valid ``event``. + :return: None, ``expr`` is normalized in-place as needed. + """ args = expr.get('data') boxed = expr.get('boxed', False) @@ -351,6 +586,17 @@ def check_event(expr: _JSONObject, info: QAPISourceInfo) -> None: def check_exprs(exprs: List[_JSONObject]) -> List[_JSONObject]: + """ + Validate and normalize a list of parsed QAPI schema expressions. + + This function accepts a list of expressions and metadata as returned + by the parser. It destructively normalizes the expressions in-place. + + :param exprs: The list of expressions to normalize and validate. + + :raise QAPISemError: When any expression fails validation. + :return: The same list of expressions (now modified). + """ for expr_elem in exprs: # Expression assert isinstance(expr_elem['expr'], dict) From eab99939a7cd289a8b50c2e7ef6a38ca2706a46c Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:31 -0400 Subject: [PATCH 0104/3028] qapi/expr.py: Use tuples instead of lists for static data It is -- maybe -- possibly -- three nanoseconds faster. Signed-off-by: John Snow Reviewed-by: Eduardo Habkost Reviewed-by: Cleber Rosa Message-Id: <20210421182032.3521476-17-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 0b66d80842..225a82e20d 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -239,11 +239,11 @@ def check_flags(expr: _JSONObject, info: QAPISourceInfo) -> None: When certain flags have an invalid value, or when incompatible flags are present. """ - for key in ['gen', 'success-response']: + for key in ('gen', 'success-response'): if key in expr and expr[key] is not False: raise QAPISemError( info, "flag '%s' may only use false value" % key) - for key in ['boxed', 'allow-oob', 'allow-preconfig', 'coroutine']: + for key in ('boxed', 'allow-oob', 'allow-preconfig', 'coroutine'): if key in expr and expr[key] is not True: raise QAPISemError( info, "flag '%s' may only use true value" % key) From e81718c698a9f1a1d98edd605f508dadbffe0d4d Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 14:20:32 -0400 Subject: [PATCH 0105/3028] qapi/expr: Update authorship and copyright information Signed-off-by: John Snow Message-Id: <20210421182032.3521476-18-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/expr.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/qapi/expr.py b/scripts/qapi/expr.py index 225a82e20d..496f7e0333 100644 --- a/scripts/qapi/expr.py +++ b/scripts/qapi/expr.py @@ -1,13 +1,14 @@ # -*- coding: utf-8 -*- # # Copyright IBM, Corp. 2011 -# Copyright (c) 2013-2019 Red Hat Inc. +# Copyright (c) 2013-2021 Red Hat Inc. # # Authors: # Anthony Liguori # Markus Armbruster # Eric Blake # Marc-André Lureau +# John Snow # # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. From 46f49468c690ff015a5b5346a279845f5e55369e Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 15:22:26 -0400 Subject: [PATCH 0106/3028] qapi/error: Repurpose QAPIError as an abstract base exception class Rename QAPIError to QAPISourceError, and then create a new QAPIError class that serves as the basis for all of our other custom exceptions, without specifying any class properties. This leaves QAPIError as a package-wide error class that's suitable for any current or future errors. (Right now, we don't have any errors that DON'T also want to specify a Source location, but this MAY change. In these cases, a common abstract ancestor would be desired.) Add docstrings to explain the intended function of each error class. Signed-off-by: John Snow Message-Id: <20210421192233.3542904-2-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- docs/sphinx/qapidoc.py | 3 ++- scripts/qapi/error.py | 11 +++++++++-- scripts/qapi/schema.py | 5 +++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py index b7a2d39c10..87c67ab23f 100644 --- a/docs/sphinx/qapidoc.py +++ b/docs/sphinx/qapidoc.py @@ -34,7 +34,8 @@ from sphinx.errors import ExtensionError from sphinx.util.nodes import nested_parse_with_titles import sphinx from qapi.gen import QAPISchemaVisitor -from qapi.schema import QAPIError, QAPISemError, QAPISchema +from qapi.error import QAPIError, QAPISemError +from qapi.schema import QAPISchema # Sphinx up to 1.6 uses AutodocReporter; 1.7 and later diff --git a/scripts/qapi/error.py b/scripts/qapi/error.py index ae60d9e2fe..126dda7c9b 100644 --- a/scripts/qapi/error.py +++ b/scripts/qapi/error.py @@ -13,6 +13,11 @@ class QAPIError(Exception): + """Base class for all exceptions from the QAPI package.""" + + +class QAPISourceError(QAPIError): + """Error class for all exceptions identifying a source location.""" def __init__(self, info, col, msg): Exception.__init__(self) self.info = info @@ -27,7 +32,8 @@ class QAPIError(Exception): return loc + ': ' + self.msg -class QAPIParseError(QAPIError): +class QAPIParseError(QAPISourceError): + """Error class for all QAPI schema parsing errors.""" def __init__(self, parser, msg): col = 1 for ch in parser.src[parser.line_pos:parser.pos]: @@ -38,6 +44,7 @@ class QAPIParseError(QAPIError): super().__init__(parser.info, col, msg) -class QAPISemError(QAPIError): +class QAPISemError(QAPISourceError): + """Error class for semantic QAPI errors.""" def __init__(self, info, msg): super().__init__(info, None, msg) diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index 703b446fd2..c277fcacc5 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -20,7 +20,7 @@ import re from typing import Optional from .common import POINTER_SUFFIX, c_name -from .error import QAPIError, QAPISemError +from .error import QAPISemError, QAPISourceError from .expr import check_exprs from .parser import QAPISchemaParser @@ -875,7 +875,8 @@ class QAPISchema: other_ent = self._entity_dict.get(ent.name) if other_ent: if other_ent.info: - where = QAPIError(other_ent.info, None, "previous definition") + where = QAPISourceError(other_ent.info, None, + "previous definition") raise QAPISemError( ent.info, "'%s' is already defined\n%s" % (ent.name, where)) From b54e07cc46064e79de275c7ea26d90a51913a9ea Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 15:22:27 -0400 Subject: [PATCH 0107/3028] qapi/error: Use Python3-style super() Missed in commit 2cae67bcb5 "qapi: Use super() now we have Python 3". Signed-off-by: John Snow Reviewed-by: Markus Armbruster Message-Id: <20210421192233.3542904-3-jsnow@redhat.com> Signed-off-by: Markus Armbruster --- scripts/qapi/error.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qapi/error.py b/scripts/qapi/error.py index 126dda7c9b..38bd7c4dd6 100644 --- a/scripts/qapi/error.py +++ b/scripts/qapi/error.py @@ -19,7 +19,7 @@ class QAPIError(Exception): class QAPISourceError(QAPIError): """Error class for all exceptions identifying a source location.""" def __init__(self, info, col, msg): - Exception.__init__(self) + super().__init__() self.info = info self.col = col self.msg = msg From 86cc2ff65a4764ade26c7741c7c05f23e7efa95c Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 15:22:28 -0400 Subject: [PATCH 0108/3028] qapi/error: Make QAPISourceError 'col' parameter optional It's already treated as optional, with one direct caller and some subclass callers passing 'None'. Make it officially optional, which requires moving the position of the argument to come after all required parameters. QAPISemError becomes functionally identical to QAPISourceError. Keep the name to preserve its semantic meaning and avoid code churn, but remove the now-useless __init__ wrapper. Signed-off-by: John Snow Message-Id: <20210421192233.3542904-4-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/error.py | 8 +++----- scripts/qapi/schema.py | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/scripts/qapi/error.py b/scripts/qapi/error.py index 38bd7c4dd6..d179a3bd0c 100644 --- a/scripts/qapi/error.py +++ b/scripts/qapi/error.py @@ -18,11 +18,11 @@ class QAPIError(Exception): class QAPISourceError(QAPIError): """Error class for all exceptions identifying a source location.""" - def __init__(self, info, col, msg): + def __init__(self, info, msg, col=None): super().__init__() self.info = info - self.col = col self.msg = msg + self.col = col def __str__(self): loc = str(self.info) @@ -41,10 +41,8 @@ class QAPIParseError(QAPISourceError): col = (col + 7) % 8 + 1 else: col += 1 - super().__init__(parser.info, col, msg) + super().__init__(parser.info, msg, col) class QAPISemError(QAPISourceError): """Error class for semantic QAPI errors.""" - def __init__(self, info, msg): - super().__init__(info, None, msg) diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index c277fcacc5..3a4172fb74 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -875,8 +875,7 @@ class QAPISchema: other_ent = self._entity_dict.get(ent.name) if other_ent: if other_ent.info: - where = QAPISourceError(other_ent.info, None, - "previous definition") + where = QAPISourceError(other_ent.info, "previous definition") raise QAPISemError( ent.info, "'%s' is already defined\n%s" % (ent.name, where)) From ac89761179ed6e3165a63ad68759f77f33bace30 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 15:22:29 -0400 Subject: [PATCH 0109/3028] qapi/error: assert QAPISourceInfo is not None Built-in stuff is not parsed from a source file, and therefore have no QAPISourceInfo. If such None info was used for reporting an error, built-in stuff would be broken. Programming error. Instead of reporting a confusing error with bogus source location then, we better crash. We currently crash only if self.col was set. Assert that self.info is not None in order to crash reliably. We can not yet change the type of the initializer to prove this cannot happen at static analysis time before the remainder of the code is fully typed. Signed-off-by: John Snow Message-Id: <20210421192233.3542904-5-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/error.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/qapi/error.py b/scripts/qapi/error.py index d179a3bd0c..d0bc7af6e7 100644 --- a/scripts/qapi/error.py +++ b/scripts/qapi/error.py @@ -25,6 +25,7 @@ class QAPISourceError(QAPIError): self.col = col def __str__(self): + assert self.info is not None loc = str(self.info) if self.col is not None: assert self.info.line is not None From ac6a7d8884762d27cc2dde5a5c6e793cc18fc4d9 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 15:22:30 -0400 Subject: [PATCH 0110/3028] qapi/error.py: move QAPIParseError to parser.py Keeping it in error.py will create some cyclic import problems when we add types to the QAPISchemaParser. Callers don't need to know the details of QAPIParseError unless they are parsing or dealing directly with the parser, so this won't create any harsh new requirements for callers in the general case. Update error.py with a little docstring that gives a nod to where the error may now be found. Signed-off-by: John Snow Message-Id: <20210421192233.3542904-6-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/error.py | 22 ++++++++-------------- scripts/qapi/parser.py | 14 +++++++++++++- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/scripts/qapi/error.py b/scripts/qapi/error.py index d0bc7af6e7..6723c5a9d9 100644 --- a/scripts/qapi/error.py +++ b/scripts/qapi/error.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- # -# QAPI error classes -# # Copyright (c) 2017-2019 Red Hat Inc. # # Authors: @@ -11,6 +9,14 @@ # This work is licensed under the terms of the GNU GPL, version 2. # See the COPYING file in the top-level directory. +""" +QAPI error classes + +Common error classes used throughout the package. Additional errors may +be defined in other modules. At present, `QAPIParseError` is defined in +parser.py. +""" + class QAPIError(Exception): """Base class for all exceptions from the QAPI package.""" @@ -33,17 +39,5 @@ class QAPISourceError(QAPIError): return loc + ': ' + self.msg -class QAPIParseError(QAPISourceError): - """Error class for all QAPI schema parsing errors.""" - def __init__(self, parser, msg): - col = 1 - for ch in parser.src[parser.line_pos:parser.pos]: - if ch == '\t': - col = (col + 7) % 8 + 1 - else: - col += 1 - super().__init__(parser.info, msg, col) - - class QAPISemError(QAPISourceError): """Error class for semantic QAPI errors.""" diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index 58267c3db9..ca5e8e18e0 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -18,10 +18,22 @@ from collections import OrderedDict import os import re -from .error import QAPIParseError, QAPISemError +from .error import QAPISemError, QAPISourceError from .source import QAPISourceInfo +class QAPIParseError(QAPISourceError): + """Error class for all QAPI schema parsing errors.""" + def __init__(self, parser, msg): + col = 1 + for ch in parser.src[parser.line_pos:parser.pos]: + if ch == '\t': + col = (col + 7) % 8 + 1 + else: + col += 1 + super().__init__(parser.info, msg, col) + + class QAPISchemaParser: def __init__(self, fname, previously_included=None, incl_info=None): From 92870cf3afe42c0f2103ff3f5e4e7edd99549040 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 15:22:31 -0400 Subject: [PATCH 0111/3028] qapi/error.py: enable pylint checks Signed-off-by: John Snow Message-Id: <20210421192233.3542904-7-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/pylintrc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/qapi/pylintrc b/scripts/qapi/pylintrc index fb0386d529..88efbf71cb 100644 --- a/scripts/qapi/pylintrc +++ b/scripts/qapi/pylintrc @@ -2,8 +2,7 @@ # Add files or directories matching the regex patterns to the ignore list. # The regex matches against base names, not paths. -ignore-patterns=error.py, - parser.py, +ignore-patterns=parser.py, schema.py, From 30d0a016e965796b41ac545b3d527f8080292869 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 15:22:32 -0400 Subject: [PATCH 0112/3028] qapi/error: Add type hints No functional change. Note: QAPISourceError's info parameter is Optional[] because schema.py treats the info property of its various classes as Optional to accommodate built-in types, which have no source. See prior commit 'qapi/error: assert QAPISourceInfo is not None'. Signed-off-by: John Snow Message-Id: <20210421192233.3542904-8-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/error.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/qapi/error.py b/scripts/qapi/error.py index 6723c5a9d9..e35e4ddb26 100644 --- a/scripts/qapi/error.py +++ b/scripts/qapi/error.py @@ -17,6 +17,10 @@ be defined in other modules. At present, `QAPIParseError` is defined in parser.py. """ +from typing import Optional + +from .source import QAPISourceInfo + class QAPIError(Exception): """Base class for all exceptions from the QAPI package.""" @@ -24,13 +28,16 @@ class QAPIError(Exception): class QAPISourceError(QAPIError): """Error class for all exceptions identifying a source location.""" - def __init__(self, info, msg, col=None): + def __init__(self, + info: Optional[QAPISourceInfo], + msg: str, + col: Optional[int] = None): super().__init__() self.info = info self.msg = msg self.col = col - def __str__(self): + def __str__(self) -> str: assert self.info is not None loc = str(self.info) if self.col is not None: From b54626e0b8f423e91b2e31fa7741e4954cebd2d6 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 21 Apr 2021 15:22:33 -0400 Subject: [PATCH 0113/3028] qapi/error.py: enable mypy checks Signed-off-by: John Snow Message-Id: <20210421192233.3542904-9-jsnow@redhat.com> Reviewed-by: Markus Armbruster Signed-off-by: Markus Armbruster --- scripts/qapi/mypy.ini | 5 ----- 1 file changed, 5 deletions(-) diff --git a/scripts/qapi/mypy.ini b/scripts/qapi/mypy.ini index 7797c83432..54ca4483d6 100644 --- a/scripts/qapi/mypy.ini +++ b/scripts/qapi/mypy.ini @@ -3,11 +3,6 @@ strict = True disallow_untyped_calls = False python_version = 3.6 -[mypy-qapi.error] -disallow_untyped_defs = False -disallow_incomplete_defs = False -check_untyped_defs = False - [mypy-qapi.parser] disallow_untyped_defs = False disallow_incomplete_defs = False From ca0fd2e345033e14f1d3358304243e8606ced14f Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 09:05:14 -0600 Subject: [PATCH 0114/3028] bsd-user: whitespace changes keyword space paren, no space before ( in function calls, spaces around operators. Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/bsdload.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c index f38c4faacf..546946b91d 100644 --- a/bsd-user/bsdload.c +++ b/bsd-user/bsdload.c @@ -20,11 +20,11 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src, return 0; } -static int count(char ** vec) +static int count(char **vec) { int i; - for(i = 0; *vec; i++) { + for (i = 0; *vec; i++) { vec++; } @@ -37,15 +37,15 @@ static int prepare_binprm(struct linux_binprm *bprm) int mode; int retval; - if(fstat(bprm->fd, &st) < 0) { + if (fstat(bprm->fd, &st) < 0) { return(-errno); } mode = st.st_mode; - if(!S_ISREG(mode)) { /* Must be regular file */ + if (!S_ISREG(mode)) { /* Must be regular file */ return(-EACCES); } - if(!(mode & 0111)) { /* Must have at least one execute bit set */ + if (!(mode & 0111)) { /* Must have at least one execute bit set */ return(-EACCES); } @@ -53,7 +53,7 @@ static int prepare_binprm(struct linux_binprm *bprm) bprm->e_gid = getegid(); /* Set-uid? */ - if(mode & S_ISUID) { + if (mode & S_ISUID) { bprm->e_uid = st.st_uid; } @@ -69,10 +69,10 @@ static int prepare_binprm(struct linux_binprm *bprm) memset(bprm->buf, 0, sizeof(bprm->buf)); retval = lseek(bprm->fd, 0L, SEEK_SET); - if(retval >= 0) { + if (retval >= 0) { retval = read(bprm->fd, bprm->buf, 128); } - if(retval < 0) { + if (retval < 0) { perror("prepare_binprm"); exit(-1); /* return(-errno); */ @@ -125,15 +125,15 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, return sp; } -int loader_exec(const char * filename, char ** argv, char ** envp, - struct target_pt_regs * regs, struct image_info *infop) +int loader_exec(const char *filename, char **argv, char **envp, + struct target_pt_regs *regs, struct image_info *infop) { struct linux_binprm bprm; int retval; int i; - bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int); - for (i=0 ; i=0) { + if (retval >= 0) { if (bprm.buf[0] == 0x7f && bprm.buf[1] == 'E' && bprm.buf[2] == 'L' && bprm.buf[3] == 'F') { - retval = load_elf_binary(&bprm,regs,infop); + retval = load_elf_binary(&bprm, regs, infop); } else { fprintf(stderr, "Unknown binary format\n"); return -1; } } - if(retval>=0) { + if (retval >= 0) { /* success. Initialize important registers */ do_init_thread(regs, infop); return retval; } /* Something went wrong, return the inode and free the argument pages*/ - for (i=0 ; i Date: Fri, 23 Apr 2021 09:05:57 -0600 Subject: [PATCH 0115/3028] bsd-user: style tweak: keyword space ( Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/qemu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index d2bcaab741..b836b603af 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -233,7 +233,7 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) #define __put_user(x, hptr)\ ({\ int size = sizeof(*hptr);\ - switch(size) {\ + switch (size) {\ case 1:\ *(uint8_t *)(hptr) = (uint8_t)(typeof(*hptr))(x);\ break;\ @@ -255,7 +255,7 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) #define __get_user(x, hptr) \ ({\ int size = sizeof(*hptr);\ - switch(size) {\ + switch (size) {\ case 1:\ x = (typeof(*hptr))*(uint8_t *)(hptr);\ break;\ From fa0546370d6d13016687854c341d057520672aec Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 16:22:19 -0600 Subject: [PATCH 0116/3028] bsd-user: style tweak: return is not a function, eliminate () Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/bsdload.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c index 546946b91d..fd14ffa4cd 100644 --- a/bsd-user/bsdload.c +++ b/bsd-user/bsdload.c @@ -28,7 +28,7 @@ static int count(char **vec) vec++; } - return(i); + return i; } static int prepare_binprm(struct linux_binprm *bprm) @@ -38,15 +38,15 @@ static int prepare_binprm(struct linux_binprm *bprm) int retval; if (fstat(bprm->fd, &st) < 0) { - return(-errno); + return -errno; } mode = st.st_mode; if (!S_ISREG(mode)) { /* Must be regular file */ - return(-EACCES); + return -EACCES; } if (!(mode & 0111)) { /* Must have at least one execute bit set */ - return(-EACCES); + return -EACCES; } bprm->e_uid = geteuid(); @@ -75,10 +75,9 @@ static int prepare_binprm(struct linux_binprm *bprm) if (retval < 0) { perror("prepare_binprm"); exit(-1); - /* return(-errno); */ } else { - return(retval); + return retval; } } @@ -169,5 +168,5 @@ int loader_exec(const char *filename, char **argv, char **envp, for (i = 0 ; i < MAX_ARG_PAGES ; i++) { g_free(bprm.page[i]); } - return(retval); + return retval; } From 92ac45049b8c17b2ea659c9533951f391ac93744 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 21:35:15 -0600 Subject: [PATCH 0117/3028] bsd-user: put back a break; that had gone missing... Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/syscall.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index adc3d21b54..4abff796c7 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -199,6 +199,7 @@ static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind) #else case CTLTYPE_LONG: *(uint64_t *)holdp = tswap64(*(long *)holdp); + break; case CTLTYPE_ULONG: *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp); break; From 58b3beb483d08066548d84eccd007b9d8bd24a2b Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 16:23:53 -0600 Subject: [PATCH 0118/3028] bsd-user: style tweak: Put {} around all if/else/for statements Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/bsdload.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c index fd14ffa4cd..e1ed3b7b60 100644 --- a/bsd-user/bsdload.c +++ b/bsd-user/bsdload.c @@ -13,8 +13,9 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src, void *host_ptr; host_ptr = lock_user(VERIFY_WRITE, dest, len, 0); - if (!host_ptr) + if (!host_ptr) { return -TARGET_EFAULT; + } memcpy(host_ptr, src, len); unlock_user(host_ptr, dest, 1); return 0; @@ -75,8 +76,7 @@ static int prepare_binprm(struct linux_binprm *bprm) if (retval < 0) { perror("prepare_binprm"); exit(-1); - } - else { + } else { return retval; } } @@ -132,11 +132,13 @@ int loader_exec(const char *filename, char **argv, char **envp, int i; bprm.p = TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(unsigned int); - for (i = 0 ; i < MAX_ARG_PAGES ; i++) /* clear page-table */ + for (i = 0 ; i < MAX_ARG_PAGES ; i++) { /* clear page-table */ bprm.page[i] = NULL; + } retval = open(filename, O_RDONLY); - if (retval < 0) + if (retval < 0) { return retval; + } bprm.fd = retval; bprm.filename = (char *)filename; bprm.argc = count(argv); From 0df2d9a673543c4ab06646d9f6bd21153c632a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:51 +0200 Subject: [PATCH 0119/3028] aspeed/smc: Use the RAM memory region for DMAs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of passing the memory address space region, simply use the RAM memory region instead. This simplifies RAM accesses. This patch breaks migration compatibility. Fixes: c4e1f0b48322 ("aspeed/smc: Add support for DMAs") Cc: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater Message-Id: <20210407171637.777743-2-clg@kaod.org> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 2 +- hw/ssi/aspeed_smc.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index a17b75f494..1cf5a15c80 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -327,7 +327,7 @@ static void aspeed_machine_init(MachineState *machine) object_property_set_int(OBJECT(&bmc->soc), "num-cs", amc->num_cs, &error_abort); object_property_set_link(OBJECT(&bmc->soc), "dram", - OBJECT(&bmc->ram_container), &error_abort); + OBJECT(machine->ram), &error_abort); if (machine->kernel_filename) { /* * When booting with a -kernel command line there is no u-boot diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 16addee4dc..6f72fb028e 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -178,8 +178,7 @@ * 0: 4 bytes * 0x7FFFFF: 32M bytes */ -#define DMA_DRAM_ADDR(s, val) ((s)->sdram_base | \ - ((val) & (s)->ctrl->dma_dram_mask)) +#define DMA_DRAM_ADDR(s, val) ((val) & (s)->ctrl->dma_dram_mask) #define DMA_FLASH_ADDR(s, val) ((s)->ctrl->flash_window_base | \ ((val) & (s)->ctrl->dma_flash_mask)) #define DMA_LENGTH(val) ((val) & 0x01FFFFFC) From d177892d4a48668a422772e19bed9b6baa384a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:51 +0200 Subject: [PATCH 0120/3028] aspeed/smc: Remove unused "sdram-base" property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210407171637.777743-3-clg@kaod.org> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast2600.c | 4 ---- hw/arm/aspeed_soc.c | 4 ---- hw/ssi/aspeed_smc.c | 1 - include/hw/ssi/aspeed_smc.h | 3 --- 4 files changed, 12 deletions(-) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index bc87e754a3..2a1255b6a0 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -344,10 +344,6 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) /* FMC, The number of CS is set at the board level */ object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); - if (!object_property_set_int(OBJECT(&s->fmc), "sdram-base", - sc->memmap[ASPEED_DEV_SDRAM], errp)) { - return; - } if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { return; } diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 057d053c84..817f3ba63d 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -301,10 +301,6 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) /* FMC, The number of CS is set at the board level */ object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); - if (!object_property_set_int(OBJECT(&s->fmc), "sdram-base", - sc->memmap[ASPEED_DEV_SDRAM], errp)) { - return; - } if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { return; } diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 6f72fb028e..884e08aca4 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -1431,7 +1431,6 @@ static const VMStateDescription vmstate_aspeed_smc = { static Property aspeed_smc_properties[] = { DEFINE_PROP_UINT32("num-cs", AspeedSMCState, num_cs, 1), DEFINE_PROP_BOOL("inject-failure", AspeedSMCState, inject_failure, false), - DEFINE_PROP_UINT64("sdram-base", AspeedSMCState, sdram_base, 0), DEFINE_PROP_LINK("dram", AspeedSMCState, dram_mr, TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index 16c03fe64f..ccd71d9b53 100644 --- a/include/hw/ssi/aspeed_smc.h +++ b/include/hw/ssi/aspeed_smc.h @@ -103,9 +103,6 @@ struct AspeedSMCState { uint8_t r_timings; uint8_t conf_enable_w0; - /* for DMA support */ - uint64_t sdram_base; - AddressSpace flash_as; MemoryRegion *dram_mr; AddressSpace dram_as; From 7492515909f043c4d82909ecdebb8643ed944c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:51 +0200 Subject: [PATCH 0121/3028] aspeed/i2c: Fix DMA address mask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The RAM memory region is now used for DMAs accesses instead of the memory address space region. Mask off the top bits of the DMA address to reflect this change. Cc: Philippe Mathieu-Daudé Signed-off-by: Cédric Le Goater Message-Id: <20210407171637.777743-4-clg@kaod.org> Signed-off-by: Cédric Le Goater --- hw/i2c/aspeed_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index 518a3f5c6f..e713352889 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -601,7 +601,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, break; } - bus->dma_addr = value & 0xfffffffc; + bus->dma_addr = value & 0x3ffffffc; break; case I2CD_DMA_LEN: From 3f7a53b22469ed4b80649ef92b94378c60dda5d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:51 +0200 Subject: [PATCH 0122/3028] aspeed/i2c: Rename DMA address space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It improves 'info mtree' output. Signed-off-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210407171637.777743-5-clg@kaod.org> Signed-off-by: Cédric Le Goater --- hw/i2c/aspeed_i2c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index e713352889..8d276d9ed3 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -816,7 +816,8 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp) return; } - address_space_init(&s->dram_as, s->dram_mr, "dma-dram"); + address_space_init(&s->dram_as, s->dram_mr, + TYPE_ASPEED_I2C "-dma-dram"); } } From e9c568dbc22551f069dbc30ca3b61e168f494d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 1 May 2021 10:03:51 +0200 Subject: [PATCH 0123/3028] hw/arm/aspeed: Do not sysbus-map mmio flash region directly, use alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flash mmio region is exposed as an AddressSpace. AddressSpaces must not be sysbus-mapped, therefore map the region using an alias. Signed-off-by: Philippe Mathieu-Daudé [ clg : Fix DMA_FLASH_ADDR() ] Signed-off-by: Cédric Le Goater Message-Id: <20210312182851.1922972-3-f4bug@amsat.org> Signed-off-by: Cédric Le Goater Message-Id: <20210407171637.777743-6-clg@kaod.org> Signed-off-by: Cédric Le Goater --- hw/ssi/aspeed_smc.c | 7 ++++--- include/hw/ssi/aspeed_smc.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 884e08aca4..50ea907aef 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -179,8 +179,7 @@ * 0x7FFFFF: 32M bytes */ #define DMA_DRAM_ADDR(s, val) ((val) & (s)->ctrl->dma_dram_mask) -#define DMA_FLASH_ADDR(s, val) ((s)->ctrl->flash_window_base | \ - ((val) & (s)->ctrl->dma_flash_mask)) +#define DMA_FLASH_ADDR(s, val) ((val) & (s)->ctrl->dma_flash_mask) #define DMA_LENGTH(val) ((val) & 0x01FFFFFC) /* Flash opcodes. */ @@ -1385,7 +1384,9 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) memory_region_init_io(&s->mmio_flash, OBJECT(s), &aspeed_smc_flash_default_ops, s, name, s->ctrl->flash_window_size); - sysbus_init_mmio(sbd, &s->mmio_flash); + memory_region_init_alias(&s->mmio_flash_alias, OBJECT(s), name, + &s->mmio_flash, 0, s->ctrl->flash_window_size); + sysbus_init_mmio(sbd, &s->mmio_flash_alias); s->flashes = g_new0(AspeedSMCFlash, s->ctrl->max_peripherals); diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index ccd71d9b53..6ea2871cd8 100644 --- a/include/hw/ssi/aspeed_smc.h +++ b/include/hw/ssi/aspeed_smc.h @@ -84,6 +84,7 @@ struct AspeedSMCState { MemoryRegion mmio; MemoryRegion mmio_flash; + MemoryRegion mmio_flash_alias; qemu_irq irq; int irqline; From c5475b3f9aa28c1c1422c7de0bab40c5dff77341 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Sat, 1 May 2021 10:03:51 +0200 Subject: [PATCH 0124/3028] hw: Model ASPEED's Hash and Crypto Engine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HACE (Hash and Crypto Engine) is a device that offloads MD5, SHA1, SHA2, RSA and other cryptographic algorithms. This initial model implements a subset of the device's functionality; currently only MD5/SHA hashing, and on the ast2600's scatter gather engine. Co-developed-by: Klaus Heinrich Kiwi Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Joel Stanley Reviewed-by: Andrew Jeffery [ clg: - fixes for 32-bit and OSX builds ] Signed-off-by: Cédric Le Goater Message-Id: <20210409000253.1475587-2-joel@jms.id.au> Signed-off-by: Cédric Le Goater --- docs/system/arm/aspeed.rst | 1 + hw/misc/aspeed_hace.c | 389 ++++++++++++++++++++++++++++++++++ hw/misc/meson.build | 1 + include/hw/misc/aspeed_hace.h | 43 ++++ 4 files changed, 434 insertions(+) create mode 100644 hw/misc/aspeed_hace.c create mode 100644 include/hw/misc/aspeed_hace.h diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index d1fb8f25b3..23a1468cd1 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -49,6 +49,7 @@ Supported devices * Ethernet controllers * Front LEDs (PCA9552 on I2C bus) * LPC Peripheral Controller (a subset of subdevices are supported) + * Hash/Crypto Engine (HACE) - Hash support only. TODO: HMAC and RSA Missing devices diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c new file mode 100644 index 0000000000..10f00e65f4 --- /dev/null +++ b/hw/misc/aspeed_hace.c @@ -0,0 +1,389 @@ +/* + * ASPEED Hash and Crypto Engine + * + * Copyright (C) 2021 IBM Corp. + * + * Joel Stanley + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "hw/misc/aspeed_hace.h" +#include "qapi/error.h" +#include "migration/vmstate.h" +#include "crypto/hash.h" +#include "hw/qdev-properties.h" +#include "hw/irq.h" + +#define R_CRYPT_CMD (0x10 / 4) + +#define R_STATUS (0x1c / 4) +#define HASH_IRQ BIT(9) +#define CRYPT_IRQ BIT(12) +#define TAG_IRQ BIT(15) + +#define R_HASH_SRC (0x20 / 4) +#define R_HASH_DEST (0x24 / 4) +#define R_HASH_SRC_LEN (0x2c / 4) + +#define R_HASH_CMD (0x30 / 4) +/* Hash algorithm selection */ +#define HASH_ALGO_MASK (BIT(4) | BIT(5) | BIT(6)) +#define HASH_ALGO_MD5 0 +#define HASH_ALGO_SHA1 BIT(5) +#define HASH_ALGO_SHA224 BIT(6) +#define HASH_ALGO_SHA256 (BIT(4) | BIT(6)) +#define HASH_ALGO_SHA512_SERIES (BIT(5) | BIT(6)) +/* SHA512 algorithm selection */ +#define SHA512_HASH_ALGO_MASK (BIT(10) | BIT(11) | BIT(12)) +#define HASH_ALGO_SHA512_SHA512 0 +#define HASH_ALGO_SHA512_SHA384 BIT(10) +#define HASH_ALGO_SHA512_SHA256 BIT(11) +#define HASH_ALGO_SHA512_SHA224 (BIT(10) | BIT(11)) +/* HMAC modes */ +#define HASH_HMAC_MASK (BIT(7) | BIT(8)) +#define HASH_DIGEST 0 +#define HASH_DIGEST_HMAC BIT(7) +#define HASH_DIGEST_ACCUM BIT(8) +#define HASH_HMAC_KEY (BIT(7) | BIT(8)) +/* Cascaded operation modes */ +#define HASH_ONLY 0 +#define HASH_ONLY2 BIT(0) +#define HASH_CRYPT_THEN_HASH BIT(1) +#define HASH_HASH_THEN_CRYPT (BIT(0) | BIT(1)) +/* Other cmd bits */ +#define HASH_IRQ_EN BIT(9) +#define HASH_SG_EN BIT(18) +/* Scatter-gather data list */ +#define SG_LIST_LEN_SIZE 4 +#define SG_LIST_LEN_MASK 0x0FFFFFFF +#define SG_LIST_LEN_LAST BIT(31) +#define SG_LIST_ADDR_SIZE 4 +#define SG_LIST_ADDR_MASK 0x7FFFFFFF +#define SG_LIST_ENTRY_SIZE (SG_LIST_LEN_SIZE + SG_LIST_ADDR_SIZE) +#define ASPEED_HACE_MAX_SG 256 /* max number of entries */ + +static const struct { + uint32_t mask; + QCryptoHashAlgorithm algo; +} hash_algo_map[] = { + { HASH_ALGO_MD5, QCRYPTO_HASH_ALG_MD5 }, + { HASH_ALGO_SHA1, QCRYPTO_HASH_ALG_SHA1 }, + { HASH_ALGO_SHA224, QCRYPTO_HASH_ALG_SHA224 }, + { HASH_ALGO_SHA256, QCRYPTO_HASH_ALG_SHA256 }, + { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA512, QCRYPTO_HASH_ALG_SHA512 }, + { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA384, QCRYPTO_HASH_ALG_SHA384 }, + { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA256, QCRYPTO_HASH_ALG_SHA256 }, +}; + +static int hash_algo_lookup(uint32_t reg) +{ + int i; + + reg &= HASH_ALGO_MASK | SHA512_HASH_ALGO_MASK; + + for (i = 0; i < ARRAY_SIZE(hash_algo_map); i++) { + if (reg == hash_algo_map[i].mask) { + return hash_algo_map[i].algo; + } + } + + return -1; +} + +static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode) +{ + struct iovec iov[ASPEED_HACE_MAX_SG]; + g_autofree uint8_t *digest_buf; + size_t digest_len = 0; + int i; + + if (sg_mode) { + uint32_t len = 0; + + for (i = 0; !(len & SG_LIST_LEN_LAST); i++) { + uint32_t addr, src; + hwaddr plen; + + if (i == ASPEED_HACE_MAX_SG) { + qemu_log_mask(LOG_GUEST_ERROR, + "aspeed_hace: guest failed to set end of sg list marker\n"); + break; + } + + src = s->regs[R_HASH_SRC] + (i * SG_LIST_ENTRY_SIZE); + + len = address_space_ldl_le(&s->dram_as, src, + MEMTXATTRS_UNSPECIFIED, NULL); + + addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, + MEMTXATTRS_UNSPECIFIED, NULL); + addr &= SG_LIST_ADDR_MASK; + + iov[i].iov_len = len & SG_LIST_LEN_MASK; + plen = iov[i].iov_len; + iov[i].iov_base = address_space_map(&s->dram_as, addr, &plen, false, + MEMTXATTRS_UNSPECIFIED); + } + } else { + hwaddr len = s->regs[R_HASH_SRC_LEN]; + + iov[0].iov_len = len; + iov[0].iov_base = address_space_map(&s->dram_as, s->regs[R_HASH_SRC], + &len, false, + MEMTXATTRS_UNSPECIFIED); + i = 1; + } + + if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, &digest_len, NULL) < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); + return; + } + + if (address_space_write(&s->dram_as, s->regs[R_HASH_DEST], + MEMTXATTRS_UNSPECIFIED, + digest_buf, digest_len)) { + qemu_log_mask(LOG_GUEST_ERROR, + "aspeed_hace: address space write failed\n"); + } + + for (; i > 0; i--) { + address_space_unmap(&s->dram_as, iov[i - 1].iov_base, + iov[i - 1].iov_len, false, + iov[i - 1].iov_len); + } + + /* + * Set status bits to indicate completion. Testing shows hardware sets + * these irrespective of HASH_IRQ_EN. + */ + s->regs[R_STATUS] |= HASH_IRQ; +} + +static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) +{ + AspeedHACEState *s = ASPEED_HACE(opaque); + + addr >>= 2; + + if (addr >= ASPEED_HACE_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", + __func__, addr << 2); + return 0; + } + + return s->regs[addr]; +} + +static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, + unsigned int size) +{ + AspeedHACEState *s = ASPEED_HACE(opaque); + AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s); + + addr >>= 2; + + if (addr >= ASPEED_HACE_NR_REGS) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", + __func__, addr << 2); + return; + } + + switch (addr) { + case R_STATUS: + if (data & HASH_IRQ) { + data &= ~HASH_IRQ; + + if (s->regs[addr] & HASH_IRQ) { + qemu_irq_lower(s->irq); + } + } + break; + case R_HASH_SRC: + data &= ahc->src_mask; + break; + case R_HASH_DEST: + data &= ahc->dest_mask; + break; + case R_HASH_SRC_LEN: + data &= 0x0FFFFFFF; + break; + case R_HASH_CMD: { + int algo; + data &= ahc->hash_mask; + + if ((data & HASH_HMAC_MASK)) { + qemu_log_mask(LOG_UNIMP, + "%s: HMAC engine command mode %"PRIx64" not implemented", + __func__, (data & HASH_HMAC_MASK) >> 8); + } + if (data & BIT(1)) { + qemu_log_mask(LOG_UNIMP, + "%s: Cascaded mode not implemented", + __func__); + } + algo = hash_algo_lookup(data); + if (algo < 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid hash algorithm selection 0x%"PRIx64"\n", + __func__, data & ahc->hash_mask); + break; + } + do_hash_operation(s, algo, data & HASH_SG_EN); + + if (data & HASH_IRQ_EN) { + qemu_irq_raise(s->irq); + } + break; + } + case R_CRYPT_CMD: + qemu_log_mask(LOG_UNIMP, "%s: Crypt commands not implemented\n", + __func__); + break; + default: + break; + } + + s->regs[addr] = data; +} + +static const MemoryRegionOps aspeed_hace_ops = { + .read = aspeed_hace_read, + .write = aspeed_hace_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 4, + }, +}; + +static void aspeed_hace_reset(DeviceState *dev) +{ + struct AspeedHACEState *s = ASPEED_HACE(dev); + + memset(s->regs, 0, sizeof(s->regs)); +} + +static void aspeed_hace_realize(DeviceState *dev, Error **errp) +{ + AspeedHACEState *s = ASPEED_HACE(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + sysbus_init_irq(sbd, &s->irq); + + memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_hace_ops, s, + TYPE_ASPEED_HACE, 0x1000); + + if (!s->dram_mr) { + error_setg(errp, TYPE_ASPEED_HACE ": 'dram' link not set"); + return; + } + + address_space_init(&s->dram_as, s->dram_mr, "dram"); + + sysbus_init_mmio(sbd, &s->iomem); +} + +static Property aspeed_hace_properties[] = { + DEFINE_PROP_LINK("dram", AspeedHACEState, dram_mr, + TYPE_MEMORY_REGION, MemoryRegion *), + DEFINE_PROP_END_OF_LIST(), +}; + + +static const VMStateDescription vmstate_aspeed_hace = { + .name = TYPE_ASPEED_HACE, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, AspeedHACEState, ASPEED_HACE_NR_REGS), + VMSTATE_END_OF_LIST(), + } +}; + +static void aspeed_hace_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = aspeed_hace_realize; + dc->reset = aspeed_hace_reset; + device_class_set_props(dc, aspeed_hace_properties); + dc->vmsd = &vmstate_aspeed_hace; +} + +static const TypeInfo aspeed_hace_info = { + .name = TYPE_ASPEED_HACE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AspeedHACEState), + .class_init = aspeed_hace_class_init, + .class_size = sizeof(AspeedHACEClass) +}; + +static void aspeed_ast2400_hace_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); + + dc->desc = "AST2400 Hash and Crypto Engine"; + + ahc->src_mask = 0x0FFFFFFF; + ahc->dest_mask = 0x0FFFFFF8; + ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */ +} + +static const TypeInfo aspeed_ast2400_hace_info = { + .name = TYPE_ASPEED_AST2400_HACE, + .parent = TYPE_ASPEED_HACE, + .class_init = aspeed_ast2400_hace_class_init, +}; + +static void aspeed_ast2500_hace_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); + + dc->desc = "AST2500 Hash and Crypto Engine"; + + ahc->src_mask = 0x3fffffff; + ahc->dest_mask = 0x3ffffff8; + ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */ +} + +static const TypeInfo aspeed_ast2500_hace_info = { + .name = TYPE_ASPEED_AST2500_HACE, + .parent = TYPE_ASPEED_HACE, + .class_init = aspeed_ast2500_hace_class_init, +}; + +static void aspeed_ast2600_hace_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); + + dc->desc = "AST2600 Hash and Crypto Engine"; + + ahc->src_mask = 0x7FFFFFFF; + ahc->dest_mask = 0x7FFFFFF8; + ahc->hash_mask = 0x00147FFF; +} + +static const TypeInfo aspeed_ast2600_hace_info = { + .name = TYPE_ASPEED_AST2600_HACE, + .parent = TYPE_ASPEED_HACE, + .class_init = aspeed_ast2600_hace_class_init, +}; + +static void aspeed_hace_register_types(void) +{ + type_register_static(&aspeed_ast2400_hace_info); + type_register_static(&aspeed_ast2500_hace_info); + type_register_static(&aspeed_ast2600_hace_info); + type_register_static(&aspeed_hace_info); +} + +type_init(aspeed_hace_register_types); diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 21034dc60a..1e7b8b064b 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -109,6 +109,7 @@ softmmu_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c')) softmmu_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c')) softmmu_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c')) softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( + 'aspeed_hace.c', 'aspeed_lpc.c', 'aspeed_scu.c', 'aspeed_sdmc.c', diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h new file mode 100644 index 0000000000..94d5ada95f --- /dev/null +++ b/include/hw/misc/aspeed_hace.h @@ -0,0 +1,43 @@ +/* + * ASPEED Hash and Crypto Engine + * + * Copyright (C) 2021 IBM Corp. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef ASPEED_HACE_H +#define ASPEED_HACE_H + +#include "hw/sysbus.h" + +#define TYPE_ASPEED_HACE "aspeed.hace" +#define TYPE_ASPEED_AST2400_HACE TYPE_ASPEED_HACE "-ast2400" +#define TYPE_ASPEED_AST2500_HACE TYPE_ASPEED_HACE "-ast2500" +#define TYPE_ASPEED_AST2600_HACE TYPE_ASPEED_HACE "-ast2600" +OBJECT_DECLARE_TYPE(AspeedHACEState, AspeedHACEClass, ASPEED_HACE) + +#define ASPEED_HACE_NR_REGS (0x64 >> 2) + +struct AspeedHACEState { + SysBusDevice parent; + + MemoryRegion iomem; + qemu_irq irq; + + uint32_t regs[ASPEED_HACE_NR_REGS]; + + MemoryRegion *dram_mr; + AddressSpace dram_as; +}; + + +struct AspeedHACEClass { + SysBusDeviceClass parent_class; + + uint32_t src_mask; + uint32_t dest_mask; + uint32_t hash_mask; +}; + +#endif /* _ASPEED_HACE_H_ */ From a3888d757acdd92c4c49fb9cad5f5733d8280a86 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Sat, 1 May 2021 10:03:51 +0200 Subject: [PATCH 0125/3028] aspeed: Integrate HACE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the hash and crypto engine model to the Aspeed socs. Reviewed-by: Andrew Jeffery Reviewed-by: Cédric Le Goater Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Klaus Heinrich Kiwi Signed-off-by: Joel Stanley Message-Id: <20210409000253.1475587-3-joel@jms.id.au> Signed-off-by: Cédric Le Goater --- docs/system/arm/aspeed.rst | 1 - hw/arm/aspeed_ast2600.c | 15 +++++++++++++++ hw/arm/aspeed_soc.c | 16 ++++++++++++++++ include/hw/arm/aspeed_soc.h | 3 +++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index 23a1468cd1..a1911f9403 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -60,7 +60,6 @@ Missing devices * PWM and Fan Controller * Slave GPIO Controller * Super I/O Controller - * Hash/Crypto Engine * PCI-Express 1 Controller * Graphic Display Controller * PECI Controller diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 2a1255b6a0..e0fbb020c7 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -42,6 +42,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = { [ASPEED_DEV_ETH2] = 0x1E680000, [ASPEED_DEV_ETH4] = 0x1E690000, [ASPEED_DEV_VIC] = 0x1E6C0000, + [ASPEED_DEV_HACE] = 0x1E6D0000, [ASPEED_DEV_SDMC] = 0x1E6E0000, [ASPEED_DEV_SCU] = 0x1E6E2000, [ASPEED_DEV_XDMA] = 0x1E6E7000, @@ -102,6 +103,7 @@ static const int aspeed_soc_ast2600_irqmap[] = { [ASPEED_DEV_I2C] = 110, /* 110 -> 125 */ [ASPEED_DEV_ETH1] = 2, [ASPEED_DEV_ETH2] = 3, + [ASPEED_DEV_HACE] = 4, [ASPEED_DEV_ETH3] = 32, [ASPEED_DEV_ETH4] = 33, [ASPEED_DEV_KCS] = 138, /* 138 -> 142 */ @@ -213,6 +215,9 @@ static void aspeed_soc_ast2600_init(Object *obj) TYPE_SYSBUS_SDHCI); object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC); + + snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname); + object_initialize_child(obj, "hace", &s->hace, typename); } /* @@ -494,6 +499,16 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_4, qdev_get_gpio_in(DEVICE(&s->a7mpcore), sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_4)); + + /* HACE */ + object_property_set_link(OBJECT(&s->hace), "dram", OBJECT(s->dram_mr), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); } static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 817f3ba63d..8ed29113f7 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -34,6 +34,7 @@ static const hwaddr aspeed_soc_ast2400_memmap[] = { [ASPEED_DEV_VIC] = 0x1E6C0000, [ASPEED_DEV_SDMC] = 0x1E6E0000, [ASPEED_DEV_SCU] = 0x1E6E2000, + [ASPEED_DEV_HACE] = 0x1E6E3000, [ASPEED_DEV_XDMA] = 0x1E6E7000, [ASPEED_DEV_VIDEO] = 0x1E700000, [ASPEED_DEV_ADC] = 0x1E6E9000, @@ -65,6 +66,7 @@ static const hwaddr aspeed_soc_ast2500_memmap[] = { [ASPEED_DEV_VIC] = 0x1E6C0000, [ASPEED_DEV_SDMC] = 0x1E6E0000, [ASPEED_DEV_SCU] = 0x1E6E2000, + [ASPEED_DEV_HACE] = 0x1E6E3000, [ASPEED_DEV_XDMA] = 0x1E6E7000, [ASPEED_DEV_ADC] = 0x1E6E9000, [ASPEED_DEV_VIDEO] = 0x1E700000, @@ -117,6 +119,7 @@ static const int aspeed_soc_ast2400_irqmap[] = { [ASPEED_DEV_ETH2] = 3, [ASPEED_DEV_XDMA] = 6, [ASPEED_DEV_SDHCI] = 26, + [ASPEED_DEV_HACE] = 4, }; #define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap @@ -212,6 +215,9 @@ static void aspeed_soc_init(Object *obj) } object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC); + + snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname); + object_initialize_child(obj, "hace", &s->hace, typename); } static void aspeed_soc_realize(DeviceState *dev, Error **errp) @@ -421,6 +427,16 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_4, qdev_get_gpio_in(DEVICE(&s->lpc), aspeed_lpc_kcs_4)); + + /* HACE */ + object_property_set_link(OBJECT(&s->hace), "dram", OBJECT(s->dram_mr), + &error_abort); + if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); } static Property aspeed_soc_properties[] = { DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION, diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 9359d6da33..d9161d26d6 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -21,6 +21,7 @@ #include "hw/rtc/aspeed_rtc.h" #include "hw/i2c/aspeed_i2c.h" #include "hw/ssi/aspeed_smc.h" +#include "hw/misc/aspeed_hace.h" #include "hw/watchdog/wdt_aspeed.h" #include "hw/net/ftgmac100.h" #include "target/arm/cpu.h" @@ -50,6 +51,7 @@ struct AspeedSoCState { AspeedTimerCtrlState timerctrl; AspeedI2CState i2c; AspeedSCUState scu; + AspeedHACEState hace; AspeedXDMAState xdma; AspeedSMCState fmc; AspeedSMCState spi[ASPEED_SPIS_NUM]; @@ -133,6 +135,7 @@ enum { ASPEED_DEV_XDMA, ASPEED_DEV_EMMC, ASPEED_DEV_KCS, + ASPEED_DEV_HACE, }; #endif /* ASPEED_SOC_H */ From 666099520aabd27f1995efd54a34ae8522eb2602 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Sat, 1 May 2021 10:03:51 +0200 Subject: [PATCH 0126/3028] tests/qtest: Add test for Aspeed HACE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds a test for the Aspeed Hash and Crypto (HACE) engine. It tests the currently implemented behavior of the hash functionality. The tests are similar, but are cut/pasted instead of broken out into a common function so the assert machinery produces useful output when a test fails. Co-developed-by: Cédric Le Goater Co-developed-by: Klaus Heinrich Kiwi Reviewed-by: Cédric Le Goater Reviewed-by: Klaus Heinrich Kiwi Acked-by: Thomas Huth Signed-off-by: Joel Stanley Message-Id: <20210409000253.1475587-4-joel@jms.id.au> Signed-off-by: Cédric Le Goater --- MAINTAINERS | 1 + tests/qtest/aspeed_hace-test.c | 469 +++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 3 + 3 files changed, 473 insertions(+) create mode 100644 tests/qtest/aspeed_hace-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 36055f14c5..0d88146509 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1026,6 +1026,7 @@ F: include/hw/misc/pca9552*.h F: hw/net/ftgmac100.c F: include/hw/net/ftgmac100.h F: docs/system/arm/aspeed.rst +F: tests/qtest/*aspeed* NRF51 M: Joel Stanley diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c new file mode 100644 index 0000000000..09ee31545e --- /dev/null +++ b/tests/qtest/aspeed_hace-test.c @@ -0,0 +1,469 @@ +/* + * QTest testcase for the ASPEED Hash and Crypto Engine + * + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 IBM Corp. + */ + +#include "qemu/osdep.h" + +#include "libqos/libqtest.h" +#include "qemu-common.h" +#include "qemu/bitops.h" + +#define HACE_CMD 0x10 +#define HACE_SHA_BE_EN BIT(3) +#define HACE_MD5_LE_EN BIT(2) +#define HACE_ALGO_MD5 0 +#define HACE_ALGO_SHA1 BIT(5) +#define HACE_ALGO_SHA224 BIT(6) +#define HACE_ALGO_SHA256 (BIT(4) | BIT(6)) +#define HACE_ALGO_SHA512 (BIT(5) | BIT(6)) +#define HACE_ALGO_SHA384 (BIT(5) | BIT(6) | BIT(10)) +#define HACE_SG_EN BIT(18) + +#define HACE_STS 0x1c +#define HACE_RSA_ISR BIT(13) +#define HACE_CRYPTO_ISR BIT(12) +#define HACE_HASH_ISR BIT(9) +#define HACE_RSA_BUSY BIT(2) +#define HACE_CRYPTO_BUSY BIT(1) +#define HACE_HASH_BUSY BIT(0) +#define HACE_HASH_SRC 0x20 +#define HACE_HASH_DIGEST 0x24 +#define HACE_HASH_KEY_BUFF 0x28 +#define HACE_HASH_DATA_LEN 0x2c +#define HACE_HASH_CMD 0x30 +/* Scatter-Gather Hash */ +#define SG_LIST_LEN_LAST BIT(31) +struct AspeedSgList { + uint32_t len; + uint32_t addr; +} __attribute__ ((__packed__)); + +/* + * Test vector is the ascii "abc" + * + * Expected results were generated using command line utitiles: + * + * echo -n -e 'abc' | dd of=/tmp/test + * for hash in sha512sum sha256sum md5sum; do $hash /tmp/test; done + * + */ +static const uint8_t test_vector[] = {0x61, 0x62, 0x63}; + +static const uint8_t test_result_sha512[] = { + 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, + 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, + 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, + 0xa5, 0x4c, 0xa4, 0x9f}; + +static const uint8_t test_result_sha256[] = { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, + 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; + +static const uint8_t test_result_md5[] = { + 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, + 0x28, 0xe1, 0x7f, 0x72}; + +/* + * The Scatter-Gather Test vector is the ascii "abc" "def" "ghi", broken + * into blocks of 3 characters as shown + * + * Expected results were generated using command line utitiles: + * + * echo -n -e 'abcdefghijkl' | dd of=/tmp/test + * for hash in sha512sum sha256sum; do $hash /tmp/test; done + * + */ +static const uint8_t test_vector_sg1[] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66}; +static const uint8_t test_vector_sg2[] = {0x67, 0x68, 0x69}; +static const uint8_t test_vector_sg3[] = {0x6a, 0x6b, 0x6c}; + +static const uint8_t test_result_sg_sha512[] = { + 0x17, 0x80, 0x7c, 0x72, 0x8e, 0xe3, 0xba, 0x35, 0xe7, 0xcf, 0x7a, 0xf8, + 0x23, 0x11, 0x6d, 0x26, 0xe4, 0x1e, 0x5d, 0x4d, 0x6c, 0x2f, 0xf1, 0xf3, + 0x72, 0x0d, 0x3d, 0x96, 0xaa, 0xcb, 0x6f, 0x69, 0xde, 0x64, 0x2e, 0x63, + 0xd5, 0xb7, 0x3f, 0xc3, 0x96, 0xc1, 0x2b, 0xe3, 0x8b, 0x2b, 0xd5, 0xd8, + 0x84, 0x25, 0x7c, 0x32, 0xc8, 0xf6, 0xd0, 0x85, 0x4a, 0xe6, 0xb5, 0x40, + 0xf8, 0x6d, 0xda, 0x2e}; + +static const uint8_t test_result_sg_sha256[] = { + 0xd6, 0x82, 0xed, 0x4c, 0xa4, 0xd9, 0x89, 0xc1, 0x34, 0xec, 0x94, 0xf1, + 0x55, 0x1e, 0x1e, 0xc5, 0x80, 0xdd, 0x6d, 0x5a, 0x6e, 0xcd, 0xe9, 0xf3, + 0xd3, 0x5e, 0x6e, 0x4a, 0x71, 0x7f, 0xbd, 0xe4}; + + +static void write_regs(QTestState *s, uint32_t base, uint32_t src, + uint32_t length, uint32_t out, uint32_t method) +{ + qtest_writel(s, base + HACE_HASH_SRC, src); + qtest_writel(s, base + HACE_HASH_DIGEST, out); + qtest_writel(s, base + HACE_HASH_DATA_LEN, length); + qtest_writel(s, base + HACE_HASH_CMD, HACE_SHA_BE_EN | method); +} + +static void test_md5(const char *machine, const uint32_t base, + const uint32_t src_addr) + +{ + QTestState *s = qtest_init(machine); + + uint32_t digest_addr = src_addr + 0x01000000; + uint8_t digest[16] = {0}; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector)); + + write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_MD5); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_md5, sizeof(digest)); + + qtest_quit(s); +} + +static void test_sha256(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t digest_addr = src_addr + 0x1000000; + uint8_t digest[32] = {0}; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector)); + + write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_SHA256); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_sha256, sizeof(digest)); + + qtest_quit(s); +} + +static void test_sha512(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t digest_addr = src_addr + 0x1000000; + uint8_t digest[64] = {0}; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector)); + + write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_SHA512); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_sha512, sizeof(digest)); + + qtest_quit(s); +} + +static void test_sha256_sg(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t src_addr_1 = src_addr + 0x1000000; + const uint32_t src_addr_2 = src_addr + 0x2000000; + const uint32_t src_addr_3 = src_addr + 0x3000000; + const uint32_t digest_addr = src_addr + 0x4000000; + uint8_t digest[32] = {0}; + struct AspeedSgList array[] = { + { cpu_to_le32(sizeof(test_vector_sg1)), + cpu_to_le32(src_addr_1) }, + { cpu_to_le32(sizeof(test_vector_sg2)), + cpu_to_le32(src_addr_2) }, + { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST), + cpu_to_le32(src_addr_3) }, + }; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1)); + qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2)); + qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3)); + qtest_memwrite(s, src_addr, array, sizeof(array)); + + write_regs(s, base, src_addr, + (sizeof(test_vector_sg1) + + sizeof(test_vector_sg2) + + sizeof(test_vector_sg3)), + digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_sg_sha256, sizeof(digest)); + + qtest_quit(s); +} + +static void test_sha512_sg(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t src_addr_1 = src_addr + 0x1000000; + const uint32_t src_addr_2 = src_addr + 0x2000000; + const uint32_t src_addr_3 = src_addr + 0x3000000; + const uint32_t digest_addr = src_addr + 0x4000000; + uint8_t digest[64] = {0}; + struct AspeedSgList array[] = { + { cpu_to_le32(sizeof(test_vector_sg1)), + cpu_to_le32(src_addr_1) }, + { cpu_to_le32(sizeof(test_vector_sg2)), + cpu_to_le32(src_addr_2) }, + { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST), + cpu_to_le32(src_addr_3) }, + }; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1)); + qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2)); + qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3)); + qtest_memwrite(s, src_addr, array, sizeof(array)); + + write_regs(s, base, src_addr, + (sizeof(test_vector_sg1) + + sizeof(test_vector_sg2) + + sizeof(test_vector_sg3)), + digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_sg_sha512, sizeof(digest)); + + qtest_quit(s); +} + +struct masks { + uint32_t src; + uint32_t dest; + uint32_t len; +}; + +static const struct masks ast2600_masks = { + .src = 0x7fffffff, + .dest = 0x7ffffff8, + .len = 0x0fffffff, +}; + +static const struct masks ast2500_masks = { + .src = 0x3fffffff, + .dest = 0x3ffffff8, + .len = 0x0fffffff, +}; + +static const struct masks ast2400_masks = { + .src = 0x0fffffff, + .dest = 0x0ffffff8, + .len = 0x0fffffff, +}; + +static void test_addresses(const char *machine, const uint32_t base, + const struct masks *expected) +{ + QTestState *s = qtest_init(machine); + + /* + * Check command mode is zero, meaning engine is in direct access mode, + * as this affects the masking behavior of the HASH_SRC register. + */ + g_assert_cmphex(qtest_readl(s, base + HACE_CMD), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0); + + + /* Check that the address masking is correct */ + qtest_writel(s, base + HACE_HASH_SRC, 0xffffffff); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, expected->src); + + qtest_writel(s, base + HACE_HASH_DIGEST, 0xffffffff); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, expected->dest); + + qtest_writel(s, base + HACE_HASH_DATA_LEN, 0xffffffff); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, expected->len); + + /* Reset to zero */ + qtest_writel(s, base + HACE_HASH_SRC, 0); + qtest_writel(s, base + HACE_HASH_DIGEST, 0); + qtest_writel(s, base + HACE_HASH_DATA_LEN, 0); + + /* Check that all bits are now zero */ + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0); + + qtest_quit(s); +} + +/* ast2600 */ +static void test_md5_ast2600(void) +{ + test_md5("-machine ast2600-evb", 0x1e6d0000, 0x80000000); +} + +static void test_sha256_ast2600(void) +{ + test_sha256("-machine ast2600-evb", 0x1e6d0000, 0x80000000); +} + +static void test_sha256_sg_ast2600(void) +{ + test_sha256_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000); +} + +static void test_sha512_ast2600(void) +{ + test_sha512("-machine ast2600-evb", 0x1e6d0000, 0x80000000); +} + +static void test_sha512_sg_ast2600(void) +{ + test_sha512_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000); +} + +static void test_addresses_ast2600(void) +{ + test_addresses("-machine ast2600-evb", 0x1e6d0000, &ast2600_masks); +} + +/* ast2500 */ +static void test_md5_ast2500(void) +{ + test_md5("-machine ast2500-evb", 0x1e6e3000, 0x80000000); +} + +static void test_sha256_ast2500(void) +{ + test_sha256("-machine ast2500-evb", 0x1e6e3000, 0x80000000); +} + +static void test_sha512_ast2500(void) +{ + test_sha512("-machine ast2500-evb", 0x1e6e3000, 0x80000000); +} + +static void test_addresses_ast2500(void) +{ + test_addresses("-machine ast2500-evb", 0x1e6e3000, &ast2500_masks); +} + +/* ast2400 */ +static void test_md5_ast2400(void) +{ + test_md5("-machine palmetto-bmc", 0x1e6e3000, 0x40000000); +} + +static void test_sha256_ast2400(void) +{ + test_sha256("-machine palmetto-bmc", 0x1e6e3000, 0x40000000); +} + +static void test_sha512_ast2400(void) +{ + test_sha512("-machine palmetto-bmc", 0x1e6e3000, 0x40000000); +} + +static void test_addresses_ast2400(void) +{ + test_addresses("-machine palmetto-bmc", 0x1e6e3000, &ast2400_masks); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("ast2600/hace/addresses", test_addresses_ast2600); + qtest_add_func("ast2600/hace/sha512", test_sha512_ast2600); + qtest_add_func("ast2600/hace/sha256", test_sha256_ast2600); + qtest_add_func("ast2600/hace/md5", test_md5_ast2600); + + qtest_add_func("ast2600/hace/sha512_sg", test_sha512_sg_ast2600); + qtest_add_func("ast2600/hace/sha256_sg", test_sha256_sg_ast2600); + + qtest_add_func("ast2500/hace/addresses", test_addresses_ast2500); + qtest_add_func("ast2500/hace/sha512", test_sha512_ast2500); + qtest_add_func("ast2500/hace/sha256", test_sha256_ast2500); + qtest_add_func("ast2500/hace/md5", test_md5_ast2500); + + qtest_add_func("ast2400/hace/addresses", test_addresses_ast2400); + qtest_add_func("ast2400/hace/sha512", test_sha512_ast2400); + qtest_add_func("ast2400/hace/sha256", test_sha256_ast2400); + qtest_add_func("ast2400/hace/md5", test_md5_ast2400); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 0c76738921..f241ba0636 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -161,12 +161,15 @@ qtests_npcm7xx = \ 'npcm7xx_timer-test', 'npcm7xx_watchdog_timer-test'] + \ (slirp.found() ? ['npcm7xx_emc-test'] : []) +qtests_aspeed = \ + ['aspeed_hace-test'] qtests_arm = \ (config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \ (config_all_devices.has_key('CONFIG_CMSDK_APB_DUALTIMER') ? ['cmsdk-apb-dualtimer-test'] : []) + \ (config_all_devices.has_key('CONFIG_CMSDK_APB_TIMER') ? ['cmsdk-apb-timer-test'] : []) + \ (config_all_devices.has_key('CONFIG_CMSDK_APB_WATCHDOG') ? ['cmsdk-apb-watchdog-test'] : []) + \ (config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \ + (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed : []) + \ (config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \ ['arm-cpu-features', 'microbit-test', From a3a178c663eef3bc1a105e8d710f40ba44192ffd Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Sat, 1 May 2021 10:03:51 +0200 Subject: [PATCH 0127/3028] tests/acceptance: Test ast2400 and ast2500 machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test MTD images from the OpenBMC project on AST2400 and AST2500 SoCs from ASPEED, by booting Palmetto and Romulus BMC machines. The images are fetched from OpenBMC's release directory on github. Cc: Cleber Rosa Cc: Wainer dos Santos Moschetta Co-developed-by: Cédric Le Goater Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Signed-off-by: Joel Stanley Reviewed-by: Cleber Rosa Tested-by: Cleber Rosa [ clg : - removed comment - removed ending self.vm.shutdown() ] Signed-off-by: Cédric Le Goater Message-Id: <20210304123951.163411-2-joel@jms.id.au> Signed-off-by: Cédric Le Goater Reviewed-by: Willian Rampazzo Message-Id: <20210407171637.777743-12-clg@kaod.org> Signed-off-by: Cédric Le Goater --- tests/acceptance/boot_linux_console.py | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 1ca32ecf25..37bca73585 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -1010,6 +1010,49 @@ class BootLinuxConsole(LinuxKernelTest): self.vm.add_args('-dtb', self.workdir + '/day16/vexpress-v2p-ca9.dtb') self.do_test_advcal_2018('16', tar_hash, 'winter.zImage') + def test_arm_ast2400_palmetto_openbmc_v2_9_0(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:palmetto-bmc + """ + + image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/' + 'obmc-phosphor-image-palmetto.static.mtd') + image_hash = ('3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d') + image_path = self.fetch_asset(image_url, asset_hash=image_hash, + algorithm='sha256') + + self.do_test_arm_aspeed(image_path) + + def test_arm_ast2500_romulus_openbmc_v2_9_0(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:romulus-bmc + """ + + image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/' + 'obmc-phosphor-image-romulus.static.mtd') + image_hash = ('820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25') + image_path = self.fetch_asset(image_url, asset_hash=image_hash, + algorithm='sha256') + + self.do_test_arm_aspeed(image_path) + + def do_test_arm_aspeed(self, image): + self.vm.set_console() + self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', + '-net', 'nic') + self.vm.launch() + + self.wait_for_console_pattern("U-Boot 2016.07") + self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000") + self.wait_for_console_pattern("Starting kernel ...") + self.wait_for_console_pattern("Booting Linux on physical CPU 0x0") + self.wait_for_console_pattern( + "aspeed-smc 1e620000.spi: read control register: 203b0641") + self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ") + self.wait_for_console_pattern("systemd[1]: Set hostname to") + def test_m68k_mcf5208evb(self): """ :avocado: tags=arch:m68k From 224f010ba81ff25c972c33c1e13d79c85ed40e35 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Sat, 1 May 2021 10:03:51 +0200 Subject: [PATCH 0128/3028] tests/acceptance: Test ast2600 machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This tests a Debian multi-soc arm32 Linux kernel on the AST2600 based Tacoma BMC machine. There is no root file system so the test terminates when boot reaches the stage where it attempts and fails to mount something. Cc: Cleber Rosa Cc: Wainer dos Santos Moschetta Signed-off-by: Joel Stanley Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater [ clg : - removed comment - removed ending self.vm.shutdown() ] Signed-off-by: Cédric Le Goater Message-Id: <20210304123951.163411-3-joel@jms.id.au> Signed-off-by: Cédric Le Goater Reviewed-by: Willian Rampazzo Message-Id: <20210407171637.777743-13-clg@kaod.org> Signed-off-by: Cédric Le Goater --- tests/acceptance/boot_linux_console.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/acceptance/boot_linux_console.py b/tests/acceptance/boot_linux_console.py index 37bca73585..276a53f146 100644 --- a/tests/acceptance/boot_linux_console.py +++ b/tests/acceptance/boot_linux_console.py @@ -1053,6 +1053,31 @@ class BootLinuxConsole(LinuxKernelTest): self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ") self.wait_for_console_pattern("systemd[1]: Set hostname to") + def test_arm_ast2600_debian(self): + """ + :avocado: tags=arch:arm + :avocado: tags=machine:tacoma-bmc + """ + deb_url = ('http://snapshot.debian.org/archive/debian/' + '20210302T203551Z/' + 'pool/main/l/linux/' + 'linux-image-5.10.0-3-armmp_5.10.13-1_armhf.deb') + deb_hash = 'db40d32fe39255d05482bea48d72467b67d6225bb2a2a4d6f618cb8976f1e09e' + deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash, + algorithm='sha256') + kernel_path = self.extract_from_deb(deb_path, '/boot/vmlinuz-5.10.0-3-armmp') + dtb_path = self.extract_from_deb(deb_path, + '/usr/lib/linux-image-5.10.0-3-armmp/aspeed-bmc-opp-tacoma.dtb') + + self.vm.set_console() + self.vm.add_args('-kernel', kernel_path, + '-dtb', dtb_path, + '-net', 'nic') + self.vm.launch() + self.wait_for_console_pattern("Booting Linux on physical CPU 0xf00") + self.wait_for_console_pattern("SMP: Total of 2 processors activated") + self.wait_for_console_pattern("No filesystem could mount root") + def test_m68k_mcf5208evb(self): """ :avocado: tags=arch:m68k From 8efbee28f4729f16cae5cbf93a029bfa55198fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:52 +0200 Subject: [PATCH 0129/3028] hw/misc/aspeed_xdma: Add AST2600 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we introduced support for the AST2600 SoC, the XDMA controller was forgotten. It went unnoticed because it's not used under emulation. But the register layout being different, the reset procedure is bogus and this breaks kexec. Add a AspeedXDMAClass to take into account the register differences. Cc: Eddie James Signed-off-by: Cédric Le Goater Reviewed-by: Eddie James Message-Id: <20210407171637.777743-14-clg@kaod.org> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast2600.c | 3 +- hw/arm/aspeed_soc.c | 3 +- hw/misc/aspeed_xdma.c | 124 +++++++++++++++++++++++++++------- include/hw/misc/aspeed_xdma.h | 17 ++++- 4 files changed, 121 insertions(+), 26 deletions(-) diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index e0fbb020c7..c60824bfee 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -187,7 +187,8 @@ static void aspeed_soc_ast2600_init(Object *obj) object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII); } - object_initialize_child(obj, "xdma", &s->xdma, TYPE_ASPEED_XDMA); + snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname); + object_initialize_child(obj, "xdma", &s->xdma, typename); snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); object_initialize_child(obj, "gpio", &s->gpio, typename); diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 8ed29113f7..4a95d27d9d 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -199,7 +199,8 @@ static void aspeed_soc_init(Object *obj) TYPE_FTGMAC100); } - object_initialize_child(obj, "xdma", &s->xdma, TYPE_ASPEED_XDMA); + snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname); + object_initialize_child(obj, "xdma", &s->xdma, typename); snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); object_initialize_child(obj, "gpio", &s->gpio, typename); diff --git a/hw/misc/aspeed_xdma.c b/hw/misc/aspeed_xdma.c index 533d237e3c..1c21577c98 100644 --- a/hw/misc/aspeed_xdma.c +++ b/hw/misc/aspeed_xdma.c @@ -30,6 +30,19 @@ #define XDMA_IRQ_ENG_STAT_US_COMP BIT(4) #define XDMA_IRQ_ENG_STAT_DS_COMP BIT(5) #define XDMA_IRQ_ENG_STAT_RESET 0xF8000000 + +#define XDMA_AST2600_BMC_CMDQ_ADDR 0x14 +#define XDMA_AST2600_BMC_CMDQ_ENDP 0x18 +#define XDMA_AST2600_BMC_CMDQ_WRP 0x1c +#define XDMA_AST2600_BMC_CMDQ_RDP 0x20 +#define XDMA_AST2600_IRQ_CTRL 0x38 +#define XDMA_AST2600_IRQ_CTRL_US_COMP BIT(16) +#define XDMA_AST2600_IRQ_CTRL_DS_COMP BIT(17) +#define XDMA_AST2600_IRQ_CTRL_W_MASK 0x017003FF +#define XDMA_AST2600_IRQ_STATUS 0x3c +#define XDMA_AST2600_IRQ_STATUS_US_COMP BIT(16) +#define XDMA_AST2600_IRQ_STATUS_DS_COMP BIT(17) + #define XDMA_MEM_SIZE 0x1000 #define TO_REG(addr) ((addr) / sizeof(uint32_t)) @@ -52,56 +65,48 @@ static void aspeed_xdma_write(void *opaque, hwaddr addr, uint64_t val, unsigned int idx; uint32_t val32 = (uint32_t)val; AspeedXDMAState *xdma = opaque; + AspeedXDMAClass *axc = ASPEED_XDMA_GET_CLASS(xdma); if (addr >= ASPEED_XDMA_REG_SIZE) { return; } - switch (addr) { - case XDMA_BMC_CMDQ_ENDP: + if (addr == axc->cmdq_endp) { xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK; - break; - case XDMA_BMC_CMDQ_WRP: + } else if (addr == axc->cmdq_wrp) { idx = TO_REG(addr); xdma->regs[idx] = val32 & XDMA_BMC_CMDQ_W_MASK; - xdma->regs[TO_REG(XDMA_BMC_CMDQ_RDP)] = xdma->regs[idx]; + xdma->regs[TO_REG(axc->cmdq_rdp)] = xdma->regs[idx]; trace_aspeed_xdma_write(addr, val); if (xdma->bmc_cmdq_readp_set) { xdma->bmc_cmdq_readp_set = 0; } else { - xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] |= - XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP; + xdma->regs[TO_REG(axc->intr_status)] |= axc->intr_complete; - if (xdma->regs[TO_REG(XDMA_IRQ_ENG_CTRL)] & - (XDMA_IRQ_ENG_CTRL_US_COMP | XDMA_IRQ_ENG_CTRL_DS_COMP)) + if (xdma->regs[TO_REG(axc->intr_ctrl)] & axc->intr_complete) { qemu_irq_raise(xdma->irq); + } } - break; - case XDMA_BMC_CMDQ_RDP: + } else if (addr == axc->cmdq_rdp) { trace_aspeed_xdma_write(addr, val); if (val32 == XDMA_BMC_CMDQ_RDP_MAGIC) { xdma->bmc_cmdq_readp_set = 1; } - break; - case XDMA_IRQ_ENG_CTRL: - xdma->regs[TO_REG(addr)] = val32 & XDMA_IRQ_ENG_CTRL_W_MASK; - break; - case XDMA_IRQ_ENG_STAT: + } else if (addr == axc->intr_ctrl) { + xdma->regs[TO_REG(addr)] = val32 & axc->intr_ctrl_mask; + } else if (addr == axc->intr_status) { trace_aspeed_xdma_write(addr, val); idx = TO_REG(addr); - if (val32 & (XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP)) { - xdma->regs[idx] &= - ~(XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP); + if (val32 & axc->intr_complete) { + xdma->regs[idx] &= ~axc->intr_complete; qemu_irq_lower(xdma->irq); } - break; - default: + } else { xdma->regs[TO_REG(addr)] = val32; - break; } } @@ -127,10 +132,11 @@ static void aspeed_xdma_realize(DeviceState *dev, Error **errp) static void aspeed_xdma_reset(DeviceState *dev) { AspeedXDMAState *xdma = ASPEED_XDMA(dev); + AspeedXDMAClass *axc = ASPEED_XDMA_GET_CLASS(xdma); xdma->bmc_cmdq_readp_set = 0; memset(xdma->regs, 0, ASPEED_XDMA_REG_SIZE); - xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] = XDMA_IRQ_ENG_STAT_RESET; + xdma->regs[TO_REG(axc->intr_status)] = XDMA_IRQ_ENG_STAT_RESET; qemu_irq_lower(xdma->irq); } @@ -144,6 +150,73 @@ static const VMStateDescription aspeed_xdma_vmstate = { }, }; +static void aspeed_2600_xdma_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); + + dc->desc = "ASPEED 2600 XDMA Controller"; + + axc->cmdq_endp = XDMA_AST2600_BMC_CMDQ_ENDP; + axc->cmdq_wrp = XDMA_AST2600_BMC_CMDQ_WRP; + axc->cmdq_rdp = XDMA_AST2600_BMC_CMDQ_RDP; + axc->intr_ctrl = XDMA_AST2600_IRQ_CTRL; + axc->intr_ctrl_mask = XDMA_AST2600_IRQ_CTRL_W_MASK; + axc->intr_status = XDMA_AST2600_IRQ_STATUS; + axc->intr_complete = XDMA_AST2600_IRQ_STATUS_US_COMP | + XDMA_AST2600_IRQ_STATUS_DS_COMP; +} + +static const TypeInfo aspeed_2600_xdma_info = { + .name = TYPE_ASPEED_2600_XDMA, + .parent = TYPE_ASPEED_XDMA, + .class_init = aspeed_2600_xdma_class_init, +}; + +static void aspeed_2500_xdma_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); + + dc->desc = "ASPEED 2500 XDMA Controller"; + + axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP; + axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP; + axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP; + axc->intr_ctrl = XDMA_IRQ_ENG_CTRL; + axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK; + axc->intr_status = XDMA_IRQ_ENG_STAT; + axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP; +}; + +static const TypeInfo aspeed_2500_xdma_info = { + .name = TYPE_ASPEED_2500_XDMA, + .parent = TYPE_ASPEED_XDMA, + .class_init = aspeed_2500_xdma_class_init, +}; + +static void aspeed_2400_xdma_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); + + dc->desc = "ASPEED 2400 XDMA Controller"; + + axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP; + axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP; + axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP; + axc->intr_ctrl = XDMA_IRQ_ENG_CTRL; + axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK; + axc->intr_status = XDMA_IRQ_ENG_STAT; + axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP; +}; + +static const TypeInfo aspeed_2400_xdma_info = { + .name = TYPE_ASPEED_2400_XDMA, + .parent = TYPE_ASPEED_XDMA, + .class_init = aspeed_2400_xdma_class_init, +}; + static void aspeed_xdma_class_init(ObjectClass *classp, void *data) { DeviceClass *dc = DEVICE_CLASS(classp); @@ -158,10 +231,15 @@ static const TypeInfo aspeed_xdma_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(AspeedXDMAState), .class_init = aspeed_xdma_class_init, + .class_size = sizeof(AspeedXDMAClass), + .abstract = true, }; static void aspeed_xdma_register_type(void) { type_register_static(&aspeed_xdma_info); + type_register_static(&aspeed_2400_xdma_info); + type_register_static(&aspeed_2500_xdma_info); + type_register_static(&aspeed_2600_xdma_info); } type_init(aspeed_xdma_register_type); diff --git a/include/hw/misc/aspeed_xdma.h b/include/hw/misc/aspeed_xdma.h index a2dea96984..b1478fd1c6 100644 --- a/include/hw/misc/aspeed_xdma.h +++ b/include/hw/misc/aspeed_xdma.h @@ -13,7 +13,10 @@ #include "qom/object.h" #define TYPE_ASPEED_XDMA "aspeed.xdma" -OBJECT_DECLARE_SIMPLE_TYPE(AspeedXDMAState, ASPEED_XDMA) +#define TYPE_ASPEED_2400_XDMA TYPE_ASPEED_XDMA "-ast2400" +#define TYPE_ASPEED_2500_XDMA TYPE_ASPEED_XDMA "-ast2500" +#define TYPE_ASPEED_2600_XDMA TYPE_ASPEED_XDMA "-ast2600" +OBJECT_DECLARE_TYPE(AspeedXDMAState, AspeedXDMAClass, ASPEED_XDMA) #define ASPEED_XDMA_NUM_REGS (ASPEED_XDMA_REG_SIZE / sizeof(uint32_t)) #define ASPEED_XDMA_REG_SIZE 0x7C @@ -28,4 +31,16 @@ struct AspeedXDMAState { uint32_t regs[ASPEED_XDMA_NUM_REGS]; }; +struct AspeedXDMAClass { + SysBusDeviceClass parent_class; + + uint8_t cmdq_endp; + uint8_t cmdq_wrp; + uint8_t cmdq_rdp; + uint8_t intr_ctrl; + uint32_t intr_ctrl_mask; + uint8_t intr_status; + uint32_t intr_complete; +}; + #endif /* ASPEED_XDMA_H */ From 1c5ee69da5e65cc04055b304a784d82fd04de764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:52 +0200 Subject: [PATCH 0130/3028] aspeed/smc: Add a 'features' attribute to the object class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will simplify extensions of the SMC model. Signed-off-by: Cédric Le Goater Reviewed-by: Joel Stanley Message-Id: <20210407171637.777743-15-clg@kaod.org> Signed-off-by: Cédric Le Goater --- hw/ssi/aspeed_smc.c | 44 +++++++++++++++++++++---------------- include/hw/ssi/aspeed_smc.h | 2 +- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 50ea907aef..4521bbd486 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -257,6 +257,12 @@ static uint32_t aspeed_2600_smc_segment_to_reg(const AspeedSMCState *s, const AspeedSegments *seg); static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s, uint32_t reg, AspeedSegments *seg); +#define ASPEED_SMC_FEATURE_DMA 0x1 + +static inline bool aspeed_smc_has_dma(const AspeedSMCState *s) +{ + return !!(s->ctrl->features & ASPEED_SMC_FEATURE_DMA); +} static const AspeedSMCController controllers[] = { { @@ -271,7 +277,7 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_legacy, .flash_window_base = ASPEED_SOC_SMC_FLASH_BASE, .flash_window_size = 0x6000000, - .has_dma = false, + .features = 0x0, .nregs = ASPEED_SMC_R_SMC_MAX, .segment_to_reg = aspeed_smc_segment_to_reg, .reg_to_segment = aspeed_smc_reg_to_segment, @@ -287,7 +293,7 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_fmc, .flash_window_base = ASPEED_SOC_FMC_FLASH_BASE, .flash_window_size = 0x10000000, - .has_dma = true, + .features = ASPEED_SMC_FEATURE_DMA, .dma_flash_mask = 0x0FFFFFFC, .dma_dram_mask = 0x1FFFFFFC, .nregs = ASPEED_SMC_R_MAX, @@ -305,7 +311,7 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_spi, .flash_window_base = ASPEED_SOC_SPI_FLASH_BASE, .flash_window_size = 0x10000000, - .has_dma = false, + .features = 0x0, .nregs = ASPEED_SMC_R_SPI_MAX, .segment_to_reg = aspeed_smc_segment_to_reg, .reg_to_segment = aspeed_smc_reg_to_segment, @@ -321,7 +327,7 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_ast2500_fmc, .flash_window_base = ASPEED_SOC_FMC_FLASH_BASE, .flash_window_size = 0x10000000, - .has_dma = true, + .features = ASPEED_SMC_FEATURE_DMA, .dma_flash_mask = 0x0FFFFFFC, .dma_dram_mask = 0x3FFFFFFC, .nregs = ASPEED_SMC_R_MAX, @@ -339,7 +345,7 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_ast2500_spi1, .flash_window_base = ASPEED_SOC_SPI_FLASH_BASE, .flash_window_size = 0x8000000, - .has_dma = false, + .features = 0x0, .nregs = ASPEED_SMC_R_MAX, .segment_to_reg = aspeed_smc_segment_to_reg, .reg_to_segment = aspeed_smc_reg_to_segment, @@ -355,7 +361,7 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_ast2500_spi2, .flash_window_base = ASPEED_SOC_SPI2_FLASH_BASE, .flash_window_size = 0x8000000, - .has_dma = false, + .features = 0x0, .nregs = ASPEED_SMC_R_MAX, .segment_to_reg = aspeed_smc_segment_to_reg, .reg_to_segment = aspeed_smc_reg_to_segment, @@ -371,7 +377,7 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_ast2600_fmc, .flash_window_base = ASPEED26_SOC_FMC_FLASH_BASE, .flash_window_size = 0x10000000, - .has_dma = true, + .features = ASPEED_SMC_FEATURE_DMA, .dma_flash_mask = 0x0FFFFFFC, .dma_dram_mask = 0x3FFFFFFC, .nregs = ASPEED_SMC_R_MAX, @@ -389,7 +395,7 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_ast2600_spi1, .flash_window_base = ASPEED26_SOC_SPI_FLASH_BASE, .flash_window_size = 0x10000000, - .has_dma = true, + .features = ASPEED_SMC_FEATURE_DMA, .dma_flash_mask = 0x0FFFFFFC, .dma_dram_mask = 0x3FFFFFFC, .nregs = ASPEED_SMC_R_MAX, @@ -407,7 +413,7 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_ast2600_spi2, .flash_window_base = ASPEED26_SOC_SPI2_FLASH_BASE, .flash_window_size = 0x10000000, - .has_dma = true, + .features = ASPEED_SMC_FEATURE_DMA, .dma_flash_mask = 0x0FFFFFFC, .dma_dram_mask = 0x3FFFFFFC, .nregs = ASPEED_SMC_R_MAX, @@ -997,11 +1003,11 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) addr == R_CE_CMD_CTRL || addr == R_INTR_CTRL || addr == R_DUMMY_DATA || - (s->ctrl->has_dma && addr == R_DMA_CTRL) || - (s->ctrl->has_dma && addr == R_DMA_FLASH_ADDR) || - (s->ctrl->has_dma && addr == R_DMA_DRAM_ADDR) || - (s->ctrl->has_dma && addr == R_DMA_LEN) || - (s->ctrl->has_dma && addr == R_DMA_CHECKSUM) || + (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) || + (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR) || + (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR) || + (aspeed_smc_has_dma(s) && addr == R_DMA_LEN) || + (aspeed_smc_has_dma(s) && addr == R_DMA_CHECKSUM) || (addr >= R_SEG_ADDR0 && addr < R_SEG_ADDR0 + s->ctrl->max_peripherals) || (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->ctrl->max_peripherals)) { @@ -1290,13 +1296,13 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, s->regs[addr] = value & 0xff; } else if (addr == R_INTR_CTRL) { s->regs[addr] = value; - } else if (s->ctrl->has_dma && addr == R_DMA_CTRL) { + } else if (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) { aspeed_smc_dma_ctrl(s, value); - } else if (s->ctrl->has_dma && addr == R_DMA_DRAM_ADDR) { + } else if (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR) { s->regs[addr] = DMA_DRAM_ADDR(s, value); - } else if (s->ctrl->has_dma && addr == R_DMA_FLASH_ADDR) { + } else if (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR) { s->regs[addr] = DMA_FLASH_ADDR(s, value); - } else if (s->ctrl->has_dma && addr == R_DMA_LEN) { + } else if (aspeed_smc_has_dma(s) && addr == R_DMA_LEN) { s->regs[addr] = DMA_LENGTH(value); } else { qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", @@ -1412,7 +1418,7 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) } /* DMA support */ - if (s->ctrl->has_dma) { + if (aspeed_smc_has_dma(s)) { aspeed_smc_dma_setup(s, errp); } } diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index 6ea2871cd8..07879fd1c4 100644 --- a/include/hw/ssi/aspeed_smc.h +++ b/include/hw/ssi/aspeed_smc.h @@ -47,7 +47,7 @@ typedef struct AspeedSMCController { const AspeedSegments *segments; hwaddr flash_window_base; uint32_t flash_window_size; - bool has_dma; + uint32_t features; hwaddr dma_flash_mask; hwaddr dma_dram_mask; uint32_t nregs; From 1769a70e54181bb3e54783f16350892e847a3a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:52 +0200 Subject: [PATCH 0131/3028] aspeed/smc: Add extra controls to request DMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2600 SPI controllers have a set of bits to request/grant DMA access. Add a new SMC feature for these controllers and use it to check access to the DMA registers. Cc: Chin-Ting Kuo Signed-off-by: Cédric Le Goater Reviewed-by: Joel Stanley Message-Id: <20210407171637.777743-16-clg@kaod.org> Signed-off-by: Cédric Le Goater --- hw/ssi/aspeed_smc.c | 74 +++++++++++++++++++++++++++++++++---- include/hw/ssi/aspeed_smc.h | 1 + 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 4521bbd486..189b35637c 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -127,6 +127,8 @@ /* DMA Control/Status Register */ #define R_DMA_CTRL (0x80 / 4) +#define DMA_CTRL_REQUEST (1 << 31) +#define DMA_CTRL_GRANT (1 << 30) #define DMA_CTRL_DELAY_MASK 0xf #define DMA_CTRL_DELAY_SHIFT 8 #define DMA_CTRL_FREQ_MASK 0xf @@ -228,6 +230,7 @@ static uint32_t aspeed_smc_segment_to_reg(const AspeedSMCState *s, const AspeedSegments *seg); static void aspeed_smc_reg_to_segment(const AspeedSMCState *s, uint32_t reg, AspeedSegments *seg); +static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t value); /* * AST2600 definitions @@ -257,7 +260,10 @@ static uint32_t aspeed_2600_smc_segment_to_reg(const AspeedSMCState *s, const AspeedSegments *seg); static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s, uint32_t reg, AspeedSegments *seg); +static void aspeed_2600_smc_dma_ctrl(AspeedSMCState *s, uint32_t value); + #define ASPEED_SMC_FEATURE_DMA 0x1 +#define ASPEED_SMC_FEATURE_DMA_GRANT 0x2 static inline bool aspeed_smc_has_dma(const AspeedSMCState *s) { @@ -281,6 +287,7 @@ static const AspeedSMCController controllers[] = { .nregs = ASPEED_SMC_R_SMC_MAX, .segment_to_reg = aspeed_smc_segment_to_reg, .reg_to_segment = aspeed_smc_reg_to_segment, + .dma_ctrl = aspeed_smc_dma_ctrl, }, { .name = "aspeed.fmc-ast2400", .r_conf = R_CONF, @@ -299,6 +306,7 @@ static const AspeedSMCController controllers[] = { .nregs = ASPEED_SMC_R_MAX, .segment_to_reg = aspeed_smc_segment_to_reg, .reg_to_segment = aspeed_smc_reg_to_segment, + .dma_ctrl = aspeed_smc_dma_ctrl, }, { .name = "aspeed.spi1-ast2400", .r_conf = R_SPI_CONF, @@ -315,6 +323,7 @@ static const AspeedSMCController controllers[] = { .nregs = ASPEED_SMC_R_SPI_MAX, .segment_to_reg = aspeed_smc_segment_to_reg, .reg_to_segment = aspeed_smc_reg_to_segment, + .dma_ctrl = aspeed_smc_dma_ctrl, }, { .name = "aspeed.fmc-ast2500", .r_conf = R_CONF, @@ -333,6 +342,7 @@ static const AspeedSMCController controllers[] = { .nregs = ASPEED_SMC_R_MAX, .segment_to_reg = aspeed_smc_segment_to_reg, .reg_to_segment = aspeed_smc_reg_to_segment, + .dma_ctrl = aspeed_smc_dma_ctrl, }, { .name = "aspeed.spi1-ast2500", .r_conf = R_CONF, @@ -349,6 +359,7 @@ static const AspeedSMCController controllers[] = { .nregs = ASPEED_SMC_R_MAX, .segment_to_reg = aspeed_smc_segment_to_reg, .reg_to_segment = aspeed_smc_reg_to_segment, + .dma_ctrl = aspeed_smc_dma_ctrl, }, { .name = "aspeed.spi2-ast2500", .r_conf = R_CONF, @@ -365,6 +376,7 @@ static const AspeedSMCController controllers[] = { .nregs = ASPEED_SMC_R_MAX, .segment_to_reg = aspeed_smc_segment_to_reg, .reg_to_segment = aspeed_smc_reg_to_segment, + .dma_ctrl = aspeed_smc_dma_ctrl, }, { .name = "aspeed.fmc-ast2600", .r_conf = R_CONF, @@ -383,6 +395,7 @@ static const AspeedSMCController controllers[] = { .nregs = ASPEED_SMC_R_MAX, .segment_to_reg = aspeed_2600_smc_segment_to_reg, .reg_to_segment = aspeed_2600_smc_reg_to_segment, + .dma_ctrl = aspeed_2600_smc_dma_ctrl, }, { .name = "aspeed.spi1-ast2600", .r_conf = R_CONF, @@ -395,12 +408,14 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_ast2600_spi1, .flash_window_base = ASPEED26_SOC_SPI_FLASH_BASE, .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA, + .features = ASPEED_SMC_FEATURE_DMA | + ASPEED_SMC_FEATURE_DMA_GRANT, .dma_flash_mask = 0x0FFFFFFC, .dma_dram_mask = 0x3FFFFFFC, .nregs = ASPEED_SMC_R_MAX, .segment_to_reg = aspeed_2600_smc_segment_to_reg, .reg_to_segment = aspeed_2600_smc_reg_to_segment, + .dma_ctrl = aspeed_2600_smc_dma_ctrl, }, { .name = "aspeed.spi2-ast2600", .r_conf = R_CONF, @@ -413,12 +428,14 @@ static const AspeedSMCController controllers[] = { .segments = aspeed_segments_ast2600_spi2, .flash_window_base = ASPEED26_SOC_SPI2_FLASH_BASE, .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA, + .features = ASPEED_SMC_FEATURE_DMA | + ASPEED_SMC_FEATURE_DMA_GRANT, .dma_flash_mask = 0x0FFFFFFC, .dma_dram_mask = 0x3FFFFFFC, .nregs = ASPEED_SMC_R_MAX, .segment_to_reg = aspeed_2600_smc_segment_to_reg, .reg_to_segment = aspeed_2600_smc_reg_to_segment, + .dma_ctrl = aspeed_2600_smc_dma_ctrl, }, }; @@ -1240,7 +1257,7 @@ static void aspeed_smc_dma_done(AspeedSMCState *s) } } -static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint64_t dma_ctrl) +static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t dma_ctrl) { if (!(dma_ctrl & DMA_CTRL_ENABLE)) { s->regs[R_DMA_CTRL] = dma_ctrl; @@ -1265,6 +1282,46 @@ static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint64_t dma_ctrl) aspeed_smc_dma_done(s); } +static inline bool aspeed_smc_dma_granted(AspeedSMCState *s) +{ + if (!(s->ctrl->features & ASPEED_SMC_FEATURE_DMA_GRANT)) { + return true; + } + + if (!(s->regs[R_DMA_CTRL] & DMA_CTRL_GRANT)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA not granted\n", __func__); + return false; + } + + return true; +} + +static void aspeed_2600_smc_dma_ctrl(AspeedSMCState *s, uint32_t dma_ctrl) +{ + /* Preserve DMA bits */ + dma_ctrl |= s->regs[R_DMA_CTRL] & (DMA_CTRL_REQUEST | DMA_CTRL_GRANT); + + if (dma_ctrl == 0xAEED0000) { + /* automatically grant request */ + s->regs[R_DMA_CTRL] |= (DMA_CTRL_REQUEST | DMA_CTRL_GRANT); + return; + } + + /* clear request */ + if (dma_ctrl == 0xDEEA0000) { + s->regs[R_DMA_CTRL] &= ~(DMA_CTRL_REQUEST | DMA_CTRL_GRANT); + return; + } + + if (!aspeed_smc_dma_granted(s)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA not granted\n", __func__); + return; + } + + aspeed_smc_dma_ctrl(s, dma_ctrl); + s->regs[R_DMA_CTRL] &= ~(DMA_CTRL_REQUEST | DMA_CTRL_GRANT); +} + static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, unsigned int size) { @@ -1297,12 +1354,15 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, } else if (addr == R_INTR_CTRL) { s->regs[addr] = value; } else if (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) { - aspeed_smc_dma_ctrl(s, value); - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR) { + s->ctrl->dma_ctrl(s, value); + } else if (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR && + aspeed_smc_dma_granted(s)) { s->regs[addr] = DMA_DRAM_ADDR(s, value); - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR) { + } else if (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR && + aspeed_smc_dma_granted(s)) { s->regs[addr] = DMA_FLASH_ADDR(s, value); - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_LEN) { + } else if (aspeed_smc_has_dma(s) && addr == R_DMA_LEN && + aspeed_smc_dma_granted(s)) { s->regs[addr] = DMA_LENGTH(value); } else { qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index 07879fd1c4..cdaf165300 100644 --- a/include/hw/ssi/aspeed_smc.h +++ b/include/hw/ssi/aspeed_smc.h @@ -55,6 +55,7 @@ typedef struct AspeedSMCController { const AspeedSegments *seg); void (*reg_to_segment)(const struct AspeedSMCState *s, uint32_t reg, AspeedSegments *seg); + void (*dma_ctrl)(struct AspeedSMCState *s, uint32_t value); } AspeedSMCController; typedef struct AspeedSMCFlash { From 5fde7f10c0185929db15401ba72abd44b9abc466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:52 +0200 Subject: [PATCH 0132/3028] tests/qtest: Rename m25p80 test in aspeed_smc test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The m25p80 test depends on the Aspeed SMC controller to test our SPI-NOR flash support. Reflect this dependency by changing the name. Signed-off-by: Cédric Le Goater Reviewed-by: Joel Stanley Message-Id: <20210407171637.777743-17-clg@kaod.org> Signed-off-by: Cédric Le Goater --- tests/qtest/{m25p80-test.c => aspeed_smc-test.c} | 12 ++++++------ tests/qtest/meson.build | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) rename tests/qtest/{m25p80-test.c => aspeed_smc-test.c} (96%) diff --git a/tests/qtest/m25p80-test.c b/tests/qtest/aspeed_smc-test.c similarity index 96% rename from tests/qtest/m25p80-test.c rename to tests/qtest/aspeed_smc-test.c index f860cef5f0..87b40a0ef1 100644 --- a/tests/qtest/m25p80-test.c +++ b/tests/qtest/aspeed_smc-test.c @@ -367,12 +367,12 @@ int main(int argc, char **argv) "-drive file=%s,format=raw,if=mtd", tmp_path); - qtest_add_func("/m25p80/read_jedec", test_read_jedec); - qtest_add_func("/m25p80/erase_sector", test_erase_sector); - qtest_add_func("/m25p80/erase_all", test_erase_all); - qtest_add_func("/m25p80/write_page", test_write_page); - qtest_add_func("/m25p80/read_page_mem", test_read_page_mem); - qtest_add_func("/m25p80/write_page_mem", test_write_page_mem); + qtest_add_func("/ast2400/smc/read_jedec", test_read_jedec); + qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector); + qtest_add_func("/ast2400/smc/erase_all", test_erase_all); + qtest_add_func("/ast2400/smc/write_page", test_write_page); + qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem); + qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem); ret = g_test_run(); diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index f241ba0636..966bc93efa 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -162,7 +162,8 @@ qtests_npcm7xx = \ 'npcm7xx_watchdog_timer-test'] + \ (slirp.found() ? ['npcm7xx_emc-test'] : []) qtests_aspeed = \ - ['aspeed_hace-test'] + ['aspeed_hace-test', + 'aspeed_smc-test'] qtests_arm = \ (config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \ (config_all_devices.has_key('CONFIG_CMSDK_APB_DUALTIMER') ? ['cmsdk-apb-dualtimer-test'] : []) + \ @@ -173,7 +174,6 @@ qtests_arm = \ (config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \ ['arm-cpu-features', 'microbit-test', - 'm25p80-test', 'test-arm-mptimer', 'boot-serial-test', 'hexloader-test'] From 63a9c7e0a0ebb141c211112b164a0d31740d5031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:52 +0200 Subject: [PATCH 0133/3028] aspeed: Deprecate the swift-bmc machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SWIFT machine never came out of the lab and we already have enough AST2500 based OpenPower machines. Cc: Adriana Kobylak Signed-off-by: Cédric Le Goater --- docs/system/deprecated.rst | 7 +++++++ hw/arm/aspeed.c | 3 +++ 2 files changed, 10 insertions(+) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 80cae86252..f9169077ae 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -245,6 +245,13 @@ The Raspberry Pi machines come in various models (A, A+, B, B+). To be able to distinguish which model QEMU is implementing, the ``raspi2`` and ``raspi3`` machines have been renamed ``raspi2b`` and ``raspi3b``. +Aspeed ``swift-bmc`` machine (since 6.1) +'''''''''''''''''''''''''''''''''''''''' + +This machine is deprecated because we have enough AST2500 based OpenPOWER +machines. It can be easily replaced by the ``witherspoon-bmc`` or the +``romulus-bmc`` machines. + Device options -------------- diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 1cf5a15c80..cefa0f1352 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -811,6 +811,9 @@ static void aspeed_machine_swift_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 512 * MiB; mc->default_cpus = mc->min_cpus = mc->max_cpus = aspeed_soc_num_cpus(amc->soc_name); + + mc->deprecation_reason = "redundant system. Please use a similar " + "OpenPOWER BMC, Witherspoon or Romulus."; }; static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data) From 58e52bdb87675093c76f8febdca52e3398f11391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:52 +0200 Subject: [PATCH 0134/3028] aspeed: Add support for the rainier-bmc board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Rainier BMC board is a board for the middle range POWER10 IBM systems. Signed-off-by: Cédric Le Goater Reviewed-by: Joel Stanley Message-Id: <20210407171637.777743-19-clg@kaod.org> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index cefa0f1352..490a8a2022 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -146,6 +146,10 @@ struct AspeedMachineState { #define TACOMA_BMC_HW_STRAP1 0x00000000 #define TACOMA_BMC_HW_STRAP2 0x00000040 +/* Rainier hardware value: (QEMU prototype) */ +#define RAINIER_BMC_HW_STRAP1 0x00000000 +#define RAINIER_BMC_HW_STRAP2 0x00000000 + /* * The max ram region is for firmwares that scan the address space * with load/store to guess how much RAM the SoC has. @@ -629,6 +633,58 @@ static void g220a_bmc_i2c_init(AspeedMachineState *bmc) eeprom_buf); } +static void rainier_bmc_i2c_init(AspeedMachineState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + + /* The rainier expects a TMP275 but a TMP105 is compatible */ + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105, + 0x48); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105, + 0x49); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105, + 0x4a); + + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), TYPE_TMP105, + 0x48); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), TYPE_TMP105, + 0x49); + + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105, + 0x48); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105, + 0x4a); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105, + 0x4b); + + /* Bus 7: TODO dps310@76 */ + /* Bus 7: TODO max31785@52 */ + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "pca9552", 0x61); + /* Bus 7: TODO si7021-a20@20 */ + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), TYPE_TMP105, + 0x48); + + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_TMP105, + 0x48); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_TMP105, + 0x4a); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x61); + /* Bus 8: ucd90320@11 */ + /* Bus 8: ucd90320@b */ + /* Bus 8: ucd90320@c */ + + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4c); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4d); + + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4c); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4d); + + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), TYPE_TMP105, + 0x48); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), TYPE_TMP105, + 0x49); +} + static bool aspeed_get_mmio_exec(Object *obj, Error **errp) { return ASPEED_MACHINE(obj)->mmio_exec; @@ -889,6 +945,25 @@ static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data) aspeed_soc_num_cpus(amc->soc_name); }; +static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "IBM Rainier BMC (Cortex A7)"; + amc->soc_name = "ast2600-a1"; + amc->hw_strap1 = RAINIER_BMC_HW_STRAP1; + amc->hw_strap2 = RAINIER_BMC_HW_STRAP2; + amc->fmc_model = "mx66l1g45g"; + amc->spi_model = "mx66l1g45g"; + amc->num_cs = 2; + amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON; + amc->i2c_init = rainier_bmc_i2c_init; + mc->default_ram_size = 1 * GiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); +}; + static const TypeInfo aspeed_machine_types[] = { { .name = MACHINE_TYPE_NAME("palmetto-bmc"), @@ -930,6 +1005,10 @@ static const TypeInfo aspeed_machine_types[] = { .name = MACHINE_TYPE_NAME("g220a-bmc"), .parent = TYPE_ASPEED_MACHINE, .class_init = aspeed_machine_g220a_class_init, + }, { + .name = MACHINE_TYPE_NAME("rainier-bmc"), + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_machine_rainier_class_init, }, { .name = TYPE_ASPEED_MACHINE, .parent = TYPE_MACHINE, From d24aa3241a6248e183532381e479f6c49c33fc28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Sat, 1 May 2021 10:03:52 +0200 Subject: [PATCH 0135/3028] hw/block: m25p80: Add support for mt25ql02g and mt25qu02g MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Micron mt25ql02g is a 3V 2Gb serial NOR flash memory supporting dual I/O and quad I/O, 4KB, 32KB, 64KB sector erase. It also supports 4B opcodes. The mt25qu02g operates at 1.8V. https://4donline.ihs.com/images/VipMasterIC/IC/MICT/MICT-S-A0008500026/MICT-S-A0008511423-1.pdf?hkey=52A5661711E402568146F3353EA87419 Cc: Alistair Francis Cc: Francisco Iglesias Acked-by: Alistair Francis Reviewed-by: Francisco Iglesias Signed-off-by: Cédric Le Goater --- hw/block/m25p80.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 183d3f44c2..b77503dc84 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -259,6 +259,8 @@ static const FlashPartInfo known_devices[] = { { INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) }, { INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) }, { INFO_STACKED("mt25qu01g", 0x20bb21, 0x1040, 64 << 10, 2048, ER_4K, 2) }, + { INFO_STACKED("mt25ql02g", 0x20ba22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) }, + { INFO_STACKED("mt25qu02g", 0x20bb22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) }, /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). From 9cccb912cfa865f0bae6b156fa94e2f216dd8835 Mon Sep 17 00:00:00 2001 From: Patrick Venture Date: Sat, 1 May 2021 10:03:52 +0200 Subject: [PATCH 0136/3028] aspeed: Add support for the quanta-q7l1-bmc board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Quanta-Q71l BMC board is a board supported by OpenBMC. Tested: Booted quanta-q71l firmware. Signed-off-by: Patrick Venture Reviewed-by: Hao Wu Reviewed-by: Cédric Le Goater Message-Id: <20210416162426.3217033-1-venture@google.com> Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 490a8a2022..a10909fa83 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -138,6 +138,19 @@ struct AspeedMachineState { /* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */ #define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1 +/* Quanta-Q71l hardware value */ +#define QUANTA_Q71L_BMC_HW_STRAP1 ( \ + SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_128MB) | \ + SCU_AST2400_HW_STRAP_DRAM_CONFIG(2/* DDR3 with CL=6, CWL=5 */) | \ + SCU_AST2400_HW_STRAP_ACPI_DIS | \ + SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(AST2400_CLK_24M_IN) | \ + SCU_HW_STRAP_VGA_CLASS_CODE | \ + SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_PASS_THROUGH) | \ + SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(AST2400_CPU_AHB_RATIO_2_1) | \ + SCU_HW_STRAP_SPI_WIDTH | \ + SCU_HW_STRAP_VGA_SIZE_SET(VGA_8M_DRAM) | \ + SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT)) + /* AST2600 evb hardware value */ #define AST2600_EVB_HW_STRAP1 0x000000C0 #define AST2600_EVB_HW_STRAP2 0x00000003 @@ -437,6 +450,34 @@ static void palmetto_bmc_i2c_init(AspeedMachineState *bmc) object_property_set_int(OBJECT(dev), "temperature3", 110000, &error_abort); } +static void quanta_q71l_bmc_i2c_init(AspeedMachineState *bmc) +{ + AspeedSoCState *soc = &bmc->soc; + + /* + * The quanta-q71l platform expects tmp75s which are compatible with + * tmp105s. + */ + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4c); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4e); + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4f); + + /* TODO: i2c-1: Add baseboard FRU eeprom@54 24c64 */ + /* TODO: i2c-1: Add Frontpanel FRU eeprom@57 24c64 */ + /* TODO: Add Memory Riser i2c mux and eeproms. */ + + /* TODO: i2c-2: pca9546@74 */ + /* TODO: i2c-2: pca9548@77 */ + /* TODO: i2c-3: Add BIOS FRU eeprom@56 24c64 */ + /* TODO: i2c-7: Add pca9546@70 */ + /* - i2c@0: pmbus@59 */ + /* - i2c@1: pmbus@58 */ + /* - i2c@2: pmbus@58 */ + /* - i2c@3: pmbus@59 */ + /* TODO: i2c-7: Add PDB FRU eeprom@52 */ + /* TODO: i2c-8: Add BMC FRU eeprom@50 */ +} + static void ast2500_evb_i2c_init(AspeedMachineState *bmc) { AspeedSoCState *soc = &bmc->soc; @@ -784,6 +825,23 @@ static void aspeed_machine_palmetto_class_init(ObjectClass *oc, void *data) aspeed_soc_num_cpus(amc->soc_name); }; +static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); + + mc->desc = "Quanta-Q71l BMC (ARM926EJ-S)"; + amc->soc_name = "ast2400-a1"; + amc->hw_strap1 = QUANTA_Q71L_BMC_HW_STRAP1; + amc->fmc_model = "n25q256a"; + amc->spi_model = "mx25l25635e"; + amc->num_cs = 1; + amc->i2c_init = quanta_q71l_bmc_i2c_init; + mc->default_ram_size = 128 * MiB; + mc->default_cpus = mc->min_cpus = mc->max_cpus = + aspeed_soc_num_cpus(amc->soc_name); +} + static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc, void *data) { @@ -1005,6 +1063,10 @@ static const TypeInfo aspeed_machine_types[] = { .name = MACHINE_TYPE_NAME("g220a-bmc"), .parent = TYPE_ASPEED_MACHINE, .class_init = aspeed_machine_g220a_class_init, + }, { + .name = MACHINE_TYPE_NAME("quanta-q71l-bmc"), + .parent = TYPE_ASPEED_MACHINE, + .class_init = aspeed_machine_quanta_q71l_class_init, }, { .name = MACHINE_TYPE_NAME("rainier-bmc"), .parent = TYPE_ASPEED_MACHINE, From a27c100c23d2b23a8d5342b8d8d75e238f6342ba Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Sun, 14 Mar 2021 23:53:04 -0500 Subject: [PATCH 0137/3028] target/hexagon: translation changes Change cpu_ldl_code to translator_ldl. Don't end the TB after every packet when HEX_DEBUG is on. Make gen_check_store_width a simple call. Reported-by: Richard Henderson < Signed-off-by: Taylor Simpson Message-Id: <1615783984-25918-1-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/translate.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index eeaad5f8ba..2317508fa5 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -88,8 +88,8 @@ static int read_packet_words(CPUHexagonState *env, DisasContext *ctx, memset(words, 0, PACKET_WORDS_MAX * sizeof(uint32_t)); for (nwords = 0; !found_end && nwords < PACKET_WORDS_MAX; nwords++) { - words[nwords] = cpu_ldl_code(env, - ctx->base.pc_next + nwords * sizeof(uint32_t)); + words[nwords] = + translator_ldl(env, ctx->base.pc_next + nwords * sizeof(uint32_t)); found_end = is_packet_end(words[nwords]); } if (!found_end) { @@ -292,20 +292,16 @@ static void gen_pred_writes(DisasContext *ctx, Packet *pkt) tcg_temp_free(pval); } -#if HEX_DEBUG -static inline void gen_check_store_width(DisasContext *ctx, int slot_num) +static void gen_check_store_width(DisasContext *ctx, int slot_num) { +#if HEX_DEBUG TCGv slot = tcg_const_tl(slot_num); TCGv check = tcg_const_tl(ctx->store_width[slot_num]); gen_helper_debug_check_store_width(cpu_env, slot, check); tcg_temp_free(slot); tcg_temp_free(check); -} -#define HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num) \ - gen_check_store_width(ctx, slot_num) -#else -#define HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num) /* nothing */ #endif +} static bool slot_is_predicated(Packet *pkt, int slot_num) { @@ -355,25 +351,25 @@ void process_store(DisasContext *ctx, Packet *pkt, int slot_num) */ switch (ctx->store_width[slot_num]) { case 1: - HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num); + gen_check_store_width(ctx, slot_num); tcg_gen_qemu_st8(hex_store_val32[slot_num], hex_store_addr[slot_num], ctx->mem_idx); break; case 2: - HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num); + gen_check_store_width(ctx, slot_num); tcg_gen_qemu_st16(hex_store_val32[slot_num], hex_store_addr[slot_num], ctx->mem_idx); break; case 4: - HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num); + gen_check_store_width(ctx, slot_num); tcg_gen_qemu_st32(hex_store_val32[slot_num], hex_store_addr[slot_num], ctx->mem_idx); break; case 8: - HEX_DEBUG_GEN_CHECK_STORE_WIDTH(ctx, slot_num); + gen_check_store_width(ctx, slot_num); tcg_gen_qemu_st64(hex_store_val64[slot_num], hex_store_addr[slot_num], ctx->mem_idx); @@ -593,10 +589,6 @@ static void hexagon_tr_translate_packet(DisasContextBase *dcbase, CPUState *cpu) if (hex_cpu->lldb_compat && qemu_loglevel_mask(CPU_LOG_TB_CPU)) { ctx->base.is_jmp = DISAS_TOO_MANY; } -#if HEX_DEBUG - /* When debugging, only put one packet per TB */ - ctx->base.is_jmp = DISAS_TOO_MANY; -#endif } } From 4c82c2b433fab9814000e7794d9168044863ecfc Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Sun, 14 Mar 2021 23:53:57 -0500 Subject: [PATCH 0138/3028] target/hexagon: remove unnecessary checks in find_iclass_slots Reported-by: Richard Henderson < Signed-off-by: Taylor Simpson Message-Id: <1615784037-26129-1-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/iclass.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/target/hexagon/iclass.c b/target/hexagon/iclass.c index 378d8a6a75..6091286993 100644 --- a/target/hexagon/iclass.c +++ b/target/hexagon/iclass.c @@ -53,10 +53,6 @@ SlotMask find_iclass_slots(Opcode opcode, int itype) (opcode == Y2_isync) || (opcode == J2_pause) || (opcode == J4_hintjumpr)) { return SLOTS_2; - } else if ((itype == ICLASS_V2LDST) && (GET_ATTRIB(opcode, A_STORE))) { - return SLOTS_01; - } else if ((itype == ICLASS_V2LDST) && (!GET_ATTRIB(opcode, A_STORE))) { - return SLOTS_01; } else if (GET_ATTRIB(opcode, A_CRSLOT23)) { return SLOTS_23; } else if (GET_ATTRIB(opcode, A_RESTRICT_PREFERSLOT0)) { From 1de468b3987e6a85bc0a046d444bf76659242dd1 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Sun, 14 Mar 2021 23:54:09 -0500 Subject: [PATCH 0139/3028] target/hexagon: Change DECODE_MAPPED_REG operand name to OPNUM Reported-by: Richard Henderson < Signed-off-by: Taylor Simpson Message-Id: <1615784049-26215-1-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/decode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index c9bacaa1ee..1c9c07412a 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -48,8 +48,8 @@ enum { DEF_REGMAP(R_16, 16, 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23) DEF_REGMAP(R__8, 8, 0, 2, 4, 6, 16, 18, 20, 22) -#define DECODE_MAPPED_REG(REGNO, NAME) \ - insn->regno[REGNO] = DECODE_REGISTER_##NAME[insn->regno[REGNO]]; +#define DECODE_MAPPED_REG(OPNUM, NAME) \ + insn->regno[OPNUM] = DECODE_REGISTER_##NAME[insn->regno[OPNUM]]; typedef struct { const struct DectreeTable *table_link; From d9099caf04bda396e084429d3dd3f6601e23b7ca Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Sun, 14 Mar 2021 23:55:15 -0500 Subject: [PATCH 0140/3028] target/hexagon: fix typo in comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Taylor Simpson Message-Id: <1615784115-26559-1-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/op_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 2c6d718579..d6b5c47500 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -298,7 +298,7 @@ int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS) } /* - * Hexagon FP operations return ~0 insteat of NaN + * Hexagon FP operations return ~0 instead of NaN * The hex_check_sfnan/hex_check_dfnan functions perform this check */ static float32 hex_check_sfnan(float32 x) From 5f261764cec291bb159ffecd291a1bfd6800215b Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Sun, 14 Mar 2021 23:55:00 -0500 Subject: [PATCH 0141/3028] target/hexagon: remove unnecessary semicolons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reported-by: Richard Henderson < Signed-off-by: Taylor Simpson Message-Id: <1615784100-26459-1-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/gen_tcg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index e044deaff2..a30048ee57 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -83,9 +83,9 @@ #define fGEN_TCG_L2_loadrub_pr(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrub_pi(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrb_pr(SHORTCODE) SHORTCODE -#define fGEN_TCG_L2_loadrb_pi(SHORTCODE) SHORTCODE; +#define fGEN_TCG_L2_loadrb_pi(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadruh_pr(SHORTCODE) SHORTCODE -#define fGEN_TCG_L2_loadruh_pi(SHORTCODE) SHORTCODE; +#define fGEN_TCG_L2_loadruh_pi(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrh_pr(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrh_pi(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadri_pr(SHORTCODE) SHORTCODE From d799f8ad08742e9c042e208d970febf87a2c4901 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:29 -0500 Subject: [PATCH 0142/3028] Hexagon (target/hexagon) TCG generation cleanup Simplify TCG generation of hex_reg_written Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-2-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/genptr.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 7481f4c1dd..87f5d92994 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -35,7 +35,6 @@ static inline TCGv gen_read_preg(TCGv pred, uint8_t num) static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot) { - TCGv one = tcg_const_tl(1); TCGv zero = tcg_const_tl(0); TCGv slot_mask = tcg_temp_new(); @@ -43,12 +42,17 @@ static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot) tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], slot_mask, zero, val, hex_new_value[rnum]); #if HEX_DEBUG - /* Do this so HELPER(debug_commit_end) will know */ - tcg_gen_movcond_tl(TCG_COND_EQ, hex_reg_written[rnum], slot_mask, zero, - one, hex_reg_written[rnum]); + /* + * Do this so HELPER(debug_commit_end) will know + * + * Note that slot_mask indicates the value is not written + * (i.e., slot was cancelled), so we create a true/false value before + * or'ing with hex_reg_written[rnum]. + */ + tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero); + tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask); #endif - tcg_temp_free(one); tcg_temp_free(zero); tcg_temp_free(slot_mask); } From edf26ade436f69c170e7eec77d4b5d1d2db78d3f Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:30 -0500 Subject: [PATCH 0143/3028] Hexagon (target/hexagon) cleanup gen_log_predicated_reg_write_pair Similar to previous cleanup of gen_log_predicated_reg_write Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-3-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/genptr.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 87f5d92994..07d970fc6c 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -69,36 +69,35 @@ static inline void gen_log_reg_write(int rnum, TCGv val) static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot) { TCGv val32 = tcg_temp_new(); - TCGv one = tcg_const_tl(1); TCGv zero = tcg_const_tl(0); TCGv slot_mask = tcg_temp_new(); tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot); /* Low word */ tcg_gen_extrl_i64_i32(val32, val); - tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], slot_mask, zero, - val32, hex_new_value[rnum]); -#if HEX_DEBUG - /* Do this so HELPER(debug_commit_end) will know */ - tcg_gen_movcond_tl(TCG_COND_EQ, hex_reg_written[rnum], + tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], slot_mask, zero, - one, hex_reg_written[rnum]); -#endif - + val32, hex_new_value[rnum]); /* High word */ tcg_gen_extrh_i64_i32(val32, val); tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum + 1], slot_mask, zero, val32, hex_new_value[rnum + 1]); #if HEX_DEBUG - /* Do this so HELPER(debug_commit_end) will know */ - tcg_gen_movcond_tl(TCG_COND_EQ, hex_reg_written[rnum + 1], - slot_mask, zero, - one, hex_reg_written[rnum + 1]); + /* + * Do this so HELPER(debug_commit_end) will know + * + * Note that slot_mask indicates the value is not written + * (i.e., slot was cancelled), so we create a true/false value before + * or'ing with hex_reg_written[rnum]. + */ + tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero); + tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask); + tcg_gen_or_tl(hex_reg_written[rnum + 1], hex_reg_written[rnum + 1], + slot_mask); #endif tcg_temp_free(val32); - tcg_temp_free(one); tcg_temp_free(zero); tcg_temp_free(slot_mask); } From 2d27cebbf8994621e0a4bda9609d24982f5ba8c6 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:31 -0500 Subject: [PATCH 0144/3028] Hexagon (target/hexagon) remove unnecessary inline directives Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-4-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/cpu.c | 9 ++++----- target/hexagon/decode.c | 6 +++--- target/hexagon/fma_emu.c | 39 +++++++++++++++++++------------------- target/hexagon/op_helper.c | 37 ++++++++++++++++++------------------ target/hexagon/translate.c | 2 +- 5 files changed, 46 insertions(+), 47 deletions(-) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index b0b3040dd1..c2fe357702 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -69,10 +69,9 @@ const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = { * stacks at different locations. This is used to compensate so the diff is * cleaner. */ -static inline target_ulong adjust_stack_ptrs(CPUHexagonState *env, - target_ulong addr) +static target_ulong adjust_stack_ptrs(CPUHexagonState *env, target_ulong addr) { - HexagonCPU *cpu = container_of(env, HexagonCPU, env); + HexagonCPU *cpu = hexagon_env_get_cpu(env); target_ulong stack_adjust = cpu->lldb_stack_adjust; target_ulong stack_start = env->stack_start; target_ulong stack_size = 0x10000; @@ -88,7 +87,7 @@ static inline target_ulong adjust_stack_ptrs(CPUHexagonState *env, } /* HEX_REG_P3_0 (aka C4) is an alias for the predicate registers */ -static inline target_ulong read_p3_0(CPUHexagonState *env) +static target_ulong read_p3_0(CPUHexagonState *env) { int32_t control_reg = 0; int i; @@ -116,7 +115,7 @@ static void print_reg(FILE *f, CPUHexagonState *env, int regnum) static void hexagon_dump(CPUHexagonState *env, FILE *f) { - HexagonCPU *cpu = container_of(env, HexagonCPU, env); + HexagonCPU *cpu = hexagon_env_get_cpu(env); if (cpu->lldb_compat) { /* diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index 1c9c07412a..65d97ce64b 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -354,7 +354,7 @@ static void decode_split_cmpjump(Packet *pkt) } } -static inline int decode_opcode_can_jump(int opcode) +static int decode_opcode_can_jump(int opcode) { if ((GET_ATTRIB(opcode, A_JUMP)) || (GET_ATTRIB(opcode, A_CALL)) || @@ -370,7 +370,7 @@ static inline int decode_opcode_can_jump(int opcode) return 0; } -static inline int decode_opcode_ends_loop(int opcode) +static int decode_opcode_ends_loop(int opcode) { return GET_ATTRIB(opcode, A_HWLOOP0_END) || GET_ATTRIB(opcode, A_HWLOOP1_END); @@ -764,7 +764,7 @@ static void decode_add_endloop_insn(Insn *insn, int loopnum) } } -static inline int decode_parsebits_is_loopend(uint32_t encoding32) +static int decode_parsebits_is_loopend(uint32_t encoding32) { uint32_t bits = parse_bits(encoding32); return bits == 0x2; diff --git a/target/hexagon/fma_emu.c b/target/hexagon/fma_emu.c index 842d903710..f324b83e3c 100644 --- a/target/hexagon/fma_emu.c +++ b/target/hexagon/fma_emu.c @@ -64,7 +64,7 @@ typedef union { }; } Float; -static inline uint64_t float64_getmant(float64 f64) +static uint64_t float64_getmant(float64 f64) { Double a = { .i = f64 }; if (float64_is_normal(f64)) { @@ -91,7 +91,7 @@ int32_t float64_getexp(float64 f64) return -1; } -static inline uint64_t float32_getmant(float32 f32) +static uint64_t float32_getmant(float32 f32) { Float a = { .i = f32 }; if (float32_is_normal(f32)) { @@ -118,17 +118,17 @@ int32_t float32_getexp(float32 f32) return -1; } -static inline uint32_t int128_getw0(Int128 x) +static uint32_t int128_getw0(Int128 x) { return int128_getlo(x); } -static inline uint32_t int128_getw1(Int128 x) +static uint32_t int128_getw1(Int128 x) { return int128_getlo(x) >> 32; } -static inline Int128 int128_mul_6464(uint64_t ai, uint64_t bi) +static Int128 int128_mul_6464(uint64_t ai, uint64_t bi) { Int128 a, b; uint64_t pp0, pp1a, pp1b, pp1s, pp2; @@ -152,7 +152,7 @@ static inline Int128 int128_mul_6464(uint64_t ai, uint64_t bi) return int128_make128(ret_low, pp2 + (pp1s >> 32)); } -static inline Int128 int128_sub_borrow(Int128 a, Int128 b, int borrow) +static Int128 int128_sub_borrow(Int128 a, Int128 b, int borrow) { Int128 ret = int128_sub(a, b); if (borrow != 0) { @@ -170,7 +170,7 @@ typedef struct { uint8_t sticky; } Accum; -static inline void accum_init(Accum *p) +static void accum_init(Accum *p) { p->mant = int128_zero(); p->exp = 0; @@ -180,7 +180,7 @@ static inline void accum_init(Accum *p) p->sticky = 0; } -static inline Accum accum_norm_left(Accum a) +static Accum accum_norm_left(Accum a) { a.exp--; a.mant = int128_lshift(a.mant, 1); @@ -190,6 +190,7 @@ static inline Accum accum_norm_left(Accum a) return a; } +/* This function is marked inline for performance reasons */ static inline Accum accum_norm_right(Accum a, int amt) { if (amt > 130) { @@ -226,7 +227,7 @@ static inline Accum accum_norm_right(Accum a, int amt) */ static Accum accum_add(Accum a, Accum b); -static inline Accum accum_sub(Accum a, Accum b, int negate) +static Accum accum_sub(Accum a, Accum b, int negate) { Accum ret; accum_init(&ret); @@ -329,7 +330,7 @@ static Accum accum_add(Accum a, Accum b) } /* Return an infinity with requested sign */ -static inline float64 infinite_float64(uint8_t sign) +static float64 infinite_float64(uint8_t sign) { if (sign) { return make_float64(DF_MINUS_INF); @@ -339,7 +340,7 @@ static inline float64 infinite_float64(uint8_t sign) } /* Return a maximum finite value with requested sign */ -static inline float64 maxfinite_float64(uint8_t sign) +static float64 maxfinite_float64(uint8_t sign) { if (sign) { return make_float64(DF_MINUS_MAXF); @@ -349,7 +350,7 @@ static inline float64 maxfinite_float64(uint8_t sign) } /* Return a zero value with requested sign */ -static inline float64 zero_float64(uint8_t sign) +static float64 zero_float64(uint8_t sign) { if (sign) { return make_float64(0x8000000000000000); @@ -369,7 +370,7 @@ float32 infinite_float32(uint8_t sign) } /* Return a maximum finite value with the requested sign */ -static inline float32 maxfinite_float32(uint8_t sign) +static float32 maxfinite_float32(uint8_t sign) { if (sign) { return make_float32(SF_MINUS_MAXF); @@ -379,7 +380,7 @@ static inline float32 maxfinite_float32(uint8_t sign) } /* Return a zero value with requested sign */ -static inline float32 zero_float32(uint8_t sign) +static float32 zero_float32(uint8_t sign) { if (sign) { return make_float32(0x80000000); @@ -389,7 +390,7 @@ static inline float32 zero_float32(uint8_t sign) } #define GEN_XF_ROUND(SUFFIX, MANTBITS, INF_EXP, INTERNAL_TYPE) \ -static inline SUFFIX accum_round_##SUFFIX(Accum a, float_status * fp_status) \ +static SUFFIX accum_round_##SUFFIX(Accum a, float_status * fp_status) \ { \ if ((int128_gethi(a.mant) == 0) && (int128_getlo(a.mant) == 0) \ && ((a.guard | a.round | a.sticky) == 0)) { \ @@ -526,8 +527,8 @@ static bool is_inf_prod(float64 a, float64 b) (float64_is_infinity(b) && is_finite(a) && (!float64_is_zero(a)))); } -static inline float64 special_fma(float64 a, float64 b, float64 c, - float_status *fp_status) +static float64 special_fma(float64 a, float64 b, float64 c, + float_status *fp_status) { float64 ret = make_float64(0); @@ -586,8 +587,8 @@ static inline float64 special_fma(float64 a, float64 b, float64 c, g_assert_not_reached(); } -static inline float32 special_fmaf(float32 a, float32 b, float32 c, - float_status *fp_status) +static float32 special_fmaf(float32 a, float32 b, float32 c, + float_status *fp_status) { float64 aa, bb, cc; aa = float32_to_float64(a, fp_status); diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index d6b5c47500..5d35dfc8f3 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -46,8 +46,8 @@ void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp) do_raise_exception_err(env, excp, 0); } -static inline void log_reg_write(CPUHexagonState *env, int rnum, - target_ulong val, uint32_t slot) +static void log_reg_write(CPUHexagonState *env, int rnum, + target_ulong val, uint32_t slot) { HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")", rnum, val, val); @@ -63,8 +63,7 @@ static inline void log_reg_write(CPUHexagonState *env, int rnum, #endif } -static inline void log_pred_write(CPUHexagonState *env, int pnum, - target_ulong val) +static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val) { HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n", @@ -79,8 +78,8 @@ static inline void log_pred_write(CPUHexagonState *env, int pnum, } } -static inline void log_store32(CPUHexagonState *env, target_ulong addr, - target_ulong val, int width, int slot) +static void log_store32(CPUHexagonState *env, target_ulong addr, + target_ulong val, int width, int slot) { HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx ", %" PRId32 " [0x08%" PRIx32 "])\n", @@ -90,8 +89,8 @@ static inline void log_store32(CPUHexagonState *env, target_ulong addr, env->mem_log_stores[slot].data32 = val; } -static inline void log_store64(CPUHexagonState *env, target_ulong addr, - int64_t val, int width, int slot) +static void log_store64(CPUHexagonState *env, target_ulong addr, + int64_t val, int width, int slot) { HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx ", %" PRId64 " [0x016%" PRIx64 "])\n", @@ -101,7 +100,7 @@ static inline void log_store64(CPUHexagonState *env, target_ulong addr, env->mem_log_stores[slot].data64 = val; } -static inline void write_new_pc(CPUHexagonState *env, target_ulong addr) +static void write_new_pc(CPUHexagonState *env, target_ulong addr) { HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr); @@ -132,7 +131,7 @@ void HELPER(debug_start_packet)(CPUHexagonState *env) } #endif -static inline int32_t new_pred_value(CPUHexagonState *env, int pnum) +static int32_t new_pred_value(CPUHexagonState *env, int pnum) { return env->new_pred_value[pnum]; } @@ -332,8 +331,8 @@ static void check_noshuf(CPUHexagonState *env, uint32_t slot) } } -static inline uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, - target_ulong vaddr) +static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, + target_ulong vaddr) { uint8_t retval; check_noshuf(env, slot); @@ -341,8 +340,8 @@ static inline uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, return retval; } -static inline uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, - target_ulong vaddr) +static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, + target_ulong vaddr) { uint16_t retval; check_noshuf(env, slot); @@ -350,8 +349,8 @@ static inline uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, return retval; } -static inline uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, - target_ulong vaddr) +static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, + target_ulong vaddr) { uint32_t retval; check_noshuf(env, slot); @@ -359,8 +358,8 @@ static inline uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, return retval; } -static inline uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, - target_ulong vaddr) +static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, + target_ulong vaddr) { uint64_t retval; check_noshuf(env, slot); @@ -939,7 +938,7 @@ float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV, return RxV; } -static inline bool is_inf_prod(int32_t a, int32_t b) +static bool is_inf_prod(int32_t a, int32_t b) { return (float32_is_infinity(a) && float32_is_infinity(b)) || (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) || diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 2317508fa5..f975d7a5a1 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -585,7 +585,7 @@ static void hexagon_tr_translate_packet(DisasContextBase *dcbase, CPUState *cpu) * The CPU log is used to compare against LLDB single stepping, * so end the TLB after every packet. */ - HexagonCPU *hex_cpu = container_of(env, HexagonCPU, env); + HexagonCPU *hex_cpu = hexagon_env_get_cpu(env); if (hex_cpu->lldb_compat && qemu_loglevel_mask(CPU_LOG_TB_CPU)) { ctx->base.is_jmp = DISAS_TOO_MANY; } From 7d9ab2021f98b93a5af10f594daad6472b530e4d Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:32 -0500 Subject: [PATCH 0145/3028] Hexagon (target/hexagon) use env_archcpu and env_cpu Remove hexagon_env_get_cpu and replace with env_archcpu Replace CPU(hexagon_env_get_cpu(env)) with env_cpu(env) Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-5-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- linux-user/hexagon/cpu_loop.c | 2 +- target/hexagon/cpu.c | 4 ++-- target/hexagon/cpu.h | 5 ----- target/hexagon/op_helper.c | 2 +- target/hexagon/translate.c | 2 +- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/linux-user/hexagon/cpu_loop.c b/linux-user/hexagon/cpu_loop.c index 9a68ca05c3..bc34f5d7c3 100644 --- a/linux-user/hexagon/cpu_loop.c +++ b/linux-user/hexagon/cpu_loop.c @@ -25,7 +25,7 @@ void cpu_loop(CPUHexagonState *env) { - CPUState *cs = CPU(hexagon_env_get_cpu(env)); + CPUState *cs = env_cpu(env); int trapnr, signum, sigcode; target_ulong sigaddr; target_ulong syscallnum; diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index c2fe357702..f044506d0f 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -71,7 +71,7 @@ const char * const hexagon_regnames[TOTAL_PER_THREAD_REGS] = { */ static target_ulong adjust_stack_ptrs(CPUHexagonState *env, target_ulong addr) { - HexagonCPU *cpu = hexagon_env_get_cpu(env); + HexagonCPU *cpu = env_archcpu(env); target_ulong stack_adjust = cpu->lldb_stack_adjust; target_ulong stack_start = env->stack_start; target_ulong stack_size = 0x10000; @@ -115,7 +115,7 @@ static void print_reg(FILE *f, CPUHexagonState *env, int regnum) static void hexagon_dump(CPUHexagonState *env, FILE *f) { - HexagonCPU *cpu = hexagon_env_get_cpu(env); + HexagonCPU *cpu = env_archcpu(env); if (cpu->lldb_compat) { /* diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index e04eac591c..2855dd3881 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -127,11 +127,6 @@ typedef struct HexagonCPU { target_ulong lldb_stack_adjust; } HexagonCPU; -static inline HexagonCPU *hexagon_env_get_cpu(CPUHexagonState *env) -{ - return container_of(env, HexagonCPU, env); -} - #include "cpu_bits.h" #define cpu_signal_handler cpu_hexagon_signal_handler diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 5d35dfc8f3..7ac85549db 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -35,7 +35,7 @@ static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env, uint32_t exception, uintptr_t pc) { - CPUState *cs = CPU(hexagon_env_get_cpu(env)); + CPUState *cs = env_cpu(env); qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); cs->exception_index = exception; cpu_loop_exit_restore(cs, pc); diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index f975d7a5a1..e235fdb315 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -585,7 +585,7 @@ static void hexagon_tr_translate_packet(DisasContextBase *dcbase, CPUState *cpu) * The CPU log is used to compare against LLDB single stepping, * so end the TLB after every packet. */ - HexagonCPU *hex_cpu = hexagon_env_get_cpu(env); + HexagonCPU *hex_cpu = env_archcpu(env); if (hex_cpu->lldb_compat && qemu_loglevel_mask(CPU_LOG_TB_CPU)) { ctx->base.is_jmp = DISAS_TOO_MANY; } From 743debbc373ffcd8eb66dc388632c03f5e951bfc Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:33 -0500 Subject: [PATCH 0146/3028] Hexagon (target/hexagon) properly generate TB end for DISAS_NORETURN When exiting a TB, generate all the code before returning from hexagon_tr_translate_packet so that nothing needs to be done in hexagon_tr_tb_stop. Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-6-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/translate.c | 62 ++++++++++++++++++++------------------ target/hexagon/translate.h | 3 -- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index e235fdb315..9f2a531969 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -54,16 +54,40 @@ static const char * const hexagon_prednames[] = { "p0", "p1", "p2", "p3" }; -void gen_exception(int excp) +static void gen_exception_raw(int excp) { TCGv_i32 helper_tmp = tcg_const_i32(excp); gen_helper_raise_exception(cpu_env, helper_tmp); tcg_temp_free_i32(helper_tmp); } -void gen_exception_debug(void) +static void gen_exec_counters(DisasContext *ctx) { - gen_exception(EXCP_DEBUG); + tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_PKT_CNT], + hex_gpr[HEX_REG_QEMU_PKT_CNT], ctx->num_packets); + tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_INSN_CNT], + hex_gpr[HEX_REG_QEMU_INSN_CNT], ctx->num_insns); +} + +static void gen_end_tb(DisasContext *ctx) +{ + gen_exec_counters(ctx); + tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC); + if (ctx->base.singlestep_enabled) { + gen_exception_raw(EXCP_DEBUG); + } else { + tcg_gen_exit_tb(NULL, 0); + } + ctx->base.is_jmp = DISAS_NORETURN; +} + +static void gen_exception_end_tb(DisasContext *ctx, int excp) +{ + gen_exec_counters(ctx); + tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC); + gen_exception_raw(excp); + ctx->base.is_jmp = DISAS_NORETURN; + } #if HEX_DEBUG @@ -225,8 +249,7 @@ static void gen_insn(CPUHexagonState *env, DisasContext *ctx, mark_implicit_writes(ctx, insn); insn->generate(env, ctx, insn, pkt); } else { - gen_exception(HEX_EXCP_INVALID_OPCODE); - ctx->base.is_jmp = DISAS_NORETURN; + gen_exception_end_tb(ctx, HEX_EXCP_INVALID_OPCODE); } } @@ -447,14 +470,6 @@ static void update_exec_counters(DisasContext *ctx, Packet *pkt) ctx->num_insns += num_real_insns; } -static void gen_exec_counters(DisasContext *ctx) -{ - tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_PKT_CNT], - hex_gpr[HEX_REG_QEMU_PKT_CNT], ctx->num_packets); - tcg_gen_addi_tl(hex_gpr[HEX_REG_QEMU_INSN_CNT], - hex_gpr[HEX_REG_QEMU_INSN_CNT], ctx->num_insns); -} - static void gen_commit_packet(DisasContext *ctx, Packet *pkt) { gen_reg_writes(ctx); @@ -478,7 +493,7 @@ static void gen_commit_packet(DisasContext *ctx, Packet *pkt) #endif if (pkt->pkt_has_cof) { - ctx->base.is_jmp = DISAS_NORETURN; + gen_end_tb(ctx); } } @@ -491,8 +506,7 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx) nwords = read_packet_words(env, ctx, words); if (!nwords) { - gen_exception(HEX_EXCP_INVALID_PACKET); - ctx->base.is_jmp = DISAS_NORETURN; + gen_exception_end_tb(ctx, HEX_EXCP_INVALID_PACKET); return; } @@ -505,8 +519,7 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx) gen_commit_packet(ctx, &pkt); ctx->base.pc_next += pkt.encod_pkt_size_in_bytes; } else { - gen_exception(HEX_EXCP_INVALID_PACKET); - ctx->base.is_jmp = DISAS_NORETURN; + gen_exception_end_tb(ctx, HEX_EXCP_INVALID_PACKET); } } @@ -536,9 +549,7 @@ static bool hexagon_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, { DisasContext *ctx = container_of(dcbase, DisasContext, base); - tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next); - ctx->base.is_jmp = DISAS_NORETURN; - gen_exception_debug(); + gen_exception_end_tb(ctx, EXCP_DEBUG); /* * The address covered by the breakpoint must be included in * [tb->pc, tb->pc + tb->size) in order to for it to be @@ -601,19 +612,12 @@ static void hexagon_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) gen_exec_counters(ctx); tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next); if (ctx->base.singlestep_enabled) { - gen_exception_debug(); + gen_exception_raw(EXCP_DEBUG); } else { tcg_gen_exit_tb(NULL, 0); } break; case DISAS_NORETURN: - gen_exec_counters(ctx); - tcg_gen_mov_tl(hex_gpr[HEX_REG_PC], hex_next_PC); - if (ctx->base.singlestep_enabled) { - gen_exception_debug(); - } else { - tcg_gen_exit_tb(NULL, 0); - } break; default: g_assert_not_reached(); diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index 938f7fbb9f..12506c8caf 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -86,8 +86,5 @@ extern TCGv hex_llsc_addr; extern TCGv hex_llsc_val; extern TCGv_i64 hex_llsc_val_i64; -void gen_exception(int excp); -void gen_exception_debug(void); - void process_store(DisasContext *ctx, Packet *pkt, int slot_num); #endif From 6c677c60ae34bd2c7936781ee8969e41b1dac81e Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:34 -0500 Subject: [PATCH 0147/3028] Hexagon (target/hexagon) decide if pred has been written at TCG gen time Multiple writes to the same preg are and'ed together. Rather than generating a runtime check, we can determine at TCG generation time if the predicate has previously been written in the packet. Test added to tests/tcg/hexagon/misc.c Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-7-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/gen_tcg_funcs.py | 2 +- target/hexagon/genptr.c | 22 +++++++++++++++------- target/hexagon/translate.c | 9 +++++++-- target/hexagon/translate.h | 2 ++ tests/tcg/hexagon/misc.c | 19 +++++++++++++++++++ 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py index db9f663a77..7ceb25b5f6 100755 --- a/target/hexagon/gen_tcg_funcs.py +++ b/target/hexagon/gen_tcg_funcs.py @@ -316,7 +316,7 @@ def genptr_dst_write(f, tag, regtype, regid): print("Bad register parse: ", regtype, regid) elif (regtype == "P"): if (regid in {"d", "e", "x"}): - f.write(" gen_log_pred_write(%s%sN, %s%sV);\n" % \ + f.write(" gen_log_pred_write(ctx, %s%sN, %s%sV);\n" % \ (regtype, regid, regtype, regid)) f.write(" ctx_log_pred_write(ctx, %s%sN);\n" % \ (regtype, regid)) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 07d970fc6c..6b74344795 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -119,20 +119,28 @@ static void gen_log_reg_write_pair(int rnum, TCGv_i64 val) #endif } -static inline void gen_log_pred_write(int pnum, TCGv val) +static inline void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val) { TCGv zero = tcg_const_tl(0); TCGv base_val = tcg_temp_new(); TCGv and_val = tcg_temp_new(); TCGv pred_written = tcg_temp_new(); - /* Multiple writes to the same preg are and'ed together */ tcg_gen_andi_tl(base_val, val, 0xff); - tcg_gen_and_tl(and_val, base_val, hex_new_pred_value[pnum]); - tcg_gen_andi_tl(pred_written, hex_pred_written, 1 << pnum); - tcg_gen_movcond_tl(TCG_COND_NE, hex_new_pred_value[pnum], - pred_written, zero, - and_val, base_val); + + /* + * Section 6.1.3 of the Hexagon V67 Programmer's Reference Manual + * + * Multiple writes to the same preg are and'ed together + * If this is the first predicate write in the packet, do a + * straight assignment. Otherwise, do an and. + */ + if (!test_bit(pnum, ctx->pregs_written)) { + tcg_gen_mov_tl(hex_new_pred_value[pnum], base_val); + } else { + tcg_gen_and_tl(hex_new_pred_value[pnum], + hex_new_pred_value[pnum], base_val); + } tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << pnum); tcg_temp_free(zero); diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 9f2a531969..49ec8b76ed 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -172,6 +172,7 @@ static void gen_start_packet(DisasContext *ctx, Packet *pkt) ctx->reg_log_idx = 0; bitmap_zero(ctx->regs_written, TOTAL_PER_THREAD_REGS); ctx->preg_log_idx = 0; + bitmap_zero(ctx->pregs_written, NUM_PREGS); for (i = 0; i < STORES_MAX; i++) { ctx->store_width[i] = 0; } @@ -226,7 +227,7 @@ static void mark_implicit_pred_write(DisasContext *ctx, Insn *insn, } } -static void mark_implicit_writes(DisasContext *ctx, Insn *insn) +static void mark_implicit_reg_writes(DisasContext *ctx, Insn *insn) { mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_FP, HEX_REG_FP); mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SP, HEX_REG_SP); @@ -235,7 +236,10 @@ static void mark_implicit_writes(DisasContext *ctx, Insn *insn) mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SA0, HEX_REG_SA0); mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_LC1, HEX_REG_LC1); mark_implicit_reg_write(ctx, insn, A_IMPLICIT_WRITES_SA1, HEX_REG_SA1); +} +static void mark_implicit_pred_writes(DisasContext *ctx, Insn *insn) +{ mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P0, 0); mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P1, 1); mark_implicit_pred_write(ctx, insn, A_IMPLICIT_WRITES_P2, 2); @@ -246,8 +250,9 @@ static void gen_insn(CPUHexagonState *env, DisasContext *ctx, Insn *insn, Packet *pkt) { if (insn->generate) { - mark_implicit_writes(ctx, insn); + mark_implicit_reg_writes(ctx, insn); insn->generate(env, ctx, insn, pkt); + mark_implicit_pred_writes(ctx, insn); } else { gen_exception_end_tb(ctx, HEX_EXCP_INVALID_OPCODE); } diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index 12506c8caf..0ecfbd7d52 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -34,6 +34,7 @@ typedef struct DisasContext { DECLARE_BITMAP(regs_written, TOTAL_PER_THREAD_REGS); int preg_log[PRED_WRITES_MAX]; int preg_log_idx; + DECLARE_BITMAP(pregs_written, NUM_PREGS); uint8_t store_width[STORES_MAX]; uint8_t s1_store_processed; } DisasContext; @@ -60,6 +61,7 @@ static inline void ctx_log_pred_write(DisasContext *ctx, int pnum) { ctx->preg_log[ctx->preg_log_idx] = pnum; ctx->preg_log_idx++; + set_bit(pnum, ctx->pregs_written); } static inline bool is_preloaded(DisasContext *ctx, int num) diff --git a/tests/tcg/hexagon/misc.c b/tests/tcg/hexagon/misc.c index 458759f7b1..e5d78b471f 100644 --- a/tests/tcg/hexagon/misc.c +++ b/tests/tcg/hexagon/misc.c @@ -264,6 +264,22 @@ static long long creg_pair(int x, int y) return retval; } +/* Check that predicates are auto-and'ed in a packet */ +static int auto_and(void) +{ + int retval; + asm ("r5 = #1\n\t" + "{\n\t" + " p0 = cmp.eq(r1, #1)\n\t" + " p0 = cmp.eq(r1, #2)\n\t" + "}\n\t" + "%0 = p0\n\t" + : "=r"(retval) + : + : "r5", "p0"); + return retval; +} + int main() { @@ -375,6 +391,9 @@ int main() res = test_clrtnew(2, 7); check(res, 7); + res = auto_and(); + check(res, 0); + puts(err ? "FAIL" : "PASS"); return err; } From 92cfa25fd2cf65749a93507e132225066bc19ed5 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:35 -0500 Subject: [PATCH 0148/3028] Hexagon (target/hexagon) change variables from int to bool when appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-8-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/cpu_bits.h | 2 +- target/hexagon/decode.c | 80 +++++++++++++++++++------------------- target/hexagon/insn.h | 21 +++++----- target/hexagon/op_helper.c | 8 ++-- target/hexagon/translate.c | 6 +-- target/hexagon/translate.h | 2 +- 6 files changed, 60 insertions(+), 59 deletions(-) diff --git a/target/hexagon/cpu_bits.h b/target/hexagon/cpu_bits.h index 96af834d0e..96fef71729 100644 --- a/target/hexagon/cpu_bits.h +++ b/target/hexagon/cpu_bits.h @@ -47,7 +47,7 @@ static inline uint32_t iclass_bits(uint32_t encoding) return iclass; } -static inline int is_packet_end(uint32_t endocing) +static inline bool is_packet_end(uint32_t endocing) { uint32_t bits = parse_bits(endocing); return ((bits == 0x3) || (bits == 0x0)); diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index 65d97ce64b..dffe1d1972 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -340,8 +340,8 @@ static void decode_split_cmpjump(Packet *pkt) if (GET_ATTRIB(pkt->insn[i].opcode, A_NEWCMPJUMP)) { last = pkt->num_insns; pkt->insn[last] = pkt->insn[i]; /* copy the instruction */ - pkt->insn[last].part1 = 1; /* last instruction does the CMP */ - pkt->insn[i].part1 = 0; /* existing instruction does the JUMP */ + pkt->insn[last].part1 = true; /* last insn does the CMP */ + pkt->insn[i].part1 = false; /* existing insn does the JUMP */ pkt->num_insns++; } } @@ -354,7 +354,7 @@ static void decode_split_cmpjump(Packet *pkt) } } -static int decode_opcode_can_jump(int opcode) +static bool decode_opcode_can_jump(int opcode) { if ((GET_ATTRIB(opcode, A_JUMP)) || (GET_ATTRIB(opcode, A_CALL)) || @@ -362,15 +362,15 @@ static int decode_opcode_can_jump(int opcode) (opcode == J2_pause)) { /* Exception to A_JUMP attribute */ if (opcode == J4_hintjumpr) { - return 0; + return false; } - return 1; + return true; } - return 0; + return false; } -static int decode_opcode_ends_loop(int opcode) +static bool decode_opcode_ends_loop(int opcode) { return GET_ATTRIB(opcode, A_HWLOOP0_END) || GET_ATTRIB(opcode, A_HWLOOP1_END); @@ -383,9 +383,9 @@ static void decode_set_insn_attr_fields(Packet *pkt) int numinsns = pkt->num_insns; uint16_t opcode; - pkt->pkt_has_cof = 0; - pkt->pkt_has_endloop = 0; - pkt->pkt_has_dczeroa = 0; + pkt->pkt_has_cof = false; + pkt->pkt_has_endloop = false; + pkt->pkt_has_dczeroa = false; for (i = 0; i < numinsns; i++) { opcode = pkt->insn[i].opcode; @@ -394,14 +394,14 @@ static void decode_set_insn_attr_fields(Packet *pkt) } if (GET_ATTRIB(opcode, A_DCZEROA)) { - pkt->pkt_has_dczeroa = 1; + pkt->pkt_has_dczeroa = true; } if (GET_ATTRIB(opcode, A_STORE)) { if (pkt->insn[i].slot == 0) { - pkt->pkt_has_store_s0 = 1; + pkt->pkt_has_store_s0 = true; } else { - pkt->pkt_has_store_s1 = 1; + pkt->pkt_has_store_s1 = true; } } @@ -422,9 +422,9 @@ static void decode_set_insn_attr_fields(Packet *pkt) */ static void decode_shuffle_for_execution(Packet *packet) { - int changed = 0; + bool changed = false; int i; - int flag; /* flag means we've seen a non-memory instruction */ + bool flag; /* flag means we've seen a non-memory instruction */ int n_mems; int last_insn = packet->num_insns - 1; @@ -437,7 +437,7 @@ static void decode_shuffle_for_execution(Packet *packet) } do { - changed = 0; + changed = false; /* * Stores go last, must not reorder. * Cannot shuffle stores past loads, either. @@ -445,13 +445,13 @@ static void decode_shuffle_for_execution(Packet *packet) * then a store, shuffle the store to the front. Don't shuffle * stores wrt each other or a load. */ - for (flag = n_mems = 0, i = last_insn; i >= 0; i--) { + for (flag = false, n_mems = 0, i = last_insn; i >= 0; i--) { int opcode = packet->insn[i].opcode; if (flag && GET_ATTRIB(opcode, A_STORE)) { decode_send_insn_to(packet, i, last_insn - n_mems); n_mems++; - changed = 1; + changed = true; } else if (GET_ATTRIB(opcode, A_STORE)) { n_mems++; } else if (GET_ATTRIB(opcode, A_LOAD)) { @@ -466,7 +466,7 @@ static void decode_shuffle_for_execution(Packet *packet) * a .new value */ } else { - flag = 1; + flag = true; } } @@ -474,7 +474,7 @@ static void decode_shuffle_for_execution(Packet *packet) continue; } /* Compares go first, may be reordered wrt each other */ - for (flag = 0, i = 0; i < last_insn + 1; i++) { + for (flag = false, i = 0; i < last_insn + 1; i++) { int opcode = packet->insn[i].opcode; if ((strstr(opcode_wregs[opcode], "Pd4") || @@ -483,7 +483,7 @@ static void decode_shuffle_for_execution(Packet *packet) /* This should be a compare (not a store conditional) */ if (flag) { decode_send_insn_to(packet, i, 0); - changed = 1; + changed = true; continue; } } else if (GET_ATTRIB(opcode, A_IMPLICIT_WRITES_P3) && @@ -495,18 +495,18 @@ static void decode_shuffle_for_execution(Packet *packet) */ if (flag) { decode_send_insn_to(packet, i, 0); - changed = 1; + changed = true; continue; } } else if (GET_ATTRIB(opcode, A_IMPLICIT_WRITES_P0) && !GET_ATTRIB(opcode, A_NEWCMPJUMP)) { if (flag) { decode_send_insn_to(packet, i, 0); - changed = 1; + changed = true; continue; } } else { - flag = 1; + flag = true; } } if (changed) { @@ -543,7 +543,7 @@ static void decode_apply_extenders(Packet *packet) int i; for (i = 0; i < packet->num_insns; i++) { if (GET_ATTRIB(packet->insn[i].opcode, A_IT_EXTENDER)) { - packet->insn[i + 1].extension_valid = 1; + packet->insn[i + 1].extension_valid = true; apply_extender(packet, i + 1, packet->insn[i].immed[0]); } } @@ -764,7 +764,7 @@ static void decode_add_endloop_insn(Insn *insn, int loopnum) } } -static int decode_parsebits_is_loopend(uint32_t encoding32) +static bool decode_parsebits_is_loopend(uint32_t encoding32) { uint32_t bits = parse_bits(encoding32); return bits == 0x2; @@ -775,8 +775,11 @@ decode_set_slot_number(Packet *pkt) { int slot; int i; - int hit_mem_insn = 0; - int hit_duplex = 0; + bool hit_mem_insn = false; + bool hit_duplex = false; + bool slot0_found = false; + bool slot1_found = false; + int slot1_iidx = 0; /* * The slots are encoded in reverse order @@ -801,7 +804,7 @@ decode_set_slot_number(Packet *pkt) if ((GET_ATTRIB(pkt->insn[i].opcode, A_MEMLIKE) || GET_ATTRIB(pkt->insn[i].opcode, A_MEMLIKE_PACKET_RULES)) && !hit_mem_insn) { - hit_mem_insn = 1; + hit_mem_insn = true; pkt->insn[i].slot = 0; continue; } @@ -818,7 +821,7 @@ decode_set_slot_number(Packet *pkt) for (i = pkt->num_insns - 1; i >= 0; i--) { /* First subinsn always goes to slot 0 */ if (GET_ATTRIB(pkt->insn[i].opcode, A_SUBINSN) && !hit_duplex) { - hit_duplex = 1; + hit_duplex = true; pkt->insn[i].slot = 0; continue; } @@ -830,13 +833,10 @@ decode_set_slot_number(Packet *pkt) } /* Fix the exceptions - slot 1 is never empty, always aligns to slot 0 */ - int slot0_found = 0; - int slot1_found = 0; - int slot1_iidx = 0; for (i = pkt->num_insns - 1; i >= 0; i--) { /* Is slot0 used? */ if (pkt->insn[i].slot == 0) { - int is_endloop = (pkt->insn[i].opcode == J2_endloop01); + bool is_endloop = (pkt->insn[i].opcode == J2_endloop01); is_endloop |= (pkt->insn[i].opcode == J2_endloop0); is_endloop |= (pkt->insn[i].opcode == J2_endloop1); @@ -845,17 +845,17 @@ decode_set_slot_number(Packet *pkt) * slot0 for endloop */ if (!is_endloop) { - slot0_found = 1; + slot0_found = true; } } /* Is slot1 used? */ if (pkt->insn[i].slot == 1) { - slot1_found = 1; + slot1_found = true; slot1_iidx = i; } } /* Is slot0 empty and slot1 used? */ - if ((slot0_found == 0) && (slot1_found == 1)) { + if ((!slot0_found) && slot1_found) { /* Then push it to slot0 */ pkt->insn[slot1_iidx].slot = 0; } @@ -873,7 +873,7 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt, { int num_insns = 0; int words_read = 0; - int end_of_packet = 0; + bool end_of_packet = false; int new_insns = 0; uint32_t encoding32; @@ -890,7 +890,7 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt, * decode works */ if (pkt->insn[num_insns].opcode == A4_ext) { - pkt->insn[num_insns + 1].extension_valid = 1; + pkt->insn[num_insns + 1].extension_valid = true; } num_insns += new_insns; words_read++; @@ -913,7 +913,7 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt, decode_add_endloop_insn(&pkt->insn[pkt->num_insns++], 0); } if (words_read >= 3) { - uint32_t has_loop0, has_loop1; + bool has_loop0, has_loop1; has_loop0 = decode_parsebits_is_loopend(words[0]); has_loop1 = decode_parsebits_is_loopend(words[1]); if (has_loop0 && has_loop1) { diff --git a/target/hexagon/insn.h b/target/hexagon/insn.h index 5756a1d0ca..2e345912a8 100644 --- a/target/hexagon/insn.h +++ b/target/hexagon/insn.h @@ -40,14 +40,15 @@ struct Instruction { uint32_t iclass:6; uint32_t slot:3; - uint32_t part1:1; /* + uint32_t which_extended:1; /* If has an extender, which immediate */ + uint32_t new_value_producer_slot:4; + + bool part1; /* * cmp-jumps are split into two insns. * set for the compare and clear for the jump */ - uint32_t extension_valid:1; /* Has a constant extender attached */ - uint32_t which_extended:1; /* If has an extender, which immediate */ - uint32_t is_endloop:1; /* This is an end of loop */ - uint32_t new_value_producer_slot:4; + bool extension_valid; /* Has a constant extender attached */ + bool is_endloop; /* This is an end of loop */ int32_t immed[IMMEDS_MAX]; /* immediate field */ }; @@ -58,13 +59,13 @@ struct Packet { uint16_t encod_pkt_size_in_bytes; /* Pre-decodes about COF */ - uint32_t pkt_has_cof:1; /* Has any change-of-flow */ - uint32_t pkt_has_endloop:1; + bool pkt_has_cof; /* Has any change-of-flow */ + bool pkt_has_endloop; - uint32_t pkt_has_dczeroa:1; + bool pkt_has_dczeroa; - uint32_t pkt_has_store_s0:1; - uint32_t pkt_has_store_s1:1; + bool pkt_has_store_s0; + bool pkt_has_store_s1; Insn insn[INSTRUCTIONS_MAX]; }; diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 7ac85549db..1d91fa2743 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -948,8 +948,8 @@ static bool is_inf_prod(int32_t a, int32_t b) float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV, float32 RsV, float32 RtV) { - int infinp; - int infminusinf; + bool infinp; + bool infminusinf; float32 tmp; arch_fpop_start(env); @@ -982,8 +982,8 @@ float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV, float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV, float32 RsV, float32 RtV) { - int infinp; - int infminusinf; + bool infinp; + bool infminusinf; float32 tmp; arch_fpop_start(env); diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 49ec8b76ed..04684221ca 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -177,7 +177,7 @@ static void gen_start_packet(DisasContext *ctx, Packet *pkt) ctx->store_width[i] = 0; } tcg_gen_movi_tl(hex_pkt_has_store_s1, pkt->pkt_has_store_s1); - ctx->s1_store_processed = 0; + ctx->s1_store_processed = false; #if HEX_DEBUG /* Handy place to set a breakpoint before the packet executes */ @@ -210,7 +210,7 @@ static void mark_implicit_reg_write(DisasContext *ctx, Insn *insn, int attrib, int rnum) { if (GET_ATTRIB(insn->opcode, attrib)) { - int is_predicated = GET_ATTRIB(insn->opcode, A_CONDEXEC); + bool is_predicated = GET_ATTRIB(insn->opcode, A_CONDEXEC); if (is_predicated && !is_preloaded(ctx, rnum)) { tcg_gen_mov_tl(hex_new_value[rnum], hex_gpr[rnum]); } @@ -354,7 +354,7 @@ void process_store(DisasContext *ctx, Packet *pkt, int slot_num) if (slot_num == 1 && ctx->s1_store_processed) { return; } - ctx->s1_store_processed = 1; + ctx->s1_store_processed = true; if (is_predicated) { TCGv cancelled = tcg_temp_new(); diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index 0ecfbd7d52..97b12a7d18 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -36,7 +36,7 @@ typedef struct DisasContext { int preg_log_idx; DECLARE_BITMAP(pregs_written, NUM_PREGS); uint8_t store_width[STORES_MAX]; - uint8_t s1_store_processed; + bool s1_store_processed; } DisasContext; static inline void ctx_log_reg_write(DisasContext *ctx, int rnum) From 85511161f7cd1f52a177413e2128b1a05b71163e Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:36 -0500 Subject: [PATCH 0149/3028] Hexagon (target/hexagon) remove unused carry_from_add64 function Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-9-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/arch.c | 13 ------------- target/hexagon/arch.h | 1 - target/hexagon/macros.h | 2 -- 3 files changed, 16 deletions(-) diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c index 09de124818..699e2cfb8f 100644 --- a/target/hexagon/arch.c +++ b/target/hexagon/arch.c @@ -76,19 +76,6 @@ uint64_t deinterleave(uint64_t src) return myeven | (myodd << 32); } -uint32_t carry_from_add64(uint64_t a, uint64_t b, uint32_t c) -{ - uint64_t tmpa, tmpb, tmpc; - tmpa = fGETUWORD(0, a); - tmpb = fGETUWORD(0, b); - tmpc = tmpa + tmpb + c; - tmpa = fGETUWORD(1, a); - tmpb = fGETUWORD(1, b); - tmpc = tmpa + tmpb + fGETUWORD(1, tmpc); - tmpc = fGETUWORD(1, tmpc); - return tmpc; -} - int32_t conv_round(int32_t a, int n) { int64_t val; diff --git a/target/hexagon/arch.h b/target/hexagon/arch.h index 1f7f03693a..6e0b0d9a24 100644 --- a/target/hexagon/arch.h +++ b/target/hexagon/arch.h @@ -22,7 +22,6 @@ uint64_t interleave(uint32_t odd, uint32_t even); uint64_t deinterleave(uint64_t src); -uint32_t carry_from_add64(uint64_t a, uint64_t b, uint32_t c); int32_t conv_round(int32_t a, int n); void arch_fpop_start(CPUHexagonState *env); void arch_fpop_end(CPUHexagonState *env); diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index cfcb8173ba..8cb211dfde 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -341,8 +341,6 @@ static inline void gen_logical_not(TCGv dest, TCGv src) #define fWRITE_LC0(VAL) WRITE_RREG(HEX_REG_LC0, VAL) #define fWRITE_LC1(VAL) WRITE_RREG(HEX_REG_LC1, VAL) -#define fCARRY_FROM_ADD(A, B, C) carry_from_add64(A, B, C) - #define fSET_OVERFLOW() SET_USR_FIELD(USR_OVF, 1) #define fSET_LPCFG(VAL) SET_USR_FIELD(USR_LPCFG, (VAL)) #define fGET_LPCFG (GET_USR_FIELD(USR_LPCFG)) From 8c36752435da380ddf2733d499c4be2cdb8c1b6f Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:37 -0500 Subject: [PATCH 0150/3028] Hexagon (target/hexagon) change type of softfloat_roundingmodes Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-10-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/arch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c index 699e2cfb8f..bb51f19a3d 100644 --- a/target/hexagon/arch.c +++ b/target/hexagon/arch.c @@ -95,7 +95,7 @@ int32_t conv_round(int32_t a, int n) /* Floating Point Stuff */ -static const int softfloat_roundingmodes[] = { +static const FloatRoundMode softfloat_roundingmodes[] = { float_round_nearest_even, float_round_to_zero, float_round_down, From c0336c87b773614eebd23714e3a866bfcd78e9f2 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:38 -0500 Subject: [PATCH 0151/3028] Hexagon (target/hexagon) use softfloat default NaN and tininess Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-11-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- fpu/softfloat-specialize.c.inc | 3 +++ target/hexagon/cpu.c | 5 ++++ target/hexagon/op_helper.c | 47 ---------------------------------- 3 files changed, 8 insertions(+), 47 deletions(-) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index c2f87addb2..9ea318f3e2 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -145,6 +145,9 @@ static FloatParts parts_default_nan(float_status *status) #elif defined(TARGET_HPPA) /* snan_bit_is_one, set msb-1. */ frac = 1ULL << (DECOMPOSED_BINARY_POINT - 2); +#elif defined(TARGET_HEXAGON) + sign = 1; + frac = ~0ULL; #else /* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V, * S390, SH4, TriCore, and Xtensa. I cannot find documentation diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index f044506d0f..ff44fd6637 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -23,6 +23,7 @@ #include "exec/exec-all.h" #include "qapi/error.h" #include "hw/qdev-properties.h" +#include "fpu/softfloat-helpers.h" static void hexagon_v67_cpu_init(Object *obj) { @@ -205,8 +206,12 @@ static void hexagon_cpu_reset(DeviceState *dev) CPUState *cs = CPU(dev); HexagonCPU *cpu = HEXAGON_CPU(cs); HexagonCPUClass *mcc = HEXAGON_CPU_GET_CLASS(cpu); + CPUHexagonState *env = &cpu->env; mcc->parent_reset(dev); + + set_default_nan_mode(1, &env->fp_status); + set_float_detect_tininess(float_tininess_before_rounding, &env->fp_status); } static void hexagon_cpu_disas_set_info(CPUState *s, disassemble_info *info) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 1d91fa2743..478421d147 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -296,26 +296,6 @@ int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS) return new_ptr; } -/* - * Hexagon FP operations return ~0 instead of NaN - * The hex_check_sfnan/hex_check_dfnan functions perform this check - */ -static float32 hex_check_sfnan(float32 x) -{ - if (float32_is_any_nan(x)) { - return make_float32(0xFFFFFFFFU); - } - return x; -} - -static float64 hex_check_dfnan(float64 x) -{ - if (float64_is_any_nan(x)) { - return make_float64(0xFFFFFFFFFFFFFFFFULL); - } - return x; -} - /* * mem_noshuf * Section 5.5 of the Hexagon V67 Programmer's Reference Manual @@ -373,7 +353,6 @@ float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV) float64 out_f64; arch_fpop_start(env); out_f64 = float32_to_float64(RsV, &env->fp_status); - out_f64 = hex_check_dfnan(out_f64); arch_fpop_end(env); return out_f64; } @@ -383,7 +362,6 @@ float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV) float32 out_f32; arch_fpop_start(env); out_f32 = float64_to_float32(RssV, &env->fp_status); - out_f32 = hex_check_sfnan(out_f32); arch_fpop_end(env); return out_f32; } @@ -393,7 +371,6 @@ float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV) float32 RdV; arch_fpop_start(env); RdV = uint32_to_float32(RsV, &env->fp_status); - RdV = hex_check_sfnan(RdV); arch_fpop_end(env); return RdV; } @@ -403,7 +380,6 @@ float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV) float64 RddV; arch_fpop_start(env); RddV = uint32_to_float64(RsV, &env->fp_status); - RddV = hex_check_dfnan(RddV); arch_fpop_end(env); return RddV; } @@ -413,7 +389,6 @@ float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV) float32 RdV; arch_fpop_start(env); RdV = int32_to_float32(RsV, &env->fp_status); - RdV = hex_check_sfnan(RdV); arch_fpop_end(env); return RdV; } @@ -423,7 +398,6 @@ float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV) float64 RddV; arch_fpop_start(env); RddV = int32_to_float64(RsV, &env->fp_status); - RddV = hex_check_dfnan(RddV); arch_fpop_end(env); return RddV; } @@ -433,7 +407,6 @@ float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV) float32 RdV; arch_fpop_start(env); RdV = uint64_to_float32(RssV, &env->fp_status); - RdV = hex_check_sfnan(RdV); arch_fpop_end(env); return RdV; } @@ -443,7 +416,6 @@ float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV) float64 RddV; arch_fpop_start(env); RddV = uint64_to_float64(RssV, &env->fp_status); - RddV = hex_check_dfnan(RddV); arch_fpop_end(env); return RddV; } @@ -453,7 +425,6 @@ float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV) float32 RdV; arch_fpop_start(env); RdV = int64_to_float32(RssV, &env->fp_status); - RdV = hex_check_sfnan(RdV); arch_fpop_end(env); return RdV; } @@ -463,7 +434,6 @@ float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV) float64 RddV; arch_fpop_start(env); RddV = int64_to_float64(RssV, &env->fp_status); - RddV = hex_check_dfnan(RddV); arch_fpop_end(env); return RddV; } @@ -625,7 +595,6 @@ float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV) float32 RdV; arch_fpop_start(env); RdV = float32_add(RsV, RtV, &env->fp_status); - RdV = hex_check_sfnan(RdV); arch_fpop_end(env); return RdV; } @@ -635,7 +604,6 @@ float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV) float32 RdV; arch_fpop_start(env); RdV = float32_sub(RsV, RtV, &env->fp_status); - RdV = hex_check_sfnan(RdV); arch_fpop_end(env); return RdV; } @@ -687,7 +655,6 @@ float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV) float32 RdV; arch_fpop_start(env); RdV = float32_maxnum(RsV, RtV, &env->fp_status); - RdV = hex_check_sfnan(RdV); arch_fpop_end(env); return RdV; } @@ -697,7 +664,6 @@ float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV) float32 RdV; arch_fpop_start(env); RdV = float32_minnum(RsV, RtV, &env->fp_status); - RdV = hex_check_sfnan(RdV); arch_fpop_end(env); return RdV; } @@ -764,7 +730,6 @@ float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV) float64 RddV; arch_fpop_start(env); RddV = float64_add(RssV, RttV, &env->fp_status); - RddV = hex_check_dfnan(RddV); arch_fpop_end(env); return RddV; } @@ -774,7 +739,6 @@ float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV) float64 RddV; arch_fpop_start(env); RddV = float64_sub(RssV, RttV, &env->fp_status); - RddV = hex_check_dfnan(RddV); arch_fpop_end(env); return RddV; } @@ -787,7 +751,6 @@ float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV) if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) { float_raise(float_flag_invalid, &env->fp_status); } - RddV = hex_check_dfnan(RddV); arch_fpop_end(env); return RddV; } @@ -800,7 +763,6 @@ float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV) if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) { float_raise(float_flag_invalid, &env->fp_status); } - RddV = hex_check_dfnan(RddV); arch_fpop_end(env); return RddV; } @@ -876,7 +838,6 @@ float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV) float32 RdV; arch_fpop_start(env); RdV = internal_mpyf(RsV, RtV, &env->fp_status); - RdV = hex_check_sfnan(RdV); arch_fpop_end(env); return RdV; } @@ -886,7 +847,6 @@ float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV, { arch_fpop_start(env); RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status); - RxV = hex_check_sfnan(RxV); arch_fpop_end(env); return RxV; } @@ -918,7 +878,6 @@ float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV, RxV = check_nan(RxV, RsV, &env->fp_status); RxV = check_nan(RxV, RtV, &env->fp_status); tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status); - tmp = hex_check_sfnan(tmp); if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { RxV = tmp; } @@ -933,7 +892,6 @@ float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV, arch_fpop_start(env); neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status); RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status); - RxV = hex_check_sfnan(RxV); arch_fpop_end(env); return RxV; } @@ -964,7 +922,6 @@ float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV, RxV = check_nan(RxV, RsV, &env->fp_status); RxV = check_nan(RxV, RtV, &env->fp_status); tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status); - tmp = hex_check_sfnan(tmp); if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { RxV = tmp; } @@ -999,7 +956,6 @@ float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV, RxV = check_nan(RxV, RtV, &env->fp_status); float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status); tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status); - tmp = hex_check_sfnan(tmp); if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { RxV = tmp; } @@ -1023,13 +979,11 @@ float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV) float64_is_normal(RttV)) { RddV = float64_mul(RssV, make_float64(0x4330000000000000), &env->fp_status); - RddV = hex_check_dfnan(RddV); } else if (float64_is_denormal(RttV) && (float64_getexp(RssV) >= 512) && float64_is_normal(RssV)) { RddV = float64_mul(RssV, make_float64(0x3cb0000000000000), &env->fp_status); - RddV = hex_check_dfnan(RddV); } else { RddV = RssV; } @@ -1042,7 +996,6 @@ float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV, { arch_fpop_start(env); RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status); - RxxV = hex_check_dfnan(RxxV); arch_fpop_end(env); return RxxV; } From 1cb532fe45991b70cf47c414e0bc4fe63f571a8a Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:39 -0500 Subject: [PATCH 0152/3028] Hexagon (target/hexagon) replace float32_mul_pow2 with float32_scalbn Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-12-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/arch.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c index bb51f19a3d..40b6e3d0c0 100644 --- a/target/hexagon/arch.c +++ b/target/hexagon/arch.c @@ -143,12 +143,6 @@ void arch_fpop_end(CPUHexagonState *env) } } -static float32 float32_mul_pow2(float32 a, uint32_t p, float_status *fp_status) -{ - float32 b = make_float32((SF_BIAS + p) << SF_MANTBITS); - return float32_mul(a, b, fp_status); -} - int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd, int *adjust, float_status *fp_status) { @@ -217,22 +211,22 @@ int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd, int *adjust, if ((n_exp - d_exp + SF_BIAS) <= SF_MANTBITS) { /* Near quotient underflow / inexact Q */ PeV = 0x80; - RtV = float32_mul_pow2(RtV, -64, fp_status); - RsV = float32_mul_pow2(RsV, 64, fp_status); + RtV = float32_scalbn(RtV, -64, fp_status); + RsV = float32_scalbn(RsV, 64, fp_status); } else if ((n_exp - d_exp + SF_BIAS) > (SF_MAXEXP - 24)) { /* Near quotient overflow */ PeV = 0x40; - RtV = float32_mul_pow2(RtV, 32, fp_status); - RsV = float32_mul_pow2(RsV, -32, fp_status); + RtV = float32_scalbn(RtV, 32, fp_status); + RsV = float32_scalbn(RsV, -32, fp_status); } else if (n_exp <= SF_MANTBITS + 2) { - RtV = float32_mul_pow2(RtV, 64, fp_status); - RsV = float32_mul_pow2(RsV, 64, fp_status); + RtV = float32_scalbn(RtV, 64, fp_status); + RsV = float32_scalbn(RsV, 64, fp_status); } else if (d_exp <= 1) { - RtV = float32_mul_pow2(RtV, 32, fp_status); - RsV = float32_mul_pow2(RsV, 32, fp_status); + RtV = float32_scalbn(RtV, 32, fp_status); + RsV = float32_scalbn(RsV, 32, fp_status); } else if (d_exp > 252) { - RtV = float32_mul_pow2(RtV, -32, fp_status); - RsV = float32_mul_pow2(RsV, -32, fp_status); + RtV = float32_scalbn(RtV, -32, fp_status); + RsV = float32_scalbn(RsV, -32, fp_status); } RdV = 0; ret = 1; @@ -274,7 +268,7 @@ int arch_sf_invsqrt_common(float32 *Rs, float32 *Rd, int *adjust, /* Basic checks passed */ r_exp = float32_getexp(RsV); if (r_exp <= 24) { - RsV = float32_mul_pow2(RsV, 64, fp_status); + RsV = float32_scalbn(RsV, 64, fp_status); PeV = 0xe0; } RdV = 0; From b3f37abdd3f4919c81ea42f9f729875544623df2 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:40 -0500 Subject: [PATCH 0153/3028] Hexagon (target/hexagon) use softfloat for float-to-int conversions Use the proper return for helpers that convert to unsigned Remove target/hexagon/conv_emu.[ch] Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-13-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/conv_emu.c | 177 ------------------------------------ target/hexagon/conv_emu.h | 31 ------- target/hexagon/fma_emu.c | 1 - target/hexagon/helper.h | 16 ++-- target/hexagon/meson.build | 1 - target/hexagon/op_helper.c | 169 +++++++++++++++++++++++++--------- tests/tcg/hexagon/fpstuff.c | 145 +++++++++++++++++++++++++++++ 7 files changed, 281 insertions(+), 259 deletions(-) delete mode 100644 target/hexagon/conv_emu.c delete mode 100644 target/hexagon/conv_emu.h diff --git a/target/hexagon/conv_emu.c b/target/hexagon/conv_emu.c deleted file mode 100644 index 3985b1032a..0000000000 --- a/target/hexagon/conv_emu.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include "qemu/osdep.h" -#include "qemu/host-utils.h" -#include "fpu/softfloat.h" -#include "macros.h" -#include "conv_emu.h" - -#define LL_MAX_POS 0x7fffffffffffffffULL -#define MAX_POS 0x7fffffffU - -static uint64_t conv_f64_to_8u_n(float64 in, int will_negate, - float_status *fp_status) -{ - uint8_t sign = float64_is_neg(in); - if (float64_is_infinity(in)) { - float_raise(float_flag_invalid, fp_status); - if (float64_is_neg(in)) { - return 0ULL; - } else { - return ~0ULL; - } - } - if (float64_is_any_nan(in)) { - float_raise(float_flag_invalid, fp_status); - return ~0ULL; - } - if (float64_is_zero(in)) { - return 0; - } - if (sign) { - float_raise(float_flag_invalid, fp_status); - return 0; - } - if (float64_lt(in, float64_half, fp_status)) { - /* Near zero, captures large fracshifts, denorms, etc */ - float_raise(float_flag_inexact, fp_status); - switch (get_float_rounding_mode(fp_status)) { - case float_round_down: - if (will_negate) { - return 1; - } else { - return 0; - } - case float_round_up: - if (!will_negate) { - return 1; - } else { - return 0; - } - default: - return 0; /* nearest or towards zero */ - } - } - return float64_to_uint64(in, fp_status); -} - -static void clr_float_exception_flags(uint8_t flag, float_status *fp_status) -{ - uint8_t flags = fp_status->float_exception_flags; - flags &= ~flag; - set_float_exception_flags(flags, fp_status); -} - -static uint32_t conv_df_to_4u_n(float64 fp64, int will_negate, - float_status *fp_status) -{ - uint64_t tmp; - tmp = conv_f64_to_8u_n(fp64, will_negate, fp_status); - if (tmp > 0x00000000ffffffffULL) { - clr_float_exception_flags(float_flag_inexact, fp_status); - float_raise(float_flag_invalid, fp_status); - return ~0U; - } - return (uint32_t)tmp; -} - -uint64_t conv_df_to_8u(float64 in, float_status *fp_status) -{ - return conv_f64_to_8u_n(in, 0, fp_status); -} - -uint32_t conv_df_to_4u(float64 in, float_status *fp_status) -{ - return conv_df_to_4u_n(in, 0, fp_status); -} - -int64_t conv_df_to_8s(float64 in, float_status *fp_status) -{ - uint8_t sign = float64_is_neg(in); - uint64_t tmp; - if (float64_is_any_nan(in)) { - float_raise(float_flag_invalid, fp_status); - return -1; - } - if (sign) { - float64 minus_fp64 = float64_abs(in); - tmp = conv_f64_to_8u_n(minus_fp64, 1, fp_status); - } else { - tmp = conv_f64_to_8u_n(in, 0, fp_status); - } - if (tmp > (LL_MAX_POS + sign)) { - clr_float_exception_flags(float_flag_inexact, fp_status); - float_raise(float_flag_invalid, fp_status); - tmp = (LL_MAX_POS + sign); - } - if (sign) { - return -tmp; - } else { - return tmp; - } -} - -int32_t conv_df_to_4s(float64 in, float_status *fp_status) -{ - uint8_t sign = float64_is_neg(in); - uint64_t tmp; - if (float64_is_any_nan(in)) { - float_raise(float_flag_invalid, fp_status); - return -1; - } - if (sign) { - float64 minus_fp64 = float64_abs(in); - tmp = conv_f64_to_8u_n(minus_fp64, 1, fp_status); - } else { - tmp = conv_f64_to_8u_n(in, 0, fp_status); - } - if (tmp > (MAX_POS + sign)) { - clr_float_exception_flags(float_flag_inexact, fp_status); - float_raise(float_flag_invalid, fp_status); - tmp = (MAX_POS + sign); - } - if (sign) { - return -tmp; - } else { - return tmp; - } -} - -uint64_t conv_sf_to_8u(float32 in, float_status *fp_status) -{ - float64 fp64 = float32_to_float64(in, fp_status); - return conv_df_to_8u(fp64, fp_status); -} - -uint32_t conv_sf_to_4u(float32 in, float_status *fp_status) -{ - float64 fp64 = float32_to_float64(in, fp_status); - return conv_df_to_4u(fp64, fp_status); -} - -int64_t conv_sf_to_8s(float32 in, float_status *fp_status) -{ - float64 fp64 = float32_to_float64(in, fp_status); - return conv_df_to_8s(fp64, fp_status); -} - -int32_t conv_sf_to_4s(float32 in, float_status *fp_status) -{ - float64 fp64 = float32_to_float64(in, fp_status); - return conv_df_to_4s(fp64, fp_status); -} diff --git a/target/hexagon/conv_emu.h b/target/hexagon/conv_emu.h deleted file mode 100644 index cade9de91f..0000000000 --- a/target/hexagon/conv_emu.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#ifndef HEXAGON_CONV_EMU_H -#define HEXAGON_CONV_EMU_H - -uint64_t conv_sf_to_8u(float32 in, float_status *fp_status); -uint32_t conv_sf_to_4u(float32 in, float_status *fp_status); -int64_t conv_sf_to_8s(float32 in, float_status *fp_status); -int32_t conv_sf_to_4s(float32 in, float_status *fp_status); - -uint64_t conv_df_to_8u(float64 in, float_status *fp_status); -uint32_t conv_df_to_4u(float64 in, float_status *fp_status); -int64_t conv_df_to_8s(float64 in, float_status *fp_status); -int32_t conv_df_to_4s(float64 in, float_status *fp_status); - -#endif diff --git a/target/hexagon/fma_emu.c b/target/hexagon/fma_emu.c index f324b83e3c..d3b45d494f 100644 --- a/target/hexagon/fma_emu.c +++ b/target/hexagon/fma_emu.c @@ -19,7 +19,6 @@ #include "qemu/int128.h" #include "fpu/softfloat.h" #include "macros.h" -#include "conv_emu.h" #include "fma_emu.h" #define DF_INF_EXP 0x7ff diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index a5f340ce67..715c24662f 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -38,21 +38,21 @@ DEF_HELPER_2(conv_ud2sf, f32, env, s64) DEF_HELPER_2(conv_ud2df, f64, env, s64) DEF_HELPER_2(conv_d2sf, f32, env, s64) DEF_HELPER_2(conv_d2df, f64, env, s64) -DEF_HELPER_2(conv_sf2uw, s32, env, f32) +DEF_HELPER_2(conv_sf2uw, i32, env, f32) DEF_HELPER_2(conv_sf2w, s32, env, f32) -DEF_HELPER_2(conv_sf2ud, s64, env, f32) +DEF_HELPER_2(conv_sf2ud, i64, env, f32) DEF_HELPER_2(conv_sf2d, s64, env, f32) -DEF_HELPER_2(conv_df2uw, s32, env, f64) +DEF_HELPER_2(conv_df2uw, i32, env, f64) DEF_HELPER_2(conv_df2w, s32, env, f64) -DEF_HELPER_2(conv_df2ud, s64, env, f64) +DEF_HELPER_2(conv_df2ud, i64, env, f64) DEF_HELPER_2(conv_df2d, s64, env, f64) -DEF_HELPER_2(conv_sf2uw_chop, s32, env, f32) +DEF_HELPER_2(conv_sf2uw_chop, i32, env, f32) DEF_HELPER_2(conv_sf2w_chop, s32, env, f32) -DEF_HELPER_2(conv_sf2ud_chop, s64, env, f32) +DEF_HELPER_2(conv_sf2ud_chop, i64, env, f32) DEF_HELPER_2(conv_sf2d_chop, s64, env, f32) -DEF_HELPER_2(conv_df2uw_chop, s32, env, f64) +DEF_HELPER_2(conv_df2uw_chop, i32, env, f64) DEF_HELPER_2(conv_df2w_chop, s32, env, f64) -DEF_HELPER_2(conv_df2ud_chop, s64, env, f64) +DEF_HELPER_2(conv_df2ud_chop, i64, env, f64) DEF_HELPER_2(conv_df2d_chop, s64, env, f64) DEF_HELPER_3(sfadd, f32, env, f32, f32) DEF_HELPER_3(sfsub, f32, env, f32, f32) diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index bb0b4fb621..6fd9360b74 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -173,7 +173,6 @@ hexagon_ss.add(files( 'printinsn.c', 'arch.c', 'fma_emu.c', - 'conv_emu.c', )) target_arch += {'hexagon': hexagon_ss} diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 478421d147..b70c5d607a 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -25,7 +25,6 @@ #include "arch.h" #include "hex_arch_types.h" #include "fma_emu.h" -#include "conv_emu.h" #define SF_BIAS 127 #define SF_MANTBITS 23 @@ -438,11 +437,17 @@ float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV) return RddV; } -int32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV) +uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV) { - int32_t RdV; + uint32_t RdV; arch_fpop_start(env); - RdV = conv_sf_to_4u(RsV, &env->fp_status); + /* Hexagon checks the sign before rounding */ + if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { + float_raise(float_flag_invalid, &env->fp_status); + RdV = 0; + } else { + RdV = float32_to_uint32(RsV, &env->fp_status); + } arch_fpop_end(env); return RdV; } @@ -451,16 +456,28 @@ int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV) { int32_t RdV; arch_fpop_start(env); - RdV = conv_sf_to_4s(RsV, &env->fp_status); + /* Hexagon returns -1 for NaN */ + if (float32_is_any_nan(RsV)) { + float_raise(float_flag_invalid, &env->fp_status); + RdV = -1; + } else { + RdV = float32_to_int32(RsV, &env->fp_status); + } arch_fpop_end(env); return RdV; } -int64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV) +uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV) { - int64_t RddV; + uint64_t RddV; arch_fpop_start(env); - RddV = conv_sf_to_8u(RsV, &env->fp_status); + /* Hexagon checks the sign before rounding */ + if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { + float_raise(float_flag_invalid, &env->fp_status); + RddV = 0; + } else { + RddV = float32_to_uint64(RsV, &env->fp_status); + } arch_fpop_end(env); return RddV; } @@ -469,16 +486,28 @@ int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV) { int64_t RddV; arch_fpop_start(env); - RddV = conv_sf_to_8s(RsV, &env->fp_status); + /* Hexagon returns -1 for NaN */ + if (float32_is_any_nan(RsV)) { + float_raise(float_flag_invalid, &env->fp_status); + RddV = -1; + } else { + RddV = float32_to_int64(RsV, &env->fp_status); + } arch_fpop_end(env); return RddV; } -int32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV) +uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV) { - int32_t RdV; + uint32_t RdV; arch_fpop_start(env); - RdV = conv_df_to_4u(RssV, &env->fp_status); + /* Hexagon checks the sign before rounding */ + if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) { + float_raise(float_flag_invalid, &env->fp_status); + RdV = 0; + } else { + RdV = float64_to_uint32(RssV, &env->fp_status); + } arch_fpop_end(env); return RdV; } @@ -487,16 +516,28 @@ int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV) { int32_t RdV; arch_fpop_start(env); - RdV = conv_df_to_4s(RssV, &env->fp_status); + /* Hexagon returns -1 for NaN */ + if (float64_is_any_nan(RssV)) { + float_raise(float_flag_invalid, &env->fp_status); + RdV = -1; + } else { + RdV = float64_to_int32(RssV, &env->fp_status); + } arch_fpop_end(env); return RdV; } -int64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV) +uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV) { - int64_t RddV; + uint64_t RddV; arch_fpop_start(env); - RddV = conv_df_to_8u(RssV, &env->fp_status); + /* Hexagon checks the sign before rounding */ + if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) { + float_raise(float_flag_invalid, &env->fp_status); + RddV = 0; + } else { + RddV = float64_to_uint64(RssV, &env->fp_status); + } arch_fpop_end(env); return RddV; } @@ -505,17 +546,28 @@ int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV) { int64_t RddV; arch_fpop_start(env); - RddV = conv_df_to_8s(RssV, &env->fp_status); + /* Hexagon returns -1 for NaN */ + if (float64_is_any_nan(RssV)) { + float_raise(float_flag_invalid, &env->fp_status); + RddV = -1; + } else { + RddV = float64_to_int64(RssV, &env->fp_status); + } arch_fpop_end(env); return RddV; } -int32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV) +uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV) { - int32_t RdV; + uint32_t RdV; arch_fpop_start(env); - set_float_rounding_mode(float_round_to_zero, &env->fp_status); - RdV = conv_sf_to_4u(RsV, &env->fp_status); + /* Hexagon checks the sign before rounding */ + if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { + float_raise(float_flag_invalid, &env->fp_status); + RdV = 0; + } else { + RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status); + } arch_fpop_end(env); return RdV; } @@ -524,18 +576,28 @@ int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV) { int32_t RdV; arch_fpop_start(env); - set_float_rounding_mode(float_round_to_zero, &env->fp_status); - RdV = conv_sf_to_4s(RsV, &env->fp_status); + /* Hexagon returns -1 for NaN */ + if (float32_is_any_nan(RsV)) { + float_raise(float_flag_invalid, &env->fp_status); + RdV = -1; + } else { + RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status); + } arch_fpop_end(env); return RdV; } -int64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV) +uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV) { - int64_t RddV; + uint64_t RddV; arch_fpop_start(env); - set_float_rounding_mode(float_round_to_zero, &env->fp_status); - RddV = conv_sf_to_8u(RsV, &env->fp_status); + /* Hexagon checks the sign before rounding */ + if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { + float_raise(float_flag_invalid, &env->fp_status); + RddV = 0; + } else { + RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status); + } arch_fpop_end(env); return RddV; } @@ -544,18 +606,28 @@ int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV) { int64_t RddV; arch_fpop_start(env); - set_float_rounding_mode(float_round_to_zero, &env->fp_status); - RddV = conv_sf_to_8s(RsV, &env->fp_status); + /* Hexagon returns -1 for NaN */ + if (float32_is_any_nan(RsV)) { + float_raise(float_flag_invalid, &env->fp_status); + RddV = -1; + } else { + RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status); + } arch_fpop_end(env); return RddV; } -int32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV) +uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV) { - int32_t RdV; + uint32_t RdV; arch_fpop_start(env); - set_float_rounding_mode(float_round_to_zero, &env->fp_status); - RdV = conv_df_to_4u(RssV, &env->fp_status); + /* Hexagon checks the sign before rounding */ + if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) { + float_raise(float_flag_invalid, &env->fp_status); + RdV = 0; + } else { + RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status); + } arch_fpop_end(env); return RdV; } @@ -564,18 +636,28 @@ int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV) { int32_t RdV; arch_fpop_start(env); - set_float_rounding_mode(float_round_to_zero, &env->fp_status); - RdV = conv_df_to_4s(RssV, &env->fp_status); + /* Hexagon returns -1 for NaN */ + if (float64_is_any_nan(RssV)) { + float_raise(float_flag_invalid, &env->fp_status); + RdV = -1; + } else { + RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status); + } arch_fpop_end(env); return RdV; } -int64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV) +uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV) { - int64_t RddV; + uint64_t RddV; arch_fpop_start(env); - set_float_rounding_mode(float_round_to_zero, &env->fp_status); - RddV = conv_df_to_8u(RssV, &env->fp_status); + /* Hexagon checks the sign before rounding */ + if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) { + float_raise(float_flag_invalid, &env->fp_status); + RddV = 0; + } else { + RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status); + } arch_fpop_end(env); return RddV; } @@ -584,8 +666,13 @@ int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV) { int64_t RddV; arch_fpop_start(env); - set_float_rounding_mode(float_round_to_zero, &env->fp_status); - RddV = conv_df_to_8s(RssV, &env->fp_status); + /* Hexagon returns -1 for NaN */ + if (float64_is_any_nan(RssV)) { + float_raise(float_flag_invalid, &env->fp_status); + RddV = -1; + } else { + RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status); + } arch_fpop_end(env); return RddV; } diff --git a/tests/tcg/hexagon/fpstuff.c b/tests/tcg/hexagon/fpstuff.c index e4f1a0eeb4..6b60f92d18 100644 --- a/tests/tcg/hexagon/fpstuff.c +++ b/tests/tcg/hexagon/fpstuff.c @@ -37,10 +37,12 @@ const int SF_NaN = 0x7fc00000; const int SF_NaN_special = 0x7f800001; const int SF_ANY = 0x3f800000; const int SF_HEX_NAN = 0xffffffff; +const int SF_small_neg = 0xab98fba8; const long long DF_NaN = 0x7ff8000000000000ULL; const long long DF_ANY = 0x3f80000000000000ULL; const long long DF_HEX_NAN = 0xffffffffffffffffULL; +const long long DF_small_neg = 0xbd731f7500000000ULL; int err; @@ -358,12 +360,155 @@ static void check_canonical_NaN(void) check_fpstatus(usr, 0); } +static void check_float2int_convs() +{ + int res32; + long long res64; + int usr; + + /* + * Check that the various forms of float-to-unsigned + * check sign before rounding + */ + asm(CLEAR_FPSTATUS + "%0 = convert_sf2uw(%2)\n\t" + "%1 = usr\n\t" + : "=r"(res32), "=r"(usr) : "r"(SF_small_neg) + : "r2", "usr"); + check32(res32, 0); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_sf2uw(%2):chop\n\t" + "%1 = usr\n\t" + : "=r"(res32), "=r"(usr) : "r"(SF_small_neg) + : "r2", "usr"); + check32(res32, 0); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_sf2ud(%2)\n\t" + "%1 = usr\n\t" + : "=r"(res64), "=r"(usr) : "r"(SF_small_neg) + : "r2", "usr"); + check64(res64, 0); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_sf2ud(%2):chop\n\t" + "%1 = usr\n\t" + : "=r"(res64), "=r"(usr) : "r"(SF_small_neg) + : "r2", "usr"); + check64(res64, 0); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_df2uw(%2)\n\t" + "%1 = usr\n\t" + : "=r"(res32), "=r"(usr) : "r"(DF_small_neg) + : "r2", "usr"); + check32(res32, 0); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_df2uw(%2):chop\n\t" + "%1 = usr\n\t" + : "=r"(res32), "=r"(usr) : "r"(DF_small_neg) + : "r2", "usr"); + check32(res32, 0); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_df2ud(%2)\n\t" + "%1 = usr\n\t" + : "=r"(res64), "=r"(usr) : "r"(DF_small_neg) + : "r2", "usr"); + check64(res64, 0); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_df2ud(%2):chop\n\t" + "%1 = usr\n\t" + : "=r"(res64), "=r"(usr) : "r"(DF_small_neg) + : "r2", "usr"); + check64(res64, 0); + check_fpstatus(usr, FPINVF); + + /* + * Check that the various forms of float-to-signed return -1 for NaN + */ + asm(CLEAR_FPSTATUS + "%0 = convert_sf2w(%2)\n\t" + "%1 = usr\n\t" + : "=r"(res32), "=r"(usr) : "r"(SF_NaN) + : "r2", "usr"); + check32(res32, -1); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_sf2w(%2):chop\n\t" + "%1 = usr\n\t" + : "=r"(res32), "=r"(usr) : "r"(SF_NaN) + : "r2", "usr"); + check32(res32, -1); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_sf2d(%2)\n\t" + "%1 = usr\n\t" + : "=r"(res64), "=r"(usr) : "r"(SF_NaN) + : "r2", "usr"); + check64(res64, -1); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_sf2d(%2):chop\n\t" + "%1 = usr\n\t" + : "=r"(res64), "=r"(usr) : "r"(SF_NaN) + : "r2", "usr"); + check64(res64, -1); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_df2w(%2)\n\t" + "%1 = usr\n\t" + : "=r"(res32), "=r"(usr) : "r"(DF_NaN) + : "r2", "usr"); + check32(res32, -1); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_df2w(%2):chop\n\t" + "%1 = usr\n\t" + : "=r"(res32), "=r"(usr) : "r"(DF_NaN) + : "r2", "usr"); + check32(res32, -1); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_df2d(%2)\n\t" + "%1 = usr\n\t" + : "=r"(res64), "=r"(usr) : "r"(DF_NaN) + : "r2", "usr"); + check64(res64, -1); + check_fpstatus(usr, FPINVF); + + asm(CLEAR_FPSTATUS + "%0 = convert_df2d(%2):chop\n\t" + "%1 = usr\n\t" + : "=r"(res64), "=r"(usr) : "r"(DF_NaN) + : "r2", "usr"); + check64(res64, -1); + check_fpstatus(usr, FPINVF); +} + int main() { check_compare_exception(); check_sfminmax(); check_dfminmax(); check_canonical_NaN(); + check_float2int_convs(); puts(err ? "FAIL" : "PASS"); return err ? 1 : 0; From 9fe33c0e7048b979d39ee579962d94871ea42e0a Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:41 -0500 Subject: [PATCH 0154/3028] Hexagon (target/hexagon) cleanup ternary operators in semantics Change (cond ? (res = x) : (res = y)) to res = (cond ? x : y) This makes the semnatics easier to for idef-parser to deal with The following instructions are impacted C2_any8 C2_all8 C2_mux C2_muxii C2_muxir C2_muxri Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-14-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/imported/compare.idef | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/hexagon/imported/compare.idef b/target/hexagon/imported/compare.idef index 3551467854..abd016ffb5 100644 --- a/target/hexagon/imported/compare.idef +++ b/target/hexagon/imported/compare.idef @@ -198,11 +198,11 @@ Q6INSN(C4_or_orn,"Pd4=or(Ps4,or(Pt4,!Pu4))",ATTRIBS(A_CRSLOT23), Q6INSN(C2_any8,"Pd4=any8(Ps4)",ATTRIBS(A_CRSLOT23), "Logical ANY of low 8 predicate bits", -{ PsV ? (PdV=0xff) : (PdV=0x00); }) +{ PdV = (PsV ? 0xff : 0x00); }) Q6INSN(C2_all8,"Pd4=all8(Ps4)",ATTRIBS(A_CRSLOT23), "Logical ALL of low 8 predicate bits", -{ (PsV==0xff) ? (PdV=0xff) : (PdV=0x00); }) +{ PdV = (PsV == 0xff ? 0xff : 0x00); }) Q6INSN(C2_vitpack,"Rd32=vitpack(Ps4,Pt4)",ATTRIBS(), "Pack the odd and even bits of two predicate registers", @@ -212,7 +212,7 @@ Q6INSN(C2_vitpack,"Rd32=vitpack(Ps4,Pt4)",ATTRIBS(), Q6INSN(C2_mux,"Rd32=mux(Pu4,Rs32,Rt32)",ATTRIBS(), "Scalar MUX", -{ (fLSBOLD(PuV)) ? (RdV=RsV):(RdV=RtV); }) +{ RdV = (fLSBOLD(PuV) ? RsV : RtV); }) Q6INSN(C2_cmovenewit,"if (Pu4.new) Rd32=#s12",ATTRIBS(A_ARCHV2), @@ -269,18 +269,18 @@ Q6INSN(C2_ccombinewf,"if (!Pu4) Rdd32=combine(Rs32,Rt32)",ATTRIBS(A_ARCHV2), Q6INSN(C2_muxii,"Rd32=mux(Pu4,#s8,#S8)",ATTRIBS(A_ARCHV2), "Scalar MUX immediates", -{ fIMMEXT(siV); (fLSBOLD(PuV)) ? (RdV=siV):(RdV=SiV); }) +{ fIMMEXT(siV); RdV = (fLSBOLD(PuV) ? siV : SiV); }) Q6INSN(C2_muxir,"Rd32=mux(Pu4,Rs32,#s8)",ATTRIBS(A_ARCHV2), "Scalar MUX register immediate", -{ fIMMEXT(siV); (fLSBOLD(PuV)) ? (RdV=RsV):(RdV=siV); }) +{ fIMMEXT(siV); RdV = (fLSBOLD(PuV) ? RsV : siV); }) Q6INSN(C2_muxri,"Rd32=mux(Pu4,#s8,Rs32)",ATTRIBS(A_ARCHV2), "Scalar MUX register immediate", -{ fIMMEXT(siV); (fLSBOLD(PuV)) ? (RdV=siV):(RdV=RsV); }) +{ fIMMEXT(siV); RdV = (fLSBOLD(PuV) ? siV : RsV); }) From 80be682844ddfeffa21576ce0cb61d06bf6b87f8 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:42 -0500 Subject: [PATCH 0155/3028] Hexagon (target/hexagon) cleanup reg_field_info definition Include size in declaration Remove {0, 0} entry Suggested-by: Richard Henderson Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-15-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/reg_fields.c | 3 +-- target/hexagon/reg_fields.h | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/target/hexagon/reg_fields.c b/target/hexagon/reg_fields.c index bdcab79428..6713203725 100644 --- a/target/hexagon/reg_fields.c +++ b/target/hexagon/reg_fields.c @@ -18,10 +18,9 @@ #include "qemu/osdep.h" #include "reg_fields.h" -const RegField reg_field_info[] = { +const RegField reg_field_info[NUM_REG_FIELDS] = { #define DEF_REG_FIELD(TAG, START, WIDTH) \ { START, WIDTH }, #include "reg_fields_def.h.inc" - { 0, 0 } #undef DEF_REG_FIELD }; diff --git a/target/hexagon/reg_fields.h b/target/hexagon/reg_fields.h index d3c86c942f..9e2ad5d997 100644 --- a/target/hexagon/reg_fields.h +++ b/target/hexagon/reg_fields.h @@ -23,8 +23,6 @@ typedef struct { int width; } RegField; -extern const RegField reg_field_info[]; - enum { #define DEF_REG_FIELD(TAG, START, WIDTH) \ TAG, @@ -33,4 +31,6 @@ enum { #undef DEF_REG_FIELD }; +extern const RegField reg_field_info[NUM_REG_FIELDS]; + #endif From a33872eb533c5b4d2eb7658fa07e6a281bfd609b Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:43 -0500 Subject: [PATCH 0156/3028] Hexagon (target/hexagon) move QEMU_GENERATE to only be on during macros.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-16-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/genptr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 6b74344795..b87e264ccf 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -15,7 +15,6 @@ * along with this program; if not, see . */ -#define QEMU_GENERATE #include "qemu/osdep.h" #include "qemu/log.h" #include "cpu.h" @@ -24,7 +23,9 @@ #include "insn.h" #include "opcodes.h" #include "translate.h" +#define QEMU_GENERATE /* Used internally by macros.h */ #include "macros.h" +#undef QEMU_GENERATE #include "gen_tcg.h" static inline TCGv gen_read_preg(TCGv pred, uint8_t num) From 85580a65577898288a29d849160601895979c661 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:44 -0500 Subject: [PATCH 0157/3028] Hexagon (target/hexagon) compile all debug code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change #if HEX_DEBUG to if (HEX_DEBUG) so the debug code doesn't bit rot Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-17-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/genptr.c | 72 ++++++++++++++++++------------------- target/hexagon/helper.h | 2 -- target/hexagon/internal.h | 11 +++--- target/hexagon/op_helper.c | 14 +++----- target/hexagon/translate.c | 74 ++++++++++++++++++-------------------- target/hexagon/translate.h | 2 -- 6 files changed, 81 insertions(+), 94 deletions(-) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index b87e264ccf..24d575853c 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -42,17 +42,17 @@ static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot) tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot); tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum], slot_mask, zero, val, hex_new_value[rnum]); -#if HEX_DEBUG - /* - * Do this so HELPER(debug_commit_end) will know - * - * Note that slot_mask indicates the value is not written - * (i.e., slot was cancelled), so we create a true/false value before - * or'ing with hex_reg_written[rnum]. - */ - tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero); - tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask); -#endif + if (HEX_DEBUG) { + /* + * Do this so HELPER(debug_commit_end) will know + * + * Note that slot_mask indicates the value is not written + * (i.e., slot was cancelled), so we create a true/false value before + * or'ing with hex_reg_written[rnum]. + */ + tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero); + tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask); + } tcg_temp_free(zero); tcg_temp_free(slot_mask); @@ -61,10 +61,10 @@ static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot) static inline void gen_log_reg_write(int rnum, TCGv val) { tcg_gen_mov_tl(hex_new_value[rnum], val); -#if HEX_DEBUG - /* Do this so HELPER(debug_commit_end) will know */ - tcg_gen_movi_tl(hex_reg_written[rnum], 1); -#endif + if (HEX_DEBUG) { + /* Do this so HELPER(debug_commit_end) will know */ + tcg_gen_movi_tl(hex_reg_written[rnum], 1); + } } static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot) @@ -84,19 +84,19 @@ static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot) tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum + 1], slot_mask, zero, val32, hex_new_value[rnum + 1]); -#if HEX_DEBUG - /* - * Do this so HELPER(debug_commit_end) will know - * - * Note that slot_mask indicates the value is not written - * (i.e., slot was cancelled), so we create a true/false value before - * or'ing with hex_reg_written[rnum]. - */ - tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero); - tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask); - tcg_gen_or_tl(hex_reg_written[rnum + 1], hex_reg_written[rnum + 1], - slot_mask); -#endif + if (HEX_DEBUG) { + /* + * Do this so HELPER(debug_commit_end) will know + * + * Note that slot_mask indicates the value is not written + * (i.e., slot was cancelled), so we create a true/false value before + * or'ing with hex_reg_written[rnum]. + */ + tcg_gen_setcond_tl(TCG_COND_EQ, slot_mask, slot_mask, zero); + tcg_gen_or_tl(hex_reg_written[rnum], hex_reg_written[rnum], slot_mask); + tcg_gen_or_tl(hex_reg_written[rnum + 1], hex_reg_written[rnum + 1], + slot_mask); + } tcg_temp_free(val32); tcg_temp_free(zero); @@ -107,17 +107,17 @@ static void gen_log_reg_write_pair(int rnum, TCGv_i64 val) { /* Low word */ tcg_gen_extrl_i64_i32(hex_new_value[rnum], val); -#if HEX_DEBUG - /* Do this so HELPER(debug_commit_end) will know */ - tcg_gen_movi_tl(hex_reg_written[rnum], 1); -#endif + if (HEX_DEBUG) { + /* Do this so HELPER(debug_commit_end) will know */ + tcg_gen_movi_tl(hex_reg_written[rnum], 1); + } /* High word */ tcg_gen_extrh_i64_i32(hex_new_value[rnum + 1], val); -#if HEX_DEBUG - /* Do this so HELPER(debug_commit_end) will know */ - tcg_gen_movi_tl(hex_reg_written[rnum + 1], 1); -#endif + if (HEX_DEBUG) { + /* Do this so HELPER(debug_commit_end) will know */ + tcg_gen_movi_tl(hex_reg_written[rnum + 1], 1); + } } static inline void gen_log_pred_write(DisasContext *ctx, int pnum, TCGv val) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 715c24662f..efe6069118 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -19,11 +19,9 @@ #include "helper_protos_generated.h.inc" DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_RETURN, noreturn, env, i32) -#if HEX_DEBUG DEF_HELPER_1(debug_start_packet, void, env) DEF_HELPER_FLAGS_3(debug_check_store_width, TCG_CALL_NO_WG, void, env, int, int) DEF_HELPER_FLAGS_3(debug_commit_end, TCG_CALL_NO_WG, void, env, int, int) -#endif DEF_HELPER_2(commit_store, void, env, int) DEF_HELPER_FLAGS_4(fcircadd, TCG_CALL_NO_RWG_SE, s32, s32, s32, s32, s32) diff --git a/target/hexagon/internal.h b/target/hexagon/internal.h index 2da85c8606..6b20affdfa 100644 --- a/target/hexagon/internal.h +++ b/target/hexagon/internal.h @@ -22,11 +22,12 @@ * Change HEX_DEBUG to 1 to turn on debugging output */ #define HEX_DEBUG 0 -#if HEX_DEBUG -#define HEX_DEBUG_LOG(...) qemu_log(__VA_ARGS__) -#else -#define HEX_DEBUG_LOG(...) do { } while (0) -#endif +#define HEX_DEBUG_LOG(...) \ + do { \ + if (HEX_DEBUG) { \ + qemu_log(__VA_ARGS__); \ + } \ + } while (0) int hexagon_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int hexagon_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index b70c5d607a..33b67138ca 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -56,10 +56,10 @@ static void log_reg_write(CPUHexagonState *env, int rnum, HEX_DEBUG_LOG("\n"); env->new_value[rnum] = val; -#if HEX_DEBUG - /* Do this so HELPER(debug_commit_end) will know */ - env->reg_written[rnum] = 1; -#endif + if (HEX_DEBUG) { + /* Do this so HELPER(debug_commit_end) will know */ + env->reg_written[rnum] = 1; + } } static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val) @@ -117,7 +117,6 @@ static void write_new_pc(CPUHexagonState *env, target_ulong addr) } } -#if HEX_DEBUG /* Handy place to set a breakpoint */ void HELPER(debug_start_packet)(CPUHexagonState *env) { @@ -128,14 +127,12 @@ void HELPER(debug_start_packet)(CPUHexagonState *env) env->reg_written[i] = 0; } } -#endif static int32_t new_pred_value(CPUHexagonState *env, int pnum) { return env->new_pred_value[pnum]; } -#if HEX_DEBUG /* Checks for bookkeeping errors between disassembly context and runtime */ void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check) { @@ -145,7 +142,6 @@ void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check) g_assert_not_reached(); } } -#endif void HELPER(commit_store)(CPUHexagonState *env, int slot_num) { @@ -171,7 +167,6 @@ void HELPER(commit_store)(CPUHexagonState *env, int slot_num) } } -#if HEX_DEBUG static void print_store(CPUHexagonState *env, int slot) { if (!(env->slot_cancelled & (1 << slot))) { @@ -255,7 +250,6 @@ void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1) env->gpr[HEX_REG_QEMU_INSN_CNT]); } -#endif static int32_t fcircadd_v4(int32_t RxV, int32_t offset, int32_t M, int32_t CS) { diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 04684221ca..9a37644182 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -35,9 +35,7 @@ TCGv hex_this_PC; TCGv hex_slot_cancelled; TCGv hex_branch_taken; TCGv hex_new_value[TOTAL_PER_THREAD_REGS]; -#if HEX_DEBUG TCGv hex_reg_written[TOTAL_PER_THREAD_REGS]; -#endif TCGv hex_new_pred_value[NUM_PREGS]; TCGv hex_pred_written; TCGv hex_store_addr[STORES_MAX]; @@ -90,7 +88,6 @@ static void gen_exception_end_tb(DisasContext *ctx, int excp) } -#if HEX_DEBUG #define PACKET_BUFFER_LEN 1028 static void print_pkt(Packet *pkt) { @@ -99,10 +96,12 @@ static void print_pkt(Packet *pkt) HEX_DEBUG_LOG("%s", buf->str); g_string_free(buf, true); } -#define HEX_DEBUG_PRINT_PKT(pkt) print_pkt(pkt) -#else -#define HEX_DEBUG_PRINT_PKT(pkt) /* nothing */ -#endif +#define HEX_DEBUG_PRINT_PKT(pkt) \ + do { \ + if (HEX_DEBUG) { \ + print_pkt(pkt); \ + } \ + } while (0) static int read_packet_words(CPUHexagonState *env, DisasContext *ctx, uint32_t words[]) @@ -179,11 +178,11 @@ static void gen_start_packet(DisasContext *ctx, Packet *pkt) tcg_gen_movi_tl(hex_pkt_has_store_s1, pkt->pkt_has_store_s1); ctx->s1_store_processed = false; -#if HEX_DEBUG - /* Handy place to set a breakpoint before the packet executes */ - gen_helper_debug_start_packet(cpu_env); - tcg_gen_movi_tl(hex_this_PC, ctx->base.pc_next); -#endif + if (HEX_DEBUG) { + /* Handy place to set a breakpoint before the packet executes */ + gen_helper_debug_start_packet(cpu_env); + tcg_gen_movi_tl(hex_this_PC, ctx->base.pc_next); + } /* Initialize the runtime state for packet semantics */ if (need_pc(pkt)) { @@ -308,10 +307,11 @@ static void gen_pred_writes(DisasContext *ctx, Packet *pkt) for (i = 0; i < ctx->preg_log_idx; i++) { int pred_num = ctx->preg_log[i]; tcg_gen_mov_tl(hex_pred[pred_num], hex_new_pred_value[pred_num]); -#if HEX_DEBUG - /* Do this so HELPER(debug_commit_end) will know */ - tcg_gen_ori_tl(hex_pred_written, hex_pred_written, 1 << pred_num); -#endif + if (HEX_DEBUG) { + /* Do this so HELPER(debug_commit_end) will know */ + tcg_gen_ori_tl(hex_pred_written, hex_pred_written, + 1 << pred_num); + } } } @@ -322,13 +322,13 @@ static void gen_pred_writes(DisasContext *ctx, Packet *pkt) static void gen_check_store_width(DisasContext *ctx, int slot_num) { -#if HEX_DEBUG - TCGv slot = tcg_const_tl(slot_num); - TCGv check = tcg_const_tl(ctx->store_width[slot_num]); - gen_helper_debug_check_store_width(cpu_env, slot, check); - tcg_temp_free(slot); - tcg_temp_free(check); -#endif + if (HEX_DEBUG) { + TCGv slot = tcg_const_tl(slot_num); + TCGv check = tcg_const_tl(ctx->store_width[slot_num]); + gen_helper_debug_check_store_width(cpu_env, slot, check); + tcg_temp_free(slot); + tcg_temp_free(check); + } } static bool slot_is_predicated(Packet *pkt, int slot_num) @@ -482,8 +482,7 @@ static void gen_commit_packet(DisasContext *ctx, Packet *pkt) process_store_log(ctx, pkt); process_dczeroa(ctx, pkt); update_exec_counters(ctx, pkt); -#if HEX_DEBUG - { + if (HEX_DEBUG) { TCGv has_st0 = tcg_const_tl(pkt->pkt_has_store_s0 && !pkt->pkt_has_dczeroa); TCGv has_st1 = @@ -495,7 +494,6 @@ static void gen_commit_packet(DisasContext *ctx, Packet *pkt) tcg_temp_free(has_st0); tcg_temp_free(has_st1); } -#endif if (pkt->pkt_has_cof) { gen_end_tb(ctx); @@ -655,9 +653,7 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) #define NAME_LEN 64 static char new_value_names[TOTAL_PER_THREAD_REGS][NAME_LEN]; -#if HEX_DEBUG static char reg_written_names[TOTAL_PER_THREAD_REGS][NAME_LEN]; -#endif static char new_pred_value_names[NUM_PREGS][NAME_LEN]; static char store_addr_names[STORES_MAX][NAME_LEN]; static char store_width_names[STORES_MAX][NAME_LEN]; @@ -670,11 +666,11 @@ void hexagon_translate_init(void) opcode_init(); -#if HEX_DEBUG - if (!qemu_logfile) { - qemu_set_log(qemu_loglevel); + if (HEX_DEBUG) { + if (!qemu_logfile) { + qemu_set_log(qemu_loglevel); + } } -#endif for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) { hex_gpr[i] = tcg_global_mem_new(cpu_env, @@ -686,13 +682,13 @@ void hexagon_translate_init(void) offsetof(CPUHexagonState, new_value[i]), new_value_names[i]); -#if HEX_DEBUG - snprintf(reg_written_names[i], NAME_LEN, "reg_written_%s", - hexagon_regnames[i]); - hex_reg_written[i] = tcg_global_mem_new(cpu_env, - offsetof(CPUHexagonState, reg_written[i]), - reg_written_names[i]); -#endif + if (HEX_DEBUG) { + snprintf(reg_written_names[i], NAME_LEN, "reg_written_%s", + hexagon_regnames[i]); + hex_reg_written[i] = tcg_global_mem_new(cpu_env, + offsetof(CPUHexagonState, reg_written[i]), + reg_written_names[i]); + } } for (i = 0; i < NUM_PREGS; i++) { hex_pred[i] = tcg_global_mem_new(cpu_env, diff --git a/target/hexagon/translate.h b/target/hexagon/translate.h index 97b12a7d18..703fd1345f 100644 --- a/target/hexagon/translate.h +++ b/target/hexagon/translate.h @@ -41,11 +41,9 @@ typedef struct DisasContext { static inline void ctx_log_reg_write(DisasContext *ctx, int rnum) { -#if HEX_DEBUG if (test_bit(rnum, ctx->regs_written)) { HEX_DEBUG_LOG("WARNING: Multiple writes to r%d\n", rnum); } -#endif ctx->reg_log[ctx->reg_log_idx] = rnum; ctx->reg_log_idx++; set_bit(rnum, ctx->regs_written); From d934c16d8a1e0fb82fd4abfa54dcb5217430577c Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:45 -0500 Subject: [PATCH 0158/3028] Hexagon (target/hexagon) add F2_sfrecipa instruction Rd32,Pe4 = sfrecipa(Rs32, Rt32) Recripocal approx Test cases in tests/tcg/hexagon/multi_result.c FP exception tests added to tests/tcg/hexagon/fpstuff.c Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-18-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/arch.c | 26 ++++++++- target/hexagon/arch.h | 2 + target/hexagon/gen_tcg.h | 21 +++++++ target/hexagon/helper.h | 1 + target/hexagon/imported/encode_pp.def | 1 + target/hexagon/imported/float.idef | 16 ++++++ target/hexagon/op_helper.c | 37 ++++++++++++ tests/tcg/hexagon/Makefile.target | 1 + tests/tcg/hexagon/fpstuff.c | 82 +++++++++++++++++++++++++++ tests/tcg/hexagon/multi_result.c | 68 ++++++++++++++++++++++ 10 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 tests/tcg/hexagon/multi_result.c diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c index 40b6e3d0c0..46edf45b13 100644 --- a/target/hexagon/arch.c +++ b/target/hexagon/arch.c @@ -181,12 +181,13 @@ int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd, int *adjust, /* or put Inf in num fixup? */ uint8_t RsV_sign = float32_is_neg(RsV); uint8_t RtV_sign = float32_is_neg(RtV); + /* Check that RsV is NOT infinite before we overwrite it */ + if (!float32_is_infinity(RsV)) { + float_raise(float_flag_divbyzero, fp_status); + } RsV = infinite_float32(RsV_sign ^ RtV_sign); RtV = float32_one; RdV = float32_one; - if (float32_is_infinity(RsV)) { - float_raise(float_flag_divbyzero, fp_status); - } } else if (float32_is_infinity(RtV)) { RsV = make_float32(0x80000000 & (RsV ^ RtV)); RtV = float32_one; @@ -279,3 +280,22 @@ int arch_sf_invsqrt_common(float32 *Rs, float32 *Rd, int *adjust, *adjust = PeV; return ret; } + +const uint8_t recip_lookup_table[128] = { + 0x0fe, 0x0fa, 0x0f6, 0x0f2, 0x0ef, 0x0eb, 0x0e7, 0x0e4, + 0x0e0, 0x0dd, 0x0d9, 0x0d6, 0x0d2, 0x0cf, 0x0cc, 0x0c9, + 0x0c6, 0x0c2, 0x0bf, 0x0bc, 0x0b9, 0x0b6, 0x0b3, 0x0b1, + 0x0ae, 0x0ab, 0x0a8, 0x0a5, 0x0a3, 0x0a0, 0x09d, 0x09b, + 0x098, 0x096, 0x093, 0x091, 0x08e, 0x08c, 0x08a, 0x087, + 0x085, 0x083, 0x080, 0x07e, 0x07c, 0x07a, 0x078, 0x075, + 0x073, 0x071, 0x06f, 0x06d, 0x06b, 0x069, 0x067, 0x065, + 0x063, 0x061, 0x05f, 0x05e, 0x05c, 0x05a, 0x058, 0x056, + 0x054, 0x053, 0x051, 0x04f, 0x04e, 0x04c, 0x04a, 0x049, + 0x047, 0x045, 0x044, 0x042, 0x040, 0x03f, 0x03d, 0x03c, + 0x03a, 0x039, 0x037, 0x036, 0x034, 0x033, 0x032, 0x030, + 0x02f, 0x02d, 0x02c, 0x02b, 0x029, 0x028, 0x027, 0x025, + 0x024, 0x023, 0x021, 0x020, 0x01f, 0x01e, 0x01c, 0x01b, + 0x01a, 0x019, 0x017, 0x016, 0x015, 0x014, 0x013, 0x012, + 0x011, 0x00f, 0x00e, 0x00d, 0x00c, 0x00b, 0x00a, 0x009, + 0x008, 0x007, 0x006, 0x005, 0x004, 0x003, 0x002, 0x000, +}; diff --git a/target/hexagon/arch.h b/target/hexagon/arch.h index 6e0b0d9a24..b6634e9615 100644 --- a/target/hexagon/arch.h +++ b/target/hexagon/arch.h @@ -30,4 +30,6 @@ int arch_sf_recip_common(float32 *Rs, float32 *Rt, float32 *Rd, int arch_sf_invsqrt_common(float32 *Rs, float32 *Rd, int *adjust, float_status *fp_status); +extern const uint8_t recip_lookup_table[128]; + #endif diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index a30048ee57..428a670281 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -195,6 +195,27 @@ #define fGEN_TCG_S4_stored_locked(SHORTCODE) \ do { SHORTCODE; READ_PREG(PdV, PdN); } while (0) +/* + * Mathematical operations with more than one definition require + * special handling + */ + +/* + * Approximate reciprocal + * r3,p1 = sfrecipa(r0, r1) + * + * The helper packs the 2 32-bit results into a 64-bit value, + * so unpack them into the proper results. + */ +#define fGEN_TCG_F2_sfrecipa(SHORTCODE) \ + do { \ + TCGv_i64 tmp = tcg_temp_new_i64(); \ + gen_helper_sfrecipa(tmp, cpu_env, RsV, RtV); \ + tcg_gen_extrh_i64_i32(RdV, tmp); \ + tcg_gen_extrl_i64_i32(PeV, tmp); \ + tcg_temp_free_i64(tmp); \ + } while (0) + /* Floating point */ #define fGEN_TCG_F2_conv_sf2df(SHORTCODE) \ gen_helper_conv_sf2df(RddV, cpu_env, RsV) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index efe6069118..b377293dd3 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -24,6 +24,7 @@ DEF_HELPER_FLAGS_3(debug_check_store_width, TCG_CALL_NO_WG, void, env, int, int) DEF_HELPER_FLAGS_3(debug_commit_end, TCG_CALL_NO_WG, void, env, int, int) DEF_HELPER_2(commit_store, void, env, int) DEF_HELPER_FLAGS_4(fcircadd, TCG_CALL_NO_RWG_SE, s32, s32, s32, s32, s32) +DEF_HELPER_3(sfrecipa, i64, env, f32, f32) /* Floating point */ DEF_HELPER_2(conv_sf2df, f64, env, f32) diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index c21cb730af..b01b4d7aa7 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -1028,6 +1028,7 @@ MPY_ENC(F2_sfmin, "1011","ddddd","0","0","0","1","01") MPY_ENC(F2_sfmpy, "1011","ddddd","0","0","1","0","00") MPY_ENC(F2_sffixupn, "1011","ddddd","0","0","1","1","00") MPY_ENC(F2_sffixupd, "1011","ddddd","0","0","1","1","01") +MPY_ENC(F2_sfrecipa, "1011","ddddd","1","1","1","1","ee") DEF_FIELDROW_DESC32(ICLASS_M" 1100 -------- PP------ --------","[#12] Rd=(Rs,Rt)") DEF_FIELD32(ICLASS_M" 1100 -------- PP------ --!-----",Mc_tH,"Rt is High") /*Rt high */ diff --git a/target/hexagon/imported/float.idef b/target/hexagon/imported/float.idef index 76cecfebf5..eb5415801a 100644 --- a/target/hexagon/imported/float.idef +++ b/target/hexagon/imported/float.idef @@ -146,6 +146,22 @@ Q6INSN(F2_sfimm_n,"Rd32=sfmake(#u10):neg",ATTRIBS(), }) +Q6INSN(F2_sfrecipa,"Rd32,Pe4=sfrecipa(Rs32,Rt32)",ATTRIBS(), +"Reciprocal Approximation for Division", +{ + fHIDE(int idx;) + fHIDE(int adjust;) + fHIDE(int mant;) + fHIDE(int exp;) + if (fSF_RECIP_COMMON(RsV,RtV,RdV,adjust)) { + PeV = adjust; + idx = (RtV >> 16) & 0x7f; + mant = (fSF_RECIP_LOOKUP(idx) << 15) | 1; + exp = fSF_BIAS() - (fSF_GETEXP(RtV) - fSF_BIAS()) - 1; + RdV = fMAKESF(fGETBIT(31,RtV),exp,mant); + } +}) + Q6INSN(F2_sffixupn,"Rd32=sffixupn(Rs32,Rt32)",ATTRIBS(), "Fix Up Numerator", { diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 33b67138ca..75861e26c4 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -289,6 +289,43 @@ int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS) return new_ptr; } +static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant) +{ + return make_float32( + ((sign & 1) << 31) | + ((exp & 0xff) << SF_MANTBITS) | + (mant & ((1 << SF_MANTBITS) - 1))); +} + +/* + * sfrecipa, sfinvsqrta have two 32-bit results + * r0,p0=sfrecipa(r1,r2) + * r0,p0=sfinvsqrta(r1) + * + * Since helpers can only return a single value, we pack the two results + * into a 64-bit value. + */ +uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV) +{ + int32_t PeV = 0; + float32 RdV; + int idx; + int adjust; + int mant; + int exp; + + arch_fpop_start(env); + if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) { + PeV = adjust; + idx = (RtV >> 16) & 0x7f; + mant = (recip_lookup_table[idx] << 15) | 1; + exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1; + RdV = build_float32(extract32(RtV, 31, 1), exp, mant); + } + arch_fpop_end(env); + return ((uint64_t)RdV << 32) | PeV; +} + /* * mem_noshuf * Section 5.5 of the Hexagon V67 Programmer's Reference Manual diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index 616af697fe..18218ad05a 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -39,6 +39,7 @@ HEX_TESTS = first HEX_TESTS += misc HEX_TESTS += preg_alias HEX_TESTS += dual_stores +HEX_TESTS += multi_result HEX_TESTS += mem_noshuf HEX_TESTS += atomics HEX_TESTS += fpstuff diff --git a/tests/tcg/hexagon/fpstuff.c b/tests/tcg/hexagon/fpstuff.c index 6b60f92d18..8e3ba780d2 100644 --- a/tests/tcg/hexagon/fpstuff.c +++ b/tests/tcg/hexagon/fpstuff.c @@ -250,6 +250,87 @@ static void check_dfminmax(void) check_fpstatus(usr, FPINVF); } +static void check_recip_exception(void) +{ + int result; + int usr; + + /* + * Check that sfrecipa doesn't set status bits when + * a NaN with bit 22 non-zero is passed + */ + asm (CLEAR_FPSTATUS + "%0,p0 = sfrecipa(%2, %3)\n\t" + "%1 = usr\n\t" + : "=r"(result), "=r"(usr) : "r"(SF_NaN), "r"(SF_ANY) + : "r2", "p0", "usr"); + check32(result, SF_HEX_NAN); + check_fpstatus(usr, 0); + + asm (CLEAR_FPSTATUS + "%0,p0 = sfrecipa(%2, %3)\n\t" + "%1 = usr\n\t" + : "=r"(result), "=r"(usr) : "r"(SF_ANY), "r"(SF_NaN) + : "r2", "p0", "usr"); + check32(result, SF_HEX_NAN); + check_fpstatus(usr, 0); + + asm (CLEAR_FPSTATUS + "%0,p0 = sfrecipa(%2, %2)\n\t" + "%1 = usr\n\t" + : "=r"(result), "=r"(usr) : "r"(SF_NaN) + : "r2", "p0", "usr"); + check32(result, SF_HEX_NAN); + check_fpstatus(usr, 0); + + /* + * Check that sfrecipa doesn't set status bits when + * a NaN with bit 22 zero is passed + */ + asm (CLEAR_FPSTATUS + "%0,p0 = sfrecipa(%2, %3)\n\t" + "%1 = usr\n\t" + : "=r"(result), "=r"(usr) : "r"(SF_NaN_special), "r"(SF_ANY) + : "r2", "p0", "usr"); + check32(result, SF_HEX_NAN); + check_fpstatus(usr, FPINVF); + + asm (CLEAR_FPSTATUS + "%0,p0 = sfrecipa(%2, %3)\n\t" + "%1 = usr\n\t" + : "=r"(result), "=r"(usr) : "r"(SF_ANY), "r"(SF_NaN_special) + : "r2", "p0", "usr"); + check32(result, SF_HEX_NAN); + check_fpstatus(usr, FPINVF); + + asm (CLEAR_FPSTATUS + "%0,p0 = sfrecipa(%2, %2)\n\t" + "%1 = usr\n\t" + : "=r"(result), "=r"(usr) : "r"(SF_NaN_special) + : "r2", "p0", "usr"); + check32(result, SF_HEX_NAN); + check_fpstatus(usr, FPINVF); + + /* + * Check that sfrecipa properly sets divid-by-zero + */ + asm (CLEAR_FPSTATUS + "%0,p0 = sfrecipa(%2, %3)\n\t" + "%1 = usr\n\t" + : "=r"(result), "=r"(usr) : "r"(0x885dc960), "r"(0x80000000) + : "r2", "p0", "usr"); + check32(result, 0x3f800000); + check_fpstatus(usr, FPDBZF); + + asm (CLEAR_FPSTATUS + "%0,p0 = sfrecipa(%2, %3)\n\t" + "%1 = usr\n\t" + : "=r"(result), "=r"(usr) : "r"(0x7f800000), "r"(SF_ZERO) + : "r2", "p0", "usr"); + check32(result, 0x3f800000); + check_fpstatus(usr, 0); +} + static void check_canonical_NaN(void) { int sf_result; @@ -507,6 +588,7 @@ int main() check_compare_exception(); check_sfminmax(); check_dfminmax(); + check_recip_exception(); check_canonical_NaN(); check_float2int_convs(); diff --git a/tests/tcg/hexagon/multi_result.c b/tests/tcg/hexagon/multi_result.c new file mode 100644 index 0000000000..cb7dd313d4 --- /dev/null +++ b/tests/tcg/hexagon/multi_result.c @@ -0,0 +1,68 @@ +/* + * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +static int sfrecipa(int Rs, int Rt, int *pred_result) +{ + int result; + int predval; + + asm volatile("%0,p0 = sfrecipa(%2, %3)\n\t" + "%1 = p0\n\t" + : "+r"(result), "=r"(predval) + : "r"(Rs), "r"(Rt) + : "p0"); + *pred_result = predval; + return result; +} + +int err; + +static void check(int val, int expect) +{ + if (val != expect) { + printf("ERROR: 0x%08x != 0x%08x\n", val, expect); + err++; + } +} + +static void check_p(int val, int expect) +{ + if (val != expect) { + printf("ERROR: 0x%02x != 0x%02x\n", val, expect); + err++; + } +} + +static void test_sfrecipa() +{ + int res; + int pred_result; + + res = sfrecipa(0x04030201, 0x05060708, &pred_result); + check(res, 0x59f38001); + check_p(pred_result, 0x00); +} + +int main() +{ + test_sfrecipa(); + + puts(err ? "FAIL" : "PASS"); + return err; +} From dd8705bdf529d2c694ec3a4d4a2c18bb770d5c6c Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:46 -0500 Subject: [PATCH 0159/3028] Hexagon (target/hexagon) add F2_sfinvsqrta Rd32,Pe4 = sfinvsqrta(Rs32) Square root approx The helper packs the 2 32-bit results into a 64-bit value, and the fGEN_TCG override unpacks them into the proper results. Test cases in tests/tcg/hexagon/multi_result.c FP exception tests added to tests/tcg/hexagon/fpstuff.c Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-19-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/arch.c | 21 ++++++++++++++++++- target/hexagon/arch.h | 2 ++ target/hexagon/gen_tcg.h | 16 +++++++++++++++ target/hexagon/helper.h | 1 + target/hexagon/imported/encode_pp.def | 1 + target/hexagon/imported/float.idef | 16 +++++++++++++++ target/hexagon/op_helper.c | 21 +++++++++++++++++++ tests/tcg/hexagon/fpstuff.c | 15 ++++++++++++++ tests/tcg/hexagon/multi_result.c | 29 +++++++++++++++++++++++++++ 9 files changed, 121 insertions(+), 1 deletion(-) diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c index 46edf45b13..dee852e106 100644 --- a/target/hexagon/arch.c +++ b/target/hexagon/arch.c @@ -247,7 +247,7 @@ int arch_sf_invsqrt_common(float32 *Rs, float32 *Rd, int *adjust, int r_exp; int ret = 0; RsV = *Rs; - if (float32_is_infinity(RsV)) { + if (float32_is_any_nan(RsV)) { if (extract32(RsV, 22, 1) == 0) { float_raise(float_flag_invalid, fp_status); } @@ -299,3 +299,22 @@ const uint8_t recip_lookup_table[128] = { 0x011, 0x00f, 0x00e, 0x00d, 0x00c, 0x00b, 0x00a, 0x009, 0x008, 0x007, 0x006, 0x005, 0x004, 0x003, 0x002, 0x000, }; + +const uint8_t invsqrt_lookup_table[128] = { + 0x069, 0x066, 0x063, 0x061, 0x05e, 0x05b, 0x059, 0x057, + 0x054, 0x052, 0x050, 0x04d, 0x04b, 0x049, 0x047, 0x045, + 0x043, 0x041, 0x03f, 0x03d, 0x03b, 0x039, 0x037, 0x036, + 0x034, 0x032, 0x030, 0x02f, 0x02d, 0x02c, 0x02a, 0x028, + 0x027, 0x025, 0x024, 0x022, 0x021, 0x01f, 0x01e, 0x01d, + 0x01b, 0x01a, 0x019, 0x017, 0x016, 0x015, 0x014, 0x012, + 0x011, 0x010, 0x00f, 0x00d, 0x00c, 0x00b, 0x00a, 0x009, + 0x008, 0x007, 0x006, 0x005, 0x004, 0x003, 0x002, 0x001, + 0x0fe, 0x0fa, 0x0f6, 0x0f3, 0x0ef, 0x0eb, 0x0e8, 0x0e4, + 0x0e1, 0x0de, 0x0db, 0x0d7, 0x0d4, 0x0d1, 0x0ce, 0x0cb, + 0x0c9, 0x0c6, 0x0c3, 0x0c0, 0x0be, 0x0bb, 0x0b8, 0x0b6, + 0x0b3, 0x0b1, 0x0af, 0x0ac, 0x0aa, 0x0a8, 0x0a5, 0x0a3, + 0x0a1, 0x09f, 0x09d, 0x09b, 0x099, 0x097, 0x095, 0x093, + 0x091, 0x08f, 0x08d, 0x08b, 0x089, 0x087, 0x086, 0x084, + 0x082, 0x080, 0x07f, 0x07d, 0x07b, 0x07a, 0x078, 0x077, + 0x075, 0x074, 0x072, 0x071, 0x06f, 0x06e, 0x06c, 0x06b, +}; diff --git a/target/hexagon/arch.h b/target/hexagon/arch.h index b6634e9615..3e0c334209 100644 --- a/target/hexagon/arch.h +++ b/target/hexagon/arch.h @@ -32,4 +32,6 @@ int arch_sf_invsqrt_common(float32 *Rs, float32 *Rd, int *adjust, extern const uint8_t recip_lookup_table[128]; +extern const uint8_t invsqrt_lookup_table[128]; + #endif diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index 428a670281..d78e7b8e5c 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -216,6 +216,22 @@ tcg_temp_free_i64(tmp); \ } while (0) +/* + * Approximation of the reciprocal square root + * r1,p0 = sfinvsqrta(r0) + * + * The helper packs the 2 32-bit results into a 64-bit value, + * so unpack them into the proper results. + */ +#define fGEN_TCG_F2_sfinvsqrta(SHORTCODE) \ + do { \ + TCGv_i64 tmp = tcg_temp_new_i64(); \ + gen_helper_sfinvsqrta(tmp, cpu_env, RsV); \ + tcg_gen_extrh_i64_i32(RdV, tmp); \ + tcg_gen_extrl_i64_i32(PeV, tmp); \ + tcg_temp_free_i64(tmp); \ + } while (0) + /* Floating point */ #define fGEN_TCG_F2_conv_sf2df(SHORTCODE) \ gen_helper_conv_sf2df(RddV, cpu_env, RsV) diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index b377293dd3..cb7508f746 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -25,6 +25,7 @@ DEF_HELPER_FLAGS_3(debug_commit_end, TCG_CALL_NO_WG, void, env, int, int) DEF_HELPER_2(commit_store, void, env, int) DEF_HELPER_FLAGS_4(fcircadd, TCG_CALL_NO_RWG_SE, s32, s32, s32, s32, s32) DEF_HELPER_3(sfrecipa, i64, env, f32, f32) +DEF_HELPER_2(sfinvsqrta, i64, env, f32) /* Floating point */ DEF_HELPER_2(conv_sf2df, f64, env, f32) diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index b01b4d7aa7..18fe45d696 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -1642,6 +1642,7 @@ SH2_RR_ENC(F2_conv_sf2w, "1011","100","-","000","ddddd") SH2_RR_ENC(F2_conv_sf2uw_chop, "1011","011","-","001","ddddd") SH2_RR_ENC(F2_conv_sf2w_chop, "1011","100","-","001","ddddd") SH2_RR_ENC(F2_sffixupr, "1011","101","-","000","ddddd") +SH2_RR_ENC(F2_sfinvsqrta, "1011","111","-","0ee","ddddd") DEF_FIELDROW_DESC32(ICLASS_S2op" 1100 -------- PP------ --------","[#12] Rd=(Rs,#u6)") diff --git a/target/hexagon/imported/float.idef b/target/hexagon/imported/float.idef index eb5415801a..3e75bc4604 100644 --- a/target/hexagon/imported/float.idef +++ b/target/hexagon/imported/float.idef @@ -178,6 +178,22 @@ Q6INSN(F2_sffixupd,"Rd32=sffixupd(Rs32,Rt32)",ATTRIBS(), RdV = RtV; }) +Q6INSN(F2_sfinvsqrta,"Rd32,Pe4=sfinvsqrta(Rs32)",ATTRIBS(), +"Reciprocal Square Root Approximation", +{ + fHIDE(int idx;) + fHIDE(int adjust;) + fHIDE(int mant;) + fHIDE(int exp;) + if (fSF_INVSQRT_COMMON(RsV,RdV,adjust)) { + PeV = adjust; + idx = (RsV >> 17) & 0x7f; + mant = (fSF_INVSQRT_LOOKUP(idx) << 15); + exp = fSF_BIAS() - ((fSF_GETEXP(RsV) - fSF_BIAS()) >> 1) - 1; + RdV = fMAKESF(fGETBIT(31,RsV),exp,mant); + } +}) + Q6INSN(F2_sffixupr,"Rd32=sffixupr(Rs32)",ATTRIBS(), "Fix Up Radicand", { diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 75861e26c4..a25fb98f24 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -326,6 +326,27 @@ uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV) return ((uint64_t)RdV << 32) | PeV; } +uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV) +{ + int PeV = 0; + float32 RdV; + int idx; + int adjust; + int mant; + int exp; + + arch_fpop_start(env); + if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) { + PeV = adjust; + idx = (RsV >> 17) & 0x7f; + mant = (invsqrt_lookup_table[idx] << 15); + exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1; + RdV = build_float32(extract32(RsV, 31, 1), exp, mant); + } + arch_fpop_end(env); + return ((uint64_t)RdV << 32) | PeV; +} + /* * mem_noshuf * Section 5.5 of the Hexagon V67 Programmer's Reference Manual diff --git a/tests/tcg/hexagon/fpstuff.c b/tests/tcg/hexagon/fpstuff.c index 8e3ba780d2..0dff429f4c 100644 --- a/tests/tcg/hexagon/fpstuff.c +++ b/tests/tcg/hexagon/fpstuff.c @@ -441,6 +441,20 @@ static void check_canonical_NaN(void) check_fpstatus(usr, 0); } +static void check_invsqrta(void) +{ + int result; + int predval; + + asm volatile("%0,p0 = sfinvsqrta(%2)\n\t" + "%1 = p0\n\t" + : "+r"(result), "=r"(predval) + : "r"(0x7f800000) + : "p0"); + check32(result, 0xff800000); + check32(predval, 0x0); +} + static void check_float2int_convs() { int res32; @@ -590,6 +604,7 @@ int main() check_dfminmax(); check_recip_exception(); check_canonical_NaN(); + check_invsqrta(); check_float2int_convs(); puts(err ? "FAIL" : "PASS"); diff --git a/tests/tcg/hexagon/multi_result.c b/tests/tcg/hexagon/multi_result.c index cb7dd313d4..67aa46249b 100644 --- a/tests/tcg/hexagon/multi_result.c +++ b/tests/tcg/hexagon/multi_result.c @@ -31,6 +31,20 @@ static int sfrecipa(int Rs, int Rt, int *pred_result) return result; } +static int sfinvsqrta(int Rs, int *pred_result) +{ + int result; + int predval; + + asm volatile("%0,p0 = sfinvsqrta(%2)\n\t" + "%1 = p0\n\t" + : "+r"(result), "=r"(predval) + : "r"(Rs) + : "p0"); + *pred_result = predval; + return result; +} + int err; static void check(int val, int expect) @@ -59,9 +73,24 @@ static void test_sfrecipa() check_p(pred_result, 0x00); } +static void test_sfinvsqrta() +{ + int res; + int pred_result; + + res = sfinvsqrta(0x04030201, &pred_result); + check(res, 0x4d330000); + check_p(pred_result, 0xe0); + + res = sfinvsqrta(0x0, &pred_result); + check(res, 0x3f800000); + check_p(pred_result, 0x0); +} + int main() { test_sfrecipa(); + test_sfinvsqrta(); puts(err ? "FAIL" : "PASS"); return err; From da74cd2dced1ca36ffa864e70cf5ee8d3a8c1fab Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:47 -0500 Subject: [PATCH 0160/3028] Hexagon (target/hexagon) add A5_ACS (vacsh) Rxx32,Pe4 = vacsh(Rss32, Rtt32) Add compare and select elements of two vectors Test cases in tests/tcg/hexagon/multi_result.c Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-20-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/gen_tcg.h | 5 ++ target/hexagon/helper.h | 2 + target/hexagon/imported/alu.idef | 19 ++++++++ target/hexagon/imported/encode_pp.def | 1 + target/hexagon/op_helper.c | 33 +++++++++++++ tests/tcg/hexagon/multi_result.c | 69 +++++++++++++++++++++++++++ 6 files changed, 129 insertions(+) diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index d78e7b8e5c..93310c5edc 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -199,6 +199,11 @@ * Mathematical operations with more than one definition require * special handling */ +#define fGEN_TCG_A5_ACS(SHORTCODE) \ + do { \ + gen_helper_vacsh_pred(PeV, cpu_env, RxxV, RssV, RttV); \ + gen_helper_vacsh_val(RxxV, cpu_env, RxxV, RssV, RttV); \ + } while (0) /* * Approximate reciprocal diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index cb7508f746..3824ae01ea 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -26,6 +26,8 @@ DEF_HELPER_2(commit_store, void, env, int) DEF_HELPER_FLAGS_4(fcircadd, TCG_CALL_NO_RWG_SE, s32, s32, s32, s32, s32) DEF_HELPER_3(sfrecipa, i64, env, f32, f32) DEF_HELPER_2(sfinvsqrta, i64, env, f32) +DEF_HELPER_4(vacsh_val, s64, env, s64, s64, s64) +DEF_HELPER_FLAGS_4(vacsh_pred, TCG_CALL_NO_RWG_SE, s32, env, s64, s64, s64) /* Floating point */ DEF_HELPER_2(conv_sf2df, f64, env, f32) diff --git a/target/hexagon/imported/alu.idef b/target/hexagon/imported/alu.idef index 45cc529fbc..e8cc52c290 100644 --- a/target/hexagon/imported/alu.idef +++ b/target/hexagon/imported/alu.idef @@ -1240,6 +1240,25 @@ MINMAX(uw,WORD,UWORD,2) #undef VMINORMAX3 +Q6INSN(A5_ACS,"Rxx32,Pe4=vacsh(Rss32,Rtt32)",ATTRIBS(), +"Add Compare and Select elements of two vectors, record the maximums and the decisions ", +{ + fHIDE(int i;) + fHIDE(int xv;) + fHIDE(int sv;) + fHIDE(int tv;) + for (i = 0; i < 4; i++) { + xv = (int) fGETHALF(i,RxxV); + sv = (int) fGETHALF(i,RssV); + tv = (int) fGETHALF(i,RttV); + xv = xv + tv; //assumes 17bit datapath + sv = sv - tv; //assumes 17bit datapath + fSETBIT(i*2, PeV, (xv > sv)); + fSETBIT(i*2+1,PeV, (xv > sv)); + fSETHALF(i, RxxV, fSATH(fMAX(xv,sv))); + } +}) + /**********************************************/ /* Vector Min/Max */ /**********************************************/ diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index 18fe45d696..87e0426c05 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -1017,6 +1017,7 @@ MPY_ENC(M7_dcmpyiwc_acc, "1010","xxxxx","1","0","1","0","10") +MPY_ENC(A5_ACS, "1010","xxxxx","0","1","0","1","ee") /* */ diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index a25fb98f24..f9fb65555b 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -347,6 +347,39 @@ uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV) return ((uint64_t)RdV << 32) | PeV; } +int64_t HELPER(vacsh_val)(CPUHexagonState *env, + int64_t RxxV, int64_t RssV, int64_t RttV) +{ + for (int i = 0; i < 4; i++) { + int xv = sextract64(RxxV, i * 16, 16); + int sv = sextract64(RssV, i * 16, 16); + int tv = sextract64(RttV, i * 16, 16); + int max; + xv = xv + tv; + sv = sv - tv; + max = xv > sv ? xv : sv; + /* Note that fSATH can set the OVF bit in usr */ + RxxV = deposit64(RxxV, i * 16, 16, fSATH(max)); + } + return RxxV; +} + +int32_t HELPER(vacsh_pred)(CPUHexagonState *env, + int64_t RxxV, int64_t RssV, int64_t RttV) +{ + int32_t PeV = 0; + for (int i = 0; i < 4; i++) { + int xv = sextract64(RxxV, i * 16, 16); + int sv = sextract64(RssV, i * 16, 16); + int tv = sextract64(RttV, i * 16, 16); + xv = xv + tv; + sv = sv - tv; + PeV = deposit32(PeV, i * 2, 1, (xv > sv)); + PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv)); + } + return PeV; +} + /* * mem_noshuf * Section 5.5 of the Hexagon V67 Programmer's Reference Manual diff --git a/tests/tcg/hexagon/multi_result.c b/tests/tcg/hexagon/multi_result.c index 67aa46249b..c21148fc20 100644 --- a/tests/tcg/hexagon/multi_result.c +++ b/tests/tcg/hexagon/multi_result.c @@ -45,8 +45,41 @@ static int sfinvsqrta(int Rs, int *pred_result) return result; } +static long long vacsh(long long Rxx, long long Rss, long long Rtt, + int *pred_result, int *ovf_result) +{ + long long result = Rxx; + int predval; + int usr; + + /* + * This instruction can set bit 0 (OVF/overflow) in usr + * Clear the bit first, then return that bit to the caller + */ + asm volatile("r2 = usr\n\t" + "r2 = clrbit(r2, #0)\n\t" /* clear overflow bit */ + "usr = r2\n\t" + "%0,p0 = vacsh(%3, %4)\n\t" + "%1 = p0\n\t" + "%2 = usr\n\t" + : "+r"(result), "=r"(predval), "=r"(usr) + : "r"(Rss), "r"(Rtt) + : "r2", "p0", "usr"); + *pred_result = predval; + *ovf_result = (usr & 1); + return result; +} + int err; +static void check_ll(long long val, long long expect) +{ + if (val != expect) { + printf("ERROR: 0x%016llx != 0x%016llx\n", val, expect); + err++; + } +} + static void check(int val, int expect) { if (val != expect) { @@ -87,10 +120,46 @@ static void test_sfinvsqrta() check_p(pred_result, 0x0); } +static void test_vacsh() +{ + long long res64; + int pred_result; + int ovf_result; + + res64 = vacsh(0x0004000300020001LL, + 0x0001000200030004LL, + 0x0000000000000000LL, &pred_result, &ovf_result); + check_ll(res64, 0x0004000300030004LL); + check_p(pred_result, 0xf0); + check(ovf_result, 0); + + res64 = vacsh(0x0004000300020001LL, + 0x0001000200030004LL, + 0x000affff000d0000LL, &pred_result, &ovf_result); + check_ll(res64, 0x000e0003000f0004LL); + check_p(pred_result, 0xcc); + check(ovf_result, 0); + + res64 = vacsh(0x00047fff00020001LL, + 0x00017fff00030004LL, + 0x000a0fff000d0000LL, &pred_result, &ovf_result); + check_ll(res64, 0x000e7fff000f0004LL); + check_p(pred_result, 0xfc); + check(ovf_result, 1); + + res64 = vacsh(0x0004000300020001LL, + 0x0001000200030009LL, + 0x000affff000d0001LL, &pred_result, &ovf_result); + check_ll(res64, 0x000e0003000f0008LL); + check_p(pred_result, 0xcc); + check(ovf_result, 0); +} + int main() { test_sfrecipa(); test_sfinvsqrta(); + test_vacsh(); puts(err ? "FAIL" : "PASS"); return err; From 0a65d286936a5fd0ac459a0a047e527ce55731e3 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:48 -0500 Subject: [PATCH 0161/3028] Hexagon (target/hexagon) add A6_vminub_RdP Rdd32,Pe4 = vminub(Rtt32, Rss32) Vector min of bytes Test cases in tests/tcg/hexagon/multi_result.c Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-21-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/gen_tcg.h | 27 +++++++++++++++++++++ target/hexagon/genptr.c | 22 +++++++++++++++++ target/hexagon/imported/alu.idef | 10 ++++++++ target/hexagon/imported/encode_pp.def | 1 + tests/tcg/hexagon/multi_result.c | 34 +++++++++++++++++++++++++++ 5 files changed, 94 insertions(+) diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index 93310c5edc..aea0c55564 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -237,6 +237,33 @@ tcg_temp_free_i64(tmp); \ } while (0) +/* + * Compare each of the 8 unsigned bytes + * The minimum is placed in each byte of the destination. + * Each bit of the predicate is set true if the bit from the first operand + * is greater than the bit from the second operand. + * r5:4,p1 = vminub(r1:0, r3:2) + */ +#define fGEN_TCG_A6_vminub_RdP(SHORTCODE) \ + do { \ + TCGv left = tcg_temp_new(); \ + TCGv right = tcg_temp_new(); \ + TCGv tmp = tcg_temp_new(); \ + tcg_gen_movi_tl(PeV, 0); \ + tcg_gen_movi_i64(RddV, 0); \ + for (int i = 0; i < 8; i++) { \ + gen_get_byte_i64(left, i, RttV, false); \ + gen_get_byte_i64(right, i, RssV, false); \ + tcg_gen_setcond_tl(TCG_COND_GT, tmp, left, right); \ + tcg_gen_deposit_tl(PeV, PeV, tmp, i, 1); \ + tcg_gen_umin_tl(tmp, left, right); \ + gen_set_byte_i64(i, RddV, tmp); \ + } \ + tcg_temp_free(left); \ + tcg_temp_free(right); \ + tcg_temp_free(tmp); \ + } while (0) + /* Floating point */ #define fGEN_TCG_F2_conv_sf2df(SHORTCODE) \ gen_helper_conv_sf2df(RddV, cpu_env, RsV) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 24d575853c..9dbebc64b5 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -266,6 +266,28 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num, } } +static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign) +{ + TCGv_i64 res64 = tcg_temp_new_i64(); + if (sign) { + tcg_gen_sextract_i64(res64, src, N * 8, 8); + } else { + tcg_gen_extract_i64(res64, src, N * 8, 8); + } + tcg_gen_extrl_i64_i32(result, res64); + tcg_temp_free_i64(res64); + + return result; +} + +static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src) +{ + TCGv_i64 src64 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(src64, src); + tcg_gen_deposit_i64(result, result, src64, N * 8, 8); + tcg_temp_free_i64(src64); +} + static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index) { tcg_gen_qemu_ld32u(dest, vaddr, mem_index); diff --git a/target/hexagon/imported/alu.idef b/target/hexagon/imported/alu.idef index e8cc52c290..f0c9bb47ec 100644 --- a/target/hexagon/imported/alu.idef +++ b/target/hexagon/imported/alu.idef @@ -1259,6 +1259,16 @@ Q6INSN(A5_ACS,"Rxx32,Pe4=vacsh(Rss32,Rtt32)",ATTRIBS(), } }) +Q6INSN(A6_vminub_RdP,"Rdd32,Pe4=vminub(Rtt32,Rss32)",ATTRIBS(), +"Vector minimum of bytes, records minimum and decision vector", +{ + fHIDE(int i;) + for (i = 0; i < 8; i++) { + fSETBIT(i, PeV, (fGETUBYTE(i,RttV) > fGETUBYTE(i,RssV))); + fSETBYTE(i,RddV,fMIN(fGETUBYTE(i,RttV),fGETUBYTE(i,RssV))); + } +}) + /**********************************************/ /* Vector Min/Max */ /**********************************************/ diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index 87e0426c05..46193984c5 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -1018,6 +1018,7 @@ MPY_ENC(M7_dcmpyiwc_acc, "1010","xxxxx","1","0","1","0","10") MPY_ENC(A5_ACS, "1010","xxxxx","0","1","0","1","ee") +MPY_ENC(A6_vminub_RdP, "1010","ddddd","0","1","1","1","ee") /* */ diff --git a/tests/tcg/hexagon/multi_result.c b/tests/tcg/hexagon/multi_result.c index c21148fc20..95d99a0c90 100644 --- a/tests/tcg/hexagon/multi_result.c +++ b/tests/tcg/hexagon/multi_result.c @@ -70,6 +70,21 @@ static long long vacsh(long long Rxx, long long Rss, long long Rtt, return result; } +static long long vminub(long long Rtt, long long Rss, + int *pred_result) +{ + long long result; + int predval; + + asm volatile("%0,p0 = vminub(%2, %3)\n\t" + "%1 = p0\n\t" + : "=r"(result), "=r"(predval) + : "r"(Rtt), "r"(Rss) + : "p0"); + *pred_result = predval; + return result; +} + int err; static void check_ll(long long val, long long expect) @@ -155,11 +170,30 @@ static void test_vacsh() check(ovf_result, 0); } +static void test_vminub() +{ + long long res64; + int pred_result; + + res64 = vminub(0x0807060504030201LL, + 0x0102030405060708LL, + &pred_result); + check_ll(res64, 0x0102030404030201LL); + check_p(pred_result, 0xf0); + + res64 = vminub(0x0802060405030701LL, + 0x0107030504060208LL, + &pred_result); + check_ll(res64, 0x0102030404030201LL); + check_p(pred_result, 0xaa); +} + int main() { test_sfrecipa(); test_sfinvsqrta(); test_vacsh(); + test_vminub(); puts(err ? "FAIL" : "PASS"); return err; From 57d352ac298b27617a53783305af2554025060d9 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:49 -0500 Subject: [PATCH 0162/3028] Hexagon (target/hexagon) add A4_addp_c/A4_subp_c Rdd32 = add(Rss32, Rtt32, Px4):carry Add with carry Rdd32 = sub(Rss32, Rtt32, Px4):carry Sub with carry Test cases in tests/tcg/hexagon/multi_result.c Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-22-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/gen_tcg.h | 37 ++++++++++++ target/hexagon/genptr.c | 11 ++++ target/hexagon/imported/alu.idef | 15 +++++ target/hexagon/imported/encode_pp.def | 2 + tests/tcg/hexagon/multi_result.c | 82 +++++++++++++++++++++++++++ 5 files changed, 147 insertions(+) diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index aea0c55564..6bc578dfda 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -237,6 +237,43 @@ tcg_temp_free_i64(tmp); \ } while (0) +/* + * Add or subtract with carry. + * Predicate register is used as an extra input and output. + * r5:4 = add(r1:0, r3:2, p1):carry + */ +#define fGEN_TCG_A4_addp_c(SHORTCODE) \ + do { \ + TCGv_i64 carry = tcg_temp_new_i64(); \ + TCGv_i64 zero = tcg_const_i64(0); \ + tcg_gen_extu_i32_i64(carry, PxV); \ + tcg_gen_andi_i64(carry, carry, 1); \ + tcg_gen_add2_i64(RddV, carry, RssV, zero, carry, zero); \ + tcg_gen_add2_i64(RddV, carry, RddV, carry, RttV, zero); \ + tcg_gen_extrl_i64_i32(PxV, carry); \ + gen_8bitsof(PxV, PxV); \ + tcg_temp_free_i64(carry); \ + tcg_temp_free_i64(zero); \ + } while (0) + +/* r5:4 = sub(r1:0, r3:2, p1):carry */ +#define fGEN_TCG_A4_subp_c(SHORTCODE) \ + do { \ + TCGv_i64 carry = tcg_temp_new_i64(); \ + TCGv_i64 zero = tcg_const_i64(0); \ + TCGv_i64 not_RttV = tcg_temp_new_i64(); \ + tcg_gen_extu_i32_i64(carry, PxV); \ + tcg_gen_andi_i64(carry, carry, 1); \ + tcg_gen_not_i64(not_RttV, RttV); \ + tcg_gen_add2_i64(RddV, carry, RssV, zero, carry, zero); \ + tcg_gen_add2_i64(RddV, carry, RddV, carry, not_RttV, zero); \ + tcg_gen_extrl_i64_i32(PxV, carry); \ + gen_8bitsof(PxV, PxV); \ + tcg_temp_free_i64(carry); \ + tcg_temp_free_i64(zero); \ + tcg_temp_free_i64(not_RttV); \ + } while (0) + /* * Compare each of the 8 unsigned bytes * The minimum is placed in each byte of the destination. diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 9dbebc64b5..333f7d74bf 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -361,5 +361,16 @@ static inline void gen_store_conditional8(CPUHexagonState *env, tcg_gen_movi_tl(hex_llsc_addr, ~0); } +static TCGv gen_8bitsof(TCGv result, TCGv value) +{ + TCGv zero = tcg_const_tl(0); + TCGv ones = tcg_const_tl(0xff); + tcg_gen_movcond_tl(TCG_COND_NE, result, value, zero, ones, zero); + tcg_temp_free(zero); + tcg_temp_free(ones); + + return result; +} + #include "tcg_funcs_generated.c.inc" #include "tcg_func_table_generated.c.inc" diff --git a/target/hexagon/imported/alu.idef b/target/hexagon/imported/alu.idef index f0c9bb47ec..58477ae40a 100644 --- a/target/hexagon/imported/alu.idef +++ b/target/hexagon/imported/alu.idef @@ -153,6 +153,21 @@ Q6INSN(A2_subp,"Rdd32=sub(Rtt32,Rss32)",ATTRIBS(), "Sub", { RddV=RttV-RssV;}) +/* 64-bit with carry */ + +Q6INSN(A4_addp_c,"Rdd32=add(Rss32,Rtt32,Px4):carry",ATTRIBS(),"Add with Carry", +{ + RddV = RssV + RttV + fLSBOLD(PxV); + PxV = f8BITSOF(fCARRY_FROM_ADD(RssV,RttV,fLSBOLD(PxV))); +}) + +Q6INSN(A4_subp_c,"Rdd32=sub(Rss32,Rtt32,Px4):carry",ATTRIBS(),"Sub with Carry", +{ + RddV = RssV + ~RttV + fLSBOLD(PxV); + PxV = f8BITSOF(fCARRY_FROM_ADD(RssV,~RttV,fLSBOLD(PxV))); +}) + + /* NEG and ABS */ Q6INSN(A2_negsat,"Rd32=neg(Rs32):sat",ATTRIBS(), diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index 46193984c5..514c2404ce 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -1749,6 +1749,8 @@ SH_RRR_ENC(S4_extractp_rp, "0001","11-","-","10-","ddddd") DEF_FIELDROW_DESC32(ICLASS_S3op" 0010 -------- PP------ --------","[#2] Rdd=(Rss,Rtt,Pu)") SH_RRR_ENC(S2_valignrb, "0010","0--","-","-uu","ddddd") SH_RRR_ENC(S2_vsplicerb, "0010","100","-","-uu","ddddd") +SH_RRR_ENC(A4_addp_c, "0010","110","-","-xx","ddddd") +SH_RRR_ENC(A4_subp_c, "0010","111","-","-xx","ddddd") DEF_FIELDROW_DESC32(ICLASS_S3op" 0011 -------- PP------ --------","[#3] Rdd=(Rss,Rt)") diff --git a/tests/tcg/hexagon/multi_result.c b/tests/tcg/hexagon/multi_result.c index 95d99a0c90..52997b3128 100644 --- a/tests/tcg/hexagon/multi_result.c +++ b/tests/tcg/hexagon/multi_result.c @@ -85,6 +85,38 @@ static long long vminub(long long Rtt, long long Rss, return result; } +static long long add_carry(long long Rss, long long Rtt, + int pred_in, int *pred_result) +{ + long long result; + int predval = pred_in; + + asm volatile("p0 = %1\n\t" + "%0 = add(%2, %3, p0):carry\n\t" + "%1 = p0\n\t" + : "=r"(result), "+r"(predval) + : "r"(Rss), "r"(Rtt) + : "p0"); + *pred_result = predval; + return result; +} + +static long long sub_carry(long long Rss, long long Rtt, + int pred_in, int *pred_result) +{ + long long result; + int predval = pred_in; + + asm volatile("p0 = !cmp.eq(%1, #0)\n\t" + "%0 = sub(%2, %3, p0):carry\n\t" + "%1 = p0\n\t" + : "=r"(result), "+r"(predval) + : "r"(Rss), "r"(Rtt) + : "p0"); + *pred_result = predval; + return result; +} + int err; static void check_ll(long long val, long long expect) @@ -188,12 +220,62 @@ static void test_vminub() check_p(pred_result, 0xaa); } +static void test_add_carry() +{ + long long res64; + int pred_result; + + res64 = add_carry(0x0000000000000000LL, + 0xffffffffffffffffLL, + 1, &pred_result); + check_ll(res64, 0x0000000000000000LL); + check_p(pred_result, 0xff); + + res64 = add_carry(0x0000000100000000LL, + 0xffffffffffffffffLL, + 0, &pred_result); + check_ll(res64, 0x00000000ffffffffLL); + check_p(pred_result, 0xff); + + res64 = add_carry(0x0000000100000000LL, + 0xffffffffffffffffLL, + 0, &pred_result); + check_ll(res64, 0x00000000ffffffffLL); + check_p(pred_result, 0xff); +} + +static void test_sub_carry() +{ + long long res64; + int pred_result; + + res64 = sub_carry(0x0000000000000000LL, + 0x0000000000000000LL, + 1, &pred_result); + check_ll(res64, 0x0000000000000000LL); + check_p(pred_result, 0xff); + + res64 = sub_carry(0x0000000100000000LL, + 0x0000000000000000LL, + 0, &pred_result); + check_ll(res64, 0x00000000ffffffffLL); + check_p(pred_result, 0xff); + + res64 = sub_carry(0x0000000100000000LL, + 0x0000000000000000LL, + 0, &pred_result); + check_ll(res64, 0x00000000ffffffffLL); + check_p(pred_result, 0xff); +} + int main() { test_sfrecipa(); test_sfinvsqrta(); test_vacsh(); test_vminub(); + test_add_carry(); + test_sub_carry(); puts(err ? "FAIL" : "PASS"); return err; From db647703ba9d82519363c107715f562187fbcc16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 10:10:08 +0200 Subject: [PATCH 0163/3028] exec: Remove accel/tcg/ from include paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When TCG is enabled, the accel/tcg/ include path is added to the project global include search list. This accel/tcg/ directory contains a header named "internal.h" which, while intented to be internal to accel/tcg/, is accessible by all files compiled when TCG is enabled. This might lead to problem with other directories using the same "internal.h" header name: $ git ls-files | fgrep /internal.h accel/tcg/internal.h include/hw/ide/internal.h target/hexagon/internal.h target/mips/internal.h target/ppc/internal.h target/s390x/internal.h As we don't need to expose accel/tcg/ internals to the rest of the code base, simplify by removing it from the include search list, and include the accel/tcg/ public headers relative to the project root search path (which is already in the generic include search path). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Claudio Fontana Message-Id: <20210413081008.3409459-1-f4bug@amsat.org> Signed-off-by: Richard Henderson --- include/exec/helper-gen.h | 4 ++-- include/exec/helper-proto.h | 4 ++-- include/exec/helper-tcg.h | 4 ++-- meson.build | 1 - 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/exec/helper-gen.h b/include/exec/helper-gen.h index 29c02f85dc..1c2e7a8ed3 100644 --- a/include/exec/helper-gen.h +++ b/include/exec/helper-gen.h @@ -81,8 +81,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \ #include "helper.h" #include "trace/generated-helpers.h" #include "trace/generated-helpers-wrappers.h" -#include "tcg-runtime.h" -#include "plugin-helpers.h" +#include "accel/tcg/tcg-runtime.h" +#include "accel/tcg/plugin-helpers.h" #undef DEF_HELPER_FLAGS_0 #undef DEF_HELPER_FLAGS_1 diff --git a/include/exec/helper-proto.h b/include/exec/helper-proto.h index 659f9298e8..ba100793a7 100644 --- a/include/exec/helper-proto.h +++ b/include/exec/helper-proto.h @@ -39,8 +39,8 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ #include "helper.h" #include "trace/generated-helpers.h" -#include "tcg-runtime.h" -#include "plugin-helpers.h" +#include "accel/tcg/tcg-runtime.h" +#include "accel/tcg/plugin-helpers.h" #undef IN_HELPER_PROTO diff --git a/include/exec/helper-tcg.h b/include/exec/helper-tcg.h index 27870509a2..6888514635 100644 --- a/include/exec/helper-tcg.h +++ b/include/exec/helper-tcg.h @@ -60,8 +60,8 @@ #include "helper.h" #include "trace/generated-helpers.h" -#include "tcg-runtime.h" -#include "plugin-helpers.h" +#include "accel/tcg/tcg-runtime.h" +#include "accel/tcg/plugin-helpers.h" #undef str #undef DEF_HELPER_FLAGS_0 diff --git a/meson.build b/meson.build index c6f4b0cf5e..d8bb1ec5aa 100644 --- a/meson.build +++ b/meson.build @@ -258,7 +258,6 @@ if not get_option('tcg').disabled() tcg_arch = 'riscv' endif add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch, - '-iquote', meson.current_source_dir() / 'accel/tcg', language: ['c', 'cpp', 'objc']) accelerators += 'CONFIG_TCG' From c7cefe6c667f706f76f4676ae2894286c5b8b9b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 16:27:56 -0700 Subject: [PATCH 0164/3028] decodetree: Introduce whex and whexC helpers Form a hex constant of the appropriate insnwidth. Begin using f-strings on changed lines. Reviewed-by: Luis Pires Signed-off-by: Richard Henderson --- scripts/decodetree.py | 66 +++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/scripts/decodetree.py b/scripts/decodetree.py index 4637b633e7..0861e5d503 100644 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -102,6 +102,21 @@ def str_fields(fields): return r[1:] +def whex(val): + """Return a hex string for val padded for insnwidth""" + global insnwidth + return f'0x{val:0{insnwidth // 4}x}' + + +def whexC(val): + """Return a hex string for val padded for insnwidth, + and with the proper suffix for a C constant.""" + suffix = '' + if val >= 0x80000000: + suffix = 'u' + return whex(val) + suffix + + def str_match_bits(bits, mask): """Return a string pretty-printing BITS/MASK""" global insnwidth @@ -477,11 +492,8 @@ class IncMultiPattern(MultiPattern): if outermask != p.fixedmask: innermask = p.fixedmask & ~outermask innerbits = p.fixedbits & ~outermask - output(ind, 'if ((insn & ', - '0x{0:08x}) == 0x{1:08x}'.format(innermask, innerbits), - ') {\n') - output(ind, ' /* ', - str_match_bits(p.fixedbits, p.fixedmask), ' */\n') + output(ind, f'if ((insn & {whexC(innermask)}) == {whexC(innerbits)}) {{\n') + output(ind, f' /* {str_match_bits(p.fixedbits, p.fixedmask)} */\n') p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask) output(ind, '}\n') else: @@ -500,12 +512,12 @@ class Tree: def str1(self, i): ind = str_indent(i) - r = '{0}{1:08x}'.format(ind, self.fixedmask) + r = ind + whex(self.fixedmask) if self.format: r += ' ' + self.format.name r += ' [\n' for (b, s) in self.subs: - r += '{0} {1:08x}:\n'.format(ind, b) + r += ind + f' {whex(b)}:\n' r += s.str1(i + 4) + '\n' r += ind + ']' return r @@ -529,16 +541,16 @@ class Tree: if sh > 0: # Propagate SH down into the local functions. def str_switch(b, sh=sh): - return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh) + return f'(insn >> {sh}) & {b >> sh:#x}' def str_case(b, sh=sh): - return '0x{0:x}'.format(b >> sh) + return hex(b >> sh) else: def str_switch(b): - return 'insn & 0x{0:08x}'.format(b) + return f'insn & {whexC(b)}' def str_case(b): - return '0x{0:08x}'.format(b) + return whexC(b) output(ind, 'switch (', str_switch(self.thismask), ') {\n') for b, s in sorted(self.subs): @@ -962,19 +974,19 @@ def parse_generic(lineno, parent_pat, name, toks): # Validate the masks that we have assembled. if fieldmask & fixedmask: - error(lineno, 'fieldmask overlaps fixedmask (0x{0:08x} & 0x{1:08x})' - .format(fieldmask, fixedmask)) + error(lineno, 'fieldmask overlaps fixedmask ', + f'({whex(fieldmask)} & {whex(fixedmask)})') if fieldmask & undefmask: - error(lineno, 'fieldmask overlaps undefmask (0x{0:08x} & 0x{1:08x})' - .format(fieldmask, undefmask)) + error(lineno, 'fieldmask overlaps undefmask ', + f'({whex(fieldmask)} & {whex(undefmask)})') if fixedmask & undefmask: - error(lineno, 'fixedmask overlaps undefmask (0x{0:08x} & 0x{1:08x})' - .format(fixedmask, undefmask)) + error(lineno, 'fixedmask overlaps undefmask ', + f'({whex(fixedmask)} & {whex(undefmask)})') if not is_format: allbits = fieldmask | fixedmask | undefmask if allbits != insnmask: - error(lineno, 'bits left unspecified (0x{0:08x})' - .format(allbits ^ insnmask)) + error(lineno, 'bits left unspecified ', + f'({whex(allbits ^ insnmask)})') # end parse_general @@ -1104,10 +1116,9 @@ class SizeTree: def str1(self, i): ind = str_indent(i) - r = '{0}{1:08x}'.format(ind, self.mask) - r += ' [\n' + r = ind + whex(self.mask) + ' [\n' for (b, s) in self.subs: - r += '{0} {1:08x}:\n'.format(ind, b) + r += ind + f' {whex(b)}:\n' r += s.str1(i + 4) + '\n' r += ind + ']' return r @@ -1131,16 +1142,16 @@ class SizeTree: if sh > 0: # Propagate SH down into the local functions. def str_switch(b, sh=sh): - return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh) + return f'(insn >> {sh}) & {b >> sh:#x}' def str_case(b, sh=sh): - return '0x{0:x}'.format(b >> sh) + return hex(b >> sh) else: def str_switch(b): - return 'insn & 0x{0:08x}'.format(b) + return f'insn & {whexC(b)}' def str_case(b): - return '0x{0:08x}'.format(b) + return whexC(b) output(ind, 'switch (', str_switch(self.mask), ') {\n') for b, s in sorted(self.subs): @@ -1162,8 +1173,7 @@ class SizeLeaf: self.width = w def str1(self, i): - ind = str_indent(i) - return '{0}{1:08x}'.format(ind, self.mask) + return str_indent(i) + whex(self.mask) def __str__(self): return self.str1(0) From 9f6e2b4d34363c066a0cee1a1df3ec7a0c9f3255 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 16:37:02 -0700 Subject: [PATCH 0165/3028] decodetree: More use of f-strings Reviewed-by: Luis Pires Signed-off-by: Richard Henderson --- scripts/decodetree.py | 50 ++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/scripts/decodetree.py b/scripts/decodetree.py index 0861e5d503..d5da101167 100644 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -59,9 +59,9 @@ def error_with_file(file, lineno, *args): prefix = '' if file: - prefix += '{0}:'.format(file) + prefix += f'{file}:' if lineno: - prefix += '{0}:'.format(lineno) + prefix += f'{lineno}:' if prefix: prefix += ' ' print(prefix, end='error: ', file=sys.stderr) @@ -203,7 +203,7 @@ class Field: extr = 'sextract32' else: extr = 'extract32' - return '{0}(insn, {1}, {2})'.format(extr, self.pos, self.len) + return f'{extr}(insn, {self.pos}, {self.len})' def __eq__(self, other): return self.sign == other.sign and self.mask == other.mask @@ -227,11 +227,11 @@ class MultiField: ret = '0' pos = 0 for f in reversed(self.subs): + ext = f.str_extract() if pos == 0: - ret = f.str_extract() + ret = ext else: - ret = 'deposit32({0}, {1}, {2}, {3})' \ - .format(ret, pos, 32 - pos, f.str_extract()) + ret = f'deposit32({ret}, {pos}, {32 - pos}, {ext})' pos += f.len return ret @@ -675,11 +675,11 @@ def parse_field(lineno, name, toks): subtoks = t.split(':') sign = False else: - error(lineno, 'invalid field token "{0}"'.format(t)) + error(lineno, f'invalid field token "{t}"') po = int(subtoks[0]) le = int(subtoks[1]) if po + le > insnwidth: - error(lineno, 'field {0} too large'.format(t)) + error(lineno, f'field {t} too large') f = Field(sign, po, le) subs.append(f) width += le @@ -724,9 +724,9 @@ def parse_arguments(lineno, name, toks): anyextern = True continue if not re.fullmatch(re_C_ident, t): - error(lineno, 'invalid argument set token "{0}"'.format(t)) + error(lineno, f'invalid argument set token "{t}"') if t in flds: - error(lineno, 'duplicate argument "{0}"'.format(t)) + error(lineno, f'duplicate argument "{t}"') flds.append(t) if name in arguments: @@ -895,14 +895,14 @@ def parse_generic(lineno, parent_pat, name, toks): flen = flen[1:] shift = int(flen, 10) if shift + width > insnwidth: - error(lineno, 'field {0} exceeds insnwidth'.format(fname)) + error(lineno, f'field {fname} exceeds insnwidth') f = Field(sign, insnwidth - width - shift, shift) flds = add_field(lineno, flds, fname, f) fixedbits <<= shift fixedmask <<= shift undefmask <<= shift else: - error(lineno, 'invalid token "{0}"'.format(t)) + error(lineno, f'invalid token "{t}"') width += shift if variablewidth and width < insnwidth and width % 8 == 0: @@ -914,7 +914,7 @@ def parse_generic(lineno, parent_pat, name, toks): # We should have filled in all of the bits of the instruction. elif not (is_format and width == 0) and width != insnwidth: - error(lineno, 'definition has {0} bits'.format(width)) + error(lineno, f'definition has {width} bits') # Do not check for fields overlapping fields; one valid usage # is to be able to duplicate fields via import. @@ -932,8 +932,7 @@ def parse_generic(lineno, parent_pat, name, toks): if arg: for f in flds.keys(): if f not in arg.fields: - error(lineno, 'field {0} not in argument set {1}' - .format(f, arg.name)) + error(lineno, f'field {f} not in argument set {arg.name}') else: arg = infer_argument_set(flds) if name in formats: @@ -960,13 +959,12 @@ def parse_generic(lineno, parent_pat, name, toks): arg = fmt.base for f in flds.keys(): if f not in arg.fields: - error(lineno, 'field {0} not in argument set {1}' - .format(f, arg.name)) + error(lineno, f'field {f} not in argument set {arg.name}') if f in fmt.fields.keys(): - error(lineno, 'field {0} set by format and pattern'.format(f)) + error(lineno, f'field {f} set by format and pattern') for f in arg.fields: if f not in flds.keys() and f not in fmt.fields.keys(): - error(lineno, 'field {0} not initialized'.format(f)) + error(lineno, f'field {f} not initialized') pat = Pattern(name, lineno, fmt, fixedbits, fixedmask, undefmask, fieldmask, flds, width) parent_pat.pats.append(pat) @@ -1097,7 +1095,7 @@ def parse_file(f, parent_pat): elif re.fullmatch(re_pat_ident, name): parse_generic(start_lineno, parent_pat, name, toks) else: - error(lineno, 'invalid token "{0}"'.format(name)) + error(lineno, f'invalid token "{name}"') toks = [] if nesting != 0: @@ -1131,9 +1129,8 @@ class SizeTree: # If we need to load more bytes to test, do so now. if extracted < self.width: - output(ind, 'insn = ', decode_function, - '_load_bytes(ctx, insn, {0}, {1});\n' - .format(extracted // 8, self.width // 8)); + output(ind, f'insn = {decode_function}_load_bytes', + f'(ctx, insn, {extracted // 8}, {self.width // 8});\n') extracted = self.width # Attempt to aid the compiler in producing compact switch statements. @@ -1184,9 +1181,8 @@ class SizeLeaf: # If we need to load more bytes, do so now. if extracted < self.width: - output(ind, 'insn = ', decode_function, - '_load_bytes(ctx, insn, {0}, {1});\n' - .format(extracted // 8, self.width // 8)); + output(ind, f'insn = {decode_function}_load_bytes', + f'(ctx, insn, {extracted // 8}, {self.width // 8});\n') extracted = self.width output(ind, 'return insn;\n') # end SizeLeaf @@ -1220,7 +1216,7 @@ def build_size_tree(pats, width, outerbits, outermask): for p in pats: pnames.append(p.name + ':' + p.file + ':' + str(p.lineno)) error_with_file(pats[0].file, pats[0].lineno, - 'overlapping patterns size {0}:'.format(width), pnames) + f'overlapping patterns size {width}:', pnames) bins = {} for i in pats: From 60c425f328957caaa46da895086cc0ea46865d3d Mon Sep 17 00:00:00 2001 From: Luis Fernando Fujita Pires Date: Wed, 7 Apr 2021 22:18:49 +0000 Subject: [PATCH 0166/3028] decodetree: Add support for 64-bit instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow '64' to be specified for the instruction width command line params and use the appropriate extract and deposit functions in that case. This will be used to implement the new 64-bit Power ISA 3.1 instructions. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Luis Pires Message-Id: [rth: Drop the change to the field type; use bitop_width instead of separate variables for extract/deposit; use "ull" for 64-bit constants.] Reviewed-by: Luis Pires Signed-off-by: Richard Henderson --- scripts/decodetree.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/scripts/decodetree.py b/scripts/decodetree.py index d5da101167..f85da45ee3 100644 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -27,6 +27,7 @@ import sys import getopt insnwidth = 32 +bitop_width = 32 insnmask = 0xffffffff variablewidth = False fields = {} @@ -112,7 +113,9 @@ def whexC(val): """Return a hex string for val padded for insnwidth, and with the proper suffix for a C constant.""" suffix = '' - if val >= 0x80000000: + if val >= 0x100000000: + suffix = 'ull' + elif val >= 0x80000000: suffix = 'u' return whex(val) + suffix @@ -199,11 +202,9 @@ class Field: return str(self.pos) + ':' + s + str(self.len) def str_extract(self): - if self.sign: - extr = 'sextract32' - else: - extr = 'extract32' - return f'{extr}(insn, {self.pos}, {self.len})' + global bitop_width + s = 's' if self.sign else '' + return f'{s}extract{bitop_width}(insn, {self.pos}, {self.len})' def __eq__(self, other): return self.sign == other.sign and self.mask == other.mask @@ -224,6 +225,7 @@ class MultiField: return str(self.subs) def str_extract(self): + global bitop_width ret = '0' pos = 0 for f in reversed(self.subs): @@ -231,7 +233,7 @@ class MultiField: if pos == 0: ret = ext else: - ret = f'deposit32({ret}, {pos}, {32 - pos}, {ext})' + ret = f'deposit{bitop_width}({ret}, {pos}, {bitop_width - pos}, {ext})' pos += f.len return ret @@ -1270,6 +1272,7 @@ def main(): global insntype global insnmask global decode_function + global bitop_width global variablewidth global anyextern @@ -1299,6 +1302,10 @@ def main(): if insnwidth == 16: insntype = 'uint16_t' insnmask = 0xffff + elif insnwidth == 64: + insntype = 'uint64_t' + insnmask = 0xffffffffffffffff + bitop_width = 64 elif insnwidth != 32: error(0, 'cannot handle insns of width', insnwidth) else: From af93ccacc772019298be4c3e47251cdaa60d0c21 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 29 Apr 2021 10:03:59 -0700 Subject: [PATCH 0167/3028] decodetree: Extend argument set syntax to allow types Rather than force all structure members to be 'int', allow the type of the member to be specified. Reviewed-by: Luis Pires Signed-off-by: Richard Henderson --- docs/devel/decodetree.rst | 11 ++++--- scripts/decodetree.py | 45 +++++++++++++++++---------- tests/decode/succ_argset_type1.decode | 1 + 3 files changed, 36 insertions(+), 21 deletions(-) create mode 100644 tests/decode/succ_argset_type1.decode diff --git a/docs/devel/decodetree.rst b/docs/devel/decodetree.rst index 74f66bf46e..49ea50c2a7 100644 --- a/docs/devel/decodetree.rst +++ b/docs/devel/decodetree.rst @@ -40,9 +40,6 @@ and returns an integral value extracted from there. A field with no ``unnamed_fields`` and no ``!function`` is in error. -FIXME: the fields of the structure into which this result will be stored -is restricted to ``int``. Which means that we cannot expand 64-bit items. - Field examples: +---------------------------+---------------------------------------------+ @@ -66,9 +63,14 @@ Argument Sets Syntax:: args_def := '&' identifier ( args_elt )+ ( !extern )? - args_elt := identifier + args_elt := identifier (':' identifier)? Each *args_elt* defines an argument within the argument set. +If the form of the *args_elt* contains a colon, the first +identifier is the argument name and the second identifier is +the argument type. If the colon is missing, the argument +type will be ``int``. + Each argument set will be rendered as a C structure "arg_$name" with each of the fields being one of the member arguments. @@ -86,6 +88,7 @@ Argument set examples:: ®3 ra rb rc &loadstore reg base offset + &longldst reg base offset:int64_t Formats diff --git a/scripts/decodetree.py b/scripts/decodetree.py index f85da45ee3..a03dc6b5e3 100644 --- a/scripts/decodetree.py +++ b/scripts/decodetree.py @@ -165,11 +165,15 @@ def is_contiguous(bits): return -1 -def eq_fields_for_args(flds_a, flds_b): - if len(flds_a) != len(flds_b): +def eq_fields_for_args(flds_a, arg): + if len(flds_a) != len(arg.fields): return False + # Only allow inference on default types + for t in arg.types: + if t != 'int': + return False for k, a in flds_a.items(): - if k not in flds_b: + if k not in arg.fields: return False return True @@ -313,10 +317,11 @@ class ParameterField: class Arguments: """Class representing the extracted fields of a format""" - def __init__(self, nm, flds, extern): + def __init__(self, nm, flds, types, extern): self.name = nm self.extern = extern - self.fields = sorted(flds) + self.fields = flds + self.types = types def __str__(self): return self.name + ' ' + str(self.fields) @@ -327,8 +332,8 @@ class Arguments: def output_def(self): if not self.extern: output('typedef struct {\n') - for n in self.fields: - output(' int ', n, ';\n') + for (n, t) in zip(self.fields, self.types): + output(f' {t} {n};\n') output('} ', self.struct_name(), ';\n\n') # end Arguments @@ -719,21 +724,27 @@ def parse_arguments(lineno, name, toks): global anyextern flds = [] + types = [] extern = False - for t in toks: - if re.fullmatch('!extern', t): + for n in toks: + if re.fullmatch('!extern', n): extern = True anyextern = True continue - if not re.fullmatch(re_C_ident, t): - error(lineno, f'invalid argument set token "{t}"') - if t in flds: - error(lineno, f'duplicate argument "{t}"') - flds.append(t) + if re.fullmatch(re_C_ident + ':' + re_C_ident, n): + (n, t) = n.split(':') + elif re.fullmatch(re_C_ident, n): + t = 'int' + else: + error(lineno, f'invalid argument set token "{n}"') + if n in flds: + error(lineno, f'duplicate argument "{n}"') + flds.append(n) + types.append(t) if name in arguments: error(lineno, 'duplicate argument set', name) - arguments[name] = Arguments(name, flds, extern) + arguments[name] = Arguments(name, flds, types, extern) # end parse_arguments @@ -760,11 +771,11 @@ def infer_argument_set(flds): global decode_function for arg in arguments.values(): - if eq_fields_for_args(flds, arg.fields): + if eq_fields_for_args(flds, arg): return arg name = decode_function + str(len(arguments)) - arg = Arguments(name, flds.keys(), False) + arg = Arguments(name, flds.keys(), ['int'] * len(flds), False) arguments[name] = arg return arg diff --git a/tests/decode/succ_argset_type1.decode b/tests/decode/succ_argset_type1.decode new file mode 100644 index 0000000000..ed946b420d --- /dev/null +++ b/tests/decode/succ_argset_type1.decode @@ -0,0 +1 @@ +&asdf b:bool c:uint64_t a From 46ef47e2a77d1a34996964760b4a0d2b19476f25 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:50 -0500 Subject: [PATCH 0168/3028] Hexagon (target/hexagon) circular addressing The following instructions are added L2_loadrub_pci Rd32 = memub(Rx32++#s4:0:circ(Mu2)) L2_loadrb_pci Rd32 = memb(Rx32++#s4:0:circ(Mu2)) L2_loadruh_pci Rd32 = memuh(Rx32++#s4:1:circ(Mu2)) L2_loadrh_pci Rd32 = memh(Rx32++#s4:1:circ(Mu2)) L2_loadri_pci Rd32 = memw(Rx32++#s4:2:circ(Mu2)) L2_loadrd_pci Rdd32 = memd(Rx32++#s4:3:circ(Mu2)) S2_storerb_pci memb(Rx32++#s4:0:circ(Mu2)) = Rt32 S2_storerh_pci memh(Rx32++#s4:1:circ(Mu2)) = Rt32 S2_storerf_pci memh(Rx32++#s4:1:circ(Mu2)) = Rt.H32 S2_storeri_pci memw(Rx32++#s4:2:circ(Mu2)) = Rt32 S2_storerd_pci memd(Rx32++#s4:3:circ(Mu2)) = Rtt32 S2_storerbnew_pci memb(Rx32++#s4:0:circ(Mu2)) = Nt8.new S2_storerhnew_pci memw(Rx32++#s4:1:circ(Mu2)) = Nt8.new S2_storerinew_pci memw(Rx32++#s4:2:circ(Mu2)) = Nt8.new L2_loadrub_pcr Rd32 = memub(Rx32++I:circ(Mu2)) L2_loadrb_pcr Rd32 = memb(Rx32++I:circ(Mu2)) L2_loadruh_pcr Rd32 = memuh(Rx32++I:circ(Mu2)) L2_loadrh_pcr Rd32 = memh(Rx32++I:circ(Mu2)) L2_loadri_pcr Rd32 = memw(Rx32++I:circ(Mu2)) L2_loadrd_pcr Rdd32 = memd(Rx32++I:circ(Mu2)) S2_storerb_pcr memb(Rx32++I:circ(Mu2)) = Rt32 S2_storerh_pcr memh(Rx32++I:circ(Mu2)) = Rt32 S2_storerf_pcr memh(Rx32++I:circ(Mu2)) = Rt32.H32 S2_storeri_pcr memw(Rx32++I:circ(Mu2)) = Rt32 S2_storerd_pcr memd(Rx32++I:circ(Mu2)) = Rtt32 S2_storerbnew_pcr memb(Rx32++I:circ(Mu2)) = Nt8.new S2_storerhnew_pcr memh(Rx32++I:circ(Mu2)) = Nt8.new S2_storerinew_pcr memw(Rx32++I:circ(Mu2)) = Nt8.new Test cases in tests/tcg/hexagon/circ.c Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-23-git-send-email-tsimpson@quicinc.com> [rth: Squash <1619667142-29636-1-git-send-email-tsimpson@quicinc.com> removing gen_read_reg and gen_set_byte to avoid clang Werror.] Signed-off-by: Richard Henderson --- target/hexagon/gen_tcg.h | 112 +++++- target/hexagon/genptr.c | 89 +++++ target/hexagon/imported/encode_pp.def | 10 + target/hexagon/imported/ldst.idef | 4 + target/hexagon/imported/macros.def | 26 ++ target/hexagon/macros.h | 92 +++++ target/hexagon/op_helper.c | 36 +- tests/tcg/hexagon/Makefile.target | 2 + tests/tcg/hexagon/circ.c | 486 ++++++++++++++++++++++++++ 9 files changed, 834 insertions(+), 23 deletions(-) create mode 100644 tests/tcg/hexagon/circ.c diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index 6bc578dfda..25c228c112 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -38,6 +38,8 @@ * _ap absolute set r0 = memw(r1=##variable) * _pr post increment register r0 = memw(r1++m1) * _pi post increment immediate r0 = memb(r1++#1) + * _pci post increment circular immediate r0 = memw(r1++#4:circ(m0)) + * _pcr post increment circular register r0 = memw(r1++I:circ(m0)) */ /* Macros for complex addressing modes */ @@ -56,7 +58,22 @@ fEA_REG(RxV); \ fPM_I(RxV, siV); \ } while (0) - +#define GET_EA_pci \ + do { \ + TCGv tcgv_siV = tcg_const_tl(siV); \ + tcg_gen_mov_tl(EA, RxV); \ + gen_helper_fcircadd(RxV, RxV, tcgv_siV, MuV, \ + hex_gpr[HEX_REG_CS0 + MuN]); \ + tcg_temp_free(tcgv_siV); \ + } while (0) +#define GET_EA_pcr(SHIFT) \ + do { \ + TCGv ireg = tcg_temp_new(); \ + tcg_gen_mov_tl(EA, RxV); \ + gen_read_ireg(ireg, MuV, (SHIFT)); \ + gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \ + tcg_temp_free(ireg); \ + } while (0) /* Instructions with multiple definitions */ #define fGEN_TCG_LOAD_AP(RES, SIZE, SIGN) \ @@ -80,6 +97,36 @@ #define fGEN_TCG_L4_loadrd_ap(SHORTCODE) \ fGEN_TCG_LOAD_AP(RddV, 8, u) +#define fGEN_TCG_L2_loadrub_pci(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadrb_pci(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadruh_pci(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadrh_pci(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadri_pci(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadrd_pci(SHORTCODE) SHORTCODE + +#define fGEN_TCG_LOAD_pcr(SHIFT, LOAD) \ + do { \ + TCGv ireg = tcg_temp_new(); \ + tcg_gen_mov_tl(EA, RxV); \ + gen_read_ireg(ireg, MuV, SHIFT); \ + gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \ + LOAD; \ + tcg_temp_free(ireg); \ + } while (0) + +#define fGEN_TCG_L2_loadrub_pcr(SHORTCODE) \ + fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, u, EA, RdV)) +#define fGEN_TCG_L2_loadrb_pcr(SHORTCODE) \ + fGEN_TCG_LOAD_pcr(0, fLOAD(1, 1, s, EA, RdV)) +#define fGEN_TCG_L2_loadruh_pcr(SHORTCODE) \ + fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, u, EA, RdV)) +#define fGEN_TCG_L2_loadrh_pcr(SHORTCODE) \ + fGEN_TCG_LOAD_pcr(1, fLOAD(1, 2, s, EA, RdV)) +#define fGEN_TCG_L2_loadri_pcr(SHORTCODE) \ + fGEN_TCG_LOAD_pcr(2, fLOAD(1, 4, u, EA, RdV)) +#define fGEN_TCG_L2_loadrd_pcr(SHORTCODE) \ + fGEN_TCG_LOAD_pcr(3, fLOAD(1, 8, u, EA, RddV)) + #define fGEN_TCG_L2_loadrub_pr(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrub_pi(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrb_pr(SHORTCODE) SHORTCODE @@ -195,6 +242,69 @@ #define fGEN_TCG_S4_stored_locked(SHORTCODE) \ do { SHORTCODE; READ_PREG(PdV, PdN); } while (0) +#define fGEN_TCG_STORE(SHORTCODE) \ + do { \ + TCGv HALF = tcg_temp_new(); \ + TCGv BYTE = tcg_temp_new(); \ + SHORTCODE; \ + tcg_temp_free(HALF); \ + tcg_temp_free(BYTE); \ + } while (0) + +#define fGEN_TCG_STORE_pcr(SHIFT, STORE) \ + do { \ + TCGv ireg = tcg_temp_new(); \ + TCGv HALF = tcg_temp_new(); \ + TCGv BYTE = tcg_temp_new(); \ + tcg_gen_mov_tl(EA, RxV); \ + gen_read_ireg(ireg, MuV, SHIFT); \ + gen_helper_fcircadd(RxV, RxV, ireg, MuV, hex_gpr[HEX_REG_CS0 + MuN]); \ + STORE; \ + tcg_temp_free(ireg); \ + tcg_temp_free(HALF); \ + tcg_temp_free(BYTE); \ + } while (0) + +#define fGEN_TCG_S2_storerb_pci(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) +#define fGEN_TCG_S2_storerb_pcr(SHORTCODE) \ + fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, RtV))) + +#define fGEN_TCG_S2_storerh_pci(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) +#define fGEN_TCG_S2_storerh_pcr(SHORTCODE) \ + fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, RtV))) + +#define fGEN_TCG_S2_storerf_pci(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) +#define fGEN_TCG_S2_storerf_pcr(SHORTCODE) \ + fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(1, RtV))) + +#define fGEN_TCG_S2_storeri_pci(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) +#define fGEN_TCG_S2_storeri_pcr(SHORTCODE) \ + fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, RtV)) + +#define fGEN_TCG_S2_storerd_pci(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) +#define fGEN_TCG_S2_storerd_pcr(SHORTCODE) \ + fGEN_TCG_STORE_pcr(3, fSTORE(1, 8, EA, RttV)) + +#define fGEN_TCG_S2_storerbnew_pci(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) +#define fGEN_TCG_S2_storerbnew_pcr(SHORTCODE) \ + fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, NtN))) + +#define fGEN_TCG_S2_storerhnew_pci(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) +#define fGEN_TCG_S2_storerhnew_pcr(SHORTCODE) \ + fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, NtN))) + +#define fGEN_TCG_S2_storerinew_pci(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) +#define fGEN_TCG_S2_storerinew_pcr(SHORTCODE) \ + fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, NtN)) + /* * Mathematical operations with more than one definition require * special handling diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 333f7d74bf..c6928d6184 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -266,6 +266,16 @@ static inline void gen_write_ctrl_reg_pair(DisasContext *ctx, int reg_num, } } +static TCGv gen_get_byte(TCGv result, int N, TCGv src, bool sign) +{ + if (sign) { + tcg_gen_sextract_tl(result, src, N * 8, 8); + } else { + tcg_gen_extract_tl(result, src, N * 8, 8); + } + return result; +} + static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign) { TCGv_i64 res64 = tcg_temp_new_i64(); @@ -280,6 +290,16 @@ static TCGv gen_get_byte_i64(TCGv result, int N, TCGv_i64 src, bool sign) return result; } +static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign) +{ + if (sign) { + tcg_gen_sextract_tl(result, src, N * 16, 16); + } else { + tcg_gen_extract_tl(result, src, N * 16, 16); + } + return result; +} + static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src) { TCGv_i64 src64 = tcg_temp_new_i64(); @@ -361,6 +381,75 @@ static inline void gen_store_conditional8(CPUHexagonState *env, tcg_gen_movi_tl(hex_llsc_addr, ~0); } +static inline void gen_store32(TCGv vaddr, TCGv src, int width, int slot) +{ + tcg_gen_mov_tl(hex_store_addr[slot], vaddr); + tcg_gen_movi_tl(hex_store_width[slot], width); + tcg_gen_mov_tl(hex_store_val32[slot], src); +} + +static inline void gen_store1(TCGv_env cpu_env, TCGv vaddr, TCGv src, + DisasContext *ctx, int slot) +{ + gen_store32(vaddr, src, 1, slot); + ctx->store_width[slot] = 1; +} + +static inline void gen_store1i(TCGv_env cpu_env, TCGv vaddr, int32_t src, + DisasContext *ctx, int slot) +{ + TCGv tmp = tcg_const_tl(src); + gen_store1(cpu_env, vaddr, tmp, ctx, slot); + tcg_temp_free(tmp); +} + +static inline void gen_store2(TCGv_env cpu_env, TCGv vaddr, TCGv src, + DisasContext *ctx, int slot) +{ + gen_store32(vaddr, src, 2, slot); + ctx->store_width[slot] = 2; +} + +static inline void gen_store2i(TCGv_env cpu_env, TCGv vaddr, int32_t src, + DisasContext *ctx, int slot) +{ + TCGv tmp = tcg_const_tl(src); + gen_store2(cpu_env, vaddr, tmp, ctx, slot); + tcg_temp_free(tmp); +} + +static inline void gen_store4(TCGv_env cpu_env, TCGv vaddr, TCGv src, + DisasContext *ctx, int slot) +{ + gen_store32(vaddr, src, 4, slot); + ctx->store_width[slot] = 4; +} + +static inline void gen_store4i(TCGv_env cpu_env, TCGv vaddr, int32_t src, + DisasContext *ctx, int slot) +{ + TCGv tmp = tcg_const_tl(src); + gen_store4(cpu_env, vaddr, tmp, ctx, slot); + tcg_temp_free(tmp); +} + +static inline void gen_store8(TCGv_env cpu_env, TCGv vaddr, TCGv_i64 src, + DisasContext *ctx, int slot) +{ + tcg_gen_mov_tl(hex_store_addr[slot], vaddr); + tcg_gen_movi_tl(hex_store_width[slot], 8); + tcg_gen_mov_i64(hex_store_val64[slot], src); + ctx->store_width[slot] = 8; +} + +static inline void gen_store8i(TCGv_env cpu_env, TCGv vaddr, int64_t src, + DisasContext *ctx, int slot) +{ + TCGv_i64 tmp = tcg_const_i64(src); + gen_store8(cpu_env, vaddr, tmp, ctx, slot); + tcg_temp_free_i64(tmp); +} + static TCGv gen_8bitsof(TCGv result, TCGv value) { TCGv zero = tcg_const_tl(0); diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index 514c2404ce..68b435ebe7 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -294,6 +294,7 @@ DEF_CLASS32(ICLASS_LD" ---- -------- PP------ --------",LD) DEF_CLASS32(ICLASS_LD" 0--- -------- PP------ --------",LD_ADDR_ROFFSET) +DEF_CLASS32(ICLASS_LD" 100- -------- PP----0- --------",LD_ADDR_POST_CIRC_IMMED) DEF_CLASS32(ICLASS_LD" 101- -------- PP00---- --------",LD_ADDR_POST_IMMED) DEF_CLASS32(ICLASS_LD" 101- -------- PP01---- --------",LD_ADDR_ABS_UPDATE_V4) DEF_CLASS32(ICLASS_LD" 101- -------- PP1----- --------",LD_ADDR_POST_IMMED_PRED_V2) @@ -308,18 +309,23 @@ DEF_FIELD32(ICLASS_LD" ---- --!----- PP------ --------",LD_UN,"Unsigned") #define STD_LD_ENC(TAG,OPC) \ DEF_ENC32(L2_load##TAG##_io, ICLASS_LD" 0 ii "OPC" sssss PPiiiiii iiiddddd")\ +DEF_ENC32(L2_load##TAG##_pci, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--0i iiiddddd")\ DEF_ENC32(L2_load##TAG##_pi, ICLASS_LD" 1 01 "OPC" xxxxx PP00---i iiiddddd")\ DEF_ENC32(L4_load##TAG##_ap, ICLASS_LD" 1 01 "OPC" eeeee PP01IIII -IIddddd")\ DEF_ENC32(L2_load##TAG##_pr, ICLASS_LD" 1 10 "OPC" xxxxx PPu0---- 0--ddddd")\ DEF_ENC32(L4_load##TAG##_ur, ICLASS_LD" 1 10 "OPC" ttttt PPi1IIII iIIddddd")\ +DEF_ENC32(L2_load##TAG##_pcr, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--1- 0--ddddd")\ #define STD_LDX_ENC(TAG,OPC) \ DEF_ENC32(L2_load##TAG##_io, ICLASS_LD" 0 ii "OPC" sssss PPiiiiii iiiyyyyy")\ +DEF_ENC32(L2_load##TAG##_pci, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--0i iiiyyyyy")\ DEF_ENC32(L2_load##TAG##_pi, ICLASS_LD" 1 01 "OPC" xxxxx PP00---i iiiyyyyy")\ DEF_ENC32(L4_load##TAG##_ap, ICLASS_LD" 1 01 "OPC" eeeee PP01IIII -IIyyyyy")\ DEF_ENC32(L2_load##TAG##_pr, ICLASS_LD" 1 10 "OPC" xxxxx PPu0---- 0--yyyyy")\ DEF_ENC32(L4_load##TAG##_ur, ICLASS_LD" 1 10 "OPC" ttttt PPi1IIII iIIyyyyy")\ +DEF_ENC32(L2_load##TAG##_pcr, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--1- 0--yyyyy")\ +DEF_ENC32(L2_load##TAG##_pbr, ICLASS_LD" 1 11 "OPC" xxxxx PPu0---- 0--yyyyy") #define STD_PLD_ENC(TAG,OPC) \ @@ -351,6 +357,7 @@ STD_PLD_ENC(rd, "1 110") /* note dest reg field LSB=0, 1 is reserved */ DEF_CLASS32( ICLASS_LD" 0--0 000----- PP------ --------",LD_MISC) DEF_ANTICLASS32(ICLASS_LD" 0--0 000----- PP------ --------",LD_ADDR_ROFFSET) +DEF_ANTICLASS32(ICLASS_LD" 1000 000----- PP------ --------",LD_ADDR_POST_CIRC_IMMED) DEF_ANTICLASS32(ICLASS_LD" 1010 000----- PP------ --------",LD_ADDR_POST_IMMED) DEF_ANTICLASS32(ICLASS_LD" 1100 000----- PP------ --------",LD_ADDR_POST_REG) DEF_ANTICLASS32(ICLASS_LD" 1110 000----- PP------ --------",LD_ADDR_POST_REG) @@ -397,6 +404,7 @@ DEF_FIELD32(ICLASS_ST" ---! !!------ PP------ --------",ST_Type,"Type") DEF_FIELD32(ICLASS_ST" ---- --!----- PP------ --------",ST_UN,"Unsigned") DEF_CLASS32(ICLASS_ST" 0--1 -------- PP------ --------",ST_ADDR_ROFFSET) +DEF_CLASS32(ICLASS_ST" 1001 -------- PP------ ------0-",ST_ADDR_POST_CIRC_IMMED) DEF_CLASS32(ICLASS_ST" 1011 -------- PP0----- 0-----0-",ST_ADDR_POST_IMMED) DEF_CLASS32(ICLASS_ST" 1011 -------- PP0----- 1-------",ST_ADDR_ABS_UPDATE_V4) DEF_CLASS32(ICLASS_ST" 1011 -------- PP1----- --------",ST_ADDR_POST_IMMED_PRED_V2) @@ -411,10 +419,12 @@ DEF_CLASS32(ICLASS_ST" 0--0 0------- PP------ --------",ST_MISC_CACHEOP) #define STD_ST_ENC(TAG,OPC,SRC) \ DEF_ENC32(S2_store##TAG##_io, ICLASS_ST" 0 ii "OPC" sssss PPi"SRC" iiiiiiii")\ +DEF_ENC32(S2_store##TAG##_pci, ICLASS_ST" 1 00 "OPC" xxxxx PPu"SRC" 0iiii-0-")\ DEF_ENC32(S2_store##TAG##_pi, ICLASS_ST" 1 01 "OPC" xxxxx PP0"SRC" 0iiii-0-")\ DEF_ENC32(S4_store##TAG##_ap, ICLASS_ST" 1 01 "OPC" eeeee PP0"SRC" 1-IIIIII")\ DEF_ENC32(S2_store##TAG##_pr, ICLASS_ST" 1 10 "OPC" xxxxx PPu"SRC" 0-------")\ DEF_ENC32(S4_store##TAG##_ur, ICLASS_ST" 1 10 "OPC" uuuuu PPi"SRC" 1iIIIIII")\ +DEF_ENC32(S2_store##TAG##_pcr, ICLASS_ST" 1 00 "OPC" xxxxx PPu"SRC" 0-----1-")\ #define STD_PST_ENC(TAG,OPC,SRC) \ diff --git a/target/hexagon/imported/ldst.idef b/target/hexagon/imported/ldst.idef index 78a2ea441c..6ce0635e32 100644 --- a/target/hexagon/imported/ldst.idef +++ b/target/hexagon/imported/ldst.idef @@ -26,6 +26,8 @@ Q6INSN(L4_##TAG##_ur, OPER"(Rt32<<#u2+#U6)", ATTRIB,DESCR,{fMUST_IM Q6INSN(L4_##TAG##_ap, OPER"(Re32=#U6)", ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IMM(UiV); SEMANTICS; ReV=UiV; })\ Q6INSN(L2_##TAG##_pr, OPER"(Rx32++Mu2)", ATTRIB,DESCR,{fEA_REG(RxV); fPM_M(RxV,MuV); SEMANTICS;})\ Q6INSN(L2_##TAG##_pi, OPER"(Rx32++#s4:"SHFT")", ATTRIB,DESCR,{fEA_REG(RxV); fPM_I(RxV,siV); SEMANTICS;})\ +Q6INSN(L2_##TAG##_pci, OPER"(Rx32++#s4:"SHFT":circ(Mu2))",ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRI(RxV,siV,MuV); SEMANTICS;})\ +Q6INSN(L2_##TAG##_pcr, OPER"(Rx32++I:circ(Mu2))", ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRR(RxV,fREAD_IREG(MuV)<> 21) | ((VAL >> 17) & 0x7f))) +#endif + #define fREAD_LR() (READ_REG(HEX_REG_LR)) #define fWRITE_LR(A) WRITE_RREG(HEX_REG_LR, A) @@ -418,6 +483,13 @@ static inline void gen_logical_not(TCGv dest, TCGv src) #define fEA_REG(REG) tcg_gen_mov_tl(EA, REG) #define fPM_I(REG, IMM) tcg_gen_addi_tl(REG, REG, IMM) #define fPM_M(REG, MVAL) tcg_gen_add_tl(REG, REG, MVAL) +#define fPM_CIRI(REG, IMM, MVAL) \ + do { \ + TCGv tcgv_siV = tcg_const_tl(siV); \ + gen_helper_fcircadd(REG, REG, tcgv_siV, MuV, \ + hex_gpr[HEX_REG_CS0 + MuN]); \ + tcg_temp_free(tcgv_siV); \ + } while (0) #else #define fEA_IMM(IMM) do { EA = (IMM); } while (0) #define fEA_REG(REG) do { EA = (REG); } while (0) @@ -494,23 +566,43 @@ static inline void gen_logical_not(TCGv dest, TCGv src) gen_load_locked##SIZE##SIGN(DST, EA, ctx->mem_idx); #endif +#ifdef QEMU_GENERATE +#define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, insn->slot) +#else #define fSTORE(NUM, SIZE, EA, SRC) MEM_STORE##SIZE(EA, SRC, slot) +#endif #ifdef QEMU_GENERATE #define fSTORE_LOCKED(NUM, SIZE, EA, SRC, PRED) \ gen_store_conditional##SIZE(env, ctx, PdN, PRED, EA, SRC); #endif +#ifdef QEMU_GENERATE +#define GETBYTE_FUNC(X) \ + __builtin_choose_expr(TYPE_TCGV(X), \ + gen_get_byte, \ + __builtin_choose_expr(TYPE_TCGV_I64(X), \ + gen_get_byte_i64, (void)0)) +#define fGETBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, true) +#define fGETUBYTE(N, SRC) GETBYTE_FUNC(SRC)(BYTE, N, SRC, false) +#else #define fGETBYTE(N, SRC) ((int8_t)((SRC >> ((N) * 8)) & 0xff)) #define fGETUBYTE(N, SRC) ((uint8_t)((SRC >> ((N) * 8)) & 0xff)) +#endif #define fSETBYTE(N, DST, VAL) \ do { \ DST = (DST & ~(0x0ffLL << ((N) * 8))) | \ (((uint64_t)((VAL) & 0x0ffLL)) << ((N) * 8)); \ } while (0) + +#ifdef QEMU_GENERATE +#define fGETHALF(N, SRC) gen_get_half(HALF, N, SRC, true) +#define fGETUHALF(N, SRC) gen_get_half(HALF, N, SRC, false) +#else #define fGETHALF(N, SRC) ((int16_t)((SRC >> ((N) * 16)) & 0xffff)) #define fGETUHALF(N, SRC) ((uint16_t)((SRC >> ((N) * 16)) & 0xffff)) +#endif #define fSETHALF(N, DST, VAL) \ do { \ DST = (DST & ~(0x0ffffLL << ((N) * 16))) | \ diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index f9fb65555b..2319b9313e 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -251,33 +251,25 @@ void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1) } -static int32_t fcircadd_v4(int32_t RxV, int32_t offset, int32_t M, int32_t CS) -{ - int32_t length = M & 0x0001ffff; - uint32_t new_ptr = RxV + offset; - uint32_t start_addr = CS; - uint32_t end_addr = start_addr + length; - - if (new_ptr >= end_addr) { - new_ptr -= length; - } else if (new_ptr < start_addr) { - new_ptr += length; - } - - return new_ptr; -} - int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS) { - int32_t K_const = (M >> 24) & 0xf; - int32_t length = M & 0x1ffff; - int32_t mask = (1 << (K_const + 2)) - 1; + int32_t K_const = sextract32(M, 24, 4); + int32_t length = sextract32(M, 0, 17); uint32_t new_ptr = RxV + offset; - uint32_t start_addr = RxV & (~mask); - uint32_t end_addr = start_addr | length; + uint32_t start_addr; + uint32_t end_addr; if (K_const == 0 && length >= 4) { - return fcircadd_v4(RxV, offset, M, CS); + start_addr = CS; + end_addr = start_addr + length; + } else { + /* + * Versions v3 and earlier used the K value to specify a power-of-2 size + * 2^(K+2) that is greater than the buffer length + */ + int32_t mask = (1 << (K_const + 2)) - 1; + start_addr = RxV & (~mask); + end_addr = start_addr | length; } if (new_ptr >= end_addr) { diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index 18218ad05a..15c7091db5 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -28,6 +28,7 @@ endif CFLAGS += -Wno-incompatible-pointer-types -Wno-undefined-internal +CFLAGS += -fno-unroll-loops HEX_SRC=$(SRC_PATH)/tests/tcg/hexagon VPATH += $(HEX_SRC) @@ -41,6 +42,7 @@ HEX_TESTS += preg_alias HEX_TESTS += dual_stores HEX_TESTS += multi_result HEX_TESTS += mem_noshuf +HEX_TESTS += circ HEX_TESTS += atomics HEX_TESTS += fpstuff diff --git a/tests/tcg/hexagon/circ.c b/tests/tcg/hexagon/circ.c new file mode 100644 index 0000000000..67a1aa3054 --- /dev/null +++ b/tests/tcg/hexagon/circ.c @@ -0,0 +1,486 @@ +/* + * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#define DEBUG 0 +#define DEBUG_PRINTF(...) \ + do { \ + if (DEBUG) { \ + printf(__VA_ARGS__); \ + } \ + } while (0) + + +#define NBYTES (1 << 8) +#define NHALFS (NBYTES / sizeof(short)) +#define NWORDS (NBYTES / sizeof(int)) +#define NDOBLS (NBYTES / sizeof(long long)) + +long long dbuf[NDOBLS] __attribute__((aligned(1 << 12))) = {0}; +int wbuf[NWORDS] __attribute__((aligned(1 << 12))) = {0}; +short hbuf[NHALFS] __attribute__((aligned(1 << 12))) = {0}; +unsigned char bbuf[NBYTES] __attribute__((aligned(1 << 12))) = {0}; + +/* + * We use the C preporcessor to deal with the combinations of types + */ + +#define INIT(BUF, N) \ + void init_##BUF(void) \ + { \ + int i; \ + for (i = 0; i < N; i++) { \ + BUF[i] = i; \ + } \ + } \ + +INIT(bbuf, NBYTES) +INIT(hbuf, NHALFS) +INIT(wbuf, NWORDS) +INIT(dbuf, NDOBLS) + +/* + * Macros for performing circular load + * RES result + * ADDR address + * START start address of buffer + * LEN length of buffer (in bytes) + * INC address increment (in bytes for IMM, elements for REG) + */ +#define CIRC_LOAD_IMM(SIZE, RES, ADDR, START, LEN, INC) \ + __asm__( \ + "r4 = %3\n\t" \ + "m0 = r4\n\t" \ + "cs0 = %2\n\t" \ + "%0 = mem" #SIZE "(%1++#" #INC ":circ(M0))\n\t" \ + : "=r"(RES), "+r"(ADDR) \ + : "r"(START), "r"(LEN) \ + : "r4", "m0", "cs0") +#define CIRC_LOAD_IMM_b(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_IMM(b, RES, ADDR, START, LEN, INC) +#define CIRC_LOAD_IMM_ub(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_IMM(ub, RES, ADDR, START, LEN, INC) +#define CIRC_LOAD_IMM_h(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_IMM(h, RES, ADDR, START, LEN, INC) +#define CIRC_LOAD_IMM_uh(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_IMM(uh, RES, ADDR, START, LEN, INC) +#define CIRC_LOAD_IMM_w(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_IMM(w, RES, ADDR, START, LEN, INC) +#define CIRC_LOAD_IMM_d(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_IMM(d, RES, ADDR, START, LEN, INC) + +/* + * The mreg has the following pieces + * mreg[31:28] increment[10:7] + * mreg[27:24] K value (used Hexagon v3 and earlier) + * mreg[23:17] increment[6:0] + * mreg[16:0] circular buffer length + */ +static int build_mreg(int inc, int K, int len) +{ + return ((inc & 0x780) << 21) | + ((K & 0xf) << 24) | + ((inc & 0x7f) << 17) | + (len & 0x1ffff); +} + +#define CIRC_LOAD_REG(SIZE, RES, ADDR, START, LEN, INC) \ + __asm__( \ + "r4 = %2\n\t" \ + "m1 = r4\n\t" \ + "cs1 = %3\n\t" \ + "%0 = mem" #SIZE "(%1++I:circ(M1))\n\t" \ + : "=r"(RES), "+r"(ADDR) \ + : "r"(build_mreg((INC), 0, (LEN))), \ + "r"(START) \ + : "r4", "m1", "cs1") +#define CIRC_LOAD_REG_b(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_REG(b, RES, ADDR, START, LEN, INC) +#define CIRC_LOAD_REG_ub(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_REG(ub, RES, ADDR, START, LEN, INC) +#define CIRC_LOAD_REG_h(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_REG(h, RES, ADDR, START, LEN, INC) +#define CIRC_LOAD_REG_uh(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_REG(uh, RES, ADDR, START, LEN, INC) +#define CIRC_LOAD_REG_w(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_REG(w, RES, ADDR, START, LEN, INC) +#define CIRC_LOAD_REG_d(RES, ADDR, START, LEN, INC) \ + CIRC_LOAD_REG(d, RES, ADDR, START, LEN, INC) + +/* + * Macros for performing circular store + * VAL value to store + * ADDR address + * START start address of buffer + * LEN length of buffer (in bytes) + * INC address increment (in bytes for IMM, elements for REG) + */ +#define CIRC_STORE_IMM(SIZE, PART, VAL, ADDR, START, LEN, INC) \ + __asm__( \ + "r4 = %3\n\t" \ + "m0 = r4\n\t" \ + "cs0 = %1\n\t" \ + "mem" #SIZE "(%0++#" #INC ":circ(M0)) = %2" PART "\n\t" \ + : "+r"(ADDR) \ + : "r"(START), "r"(VAL), "r"(LEN) \ + : "r4", "m0", "cs0", "memory") +#define CIRC_STORE_IMM_b(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_IMM(b, "", VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_IMM_h(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_IMM(h, "", VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_IMM_f(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_IMM(h, ".H", VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_IMM_w(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_IMM(w, "", VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_IMM_d(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_IMM(d, "", VAL, ADDR, START, LEN, INC) + +#define CIRC_STORE_NEW_IMM(SIZE, VAL, ADDR, START, LEN, INC) \ + __asm__( \ + "r4 = %3\n\t" \ + "m0 = r4\n\t" \ + "cs0 = %1\n\t" \ + "{\n\t" \ + " r5 = %2\n\t" \ + " mem" #SIZE "(%0++#" #INC ":circ(M0)) = r5.new\n\t" \ + "}\n\t" \ + : "+r"(ADDR) \ + : "r"(START), "r"(VAL), "r"(LEN) \ + : "r4", "r5", "m0", "cs0", "memory") +#define CIRC_STORE_IMM_bnew(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_NEW_IMM(b, VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_IMM_hnew(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_NEW_IMM(h, VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_IMM_wnew(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_NEW_IMM(w, VAL, ADDR, START, LEN, INC) + +#define CIRC_STORE_REG(SIZE, PART, VAL, ADDR, START, LEN, INC) \ + __asm__( \ + "r4 = %1\n\t" \ + "m1 = r4\n\t" \ + "cs1 = %2\n\t" \ + "mem" #SIZE "(%0++I:circ(M1)) = %3" PART "\n\t" \ + : "+r"(ADDR) \ + : "r"(build_mreg((INC), 0, (LEN))), \ + "r"(START), \ + "r"(VAL) \ + : "r4", "m1", "cs1", "memory") +#define CIRC_STORE_REG_b(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_REG(b, "", VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_REG_h(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_REG(h, "", VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_REG_f(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_REG(h, ".H", VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_REG_w(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_REG(w, "", VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_REG_d(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_REG(d, "", VAL, ADDR, START, LEN, INC) + +#define CIRC_STORE_NEW_REG(SIZE, VAL, ADDR, START, LEN, INC) \ + __asm__( \ + "r4 = %1\n\t" \ + "m1 = r4\n\t" \ + "cs1 = %2\n\t" \ + "{\n\t" \ + " r5 = %3\n\t" \ + " mem" #SIZE "(%0++I:circ(M1)) = r5.new\n\t" \ + "}\n\t" \ + : "+r"(ADDR) \ + : "r"(build_mreg((INC), 0, (LEN))), \ + "r"(START), \ + "r"(VAL) \ + : "r4", "r5", "m1", "cs1", "memory") +#define CIRC_STORE_REG_bnew(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_NEW_REG(b, VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_REG_hnew(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_NEW_REG(h, VAL, ADDR, START, LEN, INC) +#define CIRC_STORE_REG_wnew(VAL, ADDR, START, LEN, INC) \ + CIRC_STORE_NEW_REG(w, VAL, ADDR, START, LEN, INC) + + +int err; + +/* We'll test increments +1 and -1 */ +void check_load(int i, long long result, int inc, int size) +{ + int expect = (i * inc); + while (expect >= size) { + expect -= size; + } + while (expect < 0) { + expect += size; + } + if (result != expect) { + printf("ERROR(%d): %lld != %d\n", i, result, expect); + err++; + } +} + +#define TEST_LOAD_IMM(SZ, TYPE, BUF, BUFSIZE, INC, FMT) \ +void circ_test_load_imm_##SZ(void) \ +{ \ + TYPE *p = (TYPE *)BUF; \ + int size = 10; \ + int i; \ + for (i = 0; i < BUFSIZE; i++) { \ + TYPE element; \ + CIRC_LOAD_IMM_##SZ(element, p, BUF, size * sizeof(TYPE), (INC)); \ + DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \ + i, p, element); \ + check_load(i, element, ((INC) / (int)sizeof(TYPE)), size); \ + } \ + p = (TYPE *)BUF; \ + for (i = 0; i < BUFSIZE; i++) { \ + TYPE element; \ + CIRC_LOAD_IMM_##SZ(element, p, BUF, size * sizeof(TYPE), -(INC)); \ + DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \ + i, p, element); \ + check_load(i, element, (-(INC) / (int)sizeof(TYPE)), size); \ + } \ +} + +TEST_LOAD_IMM(b, char, bbuf, NBYTES, 1, d) +TEST_LOAD_IMM(ub, unsigned char, bbuf, NBYTES, 1, d) +TEST_LOAD_IMM(h, short, hbuf, NHALFS, 2, d) +TEST_LOAD_IMM(uh, unsigned short, hbuf, NHALFS, 2, d) +TEST_LOAD_IMM(w, int, wbuf, NWORDS, 4, d) +TEST_LOAD_IMM(d, long long, dbuf, NDOBLS, 8, lld) + +#define TEST_LOAD_REG(SZ, TYPE, BUF, BUFSIZE, FMT) \ +void circ_test_load_reg_##SZ(void) \ +{ \ + TYPE *p = (TYPE *)BUF; \ + int size = 13; \ + int i; \ + for (i = 0; i < BUFSIZE; i++) { \ + TYPE element; \ + CIRC_LOAD_REG_##SZ(element, p, BUF, size * sizeof(TYPE), 1); \ + DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \ + i, p, element); \ + check_load(i, element, 1, size); \ + } \ + p = (TYPE *)BUF; \ + for (i = 0; i < BUFSIZE; i++) { \ + TYPE element; \ + CIRC_LOAD_REG_##SZ(element, p, BUF, size * sizeof(TYPE), -1); \ + DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2" #FMT "\n", \ + i, p, element); \ + check_load(i, element, -1, size); \ + } \ +} + +TEST_LOAD_REG(b, char, bbuf, NBYTES, d) +TEST_LOAD_REG(ub, unsigned char, bbuf, NBYTES, d) +TEST_LOAD_REG(h, short, hbuf, NHALFS, d) +TEST_LOAD_REG(uh, unsigned short, hbuf, NHALFS, d) +TEST_LOAD_REG(w, int, wbuf, NWORDS, d) +TEST_LOAD_REG(d, long long, dbuf, NDOBLS, lld) + +/* The circular stores will wrap around somewhere inside the buffer */ +#define CIRC_VAL(SZ, TYPE, BUFSIZE) \ +TYPE circ_val_##SZ(int i, int inc, int size) \ +{ \ + int mod = BUFSIZE % size; \ + int elem = i * inc; \ + if (elem < 0) { \ + if (-elem <= size - mod) { \ + return (elem + BUFSIZE - mod); \ + } else { \ + return (elem + BUFSIZE + size - mod); \ + } \ + } else if (elem < mod) {\ + return (elem + BUFSIZE - mod); \ + } else { \ + return (elem + BUFSIZE - size - mod); \ + } \ +} + +CIRC_VAL(b, unsigned char, NBYTES) +CIRC_VAL(h, short, NHALFS) +CIRC_VAL(w, int, NWORDS) +CIRC_VAL(d, long long, NDOBLS) + +/* + * Circular stores should only write to the first "size" elements of the buffer + * the remainder of the elements should have BUF[i] == i + */ +#define CHECK_STORE(SZ, BUF, BUFSIZE, FMT) \ +void check_store_##SZ(int inc, int size) \ +{ \ + int i; \ + for (i = 0; i < size; i++) { \ + DEBUG_PRINTF(#BUF "[%3d] = 0x%02" #FMT ", guess = 0x%02" #FMT "\n", \ + i, BUF[i], circ_val_##SZ(i, inc, size)); \ + if (BUF[i] != circ_val_##SZ(i, inc, size)) { \ + printf("ERROR(%3d): 0x%02" #FMT " != 0x%02" #FMT "\n", \ + i, BUF[i], circ_val_##SZ(i, inc, size)); \ + err++; \ + } \ + } \ + for (i = size; i < BUFSIZE; i++) { \ + if (BUF[i] != i) { \ + printf("ERROR(%3d): 0x%02" #FMT " != 0x%02x\n", i, BUF[i], i); \ + err++; \ + } \ + } \ +} + +CHECK_STORE(b, bbuf, NBYTES, x) +CHECK_STORE(h, hbuf, NHALFS, x) +CHECK_STORE(w, wbuf, NWORDS, x) +CHECK_STORE(d, dbuf, NDOBLS, llx) + +#define CIRC_TEST_STORE_IMM(SZ, CHK, TYPE, BUF, BUFSIZE, SHIFT, INC) \ +void circ_test_store_imm_##SZ(void) \ +{ \ + unsigned int size = 27; \ + TYPE *p = BUF; \ + TYPE val = 0; \ + int i; \ + init_##BUF(); \ + for (i = 0; i < BUFSIZE; i++) { \ + CIRC_STORE_IMM_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), INC); \ + val++; \ + } \ + check_store_##CHK(((INC) / (int)sizeof(TYPE)), size); \ + p = BUF; \ + val = 0; \ + init_##BUF(); \ + for (i = 0; i < BUFSIZE; i++) { \ + CIRC_STORE_IMM_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), \ + -(INC)); \ + val++; \ + } \ + check_store_##CHK((-(INC) / (int)sizeof(TYPE)), size); \ +} + +CIRC_TEST_STORE_IMM(b, b, unsigned char, bbuf, NBYTES, 0, 1) +CIRC_TEST_STORE_IMM(h, h, short, hbuf, NHALFS, 0, 2) +CIRC_TEST_STORE_IMM(f, h, short, hbuf, NHALFS, 16, 2) +CIRC_TEST_STORE_IMM(w, w, int, wbuf, NWORDS, 0, 4) +CIRC_TEST_STORE_IMM(d, d, long long, dbuf, NDOBLS, 0, 8) +CIRC_TEST_STORE_IMM(bnew, b, unsigned char, bbuf, NBYTES, 0, 1) +CIRC_TEST_STORE_IMM(hnew, h, short, hbuf, NHALFS, 0, 2) +CIRC_TEST_STORE_IMM(wnew, w, int, wbuf, NWORDS, 0, 4) + +#define CIRC_TEST_STORE_REG(SZ, CHK, TYPE, BUF, BUFSIZE, SHIFT) \ +void circ_test_store_reg_##SZ(void) \ +{ \ + TYPE *p = BUF; \ + unsigned int size = 19; \ + TYPE val = 0; \ + int i; \ + init_##BUF(); \ + for (i = 0; i < BUFSIZE; i++) { \ + CIRC_STORE_REG_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), 1); \ + val++; \ + } \ + check_store_##CHK(1, size); \ + p = BUF; \ + val = 0; \ + init_##BUF(); \ + for (i = 0; i < BUFSIZE; i++) { \ + CIRC_STORE_REG_##SZ(val << SHIFT, p, BUF, size * sizeof(TYPE), -1); \ + val++; \ + } \ + check_store_##CHK(-1, size); \ +} + +CIRC_TEST_STORE_REG(b, b, unsigned char, bbuf, NBYTES, 0) +CIRC_TEST_STORE_REG(h, h, short, hbuf, NHALFS, 0) +CIRC_TEST_STORE_REG(f, h, short, hbuf, NHALFS, 16) +CIRC_TEST_STORE_REG(w, w, int, wbuf, NWORDS, 0) +CIRC_TEST_STORE_REG(d, d, long long, dbuf, NDOBLS, 0) +CIRC_TEST_STORE_REG(bnew, b, unsigned char, bbuf, NBYTES, 0) +CIRC_TEST_STORE_REG(hnew, h, short, hbuf, NHALFS, 0) +CIRC_TEST_STORE_REG(wnew, w, int, wbuf, NWORDS, 0) + +/* Test the old scheme used in Hexagon V3 */ +static void circ_test_v3(void) +{ + int *p = wbuf; + int size = 15; + int K = 4; /* 64 bytes */ + int element; + int i; + + init_wbuf(); + + for (i = 0; i < NWORDS; i++) { + __asm__( + "r4 = %2\n\t" + "m1 = r4\n\t" + "%0 = memw(%1++I:circ(M1))\n\t" + : "=r"(element), "+r"(p) + : "r"(build_mreg(1, K, size * sizeof(int))) + : "r4", "m1"); + DEBUG_PRINTF("i = %2d, p = 0x%p, element = %2d\n", i, p, element); + check_load(i, element, 1, size); + } +} + +int main() +{ + init_bbuf(); + init_hbuf(); + init_wbuf(); + init_dbuf(); + + DEBUG_PRINTF("NBYTES = %d\n", NBYTES); + DEBUG_PRINTF("Address of dbuf = 0x%p\n", dbuf); + DEBUG_PRINTF("Address of wbuf = 0x%p\n", wbuf); + DEBUG_PRINTF("Address of hbuf = 0x%p\n", hbuf); + DEBUG_PRINTF("Address of bbuf = 0x%p\n", bbuf); + + circ_test_load_imm_b(); + circ_test_load_imm_ub(); + circ_test_load_imm_h(); + circ_test_load_imm_uh(); + circ_test_load_imm_w(); + circ_test_load_imm_d(); + + circ_test_load_reg_b(); + circ_test_load_reg_ub(); + circ_test_load_reg_h(); + circ_test_load_reg_uh(); + circ_test_load_reg_w(); + circ_test_load_reg_d(); + + circ_test_store_imm_b(); + circ_test_store_imm_h(); + circ_test_store_imm_f(); + circ_test_store_imm_w(); + circ_test_store_imm_d(); + circ_test_store_imm_bnew(); + circ_test_store_imm_hnew(); + circ_test_store_imm_wnew(); + + circ_test_store_reg_b(); + circ_test_store_reg_h(); + circ_test_store_reg_f(); + circ_test_store_reg_w(); + circ_test_store_reg_d(); + circ_test_store_reg_bnew(); + circ_test_store_reg_hnew(); + circ_test_store_reg_wnew(); + + circ_test_v3(); + + puts(err ? "FAIL" : "PASS"); + return err ? 1 : 0; +} From af7f1821273c45a6101735023736882ec0399e86 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:51 -0500 Subject: [PATCH 0169/3028] Hexagon (target/hexagon) bit reverse (brev) addressing The following instructions are added L2_loadrub_pbr Rd32 = memub(Rx32++Mu2:brev) L2_loadrb_pbr Rd32 = memb(Rx32++Mu2:brev) L2_loadruh_pbr Rd32 = memuh(Rx32++Mu2:brev) L2_loadrh_pbr Rd32 = memh(Rx32++Mu2:brev) L2_loadri_pbr Rd32 = memw(Rx32++Mu2:brev) L2_loadrd_pbr Rdd32 = memd(Rx32++Mu2:brev) S2_storerb_pbr memb(Rx32++Mu2:brev).=.Rt32 S2_storerh_pbr memh(Rx32++Mu2:brev).=.Rt32 S2_storerf_pbr memh(Rx32++Mu2:brev).=.Rt.H32 S2_storeri_pbr memw(Rx32++Mu2:brev).=.Rt32 S2_storerd_pbr memd(Rx32++Mu2:brev).=.Rt32 S2_storerinew_pbr memw(Rx32++Mu2:brev).=.Nt8.new S2_storerbnew_pbr memw(Rx32++Mu2:brev).=.Nt8.new S2_storerhnew_pbr memw(Rx32++Mu2:brev).=.Nt8.new Test cases in tests/tcg/hexagon/brev.c Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-24-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/gen_tcg.h | 28 ++++ target/hexagon/helper.h | 1 + target/hexagon/imported/encode_pp.def | 4 + target/hexagon/imported/ldst.idef | 2 + target/hexagon/imported/macros.def | 6 + target/hexagon/macros.h | 1 + target/hexagon/op_helper.c | 8 ++ tests/tcg/hexagon/Makefile.target | 1 + tests/tcg/hexagon/brev.c | 190 ++++++++++++++++++++++++++ 9 files changed, 241 insertions(+) create mode 100644 tests/tcg/hexagon/brev.c diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index 25c228c112..8f0ec01f0a 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -37,6 +37,7 @@ * _sp stack pointer relative r0 = memw(r29+#12) * _ap absolute set r0 = memw(r1=##variable) * _pr post increment register r0 = memw(r1++m1) + * _pbr post increment bit reverse r0 = memw(r1++m1:brev) * _pi post increment immediate r0 = memb(r1++#1) * _pci post increment circular immediate r0 = memw(r1++#4:circ(m0)) * _pcr post increment circular register r0 = memw(r1++I:circ(m0)) @@ -53,6 +54,11 @@ fEA_REG(RxV); \ fPM_M(RxV, MuV); \ } while (0) +#define GET_EA_pbr \ + do { \ + gen_helper_fbrev(EA, RxV); \ + tcg_gen_add_tl(RxV, RxV, MuV); \ + } while (0) #define GET_EA_pi \ do { \ fEA_REG(RxV); \ @@ -128,16 +134,22 @@ fGEN_TCG_LOAD_pcr(3, fLOAD(1, 8, u, EA, RddV)) #define fGEN_TCG_L2_loadrub_pr(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadrub_pbr(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrub_pi(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrb_pr(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadrb_pbr(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrb_pi(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadruh_pr(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadruh_pbr(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadruh_pi(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrh_pr(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadrh_pbr(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrh_pi(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadri_pr(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadri_pbr(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadri_pi(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrd_pr(SHORTCODE) SHORTCODE +#define fGEN_TCG_L2_loadrd_pbr(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrd_pi(SHORTCODE) SHORTCODE /* @@ -265,41 +277,57 @@ tcg_temp_free(BYTE); \ } while (0) +#define fGEN_TCG_S2_storerb_pbr(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerb_pci(SHORTCODE) \ fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerb_pcr(SHORTCODE) \ fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, RtV))) +#define fGEN_TCG_S2_storerh_pbr(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerh_pci(SHORTCODE) \ fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerh_pcr(SHORTCODE) \ fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, RtV))) +#define fGEN_TCG_S2_storerf_pbr(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerf_pci(SHORTCODE) \ fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerf_pcr(SHORTCODE) \ fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(1, RtV))) +#define fGEN_TCG_S2_storeri_pbr(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storeri_pci(SHORTCODE) \ fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storeri_pcr(SHORTCODE) \ fGEN_TCG_STORE_pcr(2, fSTORE(1, 4, EA, RtV)) +#define fGEN_TCG_S2_storerd_pbr(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerd_pci(SHORTCODE) \ fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerd_pcr(SHORTCODE) \ fGEN_TCG_STORE_pcr(3, fSTORE(1, 8, EA, RttV)) +#define fGEN_TCG_S2_storerbnew_pbr(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerbnew_pci(SHORTCODE) \ fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerbnew_pcr(SHORTCODE) \ fGEN_TCG_STORE_pcr(0, fSTORE(1, 1, EA, fGETBYTE(0, NtN))) +#define fGEN_TCG_S2_storerhnew_pbr(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerhnew_pci(SHORTCODE) \ fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerhnew_pcr(SHORTCODE) \ fGEN_TCG_STORE_pcr(1, fSTORE(1, 2, EA, fGETHALF(0, NtN))) +#define fGEN_TCG_S2_storerinew_pbr(SHORTCODE) \ + fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerinew_pci(SHORTCODE) \ fGEN_TCG_STORE(SHORTCODE) #define fGEN_TCG_S2_storerinew_pcr(SHORTCODE) \ diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h index 3824ae01ea..ca201fb680 100644 --- a/target/hexagon/helper.h +++ b/target/hexagon/helper.h @@ -24,6 +24,7 @@ DEF_HELPER_FLAGS_3(debug_check_store_width, TCG_CALL_NO_WG, void, env, int, int) DEF_HELPER_FLAGS_3(debug_commit_end, TCG_CALL_NO_WG, void, env, int, int) DEF_HELPER_2(commit_store, void, env, int) DEF_HELPER_FLAGS_4(fcircadd, TCG_CALL_NO_RWG_SE, s32, s32, s32, s32, s32) +DEF_HELPER_FLAGS_1(fbrev, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_3(sfrecipa, i64, env, f32, f32) DEF_HELPER_2(sfinvsqrta, i64, env, f32) DEF_HELPER_4(vacsh_val, s64, env, s64, s64, s64) diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index 68b435ebe7..4464926634 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -301,6 +301,7 @@ DEF_CLASS32(ICLASS_LD" 101- -------- PP1----- --------",LD_ADDR_POST_IMMED_PRED_ DEF_CLASS32(ICLASS_LD" 110- -------- PP-0---- 0-------",LD_ADDR_POST_REG) DEF_CLASS32(ICLASS_LD" 110- -------- PP-1---- --------",LD_ADDR_ABS_PLUS_REG_V4) DEF_CLASS32(ICLASS_LD" 100- -------- PP----1- --------",LD_ADDR_POST_CREG_V2) +DEF_CLASS32(ICLASS_LD" 111- -------- PP------ 0-------",LD_ADDR_POST_BREV_REG) DEF_CLASS32(ICLASS_LD" 111- -------- PP------ 1-------",LD_ADDR_PRED_ABS_V4) DEF_FIELD32(ICLASS_LD" !!!- -------- PP------ --------",LD_Amode,"Amode") @@ -315,6 +316,7 @@ DEF_ENC32(L4_load##TAG##_ap, ICLASS_LD" 1 01 "OPC" eeeee PP01IIII -IIddddd" DEF_ENC32(L2_load##TAG##_pr, ICLASS_LD" 1 10 "OPC" xxxxx PPu0---- 0--ddddd")\ DEF_ENC32(L4_load##TAG##_ur, ICLASS_LD" 1 10 "OPC" ttttt PPi1IIII iIIddddd")\ DEF_ENC32(L2_load##TAG##_pcr, ICLASS_LD" 1 00 "OPC" xxxxx PPu0--1- 0--ddddd")\ +DEF_ENC32(L2_load##TAG##_pbr, ICLASS_LD" 1 11 "OPC" xxxxx PPu0---- 0--ddddd") #define STD_LDX_ENC(TAG,OPC) \ @@ -412,6 +414,7 @@ DEF_CLASS32(ICLASS_ST" 1111 -------- PP------ 1-------",ST_ADDR_PRED_ABS_V4) DEF_CLASS32(ICLASS_ST" 1101 -------- PP------ 0-------",ST_ADDR_POST_REG) DEF_CLASS32(ICLASS_ST" 1101 -------- PP------ 1-------",ST_ADDR_ABS_PLUS_REG_V4) DEF_CLASS32(ICLASS_ST" 1001 -------- PP------ ------1-",ST_ADDR_POST_CREG_V2) +DEF_CLASS32(ICLASS_ST" 1111 -------- PP------ 0-------",ST_ADDR_POST_BREV_REG) DEF_CLASS32(ICLASS_ST" 0--0 1------- PP------ --------",ST_MISC_STORELIKE) DEF_CLASS32(ICLASS_ST" 1--0 0------- PP------ --------",ST_MISC_BUSOP) DEF_CLASS32(ICLASS_ST" 0--0 0------- PP------ --------",ST_MISC_CACHEOP) @@ -425,6 +428,7 @@ DEF_ENC32(S4_store##TAG##_ap, ICLASS_ST" 1 01 "OPC" eeeee PP0"SRC" 1-IIIIII DEF_ENC32(S2_store##TAG##_pr, ICLASS_ST" 1 10 "OPC" xxxxx PPu"SRC" 0-------")\ DEF_ENC32(S4_store##TAG##_ur, ICLASS_ST" 1 10 "OPC" uuuuu PPi"SRC" 1iIIIIII")\ DEF_ENC32(S2_store##TAG##_pcr, ICLASS_ST" 1 00 "OPC" xxxxx PPu"SRC" 0-----1-")\ +DEF_ENC32(S2_store##TAG##_pbr, ICLASS_ST" 1 11 "OPC" xxxxx PPu"SRC" 0-------") #define STD_PST_ENC(TAG,OPC,SRC) \ diff --git a/target/hexagon/imported/ldst.idef b/target/hexagon/imported/ldst.idef index 6ce0635e32..fe7e018cf1 100644 --- a/target/hexagon/imported/ldst.idef +++ b/target/hexagon/imported/ldst.idef @@ -25,6 +25,7 @@ Q6INSN(L2_##TAG##_io, OPER"(Rs32+#s11:"SHFT")", ATTRIB,DESCR,{fIMMEXT( Q6INSN(L4_##TAG##_ur, OPER"(Rt32<<#u2+#U6)", ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IRs(UiV,RtV,uiV); SEMANTICS;})\ Q6INSN(L4_##TAG##_ap, OPER"(Re32=#U6)", ATTRIB,DESCR,{fMUST_IMMEXT(UiV); fEA_IMM(UiV); SEMANTICS; ReV=UiV; })\ Q6INSN(L2_##TAG##_pr, OPER"(Rx32++Mu2)", ATTRIB,DESCR,{fEA_REG(RxV); fPM_M(RxV,MuV); SEMANTICS;})\ +Q6INSN(L2_##TAG##_pbr, OPER"(Rx32++Mu2:brev)", ATTRIB,DESCR,{fEA_BREVR(RxV); fPM_M(RxV,MuV); SEMANTICS;})\ Q6INSN(L2_##TAG##_pi, OPER"(Rx32++#s4:"SHFT")", ATTRIB,DESCR,{fEA_REG(RxV); fPM_I(RxV,siV); SEMANTICS;})\ Q6INSN(L2_##TAG##_pci, OPER"(Rx32++#s4:"SHFT":circ(Mu2))",ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRI(RxV,siV,MuV); SEMANTICS;})\ Q6INSN(L2_##TAG##_pcr, OPER"(Rx32++I:circ(Mu2))", ATTRIB,DESCR,{fEA_REG(RxV); fPM_CIRR(RxV,fREAD_IREG(MuV)<>= 1; + } + return result; +} + +int sext8(int x) +{ + return (x << 24) >> 24; +} + +void check(int i, long long result, long long expect) +{ + if (result != expect) { + printf("ERROR(%d): 0x%04llx != 0x%04llx\n", i, result, expect); + err++; + } +} + +#define TEST_BREV_LOAD(SZ, TYPE, BUF, SHIFT, EXP) \ + do { \ + p = BUF; \ + for (i = 0; i < SIZE; i++) { \ + TYPE result; \ + BREV_LOAD_##SZ(result, p, 1 << (SHIFT - NBITS)); \ + check(i, result, EXP); \ + } \ + } while (0) + +#define TEST_BREV_STORE(SZ, TYPE, BUF, VAL, SHIFT) \ + do { \ + p = BUF; \ + memset(BUF, 0xff, sizeof(BUF)); \ + for (i = 0; i < SIZE; i++) { \ + BREV_STORE_##SZ(p, (TYPE)(VAL), 1 << (SHIFT - NBITS)); \ + } \ + for (i = 0; i < SIZE; i++) { \ + check(i, BUF[i], bitreverse(i)); \ + } \ + } while (0) + +#define TEST_BREV_STORE_NEW(SZ, BUF, SHIFT) \ + do { \ + p = BUF; \ + memset(BUF, 0xff, sizeof(BUF)); \ + for (i = 0; i < SIZE; i++) { \ + BREV_STORE_##SZ(p, i, 1 << (SHIFT - NBITS)); \ + } \ + for (i = 0; i < SIZE; i++) { \ + check(i, BUF[i], bitreverse(i)); \ + } \ + } while (0) + +/* + * We'll set high_half[i] = i << 16 for use in the .H form of store + * which stores from the high half of the word. + */ +int high_half[SIZE]; + +int main() +{ + void *p; + int i; + + for (i = 0; i < SIZE; i++) { + bbuf[i] = bitreverse(i); + hbuf[i] = bitreverse(i); + wbuf[i] = bitreverse(i); + dbuf[i] = bitreverse(i); + high_half[i] = i << 16; + } + + TEST_BREV_LOAD(b, int, bbuf, 16, sext8(i)); + TEST_BREV_LOAD(ub, int, bbuf, 16, i); + TEST_BREV_LOAD(h, int, hbuf, 15, i); + TEST_BREV_LOAD(uh, int, hbuf, 15, i); + TEST_BREV_LOAD(w, int, wbuf, 14, i); + TEST_BREV_LOAD(d, long long, dbuf, 13, i); + + TEST_BREV_STORE(b, int, bbuf, i, 16); + TEST_BREV_STORE(h, int, hbuf, i, 15); + TEST_BREV_STORE(f, int, hbuf, high_half[i], 15); + TEST_BREV_STORE(w, int, wbuf, i, 14); + TEST_BREV_STORE(d, long long, dbuf, i, 13); + + TEST_BREV_STORE_NEW(bnew, bbuf, 16); + TEST_BREV_STORE_NEW(hnew, hbuf, 15); + TEST_BREV_STORE_NEW(wnew, wbuf, 14); + + puts(err ? "FAIL" : "PASS"); + return err ? 1 : 0; +} From 0d0b91a8049967f5e3bfd86e9d372d61b4019b77 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:52 -0500 Subject: [PATCH 0170/3028] Hexagon (target/hexagon) load and unpack bytes instructions The following instructions are added L2_loadbzw2_io Rd32 = memubh(Rs32+#s11:1) L2_loadbzw4_io Rdd32 = memubh(Rs32+#s11:1) L2_loadbsw2_io Rd32 = membh(Rs32+#s11:1) L2_loadbsw4_io Rdd32 = membh(Rs32+#s11:1) L4_loadbzw2_ur Rd32 = memubh(Rt32<<#u2+#U6) L4_loadbzw4_ur Rdd32 = memubh(Rt32<<#u2+#U6) L4_loadbsw2_ur Rd32 = membh(Rt32<<#u2+#U6) L4_loadbsw4_ur Rdd32 = membh(Rt32<<#u2+#U6) L4_loadbzw2_ap Rd32 = memubh(Re32=#U6) L4_loadbzw4_ap Rdd32 = memubh(Re32=#U6) L4_loadbsw2_ap Rd32 = membh(Re32=#U6) L4_loadbsw4_ap Rdd32 = membh(Re32=#U6) L2_loadbzw2_pr Rd32 = memubh(Rx32++Mu2) L2_loadbzw4_pr Rdd32 = memubh(Rx32++Mu2) L2_loadbsw2_pr Rd32 = membh(Rx32++Mu2) L2_loadbsw4_pr Rdd32 = membh(Rx32++Mu2) L2_loadbzw2_pbr Rd32 = memubh(Rx32++Mu2:brev) L2_loadbzw4_pbr Rdd32 = memubh(Rx32++Mu2:brev) L2_loadbsw2_pbr Rd32 = membh(Rx32++Mu2:brev) L2_loadbsw4_pbr Rdd32 = membh(Rx32++Mu2:brev) L2_loadbzw2_pi Rd32 = memubh(Rx32++#s4:1) L2_loadbzw4_pi Rdd32 = memubh(Rx32++#s4:1) L2_loadbsw2_pi Rd32 = membh(Rx32++#s4:1) L2_loadbsw4_pi Rdd32 = membh(Rx32++#s4:1) L2_loadbzw2_pci Rd32 = memubh(Rx32++#s4:1:circ(Mu2)) L2_loadbzw4_pci Rdd32 = memubh(Rx32++#s4:1:circ(Mu2)) L2_loadbsw2_pci Rd32 = membh(Rx32++#s4:1:circ(Mu2)) L2_loadbsw4_pci Rdd32 = membh(Rx32++#s4:1:circ(Mu2)) L2_loadbzw2_pcr Rd32 = memubh(Rx32++I:circ(Mu2)) L2_loadbzw4_pcr Rdd32 = memubh(Rx32++I:circ(Mu2)) L2_loadbsw2_pcr Rd32 = membh(Rx32++I:circ(Mu2)) L2_loadbsw4_pcr Rdd32 = membh(Rx32++I:circ(Mu2)) Test cases in tests/tcg/hexagon/load_unpack.c Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-25-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/gen_tcg.h | 108 ++++++ target/hexagon/genptr.c | 13 + target/hexagon/imported/encode_pp.def | 6 + target/hexagon/imported/ldst.idef | 43 +++ target/hexagon/macros.h | 16 + tests/tcg/hexagon/Makefile.target | 1 + tests/tcg/hexagon/load_unpack.c | 474 ++++++++++++++++++++++++++ 7 files changed, 661 insertions(+) create mode 100644 tests/tcg/hexagon/load_unpack.c diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index 8f0ec01f0a..1120aaed4e 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -152,6 +152,114 @@ #define fGEN_TCG_L2_loadrd_pbr(SHORTCODE) SHORTCODE #define fGEN_TCG_L2_loadrd_pi(SHORTCODE) SHORTCODE +/* + * These instructions load 2 bytes and places them in + * two halves of the destination register. + * The GET_EA macro determines the addressing mode. + * The SIGN argument determines whether to zero-extend or + * sign-extend. + */ +#define fGEN_TCG_loadbXw2(GET_EA, SIGN) \ + do { \ + TCGv tmp = tcg_temp_new(); \ + TCGv byte = tcg_temp_new(); \ + GET_EA; \ + fLOAD(1, 2, u, EA, tmp); \ + tcg_gen_movi_tl(RdV, 0); \ + for (int i = 0; i < 2; i++) { \ + gen_set_half(i, RdV, gen_get_byte(byte, i, tmp, (SIGN))); \ + } \ + tcg_temp_free(tmp); \ + tcg_temp_free(byte); \ + } while (0) + +#define fGEN_TCG_L2_loadbzw2_io(SHORTCODE) \ + fGEN_TCG_loadbXw2(fEA_RI(RsV, siV), false) +#define fGEN_TCG_L4_loadbzw2_ur(SHORTCODE) \ + fGEN_TCG_loadbXw2(fEA_IRs(UiV, RtV, uiV), false) +#define fGEN_TCG_L2_loadbsw2_io(SHORTCODE) \ + fGEN_TCG_loadbXw2(fEA_RI(RsV, siV), true) +#define fGEN_TCG_L4_loadbsw2_ur(SHORTCODE) \ + fGEN_TCG_loadbXw2(fEA_IRs(UiV, RtV, uiV), true) +#define fGEN_TCG_L4_loadbzw2_ap(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_ap, false) +#define fGEN_TCG_L2_loadbzw2_pr(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_pr, false) +#define fGEN_TCG_L2_loadbzw2_pbr(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_pbr, false) +#define fGEN_TCG_L2_loadbzw2_pi(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_pi, false) +#define fGEN_TCG_L4_loadbsw2_ap(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_ap, true) +#define fGEN_TCG_L2_loadbsw2_pr(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_pr, true) +#define fGEN_TCG_L2_loadbsw2_pbr(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_pbr, true) +#define fGEN_TCG_L2_loadbsw2_pi(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_pi, true) +#define fGEN_TCG_L2_loadbzw2_pci(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_pci, false) +#define fGEN_TCG_L2_loadbsw2_pci(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_pci, true) +#define fGEN_TCG_L2_loadbzw2_pcr(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_pcr(1), false) +#define fGEN_TCG_L2_loadbsw2_pcr(SHORTCODE) \ + fGEN_TCG_loadbXw2(GET_EA_pcr(1), true) + +/* + * These instructions load 4 bytes and places them in + * four halves of the destination register pair. + * The GET_EA macro determines the addressing mode. + * The SIGN argument determines whether to zero-extend or + * sign-extend. + */ +#define fGEN_TCG_loadbXw4(GET_EA, SIGN) \ + do { \ + TCGv tmp = tcg_temp_new(); \ + TCGv byte = tcg_temp_new(); \ + GET_EA; \ + fLOAD(1, 4, u, EA, tmp); \ + tcg_gen_movi_i64(RddV, 0); \ + for (int i = 0; i < 4; i++) { \ + gen_set_half_i64(i, RddV, gen_get_byte(byte, i, tmp, (SIGN))); \ + } \ + tcg_temp_free(tmp); \ + tcg_temp_free(byte); \ + } while (0) + +#define fGEN_TCG_L2_loadbzw4_io(SHORTCODE) \ + fGEN_TCG_loadbXw4(fEA_RI(RsV, siV), false) +#define fGEN_TCG_L4_loadbzw4_ur(SHORTCODE) \ + fGEN_TCG_loadbXw4(fEA_IRs(UiV, RtV, uiV), false) +#define fGEN_TCG_L2_loadbsw4_io(SHORTCODE) \ + fGEN_TCG_loadbXw4(fEA_RI(RsV, siV), true) +#define fGEN_TCG_L4_loadbsw4_ur(SHORTCODE) \ + fGEN_TCG_loadbXw4(fEA_IRs(UiV, RtV, uiV), true) +#define fGEN_TCG_L2_loadbzw4_pci(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_pci, false) +#define fGEN_TCG_L2_loadbsw4_pci(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_pci, true) +#define fGEN_TCG_L2_loadbzw4_pcr(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_pcr(2), false) +#define fGEN_TCG_L2_loadbsw4_pcr(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_pcr(2), true) +#define fGEN_TCG_L4_loadbzw4_ap(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_ap, false) +#define fGEN_TCG_L2_loadbzw4_pr(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_pr, false) +#define fGEN_TCG_L2_loadbzw4_pbr(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_pbr, false) +#define fGEN_TCG_L2_loadbzw4_pi(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_pi, false) +#define fGEN_TCG_L4_loadbsw4_ap(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_ap, true) +#define fGEN_TCG_L2_loadbsw4_pr(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_pr, true) +#define fGEN_TCG_L2_loadbsw4_pbr(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_pbr, true) +#define fGEN_TCG_L2_loadbsw4_pi(SHORTCODE) \ + fGEN_TCG_loadbXw4(GET_EA_pi, true) + /* * Predicated loads * Here is a primer to understand the tag names diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index c6928d6184..f93f8953ff 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -300,6 +300,19 @@ static inline TCGv gen_get_half(TCGv result, int N, TCGv src, bool sign) return result; } +static inline void gen_set_half(int N, TCGv result, TCGv src) +{ + tcg_gen_deposit_tl(result, result, src, N * 16, 16); +} + +static inline void gen_set_half_i64(int N, TCGv_i64 result, TCGv src) +{ + TCGv_i64 src64 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(src64, src); + tcg_gen_deposit_i64(result, result, src64, N * 16, 16); + tcg_temp_free_i64(src64); +} + static void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src) { TCGv_i64 src64 = tcg_temp_new_i64(); diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index 4464926634..e3582ebb29 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -342,6 +342,12 @@ DEF_ENC32(L4_pload##TAG##fnew_abs,ICLASS_LD" 1 11 "OPC" iiiii PP111tti 1--ddd /* 0 000 misc: dealloc,loadw_locked,dcfetch */ +STD_LD_ENC(bzw4,"0 101") +STD_LD_ENC(bzw2,"0 011") + +STD_LD_ENC(bsw4,"0 111") +STD_LD_ENC(bsw2,"0 001") + STD_LD_ENC(rb, "1 000") STD_LD_ENC(rub, "1 001") STD_LD_ENC(rh, "1 010") diff --git a/target/hexagon/imported/ldst.idef b/target/hexagon/imported/ldst.idef index fe7e018cf1..95c0470757 100644 --- a/target/hexagon/imported/ldst.idef +++ b/target/hexagon/imported/ldst.idef @@ -38,6 +38,49 @@ STD_LD_AMODES(loadrh, "Rd32=memh", "Load signed Half integer",ATTRIBS(A_LOAD),"1 STD_LD_AMODES(loadri, "Rd32=memw", "Load Word",ATTRIBS(A_LOAD),"2",fLOAD(1,4,u,EA,RdV),2) STD_LD_AMODES(loadrd, "Rdd32=memd","Load Double integer",ATTRIBS(A_LOAD),"3",fLOAD(1,8,u,EA,RddV),3) +/* These instructions do a load an unpack */ +STD_LD_AMODES(loadbzw2, "Rd32=memubh", "Load Bytes and Vector Zero-Extend (unpack)", +ATTRIBS(A_LOAD),"1", +{fHIDE(size2u_t tmpV; int i;) + fLOAD(1,2,u,EA,tmpV); + for (i=0;i<2;i++) { + fSETHALF(i,RdV,fGETUBYTE(i,tmpV)); + } +},1) + +STD_LD_AMODES(loadbzw4, "Rdd32=memubh", "Load Bytes and Vector Zero-Extend (unpack)", +ATTRIBS(A_LOAD),"2", +{fHIDE(size4u_t tmpV; int i;) + fLOAD(1,4,u,EA,tmpV); + for (i=0;i<4;i++) { + fSETHALF(i,RddV,fGETUBYTE(i,tmpV)); + } +},2) + + + +/* These instructions do a load an unpack */ +STD_LD_AMODES(loadbsw2, "Rd32=membh", "Load Bytes and Vector Sign-Extend (unpack)", +ATTRIBS(A_LOAD),"1", +{fHIDE(size2u_t tmpV; int i;) + fLOAD(1,2,u,EA,tmpV); + for (i=0;i<2;i++) { + fSETHALF(i,RdV,fGETBYTE(i,tmpV)); + } +},1) + +STD_LD_AMODES(loadbsw4, "Rdd32=membh", "Load Bytes and Vector Sign-Extend (unpack)", +ATTRIBS(A_LOAD),"2", +{fHIDE(size4u_t tmpV; int i;) + fLOAD(1,4,u,EA,tmpV); + for (i=0;i<4;i++) { + fSETHALF(i,RddV,fGETBYTE(i,tmpV)); + } +},2) + + + + /* The set of addressing modes standard to all Store instructions */ #define STD_ST_AMODES(TAG,DEST,OPER,DESCR,ATTRIB,SHFT,SEMANTICS,SCALE)\ Q6INSN(S2_##TAG##_io, OPER"(Rs32+#s11:"SHFT")="DEST, ATTRIB,DESCR,{fIMMEXT(siV); fEA_RI(RsV,siV); SEMANTICS; })\ diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index 30c8951c16..ec5bf60f5e 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -465,6 +465,21 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) #define fCAST8S_16S(A) (int128_exts64(A)) #define fCAST16S_8S(A) (int128_getlo(A)) +#ifdef QEMU_GENERATE +#define fEA_RI(REG, IMM) tcg_gen_addi_tl(EA, REG, IMM) +#define fEA_RRs(REG, REG2, SCALE) \ + do { \ + TCGv tmp = tcg_temp_new(); \ + tcg_gen_shli_tl(tmp, REG2, SCALE); \ + tcg_gen_add_tl(EA, REG, tmp); \ + tcg_temp_free(tmp); \ + } while (0) +#define fEA_IRs(IMM, REG, SCALE) \ + do { \ + tcg_gen_shli_tl(EA, REG, SCALE); \ + tcg_gen_addi_tl(EA, EA, IMM); \ + } while (0) +#else #define fEA_RI(REG, IMM) \ do { \ EA = REG + IMM; \ @@ -477,6 +492,7 @@ static inline TCGv gen_read_ireg(TCGv result, TCGv val, int shift) do { \ EA = IMM + (REG << SCALE); \ } while (0) +#endif #ifdef QEMU_GENERATE #define fEA_IMM(IMM) tcg_gen_movi_tl(EA, IMM) diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index 6e38950d23..183f4e2efe 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -44,6 +44,7 @@ HEX_TESTS += multi_result HEX_TESTS += mem_noshuf HEX_TESTS += circ HEX_TESTS += brev +HEX_TESTS += load_unpack HEX_TESTS += atomics HEX_TESTS += fpstuff diff --git a/tests/tcg/hexagon/load_unpack.c b/tests/tcg/hexagon/load_unpack.c new file mode 100644 index 0000000000..3575a37a28 --- /dev/null +++ b/tests/tcg/hexagon/load_unpack.c @@ -0,0 +1,474 @@ +/* + * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +/* + * Test load unpack instructions + * + * Example + * r0 = memubh(r1+#0) + * loads a half word from memory and zero-extends the 2 bytes to form a word + * + * For each addressing mode, there are 4 tests + * bzw2 unsigned 2 elements + * bsw2 signed 2 elements + * bzw4 unsigned 4 elements + * bsw4 signed 4 elements + * There are 8 addressing modes, for a total of 32 instructions to test + */ + +#include +#include + +int err; + +char buf[16] __attribute__((aligned(1 << 16))); + +void init_buf(void) +{ + int i; + for (i = 0; i < 16; i++) { + int sign = i % 2 == 0 ? 0x80 : 0; + buf[i] = sign | (i + 1); + } +} + +void __check(int line, long long result, long long expect) +{ + if (result != expect) { + printf("ERROR at line %d: 0x%08llx != 0x%08llx\n", + line, result, expect); + err++; + } +} + +#define check(RES, EXP) __check(__LINE__, RES, EXP) + +void __checkp(int line, void *p, void *expect) +{ + if (p != expect) { + printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect); + err++; + } +} + +#define checkp(RES, EXP) __checkp(__LINE__, RES, EXP) + +/* + **************************************************************************** + * _io addressing mode (addr + offset) + */ +#define BxW_LOAD_io(SZ, RES, ADDR, OFF) \ + __asm__( \ + "%0 = mem" #SZ "(%1+#" #OFF ")\n\t" \ + : "=r"(RES) \ + : "r"(ADDR)) +#define BxW_LOAD_io_Z(RES, ADDR, OFF) \ + BxW_LOAD_io(ubh, RES, ADDR, OFF) +#define BxW_LOAD_io_S(RES, ADDR, OFF) \ + BxW_LOAD_io(bh, RES, ADDR, OFF) + +#define TEST_io(NAME, TYPE, SIGN, SIZE, EXT, EXP1, EXP2, EXP3, EXP4) \ +void test_##NAME(void) \ +{ \ + TYPE result; \ + init_buf(); \ + BxW_LOAD_io_##SIGN(result, buf, 0 * (SIZE)); \ + check(result, (EXP1) | (EXT)); \ + BxW_LOAD_io_##SIGN(result, buf, 1 * (SIZE)); \ + check(result, (EXP2) | (EXT)); \ + BxW_LOAD_io_##SIGN(result, buf, 2 * (SIZE)); \ + check(result, (EXP3) | (EXT)); \ + BxW_LOAD_io_##SIGN(result, buf, 3 * (SIZE)); \ + check(result, (EXP4) | (EXT)); \ +} + + +TEST_io(loadbzw2_io, int, Z, 2, 0x00000000, + 0x00020081, 0x00040083, 0x00060085, 0x00080087) +TEST_io(loadbsw2_io, int, S, 2, 0x0000ff00, + 0x00020081, 0x00040083, 0x00060085, 0x00080087) +TEST_io(loadbzw4_io, long long, Z, 4, 0x0000000000000000LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x000c008b000a0089LL, 0x0010008f000e008dLL) +TEST_io(loadbsw4_io, long long, S, 4, 0x0000ff000000ff00LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x000c008b000a0089LL, 0x0010008f000e008dLL) + +/* + **************************************************************************** + * _ur addressing mode (index << offset + base) + */ +#define BxW_LOAD_ur(SZ, RES, SHIFT, IDX) \ + __asm__( \ + "%0 = mem" #SZ "(%1<<#" #SHIFT " + ##buf)\n\t" \ + : "=r"(RES) \ + : "r"(IDX)) +#define BxW_LOAD_ur_Z(RES, SHIFT, IDX) \ + BxW_LOAD_ur(ubh, RES, SHIFT, IDX) +#define BxW_LOAD_ur_S(RES, SHIFT, IDX) \ + BxW_LOAD_ur(bh, RES, SHIFT, IDX) + +#define TEST_ur(NAME, TYPE, SIGN, SHIFT, EXT, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + TYPE result; \ + init_buf(); \ + BxW_LOAD_ur_##SIGN(result, (SHIFT), 0); \ + check(result, (RES1) | (EXT)); \ + BxW_LOAD_ur_##SIGN(result, (SHIFT), 1); \ + check(result, (RES2) | (EXT)); \ + BxW_LOAD_ur_##SIGN(result, (SHIFT), 2); \ + check(result, (RES3) | (EXT)); \ + BxW_LOAD_ur_##SIGN(result, (SHIFT), 3); \ + check(result, (RES4) | (EXT)); \ +} \ + +TEST_ur(loadbzw2_ur, int, Z, 1, 0x00000000, + 0x00020081, 0x00040083, 0x00060085, 0x00080087) +TEST_ur(loadbsw2_ur, int, S, 1, 0x0000ff00, + 0x00020081, 0x00040083, 0x00060085, 0x00080087) +TEST_ur(loadbzw4_ur, long long, Z, 2, 0x0000000000000000LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x000c008b000a0089LL, 0x0010008f000e008dLL) +TEST_ur(loadbsw4_ur, long long, S, 2, 0x0000ff000000ff00LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x000c008b000a0089LL, 0x0010008f000e008dLL) + +/* + **************************************************************************** + * _ap addressing mode (addr = base) + */ +#define BxW_LOAD_ap(SZ, RES, PTR, ADDR) \ + __asm__( \ + "%0 = mem" #SZ "(%1 = ##" #ADDR ")\n\t" \ + : "=r"(RES), "=r"(PTR)) +#define BxW_LOAD_ap_Z(RES, PTR, ADDR) \ + BxW_LOAD_ap(ubh, RES, PTR, ADDR) +#define BxW_LOAD_ap_S(RES, PTR, ADDR) \ + BxW_LOAD_ap(bh, RES, PTR, ADDR) + +#define TEST_ap(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + TYPE result; \ + void *ptr; \ + init_buf(); \ + BxW_LOAD_ap_##SIGN(result, ptr, (buf + 0 * (SIZE))); \ + check(result, (RES1) | (EXT)); \ + checkp(ptr, &buf[0 * (SIZE)]); \ + BxW_LOAD_ap_##SIGN(result, ptr, (buf + 1 * (SIZE))); \ + check(result, (RES2) | (EXT)); \ + checkp(ptr, &buf[1 * (SIZE)]); \ + BxW_LOAD_ap_##SIGN(result, ptr, (buf + 2 * (SIZE))); \ + check(result, (RES3) | (EXT)); \ + checkp(ptr, &buf[2 * (SIZE)]); \ + BxW_LOAD_ap_##SIGN(result, ptr, (buf + 3 * (SIZE))); \ + check(result, (RES4) | (EXT)); \ + checkp(ptr, &buf[3 * (SIZE)]); \ +} + +TEST_ap(loadbzw2_ap, int, Z, 2, 0x00000000, + 0x00020081, 0x00040083, 0x00060085, 0x00080087) +TEST_ap(loadbsw2_ap, int, S, 2, 0x0000ff00, + 0x00020081, 0x00040083, 0x00060085, 0x00080087) +TEST_ap(loadbzw4_ap, long long, Z, 4, 0x0000000000000000LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x000c008b000a0089LL, 0x0010008f000e008dLL) +TEST_ap(loadbsw4_ap, long long, S, 4, 0x0000ff000000ff00LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x000c008b000a0089LL, 0x0010008f000e008dLL) + +/* + **************************************************************************** + * _rp addressing mode (addr ++ modifer-reg) + */ +#define BxW_LOAD_pr(SZ, RES, PTR, INC) \ + __asm__( \ + "m0 = %2\n\t" \ + "%0 = mem" #SZ "(%1++m0)\n\t" \ + : "=r"(RES), "+r"(PTR) \ + : "r"(INC) \ + : "m0") +#define BxW_LOAD_pr_Z(RES, PTR, INC) \ + BxW_LOAD_pr(ubh, RES, PTR, INC) +#define BxW_LOAD_pr_S(RES, PTR, INC) \ + BxW_LOAD_pr(bh, RES, PTR, INC) + +#define TEST_pr(NAME, TYPE, SIGN, SIZE, EXT, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + TYPE result; \ + void *ptr = buf; \ + init_buf(); \ + BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ + check(result, (RES1) | (EXT)); \ + checkp(ptr, &buf[1 * (SIZE)]); \ + BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ + check(result, (RES2) | (EXT)); \ + checkp(ptr, &buf[2 * (SIZE)]); \ + BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ + check(result, (RES3) | (EXT)); \ + checkp(ptr, &buf[3 * (SIZE)]); \ + BxW_LOAD_pr_##SIGN(result, ptr, (SIZE)); \ + check(result, (RES4) | (EXT)); \ + checkp(ptr, &buf[4 * (SIZE)]); \ +} + +TEST_pr(loadbzw2_pr, int, Z, 2, 0x00000000, + 0x00020081, 0x0040083, 0x00060085, 0x00080087) +TEST_pr(loadbsw2_pr, int, S, 2, 0x0000ff00, + 0x00020081, 0x0040083, 0x00060085, 0x00080087) +TEST_pr(loadbzw4_pr, long long, Z, 4, 0x0000000000000000LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x000c008b000a0089LL, 0x0010008f000e008dLL) +TEST_pr(loadbsw4_pr, long long, S, 4, 0x0000ff000000ff00LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x000c008b000a0089LL, 0x0010008f000e008dLL) + +/* + **************************************************************************** + * _pbr addressing mode (addr ++ modifer-reg:brev) + */ +#define BxW_LOAD_pbr(SZ, RES, PTR) \ + __asm__( \ + "r4 = #(1 << (16 - 3))\n\t" \ + "m0 = r4\n\t" \ + "%0 = mem" #SZ "(%1++m0:brev)\n\t" \ + : "=r"(RES), "+r"(PTR) \ + : \ + : "r4", "m0") +#define BxW_LOAD_pbr_Z(RES, PTR) \ + BxW_LOAD_pbr(ubh, RES, PTR) +#define BxW_LOAD_pbr_S(RES, PTR) \ + BxW_LOAD_pbr(bh, RES, PTR) + +#define TEST_pbr(NAME, TYPE, SIGN, EXT, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + TYPE result; \ + void *ptr = buf; \ + init_buf(); \ + BxW_LOAD_pbr_##SIGN(result, ptr); \ + check(result, (RES1) | (EXT)); \ + BxW_LOAD_pbr_##SIGN(result, ptr); \ + check(result, (RES2) | (EXT)); \ + BxW_LOAD_pbr_##SIGN(result, ptr); \ + check(result, (RES3) | (EXT)); \ + BxW_LOAD_pbr_##SIGN(result, ptr); \ + check(result, (RES4) | (EXT)); \ +} + +TEST_pbr(loadbzw2_pbr, int, Z, 0x00000000, + 0x00020081, 0x00060085, 0x00040083, 0x00080087) +TEST_pbr(loadbsw2_pbr, int, S, 0x0000ff00, + 0x00020081, 0x00060085, 0x00040083, 0x00080087) +TEST_pbr(loadbzw4_pbr, long long, Z, 0x0000000000000000LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x0006008500040083LL, 0x000a008900080087LL) +TEST_pbr(loadbsw4_pbr, long long, S, 0x0000ff000000ff00LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x0006008500040083LL, 0x000a008900080087LL) + +/* + **************************************************************************** + * _pi addressing mode (addr ++ inc) + */ +#define BxW_LOAD_pi(SZ, RES, PTR, INC) \ + __asm__( \ + "%0 = mem" #SZ "(%1++#" #INC ")\n\t" \ + : "=r"(RES), "+r"(PTR)) +#define BxW_LOAD_pi_Z(RES, PTR, INC) \ + BxW_LOAD_pi(ubh, RES, PTR, INC) +#define BxW_LOAD_pi_S(RES, PTR, INC) \ + BxW_LOAD_pi(bh, RES, PTR, INC) + +#define TEST_pi(NAME, TYPE, SIGN, INC, EXT, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + TYPE result; \ + void *ptr = buf; \ + init_buf(); \ + BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ + check(result, (RES1) | (EXT)); \ + checkp(ptr, &buf[1 * (INC)]); \ + BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ + check(result, (RES2) | (EXT)); \ + checkp(ptr, &buf[2 * (INC)]); \ + BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ + check(result, (RES3) | (EXT)); \ + checkp(ptr, &buf[3 * (INC)]); \ + BxW_LOAD_pi_##SIGN(result, ptr, (INC)); \ + check(result, (RES4) | (EXT)); \ + checkp(ptr, &buf[4 * (INC)]); \ +} + +TEST_pi(loadbzw2_pi, int, Z, 2, 0x00000000, + 0x00020081, 0x00040083, 0x00060085, 0x00080087) +TEST_pi(loadbsw2_pi, int, S, 2, 0x0000ff00, + 0x00020081, 0x00040083, 0x00060085, 0x00080087) +TEST_pi(loadbzw4_pi, long long, Z, 4, 0x0000000000000000LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x000c008b000a0089LL, 0x0010008f000e008dLL) +TEST_pi(loadbsw4_pi, long long, S, 4, 0x0000ff000000ff00LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x000c008b000a0089LL, 0x0010008f000e008dLL) + +/* + **************************************************************************** + * _pci addressing mode (addr ++ inc:circ) + */ +#define BxW_LOAD_pci(SZ, RES, PTR, START, LEN, INC) \ + __asm__( \ + "r4 = %3\n\t" \ + "m0 = r4\n\t" \ + "cs0 = %2\n\t" \ + "%0 = mem" #SZ "(%1++#" #INC ":circ(m0))\n\t" \ + : "=r"(RES), "+r"(PTR) \ + : "r"(START), "r"(LEN) \ + : "r4", "m0", "cs0") +#define BxW_LOAD_pci_Z(RES, PTR, START, LEN, INC) \ + BxW_LOAD_pci(ubh, RES, PTR, START, LEN, INC) +#define BxW_LOAD_pci_S(RES, PTR, START, LEN, INC) \ + BxW_LOAD_pci(bh, RES, PTR, START, LEN, INC) + +#define TEST_pci(NAME, TYPE, SIGN, LEN, INC, EXT, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + TYPE result; \ + void *ptr = buf; \ + init_buf(); \ + BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES1) | (EXT)); \ + checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \ + BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES2) | (EXT)); \ + checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \ + BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES3) | (EXT)); \ + checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \ + BxW_LOAD_pci_##SIGN(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES4) | (EXT)); \ + checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \ +} + +TEST_pci(loadbzw2_pci, int, Z, 6, 2, 0x00000000, + 0x00020081, 0x00040083, 0x00060085, 0x00020081) +TEST_pci(loadbsw2_pci, int, S, 6, 2, 0x0000ff00, + 0x00020081, 0x00040083, 0x00060085, 0x00020081) +TEST_pci(loadbzw4_pci, long long, Z, 8, 4, 0x0000000000000000LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x0004008300020081LL, 0x0008008700060085LL) +TEST_pci(loadbsw4_pci, long long, S, 8, 4, 0x0000ff000000ff00LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x0004008300020081LL, 0x0008008700060085LL) + +/* + **************************************************************************** + * _pcr addressing mode (addr ++ I:circ(modifier-reg)) + */ +#define BxW_LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \ + __asm__( \ + "r4 = %2\n\t" \ + "m1 = r4\n\t" \ + "cs1 = %3\n\t" \ + "%0 = mem" #SZ "(%1++I:circ(m1))\n\t" \ + : "=r"(RES), "+r"(PTR) \ + : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \ + "r"(START) \ + : "r4", "m1", "cs1") +#define BxW_LOAD_pcr_Z(RES, PTR, START, LEN, INC) \ + BxW_LOAD_pcr(ubh, RES, PTR, START, LEN, INC) +#define BxW_LOAD_pcr_S(RES, PTR, START, LEN, INC) \ + BxW_LOAD_pcr(bh, RES, PTR, START, LEN, INC) + +#define TEST_pcr(NAME, TYPE, SIGN, SIZE, LEN, INC, \ + EXT, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + TYPE result; \ + void *ptr = buf; \ + init_buf(); \ + BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES1) | (EXT)); \ + checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \ + BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES2) | (EXT)); \ + checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \ + BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES3) | (EXT)); \ + checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \ + BxW_LOAD_pcr_##SIGN(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES4) | (EXT)); \ + checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \ +} + +TEST_pcr(loadbzw2_pcr, int, Z, 2, 8, 2, 0x00000000, + 0x00020081, 0x00060085, 0x00020081, 0x00060085) +TEST_pcr(loadbsw2_pcr, int, S, 2, 8, 2, 0x0000ff00, + 0x00020081, 0x00060085, 0x00020081, 0x00060085) +TEST_pcr(loadbzw4_pcr, long long, Z, 4, 8, 1, 0x0000000000000000LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x0004008300020081LL, 0x0008008700060085LL) +TEST_pcr(loadbsw4_pcr, long long, S, 4, 8, 1, 0x0000ff000000ff00LL, + 0x0004008300020081LL, 0x0008008700060085LL, + 0x0004008300020081LL, 0x0008008700060085LL) + +int main() +{ + test_loadbzw2_io(); + test_loadbsw2_io(); + test_loadbzw4_io(); + test_loadbsw4_io(); + + test_loadbzw2_ur(); + test_loadbsw2_ur(); + test_loadbzw4_ur(); + test_loadbsw4_ur(); + + test_loadbzw2_ap(); + test_loadbsw2_ap(); + test_loadbzw4_ap(); + test_loadbsw4_ap(); + + test_loadbzw2_pr(); + test_loadbsw2_pr(); + test_loadbzw4_pr(); + test_loadbsw4_pr(); + + test_loadbzw2_pbr(); + test_loadbsw2_pbr(); + test_loadbzw4_pbr(); + test_loadbsw4_pbr(); + + test_loadbzw2_pi(); + test_loadbsw2_pi(); + test_loadbzw4_pi(); + test_loadbsw4_pi(); + + test_loadbzw2_pci(); + test_loadbsw2_pci(); + test_loadbzw4_pci(); + test_loadbsw4_pci(); + + test_loadbzw2_pcr(); + test_loadbsw2_pcr(); + test_loadbzw4_pcr(); + test_loadbsw4_pcr(); + + puts(err ? "FAIL" : "PASS"); + return err ? 1 : 0; +} From 7aa9ffab79eb2f3ba998333e3709c7b8dbc630f1 Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:53 -0500 Subject: [PATCH 0171/3028] Hexagon (target/hexagon) load into shifted register instructions The following instructions are added L2_loadalignb_io Ryy32 = memb_fifo(Rs32+#s11:1) L2_loadalignh_io Ryy32 = memh_fifo(Rs32+#s11:1) L4_loadalignb_ur Ryy32 = memb_fifo(Rt32<<#u2+#U6) L4_loadalignh_ur Ryy32 = memh_fifo(Rt32<<#u2+#U6) L4_loadalignb_ap Ryy32 = memb_fifo(Re32=#U6) L4_loadalignh_ap Ryy32 = memh_fifo(Re32=#U6) L2_loadalignb_pr Ryy32 = memb_fifo(Rx32++Mu2) L2_loadalignh_pr Ryy32 = memh_fifo(Rx32++Mu2) L2_loadalignb_pbr Ryy32 = memb_fifo(Rx32++Mu2:brev) L2_loadalignh_pbr Ryy32 = memh_fifo(Rx32++Mu2:brev) L2_loadalignb_pi Ryy32 = memb_fifo(Rx32++#s4:1) L2_loadalignh_pi Ryy32 = memh_fifo(Rx32++#s4:1) L2_loadalignb_pci Ryy32 = memb_fifo(Rx32++#s4:1:circ(Mu2)) L2_loadalignh_pci Ryy32 = memh_fifo(Rx32++#s4:1:circ(Mu2)) L2_loadalignb_pcr Ryy32 = memb_fifo(Rx32++I:circ(Mu2)) L2_loadalignh_pcr Ryy32 = memh_fifo(Rx32++I:circ(Mu2)) Test cases in tests/tcg/hexagon/load_align.c Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-26-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/gen_tcg.h | 66 ++++ target/hexagon/imported/encode_pp.def | 3 + target/hexagon/imported/ldst.idef | 19 ++ tests/tcg/hexagon/Makefile.target | 1 + tests/tcg/hexagon/load_align.c | 415 ++++++++++++++++++++++++++ 5 files changed, 504 insertions(+) create mode 100644 tests/tcg/hexagon/load_align.c diff --git a/target/hexagon/gen_tcg.h b/target/hexagon/gen_tcg.h index 1120aaed4e..18fcdbc7e4 100644 --- a/target/hexagon/gen_tcg.h +++ b/target/hexagon/gen_tcg.h @@ -260,6 +260,72 @@ #define fGEN_TCG_L2_loadbsw4_pi(SHORTCODE) \ fGEN_TCG_loadbXw4(GET_EA_pi, true) +/* + * These instructions load a half word, shift the destination right by 16 bits + * and place the loaded value in the high half word of the destination pair. + * The GET_EA macro determines the addressing mode. + */ +#define fGEN_TCG_loadalignh(GET_EA) \ + do { \ + TCGv tmp = tcg_temp_new(); \ + TCGv_i64 tmp_i64 = tcg_temp_new_i64(); \ + GET_EA; \ + fLOAD(1, 2, u, EA, tmp); \ + tcg_gen_extu_i32_i64(tmp_i64, tmp); \ + tcg_gen_shri_i64(RyyV, RyyV, 16); \ + tcg_gen_deposit_i64(RyyV, RyyV, tmp_i64, 48, 16); \ + tcg_temp_free(tmp); \ + tcg_temp_free_i64(tmp_i64); \ + } while (0) + +#define fGEN_TCG_L4_loadalignh_ur(SHORTCODE) \ + fGEN_TCG_loadalignh(fEA_IRs(UiV, RtV, uiV)) +#define fGEN_TCG_L2_loadalignh_io(SHORTCODE) \ + fGEN_TCG_loadalignh(fEA_RI(RsV, siV)) +#define fGEN_TCG_L2_loadalignh_pci(SHORTCODE) \ + fGEN_TCG_loadalignh(GET_EA_pci) +#define fGEN_TCG_L2_loadalignh_pcr(SHORTCODE) \ + fGEN_TCG_loadalignh(GET_EA_pcr(1)) +#define fGEN_TCG_L4_loadalignh_ap(SHORTCODE) \ + fGEN_TCG_loadalignh(GET_EA_ap) +#define fGEN_TCG_L2_loadalignh_pr(SHORTCODE) \ + fGEN_TCG_loadalignh(GET_EA_pr) +#define fGEN_TCG_L2_loadalignh_pbr(SHORTCODE) \ + fGEN_TCG_loadalignh(GET_EA_pbr) +#define fGEN_TCG_L2_loadalignh_pi(SHORTCODE) \ + fGEN_TCG_loadalignh(GET_EA_pi) + +/* Same as above, but loads a byte instead of half word */ +#define fGEN_TCG_loadalignb(GET_EA) \ + do { \ + TCGv tmp = tcg_temp_new(); \ + TCGv_i64 tmp_i64 = tcg_temp_new_i64(); \ + GET_EA; \ + fLOAD(1, 1, u, EA, tmp); \ + tcg_gen_extu_i32_i64(tmp_i64, tmp); \ + tcg_gen_shri_i64(RyyV, RyyV, 8); \ + tcg_gen_deposit_i64(RyyV, RyyV, tmp_i64, 56, 8); \ + tcg_temp_free(tmp); \ + tcg_temp_free_i64(tmp_i64); \ + } while (0) + +#define fGEN_TCG_L2_loadalignb_io(SHORTCODE) \ + fGEN_TCG_loadalignb(fEA_RI(RsV, siV)) +#define fGEN_TCG_L4_loadalignb_ur(SHORTCODE) \ + fGEN_TCG_loadalignb(fEA_IRs(UiV, RtV, uiV)) +#define fGEN_TCG_L2_loadalignb_pci(SHORTCODE) \ + fGEN_TCG_loadalignb(GET_EA_pci) +#define fGEN_TCG_L2_loadalignb_pcr(SHORTCODE) \ + fGEN_TCG_loadalignb(GET_EA_pcr(0)) +#define fGEN_TCG_L4_loadalignb_ap(SHORTCODE) \ + fGEN_TCG_loadalignb(GET_EA_ap) +#define fGEN_TCG_L2_loadalignb_pr(SHORTCODE) \ + fGEN_TCG_loadalignb(GET_EA_pr) +#define fGEN_TCG_L2_loadalignb_pbr(SHORTCODE) \ + fGEN_TCG_loadalignb(GET_EA_pbr) +#define fGEN_TCG_L2_loadalignb_pi(SHORTCODE) \ + fGEN_TCG_loadalignb(GET_EA_pi) + /* * Predicated loads * Here is a primer to understand the tag names diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index e3582ebb29..dc4eba4f68 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -348,6 +348,9 @@ STD_LD_ENC(bzw2,"0 011") STD_LD_ENC(bsw4,"0 111") STD_LD_ENC(bsw2,"0 001") +STD_LDX_ENC(alignh,"0 010") +STD_LDX_ENC(alignb,"0 100") + STD_LD_ENC(rb, "1 000") STD_LD_ENC(rub, "1 001") STD_LD_ENC(rh, "1 010") diff --git a/target/hexagon/imported/ldst.idef b/target/hexagon/imported/ldst.idef index 95c0470757..359d3b744e 100644 --- a/target/hexagon/imported/ldst.idef +++ b/target/hexagon/imported/ldst.idef @@ -80,6 +80,25 @@ ATTRIBS(A_LOAD),"2", +STD_LD_AMODES(loadalignh, "Ryy32=memh_fifo", "Load Half-word into shifted vector", +ATTRIBS(A_LOAD),"1", +{ + fHIDE(size8u_t tmpV;) + fLOAD(1,2,u,EA,tmpV); + RyyV = (((size8u_t)RyyV)>>16)|(tmpV<<48); +},1) + + +STD_LD_AMODES(loadalignb, "Ryy32=memb_fifo", "Load byte into shifted vector", +ATTRIBS(A_LOAD),"0", +{ + fHIDE(size8u_t tmpV;) + fLOAD(1,1,u,EA,tmpV); + RyyV = (((size8u_t)RyyV)>>8)|(tmpV<<56); +},0) + + + /* The set of addressing modes standard to all Store instructions */ #define STD_ST_AMODES(TAG,DEST,OPER,DESCR,ATTRIB,SHFT,SEMANTICS,SCALE)\ diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target index 183f4e2efe..0992787d50 100644 --- a/tests/tcg/hexagon/Makefile.target +++ b/tests/tcg/hexagon/Makefile.target @@ -45,6 +45,7 @@ HEX_TESTS += mem_noshuf HEX_TESTS += circ HEX_TESTS += brev HEX_TESTS += load_unpack +HEX_TESTS += load_align HEX_TESTS += atomics HEX_TESTS += fpstuff diff --git a/tests/tcg/hexagon/load_align.c b/tests/tcg/hexagon/load_align.c new file mode 100644 index 0000000000..12fc9cbd8f --- /dev/null +++ b/tests/tcg/hexagon/load_align.c @@ -0,0 +1,415 @@ +/* + * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +/* + * Test load align instructions + * + * Example + * r1:0 = memh_fifo(r1+#0) + * loads a half word from memory, shifts the destination register + * right by one half word and inserts the loaded value into the high + * half word of the destination. + * + * There are 8 addressing modes and byte and half word variants, for a + * total of 16 instructions to test + */ + +#include +#include + +int err; + +char buf[16] __attribute__((aligned(1 << 16))); + +void init_buf(void) +{ + int i; + for (i = 0; i < 16; i++) { + buf[i] = i + 1; + } +} + +void __check(int line, long long result, long long expect) +{ + if (result != expect) { + printf("ERROR at line %d: 0x%016llx != 0x%016llx\n", + line, result, expect); + err++; + } +} + +#define check(RES, EXP) __check(__LINE__, RES, EXP) + +void __checkp(int line, void *p, void *expect) +{ + if (p != expect) { + printf("ERROR at line %d: 0x%p != 0x%p\n", line, p, expect); + err++; + } +} + +#define checkp(RES, EXP) __checkp(__LINE__, RES, EXP) + +/* + **************************************************************************** + * _io addressing mode (addr + offset) + */ +#define LOAD_io(SZ, RES, ADDR, OFF) \ + __asm__( \ + "%0 = mem" #SZ "_fifo(%1+#" #OFF ")\n\t" \ + : "+r"(RES) \ + : "r"(ADDR)) +#define LOAD_io_b(RES, ADDR, OFF) \ + LOAD_io(b, RES, ADDR, OFF) +#define LOAD_io_h(RES, ADDR, OFF) \ + LOAD_io(h, RES, ADDR, OFF) + +#define TEST_io(NAME, SZ, SIZE, EXP1, EXP2, EXP3, EXP4) \ +void test_##NAME(void) \ +{ \ + long long result = ~0LL; \ + LOAD_io_##SZ(result, buf, 0 * (SIZE)); \ + check(result, (EXP1)); \ + LOAD_io_##SZ(result, buf, 1 * (SIZE)); \ + check(result, (EXP2)); \ + LOAD_io_##SZ(result, buf, 2 * (SIZE)); \ + check(result, (EXP3)); \ + LOAD_io_##SZ(result, buf, 3 * (SIZE)); \ + check(result, (EXP4)); \ +} + +TEST_io(loadalignb_io, b, 1, + 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, + 0x030201ffffffffffLL, 0x04030201ffffffffLL) +TEST_io(loadalignh_io, h, 2, + 0x0201ffffffffffffLL, 0x04030201ffffffffLL, + 0x060504030201ffffLL, 0x0807060504030201LL) + +/* + **************************************************************************** + * _ur addressing mode (index << offset + base) + */ +#define LOAD_ur(SZ, RES, SHIFT, IDX) \ + __asm__( \ + "%0 = mem" #SZ "_fifo(%1<<#" #SHIFT " + ##buf)\n\t" \ + : "+r"(RES) \ + : "r"(IDX)) +#define LOAD_ur_b(RES, SHIFT, IDX) \ + LOAD_ur(b, RES, SHIFT, IDX) +#define LOAD_ur_h(RES, SHIFT, IDX) \ + LOAD_ur(h, RES, SHIFT, IDX) + +#define TEST_ur(NAME, SZ, SHIFT, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + long long result = ~0LL; \ + LOAD_ur_##SZ(result, (SHIFT), 0); \ + check(result, (RES1)); \ + LOAD_ur_##SZ(result, (SHIFT), 1); \ + check(result, (RES2)); \ + LOAD_ur_##SZ(result, (SHIFT), 2); \ + check(result, (RES3)); \ + LOAD_ur_##SZ(result, (SHIFT), 3); \ + check(result, (RES4)); \ +} + +TEST_ur(loadalignb_ur, b, 1, + 0x01ffffffffffffffLL, 0x0301ffffffffffffLL, + 0x050301ffffffffffLL, 0x07050301ffffffffLL) +TEST_ur(loadalignh_ur, h, 1, + 0x0201ffffffffffffLL, 0x04030201ffffffffLL, + 0x060504030201ffffLL, 0x0807060504030201LL) + +/* + **************************************************************************** + * _ap addressing mode (addr = base) + */ +#define LOAD_ap(SZ, RES, PTR, ADDR) \ + __asm__( \ + "%0 = mem" #SZ "_fifo(%1 = ##" #ADDR ")\n\t" \ + : "+r"(RES), "=r"(PTR)) +#define LOAD_ap_b(RES, PTR, ADDR) \ + LOAD_ap(b, RES, PTR, ADDR) +#define LOAD_ap_h(RES, PTR, ADDR) \ + LOAD_ap(h, RES, PTR, ADDR) + +#define TEST_ap(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + long long result = ~0LL; \ + void *ptr; \ + LOAD_ap_##SZ(result, ptr, (buf + 0 * (SIZE))); \ + check(result, (RES1)); \ + checkp(ptr, &buf[0 * (SIZE)]); \ + LOAD_ap_##SZ(result, ptr, (buf + 1 * (SIZE))); \ + check(result, (RES2)); \ + checkp(ptr, &buf[1 * (SIZE)]); \ + LOAD_ap_##SZ(result, ptr, (buf + 2 * (SIZE))); \ + check(result, (RES3)); \ + checkp(ptr, &buf[2 * (SIZE)]); \ + LOAD_ap_##SZ(result, ptr, (buf + 3 * (SIZE))); \ + check(result, (RES4)); \ + checkp(ptr, &buf[3 * (SIZE)]); \ +} + +TEST_ap(loadalignb_ap, b, 1, + 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, + 0x030201ffffffffffLL, 0x04030201ffffffffLL) +TEST_ap(loadalignh_ap, h, 2, + 0x0201ffffffffffffLL, 0x04030201ffffffffLL, + 0x060504030201ffffLL, 0x0807060504030201LL) + +/* + **************************************************************************** + * _rp addressing mode (addr ++ modifer-reg) + */ +#define LOAD_pr(SZ, RES, PTR, INC) \ + __asm__( \ + "m0 = %2\n\t" \ + "%0 = mem" #SZ "_fifo(%1++m0)\n\t" \ + : "+r"(RES), "+r"(PTR) \ + : "r"(INC) \ + : "m0") +#define LOAD_pr_b(RES, PTR, INC) \ + LOAD_pr(b, RES, PTR, INC) +#define LOAD_pr_h(RES, PTR, INC) \ + LOAD_pr(h, RES, PTR, INC) + +#define TEST_pr(NAME, SZ, SIZE, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + long long result = ~0LL; \ + void *ptr = buf; \ + LOAD_pr_##SZ(result, ptr, (SIZE)); \ + check(result, (RES1)); \ + checkp(ptr, &buf[1 * (SIZE)]); \ + LOAD_pr_##SZ(result, ptr, (SIZE)); \ + check(result, (RES2)); \ + checkp(ptr, &buf[2 * (SIZE)]); \ + LOAD_pr_##SZ(result, ptr, (SIZE)); \ + check(result, (RES3)); \ + checkp(ptr, &buf[3 * (SIZE)]); \ + LOAD_pr_##SZ(result, ptr, (SIZE)); \ + check(result, (RES4)); \ + checkp(ptr, &buf[4 * (SIZE)]); \ +} + +TEST_pr(loadalignb_pr, b, 1, + 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, + 0x030201ffffffffffLL, 0x04030201ffffffffLL) +TEST_pr(loadalignh_pr, h, 2, + 0x0201ffffffffffffLL, 0x04030201ffffffffLL, + 0x060504030201ffffLL, 0x0807060504030201LL) + +/* + **************************************************************************** + * _pbr addressing mode (addr ++ modifer-reg:brev) + */ +#define LOAD_pbr(SZ, RES, PTR) \ + __asm__( \ + "r4 = #(1 << (16 - 3))\n\t" \ + "m0 = r4\n\t" \ + "%0 = mem" #SZ "_fifo(%1++m0:brev)\n\t" \ + : "+r"(RES), "+r"(PTR) \ + : \ + : "r4", "m0") +#define LOAD_pbr_b(RES, PTR) \ + LOAD_pbr(b, RES, PTR) +#define LOAD_pbr_h(RES, PTR) \ + LOAD_pbr(h, RES, PTR) + +#define TEST_pbr(NAME, SZ, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + long long result = ~0LL; \ + void *ptr = buf; \ + LOAD_pbr_##SZ(result, ptr); \ + check(result, (RES1)); \ + LOAD_pbr_##SZ(result, ptr); \ + check(result, (RES2)); \ + LOAD_pbr_##SZ(result, ptr); \ + check(result, (RES3)); \ + LOAD_pbr_##SZ(result, ptr); \ + check(result, (RES4)); \ +} + +TEST_pbr(loadalignb_pbr, b, + 0x01ffffffffffffffLL, 0x0501ffffffffffffLL, + 0x030501ffffffffffLL, 0x07030501ffffffffLL) +TEST_pbr(loadalignh_pbr, h, + 0x0201ffffffffffffLL, 0x06050201ffffffffLL, + 0x040306050201ffffLL, 0x0807040306050201LL) + +/* + **************************************************************************** + * _pi addressing mode (addr ++ inc) + */ +#define LOAD_pi(SZ, RES, PTR, INC) \ + __asm__( \ + "%0 = mem" #SZ "_fifo(%1++#" #INC ")\n\t" \ + : "+r"(RES), "+r"(PTR)) +#define LOAD_pi_b(RES, PTR, INC) \ + LOAD_pi(b, RES, PTR, INC) +#define LOAD_pi_h(RES, PTR, INC) \ + LOAD_pi(h, RES, PTR, INC) + +#define TEST_pi(NAME, SZ, INC, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + long long result = ~0LL; \ + void *ptr = buf; \ + LOAD_pi_##SZ(result, ptr, (INC)); \ + check(result, (RES1)); \ + checkp(ptr, &buf[1 * (INC)]); \ + LOAD_pi_##SZ(result, ptr, (INC)); \ + check(result, (RES2)); \ + checkp(ptr, &buf[2 * (INC)]); \ + LOAD_pi_##SZ(result, ptr, (INC)); \ + check(result, (RES3)); \ + checkp(ptr, &buf[3 * (INC)]); \ + LOAD_pi_##SZ(result, ptr, (INC)); \ + check(result, (RES4)); \ + checkp(ptr, &buf[4 * (INC)]); \ +} + +TEST_pi(loadalignb_pi, b, 1, + 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, + 0x030201ffffffffffLL, 0x04030201ffffffffLL) +TEST_pi(loadalignh_pi, h, 2, + 0x0201ffffffffffffLL, 0x04030201ffffffffLL, + 0x060504030201ffffLL, 0x0807060504030201LL) + +/* + **************************************************************************** + * _pci addressing mode (addr ++ inc:circ) + */ +#define LOAD_pci(SZ, RES, PTR, START, LEN, INC) \ + __asm__( \ + "r4 = %3\n\t" \ + "m0 = r4\n\t" \ + "cs0 = %2\n\t" \ + "%0 = mem" #SZ "_fifo(%1++#" #INC ":circ(m0))\n\t" \ + : "+r"(RES), "+r"(PTR) \ + : "r"(START), "r"(LEN) \ + : "r4", "m0", "cs0") +#define LOAD_pci_b(RES, PTR, START, LEN, INC) \ + LOAD_pci(b, RES, PTR, START, LEN, INC) +#define LOAD_pci_h(RES, PTR, START, LEN, INC) \ + LOAD_pci(h, RES, PTR, START, LEN, INC) + +#define TEST_pci(NAME, SZ, LEN, INC, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + long long result = ~0LL; \ + void *ptr = buf; \ + LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES1)); \ + checkp(ptr, &buf[(1 * (INC)) % (LEN)]); \ + LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES2)); \ + checkp(ptr, &buf[(2 * (INC)) % (LEN)]); \ + LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES3)); \ + checkp(ptr, &buf[(3 * (INC)) % (LEN)]); \ + LOAD_pci_##SZ(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES4)); \ + checkp(ptr, &buf[(4 * (INC)) % (LEN)]); \ +} + +TEST_pci(loadalignb_pci, b, 2, 1, + 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, + 0x010201ffffffffffLL, 0x02010201ffffffffLL) +TEST_pci(loadalignh_pci, h, 4, 2, + 0x0201ffffffffffffLL, 0x04030201ffffffffLL, + 0x020104030201ffffLL, 0x0403020104030201LL) + +/* + **************************************************************************** + * _pcr addressing mode (addr ++ I:circ(modifier-reg)) + */ +#define LOAD_pcr(SZ, RES, PTR, START, LEN, INC) \ + __asm__( \ + "r4 = %2\n\t" \ + "m1 = r4\n\t" \ + "cs1 = %3\n\t" \ + "%0 = mem" #SZ "_fifo(%1++I:circ(m1))\n\t" \ + : "+r"(RES), "+r"(PTR) \ + : "r"((((INC) & 0x7f) << 17) | ((LEN) & 0x1ffff)), \ + "r"(START) \ + : "r4", "m1", "cs1") +#define LOAD_pcr_b(RES, PTR, START, LEN, INC) \ + LOAD_pcr(b, RES, PTR, START, LEN, INC) +#define LOAD_pcr_h(RES, PTR, START, LEN, INC) \ + LOAD_pcr(h, RES, PTR, START, LEN, INC) + +#define TEST_pcr(NAME, SZ, SIZE, LEN, INC, RES1, RES2, RES3, RES4) \ +void test_##NAME(void) \ +{ \ + long long result = ~0LL; \ + void *ptr = buf; \ + LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES1)); \ + checkp(ptr, &buf[(1 * (INC) * (SIZE)) % (LEN)]); \ + LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES2)); \ + checkp(ptr, &buf[(2 * (INC) * (SIZE)) % (LEN)]); \ + LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES3)); \ + checkp(ptr, &buf[(3 * (INC) * (SIZE)) % (LEN)]); \ + LOAD_pcr_##SZ(result, ptr, buf, (LEN), (INC)); \ + check(result, (RES4)); \ + checkp(ptr, &buf[(4 * (INC) * (SIZE)) % (LEN)]); \ +} + +TEST_pcr(loadalignb_pcr, b, 1, 2, 1, + 0x01ffffffffffffffLL, 0x0201ffffffffffffLL, + 0x010201ffffffffffLL, 0x02010201ffffffffLL) +TEST_pcr(loadalignh_pcr, h, 2, 4, 1, + 0x0201ffffffffffffLL, 0x04030201ffffffffLL, + 0x020104030201ffffLL, 0x0403020104030201LL) + +int main() +{ + init_buf(); + + test_loadalignb_io(); + test_loadalignh_io(); + + test_loadalignb_ur(); + test_loadalignh_ur(); + + test_loadalignb_ap(); + test_loadalignh_ap(); + + test_loadalignb_pr(); + test_loadalignh_pr(); + + test_loadalignb_pbr(); + test_loadalignh_pbr(); + + test_loadalignb_pi(); + test_loadalignh_pi(); + + test_loadalignb_pci(); + test_loadalignh_pci(); + + test_loadalignb_pcr(); + test_loadalignh_pcr(); + + puts(err ? "FAIL" : "PASS"); + return err ? 1 : 0; +} From e628c0156be74dd14a261bbd18674bacd1afcc7d Mon Sep 17 00:00:00 2001 From: Taylor Simpson Date: Thu, 8 Apr 2021 20:07:54 -0500 Subject: [PATCH 0172/3028] Hexagon (target/hexagon) CABAC decode bin The following instruction is added S2_cabacdecbin Rdd32=decbin(Rss32,Rtt32) Test cases added to tests/tcg/hexagon/misc.c Signed-off-by: Taylor Simpson Reviewed-by: Richard Henderson Message-Id: <1617930474-31979-27-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson --- target/hexagon/arch.c | 91 +++++++++++++++++++++++++++ target/hexagon/arch.h | 4 ++ target/hexagon/imported/encode_pp.def | 1 + target/hexagon/imported/macros.def | 15 +++++ target/hexagon/imported/shift.idef | 47 ++++++++++++++ target/hexagon/macros.h | 7 +++ tests/tcg/hexagon/misc.c | 28 +++++++++ 7 files changed, 193 insertions(+) diff --git a/target/hexagon/arch.c b/target/hexagon/arch.c index dee852e106..68a55b3bd4 100644 --- a/target/hexagon/arch.c +++ b/target/hexagon/arch.c @@ -27,6 +27,97 @@ #define SF_MANTBITS 23 #define float32_nan make_float32(0xffffffff) +/* + * These three tables are used by the cabacdecbin instruction + */ +const uint8_t rLPS_table_64x4[64][4] = { + {128, 176, 208, 240}, + {128, 167, 197, 227}, + {128, 158, 187, 216}, + {123, 150, 178, 205}, + {116, 142, 169, 195}, + {111, 135, 160, 185}, + {105, 128, 152, 175}, + {100, 122, 144, 166}, + {95, 116, 137, 158}, + {90, 110, 130, 150}, + {85, 104, 123, 142}, + {81, 99, 117, 135}, + {77, 94, 111, 128}, + {73, 89, 105, 122}, + {69, 85, 100, 116}, + {66, 80, 95, 110}, + {62, 76, 90, 104}, + {59, 72, 86, 99}, + {56, 69, 81, 94}, + {53, 65, 77, 89}, + {51, 62, 73, 85}, + {48, 59, 69, 80}, + {46, 56, 66, 76}, + {43, 53, 63, 72}, + {41, 50, 59, 69}, + {39, 48, 56, 65}, + {37, 45, 54, 62}, + {35, 43, 51, 59}, + {33, 41, 48, 56}, + {32, 39, 46, 53}, + {30, 37, 43, 50}, + {29, 35, 41, 48}, + {27, 33, 39, 45}, + {26, 31, 37, 43}, + {24, 30, 35, 41}, + {23, 28, 33, 39}, + {22, 27, 32, 37}, + {21, 26, 30, 35}, + {20, 24, 29, 33}, + {19, 23, 27, 31}, + {18, 22, 26, 30}, + {17, 21, 25, 28}, + {16, 20, 23, 27}, + {15, 19, 22, 25}, + {14, 18, 21, 24}, + {14, 17, 20, 23}, + {13, 16, 19, 22}, + {12, 15, 18, 21}, + {12, 14, 17, 20}, + {11, 14, 16, 19}, + {11, 13, 15, 18}, + {10, 12, 15, 17}, + {10, 12, 14, 16}, + {9, 11, 13, 15}, + {9, 11, 12, 14}, + {8, 10, 12, 14}, + {8, 9, 11, 13}, + {7, 9, 11, 12}, + {7, 9, 10, 12}, + {7, 8, 10, 11}, + {6, 8, 9, 11}, + {6, 7, 9, 10}, + {6, 7, 8, 9}, + {2, 2, 2, 2} +}; + +const uint8_t AC_next_state_MPS_64[64] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 62, 63 +}; + + +const uint8_t AC_next_state_LPS_64[64] = { + 0, 0, 1, 2, 2, 4, 4, 5, 6, 7, + 8, 9, 9, 11, 11, 12, 13, 13, 15, 15, + 16, 16, 18, 18, 19, 19, 21, 21, 22, 22, + 23, 24, 24, 25, 26, 26, 27, 27, 28, 29, + 29, 30, 30, 30, 31, 32, 32, 33, 33, 33, + 34, 34, 35, 35, 35, 36, 36, 36, 37, 37, + 37, 38, 38, 63 +}; + #define BITS_MASK_8 0x5555555555555555ULL #define PAIR_MASK_8 0x3333333333333333ULL #define NYBL_MASK_8 0x0f0f0f0f0f0f0f0fULL diff --git a/target/hexagon/arch.h b/target/hexagon/arch.h index 3e0c334209..70918065d3 100644 --- a/target/hexagon/arch.h +++ b/target/hexagon/arch.h @@ -20,6 +20,10 @@ #include "qemu/int128.h" +extern const uint8_t rLPS_table_64x4[64][4]; +extern const uint8_t AC_next_state_MPS_64[64]; +extern const uint8_t AC_next_state_LPS_64[64]; + uint64_t interleave(uint32_t odd, uint32_t even); uint64_t deinterleave(uint64_t src); int32_t conv_round(int32_t a, int n); diff --git a/target/hexagon/imported/encode_pp.def b/target/hexagon/imported/encode_pp.def index dc4eba4f68..35ae3d2369 100644 --- a/target/hexagon/imported/encode_pp.def +++ b/target/hexagon/imported/encode_pp.def @@ -1767,6 +1767,7 @@ SH_RRR_ENC(S4_vxsubaddh, "0001","01-","-","110","ddddd") SH_RRR_ENC(S4_vxaddsubhr, "0001","11-","-","00-","ddddd") SH_RRR_ENC(S4_vxsubaddhr, "0001","11-","-","01-","ddddd") SH_RRR_ENC(S4_extractp_rp, "0001","11-","-","10-","ddddd") +SH_RRR_ENC(S2_cabacdecbin, "0001","11-","-","11-","ddddd") /* implicit P0 write */ DEF_FIELDROW_DESC32(ICLASS_S3op" 0010 -------- PP------ --------","[#2] Rdd=(Rss,Rtt,Pu)") diff --git a/target/hexagon/imported/macros.def b/target/hexagon/imported/macros.def index 56c99b1d64..32ed3bf8fc 100755 --- a/target/hexagon/imported/macros.def +++ b/target/hexagon/imported/macros.def @@ -92,6 +92,21 @@ DEF_MACRO( /* attribs */ ) + +DEF_MACRO( + fINSERT_RANGE, + { + int offset=LOWBIT; + int width=HIBIT-LOWBIT+1; + /* clear bits where new bits go */ + INREG &= ~(((fCONSTLL(1)<>29)&3]; + rLPS = rLPS << 23; /* left aligned */ + + /* calculate rMPS */ + rMPS= (range&0xff800000) - rLPS; + + /* most probable region */ + if (offset < rMPS) { + RddV = AC_next_state_MPS_64[state]; + fINSERT_RANGE(RddV,8,8,valMPS); + fINSERT_RANGE(RddV,31,23,(rMPS>>23)); + fSETWORD(1,RddV,offset); + fWRITE_P0(valMPS); + + + } + /* least probable region */ + else { + RddV = AC_next_state_LPS_64[state]; + fINSERT_RANGE(RddV,8,8,((!state)?(1-valMPS):(valMPS))); + fINSERT_RANGE(RddV,31,23,(rLPS>>23)); + fSETWORD(1,RddV,(offset-rMPS)); + fWRITE_P0((valMPS^1)); + } +}) + + Q6INSN(S2_clb,"Rd32=clb(Rs32)",ATTRIBS(), "Count leading bits", {RdV = fMAX(fCL1_4(RsV),fCL1_4(~RsV));}) diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index ec5bf60f5e..b726c3b791 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -222,6 +222,13 @@ static inline void gen_pred_cancel(TCGv pred, int slot_num) (((HIBIT) - (LOWBIT) + 1) ? \ extract64((INREG), (LOWBIT), ((HIBIT) - (LOWBIT) + 1)) : \ 0LL) +#define fINSERT_RANGE(INREG, HIBIT, LOWBIT, INVAL) \ + do { \ + int width = ((HIBIT) - (LOWBIT) + 1); \ + INREG = (width >= 0 ? \ + deposit64((INREG), (LOWBIT), width, (INVAL)) : \ + INREG); \ + } while (0) #define f8BITSOF(VAL) ((VAL) ? 0xff : 0x00) diff --git a/tests/tcg/hexagon/misc.c b/tests/tcg/hexagon/misc.c index e5d78b471f..17c39198fc 100644 --- a/tests/tcg/hexagon/misc.c +++ b/tests/tcg/hexagon/misc.c @@ -231,6 +231,14 @@ static void check(int val, int expect) } } +static void check64(long long val, long long expect) +{ + if (val != expect) { + printf("ERROR: 0x%016llx != 0x%016llx\n", val, expect); + err++; + } +} + uint32_t init[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; uint32_t array[10]; @@ -264,6 +272,16 @@ static long long creg_pair(int x, int y) return retval; } +static long long decbin(long long x, long long y, int *pred) +{ + long long retval; + asm ("%0 = decbin(%2, %3)\n\t" + "%1 = p0\n\t" + : "=r"(retval), "=r"(*pred) + : "r"(x), "r"(y)); + return retval; +} + /* Check that predicates are auto-and'ed in a packet */ static int auto_and(void) { @@ -282,6 +300,8 @@ static int auto_and(void) int main() { + long long res64; + int pred; memcpy(array, init, sizeof(array)); S4_storerhnew_rr(array, 4, 0xffff); @@ -391,6 +411,14 @@ int main() res = test_clrtnew(2, 7); check(res, 7); + res64 = decbin(0xf0f1f2f3f4f5f6f7LL, 0x7f6f5f4f3f2f1f0fLL, &pred); + check64(res64, 0x357980003700010cLL); + check(pred, 0); + + res64 = decbin(0xfLL, 0x1bLL, &pred); + check64(res64, 0x78000100LL); + check(pred, 1); + res = auto_and(); check(res, 0); From bcad139192b0101e3d7ef593144c314bed4cb8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 24 Mar 2021 15:24:41 +0100 Subject: [PATCH 0173/3028] hw/isa/piix4: Use qdev_get_gpio_in_named() to get ISA IRQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 078778c5a55 ("piix4: Add an i8259 Interrupt Controller") the TYPE_PIIX4_PCI_DEVICE exposes the ISA input IRQs as "isa" alias. Use this alias to get IRQ for the power management PCI function. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210324182902.692419-1-f4bug@amsat.org> --- hw/isa/piix4.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index b3b6a4378a..5ae3b4984d 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -268,8 +268,9 @@ DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, I2CBus **smbus) pci_create_simple(pci_bus, devfn + 2, "piix4-usb-uhci"); if (smbus) { *smbus = piix4_pm_init(pci_bus, devfn + 3, 0x1100, - isa_get_irq(NULL, 9), NULL, 0, NULL); - } + qdev_get_gpio_in_named(dev, "isa", 9), + NULL, 0, NULL); + } return dev; } From 84c2fdc397b6609d1cef76aec2f1367139d1372e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 20 Apr 2021 19:49:40 +0200 Subject: [PATCH 0174/3028] target/mips: Fix CACHEE opcode (CACHE using EVA addressing) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CACHEE opcode "requires CP0 privilege". The pseudocode checks in the ISA manual is: if is_eva and not C0.Config5.EVA: raise exception('RI') if not IsCoprocessor0Enabled(): raise coprocessor_exception(0) Add the missing checks. Inspired-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210420175426.1875746-1-f4bug@amsat.org> --- target/mips/translate.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/mips/translate.c b/target/mips/translate.c index 71fa5ec197..5dad75cdf3 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -20957,6 +20957,8 @@ static int decode_nanomips_32_48_opc(CPUMIPSState *env, DisasContext *ctx) gen_ld(ctx, OPC_LHUE, rt, rs, s); break; case NM_CACHEE: + check_eva(ctx); + check_cp0_enabled(ctx); check_nms_dl_il_sl_tl_l2c(ctx); gen_cache_operation(ctx, rt, rs, s); break; @@ -24530,11 +24532,11 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) gen_st_cond(ctx, rt, rs, imm, MO_TESL, true); return; case OPC_CACHEE: + check_eva(ctx); check_cp0_enabled(ctx); if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { gen_cache_operation(ctx, rt, rs, imm); } - /* Treat as NOP. */ return; case OPC_PREFE: check_cp0_enabled(ctx); From 298d43c96b0f7dc7ea6550ea73b128b3d4ed67f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 21 Apr 2021 20:39:15 +0200 Subject: [PATCH 0175/3028] target/mips: Add missing CP0 check to nanoMIPS RDPGPR / WRPGPR opcodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the nanoMIPS32 Instruction Set Technical Reference Manual, Revision 01.01, Chapter 3. "Instruction Definitions": The Read/Write Previous GPR opcodes "require CP0 privilege". Add the missing CP0 checks. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210421185007.2231855-1-f4bug@amsat.org> --- target/mips/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/mips/translate.c b/target/mips/translate.c index 5dad75cdf3..8a0a219742 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -18969,9 +18969,11 @@ static void gen_pool32axf_nanomips_insn(CPUMIPSState *env, DisasContext *ctx) } break; case NM_RDPGPR: + check_cp0_enabled(ctx); gen_load_srsgpr(rs, rt); break; case NM_WRPGPR: + check_cp0_enabled(ctx); gen_store_srsgpr(rs, rt); break; case NM_WAIT: From bc2eb5ea1b595fb686b7bef81bbf20e6a9635476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 22 Apr 2021 10:05:10 +0200 Subject: [PATCH 0176/3028] target/mips: Remove spurious LOG_UNIMP of MTHC0 opcode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running with '-d unimp' all MTHC0 opcode executed are logged as unimplemented... Add the proper 'return' statement missed from commit 5204ea79ea7. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210422081055.2349216-1-f4bug@amsat.org> --- target/mips/translate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/mips/translate.c b/target/mips/translate.c index 8a0a219742..3230b2bca3 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -5945,6 +5945,7 @@ static void gen_mthc0(DisasContext *ctx, TCGv arg, int reg, int sel) goto cp0_unimplemented; } trace_mips_translate_c0("mthc0", register_name, reg, sel); + return; cp0_unimplemented: qemu_log_mask(LOG_UNIMP, "mthc0 %s (reg %d sel %d)\n", From df44e81703968d22ce59e1160f970c5e70db2cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 23 Apr 2021 22:00:09 +0200 Subject: [PATCH 0177/3028] target/mips: Migrate missing CPU fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add various missing fields to the CPU migration vmstate: - CP0_VPControl & CP0_GlobalNumber (01bc435b44b 2016-02-03) - CMGCRBase (c870e3f52ca 2016-03-15) - CP0_ErrCtl (0d74a222c27 2016-03-25) - MXU GPR[] & CR (eb5559f67dc 2018-10-18) - R5900 128-bit upper half (a168a796e1c 2019-01-17) This is a migration break. Fixes: 01bc435b44b ("target-mips: implement R6 multi-threading") Fixes: c870e3f52ca ("target-mips: add CMGCRBase register") Fixes: 0d74a222c27 ("target-mips: make ITC Configuration Tags accessible to the CPU") Fixes: eb5559f67dc ("target/mips: Introduce MXU registers") Fixes: a168a796e1c ("target/mips: Introduce 32 R5900 multimedia registers") Signed-off-by: Philippe Mathieu-Daudé Acked-by: Richard Henderson Message-Id: <20210423220044.3004195-1-f4bug@amsat.org> --- target/mips/machine.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/target/mips/machine.c b/target/mips/machine.c index b5fda6a278..80d37f9c2f 100644 --- a/target/mips/machine.c +++ b/target/mips/machine.c @@ -81,6 +81,9 @@ const VMStateDescription vmstate_inactive_fpu = { static VMStateField vmstate_tc_fields[] = { VMSTATE_UINTTL_ARRAY(gpr, TCState, 32), +#if defined(TARGET_MIPS64) + VMSTATE_UINT64_ARRAY(gpr_hi, TCState, 32), +#endif /* TARGET_MIPS64 */ VMSTATE_UINTTL(PC, TCState), VMSTATE_UINTTL_ARRAY(HI, TCState, MIPS_DSP_ACC), VMSTATE_UINTTL_ARRAY(LO, TCState, MIPS_DSP_ACC), @@ -95,20 +98,22 @@ static VMStateField vmstate_tc_fields[] = { VMSTATE_INT32(CP0_Debug_tcstatus, TCState), VMSTATE_UINTTL(CP0_UserLocal, TCState), VMSTATE_INT32(msacsr, TCState), + VMSTATE_UINTTL_ARRAY(mxu_gpr, TCState, NUMBER_OF_MXU_REGISTERS - 1), + VMSTATE_UINTTL(mxu_cr, TCState), VMSTATE_END_OF_LIST() }; const VMStateDescription vmstate_tc = { .name = "cpu/tc", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = vmstate_tc_fields }; const VMStateDescription vmstate_inactive_tc = { .name = "cpu/inactive_tc", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = vmstate_tc_fields }; @@ -213,8 +218,8 @@ const VMStateDescription vmstate_tlb = { const VMStateDescription vmstate_mips_cpu = { .name = "cpu", - .version_id = 20, - .minimum_version_id = 20, + .version_id = 21, + .minimum_version_id = 21, .post_load = cpu_post_load, .fields = (VMStateField[]) { /* Active TC */ @@ -241,6 +246,7 @@ const VMStateDescription vmstate_mips_cpu = { /* Remaining CP0 registers */ VMSTATE_INT32(env.CP0_Index, MIPSCPU), + VMSTATE_INT32(env.CP0_VPControl, MIPSCPU), VMSTATE_INT32(env.CP0_Random, MIPSCPU), VMSTATE_INT32(env.CP0_VPEControl, MIPSCPU), VMSTATE_INT32(env.CP0_VPEConf0, MIPSCPU), @@ -251,6 +257,7 @@ const VMStateDescription vmstate_mips_cpu = { VMSTATE_INT32(env.CP0_VPEOpt, MIPSCPU), VMSTATE_UINT64(env.CP0_EntryLo0, MIPSCPU), VMSTATE_UINT64(env.CP0_EntryLo1, MIPSCPU), + VMSTATE_INT32(env.CP0_GlobalNumber, MIPSCPU), VMSTATE_UINTTL(env.CP0_Context, MIPSCPU), VMSTATE_INT32(env.CP0_MemoryMapID, MIPSCPU), VMSTATE_INT32(env.CP0_PageMask, MIPSCPU), @@ -286,6 +293,7 @@ const VMStateDescription vmstate_mips_cpu = { VMSTATE_UINTTL(env.CP0_EPC, MIPSCPU), VMSTATE_INT32(env.CP0_PRid, MIPSCPU), VMSTATE_UINTTL(env.CP0_EBase, MIPSCPU), + VMSTATE_UINTTL(env.CP0_CMGCRBase, MIPSCPU), VMSTATE_INT32(env.CP0_Config0, MIPSCPU), VMSTATE_INT32(env.CP0_Config1, MIPSCPU), VMSTATE_INT32(env.CP0_Config2, MIPSCPU), @@ -305,6 +313,7 @@ const VMStateDescription vmstate_mips_cpu = { VMSTATE_INT32(env.CP0_Debug, MIPSCPU), VMSTATE_UINTTL(env.CP0_DEPC, MIPSCPU), VMSTATE_INT32(env.CP0_Performance0, MIPSCPU), + VMSTATE_INT32(env.CP0_ErrCtl, MIPSCPU), VMSTATE_UINT64(env.CP0_TagLo, MIPSCPU), VMSTATE_INT32(env.CP0_DataLo, MIPSCPU), VMSTATE_INT32(env.CP0_TagHi, MIPSCPU), From 905bdf72a6373bcb46fbdc8b9d7d9f83d134a266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 20 Apr 2021 20:07:38 +0200 Subject: [PATCH 0178/3028] target/mips: Make check_cp0_enabled() return a boolean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid callers to emit dead code if check_cp0_enabled() raise an exception, let it return a boolean value, whether CP0 is enabled or not. Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210420193453.1913810-4-f4bug@amsat.org> --- target/mips/translate.c | 4 +++- target/mips/translate.h | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/target/mips/translate.c b/target/mips/translate.c index 3230b2bca3..0e90d8cace 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -1572,11 +1572,13 @@ void gen_move_high32(TCGv ret, TCGv_i64 arg) #endif } -void check_cp0_enabled(DisasContext *ctx) +bool check_cp0_enabled(DisasContext *ctx) { if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0))) { generate_exception_end(ctx, EXCP_CpU); + return false; } + return true; } void check_cp1_enabled(DisasContext *ctx) diff --git a/target/mips/translate.h b/target/mips/translate.h index 2b3c7a69ec..6144259034 100644 --- a/target/mips/translate.h +++ b/target/mips/translate.h @@ -120,7 +120,12 @@ void gen_reserved_instruction(DisasContext *ctx); void check_insn(DisasContext *ctx, uint64_t flags); void check_mips_64(DisasContext *ctx); -void check_cp0_enabled(DisasContext *ctx); +/** + * check_cp0_enabled: + * Return %true if CP0 is enabled, otherwise return %false + * and emit a 'coprocessor unusable' exception. + */ +bool check_cp0_enabled(DisasContext *ctx); void check_cp1_enabled(DisasContext *ctx); void check_cp1_64bitmode(DisasContext *ctx); void check_cp1_registers(DisasContext *ctx, int regs); From 58ecf15d76e6e232d908bf115236108a639daa71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 21:20:53 +0200 Subject: [PATCH 0179/3028] target/mips: Simplify meson TCG rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have the mips_tcg_ss source set for TCG-specific files, use it for mxu_translate.c and tx79_translate.c to simplify a bit. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-2-f4bug@amsat.org> --- target/mips/meson.build | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target/mips/meson.build b/target/mips/meson.build index 3b131c4a7f..3733d1200f 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -26,10 +26,9 @@ mips_tcg_ss.add(files( 'translate_addr_const.c', 'txx9_translate.c', )) -mips_ss.add(when: ['CONFIG_TCG', 'TARGET_MIPS64'], if_true: files( +mips_tcg_ss.add(when: 'TARGET_MIPS64', if_true: files( 'tx79_translate.c', -)) -mips_tcg_ss.add(when: 'TARGET_MIPS64', if_false: files( +), if_false: files( 'mxu_translate.c', )) From 830a72301c35548907ff05399a99f34dab9c867d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 16 Jan 2021 13:55:03 +0100 Subject: [PATCH 0180/3028] target/mips: Move IEEE rounding mode array to new source file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit restore_msa_fp_status() is declared inlined in fpu_helper.h, and uses the ieee_rm[] array. Therefore any code calling restore_msa_fp_status() must have access to this ieee_rm[] array. kvm_mips_get_fpu_registers(), which is in target/mips/kvm.c, calls restore_msa_fp_status. Except this tiny array, the rest of fpu_helper.c is only useful for the TCG accelerator. To be able to restrict fpu_helper.c to TCG, we need to move the ieee_rm[] array to a new source file. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-3-f4bug@amsat.org> --- target/mips/fpu.c | 18 ++++++++++++++++++ target/mips/fpu_helper.c | 8 -------- target/mips/meson.build | 1 + 3 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 target/mips/fpu.c diff --git a/target/mips/fpu.c b/target/mips/fpu.c new file mode 100644 index 0000000000..39a2f7fd22 --- /dev/null +++ b/target/mips/fpu.c @@ -0,0 +1,18 @@ +/* + * Helpers for emulation of FPU-related MIPS instructions. + * + * Copyright (C) 2004-2005 Jocelyn Mayer + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#include "qemu/osdep.h" +#include "fpu/softfloat-helpers.h" +#include "fpu_helper.h" + +/* convert MIPS rounding mode in FCR31 to IEEE library */ +const FloatRoundMode ieee_rm[4] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; diff --git a/target/mips/fpu_helper.c b/target/mips/fpu_helper.c index 6dd853259e..8ce56ed7c8 100644 --- a/target/mips/fpu_helper.c +++ b/target/mips/fpu_helper.c @@ -38,14 +38,6 @@ #define FP_TO_INT32_OVERFLOW 0x7fffffff #define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL -/* convert MIPS rounding mode in FCR31 to IEEE library */ -const FloatRoundMode ieee_rm[4] = { - float_round_nearest_even, - float_round_to_zero, - float_round_up, - float_round_down -}; - target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) { target_ulong arg1 = 0; diff --git a/target/mips/meson.build b/target/mips/meson.build index 3733d1200f..5fcb211ca9 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -9,6 +9,7 @@ gen = [ mips_ss = ss.source_set() mips_ss.add(files( 'cpu.c', + 'fpu.c', 'gdbstub.c', )) mips_tcg_ss = ss.source_set() From fed50ffd5ce4b03f94036232c613b2ca8fba06eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 16 Jan 2021 16:32:06 +0100 Subject: [PATCH 0181/3028] target/mips: Move msa_reset() to new source file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mips_cpu_reset() is used by all accelerators, and calls msa_reset(), which is defined in msa_helper.c. Beside msa_reset(), the rest of msa_helper.c is only useful to the TCG accelerator. To be able to restrict this helper file to TCG, we need to move msa_reset() out of it. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-4-f4bug@amsat.org> --- target/mips/meson.build | 1 + target/mips/msa.c | 60 ++++++++++++++++++++++++++++++++++++++++ target/mips/msa_helper.c | 36 ------------------------ 3 files changed, 61 insertions(+), 36 deletions(-) create mode 100644 target/mips/msa.c diff --git a/target/mips/meson.build b/target/mips/meson.build index 5fcb211ca9..daf5f1d55b 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -11,6 +11,7 @@ mips_ss.add(files( 'cpu.c', 'fpu.c', 'gdbstub.c', + 'msa.c', )) mips_tcg_ss = ss.source_set() mips_tcg_ss.add(gen) diff --git a/target/mips/msa.c b/target/mips/msa.c new file mode 100644 index 0000000000..61f1a9a593 --- /dev/null +++ b/target/mips/msa.c @@ -0,0 +1,60 @@ +/* + * MIPS SIMD Architecture Module Instruction emulation helpers for QEMU. + * + * Copyright (c) 2014 Imagination Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internal.h" +#include "fpu/softfloat.h" +#include "fpu_helper.h" + +void msa_reset(CPUMIPSState *env) +{ + if (!ase_msa_available(env)) { + return; + } + +#ifdef CONFIG_USER_ONLY + /* MSA access enabled */ + env->CP0_Config5 |= 1 << CP0C5_MSAEn; + env->CP0_Status |= (1 << CP0St_CU1) | (1 << CP0St_FR); +#endif + + /* + * MSA CSR: + * - non-signaling floating point exception mode off (NX bit is 0) + * - Cause, Enables, and Flags are all 0 + * - round to nearest / ties to even (RM bits are 0) + */ + env->active_tc.msacsr = 0; + + restore_msa_fp_status(env); + + /* tininess detected after rounding.*/ + set_float_detect_tininess(float_tininess_after_rounding, + &env->active_tc.msa_fp_status); + + /* clear float_status exception flags */ + set_float_exception_flags(0, &env->active_tc.msa_fp_status); + + /* clear float_status nan mode */ + set_default_nan_mode(0, &env->active_tc.msa_fp_status); + + /* set proper signanling bit meaning ("1" means "quiet") */ + set_snan_bit_is_one(0, &env->active_tc.msa_fp_status); +} diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c index 4caefe29ad..04af54f66d 100644 --- a/target/mips/msa_helper.c +++ b/target/mips/msa_helper.c @@ -8595,39 +8595,3 @@ void helper_msa_st_d(CPUMIPSState *env, uint32_t wd, cpu_stq_data(env, addr + (1 << DF_DOUBLE), pwd->d[1]); #endif } - -void msa_reset(CPUMIPSState *env) -{ - if (!ase_msa_available(env)) { - return; - } - -#ifdef CONFIG_USER_ONLY - /* MSA access enabled */ - env->CP0_Config5 |= 1 << CP0C5_MSAEn; - env->CP0_Status |= (1 << CP0St_CU1) | (1 << CP0St_FR); -#endif - - /* - * MSA CSR: - * - non-signaling floating point exception mode off (NX bit is 0) - * - Cause, Enables, and Flags are all 0 - * - round to nearest / ties to even (RM bits are 0) - */ - env->active_tc.msacsr = 0; - - restore_msa_fp_status(env); - - /* tininess detected after rounding.*/ - set_float_detect_tininess(float_tininess_after_rounding, - &env->active_tc.msa_fp_status); - - /* clear float_status exception flags */ - set_float_exception_flags(0, &env->active_tc.msa_fp_status); - - /* clear float_status nan mode */ - set_default_nan_mode(0, &env->active_tc.msa_fp_status); - - /* set proper signanling bit meaning ("1" means "quiet") */ - set_snan_bit_is_one(0, &env->active_tc.msa_fp_status); -} From adbf1be325482af13e374573fc875fbe15600348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 16 Jan 2021 14:26:33 +0100 Subject: [PATCH 0182/3028] target/mips: Make CPU/FPU regnames[] arrays global MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CPU/FPU regnames[] arrays is used in mips_tcg_init() and mips_cpu_dump_state(), which while being in translate.c is not specific to TCG. To be able to move mips_cpu_dump_state() to cpu.c, which is compiled for all accelerator, we need to make the regnames[] arrays global to target/mips/ by declaring them in "internal.h". Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-5-f4bug@amsat.org> --- target/mips/cpu.c | 7 +++++++ target/mips/fpu.c | 7 +++++++ target/mips/internal.h | 3 +++ target/mips/translate.c | 14 -------------- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index dce1e166bd..f354d18aec 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -35,6 +35,13 @@ #include "qapi/qapi-commands-machine-target.h" #include "fpu_helper.h" +const char * const regnames[32] = { + "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", +}; + #if !defined(CONFIG_USER_ONLY) /* Called for updates to CP0_Status. */ diff --git a/target/mips/fpu.c b/target/mips/fpu.c index 39a2f7fd22..1447dba3fa 100644 --- a/target/mips/fpu.c +++ b/target/mips/fpu.c @@ -16,3 +16,10 @@ const FloatRoundMode ieee_rm[4] = { float_round_up, float_round_down }; + +const char * const fregnames[32] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", +}; diff --git a/target/mips/internal.h b/target/mips/internal.h index 99264b8bf6..a8644f754a 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -71,6 +71,9 @@ struct mips_def_t { int32_t SAARP; }; +extern const char * const regnames[32]; +extern const char * const fregnames[32]; + extern const struct mips_def_t mips_defs[]; extern const int mips_defs_number; diff --git a/target/mips/translate.c b/target/mips/translate.c index 0e90d8cace..8d686e9095 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -1267,13 +1267,6 @@ TCGv_i64 fpu_f64[32]; #define DISAS_STOP DISAS_TARGET_0 #define DISAS_EXIT DISAS_TARGET_1 -static const char * const regnames[] = { - "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", -}; - static const char * const regnames_HI[] = { "HI0", "HI1", "HI2", "HI3", }; @@ -1282,13 +1275,6 @@ static const char * const regnames_LO[] = { "LO0", "LO1", "LO2", "LO3", }; -static const char * const fregnames[] = { - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", -}; - /* General purpose registers moves. */ void gen_load_gpr(TCGv t, int reg) { From 830b87ea25b3710c3fce04dee782bcf1c89ba27f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 18 Apr 2021 23:41:10 +0200 Subject: [PATCH 0183/3028] target/mips: Optimize CPU/FPU regnames[] arrays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since all entries are no more than 4 bytes (including nul terminator), can save space and pie runtime relocations by declaring regnames[] as array of 4 const char. Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-6-f4bug@amsat.org> --- target/mips/cpu.c | 2 +- target/mips/fpu.c | 2 +- target/mips/internal.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index f354d18aec..ed9552ebeb 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -35,7 +35,7 @@ #include "qapi/qapi-commands-machine-target.h" #include "fpu_helper.h" -const char * const regnames[32] = { +const char regnames[32][4] = { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", diff --git a/target/mips/fpu.c b/target/mips/fpu.c index 1447dba3fa..c7c487c1f9 100644 --- a/target/mips/fpu.c +++ b/target/mips/fpu.c @@ -17,7 +17,7 @@ const FloatRoundMode ieee_rm[4] = { float_round_down }; -const char * const fregnames[32] = { +const char fregnames[32][4] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", diff --git a/target/mips/internal.h b/target/mips/internal.h index a8644f754a..37f54a8b3f 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -71,8 +71,8 @@ struct mips_def_t { int32_t SAARP; }; -extern const char * const regnames[32]; -extern const char * const fregnames[32]; +extern const char regnames[32][4]; +extern const char fregnames[32][4]; extern const struct mips_def_t mips_defs[]; extern const int mips_defs_number; From 4f14ce4bf4ec01a840a8de4007a95a77998c5736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 16 Jan 2021 14:26:52 +0100 Subject: [PATCH 0184/3028] target/mips: Restrict mips_cpu_dump_state() to cpu.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As mips_cpu_dump_state() is only used once to initialize the CPUClass::dump_state handler, we can move it to cpu.c to keep it symbol local. Beside, this handler is used by all accelerators, while the translate.c file targets TCG. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-7-f4bug@amsat.org> --- target/mips/cpu.c | 77 +++++++++++++++++++++++++++++++++++++++++ target/mips/internal.h | 1 - target/mips/translate.c | 77 ----------------------------------------- 3 files changed, 77 insertions(+), 78 deletions(-) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index ed9552ebeb..232f701b83 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -145,6 +145,83 @@ void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val) #endif /* !CONFIG_USER_ONLY */ +static void fpu_dump_state(CPUMIPSState *env, FILE *f, int flags) +{ + int i; + int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64); + +#define printfpr(fp) \ + do { \ + if (is_fpu64) \ + qemu_fprintf(f, "w:%08x d:%016" PRIx64 \ + " fd:%13g fs:%13g psu: %13g\n", \ + (fp)->w[FP_ENDIAN_IDX], (fp)->d, \ + (double)(fp)->fd, \ + (double)(fp)->fs[FP_ENDIAN_IDX], \ + (double)(fp)->fs[!FP_ENDIAN_IDX]); \ + else { \ + fpr_t tmp; \ + tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ + tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ + qemu_fprintf(f, "w:%08x d:%016" PRIx64 \ + " fd:%13g fs:%13g psu:%13g\n", \ + tmp.w[FP_ENDIAN_IDX], tmp.d, \ + (double)tmp.fd, \ + (double)tmp.fs[FP_ENDIAN_IDX], \ + (double)tmp.fs[!FP_ENDIAN_IDX]); \ + } \ + } while (0) + + + qemu_fprintf(f, + "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n", + env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64, + get_float_exception_flags(&env->active_fpu.fp_status)); + for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { + qemu_fprintf(f, "%3s: ", fregnames[i]); + printfpr(&env->active_fpu.fpr[i]); + } + +#undef printfpr +} + +static void mips_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + int i; + + qemu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx + " LO=0x" TARGET_FMT_lx " ds %04x " + TARGET_FMT_lx " " TARGET_FMT_ld "\n", + env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0], + env->hflags, env->btarget, env->bcond); + for (i = 0; i < 32; i++) { + if ((i & 3) == 0) { + qemu_fprintf(f, "GPR%02d:", i); + } + qemu_fprintf(f, " %s " TARGET_FMT_lx, + regnames[i], env->active_tc.gpr[i]); + if ((i & 3) == 3) { + qemu_fprintf(f, "\n"); + } + } + + qemu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" + TARGET_FMT_lx "\n", + env->CP0_Status, env->CP0_Cause, env->CP0_EPC); + qemu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%016" + PRIx64 "\n", + env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); + qemu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n", + env->CP0_Config2, env->CP0_Config3); + qemu_fprintf(f, " Config4 0x%08x Config5 0x%08x\n", + env->CP0_Config4, env->CP0_Config5); + if ((flags & CPU_DUMP_FPU) && (env->hflags & MIPS_HFLAG_FPU)) { + fpu_dump_state(env, f, flags); + } +} + static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_RESET] = "reset", [EXCP_SRESET] = "soft reset", diff --git a/target/mips/internal.h b/target/mips/internal.h index 37f54a8b3f..57072a941e 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -79,7 +79,6 @@ extern const int mips_defs_number; void mips_cpu_do_interrupt(CPUState *cpu); bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req); -void mips_cpu_dump_state(CPUState *cpu, FILE *f, int flags); hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int mips_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); diff --git a/target/mips/translate.c b/target/mips/translate.c index 8d686e9095..f0ae371602 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -25586,83 +25586,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) translator_loop(&mips_tr_ops, &ctx.base, cs, tb, max_insns); } -static void fpu_dump_state(CPUMIPSState *env, FILE * f, int flags) -{ - int i; - int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64); - -#define printfpr(fp) \ - do { \ - if (is_fpu64) \ - qemu_fprintf(f, "w:%08x d:%016" PRIx64 \ - " fd:%13g fs:%13g psu: %13g\n", \ - (fp)->w[FP_ENDIAN_IDX], (fp)->d, \ - (double)(fp)->fd, \ - (double)(fp)->fs[FP_ENDIAN_IDX], \ - (double)(fp)->fs[!FP_ENDIAN_IDX]); \ - else { \ - fpr_t tmp; \ - tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ - tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ - qemu_fprintf(f, "w:%08x d:%016" PRIx64 \ - " fd:%13g fs:%13g psu:%13g\n", \ - tmp.w[FP_ENDIAN_IDX], tmp.d, \ - (double)tmp.fd, \ - (double)tmp.fs[FP_ENDIAN_IDX], \ - (double)tmp.fs[!FP_ENDIAN_IDX]); \ - } \ - } while (0) - - - qemu_fprintf(f, - "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n", - env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64, - get_float_exception_flags(&env->active_fpu.fp_status)); - for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { - qemu_fprintf(f, "%3s: ", fregnames[i]); - printfpr(&env->active_fpu.fpr[i]); - } - -#undef printfpr -} - -void mips_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - MIPSCPU *cpu = MIPS_CPU(cs); - CPUMIPSState *env = &cpu->env; - int i; - - qemu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx - " LO=0x" TARGET_FMT_lx " ds %04x " - TARGET_FMT_lx " " TARGET_FMT_ld "\n", - env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0], - env->hflags, env->btarget, env->bcond); - for (i = 0; i < 32; i++) { - if ((i & 3) == 0) { - qemu_fprintf(f, "GPR%02d:", i); - } - qemu_fprintf(f, " %s " TARGET_FMT_lx, - regnames[i], env->active_tc.gpr[i]); - if ((i & 3) == 3) { - qemu_fprintf(f, "\n"); - } - } - - qemu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" - TARGET_FMT_lx "\n", - env->CP0_Status, env->CP0_Cause, env->CP0_EPC); - qemu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%016" - PRIx64 "\n", - env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr); - qemu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n", - env->CP0_Config2, env->CP0_Config3); - qemu_fprintf(f, " Config4 0x%08x Config5 0x%08x\n", - env->CP0_Config4, env->CP0_Config5); - if ((flags & CPU_DUMP_FPU) && (env->hflags & MIPS_HFLAG_FPU)) { - fpu_dump_state(env, f, flags); - } -} - void mips_tcg_init(void) { int i; From 4d169b9cce25bcef691d0c50a6c7d0d6350003ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 18 Apr 2021 23:50:17 +0200 Subject: [PATCH 0185/3028] target/mips: Turn printfpr() macro into a proper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turn printfpr() macro into a proper function: fpu_dump_fpr(). Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-8-f4bug@amsat.org> --- target/mips/cpu.c | 50 ++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 232f701b83..8f76f4576f 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -145,33 +145,31 @@ void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val) #endif /* !CONFIG_USER_ONLY */ +static void fpu_dump_fpr(fpr_t *fpr, FILE *f, bool is_fpu64) +{ + if (is_fpu64) { + qemu_fprintf(f, "w:%08x d:%016" PRIx64 " fd:%13g fs:%13g psu: %13g\n", + fpr->w[FP_ENDIAN_IDX], fpr->d, + (double)fpr->fd, + (double)fpr->fs[FP_ENDIAN_IDX], + (double)fpr->fs[!FP_ENDIAN_IDX]); + } else { + fpr_t tmp; + + tmp.w[FP_ENDIAN_IDX] = fpr->w[FP_ENDIAN_IDX]; + tmp.w[!FP_ENDIAN_IDX] = (fpr + 1)->w[FP_ENDIAN_IDX]; + qemu_fprintf(f, "w:%08x d:%016" PRIx64 " fd:%13g fs:%13g psu:%13g\n", + tmp.w[FP_ENDIAN_IDX], tmp.d, + (double)tmp.fd, + (double)tmp.fs[FP_ENDIAN_IDX], + (double)tmp.fs[!FP_ENDIAN_IDX]); + } +} + static void fpu_dump_state(CPUMIPSState *env, FILE *f, int flags) { int i; - int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64); - -#define printfpr(fp) \ - do { \ - if (is_fpu64) \ - qemu_fprintf(f, "w:%08x d:%016" PRIx64 \ - " fd:%13g fs:%13g psu: %13g\n", \ - (fp)->w[FP_ENDIAN_IDX], (fp)->d, \ - (double)(fp)->fd, \ - (double)(fp)->fs[FP_ENDIAN_IDX], \ - (double)(fp)->fs[!FP_ENDIAN_IDX]); \ - else { \ - fpr_t tmp; \ - tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ - tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ - qemu_fprintf(f, "w:%08x d:%016" PRIx64 \ - " fd:%13g fs:%13g psu:%13g\n", \ - tmp.w[FP_ENDIAN_IDX], tmp.d, \ - (double)tmp.fd, \ - (double)tmp.fs[FP_ENDIAN_IDX], \ - (double)tmp.fs[!FP_ENDIAN_IDX]); \ - } \ - } while (0) - + bool is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64); qemu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n", @@ -179,10 +177,8 @@ static void fpu_dump_state(CPUMIPSState *env, FILE *f, int flags) get_float_exception_flags(&env->active_fpu.fp_status)); for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { qemu_fprintf(f, "%3s: ", fregnames[i]); - printfpr(&env->active_fpu.fpr[i]); + fpu_dump_fpr(&env->active_fpu.fpr[i], f, is_fpu64); } - -#undef printfpr } static void mips_cpu_dump_state(CPUState *cs, FILE *f, int flags) From 533fc64feb96b6aafdb0d604cd1cd97877451878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 18 Apr 2021 23:59:48 +0200 Subject: [PATCH 0186/3028] target/mips: Declare mips_env_set_pc() inlined in "internal.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename set_pc() as mips_env_set_pc(), declare it inlined and use it in cpu.c and op_helper.c. Reported-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210428170410.479308-9-f4bug@amsat.org> --- target/mips/cpu.c | 8 +------- target/mips/internal.h | 10 ++++++++++ target/mips/op_helper.c | 16 +++------------- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 8f76f4576f..a751c95832 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -327,14 +327,8 @@ void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, static void mips_cpu_set_pc(CPUState *cs, vaddr value) { MIPSCPU *cpu = MIPS_CPU(cs); - CPUMIPSState *env = &cpu->env; - env->active_tc.PC = value & ~(target_ulong)1; - if (value & 1) { - env->hflags |= MIPS_HFLAG_M16; - } else { - env->hflags &= ~(MIPS_HFLAG_M16); - } + mips_env_set_pc(&cpu->env, value); } #ifdef CONFIG_TCG diff --git a/target/mips/internal.h b/target/mips/internal.h index 57072a941e..04f4b3d661 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -219,6 +219,16 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, /* op_helper.c */ void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask); +static inline void mips_env_set_pc(CPUMIPSState *env, target_ulong value) +{ + env->active_tc.PC = value & ~(target_ulong)1; + if (value & 1) { + env->hflags |= MIPS_HFLAG_M16; + } else { + env->hflags &= ~(MIPS_HFLAG_M16); + } +} + static inline void restore_pamask(CPUMIPSState *env) { if (env->hflags & MIPS_HFLAG_ELPA) { diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index b80e8f7540..222a0d7c7b 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -993,24 +993,14 @@ static void debug_post_eret(CPUMIPSState *env) } } -static void set_pc(CPUMIPSState *env, target_ulong error_pc) -{ - env->active_tc.PC = error_pc & ~(target_ulong)1; - if (error_pc & 1) { - env->hflags |= MIPS_HFLAG_M16; - } else { - env->hflags &= ~(MIPS_HFLAG_M16); - } -} - static inline void exception_return(CPUMIPSState *env) { debug_pre_eret(env); if (env->CP0_Status & (1 << CP0St_ERL)) { - set_pc(env, env->CP0_ErrorEPC); + mips_env_set_pc(env, env->CP0_ErrorEPC); env->CP0_Status &= ~(1 << CP0St_ERL); } else { - set_pc(env, env->CP0_EPC); + mips_env_set_pc(env, env->CP0_EPC); env->CP0_Status &= ~(1 << CP0St_EXL); } compute_hflags(env); @@ -1036,7 +1026,7 @@ void helper_deret(CPUMIPSState *env) env->hflags &= ~MIPS_HFLAG_DM; compute_hflags(env); - set_pc(env, env->CP0_DEPC); + mips_env_set_pc(env, env->CP0_DEPC); debug_post_eret(env); } From 0debf1400c000154948e8a6fcb89c3149d4e0880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 19 Apr 2021 18:00:55 +0200 Subject: [PATCH 0187/3028] target/mips: Merge do_translate_address into cpu_mips_translate_address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently cpu_mips_translate_address() calls raise_mmu_exception(), and do_translate_address() calls cpu_loop_exit_restore(). This API split is dangerous, we could call cpu_mips_translate_address without returning to the main loop. As there is only one caller, it is trivial (and safer) to merge do_translate_address() back to cpu_mips_translate_address(). Reported-by: Richard Henderson Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-10-f4bug@amsat.org> --- target/mips/internal.h | 2 +- target/mips/op_helper.c | 20 ++------------------ target/mips/tlb_helper.c | 11 ++++++----- 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/target/mips/internal.h b/target/mips/internal.h index 04f4b3d661..e93e057bec 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -148,7 +148,7 @@ void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, int mmu_idx, MemTxAttrs attrs, MemTxResult response, uintptr_t retaddr); hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, - MMUAccessType access_type); + MMUAccessType access_type, uintptr_t retaddr); #endif #define cpu_signal_handler cpu_mips_signal_handler diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index 222a0d7c7b..61e68cc8be 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -287,23 +287,6 @@ target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx, #ifndef CONFIG_USER_ONLY -static inline hwaddr do_translate_address(CPUMIPSState *env, - target_ulong address, - MMUAccessType access_type, - uintptr_t retaddr) -{ - hwaddr paddr; - CPUState *cs = env_cpu(env); - - paddr = cpu_mips_translate_address(env, address, access_type); - - if (paddr == -1LL) { - cpu_loop_exit_restore(cs, retaddr); - } else { - return paddr; - } -} - #define HELPER_LD_ATOMIC(name, insn, almask, do_cast) \ target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \ { \ @@ -313,7 +296,8 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \ } \ do_raise_exception(env, EXCP_AdEL, GETPC()); \ } \ - env->CP0_LLAddr = do_translate_address(env, arg, MMU_DATA_LOAD, GETPC()); \ + env->CP0_LLAddr = cpu_mips_translate_address(env, arg, MMU_DATA_LOAD, \ + GETPC()); \ env->lladdr = arg; \ env->llval = do_cast cpu_##insn##_mmuidx_ra(env, arg, mem_idx, GETPC()); \ return env->llval; \ diff --git a/target/mips/tlb_helper.c b/target/mips/tlb_helper.c index 8d3ea49780..1ffdc1f830 100644 --- a/target/mips/tlb_helper.c +++ b/target/mips/tlb_helper.c @@ -904,21 +904,22 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, #ifndef CONFIG_USER_ONLY hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, - MMUAccessType access_type) + MMUAccessType access_type, uintptr_t retaddr) { hwaddr physical; int prot; int ret = 0; + CPUState *cs = env_cpu(env); /* data access */ ret = get_physical_address(env, &physical, &prot, address, access_type, cpu_mmu_index(env, false)); - if (ret != TLBRET_MATCH) { - raise_mmu_exception(env, address, access_type, ret); - return -1LL; - } else { + if (ret == TLBRET_MATCH) { return physical; } + + raise_mmu_exception(env, address, access_type, ret); + cpu_loop_exit_restore(cs, retaddr); } static void set_hflags_for_handler(CPUMIPSState *env) From 6f4aec6a6d5524fb89e6dbd71de9920e7ec416e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 10:50:03 +0200 Subject: [PATCH 0188/3028] target/mips: Extract load/store helpers to ldst_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-11-f4bug@amsat.org> --- target/mips/ldst_helper.c | 288 ++++++++++++++++++++++++++++++++++++++ target/mips/meson.build | 1 + target/mips/op_helper.c | 259 ---------------------------------- 3 files changed, 289 insertions(+), 259 deletions(-) create mode 100644 target/mips/ldst_helper.c diff --git a/target/mips/ldst_helper.c b/target/mips/ldst_helper.c new file mode 100644 index 0000000000..d42812b8a6 --- /dev/null +++ b/target/mips/ldst_helper.c @@ -0,0 +1,288 @@ +/* + * MIPS emulation load/store helpers for QEMU. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/memop.h" +#include "internal.h" + +#ifndef CONFIG_USER_ONLY + +#define HELPER_LD_ATOMIC(name, insn, almask, do_cast) \ +target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \ +{ \ + if (arg & almask) { \ + if (!(env->hflags & MIPS_HFLAG_DM)) { \ + env->CP0_BadVAddr = arg; \ + } \ + do_raise_exception(env, EXCP_AdEL, GETPC()); \ + } \ + env->CP0_LLAddr = cpu_mips_translate_address(env, arg, MMU_DATA_LOAD, \ + GETPC()); \ + env->lladdr = arg; \ + env->llval = do_cast cpu_##insn##_mmuidx_ra(env, arg, mem_idx, GETPC()); \ + return env->llval; \ +} +HELPER_LD_ATOMIC(ll, ldl, 0x3, (target_long)(int32_t)) +#ifdef TARGET_MIPS64 +HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong)) +#endif +#undef HELPER_LD_ATOMIC + +#endif /* !CONFIG_USER_ONLY */ + +#ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK(v) ((v) & 3) +#define GET_OFFSET(addr, offset) (addr + (offset)) +#else +#define GET_LMASK(v) (((v) & 3) ^ 3) +#define GET_OFFSET(addr, offset) (addr - (offset)) +#endif + +void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, + int mem_idx) +{ + cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC()); + + if (GET_LMASK(arg2) <= 2) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), + mem_idx, GETPC()); + } + + if (GET_LMASK(arg2) <= 1) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), + mem_idx, GETPC()); + } + + if (GET_LMASK(arg2) == 0) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, + mem_idx, GETPC()); + } +} + +void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, + int mem_idx) +{ + cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC()); + + if (GET_LMASK(arg2) >= 1) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), + mem_idx, GETPC()); + } + + if (GET_LMASK(arg2) >= 2) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), + mem_idx, GETPC()); + } + + if (GET_LMASK(arg2) == 3) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), + mem_idx, GETPC()); + } +} + +#if defined(TARGET_MIPS64) +/* + * "half" load and stores. We must do the memory access inline, + * or fault handling won't work. + */ +#ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK64(v) ((v) & 7) +#else +#define GET_LMASK64(v) (((v) & 7) ^ 7) +#endif + +void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, + int mem_idx) +{ + cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC()); + + if (GET_LMASK64(arg2) <= 6) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) <= 5) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) <= 4) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) <= 3) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) <= 2) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) <= 1) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) <= 0) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, + mem_idx, GETPC()); + } +} + +void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, + int mem_idx) +{ + cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC()); + + if (GET_LMASK64(arg2) >= 1) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) >= 2) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) >= 3) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) >= 4) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) >= 5) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) >= 6) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), + mem_idx, GETPC()); + } + + if (GET_LMASK64(arg2) == 7) { + cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), + mem_idx, GETPC()); + } +} +#endif /* TARGET_MIPS64 */ + +static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 }; + +void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, + uint32_t mem_idx) +{ + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; + + if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) { + target_ulong i; + + for (i = 0; i < base_reglist; i++) { + env->active_tc.gpr[multiple_regs[i]] = + (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC()); + addr += 4; + } + } + + if (do_r31) { + env->active_tc.gpr[31] = + (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC()); + } +} + +void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, + uint32_t mem_idx) +{ + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; + + if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) { + target_ulong i; + + for (i = 0; i < base_reglist; i++) { + cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]], + mem_idx, GETPC()); + addr += 4; + } + } + + if (do_r31) { + cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC()); + } +} + +#if defined(TARGET_MIPS64) +void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, + uint32_t mem_idx) +{ + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; + + if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) { + target_ulong i; + + for (i = 0; i < base_reglist; i++) { + env->active_tc.gpr[multiple_regs[i]] = + cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC()); + addr += 8; + } + } + + if (do_r31) { + env->active_tc.gpr[31] = + cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC()); + } +} + +void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, + uint32_t mem_idx) +{ + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; + + if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) { + target_ulong i; + + for (i = 0; i < base_reglist; i++) { + cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]], + mem_idx, GETPC()); + addr += 8; + } + } + + if (do_r31) { + cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC()); + } +} + +#endif /* TARGET_MIPS64 */ diff --git a/target/mips/meson.build b/target/mips/meson.build index daf5f1d55b..15c2f835c6 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -18,6 +18,7 @@ mips_tcg_ss.add(gen) mips_tcg_ss.add(files( 'dsp_helper.c', 'fpu_helper.c', + 'ldst_helper.c', 'lmmi_helper.c', 'msa_helper.c', 'msa_translate.c', diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index 61e68cc8be..7a7369bc8a 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -285,265 +285,6 @@ target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx, return (int64_t)(int32_t)(uint32_t)tmp5; } -#ifndef CONFIG_USER_ONLY - -#define HELPER_LD_ATOMIC(name, insn, almask, do_cast) \ -target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \ -{ \ - if (arg & almask) { \ - if (!(env->hflags & MIPS_HFLAG_DM)) { \ - env->CP0_BadVAddr = arg; \ - } \ - do_raise_exception(env, EXCP_AdEL, GETPC()); \ - } \ - env->CP0_LLAddr = cpu_mips_translate_address(env, arg, MMU_DATA_LOAD, \ - GETPC()); \ - env->lladdr = arg; \ - env->llval = do_cast cpu_##insn##_mmuidx_ra(env, arg, mem_idx, GETPC()); \ - return env->llval; \ -} -HELPER_LD_ATOMIC(ll, ldl, 0x3, (target_long)(int32_t)) -#ifdef TARGET_MIPS64 -HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong)) -#endif -#undef HELPER_LD_ATOMIC -#endif - -#ifdef TARGET_WORDS_BIGENDIAN -#define GET_LMASK(v) ((v) & 3) -#define GET_OFFSET(addr, offset) (addr + (offset)) -#else -#define GET_LMASK(v) (((v) & 3) ^ 3) -#define GET_OFFSET(addr, offset) (addr - (offset)) -#endif - -void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, - int mem_idx) -{ - cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC()); - - if (GET_LMASK(arg2) <= 2) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), - mem_idx, GETPC()); - } - - if (GET_LMASK(arg2) <= 1) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), - mem_idx, GETPC()); - } - - if (GET_LMASK(arg2) == 0) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, - mem_idx, GETPC()); - } -} - -void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, - int mem_idx) -{ - cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC()); - - if (GET_LMASK(arg2) >= 1) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), - mem_idx, GETPC()); - } - - if (GET_LMASK(arg2) >= 2) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), - mem_idx, GETPC()); - } - - if (GET_LMASK(arg2) == 3) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), - mem_idx, GETPC()); - } -} - -#if defined(TARGET_MIPS64) -/* - * "half" load and stores. We must do the memory access inline, - * or fault handling won't work. - */ -#ifdef TARGET_WORDS_BIGENDIAN -#define GET_LMASK64(v) ((v) & 7) -#else -#define GET_LMASK64(v) (((v) & 7) ^ 7) -#endif - -void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, - int mem_idx) -{ - cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC()); - - if (GET_LMASK64(arg2) <= 6) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) <= 5) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) <= 4) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) <= 3) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) <= 2) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) <= 1) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) <= 0) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, - mem_idx, GETPC()); - } -} - -void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, - int mem_idx) -{ - cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC()); - - if (GET_LMASK64(arg2) >= 1) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) >= 2) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) >= 3) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) >= 4) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) >= 5) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) >= 6) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), - mem_idx, GETPC()); - } - - if (GET_LMASK64(arg2) == 7) { - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), - mem_idx, GETPC()); - } -} -#endif /* TARGET_MIPS64 */ - -static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 }; - -void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, - uint32_t mem_idx) -{ - target_ulong base_reglist = reglist & 0xf; - target_ulong do_r31 = reglist & 0x10; - - if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) { - target_ulong i; - - for (i = 0; i < base_reglist; i++) { - env->active_tc.gpr[multiple_regs[i]] = - (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC()); - addr += 4; - } - } - - if (do_r31) { - env->active_tc.gpr[31] = - (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC()); - } -} - -void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, - uint32_t mem_idx) -{ - target_ulong base_reglist = reglist & 0xf; - target_ulong do_r31 = reglist & 0x10; - - if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) { - target_ulong i; - - for (i = 0; i < base_reglist; i++) { - cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]], - mem_idx, GETPC()); - addr += 4; - } - } - - if (do_r31) { - cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC()); - } -} - -#if defined(TARGET_MIPS64) -void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, - uint32_t mem_idx) -{ - target_ulong base_reglist = reglist & 0xf; - target_ulong do_r31 = reglist & 0x10; - - if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) { - target_ulong i; - - for (i = 0; i < base_reglist; i++) { - env->active_tc.gpr[multiple_regs[i]] = - cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC()); - addr += 8; - } - } - - if (do_r31) { - env->active_tc.gpr[31] = - cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC()); - } -} - -void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, - uint32_t mem_idx) -{ - target_ulong base_reglist = reglist & 0xf; - target_ulong do_r31 = reglist & 0x10; - - if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) { - target_ulong i; - - for (i = 0; i < base_reglist; i++) { - cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]], - mem_idx, GETPC()); - addr += 8; - } - } - - if (do_r31) { - cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC()); - } -} -#endif - - void helper_fork(target_ulong arg1, target_ulong arg2) { /* From 46369b50ee3f72782507a7f88158fa62753be469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 11:27:09 +0200 Subject: [PATCH 0189/3028] meson: Introduce meson_user_arch source set for arch-specific user-mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similarly to the 'target_softmmu_arch' source set which allows to restrict target-specific sources to system emulation, add the equivalent 'target_user_arch' set for user emulation. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-12-f4bug@amsat.org> --- meson.build | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/meson.build b/meson.build index d8bb1ec5aa..1ffdc9e6c4 100644 --- a/meson.build +++ b/meson.build @@ -1751,6 +1751,7 @@ modules = {} hw_arch = {} target_arch = {} target_softmmu_arch = {} +target_user_arch = {} ############### # Trace files # @@ -2168,6 +2169,11 @@ foreach target : target_dirs abi = config_target['TARGET_ABI_DIR'] target_type='user' qemu_target_name = 'qemu-' + target_name + if arch in target_user_arch + t = target_user_arch[arch].apply(config_target, strict: false) + arch_srcs += t.sources() + arch_deps += t.dependencies() + endif if 'CONFIG_LINUX_USER' in config_target base_dir = 'linux-user' target_inc += include_directories('linux-user/host/' / config_host['ARCH']) From 6fe25ce58798815237307cf1924ef5b4d13cac99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 18 Apr 2021 15:09:50 +0200 Subject: [PATCH 0190/3028] target/mips: Introduce tcg-internal.h for TCG specific declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will gradually move TCG-specific declarations to a new local header: "tcg-internal.h". To keep review simple, first add this header with 2 TCG prototypes, which we are going to move in the next 2 commits. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-13-f4bug@amsat.org> --- target/mips/internal.h | 7 +++---- target/mips/tcg/tcg-internal.h | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 target/mips/tcg/tcg-internal.h diff --git a/target/mips/internal.h b/target/mips/internal.h index e93e057bec..754135c142 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -9,6 +9,9 @@ #define MIPS_INTERNAL_H #include "exec/memattrs.h" +#ifdef CONFIG_TCG +#include "tcg/tcg-internal.h" +#endif /* * MMU types, the first four entries have the same layout as the @@ -77,7 +80,6 @@ extern const char fregnames[32][4]; extern const struct mips_def_t mips_defs[]; extern const int mips_defs_number; -void mips_cpu_do_interrupt(CPUState *cpu); bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req); hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int mips_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); @@ -212,9 +214,6 @@ void cpu_mips_stop_count(CPUMIPSState *env); /* helper.c */ void mmu_init(CPUMIPSState *env, const mips_def_t *def); -bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr); /* op_helper.c */ void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask); diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h new file mode 100644 index 0000000000..24438667f4 --- /dev/null +++ b/target/mips/tcg/tcg-internal.h @@ -0,0 +1,20 @@ +/* + * MIPS internal definitions and helpers (TCG accelerator) + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef MIPS_TCG_INTERNAL_H +#define MIPS_TCG_INTERNAL_H + +#include "hw/core/cpu.h" + +void mips_cpu_do_interrupt(CPUState *cpu); +bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); + +#endif From 0a31c16c9ce2639c8706b9f863724ba42a46f121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 18 Apr 2021 15:16:06 +0200 Subject: [PATCH 0191/3028] target/mips: Add simple user-mode mips_cpu_do_interrupt() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The #ifdef'ry hides that the user-mode implementation of mips_cpu_do_interrupt() simply sets exception_index = EXCP_NONE. Add this simple implementation to tcg/user/tlb_helper.c, and the corresponding Meson machinery to build this file when user emulation is configured. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-14-f4bug@amsat.org> --- target/mips/meson.build | 5 +++++ target/mips/tcg/meson.build | 3 +++ target/mips/tcg/user/meson.build | 3 +++ target/mips/tcg/user/tlb_helper.c | 28 ++++++++++++++++++++++++++++ target/mips/tlb_helper.c | 5 ----- 5 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 target/mips/tcg/meson.build create mode 100644 target/mips/tcg/user/meson.build create mode 100644 target/mips/tcg/user/tlb_helper.c diff --git a/target/mips/meson.build b/target/mips/meson.build index 15c2f835c6..ca3cc62cf7 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -6,6 +6,7 @@ gen = [ decodetree.process('tx79.decode', extra_args: '--static-decode=decode_tx79'), ] +mips_user_ss = ss.source_set() mips_ss = ss.source_set() mips_ss.add(files( 'cpu.c', @@ -34,6 +35,9 @@ mips_tcg_ss.add(when: 'TARGET_MIPS64', if_true: files( ), if_false: files( 'mxu_translate.c', )) +if 'CONFIG_TCG' in config_all + subdir('tcg') +endif mips_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) @@ -52,3 +56,4 @@ mips_ss.add_all(when: 'CONFIG_TCG', if_true: [mips_tcg_ss]) target_arch += {'mips': mips_ss} target_softmmu_arch += {'mips': mips_softmmu_ss} +target_user_arch += {'mips': mips_user_ss} diff --git a/target/mips/tcg/meson.build b/target/mips/tcg/meson.build new file mode 100644 index 0000000000..b74fa04303 --- /dev/null +++ b/target/mips/tcg/meson.build @@ -0,0 +1,3 @@ +if have_user + subdir('user') +endif diff --git a/target/mips/tcg/user/meson.build b/target/mips/tcg/user/meson.build new file mode 100644 index 0000000000..79badcd321 --- /dev/null +++ b/target/mips/tcg/user/meson.build @@ -0,0 +1,3 @@ +mips_user_ss.add(files( + 'tlb_helper.c', +)) diff --git a/target/mips/tcg/user/tlb_helper.c b/target/mips/tcg/user/tlb_helper.c new file mode 100644 index 0000000000..453b9e9b93 --- /dev/null +++ b/target/mips/tcg/user/tlb_helper.c @@ -0,0 +1,28 @@ +/* + * MIPS TLB (Translation lookaside buffer) helpers. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "qemu/osdep.h" + +#include "cpu.h" +#include "exec/exec-all.h" +#include "internal.h" + +void mips_cpu_do_interrupt(CPUState *cs) +{ + cs->exception_index = EXCP_NONE; +} diff --git a/target/mips/tlb_helper.c b/target/mips/tlb_helper.c index 1ffdc1f830..78720c4d20 100644 --- a/target/mips/tlb_helper.c +++ b/target/mips/tlb_helper.c @@ -965,11 +965,8 @@ static inline void set_badinstr_registers(CPUMIPSState *env) } } -#endif /* !CONFIG_USER_ONLY */ - void mips_cpu_do_interrupt(CPUState *cs) { -#if !defined(CONFIG_USER_ONLY) MIPSCPU *cpu = MIPS_CPU(cs); CPUMIPSState *env = &cpu->env; bool update_badinstr = 0; @@ -1272,11 +1269,9 @@ void mips_cpu_do_interrupt(CPUState *cs) env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr, env->CP0_DEPC); } -#endif cs->exception_index = EXCP_NONE; } -#if !defined(CONFIG_USER_ONLY) void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra) { CPUState *cs = env_cpu(env); From 8074365fc7ab51c582565f4d77299889e511af5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 11:26:57 +0200 Subject: [PATCH 0192/3028] target/mips: Add simple user-mode mips_cpu_tlb_fill() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tlb_helper.c's #ifdef'ry hides a quite simple user-mode implementation of mips_cpu_tlb_fill(). Copy the user-mode implementation (without #ifdef'ry) to tcg/user/helper.c and simplify tlb_helper.c's #ifdef'ry. This will allow us to restrict tlb_helper.c to sysemu. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-15-f4bug@amsat.org> --- target/mips/tcg/user/tlb_helper.c | 36 +++++++++++++++++++++++++++++++ target/mips/tlb_helper.c | 10 --------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/target/mips/tcg/user/tlb_helper.c b/target/mips/tcg/user/tlb_helper.c index 453b9e9b93..b835144b82 100644 --- a/target/mips/tcg/user/tlb_helper.c +++ b/target/mips/tcg/user/tlb_helper.c @@ -22,6 +22,42 @@ #include "exec/exec-all.h" #include "internal.h" +static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, + MMUAccessType access_type) +{ + CPUState *cs = env_cpu(env); + + env->error_code = 0; + if (access_type == MMU_INST_FETCH) { + env->error_code |= EXCP_INST_NOTAVAIL; + } + + /* Reference to kernel address from user mode or supervisor mode */ + /* Reference to supervisor address from user mode */ + if (access_type == MMU_DATA_STORE) { + cs->exception_index = EXCP_AdES; + } else { + cs->exception_index = EXCP_AdEL; + } + + /* Raise exception */ + if (!(env->hflags & MIPS_HFLAG_DM)) { + env->CP0_BadVAddr = address; + } +} + +bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + + /* data access */ + raise_mmu_exception(env, address, access_type); + do_raise_exception_err(env, cs->exception_index, env->error_code, retaddr); +} + void mips_cpu_do_interrupt(CPUState *cs) { cs->exception_index = EXCP_NONE; diff --git a/target/mips/tlb_helper.c b/target/mips/tlb_helper.c index 78720c4d20..afc019c80d 100644 --- a/target/mips/tlb_helper.c +++ b/target/mips/tlb_helper.c @@ -403,8 +403,6 @@ void cpu_mips_tlb_flush(CPUMIPSState *env) env->tlb->tlb_in_use = env->tlb->nb_tlb; } -#endif /* !CONFIG_USER_ONLY */ - static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, MMUAccessType access_type, int tlb_error) { @@ -484,8 +482,6 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, env->error_code = error_code; } -#if !defined(CONFIG_USER_ONLY) - hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) { MIPSCPU *cpu = MIPS_CPU(cs); @@ -833,7 +829,6 @@ refill: return true; } #endif -#endif /* !CONFIG_USER_ONLY */ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, @@ -841,14 +836,11 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, { MIPSCPU *cpu = MIPS_CPU(cs); CPUMIPSState *env = &cpu->env; -#if !defined(CONFIG_USER_ONLY) hwaddr physical; int prot; -#endif int ret = TLBRET_BADADDR; /* data access */ -#if !defined(CONFIG_USER_ONLY) /* XXX: put correct access by using cpu_restore_state() correctly */ ret = get_physical_address(env, &physical, &prot, address, access_type, mmu_idx); @@ -896,13 +888,11 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, if (probe) { return false; } -#endif raise_mmu_exception(env, address, access_type, ret); do_raise_exception_err(env, cs->exception_index, env->error_code, retaddr); } -#ifndef CONFIG_USER_ONLY hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, MMUAccessType access_type, uintptr_t retaddr) { From 44e3b05005c6696cd526a4575293513db453f4b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 18 Apr 2021 15:22:34 +0200 Subject: [PATCH 0193/3028] target/mips: Move cpu_signal_handler definition around MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have 2 blocks guarded with #ifdef for sysemu, which are simply separated by the cpu_signal_handler definition. To simplify the following commits which involve various changes in internal.h, first join the sysemu-guarded blocks. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-16-f4bug@amsat.org> --- target/mips/internal.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/target/mips/internal.h b/target/mips/internal.h index 754135c142..3c8ccfbe92 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -151,14 +151,13 @@ void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, MemTxResult response, uintptr_t retaddr); hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, MMUAccessType access_type, uintptr_t retaddr); -#endif + +extern const VMStateDescription vmstate_mips_cpu; + +#endif /* !CONFIG_USER_ONLY */ #define cpu_signal_handler cpu_mips_signal_handler -#ifndef CONFIG_USER_ONLY -extern const VMStateDescription vmstate_mips_cpu; -#endif - static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env) { return (env->CP0_Status & (1 << CP0St_IE)) && From 85d8da3fea0c4ff38bbe759febfc2d2299b33ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 10:31:44 +0200 Subject: [PATCH 0194/3028] target/mips: Move sysemu specific files under sysemu/ subfolder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move sysemu-specific files under the new sysemu/ subfolder and adapt the Meson machinery. Update the KVM MIPS entry in MAINTAINERS. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-17-f4bug@amsat.org> --- MAINTAINERS | 3 ++- target/mips/meson.build | 12 ++++++------ target/mips/{ => sysemu}/addr.c | 0 target/mips/{ => sysemu}/cp0_timer.c | 0 target/mips/{ => sysemu}/machine.c | 0 target/mips/sysemu/meson.build | 5 +++++ 6 files changed, 13 insertions(+), 7 deletions(-) rename target/mips/{ => sysemu}/addr.c (100%) rename target/mips/{ => sysemu}/cp0_timer.c (100%) rename target/mips/{ => sysemu}/machine.c (100%) create mode 100644 target/mips/sysemu/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index 4c05ff8bba..8e4e329810 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -404,7 +404,8 @@ F: target/arm/kvm.c MIPS KVM CPUs M: Huacai Chen S: Odd Fixes -F: target/mips/kvm.c +F: target/mips/kvm* +F: target/mips/sysemu/ PPC KVM CPUs M: David Gibson diff --git a/target/mips/meson.build b/target/mips/meson.build index ca3cc62cf7..9a507937ec 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -7,6 +7,7 @@ gen = [ ] mips_user_ss = ss.source_set() +mips_softmmu_ss = ss.source_set() mips_ss = ss.source_set() mips_ss.add(files( 'cpu.c', @@ -14,6 +15,11 @@ mips_ss.add(files( 'gdbstub.c', 'msa.c', )) + +if have_system + subdir('sysemu') +endif + mips_tcg_ss = ss.source_set() mips_tcg_ss.add(gen) mips_tcg_ss.add(files( @@ -41,12 +47,6 @@ endif mips_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) -mips_softmmu_ss = ss.source_set() -mips_softmmu_ss.add(files( - 'addr.c', - 'cp0_timer.c', - 'machine.c', -)) mips_softmmu_ss.add(when: 'CONFIG_TCG', if_true: files( 'cp0_helper.c', 'mips-semi.c', diff --git a/target/mips/addr.c b/target/mips/sysemu/addr.c similarity index 100% rename from target/mips/addr.c rename to target/mips/sysemu/addr.c diff --git a/target/mips/cp0_timer.c b/target/mips/sysemu/cp0_timer.c similarity index 100% rename from target/mips/cp0_timer.c rename to target/mips/sysemu/cp0_timer.c diff --git a/target/mips/machine.c b/target/mips/sysemu/machine.c similarity index 100% rename from target/mips/machine.c rename to target/mips/sysemu/machine.c diff --git a/target/mips/sysemu/meson.build b/target/mips/sysemu/meson.build new file mode 100644 index 0000000000..f2a1ff4608 --- /dev/null +++ b/target/mips/sysemu/meson.build @@ -0,0 +1,5 @@ +mips_softmmu_ss.add(files( + 'addr.c', + 'cp0_timer.c', + 'machine.c', +)) From 137f4d87c6dd3c727fd5b5e777e89f610b51ae8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 10:33:23 +0200 Subject: [PATCH 0195/3028] target/mips: Move physical addressing code to sysemu/physaddr.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare get_physical_address() with local scope and move it along with mips_cpu_get_phys_page_debug() to sysemu/physaddr.c new file. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-18-f4bug@amsat.org> --- target/mips/internal.h | 25 +++- target/mips/sysemu/meson.build | 1 + target/mips/sysemu/physaddr.c | 257 +++++++++++++++++++++++++++++++++ target/mips/tlb_helper.c | 254 -------------------------------- 4 files changed, 282 insertions(+), 255 deletions(-) create mode 100644 target/mips/sysemu/physaddr.c diff --git a/target/mips/internal.h b/target/mips/internal.h index 3c8ccfbe92..be32102a2a 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -81,15 +81,38 @@ extern const struct mips_def_t mips_defs[]; extern const int mips_defs_number; bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req); -hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int mips_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); +#define USEG_LIMIT ((target_ulong)(int32_t)0x7FFFFFFFUL) +#define KSEG0_BASE ((target_ulong)(int32_t)0x80000000UL) +#define KSEG1_BASE ((target_ulong)(int32_t)0xA0000000UL) +#define KSEG2_BASE ((target_ulong)(int32_t)0xC0000000UL) +#define KSEG3_BASE ((target_ulong)(int32_t)0xE0000000UL) + +#define KVM_KSEG0_BASE ((target_ulong)(int32_t)0x40000000UL) +#define KVM_KSEG2_BASE ((target_ulong)(int32_t)0x60000000UL) + #if !defined(CONFIG_USER_ONLY) +enum { + TLBRET_XI = -6, + TLBRET_RI = -5, + TLBRET_DIRTY = -4, + TLBRET_INVALID = -3, + TLBRET_NOMATCH = -2, + TLBRET_BADADDR = -1, + TLBRET_MATCH = 0 +}; + +int get_physical_address(CPUMIPSState *env, hwaddr *physical, + int *prot, target_ulong real_address, + MMUAccessType access_type, int mmu_idx); +hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); + typedef struct r4k_tlb_t r4k_tlb_t; struct r4k_tlb_t { target_ulong VPN; diff --git a/target/mips/sysemu/meson.build b/target/mips/sysemu/meson.build index f2a1ff4608..925ceeaa44 100644 --- a/target/mips/sysemu/meson.build +++ b/target/mips/sysemu/meson.build @@ -2,4 +2,5 @@ mips_softmmu_ss.add(files( 'addr.c', 'cp0_timer.c', 'machine.c', + 'physaddr.c', )) diff --git a/target/mips/sysemu/physaddr.c b/target/mips/sysemu/physaddr.c new file mode 100644 index 0000000000..1918633aa1 --- /dev/null +++ b/target/mips/sysemu/physaddr.c @@ -0,0 +1,257 @@ +/* + * MIPS TLB (Translation lookaside buffer) helpers. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "../internal.h" + +static int is_seg_am_mapped(unsigned int am, bool eu, int mmu_idx) +{ + /* + * Interpret access control mode and mmu_idx. + * AdE? TLB? + * AM K S U E K S U E + * UK 0 0 1 1 0 0 - - 0 + * MK 1 0 1 1 0 1 - - !eu + * MSK 2 0 0 1 0 1 1 - !eu + * MUSK 3 0 0 0 0 1 1 1 !eu + * MUSUK 4 0 0 0 0 0 1 1 0 + * USK 5 0 0 1 0 0 0 - 0 + * - 6 - - - - - - - - + * UUSK 7 0 0 0 0 0 0 0 0 + */ + int32_t adetlb_mask; + + switch (mmu_idx) { + case 3: /* ERL */ + /* If EU is set, always unmapped */ + if (eu) { + return 0; + } + /* fall through */ + case MIPS_HFLAG_KM: + /* Never AdE, TLB mapped if AM={1,2,3} */ + adetlb_mask = 0x70000000; + goto check_tlb; + + case MIPS_HFLAG_SM: + /* AdE if AM={0,1}, TLB mapped if AM={2,3,4} */ + adetlb_mask = 0xc0380000; + goto check_ade; + + case MIPS_HFLAG_UM: + /* AdE if AM={0,1,2,5}, TLB mapped if AM={3,4} */ + adetlb_mask = 0xe4180000; + /* fall through */ + check_ade: + /* does this AM cause AdE in current execution mode */ + if ((adetlb_mask << am) < 0) { + return TLBRET_BADADDR; + } + adetlb_mask <<= 8; + /* fall through */ + check_tlb: + /* is this AM mapped in current execution mode */ + return ((adetlb_mask << am) < 0); + default: + assert(0); + return TLBRET_BADADDR; + }; +} + +static int get_seg_physical_address(CPUMIPSState *env, hwaddr *physical, + int *prot, target_ulong real_address, + MMUAccessType access_type, int mmu_idx, + unsigned int am, bool eu, + target_ulong segmask, + hwaddr physical_base) +{ + int mapped = is_seg_am_mapped(am, eu, mmu_idx); + + if (mapped < 0) { + /* is_seg_am_mapped can report TLBRET_BADADDR */ + return mapped; + } else if (mapped) { + /* The segment is TLB mapped */ + return env->tlb->map_address(env, physical, prot, real_address, + access_type); + } else { + /* The segment is unmapped */ + *physical = physical_base | (real_address & segmask); + *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + return TLBRET_MATCH; + } +} + +static int get_segctl_physical_address(CPUMIPSState *env, hwaddr *physical, + int *prot, target_ulong real_address, + MMUAccessType access_type, int mmu_idx, + uint16_t segctl, target_ulong segmask) +{ + unsigned int am = (segctl & CP0SC_AM_MASK) >> CP0SC_AM; + bool eu = (segctl >> CP0SC_EU) & 1; + hwaddr pa = ((hwaddr)segctl & CP0SC_PA_MASK) << 20; + + return get_seg_physical_address(env, physical, prot, real_address, + access_type, mmu_idx, am, eu, segmask, + pa & ~(hwaddr)segmask); +} + +int get_physical_address(CPUMIPSState *env, hwaddr *physical, + int *prot, target_ulong real_address, + MMUAccessType access_type, int mmu_idx) +{ + /* User mode can only access useg/xuseg */ +#if defined(TARGET_MIPS64) + int user_mode = mmu_idx == MIPS_HFLAG_UM; + int supervisor_mode = mmu_idx == MIPS_HFLAG_SM; + int kernel_mode = !user_mode && !supervisor_mode; + int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; + int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; + int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; +#endif + int ret = TLBRET_MATCH; + /* effective address (modified for KVM T&E kernel segments) */ + target_ulong address = real_address; + + if (mips_um_ksegs_enabled()) { + /* KVM T&E adds guest kernel segments in useg */ + if (real_address >= KVM_KSEG0_BASE) { + if (real_address < KVM_KSEG2_BASE) { + /* kseg0 */ + address += KSEG0_BASE - KVM_KSEG0_BASE; + } else if (real_address <= USEG_LIMIT) { + /* kseg2/3 */ + address += KSEG2_BASE - KVM_KSEG2_BASE; + } + } + } + + if (address <= USEG_LIMIT) { + /* useg */ + uint16_t segctl; + + if (address >= 0x40000000UL) { + segctl = env->CP0_SegCtl2; + } else { + segctl = env->CP0_SegCtl2 >> 16; + } + ret = get_segctl_physical_address(env, physical, prot, + real_address, access_type, + mmu_idx, segctl, 0x3FFFFFFF); +#if defined(TARGET_MIPS64) + } else if (address < 0x4000000000000000ULL) { + /* xuseg */ + if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { + ret = env->tlb->map_address(env, physical, prot, + real_address, access_type); + } else { + ret = TLBRET_BADADDR; + } + } else if (address < 0x8000000000000000ULL) { + /* xsseg */ + if ((supervisor_mode || kernel_mode) && + SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { + ret = env->tlb->map_address(env, physical, prot, + real_address, access_type); + } else { + ret = TLBRET_BADADDR; + } + } else if (address < 0xC000000000000000ULL) { + /* xkphys */ + if ((address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) { + /* KX/SX/UX bit to check for each xkphys EVA access mode */ + static const uint8_t am_ksux[8] = { + [CP0SC_AM_UK] = (1u << CP0St_KX), + [CP0SC_AM_MK] = (1u << CP0St_KX), + [CP0SC_AM_MSK] = (1u << CP0St_SX), + [CP0SC_AM_MUSK] = (1u << CP0St_UX), + [CP0SC_AM_MUSUK] = (1u << CP0St_UX), + [CP0SC_AM_USK] = (1u << CP0St_SX), + [6] = (1u << CP0St_KX), + [CP0SC_AM_UUSK] = (1u << CP0St_UX), + }; + unsigned int am = CP0SC_AM_UK; + unsigned int xr = (env->CP0_SegCtl2 & CP0SC2_XR_MASK) >> CP0SC2_XR; + + if (xr & (1 << ((address >> 59) & 0x7))) { + am = (env->CP0_SegCtl1 & CP0SC1_XAM_MASK) >> CP0SC1_XAM; + } + /* Does CP0_Status.KX/SX/UX permit the access mode (am) */ + if (env->CP0_Status & am_ksux[am]) { + ret = get_seg_physical_address(env, physical, prot, + real_address, access_type, + mmu_idx, am, false, env->PAMask, + 0); + } else { + ret = TLBRET_BADADDR; + } + } else { + ret = TLBRET_BADADDR; + } + } else if (address < 0xFFFFFFFF80000000ULL) { + /* xkseg */ + if (kernel_mode && KX && + address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { + ret = env->tlb->map_address(env, physical, prot, + real_address, access_type); + } else { + ret = TLBRET_BADADDR; + } +#endif + } else if (address < KSEG1_BASE) { + /* kseg0 */ + ret = get_segctl_physical_address(env, physical, prot, real_address, + access_type, mmu_idx, + env->CP0_SegCtl1 >> 16, 0x1FFFFFFF); + } else if (address < KSEG2_BASE) { + /* kseg1 */ + ret = get_segctl_physical_address(env, physical, prot, real_address, + access_type, mmu_idx, + env->CP0_SegCtl1, 0x1FFFFFFF); + } else if (address < KSEG3_BASE) { + /* sseg (kseg2) */ + ret = get_segctl_physical_address(env, physical, prot, real_address, + access_type, mmu_idx, + env->CP0_SegCtl0 >> 16, 0x1FFFFFFF); + } else { + /* + * kseg3 + * XXX: debug segment is not emulated + */ + ret = get_segctl_physical_address(env, physical, prot, real_address, + access_type, mmu_idx, + env->CP0_SegCtl0, 0x1FFFFFFF); + } + return ret; +} + +hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + hwaddr phys_addr; + int prot; + + if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD, + cpu_mmu_index(env, false)) != 0) { + return -1; + } + return phys_addr; +} diff --git a/target/mips/tlb_helper.c b/target/mips/tlb_helper.c index afc019c80d..bfb08eaf50 100644 --- a/target/mips/tlb_helper.c +++ b/target/mips/tlb_helper.c @@ -25,16 +25,6 @@ #include "exec/log.h" #include "hw/mips/cpudevs.h" -enum { - TLBRET_XI = -6, - TLBRET_RI = -5, - TLBRET_DIRTY = -4, - TLBRET_INVALID = -3, - TLBRET_NOMATCH = -2, - TLBRET_BADADDR = -1, - TLBRET_MATCH = 0 -}; - #if !defined(CONFIG_USER_ONLY) /* no MMU emulation */ @@ -166,236 +156,6 @@ void mmu_init(CPUMIPSState *env, const mips_def_t *def) } } -static int is_seg_am_mapped(unsigned int am, bool eu, int mmu_idx) -{ - /* - * Interpret access control mode and mmu_idx. - * AdE? TLB? - * AM K S U E K S U E - * UK 0 0 1 1 0 0 - - 0 - * MK 1 0 1 1 0 1 - - !eu - * MSK 2 0 0 1 0 1 1 - !eu - * MUSK 3 0 0 0 0 1 1 1 !eu - * MUSUK 4 0 0 0 0 0 1 1 0 - * USK 5 0 0 1 0 0 0 - 0 - * - 6 - - - - - - - - - * UUSK 7 0 0 0 0 0 0 0 0 - */ - int32_t adetlb_mask; - - switch (mmu_idx) { - case 3: /* ERL */ - /* If EU is set, always unmapped */ - if (eu) { - return 0; - } - /* fall through */ - case MIPS_HFLAG_KM: - /* Never AdE, TLB mapped if AM={1,2,3} */ - adetlb_mask = 0x70000000; - goto check_tlb; - - case MIPS_HFLAG_SM: - /* AdE if AM={0,1}, TLB mapped if AM={2,3,4} */ - adetlb_mask = 0xc0380000; - goto check_ade; - - case MIPS_HFLAG_UM: - /* AdE if AM={0,1,2,5}, TLB mapped if AM={3,4} */ - adetlb_mask = 0xe4180000; - /* fall through */ - check_ade: - /* does this AM cause AdE in current execution mode */ - if ((adetlb_mask << am) < 0) { - return TLBRET_BADADDR; - } - adetlb_mask <<= 8; - /* fall through */ - check_tlb: - /* is this AM mapped in current execution mode */ - return ((adetlb_mask << am) < 0); - default: - assert(0); - return TLBRET_BADADDR; - }; -} - -static int get_seg_physical_address(CPUMIPSState *env, hwaddr *physical, - int *prot, target_ulong real_address, - MMUAccessType access_type, int mmu_idx, - unsigned int am, bool eu, - target_ulong segmask, - hwaddr physical_base) -{ - int mapped = is_seg_am_mapped(am, eu, mmu_idx); - - if (mapped < 0) { - /* is_seg_am_mapped can report TLBRET_BADADDR */ - return mapped; - } else if (mapped) { - /* The segment is TLB mapped */ - return env->tlb->map_address(env, physical, prot, real_address, - access_type); - } else { - /* The segment is unmapped */ - *physical = physical_base | (real_address & segmask); - *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - return TLBRET_MATCH; - } -} - -static int get_segctl_physical_address(CPUMIPSState *env, hwaddr *physical, - int *prot, target_ulong real_address, - MMUAccessType access_type, int mmu_idx, - uint16_t segctl, target_ulong segmask) -{ - unsigned int am = (segctl & CP0SC_AM_MASK) >> CP0SC_AM; - bool eu = (segctl >> CP0SC_EU) & 1; - hwaddr pa = ((hwaddr)segctl & CP0SC_PA_MASK) << 20; - - return get_seg_physical_address(env, physical, prot, real_address, - access_type, mmu_idx, am, eu, segmask, - pa & ~(hwaddr)segmask); -} - -static int get_physical_address(CPUMIPSState *env, hwaddr *physical, - int *prot, target_ulong real_address, - MMUAccessType access_type, int mmu_idx) -{ - /* User mode can only access useg/xuseg */ -#if defined(TARGET_MIPS64) - int user_mode = mmu_idx == MIPS_HFLAG_UM; - int supervisor_mode = mmu_idx == MIPS_HFLAG_SM; - int kernel_mode = !user_mode && !supervisor_mode; - int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0; - int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0; - int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0; -#endif - int ret = TLBRET_MATCH; - /* effective address (modified for KVM T&E kernel segments) */ - target_ulong address = real_address; - -#define USEG_LIMIT ((target_ulong)(int32_t)0x7FFFFFFFUL) -#define KSEG0_BASE ((target_ulong)(int32_t)0x80000000UL) -#define KSEG1_BASE ((target_ulong)(int32_t)0xA0000000UL) -#define KSEG2_BASE ((target_ulong)(int32_t)0xC0000000UL) -#define KSEG3_BASE ((target_ulong)(int32_t)0xE0000000UL) - -#define KVM_KSEG0_BASE ((target_ulong)(int32_t)0x40000000UL) -#define KVM_KSEG2_BASE ((target_ulong)(int32_t)0x60000000UL) - - if (mips_um_ksegs_enabled()) { - /* KVM T&E adds guest kernel segments in useg */ - if (real_address >= KVM_KSEG0_BASE) { - if (real_address < KVM_KSEG2_BASE) { - /* kseg0 */ - address += KSEG0_BASE - KVM_KSEG0_BASE; - } else if (real_address <= USEG_LIMIT) { - /* kseg2/3 */ - address += KSEG2_BASE - KVM_KSEG2_BASE; - } - } - } - - if (address <= USEG_LIMIT) { - /* useg */ - uint16_t segctl; - - if (address >= 0x40000000UL) { - segctl = env->CP0_SegCtl2; - } else { - segctl = env->CP0_SegCtl2 >> 16; - } - ret = get_segctl_physical_address(env, physical, prot, - real_address, access_type, - mmu_idx, segctl, 0x3FFFFFFF); -#if defined(TARGET_MIPS64) - } else if (address < 0x4000000000000000ULL) { - /* xuseg */ - if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) { - ret = env->tlb->map_address(env, physical, prot, - real_address, access_type); - } else { - ret = TLBRET_BADADDR; - } - } else if (address < 0x8000000000000000ULL) { - /* xsseg */ - if ((supervisor_mode || kernel_mode) && - SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) { - ret = env->tlb->map_address(env, physical, prot, - real_address, access_type); - } else { - ret = TLBRET_BADADDR; - } - } else if (address < 0xC000000000000000ULL) { - /* xkphys */ - if ((address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) { - /* KX/SX/UX bit to check for each xkphys EVA access mode */ - static const uint8_t am_ksux[8] = { - [CP0SC_AM_UK] = (1u << CP0St_KX), - [CP0SC_AM_MK] = (1u << CP0St_KX), - [CP0SC_AM_MSK] = (1u << CP0St_SX), - [CP0SC_AM_MUSK] = (1u << CP0St_UX), - [CP0SC_AM_MUSUK] = (1u << CP0St_UX), - [CP0SC_AM_USK] = (1u << CP0St_SX), - [6] = (1u << CP0St_KX), - [CP0SC_AM_UUSK] = (1u << CP0St_UX), - }; - unsigned int am = CP0SC_AM_UK; - unsigned int xr = (env->CP0_SegCtl2 & CP0SC2_XR_MASK) >> CP0SC2_XR; - - if (xr & (1 << ((address >> 59) & 0x7))) { - am = (env->CP0_SegCtl1 & CP0SC1_XAM_MASK) >> CP0SC1_XAM; - } - /* Does CP0_Status.KX/SX/UX permit the access mode (am) */ - if (env->CP0_Status & am_ksux[am]) { - ret = get_seg_physical_address(env, physical, prot, - real_address, access_type, - mmu_idx, am, false, env->PAMask, - 0); - } else { - ret = TLBRET_BADADDR; - } - } else { - ret = TLBRET_BADADDR; - } - } else if (address < 0xFFFFFFFF80000000ULL) { - /* xkseg */ - if (kernel_mode && KX && - address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) { - ret = env->tlb->map_address(env, physical, prot, - real_address, access_type); - } else { - ret = TLBRET_BADADDR; - } -#endif - } else if (address < KSEG1_BASE) { - /* kseg0 */ - ret = get_segctl_physical_address(env, physical, prot, real_address, - access_type, mmu_idx, - env->CP0_SegCtl1 >> 16, 0x1FFFFFFF); - } else if (address < KSEG2_BASE) { - /* kseg1 */ - ret = get_segctl_physical_address(env, physical, prot, real_address, - access_type, mmu_idx, - env->CP0_SegCtl1, 0x1FFFFFFF); - } else if (address < KSEG3_BASE) { - /* sseg (kseg2) */ - ret = get_segctl_physical_address(env, physical, prot, real_address, - access_type, mmu_idx, - env->CP0_SegCtl0 >> 16, 0x1FFFFFFF); - } else { - /* - * kseg3 - * XXX: debug segment is not emulated - */ - ret = get_segctl_physical_address(env, physical, prot, real_address, - access_type, mmu_idx, - env->CP0_SegCtl0, 0x1FFFFFFF); - } - return ret; -} - void cpu_mips_tlb_flush(CPUMIPSState *env) { /* Flush qemu's TLB and discard all shadowed entries. */ @@ -482,20 +242,6 @@ static void raise_mmu_exception(CPUMIPSState *env, target_ulong address, env->error_code = error_code; } -hwaddr mips_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -{ - MIPSCPU *cpu = MIPS_CPU(cs); - CPUMIPSState *env = &cpu->env; - hwaddr phys_addr; - int prot; - - if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD, - cpu_mmu_index(env, false)) != 0) { - return -1; - } - return phys_addr; -} - #if !defined(TARGET_MIPS64) /* From 8b28cde403468c2f8feff4d97a9c2b98ea3d8adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 19 Apr 2021 00:43:02 +0200 Subject: [PATCH 0196/3028] target/mips: Restrict cpu_mips_get_random() / update_pagemask() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-19-f4bug@amsat.org> --- target/mips/internal.h | 4 ---- target/mips/tcg/tcg-internal.h | 9 +++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/target/mips/internal.h b/target/mips/internal.h index be32102a2a..6bac8ef704 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -165,7 +165,6 @@ void r4k_helper_tlbr(CPUMIPSState *env); void r4k_helper_tlbinv(CPUMIPSState *env); void r4k_helper_tlbinvf(CPUMIPSState *env); void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra); -uint32_t cpu_mips_get_random(CPUMIPSState *env); void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, unsigned size, @@ -237,9 +236,6 @@ void cpu_mips_stop_count(CPUMIPSState *env); /* helper.c */ void mmu_init(CPUMIPSState *env, const mips_def_t *def); -/* op_helper.c */ -void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask); - static inline void mips_env_set_pc(CPUMIPSState *env, target_ulong value) { env->active_tc.PC = value & ~(target_ulong)1; diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h index 24438667f4..b65580af21 100644 --- a/target/mips/tcg/tcg-internal.h +++ b/target/mips/tcg/tcg-internal.h @@ -11,10 +11,19 @@ #define MIPS_TCG_INTERNAL_H #include "hw/core/cpu.h" +#include "cpu.h" void mips_cpu_do_interrupt(CPUState *cpu); bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); +#if !defined(CONFIG_USER_ONLY) + +void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask); + +uint32_t cpu_mips_get_random(CPUMIPSState *env); + +#endif /* !CONFIG_USER_ONLY */ + #endif From ad520a978447bca03374b71e90d948826e669603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 11:51:53 +0200 Subject: [PATCH 0197/3028] target/mips: Move sysemu TCG-specific code to tcg/sysemu/ subfolder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move cp0_helper.c and mips-semi.c to the new tcg/sysemu/ folder, adapting the Meson machinery. Move the opcode definitions to tcg/sysemu_helper.h.inc. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-20-f4bug@amsat.org> --- target/mips/helper.h | 166 +-------------------- target/mips/meson.build | 5 - target/mips/tcg/meson.build | 3 + target/mips/{ => tcg/sysemu}/cp0_helper.c | 0 target/mips/tcg/sysemu/meson.build | 4 + target/mips/{ => tcg/sysemu}/mips-semi.c | 0 target/mips/tcg/sysemu_helper.h.inc | 168 ++++++++++++++++++++++ 7 files changed, 179 insertions(+), 167 deletions(-) rename target/mips/{ => tcg/sysemu}/cp0_helper.c (100%) create mode 100644 target/mips/tcg/sysemu/meson.build rename target/mips/{ => tcg/sysemu}/mips-semi.c (100%) create mode 100644 target/mips/tcg/sysemu_helper.h.inc diff --git a/target/mips/helper.h b/target/mips/helper.h index 709494445d..bc308e5db1 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -2,10 +2,6 @@ DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) DEF_HELPER_2(raise_exception, noreturn, env, i32) DEF_HELPER_1(raise_exception_debug, noreturn, env) -#ifndef CONFIG_USER_ONLY -DEF_HELPER_1(do_semihosting, void, env) -#endif - #ifdef TARGET_MIPS64 DEF_HELPER_4(sdl, void, env, tl, tl, int) DEF_HELPER_4(sdr, void, env, tl, tl, int) @@ -42,164 +38,6 @@ DEF_HELPER_FLAGS_1(dbitswap, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_4(rotx, TCG_CALL_NO_RWG_SE, tl, tl, i32, i32, i32) -#ifndef CONFIG_USER_ONLY -/* CP0 helpers */ -DEF_HELPER_1(mfc0_mvpcontrol, tl, env) -DEF_HELPER_1(mfc0_mvpconf0, tl, env) -DEF_HELPER_1(mfc0_mvpconf1, tl, env) -DEF_HELPER_1(mftc0_vpecontrol, tl, env) -DEF_HELPER_1(mftc0_vpeconf0, tl, env) -DEF_HELPER_1(mfc0_random, tl, env) -DEF_HELPER_1(mfc0_tcstatus, tl, env) -DEF_HELPER_1(mftc0_tcstatus, tl, env) -DEF_HELPER_1(mfc0_tcbind, tl, env) -DEF_HELPER_1(mftc0_tcbind, tl, env) -DEF_HELPER_1(mfc0_tcrestart, tl, env) -DEF_HELPER_1(mftc0_tcrestart, tl, env) -DEF_HELPER_1(mfc0_tchalt, tl, env) -DEF_HELPER_1(mftc0_tchalt, tl, env) -DEF_HELPER_1(mfc0_tccontext, tl, env) -DEF_HELPER_1(mftc0_tccontext, tl, env) -DEF_HELPER_1(mfc0_tcschedule, tl, env) -DEF_HELPER_1(mftc0_tcschedule, tl, env) -DEF_HELPER_1(mfc0_tcschefback, tl, env) -DEF_HELPER_1(mftc0_tcschefback, tl, env) -DEF_HELPER_1(mfc0_count, tl, env) -DEF_HELPER_1(mfc0_saar, tl, env) -DEF_HELPER_1(mfhc0_saar, tl, env) -DEF_HELPER_1(mftc0_entryhi, tl, env) -DEF_HELPER_1(mftc0_status, tl, env) -DEF_HELPER_1(mftc0_cause, tl, env) -DEF_HELPER_1(mftc0_epc, tl, env) -DEF_HELPER_1(mftc0_ebase, tl, env) -DEF_HELPER_2(mftc0_configx, tl, env, tl) -DEF_HELPER_1(mfc0_lladdr, tl, env) -DEF_HELPER_1(mfc0_maar, tl, env) -DEF_HELPER_1(mfhc0_maar, tl, env) -DEF_HELPER_2(mfc0_watchlo, tl, env, i32) -DEF_HELPER_2(mfc0_watchhi, tl, env, i32) -DEF_HELPER_2(mfhc0_watchhi, tl, env, i32) -DEF_HELPER_1(mfc0_debug, tl, env) -DEF_HELPER_1(mftc0_debug, tl, env) -#ifdef TARGET_MIPS64 -DEF_HELPER_1(dmfc0_tcrestart, tl, env) -DEF_HELPER_1(dmfc0_tchalt, tl, env) -DEF_HELPER_1(dmfc0_tccontext, tl, env) -DEF_HELPER_1(dmfc0_tcschedule, tl, env) -DEF_HELPER_1(dmfc0_tcschefback, tl, env) -DEF_HELPER_1(dmfc0_lladdr, tl, env) -DEF_HELPER_1(dmfc0_maar, tl, env) -DEF_HELPER_2(dmfc0_watchlo, tl, env, i32) -DEF_HELPER_2(dmfc0_watchhi, tl, env, i32) -DEF_HELPER_1(dmfc0_saar, tl, env) -#endif /* TARGET_MIPS64 */ - -DEF_HELPER_2(mtc0_index, void, env, tl) -DEF_HELPER_2(mtc0_mvpcontrol, void, env, tl) -DEF_HELPER_2(mtc0_vpecontrol, void, env, tl) -DEF_HELPER_2(mttc0_vpecontrol, void, env, tl) -DEF_HELPER_2(mtc0_vpeconf0, void, env, tl) -DEF_HELPER_2(mttc0_vpeconf0, void, env, tl) -DEF_HELPER_2(mtc0_vpeconf1, void, env, tl) -DEF_HELPER_2(mtc0_yqmask, void, env, tl) -DEF_HELPER_2(mtc0_vpeopt, void, env, tl) -DEF_HELPER_2(mtc0_entrylo0, void, env, tl) -DEF_HELPER_2(mtc0_tcstatus, void, env, tl) -DEF_HELPER_2(mttc0_tcstatus, void, env, tl) -DEF_HELPER_2(mtc0_tcbind, void, env, tl) -DEF_HELPER_2(mttc0_tcbind, void, env, tl) -DEF_HELPER_2(mtc0_tcrestart, void, env, tl) -DEF_HELPER_2(mttc0_tcrestart, void, env, tl) -DEF_HELPER_2(mtc0_tchalt, void, env, tl) -DEF_HELPER_2(mttc0_tchalt, void, env, tl) -DEF_HELPER_2(mtc0_tccontext, void, env, tl) -DEF_HELPER_2(mttc0_tccontext, void, env, tl) -DEF_HELPER_2(mtc0_tcschedule, void, env, tl) -DEF_HELPER_2(mttc0_tcschedule, void, env, tl) -DEF_HELPER_2(mtc0_tcschefback, void, env, tl) -DEF_HELPER_2(mttc0_tcschefback, void, env, tl) -DEF_HELPER_2(mtc0_entrylo1, void, env, tl) -DEF_HELPER_2(mtc0_context, void, env, tl) -DEF_HELPER_2(mtc0_memorymapid, void, env, tl) -DEF_HELPER_2(mtc0_pagemask, void, env, tl) -DEF_HELPER_2(mtc0_pagegrain, void, env, tl) -DEF_HELPER_2(mtc0_segctl0, void, env, tl) -DEF_HELPER_2(mtc0_segctl1, void, env, tl) -DEF_HELPER_2(mtc0_segctl2, void, env, tl) -DEF_HELPER_2(mtc0_pwfield, void, env, tl) -DEF_HELPER_2(mtc0_pwsize, void, env, tl) -DEF_HELPER_2(mtc0_wired, void, env, tl) -DEF_HELPER_2(mtc0_srsconf0, void, env, tl) -DEF_HELPER_2(mtc0_srsconf1, void, env, tl) -DEF_HELPER_2(mtc0_srsconf2, void, env, tl) -DEF_HELPER_2(mtc0_srsconf3, void, env, tl) -DEF_HELPER_2(mtc0_srsconf4, void, env, tl) -DEF_HELPER_2(mtc0_hwrena, void, env, tl) -DEF_HELPER_2(mtc0_pwctl, void, env, tl) -DEF_HELPER_2(mtc0_count, void, env, tl) -DEF_HELPER_2(mtc0_saari, void, env, tl) -DEF_HELPER_2(mtc0_saar, void, env, tl) -DEF_HELPER_2(mthc0_saar, void, env, tl) -DEF_HELPER_2(mtc0_entryhi, void, env, tl) -DEF_HELPER_2(mttc0_entryhi, void, env, tl) -DEF_HELPER_2(mtc0_compare, void, env, tl) -DEF_HELPER_2(mtc0_status, void, env, tl) -DEF_HELPER_2(mttc0_status, void, env, tl) -DEF_HELPER_2(mtc0_intctl, void, env, tl) -DEF_HELPER_2(mtc0_srsctl, void, env, tl) -DEF_HELPER_2(mtc0_cause, void, env, tl) -DEF_HELPER_2(mttc0_cause, void, env, tl) -DEF_HELPER_2(mtc0_ebase, void, env, tl) -DEF_HELPER_2(mttc0_ebase, void, env, tl) -DEF_HELPER_2(mtc0_config0, void, env, tl) -DEF_HELPER_2(mtc0_config2, void, env, tl) -DEF_HELPER_2(mtc0_config3, void, env, tl) -DEF_HELPER_2(mtc0_config4, void, env, tl) -DEF_HELPER_2(mtc0_config5, void, env, tl) -DEF_HELPER_2(mtc0_lladdr, void, env, tl) -DEF_HELPER_2(mtc0_maar, void, env, tl) -DEF_HELPER_2(mthc0_maar, void, env, tl) -DEF_HELPER_2(mtc0_maari, void, env, tl) -DEF_HELPER_3(mtc0_watchlo, void, env, tl, i32) -DEF_HELPER_3(mtc0_watchhi, void, env, tl, i32) -DEF_HELPER_3(mthc0_watchhi, void, env, tl, i32) -DEF_HELPER_2(mtc0_xcontext, void, env, tl) -DEF_HELPER_2(mtc0_framemask, void, env, tl) -DEF_HELPER_2(mtc0_debug, void, env, tl) -DEF_HELPER_2(mttc0_debug, void, env, tl) -DEF_HELPER_2(mtc0_performance0, void, env, tl) -DEF_HELPER_2(mtc0_errctl, void, env, tl) -DEF_HELPER_2(mtc0_taglo, void, env, tl) -DEF_HELPER_2(mtc0_datalo, void, env, tl) -DEF_HELPER_2(mtc0_taghi, void, env, tl) -DEF_HELPER_2(mtc0_datahi, void, env, tl) - -#if defined(TARGET_MIPS64) -DEF_HELPER_2(dmtc0_entrylo0, void, env, i64) -DEF_HELPER_2(dmtc0_entrylo1, void, env, i64) -#endif - -/* MIPS MT functions */ -DEF_HELPER_2(mftgpr, tl, env, i32) -DEF_HELPER_2(mftlo, tl, env, i32) -DEF_HELPER_2(mfthi, tl, env, i32) -DEF_HELPER_2(mftacx, tl, env, i32) -DEF_HELPER_1(mftdsp, tl, env) -DEF_HELPER_3(mttgpr, void, env, tl, i32) -DEF_HELPER_3(mttlo, void, env, tl, i32) -DEF_HELPER_3(mtthi, void, env, tl, i32) -DEF_HELPER_3(mttacx, void, env, tl, i32) -DEF_HELPER_2(mttdsp, void, env, tl) -DEF_HELPER_0(dmt, tl) -DEF_HELPER_0(emt, tl) -DEF_HELPER_1(dvpe, tl, env) -DEF_HELPER_1(evpe, tl, env) - -/* R6 Multi-threading */ -DEF_HELPER_1(dvp, tl, env) -DEF_HELPER_1(evp, tl, env) -#endif /* !CONFIG_USER_ONLY */ - /* microMIPS functions */ DEF_HELPER_4(lwm, void, env, tl, tl, i32) DEF_HELPER_4(swm, void, env, tl, tl, i32) @@ -783,4 +621,8 @@ DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env) DEF_HELPER_3(cache, void, env, tl, i32) +#ifndef CONFIG_USER_ONLY +#include "tcg/sysemu_helper.h.inc" +#endif /* !CONFIG_USER_ONLY */ + #include "msa_helper.h.inc" diff --git a/target/mips/meson.build b/target/mips/meson.build index 9a507937ec..a55af1cd6c 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -47,11 +47,6 @@ endif mips_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) -mips_softmmu_ss.add(when: 'CONFIG_TCG', if_true: files( - 'cp0_helper.c', - 'mips-semi.c', -)) - mips_ss.add_all(when: 'CONFIG_TCG', if_true: [mips_tcg_ss]) target_arch += {'mips': mips_ss} diff --git a/target/mips/tcg/meson.build b/target/mips/tcg/meson.build index b74fa04303..2cffc5a5ac 100644 --- a/target/mips/tcg/meson.build +++ b/target/mips/tcg/meson.build @@ -1,3 +1,6 @@ if have_user subdir('user') endif +if have_system + subdir('sysemu') +endif diff --git a/target/mips/cp0_helper.c b/target/mips/tcg/sysemu/cp0_helper.c similarity index 100% rename from target/mips/cp0_helper.c rename to target/mips/tcg/sysemu/cp0_helper.c diff --git a/target/mips/tcg/sysemu/meson.build b/target/mips/tcg/sysemu/meson.build new file mode 100644 index 0000000000..5c3024e776 --- /dev/null +++ b/target/mips/tcg/sysemu/meson.build @@ -0,0 +1,4 @@ +mips_softmmu_ss.add(files( + 'cp0_helper.c', + 'mips-semi.c', +)) diff --git a/target/mips/mips-semi.c b/target/mips/tcg/sysemu/mips-semi.c similarity index 100% rename from target/mips/mips-semi.c rename to target/mips/tcg/sysemu/mips-semi.c diff --git a/target/mips/tcg/sysemu_helper.h.inc b/target/mips/tcg/sysemu_helper.h.inc new file mode 100644 index 0000000000..d136c4160a --- /dev/null +++ b/target/mips/tcg/sysemu_helper.h.inc @@ -0,0 +1,168 @@ +/* + * QEMU MIPS sysemu helpers + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * Copyright (c) 2006 Marius Groeger (FPU operations) + * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support) + * Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support) + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +DEF_HELPER_1(do_semihosting, void, env) + +/* CP0 helpers */ +DEF_HELPER_1(mfc0_mvpcontrol, tl, env) +DEF_HELPER_1(mfc0_mvpconf0, tl, env) +DEF_HELPER_1(mfc0_mvpconf1, tl, env) +DEF_HELPER_1(mftc0_vpecontrol, tl, env) +DEF_HELPER_1(mftc0_vpeconf0, tl, env) +DEF_HELPER_1(mfc0_random, tl, env) +DEF_HELPER_1(mfc0_tcstatus, tl, env) +DEF_HELPER_1(mftc0_tcstatus, tl, env) +DEF_HELPER_1(mfc0_tcbind, tl, env) +DEF_HELPER_1(mftc0_tcbind, tl, env) +DEF_HELPER_1(mfc0_tcrestart, tl, env) +DEF_HELPER_1(mftc0_tcrestart, tl, env) +DEF_HELPER_1(mfc0_tchalt, tl, env) +DEF_HELPER_1(mftc0_tchalt, tl, env) +DEF_HELPER_1(mfc0_tccontext, tl, env) +DEF_HELPER_1(mftc0_tccontext, tl, env) +DEF_HELPER_1(mfc0_tcschedule, tl, env) +DEF_HELPER_1(mftc0_tcschedule, tl, env) +DEF_HELPER_1(mfc0_tcschefback, tl, env) +DEF_HELPER_1(mftc0_tcschefback, tl, env) +DEF_HELPER_1(mfc0_count, tl, env) +DEF_HELPER_1(mfc0_saar, tl, env) +DEF_HELPER_1(mfhc0_saar, tl, env) +DEF_HELPER_1(mftc0_entryhi, tl, env) +DEF_HELPER_1(mftc0_status, tl, env) +DEF_HELPER_1(mftc0_cause, tl, env) +DEF_HELPER_1(mftc0_epc, tl, env) +DEF_HELPER_1(mftc0_ebase, tl, env) +DEF_HELPER_2(mftc0_configx, tl, env, tl) +DEF_HELPER_1(mfc0_lladdr, tl, env) +DEF_HELPER_1(mfc0_maar, tl, env) +DEF_HELPER_1(mfhc0_maar, tl, env) +DEF_HELPER_2(mfc0_watchlo, tl, env, i32) +DEF_HELPER_2(mfc0_watchhi, tl, env, i32) +DEF_HELPER_2(mfhc0_watchhi, tl, env, i32) +DEF_HELPER_1(mfc0_debug, tl, env) +DEF_HELPER_1(mftc0_debug, tl, env) +#ifdef TARGET_MIPS64 +DEF_HELPER_1(dmfc0_tcrestart, tl, env) +DEF_HELPER_1(dmfc0_tchalt, tl, env) +DEF_HELPER_1(dmfc0_tccontext, tl, env) +DEF_HELPER_1(dmfc0_tcschedule, tl, env) +DEF_HELPER_1(dmfc0_tcschefback, tl, env) +DEF_HELPER_1(dmfc0_lladdr, tl, env) +DEF_HELPER_1(dmfc0_maar, tl, env) +DEF_HELPER_2(dmfc0_watchlo, tl, env, i32) +DEF_HELPER_2(dmfc0_watchhi, tl, env, i32) +DEF_HELPER_1(dmfc0_saar, tl, env) +#endif /* TARGET_MIPS64 */ + +DEF_HELPER_2(mtc0_index, void, env, tl) +DEF_HELPER_2(mtc0_mvpcontrol, void, env, tl) +DEF_HELPER_2(mtc0_vpecontrol, void, env, tl) +DEF_HELPER_2(mttc0_vpecontrol, void, env, tl) +DEF_HELPER_2(mtc0_vpeconf0, void, env, tl) +DEF_HELPER_2(mttc0_vpeconf0, void, env, tl) +DEF_HELPER_2(mtc0_vpeconf1, void, env, tl) +DEF_HELPER_2(mtc0_yqmask, void, env, tl) +DEF_HELPER_2(mtc0_vpeopt, void, env, tl) +DEF_HELPER_2(mtc0_entrylo0, void, env, tl) +DEF_HELPER_2(mtc0_tcstatus, void, env, tl) +DEF_HELPER_2(mttc0_tcstatus, void, env, tl) +DEF_HELPER_2(mtc0_tcbind, void, env, tl) +DEF_HELPER_2(mttc0_tcbind, void, env, tl) +DEF_HELPER_2(mtc0_tcrestart, void, env, tl) +DEF_HELPER_2(mttc0_tcrestart, void, env, tl) +DEF_HELPER_2(mtc0_tchalt, void, env, tl) +DEF_HELPER_2(mttc0_tchalt, void, env, tl) +DEF_HELPER_2(mtc0_tccontext, void, env, tl) +DEF_HELPER_2(mttc0_tccontext, void, env, tl) +DEF_HELPER_2(mtc0_tcschedule, void, env, tl) +DEF_HELPER_2(mttc0_tcschedule, void, env, tl) +DEF_HELPER_2(mtc0_tcschefback, void, env, tl) +DEF_HELPER_2(mttc0_tcschefback, void, env, tl) +DEF_HELPER_2(mtc0_entrylo1, void, env, tl) +DEF_HELPER_2(mtc0_context, void, env, tl) +DEF_HELPER_2(mtc0_memorymapid, void, env, tl) +DEF_HELPER_2(mtc0_pagemask, void, env, tl) +DEF_HELPER_2(mtc0_pagegrain, void, env, tl) +DEF_HELPER_2(mtc0_segctl0, void, env, tl) +DEF_HELPER_2(mtc0_segctl1, void, env, tl) +DEF_HELPER_2(mtc0_segctl2, void, env, tl) +DEF_HELPER_2(mtc0_pwfield, void, env, tl) +DEF_HELPER_2(mtc0_pwsize, void, env, tl) +DEF_HELPER_2(mtc0_wired, void, env, tl) +DEF_HELPER_2(mtc0_srsconf0, void, env, tl) +DEF_HELPER_2(mtc0_srsconf1, void, env, tl) +DEF_HELPER_2(mtc0_srsconf2, void, env, tl) +DEF_HELPER_2(mtc0_srsconf3, void, env, tl) +DEF_HELPER_2(mtc0_srsconf4, void, env, tl) +DEF_HELPER_2(mtc0_hwrena, void, env, tl) +DEF_HELPER_2(mtc0_pwctl, void, env, tl) +DEF_HELPER_2(mtc0_count, void, env, tl) +DEF_HELPER_2(mtc0_saari, void, env, tl) +DEF_HELPER_2(mtc0_saar, void, env, tl) +DEF_HELPER_2(mthc0_saar, void, env, tl) +DEF_HELPER_2(mtc0_entryhi, void, env, tl) +DEF_HELPER_2(mttc0_entryhi, void, env, tl) +DEF_HELPER_2(mtc0_compare, void, env, tl) +DEF_HELPER_2(mtc0_status, void, env, tl) +DEF_HELPER_2(mttc0_status, void, env, tl) +DEF_HELPER_2(mtc0_intctl, void, env, tl) +DEF_HELPER_2(mtc0_srsctl, void, env, tl) +DEF_HELPER_2(mtc0_cause, void, env, tl) +DEF_HELPER_2(mttc0_cause, void, env, tl) +DEF_HELPER_2(mtc0_ebase, void, env, tl) +DEF_HELPER_2(mttc0_ebase, void, env, tl) +DEF_HELPER_2(mtc0_config0, void, env, tl) +DEF_HELPER_2(mtc0_config2, void, env, tl) +DEF_HELPER_2(mtc0_config3, void, env, tl) +DEF_HELPER_2(mtc0_config4, void, env, tl) +DEF_HELPER_2(mtc0_config5, void, env, tl) +DEF_HELPER_2(mtc0_lladdr, void, env, tl) +DEF_HELPER_2(mtc0_maar, void, env, tl) +DEF_HELPER_2(mthc0_maar, void, env, tl) +DEF_HELPER_2(mtc0_maari, void, env, tl) +DEF_HELPER_3(mtc0_watchlo, void, env, tl, i32) +DEF_HELPER_3(mtc0_watchhi, void, env, tl, i32) +DEF_HELPER_3(mthc0_watchhi, void, env, tl, i32) +DEF_HELPER_2(mtc0_xcontext, void, env, tl) +DEF_HELPER_2(mtc0_framemask, void, env, tl) +DEF_HELPER_2(mtc0_debug, void, env, tl) +DEF_HELPER_2(mttc0_debug, void, env, tl) +DEF_HELPER_2(mtc0_performance0, void, env, tl) +DEF_HELPER_2(mtc0_errctl, void, env, tl) +DEF_HELPER_2(mtc0_taglo, void, env, tl) +DEF_HELPER_2(mtc0_datalo, void, env, tl) +DEF_HELPER_2(mtc0_taghi, void, env, tl) +DEF_HELPER_2(mtc0_datahi, void, env, tl) + +#if defined(TARGET_MIPS64) +DEF_HELPER_2(dmtc0_entrylo0, void, env, i64) +DEF_HELPER_2(dmtc0_entrylo1, void, env, i64) +#endif + +/* MIPS MT functions */ +DEF_HELPER_2(mftgpr, tl, env, i32) +DEF_HELPER_2(mftlo, tl, env, i32) +DEF_HELPER_2(mfthi, tl, env, i32) +DEF_HELPER_2(mftacx, tl, env, i32) +DEF_HELPER_1(mftdsp, tl, env) +DEF_HELPER_3(mttgpr, void, env, tl, i32) +DEF_HELPER_3(mttlo, void, env, tl, i32) +DEF_HELPER_3(mtthi, void, env, tl, i32) +DEF_HELPER_3(mttacx, void, env, tl, i32) +DEF_HELPER_2(mttdsp, void, env, tl) +DEF_HELPER_0(dmt, tl) +DEF_HELPER_0(emt, tl) +DEF_HELPER_1(dvpe, tl, env) +DEF_HELPER_1(evpe, tl, env) + +/* R6 Multi-threading */ +DEF_HELPER_1(dvp, tl, env) +DEF_HELPER_1(evp, tl, env) From c284201702386b159277422318e51697647a2047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 18 Apr 2021 16:25:49 +0200 Subject: [PATCH 0198/3028] target/mips: Restrict mmu_init() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mmu_init() is only required by TCG accelerator. Restrict its declaration and call to TCG. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-21-f4bug@amsat.org> --- target/mips/cpu.c | 2 +- target/mips/internal.h | 3 --- target/mips/tcg/tcg-internal.h | 2 ++ 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index a751c95832..c3159e3d7f 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -708,7 +708,7 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp) env->exception_base = (int32_t)0xBFC00000; -#ifndef CONFIG_USER_ONLY +#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) mmu_init(env, env->cpu_model); #endif fpu_init(env, env->cpu_model); diff --git a/target/mips/internal.h b/target/mips/internal.h index 6bac8ef704..2c9666905d 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -233,9 +233,6 @@ void cpu_mips_store_compare(CPUMIPSState *env, uint32_t value); void cpu_mips_start_count(CPUMIPSState *env); void cpu_mips_stop_count(CPUMIPSState *env); -/* helper.c */ -void mmu_init(CPUMIPSState *env, const mips_def_t *def); - static inline void mips_env_set_pc(CPUMIPSState *env, target_ulong value) { env->active_tc.PC = value & ~(target_ulong)1; diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h index b65580af21..70655bab45 100644 --- a/target/mips/tcg/tcg-internal.h +++ b/target/mips/tcg/tcg-internal.h @@ -20,6 +20,8 @@ bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, #if !defined(CONFIG_USER_ONLY) +void mmu_init(CPUMIPSState *env, const mips_def_t *def); + void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask); uint32_t cpu_mips_get_random(CPUMIPSState *env); From 920b48cc14fe44a466f7387263993e86b4e21bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 11:46:18 +0200 Subject: [PATCH 0199/3028] target/mips: Move tlb_helper.c to tcg/sysemu/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move tlb_helper.c to the tcg/sysemu/ subdir, along with the following 3 declarations to tcg-internal.h: - cpu_mips_tlb_flush() - cpu_mips_translate_address() - r4k_invalidate_tlb() Simplify tlb_helper.c #ifdef'ry because files in tcg/sysemu/ are only build when sysemu mode is configured. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-22-f4bug@amsat.org> --- target/mips/internal.h | 5 ----- target/mips/meson.build | 1 - target/mips/tcg/sysemu/meson.build | 1 + target/mips/{ => tcg/sysemu}/tlb_helper.c | 3 --- target/mips/tcg/tcg-internal.h | 5 +++++ 5 files changed, 6 insertions(+), 9 deletions(-) rename target/mips/{ => tcg/sysemu}/tlb_helper.c (99%) diff --git a/target/mips/internal.h b/target/mips/internal.h index 2c9666905d..558cdca4e8 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -164,16 +164,12 @@ void r4k_helper_tlbp(CPUMIPSState *env); void r4k_helper_tlbr(CPUMIPSState *env); void r4k_helper_tlbinv(CPUMIPSState *env); void r4k_helper_tlbinvf(CPUMIPSState *env); -void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra); void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, unsigned size, MMUAccessType access_type, int mmu_idx, MemTxAttrs attrs, MemTxResult response, uintptr_t retaddr); -hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, - MMUAccessType access_type, uintptr_t retaddr); - extern const VMStateDescription vmstate_mips_cpu; #endif /* !CONFIG_USER_ONLY */ @@ -423,7 +419,6 @@ static inline void compute_hflags(CPUMIPSState *env) } } -void cpu_mips_tlb_flush(CPUMIPSState *env); void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc); void cpu_mips_store_status(CPUMIPSState *env, target_ulong val); void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val); diff --git a/target/mips/meson.build b/target/mips/meson.build index a55af1cd6c..ff5eb210df 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -31,7 +31,6 @@ mips_tcg_ss.add(files( 'msa_translate.c', 'op_helper.c', 'rel6_translate.c', - 'tlb_helper.c', 'translate.c', 'translate_addr_const.c', 'txx9_translate.c', diff --git a/target/mips/tcg/sysemu/meson.build b/target/mips/tcg/sysemu/meson.build index 5c3024e776..73ab9571ba 100644 --- a/target/mips/tcg/sysemu/meson.build +++ b/target/mips/tcg/sysemu/meson.build @@ -1,4 +1,5 @@ mips_softmmu_ss.add(files( 'cp0_helper.c', 'mips-semi.c', + 'tlb_helper.c', )) diff --git a/target/mips/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c similarity index 99% rename from target/mips/tlb_helper.c rename to target/mips/tcg/sysemu/tlb_helper.c index bfb08eaf50..bf242f5e65 100644 --- a/target/mips/tlb_helper.c +++ b/target/mips/tcg/sysemu/tlb_helper.c @@ -25,8 +25,6 @@ #include "exec/log.h" #include "hw/mips/cpudevs.h" -#if !defined(CONFIG_USER_ONLY) - /* no MMU emulation */ int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, target_ulong address, MMUAccessType access_type) @@ -1072,4 +1070,3 @@ void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra) } } } -#endif /* !CONFIG_USER_ONLY */ diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h index 70655bab45..a39ff45d58 100644 --- a/target/mips/tcg/tcg-internal.h +++ b/target/mips/tcg/tcg-internal.h @@ -24,8 +24,13 @@ void mmu_init(CPUMIPSState *env, const mips_def_t *def); void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask); +void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra); uint32_t cpu_mips_get_random(CPUMIPSState *env); +hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, + MMUAccessType access_type, uintptr_t retaddr); +void cpu_mips_tlb_flush(CPUMIPSState *env); + #endif /* !CONFIG_USER_ONLY */ #endif From f3185ec2f35e43c06384f5ac5edc4edfbfd11623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 23:05:02 +0200 Subject: [PATCH 0200/3028] target/mips: Restrict CPUMIPSTLBContext::map_address() handlers scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 3 map_address() handlers are local to tlb_helper.c, no need to have their prototype declared publically. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-23-f4bug@amsat.org> --- target/mips/internal.h | 6 ------ target/mips/tcg/sysemu/tlb_helper.c | 13 +++++++------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/target/mips/internal.h b/target/mips/internal.h index 558cdca4e8..c175170073 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -152,12 +152,6 @@ struct CPUMIPSTLBContext { } mmu; }; -int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, MMUAccessType access_type); -int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, MMUAccessType access_type); -int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, MMUAccessType access_type); void r4k_helper_tlbwi(CPUMIPSState *env); void r4k_helper_tlbwr(CPUMIPSState *env); void r4k_helper_tlbp(CPUMIPSState *env); diff --git a/target/mips/tcg/sysemu/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c index bf242f5e65..a45146a2b2 100644 --- a/target/mips/tcg/sysemu/tlb_helper.c +++ b/target/mips/tcg/sysemu/tlb_helper.c @@ -26,8 +26,8 @@ #include "hw/mips/cpudevs.h" /* no MMU emulation */ -int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, MMUAccessType access_type) +static int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, + target_ulong address, MMUAccessType access_type) { *physical = address; *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -35,8 +35,9 @@ int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, } /* fixed mapping MMU emulation */ -int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, MMUAccessType access_type) +static int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, + int *prot, target_ulong address, + MMUAccessType access_type) { if (address <= (int32_t)0x7FFFFFFFUL) { if (!(env->CP0_Status & (1 << CP0St_ERL))) { @@ -55,8 +56,8 @@ int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, } /* MIPS32/MIPS64 R4000-style MMU emulation */ -int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, - target_ulong address, MMUAccessType access_type) +static int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, + target_ulong address, MMUAccessType access_type) { uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; uint32_t MMID = env->CP0_MemoryMapID; From d60146a9389db771fa4061d9376ba3e208ff2cdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 20:19:52 +0200 Subject: [PATCH 0201/3028] target/mips: Move Special opcodes to tcg/sysemu/special_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the Special opcodes helpers to tcg/sysemu/special_helper.c. Since mips_io_recompile_replay_branch() is set as CPUClass::io_recompile_replay_branch handler in cpu.c, we need to declare its prototype in "tcg-internal.h". Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-24-f4bug@amsat.org> --- target/mips/cpu.c | 17 --- target/mips/helper.h | 5 - target/mips/op_helper.c | 100 ----------------- target/mips/tcg/sysemu/meson.build | 1 + target/mips/tcg/sysemu/special_helper.c | 140 ++++++++++++++++++++++++ target/mips/tcg/sysemu_helper.h.inc | 7 ++ target/mips/tcg/tcg-internal.h | 3 + 7 files changed, 151 insertions(+), 122 deletions(-) create mode 100644 target/mips/tcg/sysemu/special_helper.c diff --git a/target/mips/cpu.c b/target/mips/cpu.c index c3159e3d7f..a33e3b6c20 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -342,23 +342,6 @@ static void mips_cpu_synchronize_from_tb(CPUState *cs, env->hflags &= ~MIPS_HFLAG_BMASK; env->hflags |= tb->flags & MIPS_HFLAG_BMASK; } - -# ifndef CONFIG_USER_ONLY -static bool mips_io_recompile_replay_branch(CPUState *cs, - const TranslationBlock *tb) -{ - MIPSCPU *cpu = MIPS_CPU(cs); - CPUMIPSState *env = &cpu->env; - - if ((env->hflags & MIPS_HFLAG_BMASK) != 0 - && env->active_tc.PC != tb->pc) { - env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); - env->hflags &= ~MIPS_HFLAG_BMASK; - return true; - } - return false; -} -# endif /* !CONFIG_USER_ONLY */ #endif /* CONFIG_TCG */ static bool mips_cpu_has_work(CPUState *cs) diff --git a/target/mips/helper.h b/target/mips/helper.h index bc308e5db1..4ee7916d8b 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -210,11 +210,6 @@ DEF_HELPER_1(tlbp, void, env) DEF_HELPER_1(tlbr, void, env) DEF_HELPER_1(tlbinv, void, env) DEF_HELPER_1(tlbinvf, void, env) -DEF_HELPER_1(di, tl, env) -DEF_HELPER_1(ei, tl, env) -DEF_HELPER_1(eret, void, env) -DEF_HELPER_1(eretnc, void, env) -DEF_HELPER_1(deret, void, env) DEF_HELPER_3(ginvt, void, env, tl, i32) #endif /* !CONFIG_USER_ONLY */ DEF_HELPER_1(rdhwr_cpunum, tl, env) diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index 7a7369bc8a..a077535194 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -655,106 +655,6 @@ void helper_ginvt(CPUMIPSState *env, target_ulong arg, uint32_t type) } } -/* Specials */ -target_ulong helper_di(CPUMIPSState *env) -{ - target_ulong t0 = env->CP0_Status; - - env->CP0_Status = t0 & ~(1 << CP0St_IE); - return t0; -} - -target_ulong helper_ei(CPUMIPSState *env) -{ - target_ulong t0 = env->CP0_Status; - - env->CP0_Status = t0 | (1 << CP0St_IE); - return t0; -} - -static void debug_pre_eret(CPUMIPSState *env) -{ - if (qemu_loglevel_mask(CPU_LOG_EXEC)) { - qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, - env->active_tc.PC, env->CP0_EPC); - if (env->CP0_Status & (1 << CP0St_ERL)) { - qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); - } - if (env->hflags & MIPS_HFLAG_DM) { - qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC); - } - qemu_log("\n"); - } -} - -static void debug_post_eret(CPUMIPSState *env) -{ - if (qemu_loglevel_mask(CPU_LOG_EXEC)) { - qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, - env->active_tc.PC, env->CP0_EPC); - if (env->CP0_Status & (1 << CP0St_ERL)) { - qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); - } - if (env->hflags & MIPS_HFLAG_DM) { - qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC); - } - switch (cpu_mmu_index(env, false)) { - case 3: - qemu_log(", ERL\n"); - break; - case MIPS_HFLAG_UM: - qemu_log(", UM\n"); - break; - case MIPS_HFLAG_SM: - qemu_log(", SM\n"); - break; - case MIPS_HFLAG_KM: - qemu_log("\n"); - break; - default: - cpu_abort(env_cpu(env), "Invalid MMU mode!\n"); - break; - } - } -} - -static inline void exception_return(CPUMIPSState *env) -{ - debug_pre_eret(env); - if (env->CP0_Status & (1 << CP0St_ERL)) { - mips_env_set_pc(env, env->CP0_ErrorEPC); - env->CP0_Status &= ~(1 << CP0St_ERL); - } else { - mips_env_set_pc(env, env->CP0_EPC); - env->CP0_Status &= ~(1 << CP0St_EXL); - } - compute_hflags(env); - debug_post_eret(env); -} - -void helper_eret(CPUMIPSState *env) -{ - exception_return(env); - env->CP0_LLAddr = 1; - env->lladdr = 1; -} - -void helper_eretnc(CPUMIPSState *env) -{ - exception_return(env); -} - -void helper_deret(CPUMIPSState *env) -{ - debug_pre_eret(env); - - env->hflags &= ~MIPS_HFLAG_DM; - compute_hflags(env); - - mips_env_set_pc(env, env->CP0_DEPC); - - debug_post_eret(env); -} #endif /* !CONFIG_USER_ONLY */ static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc) diff --git a/target/mips/tcg/sysemu/meson.build b/target/mips/tcg/sysemu/meson.build index 73ab9571ba..4da2c577b2 100644 --- a/target/mips/tcg/sysemu/meson.build +++ b/target/mips/tcg/sysemu/meson.build @@ -1,5 +1,6 @@ mips_softmmu_ss.add(files( 'cp0_helper.c', 'mips-semi.c', + 'special_helper.c', 'tlb_helper.c', )) diff --git a/target/mips/tcg/sysemu/special_helper.c b/target/mips/tcg/sysemu/special_helper.c new file mode 100644 index 0000000000..971883fa38 --- /dev/null +++ b/target/mips/tcg/sysemu/special_helper.c @@ -0,0 +1,140 @@ +/* + * QEMU MIPS emulation: Special opcode helpers + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "internal.h" + +/* Specials */ +target_ulong helper_di(CPUMIPSState *env) +{ + target_ulong t0 = env->CP0_Status; + + env->CP0_Status = t0 & ~(1 << CP0St_IE); + return t0; +} + +target_ulong helper_ei(CPUMIPSState *env) +{ + target_ulong t0 = env->CP0_Status; + + env->CP0_Status = t0 | (1 << CP0St_IE); + return t0; +} + +static void debug_pre_eret(CPUMIPSState *env) +{ + if (qemu_loglevel_mask(CPU_LOG_EXEC)) { + qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, + env->active_tc.PC, env->CP0_EPC); + if (env->CP0_Status & (1 << CP0St_ERL)) { + qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); + } + if (env->hflags & MIPS_HFLAG_DM) { + qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC); + } + qemu_log("\n"); + } +} + +static void debug_post_eret(CPUMIPSState *env) +{ + if (qemu_loglevel_mask(CPU_LOG_EXEC)) { + qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, + env->active_tc.PC, env->CP0_EPC); + if (env->CP0_Status & (1 << CP0St_ERL)) { + qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); + } + if (env->hflags & MIPS_HFLAG_DM) { + qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC); + } + switch (cpu_mmu_index(env, false)) { + case 3: + qemu_log(", ERL\n"); + break; + case MIPS_HFLAG_UM: + qemu_log(", UM\n"); + break; + case MIPS_HFLAG_SM: + qemu_log(", SM\n"); + break; + case MIPS_HFLAG_KM: + qemu_log("\n"); + break; + default: + cpu_abort(env_cpu(env), "Invalid MMU mode!\n"); + break; + } + } +} + +bool mips_io_recompile_replay_branch(CPUState *cs, const TranslationBlock *tb) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + + if ((env->hflags & MIPS_HFLAG_BMASK) != 0 + && env->active_tc.PC != tb->pc) { + env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); + env->hflags &= ~MIPS_HFLAG_BMASK; + return true; + } + return false; +} + +static inline void exception_return(CPUMIPSState *env) +{ + debug_pre_eret(env); + if (env->CP0_Status & (1 << CP0St_ERL)) { + mips_env_set_pc(env, env->CP0_ErrorEPC); + env->CP0_Status &= ~(1 << CP0St_ERL); + } else { + mips_env_set_pc(env, env->CP0_EPC); + env->CP0_Status &= ~(1 << CP0St_EXL); + } + compute_hflags(env); + debug_post_eret(env); +} + +void helper_eret(CPUMIPSState *env) +{ + exception_return(env); + env->CP0_LLAddr = 1; + env->lladdr = 1; +} + +void helper_eretnc(CPUMIPSState *env) +{ + exception_return(env); +} + +void helper_deret(CPUMIPSState *env) +{ + debug_pre_eret(env); + + env->hflags &= ~MIPS_HFLAG_DM; + compute_hflags(env); + + mips_env_set_pc(env, env->CP0_DEPC); + + debug_post_eret(env); +} diff --git a/target/mips/tcg/sysemu_helper.h.inc b/target/mips/tcg/sysemu_helper.h.inc index d136c4160a..38e55cbf11 100644 --- a/target/mips/tcg/sysemu_helper.h.inc +++ b/target/mips/tcg/sysemu_helper.h.inc @@ -166,3 +166,10 @@ DEF_HELPER_1(evpe, tl, env) /* R6 Multi-threading */ DEF_HELPER_1(dvp, tl, env) DEF_HELPER_1(evp, tl, env) + +/* Special */ +DEF_HELPER_1(di, tl, env) +DEF_HELPER_1(ei, tl, env) +DEF_HELPER_1(eret, void, env) +DEF_HELPER_1(eretnc, void, env) +DEF_HELPER_1(deret, void, env) diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h index a39ff45d58..73667b3577 100644 --- a/target/mips/tcg/tcg-internal.h +++ b/target/mips/tcg/tcg-internal.h @@ -10,6 +10,7 @@ #ifndef MIPS_TCG_INTERNAL_H #define MIPS_TCG_INTERNAL_H +#include "tcg/tcg.h" #include "hw/core/cpu.h" #include "cpu.h" @@ -27,6 +28,8 @@ void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask); void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra); uint32_t cpu_mips_get_random(CPUMIPSState *env); +bool mips_io_recompile_replay_branch(CPUState *cs, const TranslationBlock *tb); + hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, MMUAccessType access_type, uintptr_t retaddr); void cpu_mips_tlb_flush(CPUMIPSState *env); From ecdbcb0a9450e9109ae3dd6cfa10c71fda753bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 20:21:16 +0200 Subject: [PATCH 0202/3028] target/mips: Move helper_cache() to tcg/sysemu/special_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move helper_cache() to tcg/sysemu/special_helper.c. The CACHE opcode is privileged and is not accessible in user emulation. However we get a link failure when restricting the symbol to sysemu. For now, add a stub helper to satisfy linking, which abort if ever called. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-25-f4bug@amsat.org> --- target/mips/helper.h | 2 -- target/mips/op_helper.c | 35 ------------------------- target/mips/tcg/sysemu/special_helper.c | 33 +++++++++++++++++++++++ target/mips/tcg/sysemu_helper.h.inc | 1 + target/mips/translate.c | 13 +++++++++ 5 files changed, 47 insertions(+), 37 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index 4ee7916d8b..d49620f928 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -614,8 +614,6 @@ DEF_HELPER_FLAGS_3(dmthlip, 0, void, tl, tl, env) DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env) DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env) -DEF_HELPER_3(cache, void, env, tl, i32) - #ifndef CONFIG_USER_ONLY #include "tcg/sysemu_helper.h.inc" #endif /* !CONFIG_USER_ONLY */ diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index a077535194..a7fe1de8c4 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -788,38 +788,3 @@ void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, } } #endif /* !CONFIG_USER_ONLY */ - -void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op) -{ -#ifndef CONFIG_USER_ONLY - static const char *const type_name[] = { - "Primary Instruction", - "Primary Data or Unified Primary", - "Tertiary", - "Secondary" - }; - uint32_t cache_type = extract32(op, 0, 2); - uint32_t cache_operation = extract32(op, 2, 3); - target_ulong index = addr & 0x1fffffff; - - switch (cache_operation) { - case 0b010: /* Index Store Tag */ - memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo, - MO_64, MEMTXATTRS_UNSPECIFIED); - break; - case 0b001: /* Index Load Tag */ - memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo, - MO_64, MEMTXATTRS_UNSPECIFIED); - break; - case 0b000: /* Index Invalidate */ - case 0b100: /* Hit Invalidate */ - case 0b110: /* Hit Writeback */ - /* no-op */ - break; - default: - qemu_log_mask(LOG_UNIMP, "cache operation:%u (type: %s cache)\n", - cache_operation, type_name[cache_type]); - break; - } -#endif -} diff --git a/target/mips/tcg/sysemu/special_helper.c b/target/mips/tcg/sysemu/special_helper.c index 971883fa38..2a2afb49e8 100644 --- a/target/mips/tcg/sysemu/special_helper.c +++ b/target/mips/tcg/sysemu/special_helper.c @@ -138,3 +138,36 @@ void helper_deret(CPUMIPSState *env) debug_post_eret(env); } + +void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op) +{ + static const char *const type_name[] = { + "Primary Instruction", + "Primary Data or Unified Primary", + "Tertiary", + "Secondary" + }; + uint32_t cache_type = extract32(op, 0, 2); + uint32_t cache_operation = extract32(op, 2, 3); + target_ulong index = addr & 0x1fffffff; + + switch (cache_operation) { + case 0b010: /* Index Store Tag */ + memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo, + MO_64, MEMTXATTRS_UNSPECIFIED); + break; + case 0b001: /* Index Load Tag */ + memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo, + MO_64, MEMTXATTRS_UNSPECIFIED); + break; + case 0b000: /* Index Invalidate */ + case 0b100: /* Hit Invalidate */ + case 0b110: /* Hit Writeback */ + /* no-op */ + break; + default: + qemu_log_mask(LOG_UNIMP, "cache operation:%u (type: %s cache)\n", + cache_operation, type_name[cache_type]); + break; + } +} diff --git a/target/mips/tcg/sysemu_helper.h.inc b/target/mips/tcg/sysemu_helper.h.inc index 38e55cbf11..1ccbf68723 100644 --- a/target/mips/tcg/sysemu_helper.h.inc +++ b/target/mips/tcg/sysemu_helper.h.inc @@ -173,3 +173,4 @@ DEF_HELPER_1(ei, tl, env) DEF_HELPER_1(eret, void, env) DEF_HELPER_1(eretnc, void, env) DEF_HELPER_1(deret, void, env) +DEF_HELPER_3(cache, void, env, tl, i32) diff --git a/target/mips/translate.c b/target/mips/translate.c index f0ae371602..c03a8ae1fe 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -39,6 +39,19 @@ #include "fpu_helper.h" #include "translate.h" +/* + * Many sysemu-only helpers are not reachable for user-only. + * Define stub generators here, so that we need not either sprinkle + * ifdefs through the translator, nor provide the helper function. + */ +#define STUB_HELPER(NAME, ...) \ + static inline void gen_helper_##NAME(__VA_ARGS__) \ + { g_assert_not_reached(); } + +#ifdef CONFIG_USER_ONLY +STUB_HELPER(cache, TCGv_env env, TCGv val, TCGv_i32 reg) +#endif + enum { /* indirect opcode tables */ OPC_SPECIAL = (0x00 << 26), From 6575529b654ffeaebf1b00c53e33c834d68b7c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 21:30:40 +0200 Subject: [PATCH 0203/3028] target/mips: Move TLB management helpers to tcg/sysemu/tlb_helper.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move TLB management helpers to tcg/sysemu/tlb_helper.c. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-26-f4bug@amsat.org> --- target/mips/helper.h | 10 - target/mips/internal.h | 7 - target/mips/op_helper.c | 333 ---------------------------- target/mips/tcg/sysemu/tlb_helper.c | 331 +++++++++++++++++++++++++++ target/mips/tcg/sysemu_helper.h.inc | 9 + 5 files changed, 340 insertions(+), 350 deletions(-) diff --git a/target/mips/helper.h b/target/mips/helper.h index d49620f928..ba301ae160 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -202,16 +202,6 @@ FOP_PROTO(sune) FOP_PROTO(sne) #undef FOP_PROTO -/* Special functions */ -#ifndef CONFIG_USER_ONLY -DEF_HELPER_1(tlbwi, void, env) -DEF_HELPER_1(tlbwr, void, env) -DEF_HELPER_1(tlbp, void, env) -DEF_HELPER_1(tlbr, void, env) -DEF_HELPER_1(tlbinv, void, env) -DEF_HELPER_1(tlbinvf, void, env) -DEF_HELPER_3(ginvt, void, env, tl, i32) -#endif /* !CONFIG_USER_ONLY */ DEF_HELPER_1(rdhwr_cpunum, tl, env) DEF_HELPER_1(rdhwr_synci_step, tl, env) DEF_HELPER_1(rdhwr_cc, tl, env) diff --git a/target/mips/internal.h b/target/mips/internal.h index c175170073..a1c7f658c2 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -152,13 +152,6 @@ struct CPUMIPSTLBContext { } mmu; }; -void r4k_helper_tlbwi(CPUMIPSState *env); -void r4k_helper_tlbwr(CPUMIPSState *env); -void r4k_helper_tlbp(CPUMIPSState *env); -void r4k_helper_tlbr(CPUMIPSState *env); -void r4k_helper_tlbinv(CPUMIPSState *env); -void r4k_helper_tlbinvf(CPUMIPSState *env); - void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, unsigned size, MMUAccessType access_type, diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index a7fe1de8c4..cb2a7e96fc 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -324,339 +324,6 @@ target_ulong helper_yield(CPUMIPSState *env, target_ulong arg) return env->CP0_YQMask; } -#ifndef CONFIG_USER_ONLY -/* TLB management */ -static void r4k_mips_tlb_flush_extra(CPUMIPSState *env, int first) -{ - /* Discard entries from env->tlb[first] onwards. */ - while (env->tlb->tlb_in_use > first) { - r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0); - } -} - -static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo) -{ -#if defined(TARGET_MIPS64) - return extract64(entrylo, 6, 54); -#else - return extract64(entrylo, 6, 24) | /* PFN */ - (extract64(entrylo, 32, 32) << 24); /* PFNX */ -#endif -} - -static void r4k_fill_tlb(CPUMIPSState *env, int idx) -{ - r4k_tlb_t *tlb; - uint64_t mask = env->CP0_PageMask >> (TARGET_PAGE_BITS + 1); - - /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ - tlb = &env->tlb->mmu.r4k.tlb[idx]; - if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) { - tlb->EHINV = 1; - return; - } - tlb->EHINV = 0; - tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); -#if defined(TARGET_MIPS64) - tlb->VPN &= env->SEGMask; -#endif - tlb->ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; - tlb->MMID = env->CP0_MemoryMapID; - tlb->PageMask = env->CP0_PageMask; - tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; - tlb->V0 = (env->CP0_EntryLo0 & 2) != 0; - tlb->D0 = (env->CP0_EntryLo0 & 4) != 0; - tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7; - tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1; - tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1; - tlb->PFN[0] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) & ~mask) << 12; - tlb->V1 = (env->CP0_EntryLo1 & 2) != 0; - tlb->D1 = (env->CP0_EntryLo1 & 4) != 0; - tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7; - tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1; - tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1; - tlb->PFN[1] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) & ~mask) << 12; -} - -void r4k_helper_tlbinv(CPUMIPSState *env) -{ - bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1); - uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; - uint32_t MMID = env->CP0_MemoryMapID; - uint32_t tlb_mmid; - r4k_tlb_t *tlb; - int idx; - - MMID = mi ? MMID : (uint32_t) ASID; - for (idx = 0; idx < env->tlb->nb_tlb; idx++) { - tlb = &env->tlb->mmu.r4k.tlb[idx]; - tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID; - if (!tlb->G && tlb_mmid == MMID) { - tlb->EHINV = 1; - } - } - cpu_mips_tlb_flush(env); -} - -void r4k_helper_tlbinvf(CPUMIPSState *env) -{ - int idx; - - for (idx = 0; idx < env->tlb->nb_tlb; idx++) { - env->tlb->mmu.r4k.tlb[idx].EHINV = 1; - } - cpu_mips_tlb_flush(env); -} - -void r4k_helper_tlbwi(CPUMIPSState *env) -{ - bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1); - target_ulong VPN; - uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; - uint32_t MMID = env->CP0_MemoryMapID; - uint32_t tlb_mmid; - bool EHINV, G, V0, D0, V1, D1, XI0, XI1, RI0, RI1; - r4k_tlb_t *tlb; - int idx; - - MMID = mi ? MMID : (uint32_t) ASID; - - idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb; - tlb = &env->tlb->mmu.r4k.tlb[idx]; - VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); -#if defined(TARGET_MIPS64) - VPN &= env->SEGMask; -#endif - EHINV = (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) != 0; - G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; - V0 = (env->CP0_EntryLo0 & 2) != 0; - D0 = (env->CP0_EntryLo0 & 4) != 0; - XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) &1; - RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) &1; - V1 = (env->CP0_EntryLo1 & 2) != 0; - D1 = (env->CP0_EntryLo1 & 4) != 0; - XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) &1; - RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) &1; - - tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID; - /* - * Discard cached TLB entries, unless tlbwi is just upgrading access - * permissions on the current entry. - */ - if (tlb->VPN != VPN || tlb_mmid != MMID || tlb->G != G || - (!tlb->EHINV && EHINV) || - (tlb->V0 && !V0) || (tlb->D0 && !D0) || - (!tlb->XI0 && XI0) || (!tlb->RI0 && RI0) || - (tlb->V1 && !V1) || (tlb->D1 && !D1) || - (!tlb->XI1 && XI1) || (!tlb->RI1 && RI1)) { - r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb); - } - - r4k_invalidate_tlb(env, idx, 0); - r4k_fill_tlb(env, idx); -} - -void r4k_helper_tlbwr(CPUMIPSState *env) -{ - int r = cpu_mips_get_random(env); - - r4k_invalidate_tlb(env, r, 1); - r4k_fill_tlb(env, r); -} - -void r4k_helper_tlbp(CPUMIPSState *env) -{ - bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1); - r4k_tlb_t *tlb; - target_ulong mask; - target_ulong tag; - target_ulong VPN; - uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; - uint32_t MMID = env->CP0_MemoryMapID; - uint32_t tlb_mmid; - int i; - - MMID = mi ? MMID : (uint32_t) ASID; - for (i = 0; i < env->tlb->nb_tlb; i++) { - tlb = &env->tlb->mmu.r4k.tlb[i]; - /* 1k pages are not supported. */ - mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); - tag = env->CP0_EntryHi & ~mask; - VPN = tlb->VPN & ~mask; -#if defined(TARGET_MIPS64) - tag &= env->SEGMask; -#endif - tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID; - /* Check ASID/MMID, virtual page number & size */ - if ((tlb->G == 1 || tlb_mmid == MMID) && VPN == tag && !tlb->EHINV) { - /* TLB match */ - env->CP0_Index = i; - break; - } - } - if (i == env->tlb->nb_tlb) { - /* No match. Discard any shadow entries, if any of them match. */ - for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) { - tlb = &env->tlb->mmu.r4k.tlb[i]; - /* 1k pages are not supported. */ - mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); - tag = env->CP0_EntryHi & ~mask; - VPN = tlb->VPN & ~mask; -#if defined(TARGET_MIPS64) - tag &= env->SEGMask; -#endif - tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID; - /* Check ASID/MMID, virtual page number & size */ - if ((tlb->G == 1 || tlb_mmid == MMID) && VPN == tag) { - r4k_mips_tlb_flush_extra(env, i); - break; - } - } - - env->CP0_Index |= 0x80000000; - } -} - -static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn) -{ -#if defined(TARGET_MIPS64) - return tlb_pfn << 6; -#else - return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */ - (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */ -#endif -} - -void r4k_helper_tlbr(CPUMIPSState *env) -{ - bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1); - uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; - uint32_t MMID = env->CP0_MemoryMapID; - uint32_t tlb_mmid; - r4k_tlb_t *tlb; - int idx; - - MMID = mi ? MMID : (uint32_t) ASID; - idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb; - tlb = &env->tlb->mmu.r4k.tlb[idx]; - - tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID; - /* If this will change the current ASID/MMID, flush qemu's TLB. */ - if (MMID != tlb_mmid) { - cpu_mips_tlb_flush(env); - } - - r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb); - - if (tlb->EHINV) { - env->CP0_EntryHi = 1 << CP0EnHi_EHINV; - env->CP0_PageMask = 0; - env->CP0_EntryLo0 = 0; - env->CP0_EntryLo1 = 0; - } else { - env->CP0_EntryHi = mi ? tlb->VPN : tlb->VPN | tlb->ASID; - env->CP0_MemoryMapID = tlb->MMID; - env->CP0_PageMask = tlb->PageMask; - env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | - ((uint64_t)tlb->RI0 << CP0EnLo_RI) | - ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) | - get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12); - env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | - ((uint64_t)tlb->RI1 << CP0EnLo_RI) | - ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) | - get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12); - } -} - -void helper_tlbwi(CPUMIPSState *env) -{ - env->tlb->helper_tlbwi(env); -} - -void helper_tlbwr(CPUMIPSState *env) -{ - env->tlb->helper_tlbwr(env); -} - -void helper_tlbp(CPUMIPSState *env) -{ - env->tlb->helper_tlbp(env); -} - -void helper_tlbr(CPUMIPSState *env) -{ - env->tlb->helper_tlbr(env); -} - -void helper_tlbinv(CPUMIPSState *env) -{ - env->tlb->helper_tlbinv(env); -} - -void helper_tlbinvf(CPUMIPSState *env) -{ - env->tlb->helper_tlbinvf(env); -} - -static void global_invalidate_tlb(CPUMIPSState *env, - uint32_t invMsgVPN2, - uint8_t invMsgR, - uint32_t invMsgMMid, - bool invAll, - bool invVAMMid, - bool invMMid, - bool invVA) -{ - - int idx; - r4k_tlb_t *tlb; - bool VAMatch; - bool MMidMatch; - - for (idx = 0; idx < env->tlb->nb_tlb; idx++) { - tlb = &env->tlb->mmu.r4k.tlb[idx]; - VAMatch = - (((tlb->VPN & ~tlb->PageMask) == (invMsgVPN2 & ~tlb->PageMask)) -#ifdef TARGET_MIPS64 - && - (extract64(env->CP0_EntryHi, 62, 2) == invMsgR) -#endif - ); - MMidMatch = tlb->MMID == invMsgMMid; - if ((invAll && (idx > env->CP0_Wired)) || - (VAMatch && invVAMMid && (tlb->G || MMidMatch)) || - (VAMatch && invVA) || - (MMidMatch && !(tlb->G) && invMMid)) { - tlb->EHINV = 1; - } - } - cpu_mips_tlb_flush(env); -} - -void helper_ginvt(CPUMIPSState *env, target_ulong arg, uint32_t type) -{ - bool invAll = type == 0; - bool invVA = type == 1; - bool invMMid = type == 2; - bool invVAMMid = type == 3; - uint32_t invMsgVPN2 = arg & (TARGET_PAGE_MASK << 1); - uint8_t invMsgR = 0; - uint32_t invMsgMMid = env->CP0_MemoryMapID; - CPUState *other_cs = first_cpu; - -#ifdef TARGET_MIPS64 - invMsgR = extract64(arg, 62, 2); -#endif - - CPU_FOREACH(other_cs) { - MIPSCPU *other_cpu = MIPS_CPU(other_cs); - global_invalidate_tlb(&other_cpu->env, invMsgVPN2, invMsgR, invMsgMMid, - invAll, invVAMMid, invMMid, invVA); - } -} - -#endif /* !CONFIG_USER_ONLY */ - static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc) { if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1 << reg))) { diff --git a/target/mips/tcg/sysemu/tlb_helper.c b/target/mips/tcg/sysemu/tlb_helper.c index a45146a2b2..259f780d19 100644 --- a/target/mips/tcg/sysemu/tlb_helper.c +++ b/target/mips/tcg/sysemu/tlb_helper.c @@ -24,6 +24,337 @@ #include "exec/cpu_ldst.h" #include "exec/log.h" #include "hw/mips/cpudevs.h" +#include "exec/helper-proto.h" + +/* TLB management */ +static void r4k_mips_tlb_flush_extra(CPUMIPSState *env, int first) +{ + /* Discard entries from env->tlb[first] onwards. */ + while (env->tlb->tlb_in_use > first) { + r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0); + } +} + +static inline uint64_t get_tlb_pfn_from_entrylo(uint64_t entrylo) +{ +#if defined(TARGET_MIPS64) + return extract64(entrylo, 6, 54); +#else + return extract64(entrylo, 6, 24) | /* PFN */ + (extract64(entrylo, 32, 32) << 24); /* PFNX */ +#endif +} + +static void r4k_fill_tlb(CPUMIPSState *env, int idx) +{ + r4k_tlb_t *tlb; + uint64_t mask = env->CP0_PageMask >> (TARGET_PAGE_BITS + 1); + + /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */ + tlb = &env->tlb->mmu.r4k.tlb[idx]; + if (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) { + tlb->EHINV = 1; + return; + } + tlb->EHINV = 0; + tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); +#if defined(TARGET_MIPS64) + tlb->VPN &= env->SEGMask; +#endif + tlb->ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; + tlb->MMID = env->CP0_MemoryMapID; + tlb->PageMask = env->CP0_PageMask; + tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; + tlb->V0 = (env->CP0_EntryLo0 & 2) != 0; + tlb->D0 = (env->CP0_EntryLo0 & 4) != 0; + tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7; + tlb->XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) & 1; + tlb->RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) & 1; + tlb->PFN[0] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo0) & ~mask) << 12; + tlb->V1 = (env->CP0_EntryLo1 & 2) != 0; + tlb->D1 = (env->CP0_EntryLo1 & 4) != 0; + tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7; + tlb->XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) & 1; + tlb->RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) & 1; + tlb->PFN[1] = (get_tlb_pfn_from_entrylo(env->CP0_EntryLo1) & ~mask) << 12; +} + +static void r4k_helper_tlbinv(CPUMIPSState *env) +{ + bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1); + uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; + uint32_t MMID = env->CP0_MemoryMapID; + uint32_t tlb_mmid; + r4k_tlb_t *tlb; + int idx; + + MMID = mi ? MMID : (uint32_t) ASID; + for (idx = 0; idx < env->tlb->nb_tlb; idx++) { + tlb = &env->tlb->mmu.r4k.tlb[idx]; + tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID; + if (!tlb->G && tlb_mmid == MMID) { + tlb->EHINV = 1; + } + } + cpu_mips_tlb_flush(env); +} + +static void r4k_helper_tlbinvf(CPUMIPSState *env) +{ + int idx; + + for (idx = 0; idx < env->tlb->nb_tlb; idx++) { + env->tlb->mmu.r4k.tlb[idx].EHINV = 1; + } + cpu_mips_tlb_flush(env); +} + +static void r4k_helper_tlbwi(CPUMIPSState *env) +{ + bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1); + target_ulong VPN; + uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; + uint32_t MMID = env->CP0_MemoryMapID; + uint32_t tlb_mmid; + bool EHINV, G, V0, D0, V1, D1, XI0, XI1, RI0, RI1; + r4k_tlb_t *tlb; + int idx; + + MMID = mi ? MMID : (uint32_t) ASID; + + idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb; + tlb = &env->tlb->mmu.r4k.tlb[idx]; + VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1); +#if defined(TARGET_MIPS64) + VPN &= env->SEGMask; +#endif + EHINV = (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) != 0; + G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1; + V0 = (env->CP0_EntryLo0 & 2) != 0; + D0 = (env->CP0_EntryLo0 & 4) != 0; + XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) &1; + RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) &1; + V1 = (env->CP0_EntryLo1 & 2) != 0; + D1 = (env->CP0_EntryLo1 & 4) != 0; + XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) &1; + RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) &1; + + tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID; + /* + * Discard cached TLB entries, unless tlbwi is just upgrading access + * permissions on the current entry. + */ + if (tlb->VPN != VPN || tlb_mmid != MMID || tlb->G != G || + (!tlb->EHINV && EHINV) || + (tlb->V0 && !V0) || (tlb->D0 && !D0) || + (!tlb->XI0 && XI0) || (!tlb->RI0 && RI0) || + (tlb->V1 && !V1) || (tlb->D1 && !D1) || + (!tlb->XI1 && XI1) || (!tlb->RI1 && RI1)) { + r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb); + } + + r4k_invalidate_tlb(env, idx, 0); + r4k_fill_tlb(env, idx); +} + +static void r4k_helper_tlbwr(CPUMIPSState *env) +{ + int r = cpu_mips_get_random(env); + + r4k_invalidate_tlb(env, r, 1); + r4k_fill_tlb(env, r); +} + +static void r4k_helper_tlbp(CPUMIPSState *env) +{ + bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1); + r4k_tlb_t *tlb; + target_ulong mask; + target_ulong tag; + target_ulong VPN; + uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; + uint32_t MMID = env->CP0_MemoryMapID; + uint32_t tlb_mmid; + int i; + + MMID = mi ? MMID : (uint32_t) ASID; + for (i = 0; i < env->tlb->nb_tlb; i++) { + tlb = &env->tlb->mmu.r4k.tlb[i]; + /* 1k pages are not supported. */ + mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); + tag = env->CP0_EntryHi & ~mask; + VPN = tlb->VPN & ~mask; +#if defined(TARGET_MIPS64) + tag &= env->SEGMask; +#endif + tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID; + /* Check ASID/MMID, virtual page number & size */ + if ((tlb->G == 1 || tlb_mmid == MMID) && VPN == tag && !tlb->EHINV) { + /* TLB match */ + env->CP0_Index = i; + break; + } + } + if (i == env->tlb->nb_tlb) { + /* No match. Discard any shadow entries, if any of them match. */ + for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) { + tlb = &env->tlb->mmu.r4k.tlb[i]; + /* 1k pages are not supported. */ + mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1); + tag = env->CP0_EntryHi & ~mask; + VPN = tlb->VPN & ~mask; +#if defined(TARGET_MIPS64) + tag &= env->SEGMask; +#endif + tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID; + /* Check ASID/MMID, virtual page number & size */ + if ((tlb->G == 1 || tlb_mmid == MMID) && VPN == tag) { + r4k_mips_tlb_flush_extra(env, i); + break; + } + } + + env->CP0_Index |= 0x80000000; + } +} + +static inline uint64_t get_entrylo_pfn_from_tlb(uint64_t tlb_pfn) +{ +#if defined(TARGET_MIPS64) + return tlb_pfn << 6; +#else + return (extract64(tlb_pfn, 0, 24) << 6) | /* PFN */ + (extract64(tlb_pfn, 24, 32) << 32); /* PFNX */ +#endif +} + +static void r4k_helper_tlbr(CPUMIPSState *env) +{ + bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1); + uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; + uint32_t MMID = env->CP0_MemoryMapID; + uint32_t tlb_mmid; + r4k_tlb_t *tlb; + int idx; + + MMID = mi ? MMID : (uint32_t) ASID; + idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb; + tlb = &env->tlb->mmu.r4k.tlb[idx]; + + tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID; + /* If this will change the current ASID/MMID, flush qemu's TLB. */ + if (MMID != tlb_mmid) { + cpu_mips_tlb_flush(env); + } + + r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb); + + if (tlb->EHINV) { + env->CP0_EntryHi = 1 << CP0EnHi_EHINV; + env->CP0_PageMask = 0; + env->CP0_EntryLo0 = 0; + env->CP0_EntryLo1 = 0; + } else { + env->CP0_EntryHi = mi ? tlb->VPN : tlb->VPN | tlb->ASID; + env->CP0_MemoryMapID = tlb->MMID; + env->CP0_PageMask = tlb->PageMask; + env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) | + ((uint64_t)tlb->RI0 << CP0EnLo_RI) | + ((uint64_t)tlb->XI0 << CP0EnLo_XI) | (tlb->C0 << 3) | + get_entrylo_pfn_from_tlb(tlb->PFN[0] >> 12); + env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) | + ((uint64_t)tlb->RI1 << CP0EnLo_RI) | + ((uint64_t)tlb->XI1 << CP0EnLo_XI) | (tlb->C1 << 3) | + get_entrylo_pfn_from_tlb(tlb->PFN[1] >> 12); + } +} + +void helper_tlbwi(CPUMIPSState *env) +{ + env->tlb->helper_tlbwi(env); +} + +void helper_tlbwr(CPUMIPSState *env) +{ + env->tlb->helper_tlbwr(env); +} + +void helper_tlbp(CPUMIPSState *env) +{ + env->tlb->helper_tlbp(env); +} + +void helper_tlbr(CPUMIPSState *env) +{ + env->tlb->helper_tlbr(env); +} + +void helper_tlbinv(CPUMIPSState *env) +{ + env->tlb->helper_tlbinv(env); +} + +void helper_tlbinvf(CPUMIPSState *env) +{ + env->tlb->helper_tlbinvf(env); +} + +static void global_invalidate_tlb(CPUMIPSState *env, + uint32_t invMsgVPN2, + uint8_t invMsgR, + uint32_t invMsgMMid, + bool invAll, + bool invVAMMid, + bool invMMid, + bool invVA) +{ + + int idx; + r4k_tlb_t *tlb; + bool VAMatch; + bool MMidMatch; + + for (idx = 0; idx < env->tlb->nb_tlb; idx++) { + tlb = &env->tlb->mmu.r4k.tlb[idx]; + VAMatch = + (((tlb->VPN & ~tlb->PageMask) == (invMsgVPN2 & ~tlb->PageMask)) +#ifdef TARGET_MIPS64 + && + (extract64(env->CP0_EntryHi, 62, 2) == invMsgR) +#endif + ); + MMidMatch = tlb->MMID == invMsgMMid; + if ((invAll && (idx > env->CP0_Wired)) || + (VAMatch && invVAMMid && (tlb->G || MMidMatch)) || + (VAMatch && invVA) || + (MMidMatch && !(tlb->G) && invMMid)) { + tlb->EHINV = 1; + } + } + cpu_mips_tlb_flush(env); +} + +void helper_ginvt(CPUMIPSState *env, target_ulong arg, uint32_t type) +{ + bool invAll = type == 0; + bool invVA = type == 1; + bool invMMid = type == 2; + bool invVAMMid = type == 3; + uint32_t invMsgVPN2 = arg & (TARGET_PAGE_MASK << 1); + uint8_t invMsgR = 0; + uint32_t invMsgMMid = env->CP0_MemoryMapID; + CPUState *other_cs = first_cpu; + +#ifdef TARGET_MIPS64 + invMsgR = extract64(arg, 62, 2); +#endif + + CPU_FOREACH(other_cs) { + MIPSCPU *other_cpu = MIPS_CPU(other_cs); + global_invalidate_tlb(&other_cpu->env, invMsgVPN2, invMsgR, invMsgMMid, + invAll, invVAMMid, invMMid, invVA); + } +} /* no MMU emulation */ static int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot, diff --git a/target/mips/tcg/sysemu_helper.h.inc b/target/mips/tcg/sysemu_helper.h.inc index 1ccbf68723..4353a966f9 100644 --- a/target/mips/tcg/sysemu_helper.h.inc +++ b/target/mips/tcg/sysemu_helper.h.inc @@ -167,6 +167,15 @@ DEF_HELPER_1(evpe, tl, env) DEF_HELPER_1(dvp, tl, env) DEF_HELPER_1(evp, tl, env) +/* TLB */ +DEF_HELPER_1(tlbwi, void, env) +DEF_HELPER_1(tlbwr, void, env) +DEF_HELPER_1(tlbp, void, env) +DEF_HELPER_1(tlbr, void, env) +DEF_HELPER_1(tlbinv, void, env) +DEF_HELPER_1(tlbinvf, void, env) +DEF_HELPER_3(ginvt, void, env, tl, i32) + /* Special */ DEF_HELPER_1(di, tl, env) DEF_HELPER_1(ei, tl, env) From 8aa52bdc87aaf54c497902a91aaf4096cb780660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 21:40:33 +0200 Subject: [PATCH 0204/3028] target/mips: Move exception management code to exception.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-27-f4bug@amsat.org> --- target/mips/cpu.c | 113 ---------------------- target/mips/exception.c | 167 +++++++++++++++++++++++++++++++++ target/mips/internal.h | 13 --- target/mips/meson.build | 1 + target/mips/op_helper.c | 37 -------- target/mips/tcg/tcg-internal.h | 14 +++ 6 files changed, 182 insertions(+), 163 deletions(-) create mode 100644 target/mips/exception.c diff --git a/target/mips/cpu.c b/target/mips/cpu.c index a33e3b6c20..daa9a4791e 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -218,112 +218,12 @@ static void mips_cpu_dump_state(CPUState *cs, FILE *f, int flags) } } -static const char * const excp_names[EXCP_LAST + 1] = { - [EXCP_RESET] = "reset", - [EXCP_SRESET] = "soft reset", - [EXCP_DSS] = "debug single step", - [EXCP_DINT] = "debug interrupt", - [EXCP_NMI] = "non-maskable interrupt", - [EXCP_MCHECK] = "machine check", - [EXCP_EXT_INTERRUPT] = "interrupt", - [EXCP_DFWATCH] = "deferred watchpoint", - [EXCP_DIB] = "debug instruction breakpoint", - [EXCP_IWATCH] = "instruction fetch watchpoint", - [EXCP_AdEL] = "address error load", - [EXCP_AdES] = "address error store", - [EXCP_TLBF] = "TLB refill", - [EXCP_IBE] = "instruction bus error", - [EXCP_DBp] = "debug breakpoint", - [EXCP_SYSCALL] = "syscall", - [EXCP_BREAK] = "break", - [EXCP_CpU] = "coprocessor unusable", - [EXCP_RI] = "reserved instruction", - [EXCP_OVERFLOW] = "arithmetic overflow", - [EXCP_TRAP] = "trap", - [EXCP_FPE] = "floating point", - [EXCP_DDBS] = "debug data break store", - [EXCP_DWATCH] = "data watchpoint", - [EXCP_LTLBL] = "TLB modify", - [EXCP_TLBL] = "TLB load", - [EXCP_TLBS] = "TLB store", - [EXCP_DBE] = "data bus error", - [EXCP_DDBL] = "debug data break load", - [EXCP_THREAD] = "thread", - [EXCP_MDMX] = "MDMX", - [EXCP_C2E] = "precise coprocessor 2", - [EXCP_CACHE] = "cache error", - [EXCP_TLBXI] = "TLB execute-inhibit", - [EXCP_TLBRI] = "TLB read-inhibit", - [EXCP_MSADIS] = "MSA disabled", - [EXCP_MSAFPE] = "MSA floating point", -}; - -const char *mips_exception_name(int32_t exception) -{ - if (exception < 0 || exception > EXCP_LAST) { - return "unknown"; - } - return excp_names[exception]; -} - void cpu_set_exception_base(int vp_index, target_ulong address) { MIPSCPU *vp = MIPS_CPU(qemu_get_cpu(vp_index)); vp->env.exception_base = address; } -target_ulong exception_resume_pc(CPUMIPSState *env) -{ - target_ulong bad_pc; - target_ulong isa_mode; - - isa_mode = !!(env->hflags & MIPS_HFLAG_M16); - bad_pc = env->active_tc.PC | isa_mode; - if (env->hflags & MIPS_HFLAG_BMASK) { - /* - * If the exception was raised from a delay slot, come back to - * the jump. - */ - bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); - } - - return bad_pc; -} - -bool mips_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -{ - if (interrupt_request & CPU_INTERRUPT_HARD) { - MIPSCPU *cpu = MIPS_CPU(cs); - CPUMIPSState *env = &cpu->env; - - if (cpu_mips_hw_interrupts_enabled(env) && - cpu_mips_hw_interrupts_pending(env)) { - /* Raise it */ - cs->exception_index = EXCP_EXT_INTERRUPT; - env->error_code = 0; - mips_cpu_do_interrupt(cs); - return true; - } - } - return false; -} - -void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, - uint32_t exception, - int error_code, - uintptr_t pc) -{ - CPUState *cs = env_cpu(env); - - qemu_log_mask(CPU_LOG_INT, "%s: %d (%s) %d\n", - __func__, exception, mips_exception_name(exception), - error_code); - cs->exception_index = exception; - env->error_code = error_code; - - cpu_loop_exit_restore(cs, pc); -} - static void mips_cpu_set_pc(CPUState *cs, vaddr value) { MIPSCPU *cpu = MIPS_CPU(cs); @@ -331,19 +231,6 @@ static void mips_cpu_set_pc(CPUState *cs, vaddr value) mips_env_set_pc(&cpu->env, value); } -#ifdef CONFIG_TCG -static void mips_cpu_synchronize_from_tb(CPUState *cs, - const TranslationBlock *tb) -{ - MIPSCPU *cpu = MIPS_CPU(cs); - CPUMIPSState *env = &cpu->env; - - env->active_tc.PC = tb->pc; - env->hflags &= ~MIPS_HFLAG_BMASK; - env->hflags |= tb->flags & MIPS_HFLAG_BMASK; -} -#endif /* CONFIG_TCG */ - static bool mips_cpu_has_work(CPUState *cs) { MIPSCPU *cpu = MIPS_CPU(cs); diff --git a/target/mips/exception.c b/target/mips/exception.c new file mode 100644 index 0000000000..4fb8b00711 --- /dev/null +++ b/target/mips/exception.c @@ -0,0 +1,167 @@ +/* + * MIPS Exceptions processing helpers for QEMU. + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internal.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" + +target_ulong exception_resume_pc(CPUMIPSState *env) +{ + target_ulong bad_pc; + target_ulong isa_mode; + + isa_mode = !!(env->hflags & MIPS_HFLAG_M16); + bad_pc = env->active_tc.PC | isa_mode; + if (env->hflags & MIPS_HFLAG_BMASK) { + /* + * If the exception was raised from a delay slot, come back to + * the jump. + */ + bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4); + } + + return bad_pc; +} + +void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception, + int error_code) +{ + do_raise_exception_err(env, exception, error_code, 0); +} + +void helper_raise_exception(CPUMIPSState *env, uint32_t exception) +{ + do_raise_exception(env, exception, GETPC()); +} + +void helper_raise_exception_debug(CPUMIPSState *env) +{ + do_raise_exception(env, EXCP_DEBUG, 0); +} + +static void raise_exception(CPUMIPSState *env, uint32_t exception) +{ + do_raise_exception(env, exception, 0); +} + +void helper_wait(CPUMIPSState *env) +{ + CPUState *cs = env_cpu(env); + + cs->halted = 1; + cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); + /* + * Last instruction in the block, PC was updated before + * - no need to recover PC and icount. + */ + raise_exception(env, EXCP_HLT); +} + +void mips_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) +{ + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + + env->active_tc.PC = tb->pc; + env->hflags &= ~MIPS_HFLAG_BMASK; + env->hflags |= tb->flags & MIPS_HFLAG_BMASK; +} + +bool mips_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + if (interrupt_request & CPU_INTERRUPT_HARD) { + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; + + if (cpu_mips_hw_interrupts_enabled(env) && + cpu_mips_hw_interrupts_pending(env)) { + /* Raise it */ + cs->exception_index = EXCP_EXT_INTERRUPT; + env->error_code = 0; + mips_cpu_do_interrupt(cs); + return true; + } + } + return false; +} + +static const char * const excp_names[EXCP_LAST + 1] = { + [EXCP_RESET] = "reset", + [EXCP_SRESET] = "soft reset", + [EXCP_DSS] = "debug single step", + [EXCP_DINT] = "debug interrupt", + [EXCP_NMI] = "non-maskable interrupt", + [EXCP_MCHECK] = "machine check", + [EXCP_EXT_INTERRUPT] = "interrupt", + [EXCP_DFWATCH] = "deferred watchpoint", + [EXCP_DIB] = "debug instruction breakpoint", + [EXCP_IWATCH] = "instruction fetch watchpoint", + [EXCP_AdEL] = "address error load", + [EXCP_AdES] = "address error store", + [EXCP_TLBF] = "TLB refill", + [EXCP_IBE] = "instruction bus error", + [EXCP_DBp] = "debug breakpoint", + [EXCP_SYSCALL] = "syscall", + [EXCP_BREAK] = "break", + [EXCP_CpU] = "coprocessor unusable", + [EXCP_RI] = "reserved instruction", + [EXCP_OVERFLOW] = "arithmetic overflow", + [EXCP_TRAP] = "trap", + [EXCP_FPE] = "floating point", + [EXCP_DDBS] = "debug data break store", + [EXCP_DWATCH] = "data watchpoint", + [EXCP_LTLBL] = "TLB modify", + [EXCP_TLBL] = "TLB load", + [EXCP_TLBS] = "TLB store", + [EXCP_DBE] = "data bus error", + [EXCP_DDBL] = "debug data break load", + [EXCP_THREAD] = "thread", + [EXCP_MDMX] = "MDMX", + [EXCP_C2E] = "precise coprocessor 2", + [EXCP_CACHE] = "cache error", + [EXCP_TLBXI] = "TLB execute-inhibit", + [EXCP_TLBRI] = "TLB read-inhibit", + [EXCP_MSADIS] = "MSA disabled", + [EXCP_MSAFPE] = "MSA floating point", +}; + +const char *mips_exception_name(int32_t exception) +{ + if (exception < 0 || exception > EXCP_LAST) { + return "unknown"; + } + return excp_names[exception]; +} + +void do_raise_exception_err(CPUMIPSState *env, uint32_t exception, + int error_code, uintptr_t pc) +{ + CPUState *cs = env_cpu(env); + + qemu_log_mask(CPU_LOG_INT, "%s: %d (%s) %d\n", + __func__, exception, mips_exception_name(exception), + error_code); + cs->exception_index = exception; + env->error_code = error_code; + + cpu_loop_exit_restore(cs, pc); +} diff --git a/target/mips/internal.h b/target/mips/internal.h index a1c7f658c2..07573c3e38 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -80,7 +80,6 @@ extern const char fregnames[32][4]; extern const struct mips_def_t mips_defs[]; extern const int mips_defs_number; -bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req); int mips_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, @@ -410,16 +409,4 @@ void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc); void cpu_mips_store_status(CPUMIPSState *env, target_ulong val); void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val); -const char *mips_exception_name(int32_t exception); - -void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception, - int error_code, uintptr_t pc); - -static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env, - uint32_t exception, - uintptr_t pc) -{ - do_raise_exception_err(env, exception, 0, pc); -} - #endif diff --git a/target/mips/meson.build b/target/mips/meson.build index ff5eb210df..e08077bfc1 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -24,6 +24,7 @@ mips_tcg_ss = ss.source_set() mips_tcg_ss.add(gen) mips_tcg_ss.add(files( 'dsp_helper.c', + 'exception.c', 'fpu_helper.c', 'ldst_helper.c', 'lmmi_helper.c', diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c index cb2a7e96fc..ce1549c985 100644 --- a/target/mips/op_helper.c +++ b/target/mips/op_helper.c @@ -26,30 +26,6 @@ #include "exec/memop.h" #include "fpu_helper.h" -/*****************************************************************************/ -/* Exceptions processing helpers */ - -void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception, - int error_code) -{ - do_raise_exception_err(env, exception, error_code, 0); -} - -void helper_raise_exception(CPUMIPSState *env, uint32_t exception) -{ - do_raise_exception(env, exception, GETPC()); -} - -void helper_raise_exception_debug(CPUMIPSState *env) -{ - do_raise_exception(env, EXCP_DEBUG, 0); -} - -static void raise_exception(CPUMIPSState *env, uint32_t exception) -{ - do_raise_exception(env, exception, 0); -} - /* 64 bits arithmetic for 32 bits hosts */ static inline uint64_t get_HILO(CPUMIPSState *env) { @@ -399,19 +375,6 @@ void helper_pmon(CPUMIPSState *env, int function) } } -void helper_wait(CPUMIPSState *env) -{ - CPUState *cs = env_cpu(env); - - cs->halted = 1; - cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE); - /* - * Last instruction in the block, PC was updated before - * - no need to recover PC and icount. - */ - raise_exception(env, EXCP_HLT); -} - #if !defined(CONFIG_USER_ONLY) void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr, diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h index 73667b3577..75aa3ef98e 100644 --- a/target/mips/tcg/tcg-internal.h +++ b/target/mips/tcg/tcg-internal.h @@ -14,11 +14,25 @@ #include "hw/core/cpu.h" #include "cpu.h" +void mips_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); void mips_cpu_do_interrupt(CPUState *cpu); +bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req); bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); +const char *mips_exception_name(int32_t exception); + +void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception, + int error_code, uintptr_t pc); + +static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env, + uint32_t exception, + uintptr_t pc) +{ + do_raise_exception_err(env, exception, 0, pc); +} + #if !defined(CONFIG_USER_ONLY) void mmu_init(CPUMIPSState *env, const mips_def_t *def); From 5679479b9a1b0dd4772904c3af0d02bb3c9e635f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 23:01:12 +0200 Subject: [PATCH 0205/3028] target/mips: Move CP0 helpers to sysemu/cp0.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opcodes accessing Coprocessor 0 are privileged. Move the CP0 helpers to sysemu/ and simplify the #ifdef'ry. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-28-f4bug@amsat.org> --- target/mips/cpu.c | 103 --------------------------- target/mips/internal.h | 9 +-- target/mips/sysemu/cp0.c | 123 +++++++++++++++++++++++++++++++++ target/mips/sysemu/meson.build | 1 + 4 files changed, 129 insertions(+), 107 deletions(-) create mode 100644 target/mips/sysemu/cp0.c diff --git a/target/mips/cpu.c b/target/mips/cpu.c index daa9a4791e..1ad2fe4aa3 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -42,109 +42,6 @@ const char regnames[32][4] = { "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", }; -#if !defined(CONFIG_USER_ONLY) - -/* Called for updates to CP0_Status. */ -void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc) -{ - int32_t tcstatus, *tcst; - uint32_t v = cpu->CP0_Status; - uint32_t cu, mx, asid, ksu; - uint32_t mask = ((1 << CP0TCSt_TCU3) - | (1 << CP0TCSt_TCU2) - | (1 << CP0TCSt_TCU1) - | (1 << CP0TCSt_TCU0) - | (1 << CP0TCSt_TMX) - | (3 << CP0TCSt_TKSU) - | (0xff << CP0TCSt_TASID)); - - cu = (v >> CP0St_CU0) & 0xf; - mx = (v >> CP0St_MX) & 0x1; - ksu = (v >> CP0St_KSU) & 0x3; - asid = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; - - tcstatus = cu << CP0TCSt_TCU0; - tcstatus |= mx << CP0TCSt_TMX; - tcstatus |= ksu << CP0TCSt_TKSU; - tcstatus |= asid; - - if (tc == cpu->current_tc) { - tcst = &cpu->active_tc.CP0_TCStatus; - } else { - tcst = &cpu->tcs[tc].CP0_TCStatus; - } - - *tcst &= ~mask; - *tcst |= tcstatus; - compute_hflags(cpu); -} - -void cpu_mips_store_status(CPUMIPSState *env, target_ulong val) -{ - uint32_t mask = env->CP0_Status_rw_bitmask; - target_ulong old = env->CP0_Status; - - if (env->insn_flags & ISA_MIPS_R6) { - bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3; -#if defined(TARGET_MIPS64) - uint32_t ksux = (1 << CP0St_KX) & val; - ksux |= (ksux >> 1) & val; /* KX = 0 forces SX to be 0 */ - ksux |= (ksux >> 1) & val; /* SX = 0 forces UX to be 0 */ - val = (val & ~(7 << CP0St_UX)) | ksux; -#endif - if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) { - mask &= ~(3 << CP0St_KSU); - } - mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val); - } - - env->CP0_Status = (old & ~mask) | (val & mask); -#if defined(TARGET_MIPS64) - if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) { - /* Access to at least one of the 64-bit segments has been disabled */ - tlb_flush(env_cpu(env)); - } -#endif - if (ase_mt_available(env)) { - sync_c0_status(env, env, env->current_tc); - } else { - compute_hflags(env); - } -} - -void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val) -{ - uint32_t mask = 0x00C00300; - uint32_t old = env->CP0_Cause; - int i; - - if (env->insn_flags & ISA_MIPS_R2) { - mask |= 1 << CP0Ca_DC; - } - if (env->insn_flags & ISA_MIPS_R6) { - mask &= ~((1 << CP0Ca_WP) & val); - } - - env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask); - - if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { - if (env->CP0_Cause & (1 << CP0Ca_DC)) { - cpu_mips_stop_count(env); - } else { - cpu_mips_start_count(env); - } - } - - /* Set/reset software interrupts */ - for (i = 0 ; i < 2 ; i++) { - if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { - cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i))); - } - } -} - -#endif /* !CONFIG_USER_ONLY */ - static void fpu_dump_fpr(fpr_t *fpr, FILE *f, bool is_fpu64) { if (is_fpu64) { diff --git a/target/mips/internal.h b/target/mips/internal.h index 07573c3e38..dd332b4dce 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -156,6 +156,11 @@ void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, MMUAccessType access_type, int mmu_idx, MemTxAttrs attrs, MemTxResult response, uintptr_t retaddr); + +void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc); +void cpu_mips_store_status(CPUMIPSState *env, target_ulong val); +void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val); + extern const VMStateDescription vmstate_mips_cpu; #endif /* !CONFIG_USER_ONLY */ @@ -405,8 +410,4 @@ static inline void compute_hflags(CPUMIPSState *env) } } -void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc); -void cpu_mips_store_status(CPUMIPSState *env, target_ulong val); -void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val); - #endif diff --git a/target/mips/sysemu/cp0.c b/target/mips/sysemu/cp0.c new file mode 100644 index 0000000000..bae37f515b --- /dev/null +++ b/target/mips/sysemu/cp0.c @@ -0,0 +1,123 @@ +/* + * QEMU MIPS CPU + * + * Copyright (c) 2012 SUSE LINUX Products GmbH + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internal.h" +#include "exec/exec-all.h" + +/* Called for updates to CP0_Status. */ +void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc) +{ + int32_t tcstatus, *tcst; + uint32_t v = cpu->CP0_Status; + uint32_t cu, mx, asid, ksu; + uint32_t mask = ((1 << CP0TCSt_TCU3) + | (1 << CP0TCSt_TCU2) + | (1 << CP0TCSt_TCU1) + | (1 << CP0TCSt_TCU0) + | (1 << CP0TCSt_TMX) + | (3 << CP0TCSt_TKSU) + | (0xff << CP0TCSt_TASID)); + + cu = (v >> CP0St_CU0) & 0xf; + mx = (v >> CP0St_MX) & 0x1; + ksu = (v >> CP0St_KSU) & 0x3; + asid = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; + + tcstatus = cu << CP0TCSt_TCU0; + tcstatus |= mx << CP0TCSt_TMX; + tcstatus |= ksu << CP0TCSt_TKSU; + tcstatus |= asid; + + if (tc == cpu->current_tc) { + tcst = &cpu->active_tc.CP0_TCStatus; + } else { + tcst = &cpu->tcs[tc].CP0_TCStatus; + } + + *tcst &= ~mask; + *tcst |= tcstatus; + compute_hflags(cpu); +} + +void cpu_mips_store_status(CPUMIPSState *env, target_ulong val) +{ + uint32_t mask = env->CP0_Status_rw_bitmask; + target_ulong old = env->CP0_Status; + + if (env->insn_flags & ISA_MIPS_R6) { + bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3; +#if defined(TARGET_MIPS64) + uint32_t ksux = (1 << CP0St_KX) & val; + ksux |= (ksux >> 1) & val; /* KX = 0 forces SX to be 0 */ + ksux |= (ksux >> 1) & val; /* SX = 0 forces UX to be 0 */ + val = (val & ~(7 << CP0St_UX)) | ksux; +#endif + if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) { + mask &= ~(3 << CP0St_KSU); + } + mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val); + } + + env->CP0_Status = (old & ~mask) | (val & mask); +#if defined(TARGET_MIPS64) + if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) { + /* Access to at least one of the 64-bit segments has been disabled */ + tlb_flush(env_cpu(env)); + } +#endif + if (ase_mt_available(env)) { + sync_c0_status(env, env, env->current_tc); + } else { + compute_hflags(env); + } +} + +void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val) +{ + uint32_t mask = 0x00C00300; + uint32_t old = env->CP0_Cause; + int i; + + if (env->insn_flags & ISA_MIPS_R2) { + mask |= 1 << CP0Ca_DC; + } + if (env->insn_flags & ISA_MIPS_R6) { + mask &= ~((1 << CP0Ca_WP) & val); + } + + env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask); + + if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { + if (env->CP0_Cause & (1 << CP0Ca_DC)) { + cpu_mips_stop_count(env); + } else { + cpu_mips_start_count(env); + } + } + + /* Set/reset software interrupts */ + for (i = 0 ; i < 2 ; i++) { + if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { + cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i))); + } + } +} diff --git a/target/mips/sysemu/meson.build b/target/mips/sysemu/meson.build index 925ceeaa44..cefc227582 100644 --- a/target/mips/sysemu/meson.build +++ b/target/mips/sysemu/meson.build @@ -1,5 +1,6 @@ mips_softmmu_ss.add(files( 'addr.c', + 'cp0.c', 'cp0_timer.c', 'machine.c', 'physaddr.c', From a2b0a27d33e9b1079698cee04ff029a0555b5ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 13 Apr 2021 10:47:10 +0200 Subject: [PATCH 0206/3028] target/mips: Move TCG source files under tcg/ sub directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To ease maintenance, move all TCG specific files under the tcg/ sub-directory. Adapt the Meson machinery. The following prototypes: - mips_tcg_init() - mips_cpu_do_unaligned_access() - mips_cpu_do_transaction_failed() can now be restricted to the "tcg-internal.h" header. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-29-f4bug@amsat.org> --- target/mips/helper.h | 2 +- target/mips/internal.h | 11 ------- target/mips/meson.build | 31 -------------------- target/mips/{ => tcg}/dsp_helper.c | 0 target/mips/{ => tcg}/exception.c | 0 target/mips/{ => tcg}/fpu_helper.c | 0 target/mips/{ => tcg}/ldst_helper.c | 0 target/mips/{ => tcg}/lmmi_helper.c | 0 target/mips/tcg/meson.build | 29 ++++++++++++++++++ target/mips/{ => tcg}/mips32r6.decode | 0 target/mips/{ => tcg}/mips64r6.decode | 0 target/mips/{ => tcg}/msa32.decode | 0 target/mips/{ => tcg}/msa64.decode | 0 target/mips/{ => tcg}/msa_helper.c | 0 target/mips/{ => tcg}/msa_helper.h.inc | 0 target/mips/{ => tcg}/msa_translate.c | 0 target/mips/{ => tcg}/mxu_translate.c | 0 target/mips/{ => tcg}/op_helper.c | 0 target/mips/{ => tcg}/rel6_translate.c | 0 target/mips/tcg/tcg-internal.h | 11 +++++++ target/mips/{ => tcg}/translate.c | 0 target/mips/{ => tcg}/translate_addr_const.c | 0 target/mips/{ => tcg}/tx79.decode | 0 target/mips/{ => tcg}/tx79_translate.c | 0 target/mips/{ => tcg}/txx9_translate.c | 0 25 files changed, 41 insertions(+), 43 deletions(-) rename target/mips/{ => tcg}/dsp_helper.c (100%) rename target/mips/{ => tcg}/exception.c (100%) rename target/mips/{ => tcg}/fpu_helper.c (100%) rename target/mips/{ => tcg}/ldst_helper.c (100%) rename target/mips/{ => tcg}/lmmi_helper.c (100%) rename target/mips/{ => tcg}/mips32r6.decode (100%) rename target/mips/{ => tcg}/mips64r6.decode (100%) rename target/mips/{ => tcg}/msa32.decode (100%) rename target/mips/{ => tcg}/msa64.decode (100%) rename target/mips/{ => tcg}/msa_helper.c (100%) rename target/mips/{ => tcg}/msa_helper.h.inc (100%) rename target/mips/{ => tcg}/msa_translate.c (100%) rename target/mips/{ => tcg}/mxu_translate.c (100%) rename target/mips/{ => tcg}/op_helper.c (100%) rename target/mips/{ => tcg}/rel6_translate.c (100%) rename target/mips/{ => tcg}/translate.c (100%) rename target/mips/{ => tcg}/translate_addr_const.c (100%) rename target/mips/{ => tcg}/tx79.decode (100%) rename target/mips/{ => tcg}/tx79_translate.c (100%) rename target/mips/{ => tcg}/txx9_translate.c (100%) diff --git a/target/mips/helper.h b/target/mips/helper.h index ba301ae160..a9c6c7d1a3 100644 --- a/target/mips/helper.h +++ b/target/mips/helper.h @@ -608,4 +608,4 @@ DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env) #include "tcg/sysemu_helper.h.inc" #endif /* !CONFIG_USER_ONLY */ -#include "msa_helper.h.inc" +#include "tcg/msa_helper.h.inc" diff --git a/target/mips/internal.h b/target/mips/internal.h index dd332b4dce..18d5da64a5 100644 --- a/target/mips/internal.h +++ b/target/mips/internal.h @@ -82,9 +82,6 @@ extern const int mips_defs_number; int mips_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, - MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr); #define USEG_LIMIT ((target_ulong)(int32_t)0x7FFFFFFFUL) #define KSEG0_BASE ((target_ulong)(int32_t)0x80000000UL) @@ -151,12 +148,6 @@ struct CPUMIPSTLBContext { } mmu; }; -void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, - vaddr addr, unsigned size, - MMUAccessType access_type, - int mmu_idx, MemTxAttrs attrs, - MemTxResult response, uintptr_t retaddr); - void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc); void cpu_mips_store_status(CPUMIPSState *env, target_ulong val); void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val); @@ -209,8 +200,6 @@ static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env) return r; } -void mips_tcg_init(void); - void msa_reset(CPUMIPSState *env); /* cp0_timer.c */ diff --git a/target/mips/meson.build b/target/mips/meson.build index e08077bfc1..2407a05d4c 100644 --- a/target/mips/meson.build +++ b/target/mips/meson.build @@ -1,11 +1,3 @@ -gen = [ - decodetree.process('mips32r6.decode', extra_args: '--static-decode=decode_mips32r6'), - decodetree.process('mips64r6.decode', extra_args: '--static-decode=decode_mips64r6'), - decodetree.process('msa32.decode', extra_args: '--static-decode=decode_msa32'), - decodetree.process('msa64.decode', extra_args: '--static-decode=decode_msa64'), - decodetree.process('tx79.decode', extra_args: '--static-decode=decode_tx79'), -] - mips_user_ss = ss.source_set() mips_softmmu_ss = ss.source_set() mips_ss = ss.source_set() @@ -20,35 +12,12 @@ if have_system subdir('sysemu') endif -mips_tcg_ss = ss.source_set() -mips_tcg_ss.add(gen) -mips_tcg_ss.add(files( - 'dsp_helper.c', - 'exception.c', - 'fpu_helper.c', - 'ldst_helper.c', - 'lmmi_helper.c', - 'msa_helper.c', - 'msa_translate.c', - 'op_helper.c', - 'rel6_translate.c', - 'translate.c', - 'translate_addr_const.c', - 'txx9_translate.c', -)) -mips_tcg_ss.add(when: 'TARGET_MIPS64', if_true: files( - 'tx79_translate.c', -), if_false: files( - 'mxu_translate.c', -)) if 'CONFIG_TCG' in config_all subdir('tcg') endif mips_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) -mips_ss.add_all(when: 'CONFIG_TCG', if_true: [mips_tcg_ss]) - target_arch += {'mips': mips_ss} target_softmmu_arch += {'mips': mips_softmmu_ss} target_user_arch += {'mips': mips_user_ss} diff --git a/target/mips/dsp_helper.c b/target/mips/tcg/dsp_helper.c similarity index 100% rename from target/mips/dsp_helper.c rename to target/mips/tcg/dsp_helper.c diff --git a/target/mips/exception.c b/target/mips/tcg/exception.c similarity index 100% rename from target/mips/exception.c rename to target/mips/tcg/exception.c diff --git a/target/mips/fpu_helper.c b/target/mips/tcg/fpu_helper.c similarity index 100% rename from target/mips/fpu_helper.c rename to target/mips/tcg/fpu_helper.c diff --git a/target/mips/ldst_helper.c b/target/mips/tcg/ldst_helper.c similarity index 100% rename from target/mips/ldst_helper.c rename to target/mips/tcg/ldst_helper.c diff --git a/target/mips/lmmi_helper.c b/target/mips/tcg/lmmi_helper.c similarity index 100% rename from target/mips/lmmi_helper.c rename to target/mips/tcg/lmmi_helper.c diff --git a/target/mips/tcg/meson.build b/target/mips/tcg/meson.build index 2cffc5a5ac..5d8acbaf0d 100644 --- a/target/mips/tcg/meson.build +++ b/target/mips/tcg/meson.build @@ -1,3 +1,32 @@ +gen = [ + decodetree.process('mips32r6.decode', extra_args: '--static-decode=decode_mips32r6'), + decodetree.process('mips64r6.decode', extra_args: '--static-decode=decode_mips64r6'), + decodetree.process('msa32.decode', extra_args: '--static-decode=decode_msa32'), + decodetree.process('msa64.decode', extra_args: '--static-decode=decode_msa64'), + decodetree.process('tx79.decode', extra_args: '--static-decode=decode_tx79'), +] + +mips_ss.add(gen) +mips_ss.add(files( + 'dsp_helper.c', + 'exception.c', + 'fpu_helper.c', + 'ldst_helper.c', + 'lmmi_helper.c', + 'msa_helper.c', + 'msa_translate.c', + 'op_helper.c', + 'rel6_translate.c', + 'translate.c', + 'translate_addr_const.c', + 'txx9_translate.c', +)) +mips_ss.add(when: 'TARGET_MIPS64', if_true: files( + 'tx79_translate.c', +), if_false: files( + 'mxu_translate.c', +)) + if have_user subdir('user') endif diff --git a/target/mips/mips32r6.decode b/target/mips/tcg/mips32r6.decode similarity index 100% rename from target/mips/mips32r6.decode rename to target/mips/tcg/mips32r6.decode diff --git a/target/mips/mips64r6.decode b/target/mips/tcg/mips64r6.decode similarity index 100% rename from target/mips/mips64r6.decode rename to target/mips/tcg/mips64r6.decode diff --git a/target/mips/msa32.decode b/target/mips/tcg/msa32.decode similarity index 100% rename from target/mips/msa32.decode rename to target/mips/tcg/msa32.decode diff --git a/target/mips/msa64.decode b/target/mips/tcg/msa64.decode similarity index 100% rename from target/mips/msa64.decode rename to target/mips/tcg/msa64.decode diff --git a/target/mips/msa_helper.c b/target/mips/tcg/msa_helper.c similarity index 100% rename from target/mips/msa_helper.c rename to target/mips/tcg/msa_helper.c diff --git a/target/mips/msa_helper.h.inc b/target/mips/tcg/msa_helper.h.inc similarity index 100% rename from target/mips/msa_helper.h.inc rename to target/mips/tcg/msa_helper.h.inc diff --git a/target/mips/msa_translate.c b/target/mips/tcg/msa_translate.c similarity index 100% rename from target/mips/msa_translate.c rename to target/mips/tcg/msa_translate.c diff --git a/target/mips/mxu_translate.c b/target/mips/tcg/mxu_translate.c similarity index 100% rename from target/mips/mxu_translate.c rename to target/mips/tcg/mxu_translate.c diff --git a/target/mips/op_helper.c b/target/mips/tcg/op_helper.c similarity index 100% rename from target/mips/op_helper.c rename to target/mips/tcg/op_helper.c diff --git a/target/mips/rel6_translate.c b/target/mips/tcg/rel6_translate.c similarity index 100% rename from target/mips/rel6_translate.c rename to target/mips/tcg/rel6_translate.c diff --git a/target/mips/tcg/tcg-internal.h b/target/mips/tcg/tcg-internal.h index 75aa3ef98e..81b14eb219 100644 --- a/target/mips/tcg/tcg-internal.h +++ b/target/mips/tcg/tcg-internal.h @@ -11,15 +11,21 @@ #define MIPS_TCG_INTERNAL_H #include "tcg/tcg.h" +#include "exec/memattrs.h" #include "hw/core/cpu.h" #include "cpu.h" +void mips_tcg_init(void); + void mips_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); void mips_cpu_do_interrupt(CPUState *cpu); bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req); bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); +void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr); const char *mips_exception_name(int32_t exception); @@ -46,6 +52,11 @@ bool mips_io_recompile_replay_branch(CPUState *cs, const TranslationBlock *tb); hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address, MMUAccessType access_type, uintptr_t retaddr); +void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, + vaddr addr, unsigned size, + MMUAccessType access_type, + int mmu_idx, MemTxAttrs attrs, + MemTxResult response, uintptr_t retaddr); void cpu_mips_tlb_flush(CPUMIPSState *env); #endif /* !CONFIG_USER_ONLY */ diff --git a/target/mips/translate.c b/target/mips/tcg/translate.c similarity index 100% rename from target/mips/translate.c rename to target/mips/tcg/translate.c diff --git a/target/mips/translate_addr_const.c b/target/mips/tcg/translate_addr_const.c similarity index 100% rename from target/mips/translate_addr_const.c rename to target/mips/tcg/translate_addr_const.c diff --git a/target/mips/tx79.decode b/target/mips/tcg/tx79.decode similarity index 100% rename from target/mips/tx79.decode rename to target/mips/tcg/tx79.decode diff --git a/target/mips/tx79_translate.c b/target/mips/tcg/tx79_translate.c similarity index 100% rename from target/mips/tx79_translate.c rename to target/mips/tcg/tx79_translate.c diff --git a/target/mips/txx9_translate.c b/target/mips/tcg/txx9_translate.c similarity index 100% rename from target/mips/txx9_translate.c rename to target/mips/tcg/txx9_translate.c From db6b6f4dbfb395c4fdc4f6e601315151dbbe0190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 Apr 2021 00:11:07 +0200 Subject: [PATCH 0207/3028] hw/mips: Restrict non-virtualized machines to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the malta and loongson3-virt machines support KVM. Restrict the other machines to TCG: - mipssim - magnum - pica61 - fuloong2e - boston Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-30-f4bug@amsat.org> --- hw/mips/meson.build | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/mips/meson.build b/hw/mips/meson.build index 1195716dc7..dd0101ad4d 100644 --- a/hw/mips/meson.build +++ b/hw/mips/meson.build @@ -1,12 +1,15 @@ mips_ss = ss.source_set() mips_ss.add(files('bootloader.c', 'mips_int.c')) mips_ss.add(when: 'CONFIG_FW_CFG_MIPS', if_true: files('fw_cfg.c')) -mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c')) mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c')) -mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c')) mips_ss.add(when: 'CONFIG_MALTA', if_true: files('gt64xxx_pci.c', 'malta.c')) -mips_ss.add(when: 'CONFIG_MIPSSIM', if_true: files('mipssim.c')) -mips_ss.add(when: 'CONFIG_MIPS_BOSTON', if_true: [files('boston.c'), fdt]) mips_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('cps.c')) +if 'CONFIG_TCG' in config_all +mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c')) +mips_ss.add(when: 'CONFIG_MIPSSIM', if_true: files('mipssim.c')) +mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c')) +mips_ss.add(when: 'CONFIG_MIPS_BOSTON', if_true: [files('boston.c'), fdt]) +endif + hw_arch += {'mips': mips_ss} From 1c13514449439b5ff1f746ed0bf73b298da39cf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 18 Apr 2021 17:33:52 +0200 Subject: [PATCH 0208/3028] gitlab-ci: Add KVM mips64el cross-build jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new job to cross-build the mips64el target without the TCG accelerator (IOW: only KVM accelerator enabled). Only build the mips64el target which is known to work and has users. Reviewed-by: Richard Henderson Acked-by: Thomas Huth Reviewed-by: Willian Rampazzo Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210428170410.479308-31-f4bug@amsat.org> --- .gitlab-ci.d/crossbuilds.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml index 2d95784ed5..e44e4b49a2 100644 --- a/.gitlab-ci.d/crossbuilds.yml +++ b/.gitlab-ci.d/crossbuilds.yml @@ -176,6 +176,14 @@ cross-s390x-kvm-only: IMAGE: debian-s390x-cross ACCEL_CONFIGURE_OPTS: --disable-tcg +cross-mips64el-kvm-only: + extends: .cross_accel_build_job + needs: + job: mips64el-debian-cross-container + variables: + IMAGE: debian-mips64el-cross + ACCEL_CONFIGURE_OPTS: --disable-tcg --target-list=mips64el-softmmu + cross-win32-system: extends: .cross_system_build_job needs: From 56567da376e1dd443e06d3c1026f0a5e58abbfa9 Mon Sep 17 00:00:00 2001 From: David Edmondson Date: Wed, 28 Apr 2021 15:24:31 +0100 Subject: [PATCH 0209/3028] accel: kvm: clarify that extra exit data is hexadecimal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When dumping the extra exit data provided by KVM, make it clear that the data is hexadecimal. At the same time, zero-pad the output. Signed-off-by: David Edmondson Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210428142431.266879-1-david.edmondson@oracle.com> Signed-off-by: Laurent Vivier --- accel/kvm/kvm-all.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index b6d9f92f15..93d7cbfeaf 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -2269,7 +2269,7 @@ static int kvm_handle_internal_error(CPUState *cpu, struct kvm_run *run) int i; for (i = 0; i < run->internal.ndata; ++i) { - fprintf(stderr, "extra data[%d]: %"PRIx64"\n", + fprintf(stderr, "extra data[%d]: 0x%016"PRIx64"\n", i, (uint64_t)run->internal.data[i]); } } From 5c8ae30b2484f241890841e83435af092a3c508f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 25 Apr 2021 00:20:55 +0200 Subject: [PATCH 0210/3028] hw/arm/pxa2xx: Declare PCMCIA bus with Kconfig MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Intel XScale PXA chipsets provide a PCMCIA controller, which expose a PCMCIA bus. Express this dependency using the Kconfig 'select' expression. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Warner Losh Reviewed-by: Richard Henderson Message-Id: <20210424222057.3434459-2-f4bug@amsat.org> [lv: remove "(IDE)"] Signed-off-by: Laurent Vivier --- hw/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 8c37cf00da..b887f6a5b1 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -142,6 +142,7 @@ config PXA2XX select SD select SSI select USB_OHCI + select PCMCIA config GUMSTIX bool From 2a406e38e6f0cb2070a30ea98e779ca93a04df48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 25 Apr 2021 00:20:56 +0200 Subject: [PATCH 0211/3028] hw/ide: Add Kconfig dependency MICRODRIVE -> PCMCIA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Microdrive Compact Flash can be plugged on a PCMCIA bus. Express the dependency using the 'depends on' Kconfig expression. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Warner Losh Reviewed-by: Richard Henderson Message-Id: <20210424222057.3434459-3-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/ide/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ide/Kconfig b/hw/ide/Kconfig index 5d9106b1ac..8e2c893454 100644 --- a/hw/ide/Kconfig +++ b/hw/ide/Kconfig @@ -41,6 +41,7 @@ config IDE_VIA config MICRODRIVE bool select IDE_QDEV + depends on PCMCIA config AHCI bool From 32bec2eea2c5ab96ba8b149cda7e33716678a5a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 25 Apr 2021 00:20:57 +0200 Subject: [PATCH 0212/3028] hw/pcmcia: Do not register PCMCIA type if not required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the Kconfig 'PCMCIA' value is not selected, it is pointless to build the PCMCIA core components. (Currently only one machine of the ARM targets requires this). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210424222057.3434459-4-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/pcmcia/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pcmcia/meson.build b/hw/pcmcia/meson.build index ab50bd325d..51f2512b8e 100644 --- a/hw/pcmcia/meson.build +++ b/hw/pcmcia/meson.build @@ -1,2 +1,2 @@ -softmmu_ss.add(files('pcmcia.c')) +softmmu_ss.add(when: 'CONFIG_PCMCIA', if_true: files('pcmcia.c')) softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx.c')) From 04a252112119d34e10d9b0bd65c499e1b17dc8fe Mon Sep 17 00:00:00 2001 From: Serge Guelton Date: Fri, 30 Apr 2021 17:07:45 +0200 Subject: [PATCH 0213/3028] Fix typo in CFI build documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Serge Guelton Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210430150745.GA1401713@sguelton.remote.csb> Signed-off-by: Laurent Vivier --- docs/devel/control-flow-integrity.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/devel/control-flow-integrity.rst b/docs/devel/control-flow-integrity.rst index d89d70733d..e6b73a4fe1 100644 --- a/docs/devel/control-flow-integrity.rst +++ b/docs/devel/control-flow-integrity.rst @@ -39,7 +39,7 @@ later). Given the use of LTO, a version of AR that supports LLVM IR is required. The easies way of doing this is by selecting the AR provided by LLVM:: - AR=llvm-ar-9 CC=clang-9 CXX=lang++-9 /path/to/configure --enable-cfi + AR=llvm-ar-9 CC=clang-9 CXX=clang++-9 /path/to/configure --enable-cfi CFI is enabled on every binary produced. @@ -131,7 +131,7 @@ lld with version 11+. In other words, to compile with fuzzing and CFI, clang 11+ is required, and lld needs to be used as a linker:: - AR=llvm-ar-11 CC=clang-11 CXX=lang++-11 /path/to/configure --enable-cfi \ + AR=llvm-ar-11 CC=clang-11 CXX=clang++-11 /path/to/configure --enable-cfi \ -enable-fuzzing --extra-ldflags="-fuse-ld=lld" and then, compile the fuzzers as usual. From ac701a4f98d68156fcddbe3bb3f7c3869b8c646e Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Thu, 8 Apr 2021 22:07:06 +0800 Subject: [PATCH 0214/3028] vmstate: Constify some VMStateDescriptions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Constify vmstate_ecc_state and vmstate_x86_cpu. Signed-off-by: Keqian Zhu Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210408140706.23412-1-zhukeqian1@huawei.com> Signed-off-by: Laurent Vivier --- hw/block/ecc.c | 2 +- include/hw/block/flash.h | 2 +- target/i386/cpu.h | 2 +- target/i386/machine.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/block/ecc.c b/hw/block/ecc.c index 1a182367ee..6e0d63842c 100644 --- a/hw/block/ecc.c +++ b/hw/block/ecc.c @@ -78,7 +78,7 @@ void ecc_reset(ECCState *s) } /* Save/restore */ -VMStateDescription vmstate_ecc_state = { +const VMStateDescription vmstate_ecc_state = { .name = "ecc-state", .version_id = 0, .minimum_version_id = 0, diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h index 7dde0adcee..86d8363bb0 100644 --- a/include/hw/block/flash.h +++ b/include/hw/block/flash.h @@ -74,6 +74,6 @@ typedef struct { uint8_t ecc_digest(ECCState *s, uint8_t sample); void ecc_reset(ECCState *s); -extern VMStateDescription vmstate_ecc_state; +extern const VMStateDescription vmstate_ecc_state; #endif diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 570f916878..1bc300ce85 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1786,7 +1786,7 @@ struct X86CPU { #ifndef CONFIG_USER_ONLY -extern VMStateDescription vmstate_x86_cpu; +extern const VMStateDescription vmstate_x86_cpu; #endif int x86_cpu_pending_interrupt(CPUState *cs, int interrupt_request); diff --git a/target/i386/machine.c b/target/i386/machine.c index 137604ddb8..f6f094f1c9 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -1396,7 +1396,7 @@ static const VMStateDescription vmstate_msr_tsx_ctrl = { } }; -VMStateDescription vmstate_x86_cpu = { +const VMStateDescription vmstate_x86_cpu = { .name = "cpu", .version_id = 12, .minimum_version_id = 11, From cfa52e09c4ddf6698e3e7b590ab3b9e2a01977dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 13 Mar 2021 18:11:48 +0100 Subject: [PATCH 0215/3028] hw/arm: Constify VMStateDescription MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210313171150.2122409-2-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/arm/highbank.c | 2 +- hw/arm/pxa2xx_pic.c | 2 +- hw/arm/spitz.c | 4 ++-- hw/arm/strongarm.c | 2 +- hw/arm/z2.c | 4 ++-- hw/dma/pxa2xx_dma.c | 4 ++-- hw/misc/mst_fpga.c | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index bf886268c5..5afdd28b35 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -170,7 +170,7 @@ struct HighbankRegsState { uint32_t regs[NUM_REGS]; }; -static VMStateDescription vmstate_highbank_regs = { +static const VMStateDescription vmstate_highbank_regs = { .name = "highbank-regs", .version_id = 0, .minimum_version_id = 0, diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index cf6cb2a373..ed032fed54 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -301,7 +301,7 @@ DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu) return dev; } -static VMStateDescription vmstate_pxa2xx_pic_regs = { +static const VMStateDescription vmstate_pxa2xx_pic_regs = { .name = "pxa2xx_pic", .version_id = 0, .minimum_version_id = 0, diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 6b3bf9828b..b45a929cbd 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -1134,7 +1134,7 @@ static bool is_version_0(void *opaque, int version_id) return version_id == 0; } -static VMStateDescription vmstate_sl_nand_info = { +static const VMStateDescription vmstate_sl_nand_info = { .name = "sl-nand", .version_id = 0, .minimum_version_id = 0, @@ -1170,7 +1170,7 @@ static const TypeInfo sl_nand_info = { .class_init = sl_nand_class_init, }; -static VMStateDescription vmstate_spitz_kbd = { +static const VMStateDescription vmstate_spitz_kbd = { .name = "spitz-keyboard", .version_id = 1, .minimum_version_id = 0, diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index c7ca54bcea..e3e3ea6163 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -207,7 +207,7 @@ static int strongarm_pic_post_load(void *opaque, int version_id) return 0; } -static VMStateDescription vmstate_strongarm_pic_regs = { +static const VMStateDescription vmstate_strongarm_pic_regs = { .name = "strongarm_pic", .version_id = 0, .minimum_version_id = 0, diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 5099bd8380..9c1e876207 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -162,7 +162,7 @@ static void zipit_lcd_realize(SSIPeripheral *dev, Error **errp) z->pos = 0; } -static VMStateDescription vmstate_zipit_lcd_state = { +static const VMStateDescription vmstate_zipit_lcd_state = { .name = "zipit-lcd", .version_id = 2, .minimum_version_id = 2, @@ -268,7 +268,7 @@ static uint8_t aer915_recv(I2CSlave *slave) return retval; } -static VMStateDescription vmstate_aer915_state = { +static const VMStateDescription vmstate_aer915_state = { .name = "aer915", .version_id = 1, .minimum_version_id = 1, diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c index b3707ff3de..fa896f7edf 100644 --- a/hw/dma/pxa2xx_dma.c +++ b/hw/dma/pxa2xx_dma.c @@ -525,7 +525,7 @@ static bool is_version_0(void *opaque, int version_id) return version_id == 0; } -static VMStateDescription vmstate_pxa2xx_dma_chan = { +static const VMStateDescription vmstate_pxa2xx_dma_chan = { .name = "pxa2xx_dma_chan", .version_id = 1, .minimum_version_id = 1, @@ -540,7 +540,7 @@ static VMStateDescription vmstate_pxa2xx_dma_chan = { }, }; -static VMStateDescription vmstate_pxa2xx_dma = { +static const VMStateDescription vmstate_pxa2xx_dma = { .name = "pxa2xx_dma", .version_id = 1, .minimum_version_id = 0, diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c index edfc35d5f0..2aaadfa966 100644 --- a/hw/misc/mst_fpga.c +++ b/hw/misc/mst_fpga.c @@ -222,7 +222,7 @@ static void mst_fpga_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } -static VMStateDescription vmstate_mst_fpga_regs = { +static const VMStateDescription vmstate_mst_fpga_regs = { .name = "mainstone_fpga", .version_id = 0, .minimum_version_id = 0, From 54cbf294d37d7d7ba7fefa38a7708c808e53a9c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 13 Mar 2021 18:11:49 +0100 Subject: [PATCH 0216/3028] hw/display/qxl: Constify VMStateDescription MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210313171150.2122409-3-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/display/qxl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 93907e82a3..2ba75637ec 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2384,7 +2384,7 @@ static bool qxl_monitors_config_needed(void *opaque) } -static VMStateDescription qxl_memslot = { +static const VMStateDescription qxl_memslot = { .name = "qxl-memslot", .version_id = QXL_SAVE_VERSION, .minimum_version_id = QXL_SAVE_VERSION, @@ -2396,7 +2396,7 @@ static VMStateDescription qxl_memslot = { } }; -static VMStateDescription qxl_surface = { +static const VMStateDescription qxl_surface = { .name = "qxl-surface", .version_id = QXL_SAVE_VERSION, .minimum_version_id = QXL_SAVE_VERSION, @@ -2414,7 +2414,7 @@ static VMStateDescription qxl_surface = { } }; -static VMStateDescription qxl_vmstate_monitors_config = { +static const VMStateDescription qxl_vmstate_monitors_config = { .name = "qxl/monitors-config", .version_id = 1, .minimum_version_id = 1, @@ -2425,7 +2425,7 @@ static VMStateDescription qxl_vmstate_monitors_config = { }, }; -static VMStateDescription qxl_vmstate = { +static const VMStateDescription qxl_vmstate = { .name = "qxl", .version_id = QXL_SAVE_VERSION, .minimum_version_id = QXL_SAVE_VERSION, From db2dc7d8df15c5365dbe70f3cb0d5d61594a6807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 13 Mar 2021 18:11:50 +0100 Subject: [PATCH 0217/3028] hw/usb: Constify VMStateDescription MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210313171150.2122409-4-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/usb/ccid-card-passthru.c | 2 +- hw/usb/dev-smartcard-reader.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index c1a90fcc7a..7212d0d7fb 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -374,7 +374,7 @@ static void passthru_realize(CCIDCardState *base, Error **errp) card->atr_length = sizeof(DEFAULT_ATR); } -static VMStateDescription passthru_vmstate = { +static const VMStateDescription passthru_vmstate = { .name = "ccid-card-passthru", .version_id = 1, .minimum_version_id = 1, diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index bc3d94092a..f7043075be 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1365,7 +1365,7 @@ static int ccid_pre_save(void *opaque) return 0; } -static VMStateDescription bulk_in_vmstate = { +static const VMStateDescription bulk_in_vmstate = { .name = "CCID BulkIn state", .version_id = 1, .minimum_version_id = 1, @@ -1377,7 +1377,7 @@ static VMStateDescription bulk_in_vmstate = { } }; -static VMStateDescription answer_vmstate = { +static const VMStateDescription answer_vmstate = { .name = "CCID Answer state", .version_id = 1, .minimum_version_id = 1, @@ -1388,7 +1388,7 @@ static VMStateDescription answer_vmstate = { } }; -static VMStateDescription usb_device_vmstate = { +static const VMStateDescription usb_device_vmstate = { .name = "usb_device", .version_id = 1, .minimum_version_id = 1, @@ -1400,7 +1400,7 @@ static VMStateDescription usb_device_vmstate = { } }; -static VMStateDescription ccid_vmstate = { +static const VMStateDescription ccid_vmstate = { .name = "usb-ccid", .version_id = 1, .minimum_version_id = 1, From 7c06a34c8c4f2c883d6ab6b15faa214d4ebfb269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 30 Apr 2021 17:50:09 +0200 Subject: [PATCH 0218/3028] ui: Fix memory leak in qemu_xkeymap_mapping_table() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor qemu_xkeymap_mapping_table() to have a single exit point, so we can easily free the memory allocated by XGetAtomName(). This fixes when running a binary configured with --enable-sanitizers: Direct leak of 22 byte(s) in 1 object(s) allocated from: #0 0x561344a7473f in malloc (qemu-system-x86_64+0x1dab73f) #1 0x7fa4d9dc08aa in XGetAtomName (/lib64/libX11.so.6+0x2a8aa) Fixes: 2ec78706d18 ("ui: convert GTK and SDL1 frontends to keycodemapdb") Reviewed-by: Daniel P. Berrangé Reviewed-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210430155009.259755-1-philmd@redhat.com> Signed-off-by: Laurent Vivier --- ui/x_keymap.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ui/x_keymap.c b/ui/x_keymap.c index 555086fb6b..2ce7b89961 100644 --- a/ui/x_keymap.c +++ b/ui/x_keymap.c @@ -56,6 +56,7 @@ const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen) { XkbDescPtr desc; const gchar *keycodes = NULL; + const guint16 *map; /* There is no easy way to determine what X11 server * and platform & keyboard driver is in use. Thus we @@ -83,21 +84,21 @@ const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen) if (check_for_xwin(dpy)) { trace_xkeymap_keymap("xwin"); *maplen = qemu_input_map_xorgxwin_to_qcode_len; - return qemu_input_map_xorgxwin_to_qcode; + map = qemu_input_map_xorgxwin_to_qcode; } else if (check_for_xquartz(dpy)) { trace_xkeymap_keymap("xquartz"); *maplen = qemu_input_map_xorgxquartz_to_qcode_len; - return qemu_input_map_xorgxquartz_to_qcode; + map = qemu_input_map_xorgxquartz_to_qcode; } else if ((keycodes && g_str_has_prefix(keycodes, "evdev")) || (XKeysymToKeycode(dpy, XK_Page_Up) == 0x70)) { trace_xkeymap_keymap("evdev"); *maplen = qemu_input_map_xorgevdev_to_qcode_len; - return qemu_input_map_xorgevdev_to_qcode; + map = qemu_input_map_xorgevdev_to_qcode; } else if ((keycodes && g_str_has_prefix(keycodes, "xfree86")) || (XKeysymToKeycode(dpy, XK_Page_Up) == 0x63)) { trace_xkeymap_keymap("kbd"); *maplen = qemu_input_map_xorgkbd_to_qcode_len; - return qemu_input_map_xorgkbd_to_qcode; + map = qemu_input_map_xorgkbd_to_qcode; } else { trace_xkeymap_keymap("NULL"); g_warning("Unknown X11 keycode mapping '%s'.\n" @@ -109,6 +110,10 @@ const guint16 *qemu_xkeymap_mapping_table(Display *dpy, size_t *maplen) " - xprop -root\n" " - xdpyinfo\n", keycodes ? keycodes : ""); - return NULL; + map = NULL; } + if (keycodes) { + XFree((void *)keycodes); + } + return map; } From e06054368cceb59f720e9d7c2ceca84329105758 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 26 Mar 2021 16:18:48 +0100 Subject: [PATCH 0219/3028] hw: Remove superfluous includes of hw/hw.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The include/hw/hw.h header only has a prototype for hw_error(), so it does not make sense to include this in files that do not use this function. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210326151848.2217216-1-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/arm/musicpal.c | 1 - hw/char/sifive_uart.c | 1 - hw/display/next-fb.c | 1 - hw/dma/sifive_pdma.c | 1 - hw/dma/xlnx_csu_dma.c | 1 - hw/hppa/lasi.c | 1 - hw/input/lasips2.c | 1 - hw/m68k/mcf_intc.c | 1 - hw/m68k/next-kbd.c | 1 - hw/m68k/q800.c | 1 - hw/m68k/virt.c | 1 - hw/misc/mchp_pfsoc_dmc.c | 1 - hw/misc/mchp_pfsoc_ioscb.c | 1 - hw/misc/mchp_pfsoc_sysreg.c | 1 - hw/misc/sifive_e_prci.c | 1 - hw/misc/sifive_test.c | 1 - hw/rx/rx-gdbsim.c | 1 - hw/rx/rx62n.c | 1 - hw/vfio/pci-quirks.c | 1 - include/hw/char/avr_usart.h | 1 - include/hw/misc/avr_power.h | 1 - include/hw/misc/stm32f4xx_exti.h | 1 - include/hw/misc/stm32f4xx_syscfg.h | 1 - include/hw/pci-host/i440fx.h | 1 - include/hw/timer/avr_timer16.h | 1 - 25 files changed, 25 deletions(-) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 9cebece2de..7d67dc7254 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -19,7 +19,6 @@ #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/char/serial.h" -#include "hw/hw.h" #include "qemu/timer.h" #include "hw/ptimer.h" #include "hw/qdev-properties.h" diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c index 3a00ba7f00..ee7adb8e30 100644 --- a/hw/char/sifive_uart.c +++ b/hw/char/sifive_uart.c @@ -22,7 +22,6 @@ #include "hw/sysbus.h" #include "chardev/char.h" #include "chardev/char-fe.h" -#include "hw/hw.h" #include "hw/irq.h" #include "hw/char/sifive_uart.h" diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c index e2d895109d..cc134c2d5b 100644 --- a/hw/display/next-fb.c +++ b/hw/display/next-fb.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "ui/console.h" -#include "hw/hw.h" #include "hw/boards.h" #include "hw/loader.h" #include "framebuffer.h" diff --git a/hw/dma/sifive_pdma.c b/hw/dma/sifive_pdma.c index e1f6fedbda..9b2ac2017d 100644 --- a/hw/dma/sifive_pdma.c +++ b/hw/dma/sifive_pdma.c @@ -24,7 +24,6 @@ #include "qemu/bitops.h" #include "qemu/log.h" #include "qapi/error.h" -#include "hw/hw.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c index 98324dadcd..797b4fed8f 100644 --- a/hw/dma/xlnx_csu_dma.c +++ b/hw/dma/xlnx_csu_dma.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qapi/error.h" -#include "hw/hw.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 1a85657948..a8f5defcd0 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -15,7 +15,6 @@ #include "qapi/error.h" #include "cpu.h" #include "trace.h" -#include "hw/hw.h" #include "hw/irq.h" #include "sysemu/sysemu.h" #include "sysemu/runstate.h" diff --git a/hw/input/lasips2.c b/hw/input/lasips2.c index 0786e57338..60afb94c78 100644 --- a/hw/input/lasips2.c +++ b/hw/input/lasips2.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "hw/qdev-properties.h" -#include "hw/hw.h" #include "hw/input/ps2.h" #include "hw/input/lasips2.h" #include "hw/sysbus.h" diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c index cf02f57a71..4cd30188c0 100644 --- a/hw/m68k/mcf_intc.c +++ b/hw/m68k/mcf_intc.c @@ -11,7 +11,6 @@ #include "qemu/module.h" #include "qemu/log.h" #include "cpu.h" -#include "hw/hw.h" #include "hw/irq.h" #include "hw/sysbus.h" #include "hw/m68k/mcf.h" diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c index c11b5281f1..bee40e25bc 100644 --- a/hw/m68k/next-kbd.c +++ b/hw/m68k/next-kbd.c @@ -30,7 +30,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "exec/address-spaces.h" -#include "hw/hw.h" #include "hw/sysbus.h" #include "hw/m68k/next-cube.h" #include "ui/console.h" diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 4d2e866eec..1c7f7aa07f 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -26,7 +26,6 @@ #include "qemu/datadir.h" #include "sysemu/sysemu.h" #include "cpu.h" -#include "hw/hw.h" #include "hw/boards.h" #include "hw/irq.h" #include "hw/or-irq.h" diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index e9a5d4c69b..18e6f11041 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -12,7 +12,6 @@ #include "qemu-common.h" #include "sysemu/sysemu.h" #include "cpu.h" -#include "hw/hw.h" #include "hw/boards.h" #include "hw/irq.h" #include "hw/qdev-properties.h" diff --git a/hw/misc/mchp_pfsoc_dmc.c b/hw/misc/mchp_pfsoc_dmc.c index 15cf3d7725..43d8e970ab 100644 --- a/hw/misc/mchp_pfsoc_dmc.c +++ b/hw/misc/mchp_pfsoc_dmc.c @@ -24,7 +24,6 @@ #include "qemu/bitops.h" #include "qemu/log.h" #include "qapi/error.h" -#include "hw/hw.h" #include "hw/sysbus.h" #include "hw/misc/mchp_pfsoc_dmc.h" diff --git a/hw/misc/mchp_pfsoc_ioscb.c b/hw/misc/mchp_pfsoc_ioscb.c index 8b0d1cacd7..f4fd55a0e5 100644 --- a/hw/misc/mchp_pfsoc_ioscb.c +++ b/hw/misc/mchp_pfsoc_ioscb.c @@ -24,7 +24,6 @@ #include "qemu/bitops.h" #include "qemu/log.h" #include "qapi/error.h" -#include "hw/hw.h" #include "hw/sysbus.h" #include "hw/misc/mchp_pfsoc_ioscb.h" diff --git a/hw/misc/mchp_pfsoc_sysreg.c b/hw/misc/mchp_pfsoc_sysreg.c index 248a313345..89571eded5 100644 --- a/hw/misc/mchp_pfsoc_sysreg.c +++ b/hw/misc/mchp_pfsoc_sysreg.c @@ -24,7 +24,6 @@ #include "qemu/bitops.h" #include "qemu/log.h" #include "qapi/error.h" -#include "hw/hw.h" #include "hw/sysbus.h" #include "hw/misc/mchp_pfsoc_sysreg.h" diff --git a/hw/misc/sifive_e_prci.c b/hw/misc/sifive_e_prci.c index 8ec4ee4b41..a8702c6a5d 100644 --- a/hw/misc/sifive_e_prci.c +++ b/hw/misc/sifive_e_prci.c @@ -23,7 +23,6 @@ #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" -#include "hw/hw.h" #include "hw/misc/sifive_e_prci.h" static uint64_t sifive_e_prci_read(void *opaque, hwaddr addr, unsigned int size) diff --git a/hw/misc/sifive_test.c b/hw/misc/sifive_test.c index 2deb2072cc..56df45bfe5 100644 --- a/hw/misc/sifive_test.c +++ b/hw/misc/sifive_test.c @@ -24,7 +24,6 @@ #include "qemu/log.h" #include "qemu/module.h" #include "sysemu/runstate.h" -#include "hw/hw.h" #include "hw/misc/sifive_test.h" static uint64_t sifive_test_read(void *opaque, hwaddr addr, unsigned int size) diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c index b1d7c2488f..8c611b0a59 100644 --- a/hw/rx/rx-gdbsim.c +++ b/hw/rx/rx-gdbsim.c @@ -22,7 +22,6 @@ #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" -#include "hw/hw.h" #include "hw/sysbus.h" #include "hw/loader.h" #include "hw/rx/rx62n.h" diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index 9c34ce14de..31ddccf2cd 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "hw/hw.h" #include "hw/rx/rx62n.h" #include "hw/loader.h" #include "hw/sysbus.h" diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c index b90cf3d37c..e21a6ede11 100644 --- a/hw/vfio/pci-quirks.c +++ b/hw/vfio/pci-quirks.c @@ -22,7 +22,6 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include -#include "hw/hw.h" #include "hw/nvram/fw_cfg.h" #include "hw/qdev-properties.h" #include "pci.h" diff --git a/include/hw/char/avr_usart.h b/include/hw/char/avr_usart.h index bb57532403..62eaa1528e 100644 --- a/include/hw/char/avr_usart.h +++ b/include/hw/char/avr_usart.h @@ -24,7 +24,6 @@ #include "hw/sysbus.h" #include "chardev/char-fe.h" -#include "hw/hw.h" #include "qom/object.h" /* Offsets of registers. */ diff --git a/include/hw/misc/avr_power.h b/include/hw/misc/avr_power.h index 707df030b1..388e421aa7 100644 --- a/include/hw/misc/avr_power.h +++ b/include/hw/misc/avr_power.h @@ -26,7 +26,6 @@ #define HW_MISC_AVR_POWER_H #include "hw/sysbus.h" -#include "hw/hw.h" #include "qom/object.h" diff --git a/include/hw/misc/stm32f4xx_exti.h b/include/hw/misc/stm32f4xx_exti.h index 24b6fa7724..ea6b0097b0 100644 --- a/include/hw/misc/stm32f4xx_exti.h +++ b/include/hw/misc/stm32f4xx_exti.h @@ -26,7 +26,6 @@ #define HW_STM_EXTI_H #include "hw/sysbus.h" -#include "hw/hw.h" #include "qom/object.h" #define EXTI_IMR 0x00 diff --git a/include/hw/misc/stm32f4xx_syscfg.h b/include/hw/misc/stm32f4xx_syscfg.h index 8c31feccd3..6f8ca49228 100644 --- a/include/hw/misc/stm32f4xx_syscfg.h +++ b/include/hw/misc/stm32f4xx_syscfg.h @@ -26,7 +26,6 @@ #define HW_STM_SYSCFG_H #include "hw/sysbus.h" -#include "hw/hw.h" #include "qom/object.h" #define SYSCFG_MEMRMP 0x00 diff --git a/include/hw/pci-host/i440fx.h b/include/hw/pci-host/i440fx.h index 24fd53942c..7fcfd9485c 100644 --- a/include/hw/pci-host/i440fx.h +++ b/include/hw/pci-host/i440fx.h @@ -11,7 +11,6 @@ #ifndef HW_PCI_I440FX_H #define HW_PCI_I440FX_H -#include "hw/hw.h" #include "hw/pci/pci_bus.h" #include "hw/pci-host/pam.h" #include "qom/object.h" diff --git a/include/hw/timer/avr_timer16.h b/include/hw/timer/avr_timer16.h index 0536254337..a1a032a24d 100644 --- a/include/hw/timer/avr_timer16.h +++ b/include/hw/timer/avr_timer16.h @@ -30,7 +30,6 @@ #include "hw/sysbus.h" #include "qemu/timer.h" -#include "hw/hw.h" #include "qom/object.h" enum NextInterrupt { From f6527eadebbcceba47c6ec5c7738499194904a56 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Sat, 27 Mar 2021 09:28:04 +0100 Subject: [PATCH 0220/3028] hw: Do not include hw/sysbus.h if it is not necessary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Many files include hw/sysbus.h without needing it. Remove the superfluous include statements. Signed-off-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210327082804.2259480-1-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/arm/cubieboard.c | 1 - hw/arm/orangepi.c | 1 - hw/char/riscv_htif.c | 1 - hw/char/sifive_uart.c | 1 - hw/char/virtio-serial-bus.c | 1 - hw/core/generic-loader.c | 1 - hw/core/guest-loader.c | 1 - hw/ide/ahci_internal.h | 1 - hw/input/lasips2.c | 1 - hw/intc/arm_gic_kvm.c | 1 - hw/intc/arm_gicv3.c | 1 - hw/intc/arm_gicv3_kvm.c | 1 - hw/intc/s390_flic_kvm.c | 1 - hw/isa/lpc_ich9.c | 1 - hw/isa/piix4.c | 1 - hw/moxie/moxiesim.c | 1 - hw/nios2/generic_nommu.c | 1 - hw/nubus/nubus-bus.c | 1 - hw/nvram/spapr_nvram.c | 1 - hw/rx/rx-gdbsim.c | 1 - hw/s390x/s390-ccw.c | 1 - hw/s390x/virtio-ccw.c | 1 - hw/timer/mips_gictimer.c | 1 - hw/usb/xen-usb.c | 1 - hw/vfio/ap.c | 1 - hw/vfio/ccw.c | 1 - hw/xen/xen-bus-helper.c | 1 - 27 files changed, 27 deletions(-) diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 9d0d728180..3ec30ca5af 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -20,7 +20,6 @@ #include "qapi/error.h" #include "cpu.h" #include "sysemu/sysemu.h" -#include "hw/sysbus.h" #include "hw/boards.h" #include "hw/qdev-properties.h" #include "hw/arm/allwinner-a10.h" diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index 40cdb5c6d2..b8d38c9e8d 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -22,7 +22,6 @@ #include "exec/address-spaces.h" #include "qapi/error.h" #include "cpu.h" -#include "hw/sysbus.h" #include "hw/boards.h" #include "hw/qdev-properties.h" #include "hw/arm/allwinner-h3.h" diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c index ba1af1cfc4..ddae738d56 100644 --- a/hw/char/riscv_htif.c +++ b/hw/char/riscv_htif.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/log.h" -#include "hw/sysbus.h" #include "hw/char/riscv_htif.h" #include "hw/char/serial.h" #include "chardev/char.h" diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c index ee7adb8e30..fe12666789 100644 --- a/hw/char/sifive_uart.c +++ b/hw/char/sifive_uart.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/log.h" -#include "hw/sysbus.h" #include "chardev/char.h" #include "chardev/char-fe.h" #include "hw/irq.h" diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index b20038991a..dd6bc27b3b 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -28,7 +28,6 @@ #include "qemu/error-report.h" #include "qemu/queue.h" #include "hw/qdev-properties.h" -#include "hw/sysbus.h" #include "trace.h" #include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-access.h" diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index 2b2a7b5e9a..d14f932eea 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -32,7 +32,6 @@ #include "qemu/osdep.h" #include "hw/core/cpu.h" -#include "hw/sysbus.h" #include "sysemu/dma.h" #include "sysemu/reset.h" #include "hw/boards.h" diff --git a/hw/core/guest-loader.c b/hw/core/guest-loader.c index bde44e27b4..d3f9d1a06e 100644 --- a/hw/core/guest-loader.c +++ b/hw/core/guest-loader.c @@ -26,7 +26,6 @@ #include "qemu/osdep.h" #include "hw/core/cpu.h" -#include "hw/sysbus.h" #include "sysemu/dma.h" #include "hw/loader.h" #include "hw/qdev-properties.h" diff --git a/hw/ide/ahci_internal.h b/hw/ide/ahci_internal.h index 7f32e87731..109de9e2d1 100644 --- a/hw/ide/ahci_internal.h +++ b/hw/ide/ahci_internal.h @@ -26,7 +26,6 @@ #include "hw/ide/ahci.h" #include "hw/ide/internal.h" -#include "hw/sysbus.h" #include "hw/pci/pci.h" #define AHCI_MEM_BAR_SIZE 0x1000 diff --git a/hw/input/lasips2.c b/hw/input/lasips2.c index 60afb94c78..275737842e 100644 --- a/hw/input/lasips2.c +++ b/hw/input/lasips2.c @@ -26,7 +26,6 @@ #include "hw/qdev-properties.h" #include "hw/input/ps2.h" #include "hw/input/lasips2.h" -#include "hw/sysbus.h" #include "exec/hwaddr.h" #include "sysemu/sysemu.h" #include "trace.h" diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 9494185cf4..49f79a8674 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -23,7 +23,6 @@ #include "qapi/error.h" #include "qemu/module.h" #include "cpu.h" -#include "hw/sysbus.h" #include "migration/blocker.h" #include "sysemu/kvm.h" #include "kvm_arm.h" diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c index 66eaa97198..d63f8af604 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" -#include "hw/sysbus.h" #include "hw/intc/arm_gicv3.h" #include "gicv3_internal.h" diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 65a4c880a3..5c09f00dec 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -22,7 +22,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/intc/arm_gicv3_common.h" -#include "hw/sysbus.h" #include "qemu/error-report.h" #include "qemu/module.h" #include "sysemu/kvm.h" diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index b3fb9f8395..d1c8fb8016 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -17,7 +17,6 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qapi/error.h" -#include "hw/sysbus.h" #include "sysemu/kvm.h" #include "hw/s390x/s390_flic.h" #include "hw/s390x/adapter.h" diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 3963b73520..160bea447a 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -34,7 +34,6 @@ #include "qapi/visitor.h" #include "qemu/range.h" #include "hw/isa/isa.h" -#include "hw/sysbus.h" #include "migration/vmstate.h" #include "hw/irq.h" #include "hw/isa/apm.h" diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index b3b6a4378a..48c5dda2b6 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -29,7 +29,6 @@ #include "hw/southbridge/piix.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" -#include "hw/sysbus.h" #include "hw/intc/i8259.h" #include "hw/dma/i8257.h" #include "hw/timer/i8254.h" diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c index f7b57fcae1..196b730589 100644 --- a/hw/moxie/moxiesim.c +++ b/hw/moxie/moxiesim.c @@ -29,7 +29,6 @@ #include "qemu/error-report.h" #include "qapi/error.h" #include "cpu.h" -#include "hw/sysbus.h" #include "net/net.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" diff --git a/hw/nios2/generic_nommu.c b/hw/nios2/generic_nommu.c index 19899e2c1e..b70a42dc2f 100644 --- a/hw/nios2/generic_nommu.c +++ b/hw/nios2/generic_nommu.c @@ -31,7 +31,6 @@ #include "qemu-common.h" #include "cpu.h" -#include "hw/sysbus.h" #include "hw/char/serial.h" #include "hw/boards.h" #include "exec/memory.h" diff --git a/hw/nubus/nubus-bus.c b/hw/nubus/nubus-bus.c index 942a6d5342..5c13452308 100644 --- a/hw/nubus/nubus-bus.c +++ b/hw/nubus/nubus-bus.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "hw/nubus/nubus.h" -#include "hw/sysbus.h" #include "qapi/error.h" diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index 01f7752014..3bb4654c58 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -33,7 +33,6 @@ #include "sysemu/device_tree.h" #include "sysemu/sysemu.h" #include "sysemu/runstate.h" -#include "hw/sysbus.h" #include "migration/vmstate.h" #include "hw/nvram/chrp_nvram.h" #include "hw/ppc/spapr.h" diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c index 8c611b0a59..9b82feff52 100644 --- a/hw/rx/rx-gdbsim.c +++ b/hw/rx/rx-gdbsim.c @@ -22,7 +22,6 @@ #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" -#include "hw/sysbus.h" #include "hw/loader.h" #include "hw/rx/rx62n.h" #include "sysemu/sysemu.h" diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index b497571863..242491a1ae 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -15,7 +15,6 @@ #include #include "qapi/error.h" #include "qemu/module.h" -#include "hw/sysbus.h" #include "hw/s390x/css.h" #include "hw/s390x/css-bridge.h" #include "hw/s390x/s390-ccw.h" diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 8195f3546e..92b950e09a 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -17,7 +17,6 @@ #include "hw/virtio/virtio.h" #include "migration/qemu-file-types.h" #include "hw/virtio/virtio-net.h" -#include "hw/sysbus.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "qemu/module.h" diff --git a/hw/timer/mips_gictimer.c b/hw/timer/mips_gictimer.c index bc44cd934e..2b0696d4ac 100644 --- a/hw/timer/mips_gictimer.c +++ b/hw/timer/mips_gictimer.c @@ -7,7 +7,6 @@ */ #include "qemu/osdep.h" -#include "hw/sysbus.h" #include "qemu/timer.h" #include "hw/timer/mips_gictimer.h" diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c index 4d266d7bb4..0f7369e7ed 100644 --- a/hw/usb/xen-usb.c +++ b/hw/usb/xen-usb.c @@ -26,7 +26,6 @@ #include "qemu/config-file.h" #include "qemu/main-loop.h" #include "qemu/option.h" -#include "hw/sysbus.h" #include "hw/usb.h" #include "hw/xen/xen-legacy-backend.h" #include "monitor/qdev.h" diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index 9571c2f91f..f9dbec37da 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -14,7 +14,6 @@ #include #include #include "qapi/error.h" -#include "hw/sysbus.h" #include "hw/vfio/vfio.h" #include "hw/vfio/vfio-common.h" #include "hw/s390x/ap-device.h" diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index b2df708e4b..e752c845e9 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -20,7 +20,6 @@ #include #include "qapi/error.h" -#include "hw/sysbus.h" #include "hw/vfio/vfio.h" #include "hw/vfio/vfio-common.h" #include "hw/s390x/s390-ccw.h" diff --git a/hw/xen/xen-bus-helper.c b/hw/xen/xen-bus-helper.c index b459bb9396..5a1e12b374 100644 --- a/hw/xen/xen-bus-helper.c +++ b/hw/xen/xen-bus-helper.c @@ -6,7 +6,6 @@ */ #include "qemu/osdep.h" -#include "hw/sysbus.h" #include "hw/xen/xen.h" #include "hw/xen/xen-bus.h" #include "hw/xen/xen-bus-helper.h" From e924921f5cea55d20a90f1d8d7239d35427bef04 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Sat, 27 Mar 2021 06:02:36 +0100 Subject: [PATCH 0221/3028] hw: Do not include hw/irq.h if it is not necessary Many files include hw/irq.h without needing it. Remove the superfluous include statements. Signed-off-by: Thomas Huth Reviewed-by: Alistair Francis Message-Id: <20210327050236.2232347-1-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/arm/msf2-soc.c | 1 - hw/i386/kvm/ioapic.c | 1 - hw/i386/xen/xen_platform.c | 1 - hw/m68k/q800.c | 1 - hw/m68k/virt.c | 1 - hw/misc/led.c | 1 - hw/misc/virt_ctrl.c | 1 - hw/ppc/prep.c | 1 - hw/riscv/microchip_pfsoc.c | 1 - hw/sd/cadence_sdhci.c | 1 - hw/timer/sse-counter.c | 1 - hw/usb/xlnx-usb-subsystem.c | 1 - 12 files changed, 12 deletions(-) diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index d2c29e82d1..5cfe7caf83 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -27,7 +27,6 @@ #include "qapi/error.h" #include "exec/address-spaces.h" #include "hw/char/serial.h" -#include "hw/irq.h" #include "hw/arm/msf2-soc.h" #include "hw/misc/unimp.h" #include "sysemu/sysemu.h" diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c index dfc3c98005..71a563181e 100644 --- a/hw/i386/kvm/ioapic.c +++ b/hw/i386/kvm/ioapic.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "monitor/monitor.h" #include "hw/i386/x86.h" -#include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/i386/ioapic_internal.h" #include "hw/i386/apic_internal.h" diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 01ae1fb161..bf4f20e92b 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -27,7 +27,6 @@ #include "qapi/error.h" #include "hw/ide.h" #include "hw/pci/pci.h" -#include "hw/irq.h" #include "hw/xen/xen_common.h" #include "migration/vmstate.h" #include "hw/xen/xen-legacy-backend.h" diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 1c7f7aa07f..d1ab1ff77d 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -27,7 +27,6 @@ #include "sysemu/sysemu.h" #include "cpu.h" #include "hw/boards.h" -#include "hw/irq.h" #include "hw/or-irq.h" #include "elf.h" #include "hw/loader.h" diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 18e6f11041..9469f82800 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -13,7 +13,6 @@ #include "sysemu/sysemu.h" #include "cpu.h" #include "hw/boards.h" -#include "hw/irq.h" #include "hw/qdev-properties.h" #include "elf.h" #include "hw/loader.h" diff --git a/hw/misc/led.c b/hw/misc/led.c index f552b8b648..f6d6d68bce 100644 --- a/hw/misc/led.c +++ b/hw/misc/led.c @@ -10,7 +10,6 @@ #include "migration/vmstate.h" #include "hw/qdev-properties.h" #include "hw/misc/led.h" -#include "hw/irq.h" #include "trace.h" #define LED_INTENSITY_PERCENT_MAX 100 diff --git a/hw/misc/virt_ctrl.c b/hw/misc/virt_ctrl.c index 2ea01bd7a1..3552d7a09a 100644 --- a/hw/misc/virt_ctrl.c +++ b/hw/misc/virt_ctrl.c @@ -5,7 +5,6 @@ */ #include "qemu/osdep.h" -#include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" #include "migration/vmstate.h" diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index f1b1efdcef..af4ccb9f43 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -38,7 +38,6 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/log.h" -#include "hw/irq.h" #include "hw/loader.h" #include "hw/rtc/mc146818rtc.h" #include "hw/isa/pc87312.h" diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index c4146b7a6b..01537b30eb 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -41,7 +41,6 @@ #include "qemu/cutils.h" #include "qapi/error.h" #include "hw/boards.h" -#include "hw/irq.h" #include "hw/loader.h" #include "hw/sysbus.h" #include "chardev/char.h" diff --git a/hw/sd/cadence_sdhci.c b/hw/sd/cadence_sdhci.c index 0b371c843d..c89538b491 100644 --- a/hw/sd/cadence_sdhci.c +++ b/hw/sd/cadence_sdhci.c @@ -26,7 +26,6 @@ #include "qemu/log.h" #include "qapi/error.h" #include "migration/vmstate.h" -#include "hw/irq.h" #include "hw/sd/cadence_sdhci.h" #include "sdhci-internal.h" diff --git a/hw/timer/sse-counter.c b/hw/timer/sse-counter.c index 0384051f15..16c0e8ad15 100644 --- a/hw/timer/sse-counter.c +++ b/hw/timer/sse-counter.c @@ -33,7 +33,6 @@ #include "trace.h" #include "hw/timer/sse-counter.h" #include "hw/sysbus.h" -#include "hw/irq.h" #include "hw/registerfields.h" #include "hw/clock.h" #include "hw/qdev-clock.h" diff --git a/hw/usb/xlnx-usb-subsystem.c b/hw/usb/xlnx-usb-subsystem.c index 568257370c..c760c3058a 100644 --- a/hw/usb/xlnx-usb-subsystem.c +++ b/hw/usb/xlnx-usb-subsystem.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" -#include "hw/irq.h" #include "hw/register.h" #include "qemu/bitops.h" #include "qemu/log.h" From 19f4ed3652e0868dd840d3bfe70cfa2cf41936be Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Sun, 28 Mar 2021 07:48:33 +0200 Subject: [PATCH 0222/3028] hw: Do not include qemu/log.h if it is not necessary Many files include qemu/log.h without needing it. Remove the superfluous include statements. Signed-off-by: Thomas Huth Reviewed-by: Alistair Francis Message-Id: <20210328054833.2351597-1-thuth@redhat.com> Signed-off-by: Laurent Vivier --- hw/arm/aspeed.c | 1 - hw/arm/aspeed_ast2600.c | 1 - hw/arm/aspeed_soc.c | 1 - hw/arm/exynos4210.c | 1 - hw/arm/xlnx-versal-virt.c | 1 - hw/arm/xlnx-versal.c | 1 - hw/i2c/mpc_i2c.c | 1 - hw/intc/imx_gpcv2.c | 1 - hw/intc/ompic.c | 1 - hw/intc/openpic.c | 1 - hw/ipmi/isa_ipmi_bt.c | 1 - hw/ipmi/isa_ipmi_kcs.c | 1 - hw/mips/fuloong2e.c | 1 - hw/mips/loongson3_virt.c | 1 - hw/misc/imx7_snvs.c | 1 - hw/misc/imx_ccm.c | 1 - hw/misc/imx_rngc.c | 1 - hw/misc/pvpanic-isa.c | 1 - hw/misc/pvpanic-pci.c | 1 - hw/net/xgmac.c | 1 - hw/ppc/pnv.c | 1 - hw/ppc/pnv_pnor.c | 1 - hw/ppc/ppc405_boards.c | 1 - hw/ppc/ppc405_uc.c | 1 - hw/ppc/ppc_booke.c | 1 - hw/ppc/virtex_ml507.c | 1 - hw/riscv/microchip_pfsoc.c | 1 - hw/riscv/numa.c | 1 - hw/riscv/sifive_e.c | 1 - hw/riscv/sifive_u.c | 1 - hw/riscv/spike.c | 1 - hw/riscv/virt.c | 1 - hw/sd/cadence_sdhci.c | 1 - hw/ssi/xilinx_spi.c | 1 - hw/tricore/tc27x_soc.c | 1 - hw/usb/chipidea.c | 1 - hw/usb/hcd-dwc3.c | 1 - hw/usb/imx-usb-phy.c | 1 - hw/usb/xlnx-usb-subsystem.c | 1 - hw/usb/xlnx-versal-usb2-ctrl-regs.c | 1 - hw/xen/xen-legacy-backend.c | 1 - net/dump.c | 1 - net/filter-replay.c | 1 - semihosting/arm-compat-semi.c | 1 - target/arm/op_helper.c | 1 - target/hexagon/cpu.c | 1 - target/hexagon/decode.c | 1 - target/hexagon/genptr.c | 1 - target/lm32/lm32-semi.c | 1 - target/riscv/op_helper.c | 1 - target/s390x/interrupt.c | 1 - 51 files changed, 51 deletions(-) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index a17b75f494..c3345fce53 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -22,7 +22,6 @@ #include "hw/misc/tmp105.h" #include "hw/misc/led.h" #include "hw/qdev-properties.h" -#include "qemu/log.h" #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" #include "hw/loader.h" diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index bc87e754a3..504aabf173 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -14,7 +14,6 @@ #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" #include "hw/char/serial.h" -#include "qemu/log.h" #include "qemu/module.h" #include "qemu/error-report.h" #include "hw/i2c/aspeed_i2c.h" diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 057d053c84..516277800c 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -17,7 +17,6 @@ #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" #include "hw/char/serial.h" -#include "qemu/log.h" #include "qemu/module.h" #include "qemu/error-report.h" #include "hw/i2c/aspeed_i2c.h" diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index ced2769b10..5c7a51bbad 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu/log.h" #include "cpu.h" #include "hw/cpu/a9mpcore.h" #include "hw/irq.h" diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 8482cd6196..73e8268b35 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -10,7 +10,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "sysemu/device_tree.h" diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 79609692e4..fb776834f7 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" -#include "qemu/log.h" #include "qemu/module.h" #include "hw/sysbus.h" #include "net/net.h" diff --git a/hw/i2c/mpc_i2c.c b/hw/i2c/mpc_i2c.c index 720d2331e9..845392505f 100644 --- a/hw/i2c/mpc_i2c.c +++ b/hw/i2c/mpc_i2c.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "hw/i2c/i2c.h" #include "hw/irq.h" -#include "qemu/log.h" #include "qemu/module.h" #include "hw/sysbus.h" #include "migration/vmstate.h" diff --git a/hw/intc/imx_gpcv2.c b/hw/intc/imx_gpcv2.c index 17007a4078..237d5f97eb 100644 --- a/hw/intc/imx_gpcv2.c +++ b/hw/intc/imx_gpcv2.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "hw/intc/imx_gpcv2.h" #include "migration/vmstate.h" -#include "qemu/log.h" #include "qemu/module.h" #define GPC_PU_PGC_SW_PUP_REQ 0x0f8 diff --git a/hw/intc/ompic.c b/hw/intc/ompic.c index 1731a10683..1f10314807 100644 --- a/hw/intc/ompic.c +++ b/hw/intc/ompic.c @@ -7,7 +7,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/module.h" #include "qapi/error.h" #include "hw/irq.h" diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index 65970e1b37..9b4c17854d 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -47,7 +47,6 @@ #include "qapi/error.h" #include "qemu/bitops.h" #include "qapi/qmp/qerror.h" -#include "qemu/log.h" #include "qemu/module.h" #include "qemu/timer.h" #include "qemu/error-report.h" diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c index b7c2ad557b..02625eb94e 100644 --- a/hw/ipmi/isa_ipmi_bt.c +++ b/hw/ipmi/isa_ipmi_bt.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/module.h" #include "qapi/error.h" #include "hw/irq.h" diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c index 7dd6bf0040..3b23ad08b3 100644 --- a/hw/ipmi/isa_ipmi_kcs.c +++ b/hw/ipmi/isa_ipmi_kcs.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/module.h" #include "qapi/error.h" #include "hw/irq.h" diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index 4f61f2c873..1851eb0944 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -33,7 +33,6 @@ #include "hw/mips/bootloader.h" #include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" -#include "qemu/log.h" #include "hw/loader.h" #include "hw/ide/pci.h" #include "hw/qdev-properties.h" diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index b15071defc..f9c0873a98 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -54,7 +54,6 @@ #include "sysemu/qtest.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" -#include "qemu/log.h" #include "qemu/error-report.h" #define PM_CNTL_MODE 0x10 diff --git a/hw/misc/imx7_snvs.c b/hw/misc/imx7_snvs.c index 45972a5920..ee7698bd9c 100644 --- a/hw/misc/imx7_snvs.c +++ b/hw/misc/imx7_snvs.c @@ -14,7 +14,6 @@ #include "qemu/osdep.h" #include "hw/misc/imx7_snvs.h" -#include "qemu/log.h" #include "qemu/module.h" #include "sysemu/runstate.h" diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c index 08a50ee4c8..9403c5daa3 100644 --- a/hw/misc/imx_ccm.c +++ b/hw/misc/imx_ccm.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "hw/misc/imx_ccm.h" -#include "qemu/log.h" #include "qemu/module.h" #ifndef DEBUG_IMX_CCM diff --git a/hw/misc/imx_rngc.c b/hw/misc/imx_rngc.c index 4c270df2db..632c03779c 100644 --- a/hw/misc/imx_rngc.c +++ b/hw/misc/imx_rngc.c @@ -14,7 +14,6 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "qemu/module.h" -#include "qemu/log.h" #include "qemu/guest-random.h" #include "hw/irq.h" #include "hw/misc/imx_rngc.h" diff --git a/hw/misc/pvpanic-isa.c b/hw/misc/pvpanic-isa.c index 27113abd6c..7b66d58acc 100644 --- a/hw/misc/pvpanic-isa.c +++ b/hw/misc/pvpanic-isa.c @@ -13,7 +13,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/module.h" #include "sysemu/runstate.h" diff --git a/hw/misc/pvpanic-pci.c b/hw/misc/pvpanic-pci.c index d629639d8f..af8cbe2830 100644 --- a/hw/misc/pvpanic-pci.c +++ b/hw/misc/pvpanic-pci.c @@ -12,7 +12,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/module.h" #include "sysemu/runstate.h" diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index 00859a7d50..0ab6ae91aa 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -29,7 +29,6 @@ #include "hw/qdev-properties.h" #include "hw/sysbus.h" #include "migration/vmstate.h" -#include "qemu/log.h" #include "qemu/module.h" #include "net/net.h" #include "qom/object.h" diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 77af846cdf..6faf1fe473 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -32,7 +32,6 @@ #include "sysemu/device_tree.h" #include "sysemu/hw_accel.h" #include "target/ppc/cpu.h" -#include "qemu/log.h" #include "hw/ppc/fdt.h" #include "hw/ppc/ppc.h" #include "hw/ppc/pnv.h" diff --git a/hw/ppc/pnv_pnor.c b/hw/ppc/pnv_pnor.c index 4b455de1ea..5ef1cf2afb 100644 --- a/hw/ppc/pnv_pnor.c +++ b/hw/ppc/pnv_pnor.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "qemu/log.h" #include "qemu/units.h" #include "sysemu/block-backend.h" #include "sysemu/blockdev.h" diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index 8f77887fb1..f4e804cdb5 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -39,7 +39,6 @@ #include "sysemu/reset.h" #include "sysemu/block-backend.h" #include "hw/boards.h" -#include "qemu/log.h" #include "qemu/error-report.h" #include "hw/loader.h" #include "exec/address-spaces.h" diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index fe047074a1..e632c408bd 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -34,7 +34,6 @@ #include "qemu/timer.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" -#include "qemu/log.h" #include "exec/address-spaces.h" #include "hw/intc/ppc-uic.h" #include "hw/qdev-properties.h" diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c index 974c0c8a75..10b643861f 100644 --- a/hw/ppc/ppc_booke.c +++ b/hw/ppc/ppc_booke.c @@ -28,7 +28,6 @@ #include "qemu/timer.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" -#include "qemu/log.h" #include "hw/loader.h" #include "kvm_ppc.h" diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index cb421570da..3a57604ac0 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -38,7 +38,6 @@ #include "elf.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "qemu/log.h" #include "qemu/option.h" #include "exec/address-spaces.h" diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index 01537b30eb..6cbd17ebf2 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -36,7 +36,6 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" -#include "qemu/log.h" #include "qemu/units.h" #include "qemu/cutils.h" #include "qapi/error.h" diff --git a/hw/riscv/numa.c b/hw/riscv/numa.c index 4f92307102..7fe92d402f 100644 --- a/hw/riscv/numa.c +++ b/hw/riscv/numa.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu/log.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "hw/boards.h" diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index f939bcf9ea..97e8b0b0a2 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -29,7 +29,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "hw/boards.h" diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 7b59942369..698637e8e1 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -35,7 +35,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "qapi/visitor.h" diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index ec7cb2f707..fe0806a476 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "hw/boards.h" diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index c0dc69ff33..95a11adaa2 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu/log.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "hw/boards.h" diff --git a/hw/sd/cadence_sdhci.c b/hw/sd/cadence_sdhci.c index c89538b491..56b8bae1c3 100644 --- a/hw/sd/cadence_sdhci.c +++ b/hw/sd/cadence_sdhci.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" #include "qemu/bitops.h" #include "qemu/error-report.h" -#include "qemu/log.h" #include "qapi/error.h" #include "migration/vmstate.h" #include "hw/sd/cadence_sdhci.h" diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c index 49ff275593..b2819a7ff0 100644 --- a/hw/ssi/xilinx_spi.c +++ b/hw/ssi/xilinx_spi.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "migration/vmstate.h" -#include "qemu/log.h" #include "qemu/module.h" #include "qemu/fifo8.h" diff --git a/hw/tricore/tc27x_soc.c b/hw/tricore/tc27x_soc.c index 8af079e6b2..dea9ba3cca 100644 --- a/hw/tricore/tc27x_soc.c +++ b/hw/tricore/tc27x_soc.c @@ -26,7 +26,6 @@ #include "qemu/units.h" #include "hw/misc/unimp.h" #include "exec/address-spaces.h" -#include "qemu/log.h" #include "cpu.h" #include "hw/tricore/tc27x_soc.h" diff --git a/hw/usb/chipidea.c b/hw/usb/chipidea.c index 3dcd22ccba..b1c85404d6 100644 --- a/hw/usb/chipidea.c +++ b/hw/usb/chipidea.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "hw/usb/hcd-ehci.h" #include "hw/usb/chipidea.h" -#include "qemu/log.h" #include "qemu/module.h" enum { diff --git a/hw/usb/hcd-dwc3.c b/hw/usb/hcd-dwc3.c index d547d0538d..279263489e 100644 --- a/hw/usb/hcd-dwc3.c +++ b/hw/usb/hcd-dwc3.c @@ -31,7 +31,6 @@ #include "hw/sysbus.h" #include "hw/register.h" #include "qemu/bitops.h" -#include "qemu/log.h" #include "qom/object.h" #include "migration/vmstate.h" #include "hw/qdev-properties.h" diff --git a/hw/usb/imx-usb-phy.c b/hw/usb/imx-usb-phy.c index e705a03a1f..5d7a549e34 100644 --- a/hw/usb/imx-usb-phy.c +++ b/hw/usb/imx-usb-phy.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "hw/usb/imx-usb-phy.h" #include "migration/vmstate.h" -#include "qemu/log.h" #include "qemu/module.h" static const VMStateDescription vmstate_imx_usbphy = { diff --git a/hw/usb/xlnx-usb-subsystem.c b/hw/usb/xlnx-usb-subsystem.c index c760c3058a..d8deeb6ced 100644 --- a/hw/usb/xlnx-usb-subsystem.c +++ b/hw/usb/xlnx-usb-subsystem.c @@ -26,7 +26,6 @@ #include "hw/sysbus.h" #include "hw/register.h" #include "qemu/bitops.h" -#include "qemu/log.h" #include "qom/object.h" #include "qapi/error.h" #include "hw/qdev-properties.h" diff --git a/hw/usb/xlnx-versal-usb2-ctrl-regs.c b/hw/usb/xlnx-versal-usb2-ctrl-regs.c index 9eaa59ebb8..1c094aa1a6 100644 --- a/hw/usb/xlnx-versal-usb2-ctrl-regs.c +++ b/hw/usb/xlnx-versal-usb2-ctrl-regs.c @@ -32,7 +32,6 @@ #include "hw/irq.h" #include "hw/register.h" #include "qemu/bitops.h" -#include "qemu/log.h" #include "qom/object.h" #include "migration/vmstate.h" #include "hw/usb/xlnx-versal-usb2-ctrl-regs.h" diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index b61a4855b7..dd8ae1452d 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -27,7 +27,6 @@ #include "hw/sysbus.h" #include "hw/boards.h" #include "hw/qdev-properties.h" -#include "qemu/log.h" #include "qemu/main-loop.h" #include "qapi/error.h" #include "hw/xen/xen-legacy-backend.h" diff --git a/net/dump.c b/net/dump.c index 4d538d82a6..a07ba62401 100644 --- a/net/dump.c +++ b/net/dump.c @@ -28,7 +28,6 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/iov.h" -#include "qemu/log.h" #include "qemu/module.h" #include "qemu/timer.h" #include "qapi/visitor.h" diff --git a/net/filter-replay.c b/net/filter-replay.c index eef8443059..54690676ef 100644 --- a/net/filter-replay.c +++ b/net/filter-replay.c @@ -13,7 +13,6 @@ #include "clients.h" #include "qemu/error-report.h" #include "qemu/iov.h" -#include "qemu/log.h" #include "qemu/module.h" #include "qemu/timer.h" #include "qapi/visitor.h" diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index fe079ca93a..f9c87245b8 100644 --- a/semihosting/arm-compat-semi.c +++ b/semihosting/arm-compat-semi.c @@ -37,7 +37,6 @@ #include "semihosting/semihost.h" #include "semihosting/console.h" #include "semihosting/common-semi.h" -#include "qemu/log.h" #include "qemu/timer.h" #ifdef CONFIG_USER_ONLY #include "qemu.h" diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 65cb37d088..78b831f181 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -17,7 +17,6 @@ * License along with this library; if not, see . */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index b0b3040dd1..543fceb41c 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -16,7 +16,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "qemu/qemu-print.h" #include "cpu.h" #include "internal.h" diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c index c9bacaa1ee..9bcc8c9f32 100644 --- a/target/hexagon/decode.c +++ b/target/hexagon/decode.c @@ -16,7 +16,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "iclass.h" #include "attribs.h" #include "genptr.h" diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 7481f4c1dd..cea1f221e2 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -17,7 +17,6 @@ #define QEMU_GENERATE #include "qemu/osdep.h" -#include "qemu/log.h" #include "cpu.h" #include "internal.h" #include "tcg/tcg-op.h" diff --git a/target/lm32/lm32-semi.c b/target/lm32/lm32-semi.c index 6a11a6299a..661a770249 100644 --- a/target/lm32/lm32-semi.c +++ b/target/lm32/lm32-semi.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "qemu/log.h" #include "exec/softmmu-semi.h" enum { diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 1eddcb94de..f0bbd73ca5 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "cpu.h" #include "qemu/main-loop.h" #include "exec/exec-all.h" diff --git a/target/s390x/interrupt.c b/target/s390x/interrupt.c index 4cdbbc8849..9b4d08f2be 100644 --- a/target/s390x/interrupt.c +++ b/target/s390x/interrupt.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "qemu/log.h" #include "cpu.h" #include "kvm_s390x.h" #include "internal.h" From 4c386f8064ca3241a61341b5c5d5a70bbab496ab Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 16 Apr 2021 19:13:11 +0200 Subject: [PATCH 0223/3028] Do not include sysemu/sysemu.h if it's not really necessary Stop including sysemu/sysemu.h in files that don't need it. Signed-off-by: Thomas Huth Message-Id: <20210416171314.2074665-2-thuth@redhat.com> Signed-off-by: Laurent Vivier --- accel/kvm/kvm-all.c | 1 - accel/tcg/user-exec-stub.c | 1 - backends/hostmem-file.c | 1 - backends/hostmem-memfd.c | 1 - backends/hostmem.c | 1 - block.c | 1 - block/block-backend.c | 1 - block/nfs.c | 1 - chardev/char-mux.c | 1 - chardev/char.c | 1 - gdbstub.c | 1 - hw/alpha/dp264.c | 1 - hw/arm/aspeed.c | 1 - hw/arm/cubieboard.c | 1 - hw/arm/digic_boards.c | 1 - hw/arm/exynos4_boards.c | 1 - hw/arm/mcimx6ul-evk.c | 1 - hw/arm/mcimx7d-sabre.c | 1 - hw/arm/npcm7xx_boards.c | 1 - hw/arm/orangepi.c | 1 - hw/arm/raspi.c | 1 - hw/arm/sabrelite.c | 1 - hw/arm/virt.c | 1 - hw/block/nvme-subsys.c | 1 - hw/core/machine-qmp-cmds.c | 1 - hw/core/null-machine.c | 1 - hw/core/numa.c | 1 - hw/i386/pc_piix.c | 1 - hw/i386/pc_sysfw.c | 1 - hw/input/lasips2.c | 1 - hw/intc/sifive_plic.c | 1 - hw/isa/isa-superio.c | 1 - hw/isa/piix3.c | 1 - hw/m68k/next-kbd.c | 1 - hw/microblaze/boot.c | 1 - hw/mips/malta.c | 1 - hw/misc/macio/macio.c | 1 - hw/net/can/xlnx-zynqmp-can.c | 1 - hw/net/i82596.c | 1 - hw/net/lasi_i82596.c | 1 - hw/nios2/boot.c | 1 - hw/ppc/ppc405_boards.c | 1 - hw/ppc/prep.c | 1 - hw/rx/rx-gdbsim.c | 1 - hw/s390x/ipl.c | 1 - hw/s390x/sclp.c | 1 - hw/sh4/shix.c | 1 - hw/ssi/sifive_spi.c | 1 - hw/vfio/display.c | 1 - hw/vfio/pci.c | 1 - hw/xtensa/virt.c | 1 - migration/ram.c | 1 - monitor/monitor.c | 1 - net/net.c | 2 -- net/netmap.c | 1 - plugins/api.c | 1 - plugins/core.c | 1 - semihosting/config.c | 1 - semihosting/console.c | 1 - softmmu/arch_init.c | 1 - softmmu/device_tree.c | 1 - softmmu/physmem.c | 1 - softmmu/qdev-monitor.c | 1 - stubs/semihost.c | 1 - target/arm/cpu.c | 1 - target/openrisc/sys_helper.c | 1 - target/rx/helper.c | 1 - target/s390x/cpu.c | 1 - target/s390x/excp_helper.c | 1 - tcg/tcg.c | 1 - tests/qtest/fuzz/fuzz.c | 1 - tests/qtest/fuzz/qos_fuzz.c | 1 - util/oslib-win32.c | 1 - 73 files changed, 74 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 93d7cbfeaf..50e56664cc 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -30,7 +30,6 @@ #include "sysemu/kvm_int.h" #include "sysemu/runstate.h" #include "sysemu/cpus.h" -#include "sysemu/sysemu.h" #include "qemu/bswap.h" #include "exec/memory.h" #include "exec/ram_addr.h" diff --git a/accel/tcg/user-exec-stub.c b/accel/tcg/user-exec-stub.c index b876f5c1e4..968cd3ca60 100644 --- a/accel/tcg/user-exec-stub.c +++ b/accel/tcg/user-exec-stub.c @@ -1,7 +1,6 @@ #include "qemu/osdep.h" #include "hw/core/cpu.h" #include "sysemu/replay.h" -#include "sysemu/sysemu.h" bool enable_cpu_pm = false; diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index b683da9daf..9b1b9f0a56 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -15,7 +15,6 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "sysemu/hostmem.h" -#include "sysemu/sysemu.h" #include "qom/object_interfaces.h" #include "qom/object.h" diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c index 69b0ae30bb..da75e27057 100644 --- a/backends/hostmem-memfd.c +++ b/backends/hostmem-memfd.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "sysemu/hostmem.h" -#include "sysemu/sysemu.h" #include "qom/object_interfaces.h" #include "qemu/memfd.h" #include "qemu/module.h" diff --git a/backends/hostmem.c b/backends/hostmem.c index c6c1ff5b99..aab3de8408 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "sysemu/hostmem.h" -#include "sysemu/sysemu.h" #include "hw/boards.h" #include "qapi/error.h" #include "qapi/qapi-builtin-visit.h" diff --git a/block.c b/block.c index 874c22c43e..9ad725d205 100644 --- a/block.c +++ b/block.c @@ -42,7 +42,6 @@ #include "qapi/qobject-output-visitor.h" #include "qapi/qapi-visit-block-core.h" #include "sysemu/block-backend.h" -#include "sysemu/sysemu.h" #include "qemu/notify.h" #include "qemu/option.h" #include "qemu/coroutine.h" diff --git a/block/block-backend.c b/block/block-backend.c index 6fca9853e1..de5496af66 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -18,7 +18,6 @@ #include "hw/qdev-core.h" #include "sysemu/blockdev.h" #include "sysemu/runstate.h" -#include "sysemu/sysemu.h" #include "sysemu/replay.h" #include "qapi/error.h" #include "qapi/qapi-events-block.h" diff --git a/block/nfs.c b/block/nfs.c index 8c1968bb41..7dff64f489 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -39,7 +39,6 @@ #include "qemu/option.h" #include "qemu/uri.h" #include "qemu/cutils.h" -#include "sysemu/sysemu.h" #include "sysemu/replay.h" #include "qapi/qapi-visit-block-core.h" #include "qapi/qmp/qdict.h" diff --git a/chardev/char-mux.c b/chardev/char-mux.c index 72beef29d2..5baf419010 100644 --- a/chardev/char-mux.c +++ b/chardev/char-mux.c @@ -28,7 +28,6 @@ #include "qemu/option.h" #include "chardev/char.h" #include "sysemu/block-backend.h" -#include "sysemu/sysemu.h" #include "chardev-internal.h" /* MUX driver for serial I/O splitting */ diff --git a/chardev/char.c b/chardev/char.c index 398f09df19..a4ebfcc5ac 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" #include "monitor/monitor.h" -#include "sysemu/sysemu.h" #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qemu/qemu-print.h" diff --git a/gdbstub.c b/gdbstub.c index 054665e93e..9103ffc902 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -37,7 +37,6 @@ #include "monitor/monitor.h" #include "chardev/char.h" #include "chardev/char-fe.h" -#include "sysemu/sysemu.h" #include "exec/gdbstub.h" #include "hw/cpu/cluster.h" #include "hw/boards.h" diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index c8e300d93f..1017ecf330 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -13,7 +13,6 @@ #include "hw/loader.h" #include "alpha_sys.h" #include "qemu/error-report.h" -#include "sysemu/sysemu.h" #include "hw/rtc/mc146818rtc.h" #include "hw/ide/pci.h" #include "hw/timer/i8254.h" diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index c3345fce53..c4f85dab63 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -23,7 +23,6 @@ #include "hw/misc/led.h" #include "hw/qdev-properties.h" #include "sysemu/block-backend.h" -#include "sysemu/sysemu.h" #include "hw/loader.h" #include "qemu/error-report.h" #include "qemu/units.h" diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 3ec30ca5af..9e872135ae 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -19,7 +19,6 @@ #include "exec/address-spaces.h" #include "qapi/error.h" #include "cpu.h" -#include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/qdev-properties.h" #include "hw/arm/allwinner-a10.h" diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c index 6cdc1d83fc..65d3a9ba74 100644 --- a/hw/arm/digic_boards.c +++ b/hw/arm/digic_boards.c @@ -34,7 +34,6 @@ #include "hw/arm/digic.h" #include "hw/block/flash.h" #include "hw/loader.h" -#include "sysemu/sysemu.h" #include "sysemu/qtest.h" #include "qemu/units.h" #include "qemu/cutils.h" diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 56b729141b..8ae136bbdf 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -26,7 +26,6 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "cpu.h" -#include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "net/net.h" #include "hw/arm/boot.h" diff --git a/hw/arm/mcimx6ul-evk.c b/hw/arm/mcimx6ul-evk.c index ed69a7b037..ce16b6b317 100644 --- a/hw/arm/mcimx6ul-evk.c +++ b/hw/arm/mcimx6ul-evk.c @@ -15,7 +15,6 @@ #include "hw/arm/fsl-imx6ul.h" #include "hw/boards.h" #include "hw/qdev-properties.h" -#include "sysemu/sysemu.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" diff --git a/hw/arm/mcimx7d-sabre.c b/hw/arm/mcimx7d-sabre.c index e57d52b344..e896222c34 100644 --- a/hw/arm/mcimx7d-sabre.c +++ b/hw/arm/mcimx7d-sabre.c @@ -17,7 +17,6 @@ #include "hw/arm/fsl-imx7.h" #include "hw/boards.h" #include "hw/qdev-properties.h" -#include "sysemu/sysemu.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index e22fe4bf8f..d91d687700 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -27,7 +27,6 @@ #include "qemu-common.h" #include "qemu/datadir.h" #include "qemu/units.h" -#include "sysemu/sysemu.h" #define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7 #define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index b8d38c9e8d..6ccb61c149 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -25,7 +25,6 @@ #include "hw/boards.h" #include "hw/qdev-properties.h" #include "hw/arm/allwinner-h3.h" -#include "sysemu/sysemu.h" static struct arm_boot_info orangepi_binfo = { .nb_cpus = AW_H3_NUM_CPUS, diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 990509d385..1b7e9c4cb4 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -23,7 +23,6 @@ #include "hw/boards.h" #include "hw/loader.h" #include "hw/arm/boot.h" -#include "sysemu/sysemu.h" #include "qom/object.h" #define SMPBOOT_ADDR 0x300 /* this should leave enough space for ATAGS */ diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c index a3dbf85e0e..42348e5cb1 100644 --- a/hw/arm/sabrelite.c +++ b/hw/arm/sabrelite.c @@ -15,7 +15,6 @@ #include "hw/arm/fsl-imx6.h" #include "hw/boards.h" #include "hw/qdev-properties.h" -#include "sysemu/sysemu.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" diff --git a/hw/arm/virt.c b/hw/arm/virt.c index fee696fb0e..881969af6b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -48,7 +48,6 @@ #include "sysemu/device_tree.h" #include "sysemu/numa.h" #include "sysemu/runstate.h" -#include "sysemu/sysemu.h" #include "sysemu/tpm.h" #include "sysemu/kvm.h" #include "hw/loader.h" diff --git a/hw/block/nvme-subsys.c b/hw/block/nvme-subsys.c index 283a97b79d..9604c19117 100644 --- a/hw/block/nvme-subsys.c +++ b/hw/block/nvme-subsys.c @@ -17,7 +17,6 @@ #include "hw/block/block.h" #include "block/aio.h" #include "block/accounting.h" -#include "sysemu/sysemu.h" #include "hw/pci/pci.h" #include "nvme.h" #include "nvme-subsys.h" diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 68a942595a..2ad004430e 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -22,7 +22,6 @@ #include "sysemu/hw_accel.h" #include "sysemu/numa.h" #include "sysemu/runstate.h" -#include "sysemu/sysemu.h" static void cpustate_to_cpuinfo_s390(CpuInfoS390 *info, const CPUState *cpu) { diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c index 7e693523d7..f586a4bef5 100644 --- a/hw/core/null-machine.c +++ b/hw/core/null-machine.c @@ -14,7 +14,6 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "hw/boards.h" -#include "sysemu/sysemu.h" #include "exec/address-spaces.h" #include "hw/core/cpu.h" diff --git a/hw/core/numa.c b/hw/core/numa.c index 68cee65f61..ac6bed5817 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -26,7 +26,6 @@ #include "qemu/units.h" #include "sysemu/hostmem.h" #include "sysemu/numa.h" -#include "sysemu/sysemu.h" #include "exec/cpu-common.h" #include "exec/ramlist.h" #include "qemu/bitmap.h" diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 4e8edffeaf..ac24f70a5d 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -42,7 +42,6 @@ #include "hw/irq.h" #include "sysemu/kvm.h" #include "hw/kvm/clock.h" -#include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "sysemu/arch_init.h" #include "hw/i2c/smbus_eeprom.h" diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index 9fe72b370e..6ce37a2b05 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -35,7 +35,6 @@ #include "hw/i386/pc.h" #include "hw/loader.h" #include "hw/qdev-properties.h" -#include "sysemu/sysemu.h" #include "hw/block/flash.h" #include "sysemu/kvm.h" #include "sysemu/sev.h" diff --git a/hw/input/lasips2.c b/hw/input/lasips2.c index 275737842e..e7faf24058 100644 --- a/hw/input/lasips2.c +++ b/hw/input/lasips2.c @@ -27,7 +27,6 @@ #include "hw/input/ps2.h" #include "hw/input/lasips2.h" #include "exec/hwaddr.h" -#include "sysemu/sysemu.h" #include "trace.h" #include "exec/address-spaces.h" #include "migration/vmstate.h" diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c index 97a1a27a9a..6a53e63299 100644 --- a/hw/intc/sifive_plic.c +++ b/hw/intc/sifive_plic.c @@ -29,7 +29,6 @@ #include "hw/qdev-properties.h" #include "hw/intc/sifive_plic.h" #include "target/riscv/cpu.h" -#include "sysemu/sysemu.h" #include "migration/vmstate.h" #define RISCV_DEBUG_PLIC 0 diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index 179c185695..c81bfe58ef 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -14,7 +14,6 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qapi/error.h" -#include "sysemu/sysemu.h" #include "sysemu/blockdev.h" #include "chardev/char.h" #include "hw/block/fdc.h" diff --git a/hw/isa/piix3.c b/hw/isa/piix3.c index f46ccae25c..dab901c9ad 100644 --- a/hw/isa/piix3.c +++ b/hw/isa/piix3.c @@ -29,7 +29,6 @@ #include "hw/isa/isa.h" #include "hw/xen/xen.h" #include "sysemu/xen.h" -#include "sysemu/sysemu.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" #include "migration/vmstate.h" diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c index bee40e25bc..30a8c9fbfa 100644 --- a/hw/m68k/next-kbd.c +++ b/hw/m68k/next-kbd.c @@ -33,7 +33,6 @@ #include "hw/sysbus.h" #include "hw/m68k/next-cube.h" #include "ui/console.h" -#include "sysemu/sysemu.h" #include "migration/vmstate.h" #include "qom/object.h" diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c index caaba1aa4c..8821d009f1 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -33,7 +33,6 @@ #include "qemu/error-report.h" #include "sysemu/device_tree.h" #include "sysemu/reset.h" -#include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/loader.h" #include "elf.h" diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 26e7b1bd9f..5adb67ad2a 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -39,7 +39,6 @@ #include "hw/mips/mips.h" #include "hw/mips/cpudevs.h" #include "hw/pci/pci.h" -#include "sysemu/sysemu.h" #include "sysemu/arch_init.h" #include "qemu/log.h" #include "hw/mips/bios.h" diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index e6eeb575d5..4515296e66 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -35,7 +35,6 @@ #include "hw/char/escc.h" #include "hw/misc/macio/macio.h" #include "hw/intc/heathrow_pic.h" -#include "sysemu/sysemu.h" #include "trace.h" /* Note: this code is strongly inspirated from the corresponding code diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c index affa21a5ed..22bb8910fa 100644 --- a/hw/net/can/xlnx-zynqmp-can.c +++ b/hw/net/can/xlnx-zynqmp-can.c @@ -37,7 +37,6 @@ #include "qemu/bitops.h" #include "qemu/log.h" #include "qemu/cutils.h" -#include "sysemu/sysemu.h" #include "migration/vmstate.h" #include "hw/qdev-properties.h" #include "net/can_emu.h" diff --git a/hw/net/i82596.c b/hw/net/i82596.c index 055c3a1470..ec21e2699a 100644 --- a/hw/net/i82596.c +++ b/hw/net/i82596.c @@ -12,7 +12,6 @@ #include "qemu/timer.h" #include "net/net.h" #include "net/eth.h" -#include "sysemu/sysemu.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" diff --git a/hw/net/lasi_i82596.c b/hw/net/lasi_i82596.c index 820b63f350..e37f7fabe9 100644 --- a/hw/net/lasi_i82596.c +++ b/hw/net/lasi_i82596.c @@ -18,7 +18,6 @@ #include "hw/net/lasi_82596.h" #include "hw/net/i82596.h" #include "trace.h" -#include "sysemu/sysemu.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" diff --git a/hw/nios2/boot.c b/hw/nios2/boot.c index d9969ac148..95bdc18052 100644 --- a/hw/nios2/boot.c +++ b/hw/nios2/boot.c @@ -38,7 +38,6 @@ #include "qemu/error-report.h" #include "sysemu/device_tree.h" #include "sysemu/reset.h" -#include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/loader.h" #include "elf.h" diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index f4e804cdb5..8da7bc7af9 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -34,7 +34,6 @@ #include "ppc405.h" #include "hw/rtc/m48t59.h" #include "hw/block/flash.h" -#include "sysemu/sysemu.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" #include "sysemu/block-backend.h" diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index af4ccb9f43..b41570c747 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -29,7 +29,6 @@ #include "hw/char/serial.h" #include "hw/block/fdc.h" #include "net/net.h" -#include "sysemu/sysemu.h" #include "hw/isa/isa.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c index 9b82feff52..1f53fdb082 100644 --- a/hw/rx/rx-gdbsim.c +++ b/hw/rx/rx-gdbsim.c @@ -24,7 +24,6 @@ #include "cpu.h" #include "hw/loader.h" #include "hw/rx/rx62n.h" -#include "sysemu/sysemu.h" #include "sysemu/qtest.h" #include "sysemu/device_tree.h" #include "hw/boards.h" diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index ff6b55e816..f12af5e35b 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -18,7 +18,6 @@ #include "qapi/error.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" -#include "sysemu/sysemu.h" #include "sysemu/tcg.h" #include "cpu.h" #include "elf.h" diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 0cf2290826..f57340a7d7 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -16,7 +16,6 @@ #include "qemu/units.h" #include "qapi/error.h" #include "cpu.h" -#include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/s390x/sclp.h" #include "hw/s390x/event-facility.h" diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c index d9a9fcbc59..1a44378df4 100644 --- a/hw/sh4/shix.c +++ b/hw/sh4/shix.c @@ -31,7 +31,6 @@ #include "qapi/error.h" #include "cpu.h" #include "hw/sh4/sh.h" -#include "sysemu/sysemu.h" #include "sysemu/qtest.h" #include "hw/boards.h" #include "hw/loader.h" diff --git a/hw/ssi/sifive_spi.c b/hw/ssi/sifive_spi.c index 0c9ebca3c8..03540cf5ca 100644 --- a/hw/ssi/sifive_spi.c +++ b/hw/ssi/sifive_spi.c @@ -24,7 +24,6 @@ #include "hw/qdev-properties.h" #include "hw/sysbus.h" #include "hw/ssi/ssi.h" -#include "sysemu/sysemu.h" #include "qemu/fifo8.h" #include "qemu/log.h" #include "qemu/module.h" diff --git a/hw/vfio/display.c b/hw/vfio/display.c index f04473e3ce..89bc90508f 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -14,7 +14,6 @@ #include #include -#include "sysemu/sysemu.h" #include "hw/display/edid.h" #include "ui/console.h" #include "qapi/error.h" diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 5c65aa0a98..ab4077aad2 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -37,7 +37,6 @@ #include "qemu/units.h" #include "sysemu/kvm.h" #include "sysemu/runstate.h" -#include "sysemu/sysemu.h" #include "pci.h" #include "trace.h" #include "qapi/error.h" diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c index e47e1de676..bbf6200c49 100644 --- a/hw/xtensa/virt.c +++ b/hw/xtensa/virt.c @@ -29,7 +29,6 @@ #include "qapi/error.h" #include "cpu.h" #include "sysemu/reset.h" -#include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/loader.h" #include "hw/pci-host/gpex.h" diff --git a/migration/ram.c b/migration/ram.c index 4682f3625c..9e9b7380bf 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -51,7 +51,6 @@ #include "qemu/rcu_queue.h" #include "migration/colo.h" #include "block.h" -#include "sysemu/sysemu.h" #include "sysemu/cpu-throttle.h" #include "savevm.h" #include "qemu/iov.h" diff --git a/monitor/monitor.c b/monitor/monitor.c index 636bcc81c5..b90c0f4051 100644 --- a/monitor/monitor.c +++ b/monitor/monitor.c @@ -32,7 +32,6 @@ #include "qemu/error-report.h" #include "qemu/option.h" #include "sysemu/qtest.h" -#include "sysemu/sysemu.h" #include "trace.h" /* diff --git a/net/net.c b/net/net.c index edf9b95418..2a472604ec 100644 --- a/net/net.c +++ b/net/net.c @@ -51,9 +51,7 @@ #include "qemu/option.h" #include "qapi/error.h" #include "qapi/opts-visitor.h" -#include "sysemu/sysemu.h" #include "sysemu/runstate.h" -#include "sysemu/sysemu.h" #include "net/filter.h" #include "qapi/string-output-visitor.h" diff --git a/net/netmap.c b/net/netmap.c index 350f097f91..9e0cec58d3 100644 --- a/net/netmap.c +++ b/net/netmap.c @@ -33,7 +33,6 @@ #include "net/net.h" #include "net/tap.h" #include "clients.h" -#include "sysemu/sysemu.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "qemu/iov.h" diff --git a/plugins/api.c b/plugins/api.c index b22998cd7c..218e1342cd 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -37,7 +37,6 @@ #include "qemu/osdep.h" #include "qemu/plugin.h" #include "cpu.h" -#include "sysemu/sysemu.h" #include "tcg/tcg.h" #include "exec/exec-all.h" #include "exec/ram_addr.h" diff --git a/plugins/core.c b/plugins/core.c index 87b823bbc4..93b595a8d6 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -26,7 +26,6 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "sysemu/sysemu.h" #include "tcg/tcg.h" #include "tcg/tcg-op.h" #include "trace/mem-internal.h" /* mem_info macros */ diff --git a/semihosting/config.c b/semihosting/config.c index 3548e0f627..137171b717 100644 --- a/semihosting/config.c +++ b/semihosting/config.c @@ -24,7 +24,6 @@ #include "qemu/error-report.h" #include "semihosting/semihost.h" #include "chardev/char.h" -#include "sysemu/sysemu.h" QemuOptsList qemu_semihosting_config_opts = { .name = "semihosting-config", diff --git a/semihosting/console.c b/semihosting/console.c index c9ebd6fdd0..a78af69387 100644 --- a/semihosting/console.c +++ b/semihosting/console.c @@ -24,7 +24,6 @@ #include "qemu/log.h" #include "chardev/char.h" #include "chardev/char-fe.h" -#include "sysemu/sysemu.h" #include "qemu/main-loop.h" #include "qapi/error.h" #include "qemu/fifo8.h" diff --git a/softmmu/arch_init.c b/softmmu/arch_init.c index 7fd5c09b2b..8471711c54 100644 --- a/softmmu/arch_init.c +++ b/softmmu/arch_init.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" #include "cpu.h" -#include "sysemu/sysemu.h" #include "sysemu/arch_init.h" #include "hw/pci/pci.h" #include "hw/audio/soundhw.h" diff --git a/softmmu/device_tree.c b/softmmu/device_tree.c index 2691c58cf6..b621f63fba 100644 --- a/softmmu/device_tree.c +++ b/softmmu/device_tree.c @@ -23,7 +23,6 @@ #include "qemu/bswap.h" #include "qemu/cutils.h" #include "sysemu/device_tree.h" -#include "sysemu/sysemu.h" #include "hw/loader.h" #include "hw/boards.h" #include "qemu/config-file.h" diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 85034d9c11..7ed276b9b5 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -36,7 +36,6 @@ #include "hw/boards.h" #include "hw/xen/xen.h" #include "sysemu/kvm.h" -#include "sysemu/sysemu.h" #include "sysemu/tcg.h" #include "sysemu/qtest.h" #include "qemu/timer.h" diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c index a9955b97a0..721dec2d82 100644 --- a/softmmu/qdev-monitor.c +++ b/softmmu/qdev-monitor.c @@ -35,7 +35,6 @@ #include "qemu/qemu-print.h" #include "qemu/option_int.h" #include "sysemu/block-backend.h" -#include "sysemu/sysemu.h" #include "migration/misc.h" #include "migration/migration.h" #include "qemu/cutils.h" diff --git a/stubs/semihost.c b/stubs/semihost.c index 1b30f38b03..4bf2cf71b9 100644 --- a/stubs/semihost.c +++ b/stubs/semihost.c @@ -12,7 +12,6 @@ #include "qemu/option.h" #include "qemu/error-report.h" #include "semihosting/semihost.h" -#include "sysemu/sysemu.h" /* Empty config */ QemuOptsList qemu_semihosting_config_opts = { diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 0dd623e590..4eb0d2f85c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -36,7 +36,6 @@ #include "hw/loader.h" #include "hw/boards.h" #endif -#include "sysemu/sysemu.h" #include "sysemu/tcg.h" #include "sysemu/hw_accel.h" #include "kvm_arm.h" diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 41390d046f..48674231e7 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -23,7 +23,6 @@ #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exception.h" -#include "sysemu/sysemu.h" #ifndef CONFIG_USER_ONLY #include "hw/boards.h" #endif diff --git a/target/rx/helper.c b/target/rx/helper.c index 3e380a94fe..db6b07e389 100644 --- a/target/rx/helper.c +++ b/target/rx/helper.c @@ -21,7 +21,6 @@ #include "cpu.h" #include "exec/log.h" #include "exec/cpu_ldst.h" -#include "sysemu/sysemu.h" #include "hw/irq.h" void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte) diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index d35eb39a1b..64455cf309 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -40,7 +40,6 @@ #include "hw/s390x/pv.h" #include "hw/boards.h" #include "sysemu/arch_init.h" -#include "sysemu/sysemu.h" #include "sysemu/tcg.h" #endif #include "fpu/softfloat-helpers.h" diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index c48cd6b46f..20625c2c8f 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -29,7 +29,6 @@ #include "exec/address-spaces.h" #include "tcg_s390x.h" #ifndef CONFIG_USER_ONLY -#include "sysemu/sysemu.h" #include "hw/s390x/s390_flic.h" #include "hw/boards.h" #endif diff --git a/tcg/tcg.c b/tcg/tcg.c index 1fbe0b686d..cc947bf6f6 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -64,7 +64,6 @@ #include "elf.h" #include "exec/log.h" -#include "sysemu/sysemu.h" /* Forward declarations for functions declared in tcg-target.c.inc and used here. */ diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c index 496d11a231..04b70e114b 100644 --- a/tests/qtest/fuzz/fuzz.c +++ b/tests/qtest/fuzz/fuzz.c @@ -18,7 +18,6 @@ #include "qemu/datadir.h" #include "sysemu/qtest.h" #include "sysemu/runstate.h" -#include "sysemu/sysemu.h" #include "qemu/main-loop.h" #include "qemu/rcu.h" #include "tests/qtest/libqos/libqtest.h" diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c index cee1a2a60f..2bc474645c 100644 --- a/tests/qtest/fuzz/qos_fuzz.c +++ b/tests/qtest/fuzz/qos_fuzz.c @@ -22,7 +22,6 @@ #include "qemu-common.h" #include "exec/memory.h" #include "exec/address-spaces.h" -#include "sysemu/sysemu.h" #include "qemu/main-loop.h" #include "tests/qtest/libqos/libqtest.h" diff --git a/util/oslib-win32.c b/util/oslib-win32.c index f68b8012bb..1fc42ec0e3 100644 --- a/util/oslib-win32.c +++ b/util/oslib-win32.c @@ -34,7 +34,6 @@ #include #include "qemu-common.h" #include "qapi/error.h" -#include "sysemu/sysemu.h" #include "qemu/main-loop.h" #include "trace.h" #include "qemu/sockets.h" From ead62c75f618c072a3a18221fd03ae99ae923cca Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 16 Apr 2021 19:13:12 +0200 Subject: [PATCH 0224/3028] Do not include hw/boards.h if it's not really necessary Stop including hw/boards.h in files that don't need it. Signed-off-by: Thomas Huth Message-Id: <20210416171314.2074665-3-thuth@redhat.com> Signed-off-by: Laurent Vivier --- accel/tcg/tcg-accel-ops-icount.c | 1 - accel/tcg/tcg-accel-ops-rr.c | 1 - accel/tcg/tcg-accel-ops.c | 1 - hw/acpi/cpu.c | 1 - hw/acpi/memory_hotplug.c | 1 - hw/alpha/typhoon.c | 1 - hw/arm/aspeed.c | 1 - hw/arm/omap1.c | 1 - hw/arm/omap2.c | 1 - hw/arm/strongarm.c | 1 - hw/arm/virt.c | 1 - hw/avr/arduino.c | 1 - hw/avr/atmega.c | 1 - hw/display/next-fb.c | 1 - hw/hppa/machine.c | 1 - hw/i386/acpi-build.c | 1 - hw/i386/acpi-microvm.c | 1 - hw/i386/intel_iommu.c | 1 - hw/i386/pc.c | 1 - hw/i386/x86-iommu.c | 1 - hw/intc/sifive_plic.c | 1 - hw/mips/loongson3_virt.c | 1 - hw/ppc/e500.c | 1 - hw/ppc/mac_newworld.c | 1 - hw/ppc/mac_oldworld.c | 1 - hw/ppc/pnv.c | 1 - hw/ppc/ppc4xx_devs.c | 1 - hw/ppc/rs6000_mc.c | 1 - hw/ppc/spapr.c | 1 - hw/ppc/spapr_rtas.c | 1 - hw/remote/iohub.c | 1 - hw/s390x/s390-virtio-ccw.c | 2 -- hw/tricore/tc27x_soc.c | 1 - hw/tricore/triboard.c | 1 - softmmu/vl.c | 1 - 35 files changed, 36 deletions(-) diff --git a/accel/tcg/tcg-accel-ops-icount.c b/accel/tcg/tcg-accel-ops-icount.c index 13b8fbeb69..ea42d1d51b 100644 --- a/accel/tcg/tcg-accel-ops-icount.c +++ b/accel/tcg/tcg-accel-ops-icount.c @@ -30,7 +30,6 @@ #include "qemu/main-loop.h" #include "qemu/guest-random.h" #include "exec/exec-all.h" -#include "hw/boards.h" #include "tcg-accel-ops.h" #include "tcg-accel-ops-icount.h" diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index 018b54c508..c02c061ecb 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -30,7 +30,6 @@ #include "qemu/main-loop.h" #include "qemu/guest-random.h" #include "exec/exec-all.h" -#include "hw/boards.h" #include "tcg-accel-ops.h" #include "tcg-accel-ops-rr.h" diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 6cdcaa2855..7191315aee 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -32,7 +32,6 @@ #include "qemu/main-loop.h" #include "qemu/guest-random.h" #include "exec/exec-all.h" -#include "hw/boards.h" #include "tcg-accel-ops.h" #include "tcg-accel-ops-mttcg.h" diff --git a/hw/acpi/cpu.c b/hw/acpi/cpu.c index e2317be546..f82e9512fd 100644 --- a/hw/acpi/cpu.c +++ b/hw/acpi/cpu.c @@ -1,5 +1,4 @@ #include "qemu/osdep.h" -#include "hw/boards.h" #include "migration/vmstate.h" #include "hw/acpi/cpu.h" #include "qapi/error.h" diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c index 0bdcf15528..af37889423 100644 --- a/hw/acpi/memory_hotplug.c +++ b/hw/acpi/memory_hotplug.c @@ -2,7 +2,6 @@ #include "hw/acpi/memory_hotplug.h" #include "hw/acpi/pc-hotplug.h" #include "hw/mem/pc-dimm.h" -#include "hw/boards.h" #include "hw/qdev-core.h" #include "migration/vmstate.h" #include "trace.h" diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index a42b319812..96c35c5fdb 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -11,7 +11,6 @@ #include "qemu/units.h" #include "qapi/error.h" #include "cpu.h" -#include "hw/boards.h" #include "hw/irq.h" #include "alpha_sys.h" #include "exec/address-spaces.h" diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index c4f85dab63..b1e5bc76e4 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -16,7 +16,6 @@ #include "hw/arm/boot.h" #include "hw/arm/aspeed.h" #include "hw/arm/aspeed_soc.h" -#include "hw/boards.h" #include "hw/i2c/smbus_eeprom.h" #include "hw/misc/pca9552.h" #include "hw/misc/tmp105.h" diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index 02c0f66431..180d3788f8 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -24,7 +24,6 @@ #include "qemu-common.h" #include "cpu.h" #include "exec/address-spaces.h" -#include "hw/boards.h" #include "hw/hw.h" #include "hw/irq.h" #include "hw/qdev-properties.h" diff --git a/hw/arm/omap2.c b/hw/arm/omap2.c index 16d388fc79..02b1aa8c97 100644 --- a/hw/arm/omap2.c +++ b/hw/arm/omap2.c @@ -27,7 +27,6 @@ #include "sysemu/qtest.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" -#include "hw/boards.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/arm/boot.h" diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index e3e3ea6163..939a57dda5 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -30,7 +30,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "cpu.h" -#include "hw/boards.h" #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 881969af6b..d8cfdf23c6 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -36,7 +36,6 @@ #include "monitor/qdev.h" #include "qapi/error.h" #include "hw/sysbus.h" -#include "hw/boards.h" #include "hw/arm/boot.h" #include "hw/arm/primecell.h" #include "hw/arm/virt.h" diff --git a/hw/avr/arduino.c b/hw/avr/arduino.c index 3ff31492fa..48ef478346 100644 --- a/hw/avr/arduino.c +++ b/hw/avr/arduino.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "hw/boards.h" #include "atmega.h" #include "boot.h" #include "qom/object.h" diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c index 44c6afebbb..80b8a41cb5 100644 --- a/hw/avr/atmega.c +++ b/hw/avr/atmega.c @@ -18,7 +18,6 @@ #include "hw/qdev-properties.h" #include "hw/sysbus.h" #include "qom/object.h" -#include "hw/boards.h" /* FIXME memory_region_allocate_system_memory for sram */ #include "hw/misc/unimp.h" #include "atmega.h" diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c index cc134c2d5b..dd6a1aa8ae 100644 --- a/hw/display/next-fb.c +++ b/hw/display/next-fb.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "ui/console.h" -#include "hw/boards.h" #include "hw/loader.h" #include "framebuffer.h" #include "ui/pixel_ops.h" diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index f2b71db9bd..2a46af5bc9 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -9,7 +9,6 @@ #include "cpu.h" #include "elf.h" #include "hw/loader.h" -#include "hw/boards.h" #include "qemu/error-report.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index de98750aef..bfecb0038c 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -43,7 +43,6 @@ #include "sysemu/tpm.h" #include "hw/acpi/tpm.h" #include "hw/acpi/vmgenid.h" -#include "hw/boards.h" #include "sysemu/tpm_backend.h" #include "hw/rtc/mc146818rtc_regs.h" #include "migration/vmstate.h" diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index ccd3303aac..1a0f77b911 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -30,7 +30,6 @@ #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/generic_event_device.h" #include "hw/acpi/utils.h" -#include "hw/boards.h" #include "hw/i386/fw_cfg.h" #include "hw/i386/microvm.h" #include "hw/pci/pci.h" diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 6be8f32918..1c10643432 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -31,7 +31,6 @@ #include "hw/qdev-properties.h" #include "hw/i386/pc.h" #include "hw/i386/apic-msidef.h" -#include "hw/boards.h" #include "hw/i386/x86-iommu.h" #include "hw/pci-host/q35.h" #include "sysemu/kvm.h" diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 364816efc9..88ca37bb65 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -74,7 +74,6 @@ #include "qemu/cutils.h" #include "hw/acpi/acpi.h" #include "hw/acpi/cpu_hotplug.h" -#include "hw/boards.h" #include "acpi-build.h" #include "hw/mem/pc-dimm.h" #include "hw/mem/nvdimm.h" diff --git a/hw/i386/x86-iommu.c b/hw/i386/x86-iommu.c index 5f4301639c..86ad03972e 100644 --- a/hw/i386/x86-iommu.c +++ b/hw/i386/x86-iommu.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" -#include "hw/boards.h" #include "hw/i386/x86-iommu.h" #include "hw/qdev-properties.h" #include "hw/i386/pc.h" diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c index 6a53e63299..78903beb06 100644 --- a/hw/intc/sifive_plic.c +++ b/hw/intc/sifive_plic.c @@ -25,7 +25,6 @@ #include "qemu/error-report.h" #include "hw/sysbus.h" #include "hw/pci/msi.h" -#include "hw/boards.h" #include "hw/qdev-properties.h" #include "hw/intc/sifive_plic.h" #include "target/riscv/cpu.h" diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index f9c0873a98..1d6573bc63 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -32,7 +32,6 @@ #include "cpu.h" #include "elf.h" #include "kvm_mips.h" -#include "hw/boards.h" #include "hw/char/serial.h" #include "hw/intc/loongson_liointc.h" #include "hw/mips/mips.h" diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 79467ac512..03b3bd322f 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -25,7 +25,6 @@ #include "qemu/config-file.h" #include "hw/char/serial.h" #include "hw/pci/pci.h" -#include "hw/boards.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "sysemu/reset.h" diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 2175962846..9659857dba 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -58,7 +58,6 @@ #include "hw/pci/pci.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "hw/boards.h" #include "hw/nvram/fw_cfg.h" #include "hw/char/escc.h" #include "hw/misc/macio/macio.h" diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 963d247f5f..95d3d95158 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -38,7 +38,6 @@ #include "hw/isa/isa.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" -#include "hw/boards.h" #include "hw/nvram/fw_cfg.h" #include "hw/char/escc.h" #include "hw/misc/macio/macio.h" diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 6faf1fe473..22b1c4f1f3 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -52,7 +52,6 @@ #include "hw/ppc/pnv_pnor.h" #include "hw/isa/isa.h" -#include "hw/boards.h" #include "hw/char/serial.h" #include "hw/rtc/mc146818rtc.h" diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index fe9d4f7155..980c48944f 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -29,7 +29,6 @@ #include "hw/irq.h" #include "hw/ppc/ppc.h" #include "hw/ppc/ppc4xx.h" -#include "hw/boards.h" #include "hw/intc/ppc-uic.h" #include "hw/qdev-properties.h" #include "qemu/log.h" diff --git a/hw/ppc/rs6000_mc.c b/hw/ppc/rs6000_mc.c index 4db5b51a2d..c0bc212e92 100644 --- a/hw/ppc/rs6000_mc.c +++ b/hw/ppc/rs6000_mc.c @@ -23,7 +23,6 @@ #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "exec/address-spaces.h" -#include "hw/boards.h" #include "qapi/error.h" #include "trace.h" #include "qom/object.h" diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 529ff056dd..0ee61b3128 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -54,7 +54,6 @@ #include "cpu-models.h" #include "hw/core/cpu.h" -#include "hw/boards.h" #include "hw/ppc/ppc.h" #include "hw/loader.h" diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 8a79f9c628..fb64be1150 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -41,7 +41,6 @@ #include "hw/ppc/spapr_rtas.h" #include "hw/ppc/spapr_cpu_core.h" #include "hw/ppc/ppc.h" -#include "hw/boards.h" #include #include "hw/ppc/spapr_drc.h" diff --git a/hw/remote/iohub.c b/hw/remote/iohub.c index e4ff131a6b..547d597f0f 100644 --- a/hw/remote/iohub.c +++ b/hw/remote/iohub.c @@ -15,7 +15,6 @@ #include "hw/pci/pci_ids.h" #include "hw/pci/pci_bus.h" #include "qemu/thread.h" -#include "hw/boards.h" #include "hw/remote/machine.h" #include "hw/remote/iohub.h" #include "qemu/main-loop.h" diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 56b52d2d30..0a97310d42 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -14,10 +14,8 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" -#include "hw/boards.h" #include "exec/address-spaces.h" #include "exec/ram_addr.h" -#include "hw/boards.h" #include "hw/s390x/s390-virtio-hcall.h" #include "hw/s390x/sclp.h" #include "hw/s390x/s390_flic.h" diff --git a/hw/tricore/tc27x_soc.c b/hw/tricore/tc27x_soc.c index dea9ba3cca..dcccdba786 100644 --- a/hw/tricore/tc27x_soc.c +++ b/hw/tricore/tc27x_soc.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/sysbus.h" -#include "hw/boards.h" #include "hw/loader.h" #include "qemu/units.h" #include "hw/misc/unimp.h" diff --git a/hw/tricore/triboard.c b/hw/tricore/triboard.c index 16e2fd7e27..f8d5f7a787 100644 --- a/hw/tricore/triboard.c +++ b/hw/tricore/triboard.c @@ -24,7 +24,6 @@ #include "hw/qdev-properties.h" #include "cpu.h" #include "net/net.h" -#include "hw/boards.h" #include "hw/loader.h" #include "exec/address-spaces.h" #include "elf.h" diff --git a/softmmu/vl.c b/softmmu/vl.c index aadb526138..307944aef3 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -27,7 +27,6 @@ #include "qemu/datadir.h" #include "qemu/units.h" #include "exec/cpu-common.h" -#include "hw/boards.h" #include "hw/qdev-properties.h" #include "qapi/compat-policy.h" #include "qapi/error.h" From 2068cabd3fb1f46dbdd8b24eeaded89a4c9d85e1 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 16 Apr 2021 19:13:13 +0200 Subject: [PATCH 0225/3028] Do not include cpu.h if it's not really necessary Stop including cpu.h in files that don't need it. Signed-off-by: Thomas Huth Message-Id: <20210416171314.2074665-4-thuth@redhat.com> Signed-off-by: Laurent Vivier --- accel/stubs/kvm-stub.c | 1 - accel/stubs/tcg-stub.c | 1 - accel/tcg/cpu-exec-common.c | 1 - accel/tcg/cpu-exec.c | 1 - accel/tcg/cputlb.c | 1 - accel/tcg/plugin-gen.c | 1 - accel/tcg/translate-all.c | 1 - accel/tcg/translator.c | 1 - accel/tcg/user-exec.c | 1 - bsd-user/main.c | 1 - disas.c | 1 - dump/dump.c | 1 - dump/win_dump.c | 1 - hw/arm/allwinner-a10.c | 1 - hw/arm/allwinner-h3.c | 1 - hw/arm/armv7m.c | 1 - hw/arm/aspeed.c | 1 - hw/arm/aspeed_ast2600.c | 1 - hw/arm/aspeed_soc.c | 1 - hw/arm/bcm2836.c | 1 - hw/arm/cubieboard.c | 1 - hw/arm/digic_boards.c | 1 - hw/arm/exynos4_boards.c | 1 - hw/arm/fsl-imx25.c | 1 - hw/arm/fsl-imx31.c | 1 - hw/arm/imx25_pdk.c | 1 - hw/arm/kzm.c | 1 - hw/arm/msf2-som.c | 1 - hw/arm/nrf51_soc.c | 1 - hw/arm/orangepi.c | 1 - hw/arm/raspi.c | 1 - hw/arm/stellaris.c | 1 - hw/arm/xlnx-zcu102.c | 1 - hw/arm/xlnx-zynqmp.c | 1 - hw/char/spapr_vty.c | 1 - hw/core/machine-qmp-cmds.c | 1 - hw/hppa/dino.c | 1 - hw/hppa/lasi.c | 1 - hw/i386/kvm/apic.c | 1 - hw/i386/kvm/clock.c | 1 - hw/i386/kvmvapic.c | 1 - hw/i386/microvm.c | 1 - hw/i386/pc_piix.c | 1 - hw/i386/vmport.c | 1 - hw/intc/apic.c | 1 - hw/intc/apic_common.c | 1 - hw/intc/arm_gic_kvm.c | 1 - hw/intc/armv7m_nvic.c | 1 - hw/intc/grlib_irqmp.c | 1 - hw/intc/openpic_kvm.c | 1 - hw/intc/s390_flic.c | 1 - hw/intc/s390_flic_kvm.c | 1 - hw/intc/xics.c | 1 - hw/intc/xics_kvm.c | 1 - hw/intc/xics_spapr.c | 1 - hw/m68k/next-cube.c | 1 - hw/mips/loongson3_virt.c | 1 - hw/mips/malta.c | 1 - hw/mips/mips_int.c | 1 - hw/mips/mipssim.c | 1 - hw/misc/mips_itu.c | 1 - hw/net/spapr_llan.c | 1 - hw/nios2/10m50_devboard.c | 1 - hw/nios2/boot.c | 1 - hw/nios2/generic_nommu.c | 1 - hw/nvram/spapr_nvram.c | 1 - hw/ppc/ppc.c | 1 - hw/ppc/ppc440_uc.c | 1 - hw/ppc/prep.c | 1 - hw/ppc/spapr_drc.c | 1 - hw/ppc/spapr_events.c | 1 - hw/ppc/spapr_hcall.c | 1 - hw/ppc/spapr_pci.c | 1 - hw/ppc/spapr_pci_vfio.c | 1 - hw/ppc/spapr_rng.c | 1 - hw/ppc/spapr_rtas.c | 1 - hw/ppc/spapr_rtas_ddw.c | 1 - hw/ppc/spapr_rtc.c | 1 - hw/ppc/spapr_tpm_proxy.c | 1 - hw/remote/proxy-memory-listener.c | 1 - hw/rx/rx-gdbsim.c | 1 - hw/rx/rx62n.c | 1 - hw/s390x/3270-ccw.c | 1 - hw/s390x/css-bridge.c | 1 - hw/s390x/css.c | 1 - hw/s390x/ipl.c | 1 - hw/s390x/pv.c | 1 - hw/s390x/s390-pci-bus.c | 1 - hw/s390x/s390-pci-inst.c | 1 - hw/s390x/s390-stattrib-kvm.c | 1 - hw/s390x/s390-stattrib.c | 1 - hw/s390x/s390-virtio-ccw.c | 1 - hw/s390x/sclp.c | 1 - hw/s390x/sclpcpu.c | 1 - hw/scsi/spapr_vscsi.c | 1 - hw/sh4/sh7750.c | 1 - hw/tricore/tc27x_soc.c | 1 - hw/tricore/triboard.c | 1 - hw/vfio/ap.c | 1 - hw/vfio/migration.c | 1 - hw/vfio/spapr.c | 1 - hw/xtensa/sim.c | 1 - hw/xtensa/virt.c | 1 - hw/xtensa/xtensa_memory.c | 1 - linux-user/main.c | 1 - linux-user/semihost.c | 1 - migration/ram.c | 1 - monitor/misc.c | 1 - plugins/api.c | 1 - plugins/core.c | 1 - plugins/loader.c | 1 - semihosting/arm-compat-semi.c | 1 - semihosting/console.c | 1 - softmmu/arch_init.c | 1 - softmmu/memory.c | 1 - softmmu/memory_mapping.c | 1 - softmmu/physmem.c | 1 - tcg/tcg-op-vec.c | 1 - tcg/tcg-op.c | 1 - tcg/tcg.c | 1 - 120 files changed, 120 deletions(-) diff --git a/accel/stubs/kvm-stub.c b/accel/stubs/kvm-stub.c index 0f17acfac0..5b1d00a222 100644 --- a/accel/stubs/kvm-stub.c +++ b/accel/stubs/kvm-stub.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "sysemu/kvm.h" #ifndef CONFIG_USER_ONLY diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c index 2304606f8e..d8162673ae 100644 --- a/accel/stubs/tcg-stub.c +++ b/accel/stubs/tcg-stub.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "exec/exec-all.h" void tb_flush(CPUState *cpu) diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c index 12c1e3e974..be6fe45aa5 100644 --- a/accel/tcg/cpu-exec-common.c +++ b/accel/tcg/cpu-exec-common.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "sysemu/cpus.h" #include "sysemu/tcg.h" #include "exec/exec-all.h" diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index f62f12e717..0dc5271715 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/qemu-print.h" -#include "cpu.h" #include "hw/core/tcg-cpu-ops.h" #include "trace.h" #include "disas/disas.h" diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 8a7b779270..502f803e5e 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" -#include "cpu.h" #include "hw/core/tcg-cpu-ops.h" #include "exec/exec-all.h" #include "exec/memory.h" diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index c3dc3effe7..7627225aef 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -43,7 +43,6 @@ * CPU's index into a TCG temp, since the first callback did it already. */ #include "qemu/osdep.h" -#include "cpu.h" #include "tcg/tcg.h" #include "tcg/tcg-op.h" #include "trace/mem.h" diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index b12d0898d0..ae7e873713 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -22,7 +22,6 @@ #include "qemu-common.h" #define NO_CPU_IO_DEFS -#include "cpu.h" #include "trace.h" #include "disas/disas.h" #include "exec/exec-all.h" diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 2dfc27102f..1d32732198 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" -#include "cpu.h" #include "tcg/tcg.h" #include "tcg/tcg-op.h" #include "exec/exec-all.h" diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 0d8cc27b21..fb2d43e6a9 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -17,7 +17,6 @@ * License along with this library; if not, see . */ #include "qemu/osdep.h" -#include "cpu.h" #include "hw/core/tcg-cpu-ops.h" #include "disas/disas.h" #include "exec/exec-all.h" diff --git a/bsd-user/main.c b/bsd-user/main.c index 798aba512c..36a889d084 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -32,7 +32,6 @@ #include "qemu/path.h" #include "qemu/help_option.h" #include "qemu/module.h" -#include "cpu.h" #include "exec/exec-all.h" #include "tcg/tcg.h" #include "qemu/timer.h" diff --git a/disas.c b/disas.c index a61f95b580..3dab4482d1 100644 --- a/disas.c +++ b/disas.c @@ -4,7 +4,6 @@ #include "elf.h" #include "qemu/qemu-print.h" -#include "cpu.h" #include "disas/disas.h" #include "disas/capstone.h" diff --git a/dump/dump.c b/dump/dump.c index 929138e91d..ab625909f3 100644 --- a/dump/dump.c +++ b/dump/dump.c @@ -15,7 +15,6 @@ #include "qemu-common.h" #include "qemu/cutils.h" #include "elf.h" -#include "cpu.h" #include "exec/hwaddr.h" #include "monitor/monitor.h" #include "sysemu/kvm.h" diff --git a/dump/win_dump.c b/dump/win_dump.c index 652c7bad99..c5eb5a9aac 100644 --- a/dump/win_dump.c +++ b/dump/win_dump.c @@ -12,7 +12,6 @@ #include "qemu-common.h" #include "qemu/cutils.h" #include "elf.h" -#include "cpu.h" #include "exec/hwaddr.h" #include "monitor/monitor.h" #include "sysemu/kvm.h" diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index d404f31e02..0844a65641 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -19,7 +19,6 @@ #include "exec/address-spaces.h" #include "qapi/error.h" #include "qemu/module.h" -#include "cpu.h" #include "hw/sysbus.h" #include "hw/arm/allwinner-a10.h" #include "hw/misc/unimp.h" diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index 88259a9c0d..bbe65d1860 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -24,7 +24,6 @@ #include "qemu/module.h" #include "qemu/units.h" #include "hw/qdev-core.h" -#include "cpu.h" #include "hw/sysbus.h" #include "hw/char/serial.h" #include "hw/misc/unimp.h" diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 6dd10d8470..caeed29670 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "hw/arm/armv7m.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/sysbus.h" #include "hw/arm/boot.h" #include "hw/loader.h" diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index b1e5bc76e4..7480533cb7 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "exec/address-spaces.h" #include "hw/arm/boot.h" #include "hw/arm/aspeed.h" diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 504aabf173..8e4ef07b14 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "exec/address-spaces.h" #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 516277800c..fc270daa57 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "exec/address-spaces.h" #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index de7ade2878..24354338ca 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" -#include "cpu.h" #include "hw/arm/bcm2836.h" #include "hw/arm/raspi_platform.h" #include "hw/sysbus.h" diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index 9e872135ae..d7184e5ec2 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include "exec/address-spaces.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/boards.h" #include "hw/qdev-properties.h" #include "hw/arm/allwinner-a10.h" diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c index 65d3a9ba74..fdb6781567 100644 --- a/hw/arm/digic_boards.c +++ b/hw/arm/digic_boards.c @@ -27,7 +27,6 @@ #include "qapi/error.h" #include "qemu-common.h" #include "qemu/datadir.h" -#include "cpu.h" #include "hw/boards.h" #include "exec/address-spaces.h" #include "qemu/error-report.h" diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 8ae136bbdf..35dd9875da 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -25,7 +25,6 @@ #include "qemu/units.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "cpu.h" #include "hw/sysbus.h" #include "net/net.h" #include "hw/arm/boot.h" diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index 08a98f828f..dafc0bef47 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/arm/fsl-imx25.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 0983998bb4..def27bb913 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/arm/fsl-imx31.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 1c201d0d8e..9c58fbde57 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/qdev-properties.h" #include "hw/arm/fsl-imx25.h" #include "hw/boards.h" diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c index e3f7d4ead2..39559c44c2 100644 --- a/hw/arm/kzm.c +++ b/hw/arm/kzm.c @@ -15,7 +15,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/arm/fsl-imx31.h" #include "hw/boards.h" #include "qemu/error-report.h" diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c index f9b61c36dd..343ec977c0 100644 --- a/hw/arm/msf2-som.c +++ b/hw/arm/msf2-som.c @@ -31,7 +31,6 @@ #include "hw/arm/boot.h" #include "exec/address-spaces.h" #include "hw/arm/msf2-soc.h" -#include "cpu.h" #define DDR_BASE_ADDRESS 0xA0000000 #define DDR_SIZE (64 * MiB) diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index e15981e019..71bdcf06b4 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -15,7 +15,6 @@ #include "hw/misc/unimp.h" #include "exec/address-spaces.h" #include "qemu/log.h" -#include "cpu.h" #include "hw/arm/nrf51.h" #include "hw/arm/nrf51_soc.h" diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index 6ccb61c149..0cf9895ce7 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -21,7 +21,6 @@ #include "qemu/units.h" #include "exec/address-spaces.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/boards.h" #include "hw/qdev-properties.h" #include "hw/arm/allwinner-h3.h" diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index 1b7e9c4cb4..b30a17871f 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -16,7 +16,6 @@ #include "qemu/units.h" #include "qemu/cutils.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/arm/bcm2836.h" #include "hw/registerfields.h" #include "qemu/error-report.h" diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 27292ec411..8b4dab9b79 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -27,7 +27,6 @@ #include "migration/vmstate.h" #include "hw/misc/unimp.h" #include "hw/qdev-clock.h" -#include "cpu.h" #include "qom/object.h" #define GPIO_A 0 diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index a9db25eb99..6c6cb02e86 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -17,7 +17,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/arm/xlnx-zynqmp.h" #include "hw/boards.h" #include "qemu/error-report.h" diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 7f01284a5c..6c93dcb820 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" -#include "cpu.h" #include "hw/arm/xlnx-zynqmp.h" #include "hw/intc/arm_gic_common.h" #include "hw/boards.h" diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c index 79eaa2fa52..91eae1a598 100644 --- a/hw/char/spapr_vty.c +++ b/hw/char/spapr_vty.c @@ -2,7 +2,6 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qapi/error.h" -#include "cpu.h" #include "migration/vmstate.h" #include "chardev/char-fe.h" #include "hw/ppc/spapr.h" diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 2ad004430e..a36c96608f 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "hw/boards.h" #include "qapi/error.h" #include "qapi/qapi-builtin-visit.h" diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index 5b82c9440d..bd97e0c51d 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -14,7 +14,6 @@ #include "qemu/module.h" #include "qemu/units.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/irq.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index a8f5defcd0..408af9ccb7 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -13,7 +13,6 @@ #include "qemu/units.h" #include "qemu/log.h" #include "qapi/error.h" -#include "cpu.h" #include "trace.h" #include "hw/irq.h" #include "sysemu/sysemu.h" diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index 3dbff2be2e..52ff490910 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "qemu/module.h" -#include "cpu.h" #include "hw/i386/apic_internal.h" #include "hw/pci/msi.h" #include "sysemu/hw_accel.h" diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 51872dd84c..efbc1e0d12 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -14,7 +14,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "qemu/host-utils.h" #include "qemu/module.h" #include "sysemu/kvm.h" diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c index 46315445d2..43f8a8f679 100644 --- a/hw/i386/kvmvapic.c +++ b/hw/i386/kvmvapic.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "qemu/module.h" -#include "cpu.h" #include "sysemu/sysemu.h" #include "sysemu/cpus.h" #include "sysemu/hw_accel.h" diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index edf2b0f061..aba0c83219 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -49,7 +49,6 @@ #include "hw/pci-host/gpex.h" #include "hw/usb/xhci.h" -#include "cpu.h" #include "elf.h" #include "kvm/kvm_i386.h" #include "hw/xen/start_info.h" diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index ac24f70a5d..9adf411053 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -49,7 +49,6 @@ #include "exec/memory.h" #include "exec/address-spaces.h" #include "hw/acpi/acpi.h" -#include "cpu.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/xen.h" diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 490a57f52c..7cc75dbc6d 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -37,7 +37,6 @@ #include "sysemu/hw_accel.h" #include "sysemu/qtest.h" #include "qemu/log.h" -#include "cpu.h" #include "trace.h" #include "qom/object.h" diff --git a/hw/intc/apic.c b/hw/intc/apic.c index f4f50f974e..3df11c34d6 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -17,7 +17,6 @@ * License along with this library; if not, see */ #include "qemu/osdep.h" -#include "cpu.h" #include "qemu/thread.h" #include "hw/i386/apic_internal.h" #include "hw/i386/apic.h" diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 97dd96dffa..2a20982066 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -22,7 +22,6 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qapi/error.h" -#include "cpu.h" #include "qapi/visitor.h" #include "hw/i386/apic.h" #include "hw/i386/apic_internal.h" diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 49f79a8674..7d2a13273a 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -22,7 +22,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" -#include "cpu.h" #include "migration/blocker.h" #include "sysemu/kvm.h" #include "kvm_arm.h" diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 0d8426dafc..c4287d82d8 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/sysbus.h" #include "migration/vmstate.h" #include "qemu/timer.h" diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c index 984334fa7b..3bfe2544b7 100644 --- a/hw/intc/grlib_irqmp.c +++ b/hw/intc/grlib_irqmp.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "hw/irq.h" #include "hw/sysbus.h" -#include "cpu.h" #include "hw/qdev-properties.h" #include "hw/sparc/grlib.h" diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c index e1a39e33cb..16badace8b 100644 --- a/hw/intc/openpic_kvm.c +++ b/hw/intc/openpic_kvm.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include #include "exec/address-spaces.h" #include "hw/ppc/openpic.h" diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index aacdb1bbc2..74e02858d4 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -20,7 +20,6 @@ #include "hw/qdev-properties.h" #include "hw/s390x/css.h" #include "trace.h" -#include "cpu.h" #include "qapi/error.h" #include "hw/s390x/s390-virtio-ccw.h" diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index d1c8fb8016..929cfa3a68 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "kvm_s390x.h" #include #include "qemu/error-report.h" diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 68f9d44feb..48a835eab7 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "trace.h" #include "qemu/timer.h" #include "hw/ppc/xics.h" diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c index 570d635bcc..f5bfc501bc 100644 --- a/hw/intc/xics_kvm.c +++ b/hw/intc/xics_kvm.c @@ -28,7 +28,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" -#include "cpu.h" #include "trace.h" #include "sysemu/kvm.h" #include "hw/ppc/spapr.h" diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 8ae4f41459..37b2d99977 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -26,7 +26,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "trace.h" #include "qemu/timer.h" #include "hw/ppc/spapr.h" diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c index 92b45d760f..5bd4f2d832 100644 --- a/hw/m68k/next-cube.c +++ b/hw/m68k/next-cube.c @@ -10,7 +10,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "exec/hwaddr.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index 1d6573bc63..16f7f84d34 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -29,7 +29,6 @@ #include "qemu/cutils.h" #include "qemu/datadir.h" #include "qapi/error.h" -#include "cpu.h" #include "elf.h" #include "kvm_mips.h" #include "hw/char/serial.h" diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 5adb67ad2a..459791414a 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -27,7 +27,6 @@ #include "qemu/bitops.h" #include "qemu-common.h" #include "qemu/datadir.h" -#include "cpu.h" #include "hw/clock.h" #include "hw/southbridge/piix.h" #include "hw/isa/superio.h" diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index 0f9c6f07c1..2db5e10fe0 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -24,7 +24,6 @@ #include "qemu/main-loop.h" #include "hw/irq.h" #include "hw/mips/cpudevs.h" -#include "cpu.h" #include "sysemu/kvm.h" #include "kvm_mips.h" diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c index f5d0da05aa..2e0d4aceed 100644 --- a/hw/mips/mipssim.c +++ b/hw/mips/mipssim.c @@ -29,7 +29,6 @@ #include "qapi/error.h" #include "qemu-common.h" #include "qemu/datadir.h" -#include "cpu.h" #include "hw/clock.h" #include "hw/mips/mips.h" #include "hw/mips/cpudevs.h" diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c index 133399598f..80683fed31 100644 --- a/hw/misc/mips_itu.c +++ b/hw/misc/mips_itu.c @@ -22,7 +22,6 @@ #include "qemu/log.h" #include "qemu/module.h" #include "qapi/error.h" -#include "cpu.h" #include "exec/exec-all.h" #include "hw/misc/mips_itu.h" #include "hw/qdev-properties.h" diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 10e85a4556..a6876a936d 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -26,7 +26,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "qemu/log.h" #include "qemu/module.h" #include "net/net.h" diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c index a14fc31e86..3d1205b8bd 100644 --- a/hw/nios2/10m50_devboard.c +++ b/hw/nios2/10m50_devboard.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/sysbus.h" #include "hw/char/serial.h" diff --git a/hw/nios2/boot.c b/hw/nios2/boot.c index 95bdc18052..5b3e4efed5 100644 --- a/hw/nios2/boot.c +++ b/hw/nios2/boot.c @@ -32,7 +32,6 @@ #include "qemu/units.h" #include "qemu-common.h" #include "qemu/datadir.h" -#include "cpu.h" #include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/error-report.h" diff --git a/hw/nios2/generic_nommu.c b/hw/nios2/generic_nommu.c index b70a42dc2f..fbc18dbd04 100644 --- a/hw/nios2/generic_nommu.c +++ b/hw/nios2/generic_nommu.c @@ -29,7 +29,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" -#include "cpu.h" #include "hw/char/serial.h" #include "hw/boards.h" diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index 3bb4654c58..fbfdf47e26 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -26,7 +26,6 @@ #include "qemu/module.h" #include "qemu/units.h" #include "qapi/error.h" -#include "cpu.h" #include #include "sysemu/block-backend.h" diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index bf28d6bfc8..7375bf4fa9 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "hw/irq.h" #include "hw/ppc/ppc.h" #include "hw/ppc/ppc_e500.h" diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index f6f89058ab..96a1fe06c3 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -14,7 +14,6 @@ #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" -#include "cpu.h" #include "hw/irq.h" #include "exec/address-spaces.h" #include "exec/memory.h" diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index b41570c747..e8dc128308 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "hw/rtc/m48t59.h" #include "hw/char/serial.h" #include "hw/block/fdc.h" diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 9e16505fa1..b8c2f3daf7 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qapi/qmp/qnull.h" -#include "cpu.h" #include "qemu/cutils.h" #include "hw/ppc/spapr_drc.h" #include "qom/object.h" diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index d51daedfa6..0cfc19be19 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "sysemu/device_tree.h" #include "sysemu/runstate.h" diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 7b5cd3553c..2a464a42e6 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -7,7 +7,6 @@ #include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/error-report.h" -#include "cpu.h" #include "exec/exec-all.h" #include "helper_regs.h" #include "hw/ppc/spapr.h" diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index feba18cb12..4effe23a18 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/irq.h" #include "hw/sysbus.h" #include "migration/vmstate.h" diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index e0547b1740..7817cf72ee 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include -#include "cpu.h" #include "hw/ppc/spapr.h" #include "hw/pci-host/spapr.h" #include "hw/pci/msix.h" diff --git a/hw/ppc/spapr_rng.c b/hw/ppc/spapr_rng.c index d14800e9de..df5c4b9687 100644 --- a/hw/ppc/spapr_rng.c +++ b/hw/ppc/spapr_rng.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/module.h" diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index fb64be1150..59dbea4e22 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -26,7 +26,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "qemu/log.h" #include "qemu/error-report.h" #include "sysemu/sysemu.h" diff --git a/hw/ppc/spapr_rtas_ddw.c b/hw/ppc/spapr_rtas_ddw.c index 3501b05819..3e826e1308 100644 --- a/hw/ppc/spapr_rtas_ddw.c +++ b/hw/ppc/spapr_rtas_ddw.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "qemu/error-report.h" #include "qemu/module.h" #include "hw/ppc/spapr.h" diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c index 68cfc578a3..fba4dfca35 100644 --- a/hw/ppc/spapr_rtc.c +++ b/hw/ppc/spapr_rtc.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" -#include "cpu.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "hw/ppc/spapr.h" diff --git a/hw/ppc/spapr_tpm_proxy.c b/hw/ppc/spapr_tpm_proxy.c index a01f81f9e0..2454086744 100644 --- a/hw/ppc/spapr_tpm_proxy.c +++ b/hw/ppc/spapr_tpm_proxy.c @@ -15,7 +15,6 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/reset.h" -#include "cpu.h" #include "hw/ppc/spapr.h" #include "hw/qdev-properties.h" #include "trace.h" diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c index af1fa6f5aa..3649919f66 100644 --- a/hw/remote/proxy-memory-listener.c +++ b/hw/remote/proxy-memory-listener.c @@ -14,7 +14,6 @@ #include "qemu/range.h" #include "exec/memory.h" #include "exec/cpu-common.h" -#include "cpu.h" #include "exec/ram_addr.h" #include "exec/address-spaces.h" #include "qapi/error.h" diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c index 1f53fdb082..b52d76b9b6 100644 --- a/hw/rx/rx-gdbsim.c +++ b/hw/rx/rx-gdbsim.c @@ -21,7 +21,6 @@ #include "qemu/error-report.h" #include "qapi/error.h" #include "qemu-common.h" -#include "cpu.h" #include "hw/loader.h" #include "hw/rx/rx62n.h" #include "sysemu/qtest.h" diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index 31ddccf2cd..fa5add9f9d 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -28,7 +28,6 @@ #include "hw/sysbus.h" #include "hw/qdev-properties.h" #include "sysemu/sysemu.h" -#include "cpu.h" #include "qom/object.h" /* diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index f3e7342b1e..25e628f575 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" -#include "cpu.h" #include "hw/s390x/css.h" #include "hw/s390x/css-bridge.h" #include "hw/qdev-properties.h" diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index 9d793d671e..191b29f077 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -20,7 +20,6 @@ #include "hw/s390x/css.h" #include "ccw-device.h" #include "hw/s390x/css-bridge.h" -#include "cpu.h" /* * Invoke device-specific unplug handler, disable the subchannel diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 4149b8e5a7..bed46f5ec3 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -15,7 +15,6 @@ #include "qemu/bitops.h" #include "qemu/error-report.h" #include "exec/address-spaces.h" -#include "cpu.h" #include "hw/s390x/ioinst.h" #include "hw/qdev-properties.h" #include "hw/s390x/css.h" diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index f12af5e35b..8c863cf386 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -19,7 +19,6 @@ #include "sysemu/reset.h" #include "sysemu/runstate.h" #include "sysemu/tcg.h" -#include "cpu.h" #include "elf.h" #include "hw/loader.h" #include "hw/qdev-properties.h" diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c index 93eccfc05d..401b63d6cb 100644 --- a/hw/s390x/pv.c +++ b/hw/s390x/pv.c @@ -13,7 +13,6 @@ #include -#include "cpu.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "sysemu/kvm.h" diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index dd138dae94..7db1c5943f 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -14,7 +14,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qapi/visitor.h" -#include "cpu.h" #include "hw/s390x/s390-pci-bus.h" #include "hw/s390x/s390-pci-inst.h" #include "hw/s390x/s390-pci-vfio.h" diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 4b8326afa4..9ec277d50e 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -12,7 +12,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "exec/memop.h" #include "exec/memory-internal.h" #include "qemu/error-report.h" diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c index f89d8d9d16..f0b11a74e4 100644 --- a/hw/s390x/s390-stattrib-kvm.c +++ b/hw/s390x/s390-stattrib-kvm.c @@ -16,7 +16,6 @@ #include "qemu/error-report.h" #include "sysemu/kvm.h" #include "exec/ram_addr.h" -#include "cpu.h" #include "kvm_s390x.h" Object *kvm_s390_stattrib_create(void) diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index 4441e1d331..9eda1c3b2a 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "cpu.h" #include "migration/qemu-file.h" #include "migration/register.h" #include "hw/s390x/storage-attributes.h" diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 0a97310d42..f2f38c0c64 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "exec/address-spaces.h" #include "exec/ram_addr.h" #include "hw/s390x/s390-virtio-hcall.h" diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index f57340a7d7..edb6e3ea01 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -15,7 +15,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" -#include "cpu.h" #include "hw/boards.h" #include "hw/s390x/sclp.h" #include "hw/s390x/event-facility.h" diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c index 62806d3273..f2b1a4b037 100644 --- a/hw/s390x/sclpcpu.c +++ b/hw/s390x/sclpcpu.c @@ -17,7 +17,6 @@ #include "hw/s390x/sclp.h" #include "qemu/module.h" #include "hw/s390x/event-facility.h" -#include "cpu.h" #include "sysemu/cpus.h" typedef struct ConfigMgtData { diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index ca5c13c4a8..c210262484 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -34,7 +34,6 @@ #include "qemu/osdep.h" #include "qemu/module.h" -#include "cpu.h" #include "hw/scsi/scsi.h" #include "migration/vmstate.h" #include "scsi/constants.h" diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c index f8ac3ec6e3..d53a436d8c 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -31,7 +31,6 @@ #include "sh7750_regnames.h" #include "hw/sh4/sh_intc.h" #include "hw/timer/tmu012.h" -#include "cpu.h" #include "exec/exec-all.h" #define NB_DEVICES 4 diff --git a/hw/tricore/tc27x_soc.c b/hw/tricore/tc27x_soc.c index dcccdba786..d66d6980c3 100644 --- a/hw/tricore/tc27x_soc.c +++ b/hw/tricore/tc27x_soc.c @@ -25,7 +25,6 @@ #include "qemu/units.h" #include "hw/misc/unimp.h" #include "exec/address-spaces.h" -#include "cpu.h" #include "hw/tricore/tc27x_soc.h" #include "hw/tricore/triboard.h" diff --git a/hw/tricore/triboard.c b/hw/tricore/triboard.c index f8d5f7a787..943f706989 100644 --- a/hw/tricore/triboard.c +++ b/hw/tricore/triboard.c @@ -22,7 +22,6 @@ #include "qemu/units.h" #include "qapi/error.h" #include "hw/qdev-properties.h" -#include "cpu.h" #include "net/net.h" #include "hw/loader.h" #include "exec/address-spaces.h" diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index f9dbec37da..4b32aca1a0 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -21,7 +21,6 @@ #include "qemu/module.h" #include "qemu/option.h" #include "qemu/config-file.h" -#include "cpu.h" #include "kvm_s390x.h" #include "migration/vmstate.h" #include "hw/qdev-properties.h" diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 384576cfc0..201642d75e 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -15,7 +15,6 @@ #include "sysemu/runstate.h" #include "hw/vfio/vfio-common.h" -#include "cpu.h" #include "migration/migration.h" #include "migration/vmstate.h" #include "migration/qemu-file.h" diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index 2900bd1941..ea3f70bd2f 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -9,7 +9,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include #include diff --git a/hw/xtensa/sim.c b/hw/xtensa/sim.c index cbac50db2d..c38e522b02 100644 --- a/hw/xtensa/sim.c +++ b/hw/xtensa/sim.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" #include "hw/boards.h" diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c index bbf6200c49..18d3c3cdb2 100644 --- a/hw/xtensa/virt.c +++ b/hw/xtensa/virt.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "sysemu/reset.h" #include "hw/boards.h" #include "hw/loader.h" diff --git a/hw/xtensa/xtensa_memory.c b/hw/xtensa/xtensa_memory.c index 1c5f62b014..2c1095f017 100644 --- a/hw/xtensa/xtensa_memory.c +++ b/hw/xtensa/xtensa_memory.c @@ -27,7 +27,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "exec/memory.h" #include "qemu/error-report.h" #include "xtensa_memory.h" diff --git a/linux-user/main.c b/linux-user/main.c index f956afccab..57ba1b45ab 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -38,7 +38,6 @@ #include "qemu/help_option.h" #include "qemu/module.h" #include "qemu/plugin.h" -#include "cpu.h" #include "exec/exec-all.h" #include "tcg/tcg.h" #include "qemu/timer.h" diff --git a/linux-user/semihost.c b/linux-user/semihost.c index 82013b8b48..f53ab526fb 100644 --- a/linux-user/semihost.c +++ b/linux-user/semihost.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "semihosting/console.h" #include "qemu.h" #include diff --git a/migration/ram.c b/migration/ram.c index 9e9b7380bf..ace8ad431c 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -27,7 +27,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "qemu/cutils.h" #include "qemu/bitops.h" #include "qemu/bitmap.h" diff --git a/monitor/misc.c b/monitor/misc.c index 55f3744053..f3a393ea59 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "monitor-internal.h" -#include "cpu.h" #include "monitor/qdev.h" #include "hw/usb.h" #include "hw/pci/pci.h" diff --git a/plugins/api.c b/plugins/api.c index 218e1342cd..817c9b6b69 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -36,7 +36,6 @@ #include "qemu/osdep.h" #include "qemu/plugin.h" -#include "cpu.h" #include "tcg/tcg.h" #include "exec/exec-all.h" #include "exec/ram_addr.h" diff --git a/plugins/core.c b/plugins/core.c index 93b595a8d6..55d188af51 100644 --- a/plugins/core.c +++ b/plugins/core.c @@ -23,7 +23,6 @@ #include "hw/core/cpu.h" #include "exec/cpu-common.h" -#include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "tcg/tcg.h" diff --git a/plugins/loader.c b/plugins/loader.c index 8550e61184..05df40398d 100644 --- a/plugins/loader.c +++ b/plugins/loader.c @@ -27,7 +27,6 @@ #include "qemu/xxhash.h" #include "qemu/plugin.h" #include "hw/core/cpu.h" -#include "cpu.h" #include "exec/exec-all.h" #ifndef CONFIG_USER_ONLY #include "hw/boards.h" diff --git a/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c index f9c87245b8..1c29146dcf 100644 --- a/semihosting/arm-compat-semi.c +++ b/semihosting/arm-compat-semi.c @@ -33,7 +33,6 @@ #include "qemu/osdep.h" -#include "cpu.h" #include "semihosting/semihost.h" #include "semihosting/console.h" #include "semihosting/common-semi.h" diff --git a/semihosting/console.c b/semihosting/console.c index a78af69387..ef6958d844 100644 --- a/semihosting/console.c +++ b/semihosting/console.c @@ -16,7 +16,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "semihosting/semihost.h" #include "semihosting/console.h" #include "exec/gdbstub.h" diff --git a/softmmu/arch_init.c b/softmmu/arch_init.c index 8471711c54..f09bab830c 100644 --- a/softmmu/arch_init.c +++ b/softmmu/arch_init.c @@ -22,7 +22,6 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "cpu.h" #include "sysemu/arch_init.h" #include "hw/pci/pci.h" #include "hw/audio/soundhw.h" diff --git a/softmmu/memory.c b/softmmu/memory.c index d4493ef9e4..a62816647b 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -16,7 +16,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qapi/error.h" -#include "cpu.h" #include "exec/memory.h" #include "exec/address-spaces.h" #include "qapi/visitor.h" diff --git a/softmmu/memory_mapping.c b/softmmu/memory_mapping.c index 18d0b8067c..e7af276546 100644 --- a/softmmu/memory_mapping.c +++ b/softmmu/memory_mapping.c @@ -14,7 +14,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "cpu.h" #include "sysemu/memory_mapping.h" #include "exec/memory.h" #include "exec/address-spaces.h" diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 7ed276b9b5..1821882614 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -23,7 +23,6 @@ #include "qemu/cutils.h" #include "qemu/cacheflush.h" -#include "cpu.h" #ifdef CONFIG_TCG #include "hw/core/tcg-cpu-ops.h" diff --git a/tcg/tcg-op-vec.c b/tcg/tcg-op-vec.c index d19aa7373e..15e026ae49 100644 --- a/tcg/tcg-op-vec.c +++ b/tcg/tcg-op-vec.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "tcg/tcg.h" #include "tcg/tcg-op.h" #include "tcg/tcg-mo.h" diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 70475773f4..dcc2ed0bbc 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "exec/exec-all.h" #include "tcg/tcg.h" #include "tcg/tcg-op.h" diff --git a/tcg/tcg.c b/tcg/tcg.c index cc947bf6f6..db806a6658 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -41,7 +41,6 @@ CPU definitions. Currently they are used for qemu_ld/st instructions */ #define NO_CPU_IO_DEFS -#include "cpu.h" #include "exec/exec-all.h" From ee86213aa3ff73c49ced340e4d409943a1f752a3 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 16 Apr 2021 19:13:14 +0200 Subject: [PATCH 0226/3028] Do not include exec/address-spaces.h if it's not really necessary Stop including exec/address-spaces.h in files that don't need it. Signed-off-by: Thomas Huth Message-Id: <20210416171314.2074665-5-thuth@redhat.com> Signed-off-by: Laurent Vivier --- accel/kvm/kvm-all.c | 1 - accel/tcg/cputlb.c | 1 - hw/acpi/generic_event_device.c | 1 - hw/acpi/ich9.c | 1 - hw/acpi/pcihp.c | 1 - hw/acpi/piix4.c | 1 - hw/alpha/typhoon.c | 1 - hw/arm/allwinner-a10.c | 1 - hw/arm/allwinner-h3.c | 1 - hw/arm/armv7m.c | 1 - hw/arm/aspeed.c | 1 - hw/arm/aspeed_ast2600.c | 1 - hw/arm/aspeed_soc.c | 1 - hw/arm/boot.c | 1 - hw/arm/cubieboard.c | 1 - hw/arm/digic_boards.c | 1 - hw/arm/fsl-imx25.c | 1 - hw/arm/highbank.c | 1 - hw/arm/imx25_pdk.c | 1 - hw/arm/musicpal.c | 1 - hw/arm/npcm7xx.c | 1 - hw/arm/npcm7xx_boards.c | 1 - hw/arm/nrf51_soc.c | 1 - hw/arm/nseries.c | 1 - hw/arm/palm.c | 1 - hw/arm/realview.c | 1 - hw/arm/sbsa-ref.c | 1 - hw/arm/smmu-common.c | 1 - hw/arm/smmuv3.c | 1 - hw/arm/versatilepb.c | 1 - hw/arm/vexpress.c | 1 - hw/arm/virt.c | 1 - hw/arm/xilinx_zynq.c | 1 - hw/arm/xlnx-versal-virt.c | 1 - hw/arm/xlnx-zynqmp.c | 1 - hw/char/mchp_pfsoc_mmuart.c | 1 - hw/core/loader.c | 1 - hw/cris/axis_dev88.c | 1 - hw/dma/pl080.c | 1 - hw/hppa/dino.c | 1 - hw/hppa/lasi.c | 1 - hw/i386/intel_iommu.c | 1 - hw/i386/pc.c | 1 - hw/i386/pc_piix.c | 1 - hw/i386/pc_q35.c | 1 - hw/i386/xen/xen-hvm.c | 1 - hw/i386/xen/xen_platform.c | 1 - hw/intc/openpic_kvm.c | 1 - hw/isa/lpc_ich9.c | 1 - hw/isa/vt82c686.c | 1 - hw/lm32/lm32_boards.c | 1 - hw/lm32/milkymist.c | 1 - hw/m68k/an5206.c | 1 - hw/m68k/mcf5208.c | 1 - hw/m68k/next-cube.c | 1 - hw/m68k/next-kbd.c | 1 - hw/m68k/q800.c | 1 - hw/m68k/virt.c | 1 - hw/mem/sparse-mem.c | 1 - hw/mips/boston.c | 1 - hw/mips/fuloong2e.c | 1 - hw/mips/gt64xxx_pci.c | 1 - hw/mips/jazz.c | 1 - hw/mips/loongson3_virt.c | 1 - hw/mips/malta.c | 1 - hw/mips/mipssim.c | 1 - hw/moxie/moxiesim.c | 1 - hw/net/msf2-emac.c | 1 - hw/nvram/nrf51_nvm.c | 1 - hw/openrisc/openrisc_sim.c | 1 - hw/pci-host/bonito.c | 1 - hw/pci-host/ppce500.c | 1 - hw/pci-host/prep.c | 1 - hw/pci-host/sabre.c | 1 - hw/pci-host/sh_pci.c | 1 - hw/pci/pci.c | 1 - hw/pci/pcie_host.c | 1 - hw/ppc/e500.c | 1 - hw/ppc/mac_newworld.c | 1 - hw/ppc/mac_oldworld.c | 1 - hw/ppc/pnv.c | 1 - hw/ppc/pnv_psi.c | 1 - hw/ppc/ppc405_boards.c | 1 - hw/ppc/ppc440_bamboo.c | 1 - hw/ppc/ppc440_pcix.c | 1 - hw/ppc/ppc440_uc.c | 1 - hw/ppc/ppc4xx_pci.c | 1 - hw/ppc/prep.c | 1 - hw/ppc/sam460ex.c | 1 - hw/ppc/spapr.c | 1 - hw/ppc/spapr_iommu.c | 1 - hw/ppc/spapr_pci.c | 1 - hw/ppc/virtex_ml507.c | 1 - hw/remote/machine.c | 1 - hw/remote/memory.c | 1 - hw/remote/proxy-memory-listener.c | 1 - hw/riscv/opentitan.c | 1 - hw/riscv/sifive_e.c | 1 - hw/rtc/m48t59.c | 1 - hw/rtc/mc146818rtc.c | 1 - hw/s390x/s390-virtio-ccw.c | 1 - hw/sh4/r2d.c | 1 - hw/sh4/shix.c | 1 - hw/sparc/leon3.c | 1 - hw/sparc64/niagara.c | 1 - hw/ssi/aspeed_smc.c | 1 - hw/tpm/tpm_crb.c | 1 - hw/tricore/tc27x_soc.c | 1 - hw/tricore/triboard.c | 1 - hw/tricore/tricore_testboard.c | 1 - hw/virtio/vhost.c | 1 - hw/virtio/virtio.c | 1 - hw/xen/xen_pt.c | 1 - hw/xtensa/sim.c | 1 - hw/xtensa/virt.c | 1 - hw/xtensa/xtfpga.c | 1 - softmmu/memory.c | 1 - softmmu/physmem.c | 1 - target/i386/hvf/hvf.c | 1 - target/i386/hvf/x86_mmu.c | 1 - target/i386/sev.c | 1 - target/s390x/diag.c | 1 - target/xtensa/op_helper.c | 1 - tests/qtest/fuzz/generic_fuzz.c | 2 -- tests/qtest/fuzz/qos_fuzz.c | 1 - 125 files changed, 126 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 50e56664cc..4e0168e88b 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -33,7 +33,6 @@ #include "qemu/bswap.h" #include "exec/memory.h" #include "exec/ram_addr.h" -#include "exec/address-spaces.h" #include "qemu/event_notifier.h" #include "qemu/main-loop.h" #include "trace.h" diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 502f803e5e..84e7d91a5c 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -22,7 +22,6 @@ #include "hw/core/tcg-cpu-ops.h" #include "exec/exec-all.h" #include "exec/memory.h" -#include "exec/address-spaces.h" #include "exec/cpu_ldst.h" #include "exec/cputlb.h" #include "exec/tb-hash.h" diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index 5454be67d5..39c825763a 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/address-spaces.h" #include "hw/acpi/acpi.h" #include "hw/acpi/generic_event_device.h" #include "hw/irq.h" diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 853447cf9d..4daa79ec8d 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -35,7 +35,6 @@ #include "sysemu/runstate.h" #include "hw/acpi/acpi.h" #include "hw/acpi/tco.h" -#include "exec/address-spaces.h" #include "hw/i386/ich9.h" #include "hw/mem/pc-dimm.h" diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index f4cb3c979d..4999277d57 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -31,7 +31,6 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" #include "hw/acpi/acpi.h" -#include "exec/address-spaces.h" #include "hw/pci/pci_bus.h" #include "migration/vmstate.h" #include "qapi/error.h" diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 8f8b0e95e5..0bd23d74e2 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -33,7 +33,6 @@ #include "sysemu/xen.h" #include "qapi/error.h" #include "qemu/range.h" -#include "exec/address-spaces.h" #include "hw/acpi/pcihp.h" #include "hw/acpi/cpu_hotplug.h" #include "hw/acpi/cpu.h" diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index 96c35c5fdb..87020cbe0d 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -13,7 +13,6 @@ #include "cpu.h" #include "hw/irq.h" #include "alpha_sys.h" -#include "exec/address-spaces.h" #include "qom/object.h" diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index 0844a65641..05e84728cb 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -16,7 +16,6 @@ */ #include "qemu/osdep.h" -#include "exec/address-spaces.h" #include "qapi/error.h" #include "qemu/module.h" #include "hw/sysbus.h" diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index bbe65d1860..27f1070145 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "exec/address-spaces.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/module.h" diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index caeed29670..af0d935bf7 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -18,7 +18,6 @@ #include "sysemu/reset.h" #include "qemu/error-report.h" #include "qemu/module.h" -#include "exec/address-spaces.h" #include "target/arm/idau.h" /* Bitbanded IO. Each word corresponds to a single bit. */ diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 7480533cb7..b623226cdf 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/address-spaces.h" #include "hw/arm/boot.h" #include "hw/arm/aspeed.h" #include "hw/arm/aspeed_soc.h" diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 8e4ef07b14..8202b4f174 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -9,7 +9,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/address-spaces.h" #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" #include "hw/char/serial.h" diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index fc270daa57..abc90ed8ec 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/address-spaces.h" #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" #include "hw/char/serial.h" diff --git a/hw/arm/boot.c b/hw/arm/boot.c index e56c42ac22..d7b059225e 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -25,7 +25,6 @@ #include "sysemu/device_tree.h" #include "qemu/config-file.h" #include "qemu/option.h" -#include "exec/address-spaces.h" #include "qemu/units.h" /* Kernel boot protocol is specified in the kernel docs diff --git a/hw/arm/cubieboard.c b/hw/arm/cubieboard.c index d7184e5ec2..294ba5de6e 100644 --- a/hw/arm/cubieboard.c +++ b/hw/arm/cubieboard.c @@ -16,7 +16,6 @@ */ #include "qemu/osdep.h" -#include "exec/address-spaces.h" #include "qapi/error.h" #include "hw/boards.h" #include "hw/qdev-properties.h" diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c index fdb6781567..b771a3d8b7 100644 --- a/hw/arm/digic_boards.c +++ b/hw/arm/digic_boards.c @@ -28,7 +28,6 @@ #include "qemu-common.h" #include "qemu/datadir.h" #include "hw/boards.h" -#include "exec/address-spaces.h" #include "qemu/error-report.h" #include "hw/arm/digic.h" #include "hw/block/flash.h" diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index dafc0bef47..24c4374590 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -26,7 +26,6 @@ #include "qapi/error.h" #include "hw/arm/fsl-imx25.h" #include "sysemu/sysemu.h" -#include "exec/address-spaces.h" #include "hw/qdev-properties.h" #include "chardev/char.h" diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 5afdd28b35..c3cb315dbc 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -29,7 +29,6 @@ #include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "hw/boards.h" -#include "exec/address-spaces.h" #include "qemu/error-report.h" #include "hw/char/pl011.h" #include "hw/ide/ahci.h" diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 9c58fbde57..11426e5ec0 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -29,7 +29,6 @@ #include "hw/arm/fsl-imx25.h" #include "hw/boards.h" #include "qemu/error-report.h" -#include "exec/address-spaces.h" #include "sysemu/qtest.h" #include "hw/i2c/i2c.h" #include "qemu/cutils.h" diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 7d67dc7254..2d612cc0c9 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -31,7 +31,6 @@ #include "sysemu/block-backend.h" #include "sysemu/runstate.h" #include "sysemu/dma.h" -#include "exec/address-spaces.h" #include "ui/pixel_ops.h" #include "qemu/cutils.h" #include "qom/object.h" diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c index 495b0f8e91..2ab0080e0b 100644 --- a/hw/arm/npcm7xx.c +++ b/hw/arm/npcm7xx.c @@ -16,7 +16,6 @@ #include "qemu/osdep.h" -#include "exec/address-spaces.h" #include "hw/arm/boot.h" #include "hw/arm/npcm7xx.h" #include "hw/char/serial.h" diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index d91d687700..d4553e3786 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -16,7 +16,6 @@ #include "qemu/osdep.h" -#include "exec/address-spaces.h" #include "hw/arm/npcm7xx.h" #include "hw/core/cpu.h" #include "hw/i2c/smbus_eeprom.h" diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index 71bdcf06b4..9407c2f268 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -13,7 +13,6 @@ #include "hw/arm/boot.h" #include "hw/sysbus.h" #include "hw/misc/unimp.h" -#include "exec/address-spaces.h" #include "qemu/log.h" #include "hw/arm/nrf51.h" diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c index 387eea4d44..0aefa5d0f3 100644 --- a/hw/arm/nseries.c +++ b/hw/arm/nseries.c @@ -43,7 +43,6 @@ #include "hw/loader.h" #include "hw/sysbus.h" #include "qemu/log.h" -#include "exec/address-spaces.h" /* Nokia N8x0 support */ struct n800_s { diff --git a/hw/arm/palm.c b/hw/arm/palm.c index 4e3dc5fbbf..68e11dd1ec 100644 --- a/hw/arm/palm.c +++ b/hw/arm/palm.c @@ -29,7 +29,6 @@ #include "hw/input/tsc2xxx.h" #include "hw/irq.h" #include "hw/loader.h" -#include "exec/address-spaces.h" #include "cpu.h" #include "qemu/cutils.h" #include "qom/object.h" diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 0831159d15..1c54316ba3 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -20,7 +20,6 @@ #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/i2c/i2c.h" -#include "exec/address-spaces.h" #include "qemu/error-report.h" #include "hw/char/pl011.h" #include "hw/cpu/a9mpcore.h" diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index 88dfb2284c..43c19b4923 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -27,7 +27,6 @@ #include "sysemu/numa.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" -#include "exec/address-spaces.h" #include "exec/hwaddr.h" #include "kvm_arm.h" #include "hw/arm/boot.h" diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 84d2c62c26..0459850a93 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -17,7 +17,6 @@ */ #include "qemu/osdep.h" -#include "exec/address-spaces.h" #include "trace.h" #include "exec/target_page.h" #include "hw/core/cpu.h" diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 228dc54b0b..7bed2ac520 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -23,7 +23,6 @@ #include "migration/vmstate.h" #include "hw/qdev-core.h" #include "hw/pci/pci.h" -#include "exec/address-spaces.h" #include "cpu.h" #include "trace.h" #include "qemu/log.h" diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 1ea5534626..575399c4fc 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -21,7 +21,6 @@ #include "hw/i2c/arm_sbcon_i2c.h" #include "hw/irq.h" #include "hw/boards.h" -#include "exec/address-spaces.h" #include "hw/block/flash.h" #include "qemu/error-report.h" #include "hw/char/pl011.h" diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 326a1a6db5..58481c0762 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -35,7 +35,6 @@ #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/loader.h" -#include "exec/address-spaces.h" #include "hw/block/flash.h" #include "sysemu/device_tree.h" #include "qemu/error-report.h" diff --git a/hw/arm/virt.c b/hw/arm/virt.c index d8cfdf23c6..0a78532018 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -50,7 +50,6 @@ #include "sysemu/tpm.h" #include "sysemu/kvm.h" #include "hw/loader.h" -#include "exec/address-spaces.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "qemu/module.h" diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 8db6cfd47f..85f25d15db 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -22,7 +22,6 @@ #include "hw/sysbus.h" #include "hw/arm/boot.h" #include "net/net.h" -#include "exec/address-spaces.h" #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/block/flash.h" diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 73e8268b35..5bca360dce 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -13,7 +13,6 @@ #include "qemu/error-report.h" #include "qapi/error.h" #include "sysemu/device_tree.h" -#include "exec/address-spaces.h" #include "hw/boards.h" #include "hw/sysbus.h" #include "hw/arm/sysbus-fdt.h" diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 6c93dcb820..3597e8db4d 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -21,7 +21,6 @@ #include "hw/arm/xlnx-zynqmp.h" #include "hw/intc/arm_gic_common.h" #include "hw/boards.h" -#include "exec/address-spaces.h" #include "sysemu/kvm.h" #include "sysemu/sysemu.h" #include "kvm_arm.h" diff --git a/hw/char/mchp_pfsoc_mmuart.c b/hw/char/mchp_pfsoc_mmuart.c index 8a002b0a19..2facf85c2d 100644 --- a/hw/char/mchp_pfsoc_mmuart.c +++ b/hw/char/mchp_pfsoc_mmuart.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "chardev/char.h" -#include "exec/address-spaces.h" #include "hw/char/mchp_pfsoc_mmuart.h" static uint64_t mchp_pfsoc_mmuart_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/core/loader.c b/hw/core/loader.c index d3e5f3b423..5b34869a54 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -57,7 +57,6 @@ #include "hw/loader.h" #include "hw/nvram/fw_cfg.h" #include "exec/memory.h" -#include "exec/address-spaces.h" #include "hw/boards.h" #include "qemu/cutils.h" #include "sysemu/runstate.h" diff --git a/hw/cris/axis_dev88.c b/hw/cris/axis_dev88.c index af5a0e3517..d82050d927 100644 --- a/hw/cris/axis_dev88.c +++ b/hw/cris/axis_dev88.c @@ -34,7 +34,6 @@ #include "hw/loader.h" #include "elf.h" #include "boot.h" -#include "exec/address-spaces.h" #include "sysemu/qtest.h" #include "sysemu/sysemu.h" diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c index f1a586b1d7..2627307cc8 100644 --- a/hw/dma/pl080.c +++ b/hw/dma/pl080.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "migration/vmstate.h" -#include "exec/address-spaces.h" #include "qemu/log.h" #include "qemu/module.h" #include "hw/dma/pl080.h" diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c index bd97e0c51d..eab96dd84e 100644 --- a/hw/hppa/dino.c +++ b/hw/hppa/dino.c @@ -19,7 +19,6 @@ #include "hw/pci/pci_bus.h" #include "migration/vmstate.h" #include "hppa_sys.h" -#include "exec/address-spaces.h" #include "trace.h" #include "qom/object.h" diff --git a/hw/hppa/lasi.c b/hw/hppa/lasi.c index 408af9ccb7..88c3791eb6 100644 --- a/hw/hppa/lasi.c +++ b/hw/hppa/lasi.c @@ -22,7 +22,6 @@ #include "hw/char/parallel.h" #include "hw/char/serial.h" #include "hw/input/lasips2.h" -#include "exec/address-spaces.h" #include "migration/vmstate.h" #include "qom/object.h" diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 1c10643432..209b3f5553 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -24,7 +24,6 @@ #include "qemu/main-loop.h" #include "qapi/error.h" #include "hw/sysbus.h" -#include "exec/address-spaces.h" #include "intel_iommu_internal.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 88ca37bb65..8cfaf216e7 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -65,7 +65,6 @@ #include "hw/xen/start_info.h" #include "ui/qemu-spice.h" #include "exec/memory.h" -#include "exec/address-spaces.h" #include "sysemu/arch_init.h" #include "qemu/bitmap.h" #include "qemu/config-file.h" diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 9adf411053..5ac2edbf1f 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -47,7 +47,6 @@ #include "hw/i2c/smbus_eeprom.h" #include "hw/xen/xen-x86.h" #include "exec/memory.h" -#include "exec/address-spaces.h" #include "hw/acpi/acpi.h" #include "qapi/error.h" #include "qemu/error-report.h" diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 458ed41c65..46a0f196f4 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -38,7 +38,6 @@ #include "hw/kvm/clock.h" #include "hw/pci-host/q35.h" #include "hw/qdev-properties.h" -#include "exec/address-spaces.h" #include "hw/i386/x86.h" #include "hw/i386/pc.h" #include "hw/i386/ich9.h" diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index 7ce672e5a5..c53fa17c50 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -33,7 +33,6 @@ #include "sysemu/xen.h" #include "sysemu/xen-mapcache.h" #include "trace.h" -#include "exec/address-spaces.h" #include #include diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index bf4f20e92b..72028449ba 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -31,7 +31,6 @@ #include "migration/vmstate.h" #include "hw/xen/xen-legacy-backend.h" #include "trace.h" -#include "exec/address-spaces.h" #include "sysemu/xen.h" #include "sysemu/block-backend.h" #include "qemu/error-report.h" diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c index 16badace8b..21da680389 100644 --- a/hw/intc/openpic_kvm.c +++ b/hw/intc/openpic_kvm.c @@ -25,7 +25,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include -#include "exec/address-spaces.h" #include "hw/ppc/openpic.h" #include "hw/ppc/openpic_kvm.h" #include "hw/pci/msi.h" diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index 160bea447a..5f9de0239c 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -44,7 +44,6 @@ #include "hw/acpi/ich9.h" #include "hw/pci/pci_bus.h" #include "hw/qdev-properties.h" -#include "exec/address-spaces.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "hw/core/cpu.h" diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 98325bb32b..31b1818b21 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -30,7 +30,6 @@ #include "qemu/module.h" #include "qemu/range.h" #include "qemu/timer.h" -#include "exec/address-spaces.h" #include "trace.h" #define TYPE_VIA_PM "via-pm" diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c index b5d97dd53e..2961e4c2b4 100644 --- a/hw/lm32/lm32_boards.c +++ b/hw/lm32/lm32_boards.c @@ -30,7 +30,6 @@ #include "elf.h" #include "lm32_hwsetup.h" #include "lm32.h" -#include "exec/address-spaces.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c index 72d1326531..bef7855328 100644 --- a/hw/lm32/milkymist.c +++ b/hw/lm32/milkymist.c @@ -37,7 +37,6 @@ #include "hw/display/milkymist_tmu2.h" #include "hw/sd/sd.h" #include "lm32.h" -#include "exec/address-spaces.h" #include "qemu/cutils.h" #define BIOS_FILENAME "mmone-bios.bin" diff --git a/hw/m68k/an5206.c b/hw/m68k/an5206.c index 673898b0ea..11ae4c9795 100644 --- a/hw/m68k/an5206.c +++ b/hw/m68k/an5206.c @@ -13,7 +13,6 @@ #include "hw/boards.h" #include "hw/loader.h" #include "elf.h" -#include "exec/address-spaces.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" diff --git a/hw/m68k/mcf5208.c b/hw/m68k/mcf5208.c index 7a03c71059..93812ee206 100644 --- a/hw/m68k/mcf5208.c +++ b/hw/m68k/mcf5208.c @@ -26,7 +26,6 @@ #include "hw/loader.h" #include "hw/sysbus.h" #include "elf.h" -#include "exec/address-spaces.h" #define SYS_FREQ 166666666 diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c index 5bd4f2d832..de951ffe5d 100644 --- a/hw/m68k/next-cube.c +++ b/hw/m68k/next-cube.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "exec/hwaddr.h" -#include "exec/address-spaces.h" #include "sysemu/sysemu.h" #include "sysemu/qtest.h" #include "hw/irq.h" diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c index 30a8c9fbfa..0544160e91 100644 --- a/hw/m68k/next-kbd.c +++ b/hw/m68k/next-kbd.c @@ -29,7 +29,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" -#include "exec/address-spaces.h" #include "hw/sysbus.h" #include "hw/m68k/next-cube.h" #include "ui/console.h" diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index d1ab1ff77d..11376daa85 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -31,7 +31,6 @@ #include "elf.h" #include "hw/loader.h" #include "ui/console.h" -#include "exec/address-spaces.h" #include "hw/char/escc.h" #include "hw/sysbus.h" #include "hw/scsi/esp.h" diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 9469f82800..4e8bce5aa6 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -17,7 +17,6 @@ #include "elf.h" #include "hw/loader.h" #include "ui/console.h" -#include "exec/address-spaces.h" #include "hw/sysbus.h" #include "standard-headers/asm-m68k/bootinfo.h" #include "standard-headers/asm-m68k/bootinfo-virt.h" diff --git a/hw/mem/sparse-mem.c b/hw/mem/sparse-mem.c index a13ac74dd9..e6640eb8e7 100644 --- a/hw/mem/sparse-mem.c +++ b/hw/mem/sparse-mem.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" -#include "exec/address-spaces.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" #include "qapi/error.h" diff --git a/hw/mips/boston.c b/hw/mips/boston.c index ac2e93a05a..20b06865b2 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "exec/address-spaces.h" #include "hw/boards.h" #include "hw/char/serial.h" #include "hw/ide/pci.h" diff --git a/hw/mips/fuloong2e.c b/hw/mips/fuloong2e.c index 1851eb0944..c1b8066a13 100644 --- a/hw/mips/fuloong2e.c +++ b/hw/mips/fuloong2e.c @@ -38,7 +38,6 @@ #include "hw/qdev-properties.h" #include "elf.h" #include "hw/isa/vt82c686.h" -#include "exec/address-spaces.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" #include "sysemu/sysemu.h" diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c index 43349d6837..c7480bd019 100644 --- a/hw/mips/gt64xxx_pci.c +++ b/hw/mips/gt64xxx_pci.c @@ -33,7 +33,6 @@ #include "migration/vmstate.h" #include "hw/intc/i8259.h" #include "hw/irq.h" -#include "exec/address-spaces.h" #include "trace.h" #include "qom/object.h" diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index 1a0888a0fd..dba2088ed1 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -47,7 +47,6 @@ #include "hw/audio/pcspk.h" #include "hw/input/i8042.h" #include "hw/sysbus.h" -#include "exec/address-spaces.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" #include "qapi/error.h" diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index 16f7f84d34..ae192db0c8 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -47,7 +47,6 @@ #include "hw/pci-host/gpex.h" #include "hw/usb.h" #include "net/net.h" -#include "exec/address-spaces.h" #include "sysemu/kvm.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 459791414a..7dcf175d72 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -45,7 +45,6 @@ #include "hw/irq.h" #include "hw/loader.h" #include "elf.h" -#include "exec/address-spaces.h" #include "qom/object.h" #include "hw/sysbus.h" /* SysBusDevice */ #include "qemu/host-utils.h" diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c index 2e0d4aceed..2325e7e05a 100644 --- a/hw/mips/mipssim.c +++ b/hw/mips/mipssim.c @@ -42,7 +42,6 @@ #include "elf.h" #include "hw/sysbus.h" #include "hw/qdev-properties.h" -#include "exec/address-spaces.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" #include "sysemu/reset.h" diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c index 196b730589..3d255d4879 100644 --- a/hw/moxie/moxiesim.c +++ b/hw/moxie/moxiesim.c @@ -35,7 +35,6 @@ #include "hw/boards.h" #include "hw/loader.h" #include "hw/char/serial.h" -#include "exec/address-spaces.h" #include "elf.h" #define PHYS_MEM_BASE 0x80000000 diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c index 3e6206044f..9278fdce0b 100644 --- a/hw/net/msf2-emac.c +++ b/hw/net/msf2-emac.c @@ -32,7 +32,6 @@ #include "qemu-common.h" #include "qemu/log.h" #include "qapi/error.h" -#include "exec/address-spaces.h" #include "hw/registerfields.h" #include "hw/net/msf2-emac.h" #include "hw/net/mii.h" diff --git a/hw/nvram/nrf51_nvm.c b/hw/nvram/nrf51_nvm.c index 7b3460d52d..7f1db8c423 100644 --- a/hw/nvram/nrf51_nvm.c +++ b/hw/nvram/nrf51_nvm.c @@ -21,7 +21,6 @@ #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" -#include "exec/address-spaces.h" #include "hw/arm/nrf51.h" #include "hw/nvram/nrf51_nvm.h" #include "hw/qdev-properties.h" diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 39f1d344ae..73fe383c2d 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -29,7 +29,6 @@ #include "net/net.h" #include "hw/loader.h" #include "hw/qdev-properties.h" -#include "exec/address-spaces.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" #include "sysemu/qtest.h" diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 2a2db7cea6..afb3d1f81d 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -49,7 +49,6 @@ #include "migration/vmstate.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" -#include "exec/address-spaces.h" #include "hw/misc/unimp.h" #include "hw/registerfields.h" #include "qom/object.h" diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 5ad1424b31..89c1b53dd7 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -415,7 +415,6 @@ static const VMStateDescription vmstate_ppce500_pci = { } }; -#include "exec/address-spaces.h" static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp) { diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index 0a9162fba9..9fef74fc56 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -38,7 +38,6 @@ #include "hw/irq.h" #include "hw/loader.h" #include "hw/or-irq.h" -#include "exec/address-spaces.h" #include "elf.h" #include "qom/object.h" diff --git a/hw/pci-host/sabre.c b/hw/pci-host/sabre.c index f41a0cc301..949ecc21f2 100644 --- a/hw/pci-host/sabre.c +++ b/hw/pci-host/sabre.c @@ -34,7 +34,6 @@ #include "hw/irq.h" #include "hw/pci-bridge/simba.h" #include "hw/pci-host/sabre.h" -#include "exec/address-spaces.h" #include "qapi/error.h" #include "qemu/log.h" #include "qemu/module.h" diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 734892f47c..08c1562e22 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -30,7 +30,6 @@ #include "hw/pci/pci_host.h" #include "qemu/bswap.h" #include "qemu/module.h" -#include "exec/address-spaces.h" #include "qom/object.h" #define TYPE_SH_PCI_HOST_BRIDGE "sh_pci" diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 8f35e13a0c..377084f1a8 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -45,7 +45,6 @@ #include "trace.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" -#include "exec/address-spaces.h" #include "hw/hotplug.h" #include "hw/boards.h" #include "qapi/error.h" diff --git a/hw/pci/pcie_host.c b/hw/pci/pcie_host.c index 3534006f99..5abbe83220 100644 --- a/hw/pci/pcie_host.c +++ b/hw/pci/pcie_host.c @@ -23,7 +23,6 @@ #include "hw/pci/pci.h" #include "hw/pci/pcie_host.h" #include "qemu/module.h" -#include "exec/address-spaces.h" /* a helper function to get a PCIDevice for a given mmconfig address */ static inline PCIDevice *pcie_dev_find_by_mmcfg_addr(PCIBus *s, diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 03b3bd322f..95451414dd 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -38,7 +38,6 @@ #include "hw/loader.h" #include "elf.h" #include "hw/sysbus.h" -#include "exec/address-spaces.h" #include "qemu/host-utils.h" #include "qemu/option.h" #include "hw/pci-host/ppce500.h" diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 9659857dba..f24abf71af 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -70,7 +70,6 @@ #include "sysemu/reset.h" #include "kvm_ppc.h" #include "hw/usb.h" -#include "exec/address-spaces.h" #include "hw/sysbus.h" #include "trace.h" diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 95d3d95158..de2be960e6 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -48,7 +48,6 @@ #include "sysemu/kvm.h" #include "sysemu/reset.h" #include "kvm_ppc.h" -#include "exec/address-spaces.h" #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 22b1c4f1f3..ffe01977cd 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -38,7 +38,6 @@ #include "hw/ppc/pnv_core.h" #include "hw/loader.h" #include "hw/nmi.h" -#include "exec/address-spaces.h" #include "qapi/visitor.h" #include "monitor/monitor.h" #include "hw/intc/intc.h" diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 3e868c8c8d..382ac20fa6 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -26,7 +26,6 @@ #include "qapi/error.h" #include "monitor/monitor.h" -#include "exec/address-spaces.h" #include "hw/ppc/fdt.h" #include "hw/ppc/pnv.h" diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index 8da7bc7af9..972a7a4a3e 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -40,7 +40,6 @@ #include "hw/boards.h" #include "qemu/error-report.h" #include "hw/loader.h" -#include "exec/address-spaces.h" #include "qemu/cutils.h" #define BIOS_FILENAME "ppc405_rom.bin" diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index b7539aa721..7fb620b9a0 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -25,7 +25,6 @@ #include "sysemu/device_tree.h" #include "hw/loader.h" #include "elf.h" -#include "exec/address-spaces.h" #include "hw/char/serial.h" #include "hw/ppc/ppc.h" #include "ppc405.h" diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c index 91cbcd0504..788d25514a 100644 --- a/hw/ppc/ppc440_pcix.c +++ b/hw/ppc/ppc440_pcix.c @@ -28,7 +28,6 @@ #include "hw/ppc/ppc4xx.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" -#include "exec/address-spaces.h" #include "trace.h" #include "qom/object.h" diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index 96a1fe06c3..993e3ba955 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -15,7 +15,6 @@ #include "qemu/log.h" #include "qemu/module.h" #include "hw/irq.h" -#include "exec/address-spaces.h" #include "exec/memory.h" #include "hw/ppc/ppc.h" #include "hw/qdev-properties.h" diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c index e8789f64e8..8147ba6f94 100644 --- a/hw/ppc/ppc4xx_pci.c +++ b/hw/ppc/ppc4xx_pci.c @@ -28,7 +28,6 @@ #include "sysemu/reset.h" #include "hw/pci/pci.h" #include "hw/pci/pci_host.h" -#include "exec/address-spaces.h" #include "trace.h" #include "qom/object.h" diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index e8dc128308..acfc2a91d8 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -43,7 +43,6 @@ #include "sysemu/arch_init.h" #include "sysemu/kvm.h" #include "sysemu/reset.h" -#include "exec/address-spaces.h" #include "trace.h" #include "elf.h" #include "qemu/units.h" diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 0c6baf77e8..0737234d66 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -24,7 +24,6 @@ #include "sysemu/block-backend.h" #include "hw/loader.h" #include "elf.h" -#include "exec/address-spaces.h" #include "exec/memory.h" #include "ppc440.h" #include "ppc405.h" diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 0ee61b3128..5951e805bd 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -69,7 +69,6 @@ #include "hw/virtio/virtio-scsi.h" #include "hw/virtio/vhost-scsi-common.h" -#include "exec/address-spaces.h" #include "exec/ram_addr.h" #include "hw/usb.h" #include "qemu/config-file.h" diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 24537ffcbd..db01071858 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -25,7 +25,6 @@ #include "kvm_ppc.h" #include "migration/vmstate.h" #include "sysemu/dma.h" -#include "exec/address-spaces.h" #include "trace.h" #include "hw/ppc/spapr.h" diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 4effe23a18..7a725855f9 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -34,7 +34,6 @@ #include "hw/pci/pci_host.h" #include "hw/ppc/spapr.h" #include "hw/pci-host/spapr.h" -#include "exec/address-spaces.h" #include "exec/ram_addr.h" #include #include "trace.h" diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 3a57604ac0..9c575403b8 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -39,7 +39,6 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/option.h" -#include "exec/address-spaces.h" #include "hw/intc/ppc-uic.h" #include "hw/ppc/ppc.h" diff --git a/hw/remote/machine.c b/hw/remote/machine.c index c0ab4f528a..952105eab5 100644 --- a/hw/remote/machine.c +++ b/hw/remote/machine.c @@ -17,7 +17,6 @@ #include "qemu-common.h" #include "hw/remote/machine.h" -#include "exec/address-spaces.h" #include "exec/memory.h" #include "qapi/error.h" #include "hw/pci/pci_host.h" diff --git a/hw/remote/memory.c b/hw/remote/memory.c index 32085b1e05..2d4174614a 100644 --- a/hw/remote/memory.c +++ b/hw/remote/memory.c @@ -12,7 +12,6 @@ #include "qemu-common.h" #include "hw/remote/memory.h" -#include "exec/address-spaces.h" #include "exec/ram_addr.h" #include "qapi/error.h" diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c index 3649919f66..901dbf1357 100644 --- a/hw/remote/proxy-memory-listener.c +++ b/hw/remote/proxy-memory-listener.c @@ -15,7 +15,6 @@ #include "exec/memory.h" #include "exec/cpu-common.h" #include "exec/ram_addr.h" -#include "exec/address-spaces.h" #include "qapi/error.h" #include "hw/remote/mpqemu-link.h" #include "hw/remote/proxy-memory-listener.h" diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index e168bffe69..dc9dea117e 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -24,7 +24,6 @@ #include "hw/boards.h" #include "hw/misc/unimp.h" #include "hw/riscv/boot.h" -#include "exec/address-spaces.h" #include "qemu/units.h" #include "sysemu/sysemu.h" diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 97e8b0b0a2..3e8b44b2c0 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -47,7 +47,6 @@ #include "chardev/char.h" #include "sysemu/arch_init.h" #include "sysemu/sysemu.h" -#include "exec/address-spaces.h" static MemMapEntry sifive_e_memmap[] = { [SIFIVE_E_DEV_DEBUG] = { 0x0, 0x1000 }, diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c index d54929e861..690f4e071a 100644 --- a/hw/rtc/m48t59.c +++ b/hw/rtc/m48t59.c @@ -32,7 +32,6 @@ #include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "hw/sysbus.h" -#include "exec/address-spaces.h" #include "qapi/error.h" #include "qemu/bcd.h" #include "qemu/module.h" diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 5d0fcacd0c..36a2dbf62f 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -42,7 +42,6 @@ #include "qapi/error.h" #include "qapi/qapi-events-misc-target.h" #include "qapi/visitor.h" -#include "exec/address-spaces.h" #include "hw/rtc/mc146818rtc_regs.h" #ifdef TARGET_I386 diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index f2f38c0c64..7af27ca305 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/address-spaces.h" #include "exec/ram_addr.h" #include "hw/s390x/s390-virtio-hcall.h" #include "hw/s390x/sclp.h" diff --git a/hw/sh4/r2d.c b/hw/sh4/r2d.c index 443820901d..006010f30a 100644 --- a/hw/sh4/r2d.c +++ b/hw/sh4/r2d.c @@ -42,7 +42,6 @@ #include "hw/loader.h" #include "hw/usb.h" #include "hw/block/flash.h" -#include "exec/address-spaces.h" #define FLASH_BASE 0x00000000 #define FLASH_SIZE (16 * MiB) diff --git a/hw/sh4/shix.c b/hw/sh4/shix.c index 1a44378df4..b0579aa0f1 100644 --- a/hw/sh4/shix.c +++ b/hw/sh4/shix.c @@ -34,7 +34,6 @@ #include "sysemu/qtest.h" #include "hw/boards.h" #include "hw/loader.h" -#include "exec/address-spaces.h" #include "qemu/error-report.h" #define BIOS_FILENAME "shix_bios.bin" diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index 7e16eea9e6..eb5d2a6792 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -40,7 +40,6 @@ #include "hw/loader.h" #include "elf.h" #include "trace.h" -#include "exec/address-spaces.h" #include "hw/sparc/grlib.h" #include "hw/misc/grlib_ahb_apb_pnp.h" diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c index a87d55f6bb..f3e42d0326 100644 --- a/hw/sparc64/niagara.c +++ b/hw/sparc64/niagara.c @@ -31,7 +31,6 @@ #include "hw/loader.h" #include "hw/sparc/sparc64.h" #include "hw/rtc/sun4v-rtc.h" -#include "exec/address-spaces.h" #include "sysemu/block-backend.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 16addee4dc..72cb2175c5 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -29,7 +29,6 @@ #include "qemu/module.h" #include "qemu/error-report.h" #include "qapi/error.h" -#include "exec/address-spaces.h" #include "qemu/units.h" #include "trace.h" diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index aa9c00aad3..58ebd1469c 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -18,7 +18,6 @@ #include "qemu/module.h" #include "qapi/error.h" -#include "exec/address-spaces.h" #include "hw/qdev-properties.h" #include "hw/pci/pci_ids.h" #include "hw/acpi/tpm.h" diff --git a/hw/tricore/tc27x_soc.c b/hw/tricore/tc27x_soc.c index d66d6980c3..ecd92717b5 100644 --- a/hw/tricore/tc27x_soc.c +++ b/hw/tricore/tc27x_soc.c @@ -24,7 +24,6 @@ #include "hw/loader.h" #include "qemu/units.h" #include "hw/misc/unimp.h" -#include "exec/address-spaces.h" #include "hw/tricore/tc27x_soc.h" #include "hw/tricore/triboard.h" diff --git a/hw/tricore/triboard.c b/hw/tricore/triboard.c index 943f706989..4dba0259cd 100644 --- a/hw/tricore/triboard.c +++ b/hw/tricore/triboard.c @@ -24,7 +24,6 @@ #include "hw/qdev-properties.h" #include "net/net.h" #include "hw/loader.h" -#include "exec/address-spaces.h" #include "elf.h" #include "hw/tricore/tricore.h" #include "qemu/error-report.h" diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c index 12ea1490fd..51658d9e37 100644 --- a/hw/tricore/tricore_testboard.c +++ b/hw/tricore/tricore_testboard.c @@ -25,7 +25,6 @@ #include "net/net.h" #include "hw/boards.h" #include "hw/loader.h" -#include "exec/address-spaces.h" #include "elf.h" #include "hw/tricore/tricore.h" #include "qemu/error-report.h" diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index e2163a0d63..7b7bde7657 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -21,7 +21,6 @@ #include "qemu/error-report.h" #include "qemu/memfd.h" #include "standard-headers/linux/vhost_types.h" -#include "exec/address-spaces.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" #include "migration/blocker.h" diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 07f4e60b30..9e13cb9e3a 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -15,7 +15,6 @@ #include "qapi/error.h" #include "cpu.h" #include "trace.h" -#include "exec/address-spaces.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/main-loop.h" diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index a513fdd62d..232482d65f 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -64,7 +64,6 @@ #include "hw/xen/xen-legacy-backend.h" #include "xen_pt.h" #include "qemu/range.h" -#include "exec/address-spaces.h" static bool has_igd_gfx_passthru; diff --git a/hw/xtensa/sim.c b/hw/xtensa/sim.c index c38e522b02..2028fe793d 100644 --- a/hw/xtensa/sim.c +++ b/hw/xtensa/sim.c @@ -33,7 +33,6 @@ #include "hw/loader.h" #include "elf.h" #include "exec/memory.h" -#include "exec/address-spaces.h" #include "qemu/error-report.h" #include "xtensa_memory.h" #include "xtensa_sim.h" diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c index 18d3c3cdb2..a18e3fc910 100644 --- a/hw/xtensa/virt.c +++ b/hw/xtensa/virt.c @@ -34,7 +34,6 @@ #include "net/net.h" #include "elf.h" #include "exec/memory.h" -#include "exec/address-spaces.h" #include "qemu/error-report.h" #include "xtensa_memory.h" #include "xtensa_sim.h" diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index 7be53f1895..17f087b395 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -35,7 +35,6 @@ #include "hw/qdev-properties.h" #include "elf.h" #include "exec/memory.h" -#include "exec/address-spaces.h" #include "hw/char/serial.h" #include "net/net.h" #include "hw/sysbus.h" diff --git a/softmmu/memory.c b/softmmu/memory.c index a62816647b..3bb533c0bc 100644 --- a/softmmu/memory.c +++ b/softmmu/memory.c @@ -17,7 +17,6 @@ #include "qemu/log.h" #include "qapi/error.h" #include "exec/memory.h" -#include "exec/address-spaces.h" #include "qapi/visitor.h" #include "qemu/bitops.h" #include "qemu/error-report.h" diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 1821882614..5232696571 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -46,7 +46,6 @@ #include "sysemu/dma.h" #include "sysemu/hostmem.h" #include "sysemu/hw_accel.h" -#include "exec/address-spaces.h" #include "sysemu/xen-mapcache.h" #include "trace/trace-root.h" diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 15f14ac69e..f044181d06 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -67,7 +67,6 @@ #include #include -#include "exec/address-spaces.h" #include "hw/i386/apic_internal.h" #include "qemu/main-loop.h" #include "qemu/accel.h" diff --git a/target/i386/hvf/x86_mmu.c b/target/i386/hvf/x86_mmu.c index 882a6237ee..78fff04684 100644 --- a/target/i386/hvf/x86_mmu.c +++ b/target/i386/hvf/x86_mmu.c @@ -24,7 +24,6 @@ #include "x86_mmu.h" #include "vmcs.h" #include "vmx.h" -#include "exec/address-spaces.h" #define pte_present(pte) (pte & PT_PRESENT) #define pte_write_access(pte) (pte & PT_WRITE) diff --git a/target/i386/sev.c b/target/i386/sev.c index 72b9e2ab40..9a43be11cb 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -30,7 +30,6 @@ #include "trace.h" #include "migration/blocker.h" #include "qom/object.h" -#include "exec/address-spaces.h" #include "monitor/monitor.h" #include "exec/confidential-guest-support.h" #include "hw/i386/pc.h" diff --git a/target/s390x/diag.c b/target/s390x/diag.c index 1a48429564..d620cd4bd4 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -15,7 +15,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "internal.h" -#include "exec/address-spaces.h" #include "hw/watchdog/wdt_diag288.h" #include "sysemu/cpus.h" #include "hw/s390x/ipl.h" diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index 143476849f..d85d3516d6 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -32,7 +32,6 @@ #include "qemu/host-utils.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" -#include "exec/address-spaces.h" #include "qemu/timer.h" #ifndef CONFIG_USER_ONLY diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c index ae219540b4..cea7d4058e 100644 --- a/tests/qtest/fuzz/generic_fuzz.c +++ b/tests/qtest/fuzz/generic_fuzz.c @@ -19,11 +19,9 @@ #include "tests/qtest/libqos/pci-pc.h" #include "fuzz.h" #include "fork_fuzz.h" -#include "exec/address-spaces.h" #include "string.h" #include "exec/memory.h" #include "exec/ramblock.h" -#include "exec/address-spaces.h" #include "hw/qdev-core.h" #include "hw/pci/pci.h" #include "hw/boards.h" diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c index 2bc474645c..7a244c951e 100644 --- a/tests/qtest/fuzz/qos_fuzz.c +++ b/tests/qtest/fuzz/qos_fuzz.c @@ -21,7 +21,6 @@ #include "qapi/error.h" #include "qemu-common.h" #include "exec/memory.h" -#include "exec/address-spaces.h" #include "qemu/main-loop.h" #include "tests/qtest/libqos/libqtest.h" From 76d79cf3d5a1bb83c954db259d0ed6add1d38e43 Mon Sep 17 00:00:00 2001 From: Gan Qixin Date: Mon, 30 Nov 2020 16:36:23 +0800 Subject: [PATCH 0227/3028] mc146818rtc: put it into the 'misc' category The category of the mc146818rtc device is not set, put it into the 'misc' category. Signed-off-by: Gan Qixin Reviewed-by: Thomas Huth Message-Id: <20201130083630.2520597-6-ganqixin@huawei.com> Signed-off-by: Laurent Vivier --- hw/rtc/mc146818rtc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 36a2dbf62f..3d2d3854e7 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -1039,6 +1039,7 @@ static void rtc_class_initfn(ObjectClass *klass, void *data) dc->vmsd = &vmstate_rtc; isa->build_aml = rtc_build_aml; device_class_set_props(dc, mc146818rtc_properties); + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo mc146818rtc_info = { From a058b895079348d0854a027a42ce3396a4a00bb7 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 22 Feb 2021 12:28:08 +0100 Subject: [PATCH 0228/3028] docs/system: Document the removal of "compat" property for POWER CPUs This is just an oversight. Fixes: f518be3aa35b ("target/ppc: Remove "compat" property of server class POWER CPUs") Cc: groug@kaod.org Signed-off-by: Greg Kurz Reviewed-by: Laurent Vivier Message-Id: <161399328834.51902.14269239378658110394.stgit@bahia.lan> Signed-off-by: Laurent Vivier --- docs/system/removed-features.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst index 29e90601a5..c21e6fa5ee 100644 --- a/docs/system/removed-features.rst +++ b/docs/system/removed-features.rst @@ -285,6 +285,12 @@ The RISC-V no MMU cpus have been removed. The two CPUs: ``rv32imacu-nommu`` and ``rv64imacu-nommu`` can no longer be used. Instead the MMU status can be specified via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs. +``compat`` property of server class POWER CPUs (removed in 6.0) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``max-cpu-compat`` property of the ``pseries`` machine type should be used +instead. + System emulator machines ------------------------ From e75941331e4cdc05878119e08635ace437aae721 Mon Sep 17 00:00:00 2001 From: Silvano Cirujano Cuesta Date: Tue, 23 Mar 2021 13:34:57 +0100 Subject: [PATCH 0229/3028] scripts: fix generation update-binfmts templates This patch fixes the update-binfmts templates being used in the script scripts/qemu-binfmt-conf.sh when the option --debian is used. Fixed issues are: - Typo in flag 'credentials' (previously 'credential'). - Missing flags 'preserve' and 'fix_binary'. Reference: https://manpages.debian.org/buster/binfmt-support/update-binfmts.8.en.html#FORMAT_FILES Signed-off-by: Silvano Cirujano Cuesta Reviewed-by: Laurent Vivier Message-Id: <20210323123457.23747-1-silvano.cirujano-cuesta@siemens.com> Signed-off-by: Laurent Vivier --- scripts/qemu-binfmt-conf.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 573b5dc6ac..7de996d536 100755 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -294,7 +294,9 @@ package qemu-$cpu interpreter $qemu magic $magic mask $mask -credential $CREDENTIAL +credentials $CREDENTIAL +preserve $PRESERVE_ARG0 +fix_binary $PERSISTENT EOF } From 56c9f00ef96844d3c77bc14e06ad894ed5d07441 Mon Sep 17 00:00:00 2001 From: Robert Hoo Date: Thu, 22 Apr 2021 16:42:02 +0800 Subject: [PATCH 0230/3028] docs: More precisely describe memory-backend-*::id's user 'id' of memory-backend-{file,ram} is not only for '-numa''s reference, but also other parameters like '-device nvdimm'. More clearly call out this to avoid misinterpretation. Signed-off-by: Robert Hoo Reviewed-by: Markus Armbruster Message-Id: <1619080922-83527-1-git-send-email-robert.hu@linux.intel.com> Signed-off-by: Laurent Vivier --- qemu-options.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index fd21002bd6..635dc8a624 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4508,11 +4508,11 @@ SRST the guest RAM with huge pages. The ``id`` parameter is a unique ID that will be used to - reference this memory region when configuring the ``-numa`` - argument. + reference this memory region in other parameters, e.g. ``-numa``, + ``-device nvdimm``, etc. The ``size`` option provides the size of the memory region, and - accepts common suffixes, eg ``500M``. + accepts common suffixes, e.g. ``500M``. The ``mem-path`` provides the path to either a shared memory or huge page filesystem mount. From 9197b5d4b5f163455c891baec531ae73f5d3a73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Apr 2021 00:30:56 +0200 Subject: [PATCH 0231/3028] hw/rx/rx-gdbsim: Do not accept invalid memory size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We check the amount of RAM is enough, warn when it is not, but if so we neglect to bail out. Fix that by adding the missing exit() call. Fixes: bda19d7bb56 ("hw/rx: Add RX GDB simulator") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Yoshinori Sato Message-Id: <20210407223056.1870497-1-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/rx/rx-gdbsim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c index b52d76b9b6..75d1fec6ca 100644 --- a/hw/rx/rx-gdbsim.c +++ b/hw/rx/rx-gdbsim.c @@ -89,6 +89,7 @@ static void rx_gdbsim_init(MachineState *machine) char *sz = size_to_str(mc->default_ram_size); error_report("Invalid RAM size, should be more than %s", sz); g_free(sz); + exit(1); } /* Allocate memory space */ From 03b3542ac93cb196bf6a6d85e92fa68a894f5256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 6 Apr 2021 10:48:42 +0200 Subject: [PATCH 0232/3028] hw/ppc/mac_newworld: Restrict RAM to 2 GiB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Mac99 and newer machines, the Uninorth PCI host bridge maps the PCI hole region at 2GiB, so the RAM area beside 2GiB is not accessible by the CPU. Restrict the memory to 2GiB to avoid problems such the one reported in the buglink. Buglink: https://bugs.launchpad.net/qemu/+bug/1922391 Reported-by: Håvard Eidnes Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210406084842.2859664-1-f4bug@amsat.org> Reviewed-by: BALATON Zoltan Signed-off-by: David Gibson --- hw/ppc/mac_newworld.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 2175962846..d88b38e925 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -157,6 +157,10 @@ static void ppc_core99_init(MachineState *machine) } /* allocate RAM */ + if (machine->ram_size > 2 * GiB) { + error_report("RAM size more than 2 GiB is not supported"); + exit(1); + } memory_region_add_subregion(get_system_memory(), 0, machine->ram); /* allocate and load firmware ROM */ From 8a05fd9a22aa16d8a076a5dc9af2b5ed3658243c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 15 Mar 2021 12:45:59 -0600 Subject: [PATCH 0233/3028] target/ppc: Move helper_regs.h functions out-of-line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the functions to a new file, helper_regs.c. Note int_helper.c was relying on helper_regs.h to indirectly include qemu/log.h. Signed-off-by: Richard Henderson Message-Id: <20210315184615.1985590-2-richard.henderson@linaro.org> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/helper_regs.c | 197 +++++++++++++++++++++++++++++++++++++++ target/ppc/helper_regs.h | 184 ++---------------------------------- target/ppc/int_helper.c | 1 + target/ppc/meson.build | 1 + 4 files changed, 207 insertions(+), 176 deletions(-) create mode 100644 target/ppc/helper_regs.c diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c new file mode 100644 index 0000000000..5e18232b84 --- /dev/null +++ b/target/ppc/helper_regs.c @@ -0,0 +1,197 @@ +/* + * PowerPC emulation special registers manipulation helpers for qemu. + * + * Copyright (c) 2003-2007 Jocelyn Mayer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "exec/exec-all.h" +#include "sysemu/kvm.h" +#include "helper_regs.h" + +/* Swap temporary saved registers with GPRs */ +void hreg_swap_gpr_tgpr(CPUPPCState *env) +{ + target_ulong tmp; + + tmp = env->gpr[0]; + env->gpr[0] = env->tgpr[0]; + env->tgpr[0] = tmp; + tmp = env->gpr[1]; + env->gpr[1] = env->tgpr[1]; + env->tgpr[1] = tmp; + tmp = env->gpr[2]; + env->gpr[2] = env->tgpr[2]; + env->tgpr[2] = tmp; + tmp = env->gpr[3]; + env->gpr[3] = env->tgpr[3]; + env->tgpr[3] = tmp; +} + +void hreg_compute_mem_idx(CPUPPCState *env) +{ + /* + * This is our encoding for server processors. The architecture + * specifies that there is no such thing as userspace with + * translation off, however it appears that MacOS does it and some + * 32-bit CPUs support it. Weird... + * + * 0 = Guest User space virtual mode + * 1 = Guest Kernel space virtual mode + * 2 = Guest User space real mode + * 3 = Guest Kernel space real mode + * 4 = HV User space virtual mode + * 5 = HV Kernel space virtual mode + * 6 = HV User space real mode + * 7 = HV Kernel space real mode + * + * For BookE, we need 8 MMU modes as follow: + * + * 0 = AS 0 HV User space + * 1 = AS 0 HV Kernel space + * 2 = AS 1 HV User space + * 3 = AS 1 HV Kernel space + * 4 = AS 0 Guest User space + * 5 = AS 0 Guest Kernel space + * 6 = AS 1 Guest User space + * 7 = AS 1 Guest Kernel space + */ + if (env->mmu_model & POWERPC_MMU_BOOKE) { + env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1; + env->immu_idx += msr_is ? 2 : 0; + env->dmmu_idx += msr_ds ? 2 : 0; + env->immu_idx += msr_gs ? 4 : 0; + env->dmmu_idx += msr_gs ? 4 : 0; + } else { + env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1; + env->immu_idx += msr_ir ? 0 : 2; + env->dmmu_idx += msr_dr ? 0 : 2; + env->immu_idx += msr_hv ? 4 : 0; + env->dmmu_idx += msr_hv ? 4 : 0; + } +} + +void hreg_compute_hflags(CPUPPCState *env) +{ + target_ulong hflags_mask; + + /* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */ + hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) | + (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | + (1 << MSR_LE) | (1 << MSR_VSX) | (1 << MSR_IR) | (1 << MSR_DR); + hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB; + hreg_compute_mem_idx(env); + env->hflags = env->msr & hflags_mask; + /* Merge with hflags coming from other registers */ + env->hflags |= env->hflags_nmsr; +} + +void cpu_interrupt_exittb(CPUState *cs) +{ + if (!kvm_enabled()) { + return; + } + + if (!qemu_mutex_iothread_locked()) { + qemu_mutex_lock_iothread(); + cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); + qemu_mutex_unlock_iothread(); + } else { + cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); + } +} + +int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) +{ + int excp; +#if !defined(CONFIG_USER_ONLY) + CPUState *cs = env_cpu(env); +#endif + + excp = 0; + value &= env->msr_mask; +#if !defined(CONFIG_USER_ONLY) + /* Neither mtmsr nor guest state can alter HV */ + if (!alter_hv || !(env->msr & MSR_HVB)) { + value &= ~MSR_HVB; + value |= env->msr & MSR_HVB; + } + if (((value >> MSR_IR) & 1) != msr_ir || + ((value >> MSR_DR) & 1) != msr_dr) { + cpu_interrupt_exittb(cs); + } + if ((env->mmu_model & POWERPC_MMU_BOOKE) && + ((value >> MSR_GS) & 1) != msr_gs) { + cpu_interrupt_exittb(cs); + } + if (unlikely((env->flags & POWERPC_FLAG_TGPR) && + ((value ^ env->msr) & (1 << MSR_TGPR)))) { + /* Swap temporary saved registers with GPRs */ + hreg_swap_gpr_tgpr(env); + } + if (unlikely((value >> MSR_EP) & 1) != msr_ep) { + /* Change the exception prefix on PowerPC 601 */ + env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; + } + /* + * If PR=1 then EE, IR and DR must be 1 + * + * Note: We only enforce this on 64-bit server processors. + * It appears that: + * - 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS + * exploits it. + * - 64-bit embedded implementations do not need any operation to be + * performed when PR is set. + */ + if (is_book3s_arch2x(env) && ((value >> MSR_PR) & 1)) { + value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR); + } +#endif + env->msr = value; + hreg_compute_hflags(env); +#if !defined(CONFIG_USER_ONLY) + if (unlikely(msr_pow == 1)) { + if (!env->pending_interrupts && (*env->check_pow)(env)) { + cs->halted = 1; + excp = EXCP_HALTED; + } + } +#endif + + return excp; +} + +#ifndef CONFIG_USER_ONLY +void check_tlb_flush(CPUPPCState *env, bool global) +{ + CPUState *cs = env_cpu(env); + + /* Handle global flushes first */ + if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { + env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; + env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; + tlb_flush_all_cpus_synced(cs); + return; + } + + /* Then handle local ones */ + if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { + env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; + tlb_flush(cs); + } +} +#endif diff --git a/target/ppc/helper_regs.h b/target/ppc/helper_regs.h index efcc903427..4148a442b3 100644 --- a/target/ppc/helper_regs.h +++ b/target/ppc/helper_regs.h @@ -20,184 +20,16 @@ #ifndef HELPER_REGS_H #define HELPER_REGS_H -#include "qemu/main-loop.h" -#include "exec/exec-all.h" -#include "sysemu/kvm.h" +void hreg_swap_gpr_tgpr(CPUPPCState *env); +void hreg_compute_mem_idx(CPUPPCState *env); +void hreg_compute_hflags(CPUPPCState *env); +void cpu_interrupt_exittb(CPUState *cs); +int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv); -/* Swap temporary saved registers with GPRs */ -static inline void hreg_swap_gpr_tgpr(CPUPPCState *env) -{ - target_ulong tmp; - - tmp = env->gpr[0]; - env->gpr[0] = env->tgpr[0]; - env->tgpr[0] = tmp; - tmp = env->gpr[1]; - env->gpr[1] = env->tgpr[1]; - env->tgpr[1] = tmp; - tmp = env->gpr[2]; - env->gpr[2] = env->tgpr[2]; - env->tgpr[2] = tmp; - tmp = env->gpr[3]; - env->gpr[3] = env->tgpr[3]; - env->tgpr[3] = tmp; -} - -static inline void hreg_compute_mem_idx(CPUPPCState *env) -{ - /* - * This is our encoding for server processors. The architecture - * specifies that there is no such thing as userspace with - * translation off, however it appears that MacOS does it and some - * 32-bit CPUs support it. Weird... - * - * 0 = Guest User space virtual mode - * 1 = Guest Kernel space virtual mode - * 2 = Guest User space real mode - * 3 = Guest Kernel space real mode - * 4 = HV User space virtual mode - * 5 = HV Kernel space virtual mode - * 6 = HV User space real mode - * 7 = HV Kernel space real mode - * - * For BookE, we need 8 MMU modes as follow: - * - * 0 = AS 0 HV User space - * 1 = AS 0 HV Kernel space - * 2 = AS 1 HV User space - * 3 = AS 1 HV Kernel space - * 4 = AS 0 Guest User space - * 5 = AS 0 Guest Kernel space - * 6 = AS 1 Guest User space - * 7 = AS 1 Guest Kernel space - */ - if (env->mmu_model & POWERPC_MMU_BOOKE) { - env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1; - env->immu_idx += msr_is ? 2 : 0; - env->dmmu_idx += msr_ds ? 2 : 0; - env->immu_idx += msr_gs ? 4 : 0; - env->dmmu_idx += msr_gs ? 4 : 0; - } else { - env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1; - env->immu_idx += msr_ir ? 0 : 2; - env->dmmu_idx += msr_dr ? 0 : 2; - env->immu_idx += msr_hv ? 4 : 0; - env->dmmu_idx += msr_hv ? 4 : 0; - } -} - -static inline void hreg_compute_hflags(CPUPPCState *env) -{ - target_ulong hflags_mask; - - /* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */ - hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) | - (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | - (1 << MSR_LE) | (1 << MSR_VSX) | (1 << MSR_IR) | (1 << MSR_DR); - hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB; - hreg_compute_mem_idx(env); - env->hflags = env->msr & hflags_mask; - /* Merge with hflags coming from other registers */ - env->hflags |= env->hflags_nmsr; -} - -static inline void cpu_interrupt_exittb(CPUState *cs) -{ - if (!kvm_enabled()) { - return; - } - - if (!qemu_mutex_iothread_locked()) { - qemu_mutex_lock_iothread(); - cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); - qemu_mutex_unlock_iothread(); - } else { - cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); - } -} - -static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, - int alter_hv) -{ - int excp; -#if !defined(CONFIG_USER_ONLY) - CPUState *cs = env_cpu(env); -#endif - - excp = 0; - value &= env->msr_mask; -#if !defined(CONFIG_USER_ONLY) - /* Neither mtmsr nor guest state can alter HV */ - if (!alter_hv || !(env->msr & MSR_HVB)) { - value &= ~MSR_HVB; - value |= env->msr & MSR_HVB; - } - if (((value >> MSR_IR) & 1) != msr_ir || - ((value >> MSR_DR) & 1) != msr_dr) { - cpu_interrupt_exittb(cs); - } - if ((env->mmu_model & POWERPC_MMU_BOOKE) && - ((value >> MSR_GS) & 1) != msr_gs) { - cpu_interrupt_exittb(cs); - } - if (unlikely((env->flags & POWERPC_FLAG_TGPR) && - ((value ^ env->msr) & (1 << MSR_TGPR)))) { - /* Swap temporary saved registers with GPRs */ - hreg_swap_gpr_tgpr(env); - } - if (unlikely((value >> MSR_EP) & 1) != msr_ep) { - /* Change the exception prefix on PowerPC 601 */ - env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; - } - /* - * If PR=1 then EE, IR and DR must be 1 - * - * Note: We only enforce this on 64-bit server processors. - * It appears that: - * - 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS - * exploits it. - * - 64-bit embedded implementations do not need any operation to be - * performed when PR is set. - */ - if (is_book3s_arch2x(env) && ((value >> MSR_PR) & 1)) { - value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR); - } -#endif - env->msr = value; - hreg_compute_hflags(env); -#if !defined(CONFIG_USER_ONLY) - if (unlikely(msr_pow == 1)) { - if (!env->pending_interrupts && (*env->check_pow)(env)) { - cs->halted = 1; - excp = EXCP_HALTED; - } - } -#endif - - return excp; -} - -#if !defined(CONFIG_USER_ONLY) -static inline void check_tlb_flush(CPUPPCState *env, bool global) -{ - CPUState *cs = env_cpu(env); - - /* Handle global flushes first */ - if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { - env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; - env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; - tlb_flush_all_cpus_synced(cs); - return; - } - - /* Then handle local ones */ - if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { - env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; - tlb_flush(cs); - } -} -#else +#ifdef CONFIG_USER_ONLY static inline void check_tlb_flush(CPUPPCState *env, bool global) { } +#else +void check_tlb_flush(CPUPPCState *env, bool global); #endif #endif /* HELPER_REGS_H */ diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 429de28494..a44c2d90ea 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -22,6 +22,7 @@ #include "internal.h" #include "qemu/host-utils.h" #include "qemu/main-loop.h" +#include "qemu/log.h" #include "exec/helper-proto.h" #include "crypto/aes.h" #include "fpu/softfloat.h" diff --git a/target/ppc/meson.build b/target/ppc/meson.build index bbfef90e08..4079d01ee3 100644 --- a/target/ppc/meson.build +++ b/target/ppc/meson.build @@ -6,6 +6,7 @@ ppc_ss.add(files( 'excp_helper.c', 'fpu_helper.c', 'gdbstub.c', + 'helper_regs.c', 'int_helper.c', 'mem_helper.c', 'misc_helper.c', From 1828504672cece95f7b38e9e63eb2dfeeb447830 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 15 Mar 2021 12:46:00 -0600 Subject: [PATCH 0234/3028] target/ppc: Move 601 hflags adjustment to hreg_compute_hflags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep all hflags computation in one place, as this will be especially important later. Introduce a new POWERPC_FLAG_HID0_LE bit to indicate when LE should be taken from HID0. This appears to be set if and only if POWERPC_FLAG_RTC_CLK is set, but we're not short of bits and having both names will avoid confusion. Note that this was the only user of hflags_nmsr, so we can perform a straight assignment rather than mask and set. Signed-off-by: Richard Henderson Message-Id: <20210315184615.1985590-3-richard.henderson@linaro.org> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/cpu.h | 2 ++ target/ppc/helper_regs.c | 13 +++++++++++-- target/ppc/misc_helper.c | 8 +++----- target/ppc/translate_init.c.inc | 4 ++-- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index e73416da68..061d2eed1b 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -581,6 +581,8 @@ enum { POWERPC_FLAG_TM = 0x00100000, /* Has SCV (ISA 3.00) */ POWERPC_FLAG_SCV = 0x00200000, + /* Has HID0 for LE bit (601) */ + POWERPC_FLAG_HID0_LE = 0x00400000, }; /*****************************************************************************/ diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 5e18232b84..95b9aca61f 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -96,8 +96,17 @@ void hreg_compute_hflags(CPUPPCState *env) hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB; hreg_compute_mem_idx(env); env->hflags = env->msr & hflags_mask; - /* Merge with hflags coming from other registers */ - env->hflags |= env->hflags_nmsr; + + if (env->flags & POWERPC_FLAG_HID0_LE) { + /* + * Note that MSR_LE is not set in env->msr_mask for this cpu, + * and so will never be set in msr or hflags at this point. + */ + uint32_t le = extract32(env->spr[SPR_HID0], 3, 1); + env->hflags |= le << MSR_LE; + /* Retain for backward compatibility with migration. */ + env->hflags_nmsr = le << MSR_LE; + } } void cpu_interrupt_exittb(CPUState *cs) diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 5d6e0de396..63e3147eb4 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -194,16 +194,14 @@ void helper_store_hid0_601(CPUPPCState *env, target_ulong val) target_ulong hid0; hid0 = env->spr[SPR_HID0]; + env->spr[SPR_HID0] = (uint32_t)val; + if ((val ^ hid0) & 0x00000008) { /* Change current endianness */ - env->hflags &= ~(1 << MSR_LE); - env->hflags_nmsr &= ~(1 << MSR_LE); - env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE); - env->hflags |= env->hflags_nmsr; + hreg_compute_hflags(env); qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__, val & 0x8 ? 'l' : 'b', env->hflags); } - env->spr[SPR_HID0] = (uint32_t)val; } void helper_store_403_pbr(CPUPPCState *env, uint32_t num, target_ulong value) diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index c03a7c4f52..049d76cfd1 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -5441,7 +5441,7 @@ POWERPC_FAMILY(601)(ObjectClass *oc, void *data) pcc->excp_model = POWERPC_EXCP_601; pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_601; - pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE; } #define POWERPC_MSRR_601v (0x0000000000001040ULL) @@ -5485,7 +5485,7 @@ POWERPC_FAMILY(601v)(ObjectClass *oc, void *data) #endif pcc->bus_model = PPC_FLAGS_INPUT_6xx; pcc->bfd_mach = bfd_mach_ppc_601; - pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK; + pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE; } static void init_proc_602(CPUPPCState *env) From dafe299cf0249d2a83fd2d9262796a90c50fc1d3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 15 Mar 2021 12:46:01 -0600 Subject: [PATCH 0235/3028] target/ppc: Properly sync cpu state with new msr in cpu_load_old MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Match cpu_post_load in using ppc_store_msr to set all of the cpu state implied by the value of msr. Do not restore hflags or hflags_nmsr, as we recompute them in ppc_store_msr. Signed-off-by: Richard Henderson Message-Id: <20210315184615.1985590-4-richard.henderson@linaro.org> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/machine.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target/ppc/machine.c b/target/ppc/machine.c index 283db1d28a..87d7bffb86 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -21,6 +21,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) int32_t slb_nr; #endif target_ulong xer; + target_ulong msr; for (i = 0; i < 32; i++) { qemu_get_betls(f, &env->gpr[i]); @@ -111,11 +112,19 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) qemu_get_betls(f, &env->ivpr_mask); qemu_get_betls(f, &env->hreset_vector); qemu_get_betls(f, &env->nip); - qemu_get_betls(f, &env->hflags); - qemu_get_betls(f, &env->hflags_nmsr); + qemu_get_sbetl(f); /* Discard unused hflags */ + qemu_get_sbetl(f); /* Discard unused hflags_nmsr */ qemu_get_sbe32(f); /* Discard unused mmu_idx */ qemu_get_sbe32(f); /* Discard unused power_mode */ + /* + * Invalidate all supported msr bits except MSR_TGPR/MSR_HVB + * before restoring. Note that this recomputes hflags and mem_idx. + */ + msr = env->msr; + env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB); + ppc_store_msr(env, msr); + /* Recompute mmu indices */ hreg_compute_mem_idx(env); From da77d2b03708c4b2a8cd32f689a6d65af243952d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 15 Mar 2021 12:46:02 -0600 Subject: [PATCH 0236/3028] target/ppc: Do not call hreg_compute_mem_idx after ppc_store_msr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In ppc_store_msr we call hreg_compute_hflags, which itself calls hreg_compute_mem_idx. Rely on ppc_store_msr to update everything required by the msr update. Signed-off-by: Richard Henderson Message-Id: <20210315184615.1985590-5-richard.henderson@linaro.org> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/machine.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/target/ppc/machine.c b/target/ppc/machine.c index 87d7bffb86..f6eeda9642 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -125,9 +125,6 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB); ppc_store_msr(env, msr); - /* Recompute mmu indices */ - hreg_compute_mem_idx(env); - return 0; } @@ -418,14 +415,12 @@ static int cpu_post_load(void *opaque, int version_id) /* * Invalidate all supported msr bits except MSR_TGPR/MSR_HVB - * before restoring + * before restoring. Note that this recomputes hflags and mem_idx. */ msr = env->msr; env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB); ppc_store_msr(env, msr); - hreg_compute_mem_idx(env); - return 0; } From f7a7b6525c5b5f06553582d8617052bf43678984 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 15 Mar 2021 12:46:03 -0600 Subject: [PATCH 0237/3028] target/ppc: Retain hflags_nmsr only for migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have eliminated all normal uses of hflags_nmsr. We need not even compute it except when we want to migrate. Rename the field to emphasize this. Remove the fixme comment for migrating access_type. This value is only ever used with the current executing instruction, and is never live when the cpu is halted for migration. Signed-off-by: Richard Henderson Message-Id: <20210315184615.1985590-6-richard.henderson@linaro.org> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/cpu.h | 4 ++-- target/ppc/helper_regs.c | 2 -- target/ppc/machine.c | 9 ++++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 061d2eed1b..79c4033a42 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1105,8 +1105,8 @@ struct CPUPPCState { #endif /* These resources are used only in QEMU core */ - target_ulong hflags; /* hflags is MSR & HFLAGS_MASK */ - target_ulong hflags_nmsr; /* specific hflags, not coming from MSR */ + target_ulong hflags; + target_ulong hflags_compat_nmsr; /* for migration compatibility */ int immu_idx; /* precomputed MMU index to speed up insn accesses */ int dmmu_idx; /* precomputed MMU index to speed up data accesses */ diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 95b9aca61f..a87e354ca2 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -104,8 +104,6 @@ void hreg_compute_hflags(CPUPPCState *env) */ uint32_t le = extract32(env->spr[SPR_HID0], 3, 1); env->hflags |= le << MSR_LE; - /* Retain for backward compatibility with migration. */ - env->hflags_nmsr = le << MSR_LE; } } diff --git a/target/ppc/machine.c b/target/ppc/machine.c index f6eeda9642..1f7a353c78 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -310,6 +310,10 @@ static int cpu_pre_save(void *opaque) } } + /* Retain migration compatibility for pre 6.0 for 601 machines. */ + env->hflags_compat_nmsr = (env->flags & POWERPC_FLAG_HID0_LE + ? env->hflags & MSR_LE : 0); + return 0; } @@ -829,9 +833,8 @@ const VMStateDescription vmstate_ppc_cpu = { /* Supervisor mode architected state */ VMSTATE_UINTTL(env.msr, PowerPCCPU), - /* Internal state */ - VMSTATE_UINTTL(env.hflags_nmsr, PowerPCCPU), - /* FIXME: access_type? */ + /* Backward compatible internal state */ + VMSTATE_UINTTL(env.hflags_compat_nmsr, PowerPCCPU), /* Sanity checking */ VMSTATE_UINTTL_TEST(mig_msr_mask, PowerPCCPU, cpu_pre_2_8_migration), From 56ced49760df758650e852361b1b1a359ca6c904 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 15 Mar 2021 12:46:04 -0600 Subject: [PATCH 0238/3028] target/ppc: Fix comment for MSR_FE{0,1} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As per hreg_compute_hflags: We 'forget' FE0 & FE1: we'll never generate imprecise exceptions remove the hflags marker from the respective comments. Signed-off-by: Richard Henderson Message-Id: <20210315184615.1985590-7-richard.henderson@linaro.org> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/cpu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 79c4033a42..fd13489dce 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -322,13 +322,13 @@ typedef struct ppc_v3_pate_t { #define MSR_PR 14 /* Problem state hflags */ #define MSR_FP 13 /* Floating point available hflags */ #define MSR_ME 12 /* Machine check interrupt enable */ -#define MSR_FE0 11 /* Floating point exception mode 0 hflags */ +#define MSR_FE0 11 /* Floating point exception mode 0 */ #define MSR_SE 10 /* Single-step trace enable x hflags */ #define MSR_DWE 10 /* Debug wait enable on 405 x */ #define MSR_UBLE 10 /* User BTB lock enable on e500 x */ #define MSR_BE 9 /* Branch trace enable x hflags */ #define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC x */ -#define MSR_FE1 8 /* Floating point exception mode 1 hflags */ +#define MSR_FE1 8 /* Floating point exception mode 1 */ #define MSR_AL 7 /* AL bit on POWER */ #define MSR_EP 6 /* Exception prefix on 601 */ #define MSR_IR 5 /* Instruction relocate */ From bd4160bc6adc2fd5484a9c1cee6df65e6f2f4508 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 15 Mar 2021 12:46:12 -0600 Subject: [PATCH 0239/3028] hw/ppc/pnv_core: Update hflags after setting msr Signed-off-by: Richard Henderson Message-Id: <20210315184615.1985590-15-richard.henderson@linaro.org> Signed-off-by: David Gibson --- hw/ppc/pnv_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index bd2bf2e044..8c2a15a0fb 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -29,6 +29,7 @@ #include "hw/ppc/pnv_xscom.h" #include "hw/ppc/xics.h" #include "hw/qdev-properties.h" +#include "helper_regs.h" static const char *pnv_core_cpu_typename(PnvCore *pc) { @@ -55,8 +56,8 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu) env->gpr[3] = PNV_FDT_ADDR; env->nip = 0x10; env->msr |= MSR_HVB; /* Hypervisor mode */ - env->spr[SPR_HRMOR] = pc->hrmor; + hreg_compute_hflags(env); pcc->intc_reset(pc->chip, cpu); } From e81f17a3f616a4f2c803aafed60500ac45df9b3d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 15 Mar 2021 12:46:13 -0600 Subject: [PATCH 0240/3028] hw/ppc/spapr_rtas: Update hflags after setting msr Signed-off-by: Richard Henderson Message-Id: <20210315184615.1985590-16-richard.henderson@linaro.org> Signed-off-by: David Gibson --- hw/ppc/spapr_rtas.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 8a79f9c628..6ec3e71757 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -51,6 +51,7 @@ #include "target/ppc/mmu-hash64.h" #include "target/ppc/mmu-book3s-v3.h" #include "migration/blocker.h" +#include "helper_regs.h" static void rtas_display_character(PowerPCCPU *cpu, SpaprMachineState *spapr, uint32_t token, uint32_t nargs, @@ -163,6 +164,7 @@ static void rtas_start_cpu(PowerPCCPU *callcpu, SpaprMachineState *spapr, cpu_synchronize_state(CPU(newcpu)); env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); + hreg_compute_hflags(env); /* Enable Power-saving mode Exit Cause exceptions for the new CPU */ lpcr = env->spr[SPR_LPCR]; From edece45d4ac2a12a7183d8fb1ddd7f7984910ab8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 23 Mar 2021 12:43:31 -0600 Subject: [PATCH 0241/3028] target/ppc: Extract post_load_update_msr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract post_load_update_msr to share between cpu_load_old and cpu_post_load in updating the msr. Suggested-by: Cédric Le Goater Signed-off-by: Richard Henderson Message-Id: <20210323184340.619757-2-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/machine.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/target/ppc/machine.c b/target/ppc/machine.c index 1f7a353c78..09c5765a87 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -10,6 +10,18 @@ #include "kvm_ppc.h" #include "exec/helper-proto.h" +static void post_load_update_msr(CPUPPCState *env) +{ + target_ulong msr = env->msr; + + /* + * Invalidate all supported msr bits except MSR_TGPR/MSR_HVB + * before restoring. Note that this recomputes hflags and mem_idx. + */ + env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB); + ppc_store_msr(env, msr); +} + static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) { PowerPCCPU *cpu = opaque; @@ -21,7 +33,6 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) int32_t slb_nr; #endif target_ulong xer; - target_ulong msr; for (i = 0; i < 32; i++) { qemu_get_betls(f, &env->gpr[i]); @@ -117,13 +128,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) qemu_get_sbe32(f); /* Discard unused mmu_idx */ qemu_get_sbe32(f); /* Discard unused power_mode */ - /* - * Invalidate all supported msr bits except MSR_TGPR/MSR_HVB - * before restoring. Note that this recomputes hflags and mem_idx. - */ - msr = env->msr; - env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB); - ppc_store_msr(env, msr); + post_load_update_msr(env); return 0; } @@ -343,7 +348,6 @@ static int cpu_post_load(void *opaque, int version_id) PowerPCCPU *cpu = opaque; CPUPPCState *env = &cpu->env; int i; - target_ulong msr; /* * If we're operating in compat mode, we should be ok as long as @@ -417,13 +421,7 @@ static int cpu_post_load(void *opaque, int version_id) ppc_store_sdr1(env, env->spr[SPR_SDR1]); } - /* - * Invalidate all supported msr bits except MSR_TGPR/MSR_HVB - * before restoring. Note that this recomputes hflags and mem_idx. - */ - msr = env->msr; - env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB); - ppc_store_msr(env, msr); + post_load_update_msr(env); return 0; } From 2df4fe7abeed5be7c4350c12cfe33242261b28ef Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 23 Mar 2021 12:43:32 -0600 Subject: [PATCH 0242/3028] target/ppc: Disconnect hflags from MSR Copying flags directly from msr has drawbacks: (1) msr bits mean different things per cpu, (2) msr has 64 bits on 64 cpus while tb->flags has only 32 bits. Create a enum to define these bits. Document the origin of each bit and validate those bits that must match MSR. This fixes the truncation of env->hflags to tb->flags, because we no longer have hflags bits set above bit 31. Most of the code in ppc_tr_init_disas_context is moved over to hreg_compute_hflags. Some of it is simple extractions from msr, some requires examining other cpu flags. Anything that is moved becomes a simple extract from hflags in ppc_tr_init_disas_context. Several existing bugs are left in ppc_tr_init_disas_context, where additional changes are required -- to be addressed in future patches. Remove a broken #if 0 block. Reported-by: Ivan Warren Signed-off-by: Richard Henderson Message-Id: <20210323184340.619757-3-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/cpu.h | 25 ++++++++++++++++ target/ppc/helper_regs.c | 65 +++++++++++++++++++++++++++++++++------- target/ppc/translate.c | 55 ++++++++++------------------------ 3 files changed, 95 insertions(+), 50 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index fd13489dce..fe6c3f815d 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -585,6 +585,31 @@ enum { POWERPC_FLAG_HID0_LE = 0x00400000, }; +/* + * Bits for env->hflags. + * + * Most of these bits overlap with corresponding bits in MSR, + * but some come from other sources. Those that do come from + * the MSR are validated in hreg_compute_hflags. + */ +enum { + HFLAGS_LE = 0, /* MSR_LE -- comes from elsewhere on 601 */ + HFLAGS_HV = 1, /* computed from MSR_HV and other state */ + HFLAGS_64 = 2, /* computed from MSR_CE and MSR_SF */ + HFLAGS_DR = 4, /* MSR_DR */ + HFLAGS_IR = 5, /* MSR_IR */ + HFLAGS_SPE = 6, /* from MSR_SPE if cpu has SPE; avoid overlap w/ MSR_VR */ + HFLAGS_VSX = 7, /* from MSR_VSX if cpu has VSX; avoid overlap w/ MSR_AP */ + HFLAGS_TM = 8, /* computed from MSR_TM */ + HFLAGS_BE = 9, /* MSR_BE -- from elsewhere on embedded ppc */ + HFLAGS_SE = 10, /* MSR_SE -- from elsewhere on embedded ppc */ + HFLAGS_FP = 13, /* MSR_FP */ + HFLAGS_PR = 14, /* MSR_PR */ + HFLAGS_SA = 22, /* MSR_SA */ + HFLAGS_AP = 23, /* MSR_AP */ + HFLAGS_VR = 25, /* MSR_VR if cpu has VRE */ +}; + /*****************************************************************************/ /* Floating point status and control register */ #define FPSCR_DRN2 34 /* Decimal Floating-Point rounding control */ diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index a87e354ca2..df9673b90f 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "cpu.h" #include "qemu/main-loop.h" #include "exec/exec-all.h" #include "sysemu/kvm.h" @@ -87,24 +88,66 @@ void hreg_compute_mem_idx(CPUPPCState *env) void hreg_compute_hflags(CPUPPCState *env) { - target_ulong hflags_mask; + target_ulong msr = env->msr; + uint32_t ppc_flags = env->flags; + uint32_t hflags = 0; + uint32_t msr_mask; - /* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */ - hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) | - (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | - (1 << MSR_LE) | (1 << MSR_VSX) | (1 << MSR_IR) | (1 << MSR_DR); - hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB; - hreg_compute_mem_idx(env); - env->hflags = env->msr & hflags_mask; + /* Some bits come straight across from MSR. */ + QEMU_BUILD_BUG_ON(MSR_LE != HFLAGS_LE); + QEMU_BUILD_BUG_ON(MSR_PR != HFLAGS_PR); + QEMU_BUILD_BUG_ON(MSR_DR != HFLAGS_DR); + QEMU_BUILD_BUG_ON(MSR_IR != HFLAGS_IR); + QEMU_BUILD_BUG_ON(MSR_FP != HFLAGS_FP); + QEMU_BUILD_BUG_ON(MSR_SA != HFLAGS_SA); + QEMU_BUILD_BUG_ON(MSR_AP != HFLAGS_AP); + msr_mask = ((1 << MSR_LE) | (1 << MSR_PR) | + (1 << MSR_DR) | (1 << MSR_IR) | + (1 << MSR_FP) | (1 << MSR_SA) | (1 << MSR_AP)); - if (env->flags & POWERPC_FLAG_HID0_LE) { + if (ppc_flags & POWERPC_FLAG_HID0_LE) { /* * Note that MSR_LE is not set in env->msr_mask for this cpu, - * and so will never be set in msr or hflags at this point. + * and so will never be set in msr. */ uint32_t le = extract32(env->spr[SPR_HID0], 3, 1); - env->hflags |= le << MSR_LE; + hflags |= le << MSR_LE; } + + if (ppc_flags & POWERPC_FLAG_BE) { + QEMU_BUILD_BUG_ON(MSR_BE != HFLAGS_BE); + msr_mask |= 1 << MSR_BE; + } + if (ppc_flags & POWERPC_FLAG_SE) { + QEMU_BUILD_BUG_ON(MSR_SE != HFLAGS_SE); + msr_mask |= 1 << MSR_SE; + } + + if (msr_is_64bit(env, msr)) { + hflags |= 1 << HFLAGS_64; + } + if ((ppc_flags & POWERPC_FLAG_SPE) && (msr & (1 << MSR_SPE))) { + hflags |= 1 << HFLAGS_SPE; + } + if (ppc_flags & POWERPC_FLAG_VRE) { + QEMU_BUILD_BUG_ON(MSR_VR != HFLAGS_VR); + msr_mask |= 1 << MSR_VR; + } + if ((ppc_flags & POWERPC_FLAG_VSX) && (msr & (1 << MSR_VSX))) { + hflags |= 1 << HFLAGS_VSX; + } + if ((ppc_flags & POWERPC_FLAG_TM) && (msr & (1ull << MSR_TM))) { + hflags |= 1 << HFLAGS_TM; + } + +#ifndef CONFIG_USER_ONLY + if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) { + hflags |= 1 << HFLAGS_HV; + } +#endif + + env->hflags = hflags | (msr & msr_mask); + hreg_compute_mem_idx(env); } void cpu_interrupt_exittb(CPUState *cs) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 0984ce637b..a9325a12e5 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7879,67 +7879,48 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) { DisasContext *ctx = container_of(dcbase, DisasContext, base); CPUPPCState *env = cs->env_ptr; + uint32_t hflags = ctx->base.tb->flags; int bound; ctx->exception = POWERPC_EXCP_NONE; ctx->spr_cb = env->spr_cb; - ctx->pr = msr_pr; + ctx->pr = (hflags >> HFLAGS_PR) & 1; ctx->mem_idx = env->dmmu_idx; - ctx->dr = msr_dr; -#if !defined(CONFIG_USER_ONLY) - ctx->hv = msr_hv || !env->has_hv_mode; -#endif + ctx->dr = (hflags >> HFLAGS_DR) & 1; + ctx->hv = (hflags >> HFLAGS_HV) & 1; ctx->insns_flags = env->insns_flags; ctx->insns_flags2 = env->insns_flags2; ctx->access_type = -1; ctx->need_access_type = !mmu_is_64bit(env->mmu_model); - ctx->le_mode = !!(env->hflags & (1 << MSR_LE)); + ctx->le_mode = (hflags >> HFLAGS_LE) & 1; ctx->default_tcg_memop_mask = ctx->le_mode ? MO_LE : MO_BE; ctx->flags = env->flags; #if defined(TARGET_PPC64) - ctx->sf_mode = msr_is_64bit(env, env->msr); + ctx->sf_mode = (hflags >> HFLAGS_64) & 1; ctx->has_cfar = !!(env->flags & POWERPC_FLAG_CFAR); #endif ctx->lazy_tlb_flush = env->mmu_model == POWERPC_MMU_32B || env->mmu_model == POWERPC_MMU_601 || env->mmu_model & POWERPC_MMU_64; - ctx->fpu_enabled = !!msr_fp; - if ((env->flags & POWERPC_FLAG_SPE) && msr_spe) { - ctx->spe_enabled = !!msr_spe; - } else { - ctx->spe_enabled = false; - } - if ((env->flags & POWERPC_FLAG_VRE) && msr_vr) { - ctx->altivec_enabled = !!msr_vr; - } else { - ctx->altivec_enabled = false; - } - if ((env->flags & POWERPC_FLAG_VSX) && msr_vsx) { - ctx->vsx_enabled = !!msr_vsx; - } else { - ctx->vsx_enabled = false; - } + ctx->fpu_enabled = (hflags >> HFLAGS_FP) & 1; + ctx->spe_enabled = (hflags >> HFLAGS_SPE) & 1; + ctx->altivec_enabled = (hflags >> HFLAGS_VR) & 1; + ctx->vsx_enabled = (hflags >> HFLAGS_VSX) & 1; if ((env->flags & POWERPC_FLAG_SCV) && (env->spr[SPR_FSCR] & (1ull << FSCR_SCV))) { ctx->scv_enabled = true; } else { ctx->scv_enabled = false; } -#if defined(TARGET_PPC64) - if ((env->flags & POWERPC_FLAG_TM) && msr_tm) { - ctx->tm_enabled = !!msr_tm; - } else { - ctx->tm_enabled = false; - } -#endif + ctx->tm_enabled = (hflags >> HFLAGS_TM) & 1; ctx->gtse = !!(env->spr[SPR_LPCR] & LPCR_GTSE); - if ((env->flags & POWERPC_FLAG_SE) && msr_se) { - ctx->singlestep_enabled = CPU_SINGLE_STEP; - } else { - ctx->singlestep_enabled = 0; + + ctx->singlestep_enabled = 0; + if ((hflags >> HFLAGS_SE) & 1) { + ctx->singlestep_enabled |= CPU_SINGLE_STEP; } - if ((env->flags & POWERPC_FLAG_BE) && msr_be) { + if ((hflags >> HFLAGS_BE) & 1) { ctx->singlestep_enabled |= CPU_BRANCH_STEP; } if ((env->flags & POWERPC_FLAG_DE) && msr_de) { @@ -7956,10 +7937,6 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) if (unlikely(ctx->base.singlestep_enabled)) { ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP; } -#if defined(DO_SINGLE_STEP) && 0 - /* Single step trace mode */ - msr_se = 1; -#endif bound = -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; ctx->base.max_insns = MIN(ctx->base.max_insns, bound); From 26c55599b8c79887040c6910054a8c3f3f6f9147 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 23 Mar 2021 12:43:33 -0600 Subject: [PATCH 0243/3028] target/ppc: Reduce env->hflags to uint32_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will be stored in tb->flags, which is also uint32_t, so let's use the correct size. Reviewed-by: Cédric Le Goater Reviewed-by: David Gibson Signed-off-by: Richard Henderson Message-Id: <20210323184340.619757-4-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/cpu.h | 4 ++-- target/ppc/misc_helper.c | 2 +- target/ppc/translate.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index fe6c3f815d..d5f362506a 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1129,8 +1129,8 @@ struct CPUPPCState { bool resume_as_sreset; #endif - /* These resources are used only in QEMU core */ - target_ulong hflags; + /* These resources are used only in TCG */ + uint32_t hflags; target_ulong hflags_compat_nmsr; /* for migration compatibility */ int immu_idx; /* precomputed MMU index to speed up insn accesses */ int dmmu_idx; /* precomputed MMU index to speed up data accesses */ diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 63e3147eb4..b04b4d7c6e 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -199,7 +199,7 @@ void helper_store_hid0_601(CPUPPCState *env, target_ulong val) if ((val ^ hid0) & 0x00000008) { /* Change current endianness */ hreg_compute_hflags(env); - qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__, + qemu_log("%s: set endianness to %c => %08x\n", __func__, val & 0x8 ? 'l' : 'b', env->hflags); } } diff --git a/target/ppc/translate.c b/target/ppc/translate.c index a9325a12e5..a85b890bb0 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7657,7 +7657,7 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags) env->nip, env->lr, env->ctr, cpu_read_xer(env), cs->cpu_index); qemu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF " - TARGET_FMT_lx " iidx %d didx %d\n", + "%08x iidx %d didx %d\n", env->msr, env->spr[SPR_HID0], env->hflags, env->immu_idx, env->dmmu_idx); #if !defined(NO_TIMER_DUMP) From 7da31f260d194d203c83712cfa7b2dfe605375fd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 23 Mar 2021 12:43:34 -0600 Subject: [PATCH 0244/3028] target/ppc: Put dbcr0 single-step bits into hflags Because these bits were not in hflags, the code generated for single-stepping on BookE was essentially random. Recompute hflags when storing to dbcr0. Reviewed-by: David Gibson Signed-off-by: Richard Henderson Message-Id: <20210323184340.619757-5-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/helper_regs.c | 24 +++++++++++++++++------- target/ppc/misc_helper.c | 3 +++ target/ppc/translate.c | 11 ----------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index df9673b90f..e345966b6b 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -114,13 +114,23 @@ void hreg_compute_hflags(CPUPPCState *env) hflags |= le << MSR_LE; } - if (ppc_flags & POWERPC_FLAG_BE) { - QEMU_BUILD_BUG_ON(MSR_BE != HFLAGS_BE); - msr_mask |= 1 << MSR_BE; - } - if (ppc_flags & POWERPC_FLAG_SE) { - QEMU_BUILD_BUG_ON(MSR_SE != HFLAGS_SE); - msr_mask |= 1 << MSR_SE; + if (ppc_flags & POWERPC_FLAG_DE) { + target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0]; + if (dbcr0 & DBCR0_ICMP) { + hflags |= 1 << HFLAGS_SE; + } + if (dbcr0 & DBCR0_BRT) { + hflags |= 1 << HFLAGS_BE; + } + } else { + if (ppc_flags & POWERPC_FLAG_BE) { + QEMU_BUILD_BUG_ON(MSR_BE != HFLAGS_BE); + msr_mask |= 1 << MSR_BE; + } + if (ppc_flags & POWERPC_FLAG_SE) { + QEMU_BUILD_BUG_ON(MSR_SE != HFLAGS_SE); + msr_mask |= 1 << MSR_SE; + } } if (msr_is_64bit(env, msr)) { diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index b04b4d7c6e..002958be26 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -215,6 +215,9 @@ void helper_store_403_pbr(CPUPPCState *env, uint32_t num, target_ulong value) void helper_store_40x_dbcr0(CPUPPCState *env, target_ulong val) { + /* Bits 26 & 27 affect single-stepping. */ + hreg_compute_hflags(env); + /* Bits 28 & 29 affect reset or shutdown. */ store_40x_dbcr0(env, val); } diff --git a/target/ppc/translate.c b/target/ppc/translate.c index a85b890bb0..7912495f28 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7923,17 +7923,6 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) if ((hflags >> HFLAGS_BE) & 1) { ctx->singlestep_enabled |= CPU_BRANCH_STEP; } - if ((env->flags & POWERPC_FLAG_DE) && msr_de) { - ctx->singlestep_enabled = 0; - target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0]; - if (dbcr0 & DBCR0_ICMP) { - ctx->singlestep_enabled |= CPU_SINGLE_STEP; - } - if (dbcr0 & DBCR0_BRT) { - ctx->singlestep_enabled |= CPU_BRANCH_STEP; - } - - } if (unlikely(ctx->base.singlestep_enabled)) { ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP; } From f43520e5b233828bd4d98b4a1300ddb475e7486a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 23 Mar 2021 12:43:35 -0600 Subject: [PATCH 0245/3028] target/ppc: Create helper_scv Perform the test against FSCR_SCV at runtime, in the helper. This means we can remove the incorrect set against SCV in ppc_tr_init_disas_context and do not need to add an HFLAGS bit. Signed-off-by: Richard Henderson Message-Id: <20210323184340.619757-6-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/excp_helper.c | 9 +++++++++ target/ppc/helper.h | 1 + target/ppc/translate.c | 20 +++++++------------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 85de7e6c90..5c95e0c103 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1130,6 +1130,15 @@ void helper_store_msr(CPUPPCState *env, target_ulong val) } #if defined(TARGET_PPC64) +void helper_scv(CPUPPCState *env, uint32_t lev) +{ + if (env->spr[SPR_FSCR] & (1ull << FSCR_SCV)) { + raise_exception_err(env, POWERPC_EXCP_SYSCALL_VECTORED, lev); + } else { + raise_exception_err(env, POWERPC_EXCP_FU, FSCR_IC_SCV); + } +} + void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) { CPUState *cs; diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 6a4dccf70c..513066d54d 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -13,6 +13,7 @@ DEF_HELPER_1(rfci, void, env) DEF_HELPER_1(rfdi, void, env) DEF_HELPER_1(rfmci, void, env) #if defined(TARGET_PPC64) +DEF_HELPER_2(scv, noreturn, env, i32) DEF_HELPER_2(pminsn, void, env, i32) DEF_HELPER_1(rfid, void, env) DEF_HELPER_1(rfscv, void, env) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 7912495f28..d48c554290 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -173,7 +173,6 @@ struct DisasContext { bool vsx_enabled; bool spe_enabled; bool tm_enabled; - bool scv_enabled; bool gtse; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; @@ -4081,15 +4080,16 @@ static void gen_sc(DisasContext *ctx) #if !defined(CONFIG_USER_ONLY) static void gen_scv(DisasContext *ctx) { - uint32_t lev; + uint32_t lev = (ctx->opcode >> 5) & 0x7F; - if (unlikely(!ctx->scv_enabled)) { - gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_SCV); - return; + /* Set the PC back to the faulting instruction. */ + if (ctx->exception == POWERPC_EXCP_NONE) { + gen_update_nip(ctx, ctx->base.pc_next - 4); } + gen_helper_scv(cpu_env, tcg_constant_i32(lev)); - lev = (ctx->opcode >> 5) & 0x7F; - gen_exception_err(ctx, POWERPC_SYSCALL_VECTORED, lev); + /* This need not be exact, just not POWERPC_EXCP_NONE */ + ctx->exception = POWERPC_SYSCALL_VECTORED; } #endif #endif @@ -7907,12 +7907,6 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->spe_enabled = (hflags >> HFLAGS_SPE) & 1; ctx->altivec_enabled = (hflags >> HFLAGS_VR) & 1; ctx->vsx_enabled = (hflags >> HFLAGS_VSX) & 1; - if ((env->flags & POWERPC_FLAG_SCV) - && (env->spr[SPR_FSCR] & (1ull << FSCR_SCV))) { - ctx->scv_enabled = true; - } else { - ctx->scv_enabled = false; - } ctx->tm_enabled = (hflags >> HFLAGS_TM) & 1; ctx->gtse = !!(env->spr[SPR_LPCR] & LPCR_GTSE); From f03de3b44b1053c3c82f41a22ae452d1ecfdd8c5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 23 Mar 2021 12:43:36 -0600 Subject: [PATCH 0246/3028] target/ppc: Put LPCR[GTSE] in hflags Because this bit was not in hflags, the privilege check for tlb instructions was essentially random. Recompute hflags when storing to LPCR. Reviewed-by: David Gibson Signed-off-by: Richard Henderson Message-Id: <20210323184340.619757-7-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/cpu.h | 1 + target/ppc/helper_regs.c | 3 +++ target/ppc/mmu-hash64.c | 3 +++ target/ppc/translate.c | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index d5f362506a..3c28ddb331 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -596,6 +596,7 @@ enum { HFLAGS_LE = 0, /* MSR_LE -- comes from elsewhere on 601 */ HFLAGS_HV = 1, /* computed from MSR_HV and other state */ HFLAGS_64 = 2, /* computed from MSR_CE and MSR_SF */ + HFLAGS_GTSE = 3, /* computed from SPR_LPCR[GTSE] */ HFLAGS_DR = 4, /* MSR_DR */ HFLAGS_IR = 5, /* MSR_IR */ HFLAGS_SPE = 6, /* from MSR_SPE if cpu has SPE; avoid overlap w/ MSR_VR */ diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index e345966b6b..f85bb14d1d 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -149,6 +149,9 @@ void hreg_compute_hflags(CPUPPCState *env) if ((ppc_flags & POWERPC_FLAG_TM) && (msr & (1ull << MSR_TM))) { hflags |= 1 << HFLAGS_TM; } + if (env->spr[SPR_LPCR] & LPCR_GTSE) { + hflags |= 1 << HFLAGS_GTSE; + } #ifndef CONFIG_USER_ONLY if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) { diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index 0fabc10302..d517a99832 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -30,6 +30,7 @@ #include "exec/log.h" #include "hw/hw.h" #include "mmu-book3s-v3.h" +#include "helper_regs.h" /* #define DEBUG_SLB */ @@ -1125,6 +1126,8 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) CPUPPCState *env = &cpu->env; env->spr[SPR_LPCR] = val & pcc->lpcr_mask; + /* The gtse bit affects hflags */ + hreg_compute_hflags(env); } void helper_store_lpcr(CPUPPCState *env, target_ulong val) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index d48c554290..5e629291d3 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7908,7 +7908,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->altivec_enabled = (hflags >> HFLAGS_VR) & 1; ctx->vsx_enabled = (hflags >> HFLAGS_VSX) & 1; ctx->tm_enabled = (hflags >> HFLAGS_TM) & 1; - ctx->gtse = !!(env->spr[SPR_LPCR] & LPCR_GTSE); + ctx->gtse = (hflags >> HFLAGS_GTSE) & 1; ctx->singlestep_enabled = 0; if ((hflags >> HFLAGS_SE) & 1) { From 0e6bac3edb42b284aad329313e3a65c451af1d52 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 23 Mar 2021 12:43:37 -0600 Subject: [PATCH 0247/3028] target/ppc: Remove MSR_SA and MSR_AP from hflags Nothing within the translator -- or anywhere else for that matter -- checks MSR_SA or MSR_AP on the 602. This may be a mistake. However, for the moment, we need not record these bits in hflags. This allows us to simplify HFLAGS_VSX computation by moving it to overlap with MSR_VSX. Reviewed-by: David Gibson Signed-off-by: Richard Henderson Message-Id: <20210323184340.619757-8-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/cpu.h | 4 +--- target/ppc/helper_regs.c | 10 ++++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 3c28ddb331..2f72f83ee3 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -600,14 +600,12 @@ enum { HFLAGS_DR = 4, /* MSR_DR */ HFLAGS_IR = 5, /* MSR_IR */ HFLAGS_SPE = 6, /* from MSR_SPE if cpu has SPE; avoid overlap w/ MSR_VR */ - HFLAGS_VSX = 7, /* from MSR_VSX if cpu has VSX; avoid overlap w/ MSR_AP */ HFLAGS_TM = 8, /* computed from MSR_TM */ HFLAGS_BE = 9, /* MSR_BE -- from elsewhere on embedded ppc */ HFLAGS_SE = 10, /* MSR_SE -- from elsewhere on embedded ppc */ HFLAGS_FP = 13, /* MSR_FP */ HFLAGS_PR = 14, /* MSR_PR */ - HFLAGS_SA = 22, /* MSR_SA */ - HFLAGS_AP = 23, /* MSR_AP */ + HFLAGS_VSX = 23, /* MSR_VSX if cpu has VSX */ HFLAGS_VR = 25, /* MSR_VR if cpu has VRE */ }; diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index f85bb14d1d..dd3cd770a3 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -99,11 +99,8 @@ void hreg_compute_hflags(CPUPPCState *env) QEMU_BUILD_BUG_ON(MSR_DR != HFLAGS_DR); QEMU_BUILD_BUG_ON(MSR_IR != HFLAGS_IR); QEMU_BUILD_BUG_ON(MSR_FP != HFLAGS_FP); - QEMU_BUILD_BUG_ON(MSR_SA != HFLAGS_SA); - QEMU_BUILD_BUG_ON(MSR_AP != HFLAGS_AP); msr_mask = ((1 << MSR_LE) | (1 << MSR_PR) | - (1 << MSR_DR) | (1 << MSR_IR) | - (1 << MSR_FP) | (1 << MSR_SA) | (1 << MSR_AP)); + (1 << MSR_DR) | (1 << MSR_IR) | (1 << MSR_FP)); if (ppc_flags & POWERPC_FLAG_HID0_LE) { /* @@ -143,8 +140,9 @@ void hreg_compute_hflags(CPUPPCState *env) QEMU_BUILD_BUG_ON(MSR_VR != HFLAGS_VR); msr_mask |= 1 << MSR_VR; } - if ((ppc_flags & POWERPC_FLAG_VSX) && (msr & (1 << MSR_VSX))) { - hflags |= 1 << HFLAGS_VSX; + if (ppc_flags & POWERPC_FLAG_VSX) { + QEMU_BUILD_BUG_ON(MSR_VSX != HFLAGS_VSX); + msr_mask |= 1 << MSR_VSX; } if ((ppc_flags & POWERPC_FLAG_TM) && (msr & (1ull << MSR_TM))) { hflags |= 1 << HFLAGS_TM; From d764184ddb22a7a41a293e54c26cfe1717167a3f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 23 Mar 2021 12:43:38 -0600 Subject: [PATCH 0248/3028] target/ppc: Remove env->immu_idx and env->dmmu_idx We weren't recording MSR_GS in hflags, which means that BookE memory accesses were essentially random vs Guest State. Instead of adding this bit directly, record the completed mmu indexes instead. This makes it obvious that we are recording exactly the information that we need. This also means that we can stop directly recording MSR_IR. Reviewed-by: David Gibson Signed-off-by: Richard Henderson Message-Id: <20210323184340.619757-9-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/cpu.h | 12 ++++-- target/ppc/helper_regs.c | 89 +++++++++++++++++++--------------------- target/ppc/helper_regs.h | 1 - target/ppc/machine.c | 2 +- target/ppc/mem_helper.c | 2 +- target/ppc/translate.c | 6 +-- 6 files changed, 56 insertions(+), 56 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 2f72f83ee3..3d021f61f3 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -598,7 +598,6 @@ enum { HFLAGS_64 = 2, /* computed from MSR_CE and MSR_SF */ HFLAGS_GTSE = 3, /* computed from SPR_LPCR[GTSE] */ HFLAGS_DR = 4, /* MSR_DR */ - HFLAGS_IR = 5, /* MSR_IR */ HFLAGS_SPE = 6, /* from MSR_SPE if cpu has SPE; avoid overlap w/ MSR_VR */ HFLAGS_TM = 8, /* computed from MSR_TM */ HFLAGS_BE = 9, /* MSR_BE -- from elsewhere on embedded ppc */ @@ -607,6 +606,9 @@ enum { HFLAGS_PR = 14, /* MSR_PR */ HFLAGS_VSX = 23, /* MSR_VSX if cpu has VSX */ HFLAGS_VR = 25, /* MSR_VR if cpu has VRE */ + + HFLAGS_IMMU_IDX = 26, /* 26..28 -- the composite immu_idx */ + HFLAGS_DMMU_IDX = 29, /* 29..31 -- the composite dmmu_idx */ }; /*****************************************************************************/ @@ -1131,8 +1133,6 @@ struct CPUPPCState { /* These resources are used only in TCG */ uint32_t hflags; target_ulong hflags_compat_nmsr; /* for migration compatibility */ - int immu_idx; /* precomputed MMU index to speed up insn accesses */ - int dmmu_idx; /* precomputed MMU index to speed up data accesses */ /* Power management */ int (*check_pow)(CPUPPCState *env); @@ -1368,7 +1368,11 @@ int ppc_dcr_write(ppc_dcr_t *dcr_env, int dcrn, uint32_t val); #define MMU_USER_IDX 0 static inline int cpu_mmu_index(CPUPPCState *env, bool ifetch) { - return ifetch ? env->immu_idx : env->dmmu_idx; +#ifdef CONFIG_USER_ONLY + return MMU_USER_IDX; +#else + return (env->hflags >> (ifetch ? HFLAGS_IMMU_IDX : HFLAGS_DMMU_IDX)) & 7; +#endif } /* Compatibility modes */ diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index dd3cd770a3..5411a67e9a 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -43,49 +43,6 @@ void hreg_swap_gpr_tgpr(CPUPPCState *env) env->tgpr[3] = tmp; } -void hreg_compute_mem_idx(CPUPPCState *env) -{ - /* - * This is our encoding for server processors. The architecture - * specifies that there is no such thing as userspace with - * translation off, however it appears that MacOS does it and some - * 32-bit CPUs support it. Weird... - * - * 0 = Guest User space virtual mode - * 1 = Guest Kernel space virtual mode - * 2 = Guest User space real mode - * 3 = Guest Kernel space real mode - * 4 = HV User space virtual mode - * 5 = HV Kernel space virtual mode - * 6 = HV User space real mode - * 7 = HV Kernel space real mode - * - * For BookE, we need 8 MMU modes as follow: - * - * 0 = AS 0 HV User space - * 1 = AS 0 HV Kernel space - * 2 = AS 1 HV User space - * 3 = AS 1 HV Kernel space - * 4 = AS 0 Guest User space - * 5 = AS 0 Guest Kernel space - * 6 = AS 1 Guest User space - * 7 = AS 1 Guest Kernel space - */ - if (env->mmu_model & POWERPC_MMU_BOOKE) { - env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1; - env->immu_idx += msr_is ? 2 : 0; - env->dmmu_idx += msr_ds ? 2 : 0; - env->immu_idx += msr_gs ? 4 : 0; - env->dmmu_idx += msr_gs ? 4 : 0; - } else { - env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1; - env->immu_idx += msr_ir ? 0 : 2; - env->dmmu_idx += msr_dr ? 0 : 2; - env->immu_idx += msr_hv ? 4 : 0; - env->dmmu_idx += msr_hv ? 4 : 0; - } -} - void hreg_compute_hflags(CPUPPCState *env) { target_ulong msr = env->msr; @@ -97,10 +54,9 @@ void hreg_compute_hflags(CPUPPCState *env) QEMU_BUILD_BUG_ON(MSR_LE != HFLAGS_LE); QEMU_BUILD_BUG_ON(MSR_PR != HFLAGS_PR); QEMU_BUILD_BUG_ON(MSR_DR != HFLAGS_DR); - QEMU_BUILD_BUG_ON(MSR_IR != HFLAGS_IR); QEMU_BUILD_BUG_ON(MSR_FP != HFLAGS_FP); msr_mask = ((1 << MSR_LE) | (1 << MSR_PR) | - (1 << MSR_DR) | (1 << MSR_IR) | (1 << MSR_FP)); + (1 << MSR_DR) | (1 << MSR_FP)); if (ppc_flags & POWERPC_FLAG_HID0_LE) { /* @@ -155,10 +111,51 @@ void hreg_compute_hflags(CPUPPCState *env) if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) { hflags |= 1 << HFLAGS_HV; } + + /* + * This is our encoding for server processors. The architecture + * specifies that there is no such thing as userspace with + * translation off, however it appears that MacOS does it and some + * 32-bit CPUs support it. Weird... + * + * 0 = Guest User space virtual mode + * 1 = Guest Kernel space virtual mode + * 2 = Guest User space real mode + * 3 = Guest Kernel space real mode + * 4 = HV User space virtual mode + * 5 = HV Kernel space virtual mode + * 6 = HV User space real mode + * 7 = HV Kernel space real mode + * + * For BookE, we need 8 MMU modes as follow: + * + * 0 = AS 0 HV User space + * 1 = AS 0 HV Kernel space + * 2 = AS 1 HV User space + * 3 = AS 1 HV Kernel space + * 4 = AS 0 Guest User space + * 5 = AS 0 Guest Kernel space + * 6 = AS 1 Guest User space + * 7 = AS 1 Guest Kernel space + */ + unsigned immu_idx, dmmu_idx; + dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1; + if (env->mmu_model & POWERPC_MMU_BOOKE) { + dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0; + immu_idx = dmmu_idx; + immu_idx |= msr & (1 << MSR_IS) ? 2 : 0; + dmmu_idx |= msr & (1 << MSR_DS) ? 2 : 0; + } else { + dmmu_idx |= msr & (1ull << MSR_HV) ? 4 : 0; + immu_idx = dmmu_idx; + immu_idx |= msr & (1 << MSR_IR) ? 0 : 2; + dmmu_idx |= msr & (1 << MSR_DR) ? 0 : 2; + } + hflags |= immu_idx << HFLAGS_IMMU_IDX; + hflags |= dmmu_idx << HFLAGS_DMMU_IDX; #endif env->hflags = hflags | (msr & msr_mask); - hreg_compute_mem_idx(env); } void cpu_interrupt_exittb(CPUState *cs) diff --git a/target/ppc/helper_regs.h b/target/ppc/helper_regs.h index 4148a442b3..42f26870b9 100644 --- a/target/ppc/helper_regs.h +++ b/target/ppc/helper_regs.h @@ -21,7 +21,6 @@ #define HELPER_REGS_H void hreg_swap_gpr_tgpr(CPUPPCState *env); -void hreg_compute_mem_idx(CPUPPCState *env); void hreg_compute_hflags(CPUPPCState *env); void cpu_interrupt_exittb(CPUState *cs); int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv); diff --git a/target/ppc/machine.c b/target/ppc/machine.c index 09c5765a87..e5bffbe365 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -16,7 +16,7 @@ static void post_load_update_msr(CPUPPCState *env) /* * Invalidate all supported msr bits except MSR_TGPR/MSR_HVB - * before restoring. Note that this recomputes hflags and mem_idx. + * before restoring. Note that this recomputes hflags. */ env->msr ^= env->msr_mask & ~((1ULL << MSR_TGPR) | MSR_HVB); ppc_store_msr(env, msr); diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index f4f7e730de..444b2a30ef 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -278,7 +278,7 @@ static void dcbz_common(CPUPPCState *env, target_ulong addr, target_ulong mask, dcbz_size = env->dcache_line_size; uint32_t i; void *haddr; - int mmu_idx = epid ? PPC_TLB_EPID_STORE : env->dmmu_idx; + int mmu_idx = epid ? PPC_TLB_EPID_STORE : cpu_mmu_index(env, false); #if defined(TARGET_PPC64) /* Check for dcbz vs dcbzl on 970 */ diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 5e629291d3..a53463b9b8 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7658,8 +7658,8 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags) cs->cpu_index); qemu_fprintf(f, "MSR " TARGET_FMT_lx " HID0 " TARGET_FMT_lx " HF " "%08x iidx %d didx %d\n", - env->msr, env->spr[SPR_HID0], - env->hflags, env->immu_idx, env->dmmu_idx); + env->msr, env->spr[SPR_HID0], env->hflags, + cpu_mmu_index(env, true), cpu_mmu_index(env, false)); #if !defined(NO_TIMER_DUMP) qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 #if !defined(CONFIG_USER_ONLY) @@ -7885,7 +7885,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->exception = POWERPC_EXCP_NONE; ctx->spr_cb = env->spr_cb; ctx->pr = (hflags >> HFLAGS_PR) & 1; - ctx->mem_idx = env->dmmu_idx; + ctx->mem_idx = (hflags >> HFLAGS_DMMU_IDX) & 7; ctx->dr = (hflags >> HFLAGS_DR) & 1; ctx->hv = (hflags >> HFLAGS_HV) & 1; ctx->insns_flags = env->insns_flags; From 75da499733696889453b3fda9ae0f0f5c28fcd6b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 23 Mar 2021 12:43:39 -0600 Subject: [PATCH 0249/3028] linux-user/ppc: Fix msr updates for signal handling In save_user_regs, there are two bugs where we OR in a bit number instead of the bit, clobbering the low bits of MSR. However: The MSR_VR and MSR_SPE bits control the availability of the insns. If the bits were not already set in MSR, then any attempt to access those registers would result in SIGILL. For linux-user, we always initialize MSR to the capabilities of the cpu. We *could* add checks vs MSR where we currently check insn_flags and insn_flags2, but we know they match. Also, there's a stray cut-and-paste comment in restore. Then, do not force little-endian binaries into big-endian mode. Finally, use ppc_store_msr for the update to affect hflags. Which is the reason none of these bugs were previously noticed. Signed-off-by: Richard Henderson Message-Id: <20210323184340.619757-10-richard.henderson@linaro.org> Signed-off-by: David Gibson --- linux-user/ppc/cpu_loop.c | 5 +++-- linux-user/ppc/signal.c | 23 +++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c index df71e15a25..4a0f6c8dc2 100644 --- a/linux-user/ppc/cpu_loop.c +++ b/linux-user/ppc/cpu_loop.c @@ -492,11 +492,12 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) #if defined(TARGET_PPC64) int flag = (env->insns_flags2 & PPC2_BOOKE206) ? MSR_CM : MSR_SF; #if defined(TARGET_ABI32) - env->msr &= ~((target_ulong)1 << flag); + ppc_store_msr(env, env->msr & ~((target_ulong)1 << flag)); #else - env->msr |= (target_ulong)1 << flag; + ppc_store_msr(env, env->msr | (target_ulong)1 << flag); #endif #endif + env->nip = regs->nip; for(i = 0; i < 32; i++) { env->gpr[i] = regs->gpr[i]; diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index b78613f7c8..bad38f8ed9 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -261,9 +261,6 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) __put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]); __put_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]); } - /* Set MSR_VR in the saved MSR value to indicate that - frame->mc_vregs contains valid data. */ - msr |= MSR_VR; #if defined(TARGET_PPC64) vrsave = (uint32_t *)&frame->mc_vregs.altivec[33]; /* 64-bit needs to put a pointer to the vectors in the frame */ @@ -300,9 +297,6 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) for (i = 0; i < ARRAY_SIZE(env->gprh); i++) { __put_user(env->gprh[i], &frame->mc_vregs.spe[i]); } - /* Set MSR_SPE in the saved MSR value to indicate that - frame->mc_vregs contains valid data. */ - msr |= MSR_SPE; __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]); } #endif @@ -354,8 +348,10 @@ static void restore_user_regs(CPUPPCState *env, __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]); /* If doing signal return, restore the previous little-endian mode. */ - if (sig) - env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE)); + if (sig) { + ppc_store_msr(env, ((env->msr & ~(1ull << MSR_LE)) | + (msr & (1ull << MSR_LE)))); + } /* Restore Altivec registers if necessary. */ if (env->insns_flags & PPC_ALTIVEC) { @@ -376,8 +372,6 @@ static void restore_user_regs(CPUPPCState *env, __get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]); __get_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]); } - /* Set MSR_VEC in the saved MSR value to indicate that - frame->mc_vregs contains valid data. */ #if defined(TARGET_PPC64) vrsave = (uint32_t *)&v_regs[33]; #else @@ -468,7 +462,7 @@ void setup_frame(int sig, struct target_sigaction *ka, env->nip = (target_ulong) ka->_sa_handler; /* Signal handlers are entered in big-endian mode. */ - env->msr &= ~(1ull << MSR_LE); + ppc_store_msr(env, env->msr & ~(1ull << MSR_LE)); unlock_user_struct(frame, frame_addr, 1); return; @@ -563,8 +557,13 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, env->nip = (target_ulong) ka->_sa_handler; #endif +#ifdef TARGET_WORDS_BIGENDIAN /* Signal handlers are entered in big-endian mode. */ - env->msr &= ~(1ull << MSR_LE); + ppc_store_msr(env, env->msr & ~(1ull << MSR_LE)); +#else + /* Signal handlers are entered in little-endian mode. */ + ppc_store_msr(env, env->msr | (1ull << MSR_LE)); +#endif unlock_user_struct(rt_sf, rt_sf_addr, 1); return; From 2da8a6bcdca72c7a79a9c732133eaeb9452242cc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 23 Mar 2021 12:43:40 -0600 Subject: [PATCH 0250/3028] target/ppc: Validate hflags with CONFIG_DEBUG_TCG Verify that hflags was updated correctly whenever we change cpu state that is used by hflags. Signed-off-by: Richard Henderson Message-Id: <20210323184340.619757-11-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/cpu.h | 5 +++++ target/ppc/helper_regs.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 3d021f61f3..69fc9a2831 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -2425,6 +2425,10 @@ void cpu_write_xer(CPUPPCState *env, target_ulong xer); */ #define is_book3s_arch2x(ctx) (!!((ctx)->insns_flags & PPC_SEGMENT_64B)) +#ifdef CONFIG_DEBUG_TCG +void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *flags); +#else static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { @@ -2432,6 +2436,7 @@ static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, *cs_base = 0; *flags = env->hflags; } +#endif void QEMU_NORETURN raise_exception(CPUPPCState *env, uint32_t exception); void QEMU_NORETURN raise_exception_ra(CPUPPCState *env, uint32_t exception, diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 5411a67e9a..3723872aa6 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -43,7 +43,7 @@ void hreg_swap_gpr_tgpr(CPUPPCState *env) env->tgpr[3] = tmp; } -void hreg_compute_hflags(CPUPPCState *env) +static uint32_t hreg_compute_hflags_value(CPUPPCState *env) { target_ulong msr = env->msr; uint32_t ppc_flags = env->flags; @@ -155,9 +155,34 @@ void hreg_compute_hflags(CPUPPCState *env) hflags |= dmmu_idx << HFLAGS_DMMU_IDX; #endif - env->hflags = hflags | (msr & msr_mask); + return hflags | (msr & msr_mask); } +void hreg_compute_hflags(CPUPPCState *env) +{ + env->hflags = hreg_compute_hflags_value(env); +} + +#ifdef CONFIG_DEBUG_TCG +void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *flags) +{ + uint32_t hflags_current = env->hflags; + uint32_t hflags_rebuilt; + + *pc = env->nip; + *cs_base = 0; + *flags = hflags_current; + + hflags_rebuilt = hreg_compute_hflags_value(env); + if (unlikely(hflags_current != hflags_rebuilt)) { + cpu_abort(env_cpu(env), + "TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n", + hflags_current, hflags_rebuilt); + } +} +#endif + void cpu_interrupt_exittb(CPUState *cs) { if (!kvm_enabled()) { From f028c2ded2ccbd6a15493e6e0f292542d417b969 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 25 Mar 2021 14:50:39 +0100 Subject: [PATCH 0251/3028] vt82c686: QOM-ify superio related functionality Collect superio functionality and its controlling config registers handling in an abstract VIA_SUPERIO class that is a subclass of ISA_SUPERIO and put vt82c686b specific parts in a subclass of this abstract class. Signed-off-by: BALATON Zoltan Reviewed-by: Mark Cave-Ayland Message-Id: Signed-off-by: David Gibson --- hw/isa/vt82c686.c | 200 +++++++++++++++++++++++++------------- include/hw/isa/vt82c686.h | 1 - 2 files changed, 134 insertions(+), 67 deletions(-) diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 98325bb32b..ea55117724 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -265,15 +265,80 @@ static const TypeInfo vt8231_pm_info = { }; -typedef struct SuperIOConfig { - uint8_t regs[0x100]; - MemoryRegion io; -} SuperIOConfig; +#define TYPE_VIA_SUPERIO "via-superio" +OBJECT_DECLARE_SIMPLE_TYPE(ViaSuperIOState, VIA_SUPERIO) -static void superio_cfg_write(void *opaque, hwaddr addr, uint64_t data, - unsigned size) +struct ViaSuperIOState { + ISASuperIODevice superio; + uint8_t regs[0x100]; + const MemoryRegionOps *io_ops; + MemoryRegion io; +}; + +static inline void via_superio_io_enable(ViaSuperIOState *s, bool enable) { - SuperIOConfig *sc = opaque; + memory_region_set_enabled(&s->io, enable); +} + +static void via_superio_realize(DeviceState *d, Error **errp) +{ + ViaSuperIOState *s = VIA_SUPERIO(d); + ISASuperIOClass *ic = ISA_SUPERIO_GET_CLASS(s); + Error *local_err = NULL; + + assert(s->io_ops); + ic->parent_realize(d, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + memory_region_init_io(&s->io, OBJECT(d), s->io_ops, s, "via-superio", 2); + memory_region_set_enabled(&s->io, false); + /* The floppy also uses 0x3f0 and 0x3f1 but this seems to work anyway */ + memory_region_add_subregion(isa_address_space_io(ISA_DEVICE(s)), 0x3f0, + &s->io); +} + +static uint64_t via_superio_cfg_read(void *opaque, hwaddr addr, unsigned size) +{ + ViaSuperIOState *sc = opaque; + uint8_t idx = sc->regs[0]; + uint8_t val = sc->regs[idx]; + + if (addr == 0) { + return idx; + } + if (addr == 1 && idx == 0) { + val = 0; /* reading reg 0 where we store index value */ + } + trace_via_superio_read(idx, val); + return val; +} + +static void via_superio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); + + sc->parent_realize = dc->realize; + dc->realize = via_superio_realize; +} + +static const TypeInfo via_superio_info = { + .name = TYPE_VIA_SUPERIO, + .parent = TYPE_ISA_SUPERIO, + .instance_size = sizeof(ViaSuperIOState), + .class_size = sizeof(ISASuperIOClass), + .class_init = via_superio_class_init, + .abstract = true, +}; + +#define TYPE_VT82C686B_SUPERIO "vt82c686b-superio" + +static void vt82c686b_superio_cfg_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + ViaSuperIOState *sc = opaque; uint8_t idx = sc->regs[0]; if (addr == 0) { /* config index register */ @@ -304,25 +369,9 @@ static void superio_cfg_write(void *opaque, hwaddr addr, uint64_t data, sc->regs[idx] = data; } -static uint64_t superio_cfg_read(void *opaque, hwaddr addr, unsigned size) -{ - SuperIOConfig *sc = opaque; - uint8_t idx = sc->regs[0]; - uint8_t val = sc->regs[idx]; - - if (addr == 0) { - return idx; - } - if (addr == 1 && idx == 0) { - val = 0; /* reading reg 0 where we store index value */ - } - trace_via_superio_read(idx, val); - return val; -} - -static const MemoryRegionOps superio_cfg_ops = { - .read = superio_cfg_read, - .write = superio_cfg_write, +static const MemoryRegionOps vt82c686b_superio_cfg_ops = { + .read = via_superio_cfg_read, + .write = vt82c686b_superio_cfg_write, .endianness = DEVICE_NATIVE_ENDIAN, .impl = { .min_access_size = 1, @@ -330,13 +379,66 @@ static const MemoryRegionOps superio_cfg_ops = { }, }; +static void vt82c686b_superio_reset(DeviceState *dev) +{ + ViaSuperIOState *s = VIA_SUPERIO(dev); + + memset(s->regs, 0, sizeof(s->regs)); + /* Device ID */ + vt82c686b_superio_cfg_write(s, 0, 0xe0, 1); + vt82c686b_superio_cfg_write(s, 1, 0x3c, 1); + /* Function select - all disabled */ + vt82c686b_superio_cfg_write(s, 0, 0xe2, 1); + vt82c686b_superio_cfg_write(s, 1, 0x03, 1); + /* Floppy ctrl base addr 0x3f0-7 */ + vt82c686b_superio_cfg_write(s, 0, 0xe3, 1); + vt82c686b_superio_cfg_write(s, 1, 0xfc, 1); + /* Parallel port base addr 0x378-f */ + vt82c686b_superio_cfg_write(s, 0, 0xe6, 1); + vt82c686b_superio_cfg_write(s, 1, 0xde, 1); + /* Serial port 1 base addr 0x3f8-f */ + vt82c686b_superio_cfg_write(s, 0, 0xe7, 1); + vt82c686b_superio_cfg_write(s, 1, 0xfe, 1); + /* Serial port 2 base addr 0x2f8-f */ + vt82c686b_superio_cfg_write(s, 0, 0xe8, 1); + vt82c686b_superio_cfg_write(s, 1, 0xbe, 1); + + vt82c686b_superio_cfg_write(s, 0, 0, 1); +} + +static void vt82c686b_superio_init(Object *obj) +{ + VIA_SUPERIO(obj)->io_ops = &vt82c686b_superio_cfg_ops; +} + +static void vt82c686b_superio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); + + dc->reset = vt82c686b_superio_reset; + sc->serial.count = 2; + sc->parallel.count = 1; + sc->ide.count = 0; /* emulated by via-ide */ + sc->floppy.count = 1; +} + +static const TypeInfo vt82c686b_superio_info = { + .name = TYPE_VT82C686B_SUPERIO, + .parent = TYPE_VIA_SUPERIO, + .instance_size = sizeof(ViaSuperIOState), + .instance_init = vt82c686b_superio_init, + .class_size = sizeof(ISASuperIOClass), + .class_init = vt82c686b_superio_class_init, +}; + OBJECT_DECLARE_SIMPLE_TYPE(VT82C686BISAState, VT82C686B_ISA) struct VT82C686BISAState { PCIDevice dev; qemu_irq cpu_intr; - SuperIOConfig superio_cfg; + ViaSuperIOState *via_sio; }; static void via_isa_request_i8259_irq(void *opaque, int irq, int level) @@ -354,7 +456,7 @@ static void vt82c686b_write_config(PCIDevice *d, uint32_t addr, pci_default_write_config(d, addr, val, len); if (addr == 0x85) { /* BIT(1): enable or disable superio config io ports */ - memory_region_set_enabled(&s->superio_cfg.io, val & BIT(1)); + via_superio_io_enable(s->via_sio, val & BIT(1)); } } @@ -386,13 +488,6 @@ static void vt82c686b_isa_reset(DeviceState *dev) pci_conf[0x5a] = 0x04; /* KBC/RTC Control*/ pci_conf[0x5f] = 0x04; pci_conf[0x77] = 0x10; /* GPIO Control 1/2/3/4 */ - - s->superio_cfg.regs[0xe0] = 0x3c; /* Device ID */ - s->superio_cfg.regs[0xe2] = 0x03; /* Function select */ - s->superio_cfg.regs[0xe3] = 0xfc; /* Floppy ctrl base addr */ - s->superio_cfg.regs[0xe6] = 0xde; /* Parallel port base addr */ - s->superio_cfg.regs[0xe7] = 0xfe; /* Serial port 1 base addr */ - s->superio_cfg.regs[0xe8] = 0xbe; /* Serial port 2 base addr */ } static void vt82c686b_realize(PCIDevice *d, Error **errp) @@ -410,7 +505,8 @@ static void vt82c686b_realize(PCIDevice *d, Error **errp) isa_bus_irqs(isa_bus, i8259_init(isa_bus, *isa_irq)); i8254_pit_init(isa_bus, 0x40, 0, NULL); i8257_dma_init(isa_bus, 0); - isa_create_simple(isa_bus, TYPE_VT82C686B_SUPERIO); + s->via_sio = VIA_SUPERIO(isa_create_simple(isa_bus, + TYPE_VT82C686B_SUPERIO)); mc146818_rtc_init(isa_bus, 2000, NULL); for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i++) { @@ -418,16 +514,6 @@ static void vt82c686b_realize(PCIDevice *d, Error **errp) d->wmask[i] = 0; } } - - memory_region_init_io(&s->superio_cfg.io, OBJECT(d), &superio_cfg_ops, - &s->superio_cfg, "superio_cfg", 2); - memory_region_set_enabled(&s->superio_cfg.io, false); - /* - * The floppy also uses 0x3f0 and 0x3f1. - * But we do not emulate a floppy, so just set it here. - */ - memory_region_add_subregion(isa_bus->address_space_io, 0x3f0, - &s->superio_cfg.io); } static void via_class_init(ObjectClass *klass, void *data) @@ -463,32 +549,14 @@ static const TypeInfo via_info = { }; -static void vt82c686b_superio_class_init(ObjectClass *klass, void *data) -{ - ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); - - sc->serial.count = 2; - sc->parallel.count = 1; - sc->ide.count = 0; - sc->floppy.count = 1; -} - -static const TypeInfo via_superio_info = { - .name = TYPE_VT82C686B_SUPERIO, - .parent = TYPE_ISA_SUPERIO, - .instance_size = sizeof(ISASuperIODevice), - .class_size = sizeof(ISASuperIOClass), - .class_init = vt82c686b_superio_class_init, -}; - - static void vt82c686b_register_types(void) { type_register_static(&via_pm_info); type_register_static(&vt82c686b_pm_info); type_register_static(&vt8231_pm_info); - type_register_static(&via_info); type_register_static(&via_superio_info); + type_register_static(&vt82c686b_superio_info); + type_register_static(&via_info); } type_init(vt82c686b_register_types) diff --git a/include/hw/isa/vt82c686.h b/include/hw/isa/vt82c686.h index 9b6d610e83..0692b9a527 100644 --- a/include/hw/isa/vt82c686.h +++ b/include/hw/isa/vt82c686.h @@ -2,7 +2,6 @@ #define HW_VT82C686_H #define TYPE_VT82C686B_ISA "vt82c686b-isa" -#define TYPE_VT82C686B_SUPERIO "vt82c686b-superio" #define TYPE_VT82C686B_PM "vt82c686b-pm" #define TYPE_VT8231_PM "vt8231-pm" #define TYPE_VIA_AC97 "via-ac97" From ab74864fed2dcebe9a2ece659253e1bb2ead75ce Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 25 Mar 2021 14:50:39 +0100 Subject: [PATCH 0252/3028] vt82c686: Add VT8231_SUPERIO based on VIA_SUPERIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VT8231 south bridge is very similar to VT82C686B but there are some differences in register addresses and functionality, e.g. the VT8231 only has one serial port. This commit adds VT8231_SUPERIO subclass based on the abstract VIA_SUPERIO class to emulate the superio part of VT8231. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <8108809321f9ecf3fb1aea22ddaeccc7c3a57c8e.1616680239.git.balaton@eik.bme.hu> Signed-off-by: David Gibson --- hw/isa/vt82c686.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index ea55117724..952c6fc867 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -433,6 +433,107 @@ static const TypeInfo vt82c686b_superio_info = { }; +#define TYPE_VT8231_SUPERIO "vt8231-superio" + +static void vt8231_superio_cfg_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + ViaSuperIOState *sc = opaque; + uint8_t idx = sc->regs[0]; + + if (addr == 0) { /* config index register */ + sc->regs[0] = data; + return; + } + + /* config data register */ + trace_via_superio_write(idx, data); + switch (idx) { + case 0x00 ... 0xdf: + case 0xe7 ... 0xef: + case 0xf0 ... 0xf1: + case 0xf5: + case 0xf8: + case 0xfd: + /* ignore write to read only registers */ + return; + default: + qemu_log_mask(LOG_UNIMP, + "via_superio_cfg: unimplemented register 0x%x\n", idx); + break; + } + sc->regs[idx] = data; +} + +static const MemoryRegionOps vt8231_superio_cfg_ops = { + .read = via_superio_cfg_read, + .write = vt8231_superio_cfg_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static void vt8231_superio_reset(DeviceState *dev) +{ + ViaSuperIOState *s = VIA_SUPERIO(dev); + + memset(s->regs, 0, sizeof(s->regs)); + /* Device ID */ + s->regs[0xf0] = 0x3c; + /* Device revision */ + s->regs[0xf1] = 0x01; + /* Function select - all disabled */ + vt8231_superio_cfg_write(s, 0, 0xf2, 1); + vt8231_superio_cfg_write(s, 1, 0x03, 1); + /* Serial port base addr */ + vt8231_superio_cfg_write(s, 0, 0xf4, 1); + vt8231_superio_cfg_write(s, 1, 0xfe, 1); + /* Parallel port base addr */ + vt8231_superio_cfg_write(s, 0, 0xf6, 1); + vt8231_superio_cfg_write(s, 1, 0xde, 1); + /* Floppy ctrl base addr */ + vt8231_superio_cfg_write(s, 0, 0xf7, 1); + vt8231_superio_cfg_write(s, 1, 0xfc, 1); + + vt8231_superio_cfg_write(s, 0, 0, 1); +} + +static void vt8231_superio_init(Object *obj) +{ + VIA_SUPERIO(obj)->io_ops = &vt8231_superio_cfg_ops; +} + +static uint16_t vt8231_superio_serial_iobase(ISASuperIODevice *sio, + uint8_t index) +{ + return 0x2f8; /* FIXME: This should be settable via registers f2-f4 */ +} + +static void vt8231_superio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); + + dc->reset = vt8231_superio_reset; + sc->serial.count = 1; + sc->serial.get_iobase = vt8231_superio_serial_iobase; + sc->parallel.count = 1; + sc->ide.count = 0; /* emulated by via-ide */ + sc->floppy.count = 1; +} + +static const TypeInfo vt8231_superio_info = { + .name = TYPE_VT8231_SUPERIO, + .parent = TYPE_VIA_SUPERIO, + .instance_size = sizeof(ViaSuperIOState), + .instance_init = vt8231_superio_init, + .class_size = sizeof(ISASuperIOClass), + .class_init = vt8231_superio_class_init, +}; + + OBJECT_DECLARE_SIMPLE_TYPE(VT82C686BISAState, VT82C686B_ISA) struct VT82C686BISAState { @@ -556,6 +657,7 @@ static void vt82c686b_register_types(void) type_register_static(&vt8231_pm_info); type_register_static(&via_superio_info); type_register_static(&vt82c686b_superio_info); + type_register_static(&vt8231_superio_info); type_register_static(&via_info); } From 2e84e107a0309073d2427dc2c400d02a554afd9d Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 25 Mar 2021 14:50:39 +0100 Subject: [PATCH 0253/3028] vt82c686: Introduce abstract TYPE_VIA_ISA and base vt82c686b_isa on it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To allow reusing ISA bridge emulation for vt8231_isa move the device state of vt82c686b_isa emulation in an abstract via_isa class. This change breaks migration back compatibility but this is not an issue for Fuloong2E machine which is not versioned or migration supported. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <0cb8fc69c7aaa555589181931b881335fecd2ef3.1616680239.git.balaton@eik.bme.hu> Signed-off-by: David Gibson --- hw/isa/vt82c686.c | 70 ++++++++++++++++++++++------------------ include/hw/pci/pci_ids.h | 2 +- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 952c6fc867..b09bfe3fa2 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -534,24 +534,48 @@ static const TypeInfo vt8231_superio_info = { }; -OBJECT_DECLARE_SIMPLE_TYPE(VT82C686BISAState, VT82C686B_ISA) +#define TYPE_VIA_ISA "via-isa" +OBJECT_DECLARE_SIMPLE_TYPE(ViaISAState, VIA_ISA) -struct VT82C686BISAState { +struct ViaISAState { PCIDevice dev; qemu_irq cpu_intr; ViaSuperIOState *via_sio; }; +static const VMStateDescription vmstate_via = { + .name = "via-isa", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, ViaISAState), + VMSTATE_END_OF_LIST() + } +}; + +static const TypeInfo via_isa_info = { + .name = TYPE_VIA_ISA, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(ViaISAState), + .abstract = true, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + static void via_isa_request_i8259_irq(void *opaque, int irq, int level) { - VT82C686BISAState *s = opaque; + ViaISAState *s = opaque; qemu_set_irq(s->cpu_intr, level); } +/* TYPE_VT82C686B_ISA */ + static void vt82c686b_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len) { - VT82C686BISAState *s = VT82C686B_ISA(d); + ViaISAState *s = VIA_ISA(d); trace_via_isa_write(addr, val, len); pci_default_write_config(d, addr, val, len); @@ -561,19 +585,9 @@ static void vt82c686b_write_config(PCIDevice *d, uint32_t addr, } } -static const VMStateDescription vmstate_via = { - .name = "vt82c686b", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, VT82C686BISAState), - VMSTATE_END_OF_LIST() - } -}; - static void vt82c686b_isa_reset(DeviceState *dev) { - VT82C686BISAState *s = VT82C686B_ISA(dev); + ViaISAState *s = VIA_ISA(dev); uint8_t *pci_conf = s->dev.config; pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0); @@ -593,7 +607,7 @@ static void vt82c686b_isa_reset(DeviceState *dev) static void vt82c686b_realize(PCIDevice *d, Error **errp) { - VT82C686BISAState *s = VT82C686B_ISA(d); + ViaISAState *s = VIA_ISA(d); DeviceState *dev = DEVICE(d); ISABus *isa_bus; qemu_irq *isa_irq; @@ -617,7 +631,7 @@ static void vt82c686b_realize(PCIDevice *d, Error **errp) } } -static void via_class_init(ObjectClass *klass, void *data) +static void vt82c686b_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -625,28 +639,21 @@ static void via_class_init(ObjectClass *klass, void *data) k->realize = vt82c686b_realize; k->config_write = vt82c686b_write_config; k->vendor_id = PCI_VENDOR_ID_VIA; - k->device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE; + k->device_id = PCI_DEVICE_ID_VIA_82C686B_ISA; k->class_id = PCI_CLASS_BRIDGE_ISA; k->revision = 0x40; dc->reset = vt82c686b_isa_reset; dc->desc = "ISA bridge"; dc->vmsd = &vmstate_via; - /* - * Reason: part of VIA VT82C686 southbridge, needs to be wired up, - * e.g. by mips_fuloong2e_init() - */ + /* Reason: part of VIA VT82C686 southbridge, needs to be wired up */ dc->user_creatable = false; } -static const TypeInfo via_info = { +static const TypeInfo vt82c686b_isa_info = { .name = TYPE_VT82C686B_ISA, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(VT82C686BISAState), - .class_init = via_class_init, - .interfaces = (InterfaceInfo[]) { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }, + .parent = TYPE_VIA_ISA, + .instance_size = sizeof(ViaISAState), + .class_init = vt82c686b_class_init, }; @@ -658,7 +665,8 @@ static void vt82c686b_register_types(void) type_register_static(&via_superio_info); type_register_static(&vt82c686b_superio_info); type_register_static(&vt8231_superio_info); - type_register_static(&via_info); + type_register_static(&via_isa_info); + type_register_static(&vt82c686b_isa_info); } type_init(vt82c686b_register_types) diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index ea28dcc850..aa3f67eaa4 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -204,7 +204,7 @@ #define PCI_VENDOR_ID_XILINX 0x10ee #define PCI_VENDOR_ID_VIA 0x1106 -#define PCI_DEVICE_ID_VIA_ISA_BRIDGE 0x0686 +#define PCI_DEVICE_ID_VIA_82C686B_ISA 0x0686 #define PCI_DEVICE_ID_VIA_IDE 0x0571 #define PCI_DEVICE_ID_VIA_UHCI 0x3038 #define PCI_DEVICE_ID_VIA_82C686B_PM 0x3057 From f9f0c9e2faab18a44d9f60a8653688a8f841a909 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 25 Mar 2021 14:50:39 +0100 Subject: [PATCH 0254/3028] vt82c686: Add emulation of VT8231 south bridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add emulation of VT8231 south bridge ISA part based on the similar VT82C686B but implemented in a separate subclass that holds the differences while reusing parts that can be shared. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <10abc9f89854e7c980b9731c33d25a2e307e9c4f.1616680239.git.balaton@eik.bme.hu> Signed-off-by: David Gibson --- hw/isa/vt82c686.c | 84 +++++++++++++++++++++++++++++++++++++++ include/hw/isa/vt82c686.h | 1 + include/hw/pci/pci_ids.h | 1 + 3 files changed, 86 insertions(+) diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index b09bfe3fa2..7b2e90c7e1 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -8,6 +8,9 @@ * * Contributions after 2012-01-13 are licensed under the terms of the * GNU GPL, version 2 or (at your option) any later version. + * + * VT8231 south bridge support and general clean up to allow it + * Copyright (c) 2018-2020 BALATON Zoltan */ #include "qemu/osdep.h" @@ -656,6 +659,86 @@ static const TypeInfo vt82c686b_isa_info = { .class_init = vt82c686b_class_init, }; +/* TYPE_VT8231_ISA */ + +static void vt8231_write_config(PCIDevice *d, uint32_t addr, + uint32_t val, int len) +{ + ViaISAState *s = VIA_ISA(d); + + trace_via_isa_write(addr, val, len); + pci_default_write_config(d, addr, val, len); + if (addr == 0x50) { + /* BIT(2): enable or disable superio config io ports */ + via_superio_io_enable(s->via_sio, val & BIT(2)); + } +} + +static void vt8231_isa_reset(DeviceState *dev) +{ + ViaISAState *s = VIA_ISA(dev); + uint8_t *pci_conf = s->dev.config; + + pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0); + pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL); + pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM); + + pci_conf[0x58] = 0x40; /* Miscellaneous Control 0 */ + pci_conf[0x67] = 0x08; /* Fast IR Config */ + pci_conf[0x6b] = 0x01; /* Fast IR I/O Base */ +} + +static void vt8231_realize(PCIDevice *d, Error **errp) +{ + ViaISAState *s = VIA_ISA(d); + DeviceState *dev = DEVICE(d); + ISABus *isa_bus; + qemu_irq *isa_irq; + int i; + + qdev_init_gpio_out(dev, &s->cpu_intr, 1); + isa_irq = qemu_allocate_irqs(via_isa_request_i8259_irq, s, 1); + isa_bus = isa_bus_new(dev, get_system_memory(), pci_address_space_io(d), + &error_fatal); + isa_bus_irqs(isa_bus, i8259_init(isa_bus, *isa_irq)); + i8254_pit_init(isa_bus, 0x40, 0, NULL); + i8257_dma_init(isa_bus, 0); + s->via_sio = VIA_SUPERIO(isa_create_simple(isa_bus, TYPE_VT8231_SUPERIO)); + mc146818_rtc_init(isa_bus, 2000, NULL); + + for (i = 0; i < PCI_CONFIG_HEADER_SIZE; i++) { + if (i < PCI_COMMAND || i >= PCI_REVISION_ID) { + d->wmask[i] = 0; + } + } +} + +static void vt8231_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->realize = vt8231_realize; + k->config_write = vt8231_write_config; + k->vendor_id = PCI_VENDOR_ID_VIA; + k->device_id = PCI_DEVICE_ID_VIA_8231_ISA; + k->class_id = PCI_CLASS_BRIDGE_ISA; + k->revision = 0x10; + dc->reset = vt8231_isa_reset; + dc->desc = "ISA bridge"; + dc->vmsd = &vmstate_via; + /* Reason: part of VIA VT8231 southbridge, needs to be wired up */ + dc->user_creatable = false; +} + +static const TypeInfo vt8231_isa_info = { + .name = TYPE_VT8231_ISA, + .parent = TYPE_VIA_ISA, + .instance_size = sizeof(ViaISAState), + .class_init = vt8231_class_init, +}; + static void vt82c686b_register_types(void) { @@ -667,6 +750,7 @@ static void vt82c686b_register_types(void) type_register_static(&vt8231_superio_info); type_register_static(&via_isa_info); type_register_static(&vt82c686b_isa_info); + type_register_static(&vt8231_isa_info); } type_init(vt82c686b_register_types) diff --git a/include/hw/isa/vt82c686.h b/include/hw/isa/vt82c686.h index 0692b9a527..0f01aaa471 100644 --- a/include/hw/isa/vt82c686.h +++ b/include/hw/isa/vt82c686.h @@ -3,6 +3,7 @@ #define TYPE_VT82C686B_ISA "vt82c686b-isa" #define TYPE_VT82C686B_PM "vt82c686b-pm" +#define TYPE_VT8231_ISA "vt8231-isa" #define TYPE_VT8231_PM "vt8231-pm" #define TYPE_VIA_AC97 "via-ac97" #define TYPE_VIA_MC97 "via-mc97" diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index aa3f67eaa4..ac0c23ebc7 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -210,6 +210,7 @@ #define PCI_DEVICE_ID_VIA_82C686B_PM 0x3057 #define PCI_DEVICE_ID_VIA_AC97 0x3058 #define PCI_DEVICE_ID_VIA_MC97 0x3068 +#define PCI_DEVICE_ID_VIA_8231_ISA 0x8231 #define PCI_DEVICE_ID_VIA_8231_PM 0x8235 #define PCI_VENDOR_ID_MARVELL 0x11ab From dcdf98a90155545eeadb63edccd41b7ee5ce201d Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 25 Mar 2021 14:50:39 +0100 Subject: [PATCH 0255/3028] hw/pci-host: Add emulation of Marvell MV64361 PPC system controller The Marvell Discovery II aka. MV64361 is a PowerPC system controller chip that is used on the pegasos2 PPC board. This adds emulation of it that models the device enough to boot guests on this board. The mv643xx.h header with register definitions is taken from Linux 4.15.10 only fixing white space errors, removing not needed parts and changing formatting for QEMU coding style. Signed-off-by: BALATON Zoltan Message-Id: <79545ebd03bfe0665b73d2d7cbc74fdf3d62629e.1616680239.git.balaton@eik.bme.hu> Signed-off-by: David Gibson --- hw/pci-host/Kconfig | 4 + hw/pci-host/meson.build | 2 + hw/pci-host/mv64361.c | 951 ++++++++++++++++++++++++++++++++++ hw/pci-host/mv643xx.h | 918 ++++++++++++++++++++++++++++++++ hw/pci-host/trace-events | 6 + include/hw/pci-host/mv64361.h | 8 + include/hw/pci/pci_ids.h | 1 + 7 files changed, 1890 insertions(+) create mode 100644 hw/pci-host/mv64361.c create mode 100644 hw/pci-host/mv643xx.h create mode 100644 include/hw/pci-host/mv64361.h diff --git a/hw/pci-host/Kconfig b/hw/pci-host/Kconfig index 2ccc96f02c..79c20bf28b 100644 --- a/hw/pci-host/Kconfig +++ b/hw/pci-host/Kconfig @@ -72,3 +72,7 @@ config REMOTE_PCIHOST config SH_PCI bool select PCI + +config MV64361 + bool + select PCI diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index 87a896973e..34b3538beb 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -19,6 +19,8 @@ pci_ss.add(when: 'CONFIG_GRACKLE_PCI', if_true: files('grackle.c')) pci_ss.add(when: 'CONFIG_UNIN_PCI', if_true: files('uninorth.c')) # PowerPC E500 boards pci_ss.add(when: 'CONFIG_PPCE500_PCI', if_true: files('ppce500.c')) +# Pegasos2 +pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c')) # ARM devices pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c')) diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c new file mode 100644 index 0000000000..20510d8680 --- /dev/null +++ b/hw/pci-host/mv64361.c @@ -0,0 +1,951 @@ +/* + * Marvell Discovery II MV64361 System Controller for + * QEMU PowerPC CHRP (Genesi/bPlan Pegasos II) hardware System Emulator + * + * Copyright (c) 2018-2020 BALATON Zoltan + * + * This work is licensed under the GNU GPL license version 2 or later. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "hw/irq.h" +#include "hw/intc/i8259.h" +#include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "trace.h" +#include "hw/pci-host/mv64361.h" +#include "mv643xx.h" + +#define TYPE_MV64361_PCI_BRIDGE "mv64361-pcibridge" + +static void mv64361_pcibridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->vendor_id = PCI_VENDOR_ID_MARVELL; + k->device_id = PCI_DEVICE_ID_MARVELL_MV6436X; + k->class_id = PCI_CLASS_BRIDGE_HOST; + /* + * PCI-facing part of the host bridge, + * not usable without the host-facing part + */ + dc->user_creatable = false; +} + +static const TypeInfo mv64361_pcibridge_info = { + .name = TYPE_MV64361_PCI_BRIDGE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = mv64361_pcibridge_class_init, + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, +}; + + +#define TYPE_MV64361_PCI "mv64361-pcihost" +OBJECT_DECLARE_SIMPLE_TYPE(MV64361PCIState, MV64361_PCI) + +struct MV64361PCIState { + PCIHostState parent_obj; + + uint8_t index; + MemoryRegion io; + MemoryRegion mem; + qemu_irq irq[PCI_NUM_PINS]; + + uint32_t io_base; + uint32_t io_size; + uint32_t mem_base[4]; + uint32_t mem_size[4]; + uint64_t remap[5]; +}; + +static int mv64361_pcihost_map_irq(PCIDevice *pci_dev, int n) +{ + return (n + PCI_SLOT(pci_dev->devfn)) % PCI_NUM_PINS; +} + +static void mv64361_pcihost_set_irq(void *opaque, int n, int level) +{ + MV64361PCIState *s = opaque; + qemu_set_irq(s->irq[n], level); +} + +static void mv64361_pcihost_realize(DeviceState *dev, Error **errp) +{ + MV64361PCIState *s = MV64361_PCI(dev); + PCIHostState *h = PCI_HOST_BRIDGE(dev); + char *name; + + name = g_strdup_printf("pci%d-io", s->index); + memory_region_init(&s->io, OBJECT(dev), name, 0x10000); + g_free(name); + name = g_strdup_printf("pci%d-mem", s->index); + memory_region_init(&s->mem, OBJECT(dev), name, 1ULL << 32); + g_free(name); + name = g_strdup_printf("pci.%d", s->index); + h->bus = pci_register_root_bus(dev, name, mv64361_pcihost_set_irq, + mv64361_pcihost_map_irq, dev, + &s->mem, &s->io, 0, 4, TYPE_PCI_BUS); + g_free(name); + pci_create_simple(h->bus, 0, TYPE_MV64361_PCI_BRIDGE); +} + +static Property mv64361_pcihost_props[] = { + DEFINE_PROP_UINT8("index", MV64361PCIState, index, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void mv64361_pcihost_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = mv64361_pcihost_realize; + device_class_set_props(dc, mv64361_pcihost_props); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); +} + +static const TypeInfo mv64361_pcihost_info = { + .name = TYPE_MV64361_PCI, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(MV64361PCIState), + .class_init = mv64361_pcihost_class_init, +}; + +static void mv64361_pci_register_types(void) +{ + type_register_static(&mv64361_pcihost_info); + type_register_static(&mv64361_pcibridge_info); +} + +type_init(mv64361_pci_register_types) + + +OBJECT_DECLARE_SIMPLE_TYPE(MV64361State, MV64361) + +struct MV64361State { + SysBusDevice parent_obj; + + MemoryRegion regs; + MV64361PCIState pci[2]; + MemoryRegion cpu_win[19]; + qemu_irq cpu_irq; + + /* registers state */ + uint32_t cpu_conf; + uint32_t regs_base; + uint32_t base_addr_enable; + uint64_t main_int_cr; + uint64_t cpu0_int_mask; + uint32_t gpp_io; + uint32_t gpp_level; + uint32_t gpp_value; + uint32_t gpp_int_cr; + uint32_t gpp_int_mask; + bool gpp_int_level; +}; + +enum mv64361_irq_cause { + MV64361_IRQ_DEVERR = 1, + MV64361_IRQ_DMAERR = 2, + MV64361_IRQ_CPUERR = 3, + MV64361_IRQ_IDMA0 = 4, + MV64361_IRQ_IDMA1 = 5, + MV64361_IRQ_IDMA2 = 6, + MV64361_IRQ_IDMA3 = 7, + MV64361_IRQ_TIMER0 = 8, + MV64361_IRQ_TIMER1 = 9, + MV64361_IRQ_TIMER2 = 10, + MV64361_IRQ_TIMER3 = 11, + MV64361_IRQ_PCI0 = 12, + MV64361_IRQ_SRAMERR = 13, + MV64361_IRQ_GBEERR = 14, + MV64361_IRQ_CERR = 15, + MV64361_IRQ_PCI1 = 16, + MV64361_IRQ_DRAMERR = 17, + MV64361_IRQ_WDNMI = 18, + MV64361_IRQ_WDE = 19, + MV64361_IRQ_PCI0IN = 20, + MV64361_IRQ_PCI0OUT = 21, + MV64361_IRQ_PCI1IN = 22, + MV64361_IRQ_PCI1OUT = 23, + MV64361_IRQ_P1_GPP0_7 = 24, + MV64361_IRQ_P1_GPP8_15 = 25, + MV64361_IRQ_P1_GPP16_23 = 26, + MV64361_IRQ_P1_GPP24_31 = 27, + MV64361_IRQ_P1_CPU_DB = 28, + /* 29-31: reserved */ + MV64361_IRQ_GBE0 = 32, + MV64361_IRQ_GBE1 = 33, + MV64361_IRQ_GBE2 = 34, + /* 35: reserved */ + MV64361_IRQ_SDMA0 = 36, + MV64361_IRQ_TWSI = 37, + MV64361_IRQ_SDMA1 = 38, + MV64361_IRQ_BRG = 39, + MV64361_IRQ_MPSC0 = 40, + MV64361_IRQ_MPSC1 = 41, + MV64361_IRQ_G0RX = 42, + MV64361_IRQ_G0TX = 43, + MV64361_IRQ_G0MISC = 44, + MV64361_IRQ_G1RX = 45, + MV64361_IRQ_G1TX = 46, + MV64361_IRQ_G1MISC = 47, + MV64361_IRQ_G2RX = 48, + MV64361_IRQ_G2TX = 49, + MV64361_IRQ_G2MISC = 50, + /* 51-55: reserved */ + MV64361_IRQ_P0_GPP0_7 = 56, + MV64361_IRQ_P0_GPP8_15 = 57, + MV64361_IRQ_P0_GPP16_23 = 58, + MV64361_IRQ_P0_GPP24_31 = 59, + MV64361_IRQ_P0_CPU_DB = 60, + /* 61-63: reserved */ +}; + +PCIBus *mv64361_get_pci_bus(DeviceState *dev, int n) +{ + MV64361State *mv = MV64361(dev); + return PCI_HOST_BRIDGE(&mv->pci[n])->bus; +} + +static void unmap_region(MemoryRegion *mr) +{ + if (memory_region_is_mapped(mr)) { + memory_region_del_subregion(get_system_memory(), mr); + object_unparent(OBJECT(mr)); + } +} + +static void map_pci_region(MemoryRegion *mr, MemoryRegion *parent, + struct Object *owner, const char *name, + hwaddr poffs, uint64_t size, hwaddr moffs) +{ + memory_region_init_alias(mr, owner, name, parent, poffs, size); + memory_region_add_subregion(get_system_memory(), moffs, mr); + trace_mv64361_region_map(name, poffs, size, moffs); +} + +static void set_mem_windows(MV64361State *s, uint32_t val) +{ + MV64361PCIState *p; + MemoryRegion *mr; + uint32_t mask; + int i; + + val &= 0x1fffff; + for (mask = 1, i = 0; i < 21; i++, mask <<= 1) { + if ((val & mask) != (s->base_addr_enable & mask)) { + trace_mv64361_region_enable(!(val & mask) ? "enable" : "disable", i); + /* + * 0-3 are SDRAM chip selects but we map all RAM directly + * 4-7 are device chip selects (not sure what those are) + * 8 is Boot device (ROM) chip select but we map that directly too + */ + if (i == 9) { + p = &s->pci[0]; + mr = &s->cpu_win[i]; + unmap_region(mr); + if (!(val & mask)) { + map_pci_region(mr, &p->io, OBJECT(s), "pci0-io-win", + p->remap[4], (p->io_size + 1) << 16, + (p->io_base & 0xfffff) << 16); + } + } else if (i == 10) { + p = &s->pci[0]; + mr = &s->cpu_win[i]; + unmap_region(mr); + if (!(val & mask)) { + map_pci_region(mr, &p->mem, OBJECT(s), "pci0-mem0-win", + p->remap[0], (p->mem_size[0] + 1) << 16, + (p->mem_base[0] & 0xfffff) << 16); + } + } else if (i == 11) { + p = &s->pci[0]; + mr = &s->cpu_win[i]; + unmap_region(mr); + if (!(val & mask)) { + map_pci_region(mr, &p->mem, OBJECT(s), "pci0-mem1-win", + p->remap[1], (p->mem_size[1] + 1) << 16, + (p->mem_base[1] & 0xfffff) << 16); + } + } else if (i == 12) { + p = &s->pci[0]; + mr = &s->cpu_win[i]; + unmap_region(mr); + if (!(val & mask)) { + map_pci_region(mr, &p->mem, OBJECT(s), "pci0-mem2-win", + p->remap[2], (p->mem_size[2] + 1) << 16, + (p->mem_base[2] & 0xfffff) << 16); + } + } else if (i == 13) { + p = &s->pci[0]; + mr = &s->cpu_win[i]; + unmap_region(mr); + if (!(val & mask)) { + map_pci_region(mr, &p->mem, OBJECT(s), "pci0-mem3-win", + p->remap[3], (p->mem_size[3] + 1) << 16, + (p->mem_base[3] & 0xfffff) << 16); + } + } else if (i == 14) { + p = &s->pci[1]; + mr = &s->cpu_win[i]; + unmap_region(mr); + if (!(val & mask)) { + map_pci_region(mr, &p->io, OBJECT(s), "pci1-io-win", + p->remap[4], (p->io_size + 1) << 16, + (p->io_base & 0xfffff) << 16); + } + } else if (i == 15) { + p = &s->pci[1]; + mr = &s->cpu_win[i]; + unmap_region(mr); + if (!(val & mask)) { + map_pci_region(mr, &p->mem, OBJECT(s), "pci1-mem0-win", + p->remap[0], (p->mem_size[0] + 1) << 16, + (p->mem_base[0] & 0xfffff) << 16); + } + } else if (i == 16) { + p = &s->pci[1]; + mr = &s->cpu_win[i]; + unmap_region(mr); + if (!(val & mask)) { + map_pci_region(mr, &p->mem, OBJECT(s), "pci1-mem1-win", + p->remap[1], (p->mem_size[1] + 1) << 16, + (p->mem_base[1] & 0xfffff) << 16); + } + } else if (i == 17) { + p = &s->pci[1]; + mr = &s->cpu_win[i]; + unmap_region(mr); + if (!(val & mask)) { + map_pci_region(mr, &p->mem, OBJECT(s), "pci1-mem2-win", + p->remap[2], (p->mem_size[2] + 1) << 16, + (p->mem_base[2] & 0xfffff) << 16); + } + } else if (i == 18) { + p = &s->pci[1]; + mr = &s->cpu_win[i]; + unmap_region(mr); + if (!(val & mask)) { + map_pci_region(mr, &p->mem, OBJECT(s), "pci1-mem3-win", + p->remap[3], (p->mem_size[3] + 1) << 16, + (p->mem_base[3] & 0xfffff) << 16); + } + /* 19 is integrated SRAM */ + } else if (i == 20) { + mr = &s->regs; + unmap_region(mr); + if (!(val & mask)) { + memory_region_add_subregion(get_system_memory(), + (s->regs_base & 0xfffff) << 16, mr); + } + } + } + } + s->base_addr_enable = val; +} + +static void mv64361_update_irq(void *opaque, int n, int level) +{ + MV64361State *s = opaque; + uint64_t val = s->main_int_cr; + + if (level) { + val |= BIT_ULL(n); + } else { + val &= ~BIT_ULL(n); + } + if ((s->main_int_cr & s->cpu0_int_mask) != (val & s->cpu0_int_mask)) { + qemu_set_irq(s->cpu_irq, level); + } + s->main_int_cr = val; +} + +static uint64_t mv64361_read(void *opaque, hwaddr addr, unsigned int size) +{ + MV64361State *s = MV64361(opaque); + uint32_t ret = 0; + + switch (addr) { + case MV64340_CPU_CONFIG: + ret = s->cpu_conf; + break; + case MV64340_PCI_0_IO_BASE_ADDR: + ret = s->pci[0].io_base; + break; + case MV64340_PCI_0_IO_SIZE: + ret = s->pci[0].io_size; + break; + case MV64340_PCI_0_IO_ADDR_REMAP: + ret = s->pci[0].remap[4] >> 16; + break; + case MV64340_PCI_0_MEMORY0_BASE_ADDR: + ret = s->pci[0].mem_base[0]; + break; + case MV64340_PCI_0_MEMORY0_SIZE: + ret = s->pci[0].mem_size[0]; + break; + case MV64340_PCI_0_MEMORY0_LOW_ADDR_REMAP: + ret = (s->pci[0].remap[0] & 0xffff0000) >> 16; + break; + case MV64340_PCI_0_MEMORY0_HIGH_ADDR_REMAP: + ret = s->pci[0].remap[0] >> 32; + break; + case MV64340_PCI_0_MEMORY1_BASE_ADDR: + ret = s->pci[0].mem_base[1]; + break; + case MV64340_PCI_0_MEMORY1_SIZE: + ret = s->pci[0].mem_size[1]; + break; + case MV64340_PCI_0_MEMORY1_LOW_ADDR_REMAP: + ret = (s->pci[0].remap[1] & 0xffff0000) >> 16; + break; + case MV64340_PCI_0_MEMORY1_HIGH_ADDR_REMAP: + ret = s->pci[0].remap[1] >> 32; + break; + case MV64340_PCI_0_MEMORY2_BASE_ADDR: + ret = s->pci[0].mem_base[2]; + break; + case MV64340_PCI_0_MEMORY2_SIZE: + ret = s->pci[0].mem_size[2]; + break; + case MV64340_PCI_0_MEMORY2_LOW_ADDR_REMAP: + ret = (s->pci[0].remap[2] & 0xffff0000) >> 16; + break; + case MV64340_PCI_0_MEMORY2_HIGH_ADDR_REMAP: + ret = s->pci[0].remap[2] >> 32; + break; + case MV64340_PCI_0_MEMORY3_BASE_ADDR: + ret = s->pci[0].mem_base[3]; + break; + case MV64340_PCI_0_MEMORY3_SIZE: + ret = s->pci[0].mem_size[3]; + break; + case MV64340_PCI_0_MEMORY3_LOW_ADDR_REMAP: + ret = (s->pci[0].remap[3] & 0xffff0000) >> 16; + break; + case MV64340_PCI_0_MEMORY3_HIGH_ADDR_REMAP: + ret = s->pci[0].remap[3] >> 32; + break; + case MV64340_PCI_1_IO_BASE_ADDR: + ret = s->pci[1].io_base; + break; + case MV64340_PCI_1_IO_SIZE: + ret = s->pci[1].io_size; + break; + case MV64340_PCI_1_IO_ADDR_REMAP: + ret = s->pci[1].remap[4] >> 16; + break; + case MV64340_PCI_1_MEMORY0_BASE_ADDR: + ret = s->pci[1].mem_base[0]; + break; + case MV64340_PCI_1_MEMORY0_SIZE: + ret = s->pci[1].mem_size[0]; + break; + case MV64340_PCI_1_MEMORY0_LOW_ADDR_REMAP: + ret = (s->pci[1].remap[0] & 0xffff0000) >> 16; + break; + case MV64340_PCI_1_MEMORY0_HIGH_ADDR_REMAP: + ret = s->pci[1].remap[0] >> 32; + break; + case MV64340_PCI_1_MEMORY1_BASE_ADDR: + ret = s->pci[1].mem_base[1]; + break; + case MV64340_PCI_1_MEMORY1_SIZE: + ret = s->pci[1].mem_size[1]; + break; + case MV64340_PCI_1_MEMORY1_LOW_ADDR_REMAP: + ret = (s->pci[1].remap[1] & 0xffff0000) >> 16; + break; + case MV64340_PCI_1_MEMORY1_HIGH_ADDR_REMAP: + ret = s->pci[1].remap[1] >> 32; + break; + case MV64340_PCI_1_MEMORY2_BASE_ADDR: + ret = s->pci[1].mem_base[2]; + break; + case MV64340_PCI_1_MEMORY2_SIZE: + ret = s->pci[1].mem_size[2]; + break; + case MV64340_PCI_1_MEMORY2_LOW_ADDR_REMAP: + ret = (s->pci[1].remap[2] & 0xffff0000) >> 16; + break; + case MV64340_PCI_1_MEMORY2_HIGH_ADDR_REMAP: + ret = s->pci[1].remap[2] >> 32; + break; + case MV64340_PCI_1_MEMORY3_BASE_ADDR: + ret = s->pci[1].mem_base[3]; + break; + case MV64340_PCI_1_MEMORY3_SIZE: + ret = s->pci[1].mem_size[3]; + break; + case MV64340_PCI_1_MEMORY3_LOW_ADDR_REMAP: + ret = (s->pci[1].remap[3] & 0xffff0000) >> 16; + break; + case MV64340_PCI_1_MEMORY3_HIGH_ADDR_REMAP: + ret = s->pci[1].remap[3] >> 32; + break; + case MV64340_INTERNAL_SPACE_BASE_ADDR: + ret = s->regs_base; + break; + case MV64340_BASE_ADDR_ENABLE: + ret = s->base_addr_enable; + break; + case MV64340_PCI_0_CONFIG_ADDR: + ret = pci_host_conf_le_ops.read(PCI_HOST_BRIDGE(&s->pci[0]), 0, size); + break; + case MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG ... + MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG + 3: + ret = pci_host_data_le_ops.read(PCI_HOST_BRIDGE(&s->pci[0]), + addr - MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG, size); + break; + case MV64340_PCI_1_CONFIG_ADDR: + ret = pci_host_conf_le_ops.read(PCI_HOST_BRIDGE(&s->pci[1]), 0, size); + break; + case MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG ... + MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG + 3: + ret = pci_host_data_le_ops.read(PCI_HOST_BRIDGE(&s->pci[1]), + addr - MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG, size); + break; + case MV64340_PCI_1_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG: + /* FIXME: Should this be sent via the PCI bus somehow? */ + if (s->gpp_int_level && (s->gpp_value & BIT(31))) { + ret = pic_read_irq(isa_pic); + } + break; + case MV64340_MAIN_INTERRUPT_CAUSE_LOW: + ret = s->main_int_cr; + break; + case MV64340_MAIN_INTERRUPT_CAUSE_HIGH: + ret = s->main_int_cr >> 32; + break; + case MV64340_CPU_INTERRUPT0_MASK_LOW: + ret = s->cpu0_int_mask; + break; + case MV64340_CPU_INTERRUPT0_MASK_HIGH: + ret = s->cpu0_int_mask >> 32; + break; + case MV64340_CPU_INTERRUPT0_SELECT_CAUSE: + ret = s->main_int_cr; + if (s->main_int_cr & s->cpu0_int_mask) { + if (!(s->main_int_cr & s->cpu0_int_mask & 0xffffffff)) { + ret = s->main_int_cr >> 32 | BIT(30); + } else if ((s->main_int_cr & s->cpu0_int_mask) >> 32) { + ret |= BIT(31); + } + } + break; + case MV64340_CUNIT_ARBITER_CONTROL_REG: + ret = 0x11ff0000 | (s->gpp_int_level << 10); + break; + case MV64340_GPP_IO_CONTROL: + ret = s->gpp_io; + break; + case MV64340_GPP_LEVEL_CONTROL: + ret = s->gpp_level; + break; + case MV64340_GPP_VALUE: + ret = s->gpp_value; + break; + case MV64340_GPP_VALUE_SET: + case MV64340_GPP_VALUE_CLEAR: + ret = 0; + break; + case MV64340_GPP_INTERRUPT_CAUSE: + ret = s->gpp_int_cr; + break; + case MV64340_GPP_INTERRUPT_MASK0: + case MV64340_GPP_INTERRUPT_MASK1: + ret = s->gpp_int_mask; + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register read 0x%" + HWADDR_PRIx "\n", __func__, addr); + break; + } + if (addr != MV64340_PCI_1_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG) { + trace_mv64361_reg_read(addr, ret); + } + return ret; +} + +static void warn_swap_bit(uint64_t val) +{ + if ((val & 0x3000000ULL) >> 24 != 1) { + qemu_log_mask(LOG_UNIMP, "%s: Data swap not implemented", __func__); + } +} + +static void mv64361_set_pci_mem_remap(MV64361State *s, int bus, int idx, + uint64_t val, bool high) +{ + if (high) { + s->pci[bus].remap[idx] = val; + } else { + s->pci[bus].remap[idx] &= 0xffffffff00000000ULL; + s->pci[bus].remap[idx] |= (val & 0xffffULL) << 16; + } +} + +static void mv64361_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int size) +{ + MV64361State *s = MV64361(opaque); + + trace_mv64361_reg_write(addr, val); + switch (addr) { + case MV64340_CPU_CONFIG: + s->cpu_conf = val & 0xe4e3bffULL; + s->cpu_conf |= BIT(23); + break; + case MV64340_PCI_0_IO_BASE_ADDR: + s->pci[0].io_base = val & 0x30fffffULL; + warn_swap_bit(val); + if (!(s->cpu_conf & BIT(27))) { + s->pci[0].remap[4] = (val & 0xffffULL) << 16; + } + break; + case MV64340_PCI_0_IO_SIZE: + s->pci[0].io_size = val & 0xffffULL; + break; + case MV64340_PCI_0_IO_ADDR_REMAP: + s->pci[0].remap[4] = (val & 0xffffULL) << 16; + break; + case MV64340_PCI_0_MEMORY0_BASE_ADDR: + s->pci[0].mem_base[0] = val & 0x70fffffULL; + warn_swap_bit(val); + if (!(s->cpu_conf & BIT(27))) { + mv64361_set_pci_mem_remap(s, 0, 0, val, false); + } + break; + case MV64340_PCI_0_MEMORY0_SIZE: + s->pci[0].mem_size[0] = val & 0xffffULL; + break; + case MV64340_PCI_0_MEMORY0_LOW_ADDR_REMAP: + case MV64340_PCI_0_MEMORY0_HIGH_ADDR_REMAP: + mv64361_set_pci_mem_remap(s, 0, 0, val, + (addr == MV64340_PCI_0_MEMORY0_HIGH_ADDR_REMAP)); + break; + case MV64340_PCI_0_MEMORY1_BASE_ADDR: + s->pci[0].mem_base[1] = val & 0x70fffffULL; + warn_swap_bit(val); + if (!(s->cpu_conf & BIT(27))) { + mv64361_set_pci_mem_remap(s, 0, 1, val, false); + } + break; + case MV64340_PCI_0_MEMORY1_SIZE: + s->pci[0].mem_size[1] = val & 0xffffULL; + break; + case MV64340_PCI_0_MEMORY1_LOW_ADDR_REMAP: + case MV64340_PCI_0_MEMORY1_HIGH_ADDR_REMAP: + mv64361_set_pci_mem_remap(s, 0, 1, val, + (addr == MV64340_PCI_0_MEMORY1_HIGH_ADDR_REMAP)); + break; + case MV64340_PCI_0_MEMORY2_BASE_ADDR: + s->pci[0].mem_base[2] = val & 0x70fffffULL; + warn_swap_bit(val); + if (!(s->cpu_conf & BIT(27))) { + mv64361_set_pci_mem_remap(s, 0, 2, val, false); + } + break; + case MV64340_PCI_0_MEMORY2_SIZE: + s->pci[0].mem_size[2] = val & 0xffffULL; + break; + case MV64340_PCI_0_MEMORY2_LOW_ADDR_REMAP: + case MV64340_PCI_0_MEMORY2_HIGH_ADDR_REMAP: + mv64361_set_pci_mem_remap(s, 0, 2, val, + (addr == MV64340_PCI_0_MEMORY2_HIGH_ADDR_REMAP)); + break; + case MV64340_PCI_0_MEMORY3_BASE_ADDR: + s->pci[0].mem_base[3] = val & 0x70fffffULL; + warn_swap_bit(val); + if (!(s->cpu_conf & BIT(27))) { + mv64361_set_pci_mem_remap(s, 0, 3, val, false); + } + break; + case MV64340_PCI_0_MEMORY3_SIZE: + s->pci[0].mem_size[3] = val & 0xffffULL; + break; + case MV64340_PCI_0_MEMORY3_LOW_ADDR_REMAP: + case MV64340_PCI_0_MEMORY3_HIGH_ADDR_REMAP: + mv64361_set_pci_mem_remap(s, 0, 3, val, + (addr == MV64340_PCI_0_MEMORY3_HIGH_ADDR_REMAP)); + break; + case MV64340_PCI_1_IO_BASE_ADDR: + s->pci[1].io_base = val & 0x30fffffULL; + warn_swap_bit(val); + break; + if (!(s->cpu_conf & BIT(27))) { + s->pci[1].remap[4] = (val & 0xffffULL) << 16; + } + break; + case MV64340_PCI_1_IO_SIZE: + s->pci[1].io_size = val & 0xffffULL; + break; + case MV64340_PCI_1_MEMORY0_BASE_ADDR: + s->pci[1].mem_base[0] = val & 0x70fffffULL; + warn_swap_bit(val); + if (!(s->cpu_conf & BIT(27))) { + mv64361_set_pci_mem_remap(s, 1, 0, val, false); + } + break; + case MV64340_PCI_1_MEMORY0_SIZE: + s->pci[1].mem_size[0] = val & 0xffffULL; + break; + case MV64340_PCI_1_MEMORY0_LOW_ADDR_REMAP: + case MV64340_PCI_1_MEMORY0_HIGH_ADDR_REMAP: + mv64361_set_pci_mem_remap(s, 1, 0, val, + (addr == MV64340_PCI_1_MEMORY0_HIGH_ADDR_REMAP)); + break; + case MV64340_PCI_1_MEMORY1_BASE_ADDR: + s->pci[1].mem_base[1] = val & 0x70fffffULL; + warn_swap_bit(val); + if (!(s->cpu_conf & BIT(27))) { + mv64361_set_pci_mem_remap(s, 1, 1, val, false); + } + break; + case MV64340_PCI_1_MEMORY1_SIZE: + s->pci[1].mem_size[1] = val & 0xffffULL; + break; + case MV64340_PCI_1_MEMORY1_LOW_ADDR_REMAP: + case MV64340_PCI_1_MEMORY1_HIGH_ADDR_REMAP: + mv64361_set_pci_mem_remap(s, 1, 1, val, + (addr == MV64340_PCI_1_MEMORY1_HIGH_ADDR_REMAP)); + break; + case MV64340_PCI_1_MEMORY2_BASE_ADDR: + s->pci[1].mem_base[2] = val & 0x70fffffULL; + warn_swap_bit(val); + if (!(s->cpu_conf & BIT(27))) { + mv64361_set_pci_mem_remap(s, 1, 2, val, false); + } + break; + case MV64340_PCI_1_MEMORY2_SIZE: + s->pci[1].mem_size[2] = val & 0xffffULL; + break; + case MV64340_PCI_1_MEMORY2_LOW_ADDR_REMAP: + case MV64340_PCI_1_MEMORY2_HIGH_ADDR_REMAP: + mv64361_set_pci_mem_remap(s, 1, 2, val, + (addr == MV64340_PCI_1_MEMORY2_HIGH_ADDR_REMAP)); + break; + case MV64340_PCI_1_MEMORY3_BASE_ADDR: + s->pci[1].mem_base[3] = val & 0x70fffffULL; + warn_swap_bit(val); + if (!(s->cpu_conf & BIT(27))) { + mv64361_set_pci_mem_remap(s, 1, 3, val, false); + } + break; + case MV64340_PCI_1_MEMORY3_SIZE: + s->pci[1].mem_size[3] = val & 0xffffULL; + break; + case MV64340_PCI_1_MEMORY3_LOW_ADDR_REMAP: + case MV64340_PCI_1_MEMORY3_HIGH_ADDR_REMAP: + mv64361_set_pci_mem_remap(s, 1, 3, val, + (addr == MV64340_PCI_1_MEMORY3_HIGH_ADDR_REMAP)); + break; + case MV64340_INTERNAL_SPACE_BASE_ADDR: + s->regs_base = val & 0xfffffULL; + break; + case MV64340_BASE_ADDR_ENABLE: + set_mem_windows(s, val); + break; + case MV64340_PCI_0_CONFIG_ADDR: + pci_host_conf_le_ops.write(PCI_HOST_BRIDGE(&s->pci[0]), 0, val, size); + break; + case MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG ... + MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG + 3: + pci_host_data_le_ops.write(PCI_HOST_BRIDGE(&s->pci[0]), + addr - MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG, val, size); + break; + case MV64340_PCI_1_CONFIG_ADDR: + pci_host_conf_le_ops.write(PCI_HOST_BRIDGE(&s->pci[1]), 0, val, size); + break; + case MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG ... + MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG + 3: + pci_host_data_le_ops.write(PCI_HOST_BRIDGE(&s->pci[1]), + addr - MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG, val, size); + break; + case MV64340_CPU_INTERRUPT0_MASK_LOW: + s->cpu0_int_mask &= 0xffffffff00000000ULL; + s->cpu0_int_mask |= val & 0xffffffffULL; + break; + case MV64340_CPU_INTERRUPT0_MASK_HIGH: + s->cpu0_int_mask &= 0xffffffffULL; + s->cpu0_int_mask |= val << 32; + break; + case MV64340_CUNIT_ARBITER_CONTROL_REG: + s->gpp_int_level = !!(val & BIT(10)); + break; + case MV64340_GPP_IO_CONTROL: + s->gpp_io = val; + break; + case MV64340_GPP_LEVEL_CONTROL: + s->gpp_level = val; + break; + case MV64340_GPP_VALUE: + s->gpp_value &= ~s->gpp_io; + s->gpp_value |= val & s->gpp_io; + break; + case MV64340_GPP_VALUE_SET: + s->gpp_value |= val & s->gpp_io; + break; + case MV64340_GPP_VALUE_CLEAR: + s->gpp_value &= ~(val & s->gpp_io); + break; + case MV64340_GPP_INTERRUPT_CAUSE: + if (!s->gpp_int_level && val != s->gpp_int_cr) { + int i; + uint32_t ch = s->gpp_int_cr ^ val; + s->gpp_int_cr = val; + for (i = 0; i < 4; i++) { + if ((ch & 0xff << i) && !(val & 0xff << i)) { + mv64361_update_irq(opaque, MV64361_IRQ_P0_GPP0_7 + i, 0); + } + } + } else { + s->gpp_int_cr = val; + } + break; + case MV64340_GPP_INTERRUPT_MASK0: + case MV64340_GPP_INTERRUPT_MASK1: + s->gpp_int_mask = val; + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: Unimplemented register write 0x%" + HWADDR_PRIx " = %"PRIx64"\n", __func__, addr, val); + break; + } +} + +static const MemoryRegionOps mv64361_ops = { + .read = mv64361_read, + .write = mv64361_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void mv64361_gpp_irq(void *opaque, int n, int level) +{ + MV64361State *s = opaque; + uint32_t mask = BIT(n); + uint32_t val = s->gpp_value & ~mask; + + if (s->gpp_level & mask) { + level = !level; + } + val |= level << n; + if (val > s->gpp_value) { + s->gpp_value = val; + s->gpp_int_cr |= mask; + if (s->gpp_int_mask & mask) { + mv64361_update_irq(opaque, MV64361_IRQ_P0_GPP0_7 + n / 8, 1); + } + } else if (val < s->gpp_value) { + int b = n / 8; + s->gpp_value = val; + if (s->gpp_int_level && !(val & 0xff << b)) { + mv64361_update_irq(opaque, MV64361_IRQ_P0_GPP0_7 + b, 0); + } + } +} + +static void mv64361_realize(DeviceState *dev, Error **errp) +{ + MV64361State *s = MV64361(dev); + int i; + + s->base_addr_enable = 0x1fffff; + memory_region_init_io(&s->regs, OBJECT(s), &mv64361_ops, s, + TYPE_MV64361, 0x10000); + for (i = 0; i < 2; i++) { + g_autofree char *name = g_strdup_printf("pcihost%d", i); + object_initialize_child(OBJECT(dev), name, &s->pci[i], + TYPE_MV64361_PCI); + DeviceState *pci = DEVICE(&s->pci[i]); + qdev_prop_set_uint8(pci, "index", i); + sysbus_realize_and_unref(SYS_BUS_DEVICE(pci), &error_fatal); + } + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cpu_irq); + qdev_init_gpio_in_named(dev, mv64361_gpp_irq, "gpp", 32); + /* FIXME: PCI IRQ connections may be board specific */ + for (i = 0; i < PCI_NUM_PINS; i++) { + s->pci[1].irq[i] = qdev_get_gpio_in_named(dev, "gpp", 12 + i); + } +} + +static void mv64361_reset(DeviceState *dev) +{ + MV64361State *s = MV64361(dev); + int i, j; + + /* + * These values may be board specific + * Real chip supports init from an eprom but that's not modelled + */ + set_mem_windows(s, 0x1fffff); + s->cpu_conf = 0x28000ff; + s->regs_base = 0x100f100; + s->pci[0].io_base = 0x100f800; + s->pci[0].io_size = 0xff; + s->pci[0].mem_base[0] = 0x100c000; + s->pci[0].mem_size[0] = 0x1fff; + s->pci[0].mem_base[1] = 0x100f900; + s->pci[0].mem_size[1] = 0xff; + s->pci[0].mem_base[2] = 0x100f400; + s->pci[0].mem_size[2] = 0x1ff; + s->pci[0].mem_base[3] = 0x100f600; + s->pci[0].mem_size[3] = 0x1ff; + s->pci[1].io_base = 0x100fe00; + s->pci[1].io_size = 0xff; + s->pci[1].mem_base[0] = 0x1008000; + s->pci[1].mem_size[0] = 0x3fff; + s->pci[1].mem_base[1] = 0x100fd00; + s->pci[1].mem_size[1] = 0xff; + s->pci[1].mem_base[2] = 0x1002600; + s->pci[1].mem_size[2] = 0x1ff; + s->pci[1].mem_base[3] = 0x100ff80; + s->pci[1].mem_size[3] = 0x7f; + for (i = 0; i < 2; i++) { + for (j = 0; j < 4; j++) { + s->pci[i].remap[j] = s->pci[i].mem_base[j] << 16; + } + } + s->pci[0].remap[1] = 0; + s->pci[1].remap[1] = 0; + set_mem_windows(s, 0xfbfff); +} + +static void mv64361_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = mv64361_realize; + dc->reset = mv64361_reset; +} + +static const TypeInfo mv64361_type_info = { + .name = TYPE_MV64361, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MV64361State), + .class_init = mv64361_class_init, +}; + +static void mv64361_register_types(void) +{ + type_register_static(&mv64361_type_info); +} + +type_init(mv64361_register_types) diff --git a/hw/pci-host/mv643xx.h b/hw/pci-host/mv643xx.h new file mode 100644 index 0000000000..cd26a43f18 --- /dev/null +++ b/hw/pci-host/mv643xx.h @@ -0,0 +1,918 @@ +/* + * mv643xx.h - MV-643XX Internal registers definition file. + * + * Copyright 2002 Momentum Computer, Inc. + * Author: Matthew Dharm + * Copyright 2002 GALILEO TECHNOLOGY, LTD. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef ASM_MV643XX_H +#define ASM_MV643XX_H + +/****************************************/ +/* Processor Address Space */ +/****************************************/ + +/* DDR SDRAM BAR and size registers */ + +#define MV64340_CS_0_BASE_ADDR 0x008 +#define MV64340_CS_0_SIZE 0x010 +#define MV64340_CS_1_BASE_ADDR 0x208 +#define MV64340_CS_1_SIZE 0x210 +#define MV64340_CS_2_BASE_ADDR 0x018 +#define MV64340_CS_2_SIZE 0x020 +#define MV64340_CS_3_BASE_ADDR 0x218 +#define MV64340_CS_3_SIZE 0x220 + +/* Devices BAR and size registers */ + +#define MV64340_DEV_CS0_BASE_ADDR 0x028 +#define MV64340_DEV_CS0_SIZE 0x030 +#define MV64340_DEV_CS1_BASE_ADDR 0x228 +#define MV64340_DEV_CS1_SIZE 0x230 +#define MV64340_DEV_CS2_BASE_ADDR 0x248 +#define MV64340_DEV_CS2_SIZE 0x250 +#define MV64340_DEV_CS3_BASE_ADDR 0x038 +#define MV64340_DEV_CS3_SIZE 0x040 +#define MV64340_BOOTCS_BASE_ADDR 0x238 +#define MV64340_BOOTCS_SIZE 0x240 + +/* PCI 0 BAR and size registers */ + +#define MV64340_PCI_0_IO_BASE_ADDR 0x048 +#define MV64340_PCI_0_IO_SIZE 0x050 +#define MV64340_PCI_0_MEMORY0_BASE_ADDR 0x058 +#define MV64340_PCI_0_MEMORY0_SIZE 0x060 +#define MV64340_PCI_0_MEMORY1_BASE_ADDR 0x080 +#define MV64340_PCI_0_MEMORY1_SIZE 0x088 +#define MV64340_PCI_0_MEMORY2_BASE_ADDR 0x258 +#define MV64340_PCI_0_MEMORY2_SIZE 0x260 +#define MV64340_PCI_0_MEMORY3_BASE_ADDR 0x280 +#define MV64340_PCI_0_MEMORY3_SIZE 0x288 + +/* PCI 1 BAR and size registers */ +#define MV64340_PCI_1_IO_BASE_ADDR 0x090 +#define MV64340_PCI_1_IO_SIZE 0x098 +#define MV64340_PCI_1_MEMORY0_BASE_ADDR 0x0a0 +#define MV64340_PCI_1_MEMORY0_SIZE 0x0a8 +#define MV64340_PCI_1_MEMORY1_BASE_ADDR 0x0b0 +#define MV64340_PCI_1_MEMORY1_SIZE 0x0b8 +#define MV64340_PCI_1_MEMORY2_BASE_ADDR 0x2a0 +#define MV64340_PCI_1_MEMORY2_SIZE 0x2a8 +#define MV64340_PCI_1_MEMORY3_BASE_ADDR 0x2b0 +#define MV64340_PCI_1_MEMORY3_SIZE 0x2b8 + +/* SRAM base address */ +#define MV64340_INTEGRATED_SRAM_BASE_ADDR 0x268 + +/* internal registers space base address */ +#define MV64340_INTERNAL_SPACE_BASE_ADDR 0x068 + +/* Enables the CS , DEV_CS , PCI 0 and PCI 1 windows above */ +#define MV64340_BASE_ADDR_ENABLE 0x278 + +/****************************************/ +/* PCI remap registers */ +/****************************************/ + + /* PCI 0 */ +#define MV64340_PCI_0_IO_ADDR_REMAP 0x0f0 +#define MV64340_PCI_0_MEMORY0_LOW_ADDR_REMAP 0x0f8 +#define MV64340_PCI_0_MEMORY0_HIGH_ADDR_REMAP 0x320 +#define MV64340_PCI_0_MEMORY1_LOW_ADDR_REMAP 0x100 +#define MV64340_PCI_0_MEMORY1_HIGH_ADDR_REMAP 0x328 +#define MV64340_PCI_0_MEMORY2_LOW_ADDR_REMAP 0x2f8 +#define MV64340_PCI_0_MEMORY2_HIGH_ADDR_REMAP 0x330 +#define MV64340_PCI_0_MEMORY3_LOW_ADDR_REMAP 0x300 +#define MV64340_PCI_0_MEMORY3_HIGH_ADDR_REMAP 0x338 + /* PCI 1 */ +#define MV64340_PCI_1_IO_ADDR_REMAP 0x108 +#define MV64340_PCI_1_MEMORY0_LOW_ADDR_REMAP 0x110 +#define MV64340_PCI_1_MEMORY0_HIGH_ADDR_REMAP 0x340 +#define MV64340_PCI_1_MEMORY1_LOW_ADDR_REMAP 0x118 +#define MV64340_PCI_1_MEMORY1_HIGH_ADDR_REMAP 0x348 +#define MV64340_PCI_1_MEMORY2_LOW_ADDR_REMAP 0x310 +#define MV64340_PCI_1_MEMORY2_HIGH_ADDR_REMAP 0x350 +#define MV64340_PCI_1_MEMORY3_LOW_ADDR_REMAP 0x318 +#define MV64340_PCI_1_MEMORY3_HIGH_ADDR_REMAP 0x358 + +#define MV64340_CPU_PCI_0_HEADERS_RETARGET_CONTROL 0x3b0 +#define MV64340_CPU_PCI_0_HEADERS_RETARGET_BASE 0x3b8 +#define MV64340_CPU_PCI_1_HEADERS_RETARGET_CONTROL 0x3c0 +#define MV64340_CPU_PCI_1_HEADERS_RETARGET_BASE 0x3c8 +#define MV64340_CPU_GE_HEADERS_RETARGET_CONTROL 0x3d0 +#define MV64340_CPU_GE_HEADERS_RETARGET_BASE 0x3d8 +#define MV64340_CPU_IDMA_HEADERS_RETARGET_CONTROL 0x3e0 +#define MV64340_CPU_IDMA_HEADERS_RETARGET_BASE 0x3e8 + +/****************************************/ +/* CPU Control Registers */ +/****************************************/ + +#define MV64340_CPU_CONFIG 0x000 +#define MV64340_CPU_MODE 0x120 +#define MV64340_CPU_MASTER_CONTROL 0x160 +#define MV64340_CPU_CROSS_BAR_CONTROL_LOW 0x150 +#define MV64340_CPU_CROSS_BAR_CONTROL_HIGH 0x158 +#define MV64340_CPU_CROSS_BAR_TIMEOUT 0x168 + +/****************************************/ +/* SMP RegisterS */ +/****************************************/ + +#define MV64340_SMP_WHO_AM_I 0x200 +#define MV64340_SMP_CPU0_DOORBELL 0x214 +#define MV64340_SMP_CPU0_DOORBELL_CLEAR 0x21C +#define MV64340_SMP_CPU1_DOORBELL 0x224 +#define MV64340_SMP_CPU1_DOORBELL_CLEAR 0x22C +#define MV64340_SMP_CPU0_DOORBELL_MASK 0x234 +#define MV64340_SMP_CPU1_DOORBELL_MASK 0x23C +#define MV64340_SMP_SEMAPHOR0 0x244 +#define MV64340_SMP_SEMAPHOR1 0x24c +#define MV64340_SMP_SEMAPHOR2 0x254 +#define MV64340_SMP_SEMAPHOR3 0x25c +#define MV64340_SMP_SEMAPHOR4 0x264 +#define MV64340_SMP_SEMAPHOR5 0x26c +#define MV64340_SMP_SEMAPHOR6 0x274 +#define MV64340_SMP_SEMAPHOR7 0x27c + +/****************************************/ +/* CPU Sync Barrier Register */ +/****************************************/ + +#define MV64340_CPU_0_SYNC_BARRIER_TRIGGER 0x0c0 +#define MV64340_CPU_0_SYNC_BARRIER_VIRTUAL 0x0c8 +#define MV64340_CPU_1_SYNC_BARRIER_TRIGGER 0x0d0 +#define MV64340_CPU_1_SYNC_BARRIER_VIRTUAL 0x0d8 + +/****************************************/ +/* CPU Access Protect */ +/****************************************/ + +#define MV64340_CPU_PROTECT_WINDOW_0_BASE_ADDR 0x180 +#define MV64340_CPU_PROTECT_WINDOW_0_SIZE 0x188 +#define MV64340_CPU_PROTECT_WINDOW_1_BASE_ADDR 0x190 +#define MV64340_CPU_PROTECT_WINDOW_1_SIZE 0x198 +#define MV64340_CPU_PROTECT_WINDOW_2_BASE_ADDR 0x1a0 +#define MV64340_CPU_PROTECT_WINDOW_2_SIZE 0x1a8 +#define MV64340_CPU_PROTECT_WINDOW_3_BASE_ADDR 0x1b0 +#define MV64340_CPU_PROTECT_WINDOW_3_SIZE 0x1b8 + + +/****************************************/ +/* CPU Error Report */ +/****************************************/ + +#define MV64340_CPU_ERROR_ADDR_LOW 0x070 +#define MV64340_CPU_ERROR_ADDR_HIGH 0x078 +#define MV64340_CPU_ERROR_DATA_LOW 0x128 +#define MV64340_CPU_ERROR_DATA_HIGH 0x130 +#define MV64340_CPU_ERROR_PARITY 0x138 +#define MV64340_CPU_ERROR_CAUSE 0x140 +#define MV64340_CPU_ERROR_MASK 0x148 + +/****************************************/ +/* CPU Interface Debug Registers */ +/****************************************/ + +#define MV64340_PUNIT_SLAVE_DEBUG_LOW 0x360 +#define MV64340_PUNIT_SLAVE_DEBUG_HIGH 0x368 +#define MV64340_PUNIT_MASTER_DEBUG_LOW 0x370 +#define MV64340_PUNIT_MASTER_DEBUG_HIGH 0x378 +#define MV64340_PUNIT_MMASK 0x3e4 + +/****************************************/ +/* Integrated SRAM Registers */ +/****************************************/ + +#define MV64340_SRAM_CONFIG 0x380 +#define MV64340_SRAM_TEST_MODE 0X3F4 +#define MV64340_SRAM_ERROR_CAUSE 0x388 +#define MV64340_SRAM_ERROR_ADDR 0x390 +#define MV64340_SRAM_ERROR_ADDR_HIGH 0X3F8 +#define MV64340_SRAM_ERROR_DATA_LOW 0x398 +#define MV64340_SRAM_ERROR_DATA_HIGH 0x3a0 +#define MV64340_SRAM_ERROR_DATA_PARITY 0x3a8 + +/****************************************/ +/* SDRAM Configuration */ +/****************************************/ + +#define MV64340_SDRAM_CONFIG 0x1400 +#define MV64340_D_UNIT_CONTROL_LOW 0x1404 +#define MV64340_D_UNIT_CONTROL_HIGH 0x1424 +#define MV64340_SDRAM_TIMING_CONTROL_LOW 0x1408 +#define MV64340_SDRAM_TIMING_CONTROL_HIGH 0x140c +#define MV64340_SDRAM_ADDR_CONTROL 0x1410 +#define MV64340_SDRAM_OPEN_PAGES_CONTROL 0x1414 +#define MV64340_SDRAM_OPERATION 0x1418 +#define MV64340_SDRAM_MODE 0x141c +#define MV64340_EXTENDED_DRAM_MODE 0x1420 +#define MV64340_SDRAM_CROSS_BAR_CONTROL_LOW 0x1430 +#define MV64340_SDRAM_CROSS_BAR_CONTROL_HIGH 0x1434 +#define MV64340_SDRAM_CROSS_BAR_TIMEOUT 0x1438 +#define MV64340_SDRAM_ADDR_CTRL_PADS_CALIBRATION 0x14c0 +#define MV64340_SDRAM_DATA_PADS_CALIBRATION 0x14c4 + +/****************************************/ +/* SDRAM Error Report */ +/****************************************/ + +#define MV64340_SDRAM_ERROR_DATA_LOW 0x1444 +#define MV64340_SDRAM_ERROR_DATA_HIGH 0x1440 +#define MV64340_SDRAM_ERROR_ADDR 0x1450 +#define MV64340_SDRAM_RECEIVED_ECC 0x1448 +#define MV64340_SDRAM_CALCULATED_ECC 0x144c +#define MV64340_SDRAM_ECC_CONTROL 0x1454 +#define MV64340_SDRAM_ECC_ERROR_COUNTER 0x1458 + +/******************************************/ +/* Controlled Delay Line (CDL) Registers */ +/******************************************/ + +#define MV64340_DFCDL_CONFIG0 0x1480 +#define MV64340_DFCDL_CONFIG1 0x1484 +#define MV64340_DLL_WRITE 0x1488 +#define MV64340_DLL_READ 0x148c +#define MV64340_SRAM_ADDR 0x1490 +#define MV64340_SRAM_DATA0 0x1494 +#define MV64340_SRAM_DATA1 0x1498 +#define MV64340_SRAM_DATA2 0x149c +#define MV64340_DFCL_PROBE 0x14a0 + +/******************************************/ +/* Debug Registers */ +/******************************************/ + +#define MV64340_DUNIT_DEBUG_LOW 0x1460 +#define MV64340_DUNIT_DEBUG_HIGH 0x1464 +#define MV64340_DUNIT_MMASK 0X1b40 + +/****************************************/ +/* Device Parameters */ +/****************************************/ + +#define MV64340_DEVICE_BANK0_PARAMETERS 0x45c +#define MV64340_DEVICE_BANK1_PARAMETERS 0x460 +#define MV64340_DEVICE_BANK2_PARAMETERS 0x464 +#define MV64340_DEVICE_BANK3_PARAMETERS 0x468 +#define MV64340_DEVICE_BOOT_BANK_PARAMETERS 0x46c +#define MV64340_DEVICE_INTERFACE_CONTROL 0x4c0 +#define MV64340_DEVICE_INTERFACE_CROSS_BAR_CONTROL_LOW 0x4c8 +#define MV64340_DEVICE_INTERFACE_CROSS_BAR_CONTROL_HIGH 0x4cc +#define MV64340_DEVICE_INTERFACE_CROSS_BAR_TIMEOUT 0x4c4 + +/****************************************/ +/* Device interrupt registers */ +/****************************************/ + +#define MV64340_DEVICE_INTERRUPT_CAUSE 0x4d0 +#define MV64340_DEVICE_INTERRUPT_MASK 0x4d4 +#define MV64340_DEVICE_ERROR_ADDR 0x4d8 +#define MV64340_DEVICE_ERROR_DATA 0x4dc +#define MV64340_DEVICE_ERROR_PARITY 0x4e0 + +/****************************************/ +/* Device debug registers */ +/****************************************/ + +#define MV64340_DEVICE_DEBUG_LOW 0x4e4 +#define MV64340_DEVICE_DEBUG_HIGH 0x4e8 +#define MV64340_RUNIT_MMASK 0x4f0 + +/****************************************/ +/* PCI Slave Address Decoding registers */ +/****************************************/ + +#define MV64340_PCI_0_CS_0_BANK_SIZE 0xc08 +#define MV64340_PCI_1_CS_0_BANK_SIZE 0xc88 +#define MV64340_PCI_0_CS_1_BANK_SIZE 0xd08 +#define MV64340_PCI_1_CS_1_BANK_SIZE 0xd88 +#define MV64340_PCI_0_CS_2_BANK_SIZE 0xc0c +#define MV64340_PCI_1_CS_2_BANK_SIZE 0xc8c +#define MV64340_PCI_0_CS_3_BANK_SIZE 0xd0c +#define MV64340_PCI_1_CS_3_BANK_SIZE 0xd8c +#define MV64340_PCI_0_DEVCS_0_BANK_SIZE 0xc10 +#define MV64340_PCI_1_DEVCS_0_BANK_SIZE 0xc90 +#define MV64340_PCI_0_DEVCS_1_BANK_SIZE 0xd10 +#define MV64340_PCI_1_DEVCS_1_BANK_SIZE 0xd90 +#define MV64340_PCI_0_DEVCS_2_BANK_SIZE 0xd18 +#define MV64340_PCI_1_DEVCS_2_BANK_SIZE 0xd98 +#define MV64340_PCI_0_DEVCS_3_BANK_SIZE 0xc14 +#define MV64340_PCI_1_DEVCS_3_BANK_SIZE 0xc94 +#define MV64340_PCI_0_DEVCS_BOOT_BANK_SIZE 0xd14 +#define MV64340_PCI_1_DEVCS_BOOT_BANK_SIZE 0xd94 +#define MV64340_PCI_0_P2P_MEM0_BAR_SIZE 0xd1c +#define MV64340_PCI_1_P2P_MEM0_BAR_SIZE 0xd9c +#define MV64340_PCI_0_P2P_MEM1_BAR_SIZE 0xd20 +#define MV64340_PCI_1_P2P_MEM1_BAR_SIZE 0xda0 +#define MV64340_PCI_0_P2P_I_O_BAR_SIZE 0xd24 +#define MV64340_PCI_1_P2P_I_O_BAR_SIZE 0xda4 +#define MV64340_PCI_0_CPU_BAR_SIZE 0xd28 +#define MV64340_PCI_1_CPU_BAR_SIZE 0xda8 +#define MV64340_PCI_0_INTERNAL_SRAM_BAR_SIZE 0xe00 +#define MV64340_PCI_1_INTERNAL_SRAM_BAR_SIZE 0xe80 +#define MV64340_PCI_0_EXPANSION_ROM_BAR_SIZE 0xd2c +#define MV64340_PCI_1_EXPANSION_ROM_BAR_SIZE 0xd9c +#define MV64340_PCI_0_BASE_ADDR_REG_ENABLE 0xc3c +#define MV64340_PCI_1_BASE_ADDR_REG_ENABLE 0xcbc +#define MV64340_PCI_0_CS_0_BASE_ADDR_REMAP 0xc48 +#define MV64340_PCI_1_CS_0_BASE_ADDR_REMAP 0xcc8 +#define MV64340_PCI_0_CS_1_BASE_ADDR_REMAP 0xd48 +#define MV64340_PCI_1_CS_1_BASE_ADDR_REMAP 0xdc8 +#define MV64340_PCI_0_CS_2_BASE_ADDR_REMAP 0xc4c +#define MV64340_PCI_1_CS_2_BASE_ADDR_REMAP 0xccc +#define MV64340_PCI_0_CS_3_BASE_ADDR_REMAP 0xd4c +#define MV64340_PCI_1_CS_3_BASE_ADDR_REMAP 0xdcc +#define MV64340_PCI_0_CS_0_BASE_HIGH_ADDR_REMAP 0xF04 +#define MV64340_PCI_1_CS_0_BASE_HIGH_ADDR_REMAP 0xF84 +#define MV64340_PCI_0_CS_1_BASE_HIGH_ADDR_REMAP 0xF08 +#define MV64340_PCI_1_CS_1_BASE_HIGH_ADDR_REMAP 0xF88 +#define MV64340_PCI_0_CS_2_BASE_HIGH_ADDR_REMAP 0xF0C +#define MV64340_PCI_1_CS_2_BASE_HIGH_ADDR_REMAP 0xF8C +#define MV64340_PCI_0_CS_3_BASE_HIGH_ADDR_REMAP 0xF10 +#define MV64340_PCI_1_CS_3_BASE_HIGH_ADDR_REMAP 0xF90 +#define MV64340_PCI_0_DEVCS_0_BASE_ADDR_REMAP 0xc50 +#define MV64340_PCI_1_DEVCS_0_BASE_ADDR_REMAP 0xcd0 +#define MV64340_PCI_0_DEVCS_1_BASE_ADDR_REMAP 0xd50 +#define MV64340_PCI_1_DEVCS_1_BASE_ADDR_REMAP 0xdd0 +#define MV64340_PCI_0_DEVCS_2_BASE_ADDR_REMAP 0xd58 +#define MV64340_PCI_1_DEVCS_2_BASE_ADDR_REMAP 0xdd8 +#define MV64340_PCI_0_DEVCS_3_BASE_ADDR_REMAP 0xc54 +#define MV64340_PCI_1_DEVCS_3_BASE_ADDR_REMAP 0xcd4 +#define MV64340_PCI_0_DEVCS_BOOTCS_BASE_ADDR_REMAP 0xd54 +#define MV64340_PCI_1_DEVCS_BOOTCS_BASE_ADDR_REMAP 0xdd4 +#define MV64340_PCI_0_P2P_MEM0_BASE_ADDR_REMAP_LOW 0xd5c +#define MV64340_PCI_1_P2P_MEM0_BASE_ADDR_REMAP_LOW 0xddc +#define MV64340_PCI_0_P2P_MEM0_BASE_ADDR_REMAP_HIGH 0xd60 +#define MV64340_PCI_1_P2P_MEM0_BASE_ADDR_REMAP_HIGH 0xde0 +#define MV64340_PCI_0_P2P_MEM1_BASE_ADDR_REMAP_LOW 0xd64 +#define MV64340_PCI_1_P2P_MEM1_BASE_ADDR_REMAP_LOW 0xde4 +#define MV64340_PCI_0_P2P_MEM1_BASE_ADDR_REMAP_HIGH 0xd68 +#define MV64340_PCI_1_P2P_MEM1_BASE_ADDR_REMAP_HIGH 0xde8 +#define MV64340_PCI_0_P2P_I_O_BASE_ADDR_REMAP 0xd6c +#define MV64340_PCI_1_P2P_I_O_BASE_ADDR_REMAP 0xdec +#define MV64340_PCI_0_CPU_BASE_ADDR_REMAP_LOW 0xd70 +#define MV64340_PCI_1_CPU_BASE_ADDR_REMAP_LOW 0xdf0 +#define MV64340_PCI_0_CPU_BASE_ADDR_REMAP_HIGH 0xd74 +#define MV64340_PCI_1_CPU_BASE_ADDR_REMAP_HIGH 0xdf4 +#define MV64340_PCI_0_INTEGRATED_SRAM_BASE_ADDR_REMAP 0xf00 +#define MV64340_PCI_1_INTEGRATED_SRAM_BASE_ADDR_REMAP 0xf80 +#define MV64340_PCI_0_EXPANSION_ROM_BASE_ADDR_REMAP 0xf38 +#define MV64340_PCI_1_EXPANSION_ROM_BASE_ADDR_REMAP 0xfb8 +#define MV64340_PCI_0_ADDR_DECODE_CONTROL 0xd3c +#define MV64340_PCI_1_ADDR_DECODE_CONTROL 0xdbc +#define MV64340_PCI_0_HEADERS_RETARGET_CONTROL 0xF40 +#define MV64340_PCI_1_HEADERS_RETARGET_CONTROL 0xFc0 +#define MV64340_PCI_0_HEADERS_RETARGET_BASE 0xF44 +#define MV64340_PCI_1_HEADERS_RETARGET_BASE 0xFc4 +#define MV64340_PCI_0_HEADERS_RETARGET_HIGH 0xF48 +#define MV64340_PCI_1_HEADERS_RETARGET_HIGH 0xFc8 + +/***********************************/ +/* PCI Control Register Map */ +/***********************************/ + +#define MV64340_PCI_0_DLL_STATUS_AND_COMMAND 0x1d20 +#define MV64340_PCI_1_DLL_STATUS_AND_COMMAND 0x1da0 +#define MV64340_PCI_0_MPP_PADS_DRIVE_CONTROL 0x1d1C +#define MV64340_PCI_1_MPP_PADS_DRIVE_CONTROL 0x1d9C +#define MV64340_PCI_0_COMMAND 0xc00 +#define MV64340_PCI_1_COMMAND 0xc80 +#define MV64340_PCI_0_MODE 0xd00 +#define MV64340_PCI_1_MODE 0xd80 +#define MV64340_PCI_0_RETRY 0xc04 +#define MV64340_PCI_1_RETRY 0xc84 +#define MV64340_PCI_0_READ_BUFFER_DISCARD_TIMER 0xd04 +#define MV64340_PCI_1_READ_BUFFER_DISCARD_TIMER 0xd84 +#define MV64340_PCI_0_MSI_TRIGGER_TIMER 0xc38 +#define MV64340_PCI_1_MSI_TRIGGER_TIMER 0xcb8 +#define MV64340_PCI_0_ARBITER_CONTROL 0x1d00 +#define MV64340_PCI_1_ARBITER_CONTROL 0x1d80 +#define MV64340_PCI_0_CROSS_BAR_CONTROL_LOW 0x1d08 +#define MV64340_PCI_1_CROSS_BAR_CONTROL_LOW 0x1d88 +#define MV64340_PCI_0_CROSS_BAR_CONTROL_HIGH 0x1d0c +#define MV64340_PCI_1_CROSS_BAR_CONTROL_HIGH 0x1d8c +#define MV64340_PCI_0_CROSS_BAR_TIMEOUT 0x1d04 +#define MV64340_PCI_1_CROSS_BAR_TIMEOUT 0x1d84 +#define MV64340_PCI_0_SYNC_BARRIER_TRIGGER_REG 0x1D18 +#define MV64340_PCI_1_SYNC_BARRIER_TRIGGER_REG 0x1D98 +#define MV64340_PCI_0_SYNC_BARRIER_VIRTUAL_REG 0x1d10 +#define MV64340_PCI_1_SYNC_BARRIER_VIRTUAL_REG 0x1d90 +#define MV64340_PCI_0_P2P_CONFIG 0x1d14 +#define MV64340_PCI_1_P2P_CONFIG 0x1d94 + +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_0_LOW 0x1e00 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_0_HIGH 0x1e04 +#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_0 0x1e08 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_1_LOW 0x1e10 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_1_HIGH 0x1e14 +#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_1 0x1e18 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_2_LOW 0x1e20 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_2_HIGH 0x1e24 +#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_2 0x1e28 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_3_LOW 0x1e30 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_3_HIGH 0x1e34 +#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_3 0x1e38 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_4_LOW 0x1e40 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_4_HIGH 0x1e44 +#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_4 0x1e48 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_5_LOW 0x1e50 +#define MV64340_PCI_0_ACCESS_CONTROL_BASE_5_HIGH 0x1e54 +#define MV64340_PCI_0_ACCESS_CONTROL_SIZE_5 0x1e58 + +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_0_LOW 0x1e80 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_0_HIGH 0x1e84 +#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_0 0x1e88 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_1_LOW 0x1e90 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_1_HIGH 0x1e94 +#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_1 0x1e98 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_2_LOW 0x1ea0 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_2_HIGH 0x1ea4 +#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_2 0x1ea8 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_3_LOW 0x1eb0 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_3_HIGH 0x1eb4 +#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_3 0x1eb8 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_4_LOW 0x1ec0 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_4_HIGH 0x1ec4 +#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_4 0x1ec8 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_5_LOW 0x1ed0 +#define MV64340_PCI_1_ACCESS_CONTROL_BASE_5_HIGH 0x1ed4 +#define MV64340_PCI_1_ACCESS_CONTROL_SIZE_5 0x1ed8 + +/****************************************/ +/* PCI Configuration Access Registers */ +/****************************************/ + +#define MV64340_PCI_0_CONFIG_ADDR 0xcf8 +#define MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG 0xcfc +#define MV64340_PCI_1_CONFIG_ADDR 0xc78 +#define MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG 0xc7c +#define MV64340_PCI_0_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG 0xc34 +#define MV64340_PCI_1_INTERRUPT_ACKNOWLEDGE_VIRTUAL_REG 0xcb4 + +/****************************************/ +/* PCI Error Report Registers */ +/****************************************/ + +#define MV64340_PCI_0_SERR_MASK 0xc28 +#define MV64340_PCI_1_SERR_MASK 0xca8 +#define MV64340_PCI_0_ERROR_ADDR_LOW 0x1d40 +#define MV64340_PCI_1_ERROR_ADDR_LOW 0x1dc0 +#define MV64340_PCI_0_ERROR_ADDR_HIGH 0x1d44 +#define MV64340_PCI_1_ERROR_ADDR_HIGH 0x1dc4 +#define MV64340_PCI_0_ERROR_ATTRIBUTE 0x1d48 +#define MV64340_PCI_1_ERROR_ATTRIBUTE 0x1dc8 +#define MV64340_PCI_0_ERROR_COMMAND 0x1d50 +#define MV64340_PCI_1_ERROR_COMMAND 0x1dd0 +#define MV64340_PCI_0_ERROR_CAUSE 0x1d58 +#define MV64340_PCI_1_ERROR_CAUSE 0x1dd8 +#define MV64340_PCI_0_ERROR_MASK 0x1d5c +#define MV64340_PCI_1_ERROR_MASK 0x1ddc + +/****************************************/ +/* PCI Debug Registers */ +/****************************************/ + +#define MV64340_PCI_0_MMASK 0X1D24 +#define MV64340_PCI_1_MMASK 0X1DA4 + +/*********************************************/ +/* PCI Configuration, Function 0, Registers */ +/*********************************************/ + +#define MV64340_PCI_DEVICE_AND_VENDOR_ID 0x000 +#define MV64340_PCI_STATUS_AND_COMMAND 0x004 +#define MV64340_PCI_CLASS_CODE_AND_REVISION_ID 0x008 +#define MV64340_PCI_BIST_HEADER_TYPE_LATENCY_TIMER_CACHE_LINE 0x00C + +#define MV64340_PCI_SCS_0_BASE_ADDR_LOW 0x010 +#define MV64340_PCI_SCS_0_BASE_ADDR_HIGH 0x014 +#define MV64340_PCI_SCS_1_BASE_ADDR_LOW 0x018 +#define MV64340_PCI_SCS_1_BASE_ADDR_HIGH 0x01C +#define MV64340_PCI_INTERNAL_REG_MEM_MAPPED_BASE_ADDR_LOW 0x020 +#define MV64340_PCI_INTERNAL_REG_MEM_MAPPED_BASE_ADDR_HIGH 0x024 +#define MV64340_PCI_SUBSYSTEM_ID_AND_SUBSYSTEM_VENDOR_ID 0x02c +#define MV64340_PCI_EXPANSION_ROM_BASE_ADDR_REG 0x030 +#define MV64340_PCI_CAPABILTY_LIST_POINTER 0x034 +#define MV64340_PCI_INTERRUPT_PIN_AND_LINE 0x03C + /* capability list */ +#define MV64340_PCI_POWER_MANAGEMENT_CAPABILITY 0x040 +#define MV64340_PCI_POWER_MANAGEMENT_STATUS_AND_CONTROL 0x044 +#define MV64340_PCI_VPD_ADDR 0x048 +#define MV64340_PCI_VPD_DATA 0x04c +#define MV64340_PCI_MSI_MESSAGE_CONTROL 0x050 +#define MV64340_PCI_MSI_MESSAGE_ADDR 0x054 +#define MV64340_PCI_MSI_MESSAGE_UPPER_ADDR 0x058 +#define MV64340_PCI_MSI_MESSAGE_DATA 0x05c +#define MV64340_PCI_X_COMMAND 0x060 +#define MV64340_PCI_X_STATUS 0x064 +#define MV64340_PCI_COMPACT_PCI_HOT_SWAP 0x068 + +/***********************************************/ +/* PCI Configuration, Function 1, Registers */ +/***********************************************/ + +#define MV64340_PCI_SCS_2_BASE_ADDR_LOW 0x110 +#define MV64340_PCI_SCS_2_BASE_ADDR_HIGH 0x114 +#define MV64340_PCI_SCS_3_BASE_ADDR_LOW 0x118 +#define MV64340_PCI_SCS_3_BASE_ADDR_HIGH 0x11c +#define MV64340_PCI_INTERNAL_SRAM_BASE_ADDR_LOW 0x120 +#define MV64340_PCI_INTERNAL_SRAM_BASE_ADDR_HIGH 0x124 + +/***********************************************/ +/* PCI Configuration, Function 2, Registers */ +/***********************************************/ + +#define MV64340_PCI_DEVCS_0_BASE_ADDR_LOW 0x210 +#define MV64340_PCI_DEVCS_0_BASE_ADDR_HIGH 0x214 +#define MV64340_PCI_DEVCS_1_BASE_ADDR_LOW 0x218 +#define MV64340_PCI_DEVCS_1_BASE_ADDR_HIGH 0x21c +#define MV64340_PCI_DEVCS_2_BASE_ADDR_LOW 0x220 +#define MV64340_PCI_DEVCS_2_BASE_ADDR_HIGH 0x224 + +/***********************************************/ +/* PCI Configuration, Function 3, Registers */ +/***********************************************/ + +#define MV64340_PCI_DEVCS_3_BASE_ADDR_LOW 0x310 +#define MV64340_PCI_DEVCS_3_BASE_ADDR_HIGH 0x314 +#define MV64340_PCI_BOOT_CS_BASE_ADDR_LOW 0x318 +#define MV64340_PCI_BOOT_CS_BASE_ADDR_HIGH 0x31c +#define MV64340_PCI_CPU_BASE_ADDR_LOW 0x220 +#define MV64340_PCI_CPU_BASE_ADDR_HIGH 0x224 + +/***********************************************/ +/* PCI Configuration, Function 4, Registers */ +/***********************************************/ + +#define MV64340_PCI_P2P_MEM0_BASE_ADDR_LOW 0x410 +#define MV64340_PCI_P2P_MEM0_BASE_ADDR_HIGH 0x414 +#define MV64340_PCI_P2P_MEM1_BASE_ADDR_LOW 0x418 +#define MV64340_PCI_P2P_MEM1_BASE_ADDR_HIGH 0x41c +#define MV64340_PCI_P2P_I_O_BASE_ADDR 0x420 +#define MV64340_PCI_INTERNAL_REGS_I_O_MAPPED_BASE_ADDR 0x424 + +/****************************************/ +/* Messaging Unit Registers (I20) */ +/****************************************/ + +#define MV64340_I2O_INBOUND_MESSAGE_REG0_PCI_0_SIDE 0x010 +#define MV64340_I2O_INBOUND_MESSAGE_REG1_PCI_0_SIDE 0x014 +#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_PCI_0_SIDE 0x018 +#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_PCI_0_SIDE 0x01C +#define MV64340_I2O_INBOUND_DOORBELL_REG_PCI_0_SIDE 0x020 +#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_PCI_0_SIDE 0x024 +#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_PCI_0_SIDE 0x028 +#define MV64340_I2O_OUTBOUND_DOORBELL_REG_PCI_0_SIDE 0x02C +#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_PCI_0_SIDE 0x030 +#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_PCI_0_SIDE 0x034 +#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_0_SIDE 0x040 +#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_0_SIDE 0x044 +#define MV64340_I2O_QUEUE_CONTROL_REG_PCI_0_SIDE 0x050 +#define MV64340_I2O_QUEUE_BASE_ADDR_REG_PCI_0_SIDE 0x054 +#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_PCI_0_SIDE 0x060 +#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_PCI_0_SIDE 0x064 +#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_PCI_0_SIDE 0x068 +#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_PCI_0_SIDE 0x06C +#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_PCI_0_SIDE 0x070 +#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_PCI_0_SIDE 0x074 +#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_PCI_0_SIDE 0x0F8 +#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_PCI_0_SIDE 0x0FC + +#define MV64340_I2O_INBOUND_MESSAGE_REG0_PCI_1_SIDE 0x090 +#define MV64340_I2O_INBOUND_MESSAGE_REG1_PCI_1_SIDE 0x094 +#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_PCI_1_SIDE 0x098 +#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_PCI_1_SIDE 0x09C +#define MV64340_I2O_INBOUND_DOORBELL_REG_PCI_1_SIDE 0x0A0 +#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_PCI_1_SIDE 0x0A4 +#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_PCI_1_SIDE 0x0A8 +#define MV64340_I2O_OUTBOUND_DOORBELL_REG_PCI_1_SIDE 0x0AC +#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_PCI_1_SIDE 0x0B0 +#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_PCI_1_SIDE 0x0B4 +#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_1_SIDE 0x0C0 +#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_PCI_1_SIDE 0x0C4 +#define MV64340_I2O_QUEUE_CONTROL_REG_PCI_1_SIDE 0x0D0 +#define MV64340_I2O_QUEUE_BASE_ADDR_REG_PCI_1_SIDE 0x0D4 +#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_PCI_1_SIDE 0x0E0 +#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_PCI_1_SIDE 0x0E4 +#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_PCI_1_SIDE 0x0E8 +#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_PCI_1_SIDE 0x0EC +#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_PCI_1_SIDE 0x0F0 +#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_PCI_1_SIDE 0x0F4 +#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_PCI_1_SIDE 0x078 +#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_PCI_1_SIDE 0x07C + +#define MV64340_I2O_INBOUND_MESSAGE_REG0_CPU0_SIDE 0x1C10 +#define MV64340_I2O_INBOUND_MESSAGE_REG1_CPU0_SIDE 0x1C14 +#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_CPU0_SIDE 0x1C18 +#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_CPU0_SIDE 0x1C1C +#define MV64340_I2O_INBOUND_DOORBELL_REG_CPU0_SIDE 0x1C20 +#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_CPU0_SIDE 0x1C24 +#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_CPU0_SIDE 0x1C28 +#define MV64340_I2O_OUTBOUND_DOORBELL_REG_CPU0_SIDE 0x1C2C +#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_CPU0_SIDE 0x1C30 +#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_CPU0_SIDE 0x1C34 +#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_CPU0_SIDE 0x1C40 +#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_CPU0_SIDE 0x1C44 +#define MV64340_I2O_QUEUE_CONTROL_REG_CPU0_SIDE 0x1C50 +#define MV64340_I2O_QUEUE_BASE_ADDR_REG_CPU0_SIDE 0x1C54 +#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_CPU0_SIDE 0x1C60 +#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_CPU0_SIDE 0x1C64 +#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_CPU0_SIDE 0x1C68 +#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_CPU0_SIDE 0x1C6C +#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_CPU0_SIDE 0x1C70 +#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_CPU0_SIDE 0x1C74 +#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_CPU0_SIDE 0x1CF8 +#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_CPU0_SIDE 0x1CFC +#define MV64340_I2O_INBOUND_MESSAGE_REG0_CPU1_SIDE 0x1C90 +#define MV64340_I2O_INBOUND_MESSAGE_REG1_CPU1_SIDE 0x1C94 +#define MV64340_I2O_OUTBOUND_MESSAGE_REG0_CPU1_SIDE 0x1C98 +#define MV64340_I2O_OUTBOUND_MESSAGE_REG1_CPU1_SIDE 0x1C9C +#define MV64340_I2O_INBOUND_DOORBELL_REG_CPU1_SIDE 0x1CA0 +#define MV64340_I2O_INBOUND_INTERRUPT_CAUSE_REG_CPU1_SIDE 0x1CA4 +#define MV64340_I2O_INBOUND_INTERRUPT_MASK_REG_CPU1_SIDE 0x1CA8 +#define MV64340_I2O_OUTBOUND_DOORBELL_REG_CPU1_SIDE 0x1CAC +#define MV64340_I2O_OUTBOUND_INTERRUPT_CAUSE_REG_CPU1_SIDE 0x1CB0 +#define MV64340_I2O_OUTBOUND_INTERRUPT_MASK_REG_CPU1_SIDE 0x1CB4 +#define MV64340_I2O_INBOUND_QUEUE_PORT_VIRTUAL_REG_CPU1_SIDE 0x1CC0 +#define MV64340_I2O_OUTBOUND_QUEUE_PORT_VIRTUAL_REG_CPU1_SIDE 0x1CC4 +#define MV64340_I2O_QUEUE_CONTROL_REG_CPU1_SIDE 0x1CD0 +#define MV64340_I2O_QUEUE_BASE_ADDR_REG_CPU1_SIDE 0x1CD4 +#define MV64340_I2O_INBOUND_FREE_HEAD_POINTER_REG_CPU1_SIDE 0x1CE0 +#define MV64340_I2O_INBOUND_FREE_TAIL_POINTER_REG_CPU1_SIDE 0x1CE4 +#define MV64340_I2O_INBOUND_POST_HEAD_POINTER_REG_CPU1_SIDE 0x1CE8 +#define MV64340_I2O_INBOUND_POST_TAIL_POINTER_REG_CPU1_SIDE 0x1CEC +#define MV64340_I2O_OUTBOUND_FREE_HEAD_POINTER_REG_CPU1_SIDE 0x1CF0 +#define MV64340_I2O_OUTBOUND_FREE_TAIL_POINTER_REG_CPU1_SIDE 0x1CF4 +#define MV64340_I2O_OUTBOUND_POST_HEAD_POINTER_REG_CPU1_SIDE 0x1C78 +#define MV64340_I2O_OUTBOUND_POST_TAIL_POINTER_REG_CPU1_SIDE 0x1C7C + +/****************************************/ +/* Ethernet Unit Registers */ +/****************************************/ + +/*******************************************/ +/* CUNIT Registers */ +/*******************************************/ + + /* Address Decoding Register Map */ + +#define MV64340_CUNIT_BASE_ADDR_REG0 0xf200 +#define MV64340_CUNIT_BASE_ADDR_REG1 0xf208 +#define MV64340_CUNIT_BASE_ADDR_REG2 0xf210 +#define MV64340_CUNIT_BASE_ADDR_REG3 0xf218 +#define MV64340_CUNIT_SIZE0 0xf204 +#define MV64340_CUNIT_SIZE1 0xf20c +#define MV64340_CUNIT_SIZE2 0xf214 +#define MV64340_CUNIT_SIZE3 0xf21c +#define MV64340_CUNIT_HIGH_ADDR_REMAP_REG0 0xf240 +#define MV64340_CUNIT_HIGH_ADDR_REMAP_REG1 0xf244 +#define MV64340_CUNIT_BASE_ADDR_ENABLE_REG 0xf250 +#define MV64340_MPSC0_ACCESS_PROTECTION_REG 0xf254 +#define MV64340_MPSC1_ACCESS_PROTECTION_REG 0xf258 +#define MV64340_CUNIT_INTERNAL_SPACE_BASE_ADDR_REG 0xf25C + + /* Error Report Registers */ + +#define MV64340_CUNIT_INTERRUPT_CAUSE_REG 0xf310 +#define MV64340_CUNIT_INTERRUPT_MASK_REG 0xf314 +#define MV64340_CUNIT_ERROR_ADDR 0xf318 + + /* Cunit Control Registers */ + +#define MV64340_CUNIT_ARBITER_CONTROL_REG 0xf300 +#define MV64340_CUNIT_CONFIG_REG 0xb40c +#define MV64340_CUNIT_CRROSBAR_TIMEOUT_REG 0xf304 + + /* Cunit Debug Registers */ + +#define MV64340_CUNIT_DEBUG_LOW 0xf340 +#define MV64340_CUNIT_DEBUG_HIGH 0xf344 +#define MV64340_CUNIT_MMASK 0xf380 + + /* MPSCs Clocks Routing Registers */ + +#define MV64340_MPSC_ROUTING_REG 0xb400 +#define MV64340_MPSC_RX_CLOCK_ROUTING_REG 0xb404 +#define MV64340_MPSC_TX_CLOCK_ROUTING_REG 0xb408 + + /* MPSCs Interrupts Registers */ + +#define MV64340_MPSC_CAUSE_REG(port) (0xb804 + (port << 3)) +#define MV64340_MPSC_MASK_REG(port) (0xb884 + (port << 3)) + +#define MV64340_MPSC_MAIN_CONFIG_LOW(port) (0x8000 + (port << 12)) +#define MV64340_MPSC_MAIN_CONFIG_HIGH(port) (0x8004 + (port << 12)) +#define MV64340_MPSC_PROTOCOL_CONFIG(port) (0x8008 + (port << 12)) +#define MV64340_MPSC_CHANNEL_REG1(port) (0x800c + (port << 12)) +#define MV64340_MPSC_CHANNEL_REG2(port) (0x8010 + (port << 12)) +#define MV64340_MPSC_CHANNEL_REG3(port) (0x8014 + (port << 12)) +#define MV64340_MPSC_CHANNEL_REG4(port) (0x8018 + (port << 12)) +#define MV64340_MPSC_CHANNEL_REG5(port) (0x801c + (port << 12)) +#define MV64340_MPSC_CHANNEL_REG6(port) (0x8020 + (port << 12)) +#define MV64340_MPSC_CHANNEL_REG7(port) (0x8024 + (port << 12)) +#define MV64340_MPSC_CHANNEL_REG8(port) (0x8028 + (port << 12)) +#define MV64340_MPSC_CHANNEL_REG9(port) (0x802c + (port << 12)) +#define MV64340_MPSC_CHANNEL_REG10(port) (0x8030 + (port << 12)) + + /* MPSC0 Registers */ + + +/***************************************/ +/* SDMA Registers */ +/***************************************/ + +#define MV64340_SDMA_CONFIG_REG(channel) (0x4000 + (channel << 13)) +#define MV64340_SDMA_COMMAND_REG(channel) (0x4008 + (channel << 13)) +#define MV64340_SDMA_CURRENT_RX_DESCRIPTOR_POINTER(channel) (0x4810 + (channel << 13)) +#define MV64340_SDMA_CURRENT_TX_DESCRIPTOR_POINTER(channel) (0x4c10 + (channel << 13)) +#define MV64340_SDMA_FIRST_TX_DESCRIPTOR_POINTER(channel) (0x4c14 + (channel << 13)) + +#define MV64340_SDMA_CAUSE_REG 0xb800 +#define MV64340_SDMA_MASK_REG 0xb880 + +/* BRG Interrupts */ + +#define MV64340_BRG_CONFIG_REG(brg) (0xb200 + (brg << 3)) +#define MV64340_BRG_BAUDE_TUNING_REG(brg) (0xb208 + (brg << 3)) +#define MV64340_BRG_CAUSE_REG 0xb834 +#define MV64340_BRG_MASK_REG 0xb8b4 + +/****************************************/ +/* DMA Channel Control */ +/****************************************/ + +#define MV64340_DMA_CHANNEL0_CONTROL 0x840 +#define MV64340_DMA_CHANNEL0_CONTROL_HIGH 0x880 +#define MV64340_DMA_CHANNEL1_CONTROL 0x844 +#define MV64340_DMA_CHANNEL1_CONTROL_HIGH 0x884 +#define MV64340_DMA_CHANNEL2_CONTROL 0x848 +#define MV64340_DMA_CHANNEL2_CONTROL_HIGH 0x888 +#define MV64340_DMA_CHANNEL3_CONTROL 0x84C +#define MV64340_DMA_CHANNEL3_CONTROL_HIGH 0x88C + + +/****************************************/ +/* IDMA Registers */ +/****************************************/ + +#define MV64340_DMA_CHANNEL0_BYTE_COUNT 0x800 +#define MV64340_DMA_CHANNEL1_BYTE_COUNT 0x804 +#define MV64340_DMA_CHANNEL2_BYTE_COUNT 0x808 +#define MV64340_DMA_CHANNEL3_BYTE_COUNT 0x80C +#define MV64340_DMA_CHANNEL0_SOURCE_ADDR 0x810 +#define MV64340_DMA_CHANNEL1_SOURCE_ADDR 0x814 +#define MV64340_DMA_CHANNEL2_SOURCE_ADDR 0x818 +#define MV64340_DMA_CHANNEL3_SOURCE_ADDR 0x81c +#define MV64340_DMA_CHANNEL0_DESTINATION_ADDR 0x820 +#define MV64340_DMA_CHANNEL1_DESTINATION_ADDR 0x824 +#define MV64340_DMA_CHANNEL2_DESTINATION_ADDR 0x828 +#define MV64340_DMA_CHANNEL3_DESTINATION_ADDR 0x82C +#define MV64340_DMA_CHANNEL0_NEXT_DESCRIPTOR_POINTER 0x830 +#define MV64340_DMA_CHANNEL1_NEXT_DESCRIPTOR_POINTER 0x834 +#define MV64340_DMA_CHANNEL2_NEXT_DESCRIPTOR_POINTER 0x838 +#define MV64340_DMA_CHANNEL3_NEXT_DESCRIPTOR_POINTER 0x83C +#define MV64340_DMA_CHANNEL0_CURRENT_DESCRIPTOR_POINTER 0x870 +#define MV64340_DMA_CHANNEL1_CURRENT_DESCRIPTOR_POINTER 0x874 +#define MV64340_DMA_CHANNEL2_CURRENT_DESCRIPTOR_POINTER 0x878 +#define MV64340_DMA_CHANNEL3_CURRENT_DESCRIPTOR_POINTER 0x87C + + /* IDMA Address Decoding Base Address Registers */ + +#define MV64340_DMA_BASE_ADDR_REG0 0xa00 +#define MV64340_DMA_BASE_ADDR_REG1 0xa08 +#define MV64340_DMA_BASE_ADDR_REG2 0xa10 +#define MV64340_DMA_BASE_ADDR_REG3 0xa18 +#define MV64340_DMA_BASE_ADDR_REG4 0xa20 +#define MV64340_DMA_BASE_ADDR_REG5 0xa28 +#define MV64340_DMA_BASE_ADDR_REG6 0xa30 +#define MV64340_DMA_BASE_ADDR_REG7 0xa38 + + /* IDMA Address Decoding Size Address Register */ + +#define MV64340_DMA_SIZE_REG0 0xa04 +#define MV64340_DMA_SIZE_REG1 0xa0c +#define MV64340_DMA_SIZE_REG2 0xa14 +#define MV64340_DMA_SIZE_REG3 0xa1c +#define MV64340_DMA_SIZE_REG4 0xa24 +#define MV64340_DMA_SIZE_REG5 0xa2c +#define MV64340_DMA_SIZE_REG6 0xa34 +#define MV64340_DMA_SIZE_REG7 0xa3C + + /* IDMA Address Decoding High Address Remap and Access Protection Registers */ + +#define MV64340_DMA_HIGH_ADDR_REMAP_REG0 0xa60 +#define MV64340_DMA_HIGH_ADDR_REMAP_REG1 0xa64 +#define MV64340_DMA_HIGH_ADDR_REMAP_REG2 0xa68 +#define MV64340_DMA_HIGH_ADDR_REMAP_REG3 0xa6C +#define MV64340_DMA_BASE_ADDR_ENABLE_REG 0xa80 +#define MV64340_DMA_CHANNEL0_ACCESS_PROTECTION_REG 0xa70 +#define MV64340_DMA_CHANNEL1_ACCESS_PROTECTION_REG 0xa74 +#define MV64340_DMA_CHANNEL2_ACCESS_PROTECTION_REG 0xa78 +#define MV64340_DMA_CHANNEL3_ACCESS_PROTECTION_REG 0xa7c +#define MV64340_DMA_ARBITER_CONTROL 0x860 +#define MV64340_DMA_CROSS_BAR_TIMEOUT 0x8d0 + + /* IDMA Headers Retarget Registers */ + +#define MV64340_DMA_HEADERS_RETARGET_CONTROL 0xa84 +#define MV64340_DMA_HEADERS_RETARGET_BASE 0xa88 + + /* IDMA Interrupt Register */ + +#define MV64340_DMA_INTERRUPT_CAUSE_REG 0x8c0 +#define MV64340_DMA_INTERRUPT_CAUSE_MASK 0x8c4 +#define MV64340_DMA_ERROR_ADDR 0x8c8 +#define MV64340_DMA_ERROR_SELECT 0x8cc + + /* IDMA Debug Register ( for internal use ) */ + +#define MV64340_DMA_DEBUG_LOW 0x8e0 +#define MV64340_DMA_DEBUG_HIGH 0x8e4 +#define MV64340_DMA_SPARE 0xA8C + +/****************************************/ +/* Timer_Counter */ +/****************************************/ + +#define MV64340_TIMER_COUNTER0 0x850 +#define MV64340_TIMER_COUNTER1 0x854 +#define MV64340_TIMER_COUNTER2 0x858 +#define MV64340_TIMER_COUNTER3 0x85C +#define MV64340_TIMER_COUNTER_0_3_CONTROL 0x864 +#define MV64340_TIMER_COUNTER_0_3_INTERRUPT_CAUSE 0x868 +#define MV64340_TIMER_COUNTER_0_3_INTERRUPT_MASK 0x86c + +/****************************************/ +/* Watchdog registers */ +/****************************************/ + +#define MV64340_WATCHDOG_CONFIG_REG 0xb410 +#define MV64340_WATCHDOG_VALUE_REG 0xb414 + +/****************************************/ +/* I2C Registers */ +/****************************************/ + +#define MV64XXX_I2C_OFFSET 0xc000 +#define MV64XXX_I2C_REG_BLOCK_SIZE 0x0020 + +/****************************************/ +/* GPP Interface Registers */ +/****************************************/ + +#define MV64340_GPP_IO_CONTROL 0xf100 +#define MV64340_GPP_LEVEL_CONTROL 0xf110 +#define MV64340_GPP_VALUE 0xf104 +#define MV64340_GPP_INTERRUPT_CAUSE 0xf108 +#define MV64340_GPP_INTERRUPT_MASK0 0xf10c +#define MV64340_GPP_INTERRUPT_MASK1 0xf114 +#define MV64340_GPP_VALUE_SET 0xf118 +#define MV64340_GPP_VALUE_CLEAR 0xf11c + +/****************************************/ +/* Interrupt Controller Registers */ +/****************************************/ + +/****************************************/ +/* Interrupts */ +/****************************************/ + +#define MV64340_MAIN_INTERRUPT_CAUSE_LOW 0x004 +#define MV64340_MAIN_INTERRUPT_CAUSE_HIGH 0x00c +#define MV64340_CPU_INTERRUPT0_MASK_LOW 0x014 +#define MV64340_CPU_INTERRUPT0_MASK_HIGH 0x01c +#define MV64340_CPU_INTERRUPT0_SELECT_CAUSE 0x024 +#define MV64340_CPU_INTERRUPT1_MASK_LOW 0x034 +#define MV64340_CPU_INTERRUPT1_MASK_HIGH 0x03c +#define MV64340_CPU_INTERRUPT1_SELECT_CAUSE 0x044 +#define MV64340_INTERRUPT0_MASK_0_LOW 0x054 +#define MV64340_INTERRUPT0_MASK_0_HIGH 0x05c +#define MV64340_INTERRUPT0_SELECT_CAUSE 0x064 +#define MV64340_INTERRUPT1_MASK_0_LOW 0x074 +#define MV64340_INTERRUPT1_MASK_0_HIGH 0x07c +#define MV64340_INTERRUPT1_SELECT_CAUSE 0x084 + +/****************************************/ +/* MPP Interface Registers */ +/****************************************/ + +#define MV64340_MPP_CONTROL0 0xf000 +#define MV64340_MPP_CONTROL1 0xf004 +#define MV64340_MPP_CONTROL2 0xf008 +#define MV64340_MPP_CONTROL3 0xf00c + +/****************************************/ +/* Serial Initialization registers */ +/****************************************/ + +#define MV64340_SERIAL_INIT_LAST_DATA 0xf324 +#define MV64340_SERIAL_INIT_CONTROL 0xf328 +#define MV64340_SERIAL_INIT_STATUS 0xf32c + +#endif /* ASM_MV643XX_H */ diff --git a/hw/pci-host/trace-events b/hw/pci-host/trace-events index 7d8063ac42..dac86ad3f0 100644 --- a/hw/pci-host/trace-events +++ b/hw/pci-host/trace-events @@ -3,6 +3,12 @@ # grackle.c grackle_set_irq(int irq_num, int level) "set_irq num %d level %d" +# mv64361.c +mv64361_region_map(const char *name, uint64_t poffs, uint64_t size, uint64_t moffs) "Mapping %s 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64 +mv64361_region_enable(const char *op, int num) "Should %s region %d" +mv64361_reg_read(uint64_t addr, uint32_t val) "0x%"PRIx64" -> 0x%x" +mv64361_reg_write(uint64_t addr, uint64_t val) "0x%"PRIx64" <- 0x%"PRIx64 + # sabre.c sabre_set_request(int irq_num) "request irq %d" sabre_clear_request(int irq_num) "clear request irq %d" diff --git a/include/hw/pci-host/mv64361.h b/include/hw/pci-host/mv64361.h new file mode 100644 index 0000000000..9cdb35cb3c --- /dev/null +++ b/include/hw/pci-host/mv64361.h @@ -0,0 +1,8 @@ +#ifndef MV64361_H +#define MV64361_H + +#define TYPE_MV64361 "mv64361" + +PCIBus *mv64361_get_pci_bus(DeviceState *dev, int n); + +#endif diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h index ac0c23ebc7..5c14681b82 100644 --- a/include/hw/pci/pci_ids.h +++ b/include/hw/pci/pci_ids.h @@ -214,6 +214,7 @@ #define PCI_DEVICE_ID_VIA_8231_PM 0x8235 #define PCI_VENDOR_ID_MARVELL 0x11ab +#define PCI_DEVICE_ID_MARVELL_MV6436X 0x6460 #define PCI_VENDOR_ID_SILICON_MOTION 0x126f #define PCI_DEVICE_ID_SM501 0x0501 From ba7e5ac18e7b3232ec93e0d3324bba167b965d70 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Thu, 25 Mar 2021 14:50:39 +0100 Subject: [PATCH 0256/3028] hw/ppc: Add emulation of Genesi/bPlan Pegasos II MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new machine called pegasos2 emulating the Genesi/bPlan Pegasos II, a PowerPC board based on the Marvell MV64361 system controller and the VIA VT8231 integrated south bridge/superio chips. It can run Linux, AmigaOS and a wide range of MorphOS versions. Currently a firmware ROM image is needed to boot and only MorphOS has a video driver to produce graphics output. Linux could work too but distros that supported this machine don't include usual video drivers so those only run with serial console for now. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-Id: <30cbfb9cbe6f46a1e15a69a75fac45ac39340122.1616680239.git.balaton@eik.bme.hu> Signed-off-by: David Gibson --- MAINTAINERS | 10 ++ default-configs/devices/ppc-softmmu.mak | 2 + hw/ppc/Kconfig | 9 ++ hw/ppc/meson.build | 2 + hw/ppc/pegasos2.c | 144 ++++++++++++++++++++++++ 5 files changed, 167 insertions(+) create mode 100644 hw/ppc/pegasos2.c diff --git a/MAINTAINERS b/MAINTAINERS index 4c05ff8bba..6bc008d825 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1364,6 +1364,16 @@ F: pc-bios/canyonlands.dt[sb] F: pc-bios/u-boot-sam460ex-20100605.bin F: roms/u-boot-sam460ex +pegasos2 +M: BALATON Zoltan +R: David Gibson +L: qemu-ppc@nongnu.org +S: Maintained +F: hw/ppc/pegasos2.c +F: hw/pci-host/mv64361.c +F: hw/pci-host/mv643xx.h +F: include/hw/pci-host/mv64361.h + RISC-V Machines --------------- OpenTitan diff --git a/default-configs/devices/ppc-softmmu.mak b/default-configs/devices/ppc-softmmu.mak index 61b78b844d..c2d41198cd 100644 --- a/default-configs/devices/ppc-softmmu.mak +++ b/default-configs/devices/ppc-softmmu.mak @@ -14,5 +14,7 @@ CONFIG_SAM460EX=y CONFIG_MAC_OLDWORLD=y CONFIG_MAC_NEWWORLD=y +CONFIG_PEGASOS2=n + # For PReP CONFIG_PREP=y diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index d11dc30509..e51e0e5e5a 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -68,6 +68,15 @@ config SAM460EX select USB_OHCI select FDT_PPC +config PEGASOS2 + bool + select MV64361 + select VT82C686 + select IDE_VIA + select SMBUS_EEPROM +# This should come with VT82C686 + select ACPI_X86 + config PREP bool imply PCI_DEVICES diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build index 218631c883..86d6f379d1 100644 --- a/hw/ppc/meson.build +++ b/hw/ppc/meson.build @@ -78,5 +78,7 @@ ppc_ss.add(when: 'CONFIG_E500', if_true: files( )) # PowerPC 440 Xilinx ML507 reference board. ppc_ss.add(when: 'CONFIG_VIRTEX', if_true: files('virtex_ml507.c')) +# Pegasos2 +ppc_ss.add(when: 'CONFIG_PEGASOS2', if_true: files('pegasos2.c')) hw_arch += {'ppc': ppc_ss} diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c new file mode 100644 index 0000000000..0bfd0928aa --- /dev/null +++ b/hw/ppc/pegasos2.c @@ -0,0 +1,144 @@ +/* + * QEMU PowerPC CHRP (Genesi/bPlan Pegasos II) hardware System Emulator + * + * Copyright (c) 2018-2020 BALATON Zoltan + * + * This work is licensed under the GNU GPL license version 2 or later. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/ppc/ppc.h" +#include "hw/sysbus.h" +#include "hw/pci/pci_host.h" +#include "hw/irq.h" +#include "hw/pci-host/mv64361.h" +#include "hw/isa/vt82c686.h" +#include "hw/ide/pci.h" +#include "hw/i2c/smbus_eeprom.h" +#include "hw/qdev-properties.h" +#include "sysemu/reset.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/fw-path-provider.h" +#include "elf.h" +#include "qemu/log.h" +#include "qemu/error-report.h" +#include "sysemu/kvm.h" +#include "kvm_ppc.h" +#include "exec/address-spaces.h" +#include "trace.h" +#include "qemu/datadir.h" +#include "sysemu/device_tree.h" + +#define PROM_FILENAME "pegasos2.rom" +#define PROM_ADDR 0xfff00000 +#define PROM_SIZE 0x80000 + +#define BUS_FREQ_HZ 133333333 + +static void pegasos2_cpu_reset(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + cpu_reset(CPU(cpu)); + cpu->env.spr[SPR_HID1] = 7ULL << 28; +} + +static void pegasos2_init(MachineState *machine) +{ + PowerPCCPU *cpu = NULL; + MemoryRegion *rom = g_new(MemoryRegion, 1); + DeviceState *mv; + PCIBus *pci_bus; + PCIDevice *dev; + I2CBus *i2c_bus; + const char *fwname = machine->firmware ?: PROM_FILENAME; + char *filename; + int sz; + uint8_t *spd_data; + + /* init CPU */ + cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); + if (PPC_INPUT(&cpu->env) != PPC_FLAGS_INPUT_6xx) { + error_report("Incompatible CPU, only 6xx bus supported"); + exit(1); + } + + /* Set time-base frequency */ + cpu_ppc_tb_init(&cpu->env, BUS_FREQ_HZ / 4); + qemu_register_reset(pegasos2_cpu_reset, cpu); + + /* RAM */ + memory_region_add_subregion(get_system_memory(), 0, machine->ram); + + /* allocate and load firmware */ + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, fwname); + if (!filename) { + error_report("Could not find firmware '%s'", fwname); + exit(1); + } + memory_region_init_rom(rom, NULL, "pegasos2.rom", PROM_SIZE, &error_fatal); + memory_region_add_subregion(get_system_memory(), PROM_ADDR, rom); + sz = load_elf(filename, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, + PPC_ELF_MACHINE, 0, 0); + if (sz <= 0) { + sz = load_image_targphys(filename, PROM_ADDR, PROM_SIZE); + } + if (sz <= 0 || sz > PROM_SIZE) { + error_report("Could not load firmware '%s'", filename); + exit(1); + } + g_free(filename); + + /* Marvell Discovery II system controller */ + mv = DEVICE(sysbus_create_simple(TYPE_MV64361, -1, + ((qemu_irq *)cpu->env.irq_inputs)[PPC6xx_INPUT_INT])); + pci_bus = mv64361_get_pci_bus(mv, 1); + + /* VIA VT8231 South Bridge (multifunction PCI device) */ + /* VT8231 function 0: PCI-to-ISA Bridge */ + dev = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(12, 0), true, + TYPE_VT8231_ISA); + qdev_connect_gpio_out(DEVICE(dev), 0, + qdev_get_gpio_in_named(mv, "gpp", 31)); + + /* VT8231 function 1: IDE Controller */ + dev = pci_create_simple(pci_bus, PCI_DEVFN(12, 1), "via-ide"); + pci_ide_create_devs(dev); + + /* VT8231 function 2-3: USB Ports */ + pci_create_simple(pci_bus, PCI_DEVFN(12, 2), "vt82c686b-usb-uhci"); + pci_create_simple(pci_bus, PCI_DEVFN(12, 3), "vt82c686b-usb-uhci"); + + /* VT8231 function 4: Power Management Controller */ + dev = pci_create_simple(pci_bus, PCI_DEVFN(12, 4), TYPE_VT8231_PM); + i2c_bus = I2C_BUS(qdev_get_child_bus(DEVICE(dev), "i2c")); + spd_data = spd_data_generate(DDR, machine->ram_size); + smbus_eeprom_init_one(i2c_bus, 0x57, spd_data); + + /* VT8231 function 5-6: AC97 Audio & Modem */ + pci_create_simple(pci_bus, PCI_DEVFN(12, 5), TYPE_VIA_AC97); + pci_create_simple(pci_bus, PCI_DEVFN(12, 6), TYPE_VIA_MC97); + + /* other PC hardware */ + pci_vga_init(pci_bus); +} + +static void pegasos2_machine(MachineClass *mc) +{ + mc->desc = "Genesi/bPlan Pegasos II"; + mc->init = pegasos2_init; + mc->block_default_type = IF_IDE; + mc->default_boot_order = "cd"; + mc->default_display = "std"; + mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("7400_v2.9"); + mc->default_ram_id = "pegasos2.ram"; + mc->default_ram_size = 512 * MiB; +} + +DEFINE_MACHINE("pegasos2", pegasos2_machine) From 4b98e72d973f8612d3f65fd1dbcdd232a62bd6d6 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 31 Mar 2021 13:51:23 +1100 Subject: [PATCH 0257/3028] spapr: Rename RTAS_MAX_ADDR to FDT_MAX_ADDR SLOF instantiates RTAS since 744a928ccee9 ("spapr: Stop providing RTAS blob") so the max address applies to the FDT only. This renames the macro and fixes up the comment. This should not cause any behavioral change. Signed-off-by: Alexey Kardashevskiy Message-Id: <20210331025123.29310-1-aik@ozlabs.ru> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 529ff056dd..fd53615df0 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -100,7 +100,7 @@ * * We load our kernel at 4M, leaving space for SLOF initial image */ -#define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */ +#define FDT_MAX_ADDR 0x80000000 /* FDT must stay below that */ #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" #define FW_OVERHEAD 0x2800000 @@ -1617,11 +1617,11 @@ static void spapr_machine_reset(MachineState *machine) spapr_clear_pending_events(spapr); /* - * We place the device tree and RTAS just below either the top of the RMA, + * We place the device tree just below either the top of the RMA, * or just below 2GB, whichever is lower, so that it can be * processed with 32-bit real mode code if necessary */ - fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE; + fdt_addr = MIN(spapr->rma_size, FDT_MAX_ADDR) - FDT_MAX_SIZE; fdt = spapr_build_fdt(spapr, true, FDT_MAX_SIZE); @@ -2694,7 +2694,7 @@ static void spapr_machine_init(MachineState *machine) spapr->rma_size = spapr_rma_size(spapr, &error_fatal); /* Setup a load limit for the ramdisk leaving room for SLOF and FDT */ - load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD; + load_limit = MIN(spapr->rma_size, FDT_MAX_ADDR) - FW_OVERHEAD; /* * VSMT must be set in order to be able to compute VCPU ids, ie to From 53d7d7e2b164f97ae36bca3cb3b3cf1ba2abe4c0 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Fri, 2 Apr 2021 15:51:28 +0530 Subject: [PATCH 0258/3028] ppc/spapr: Add support for implement support for H_SCM_HEALTH Add support for H_SCM_HEALTH hcall described at [1] for spapr nvdimms. This enables guest to detect the 'unarmed' status of a specific spapr nvdimm identified by its DRC and if its unarmed, mark the region backed by the nvdimm as read-only. The patch adds h_scm_health() to handle the H_SCM_HEALTH hcall which returns two 64-bit bitmaps (health bitmap, health bitmap mask) derived from 'struct nvdimm->unarmed' member. Linux kernel side changes to enable handling of 'unarmed' nvdimms for ppc64 are proposed at [2]. References: [1] "Hypercall Op-codes (hcalls)" https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/powerpc/papr_hcalls.rst#n220 [2] "powerpc/papr_scm: Mark nvdimm as unarmed if needed during probe" https://lore.kernel.org/linux-nvdimm/20210329113103.476760-1-vaibhav@linux.ibm.com/ Signed-off-by: Vaibhav Jain Message-Id: <20210402102128.213943-1-vaibhav@linux.ibm.com> Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr_nvdimm.c | 36 ++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 3 ++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index b46c36917c..252204e25f 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -31,6 +31,10 @@ #include "qemu/range.h" #include "hw/ppc/spapr_numa.h" +/* DIMM health bitmap bitmap indicators. Taken from kernel's papr_scm.c */ +/* SCM device is unable to persist memory contents */ +#define PAPR_PMEM_UNARMED PPC_BIT(0) + bool spapr_nvdimm_validate(HotplugHandler *hotplug_dev, NVDIMMDevice *nvdimm, uint64_t size, Error **errp) { @@ -467,6 +471,37 @@ static target_ulong h_scm_unbind_all(PowerPCCPU *cpu, SpaprMachineState *spapr, return H_SUCCESS; } +static target_ulong h_scm_health(PowerPCCPU *cpu, SpaprMachineState *spapr, + target_ulong opcode, target_ulong *args) +{ + + NVDIMMDevice *nvdimm; + uint64_t hbitmap = 0; + uint32_t drc_index = args[0]; + SpaprDrc *drc = spapr_drc_by_index(drc_index); + const uint64_t hbitmap_mask = PAPR_PMEM_UNARMED; + + + /* Ensure that the drc is valid & is valid PMEM dimm and is plugged in */ + if (!drc || !drc->dev || + spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PMEM) { + return H_PARAMETER; + } + + nvdimm = NVDIMM(drc->dev); + + /* Update if the nvdimm is unarmed and send its status via health bitmaps */ + if (object_property_get_bool(OBJECT(nvdimm), NVDIMM_UNARMED_PROP, NULL)) { + hbitmap |= PAPR_PMEM_UNARMED; + } + + /* Update the out args with health bitmap/mask */ + args[0] = hbitmap; + args[1] = hbitmap_mask; + + return H_SUCCESS; +} + static void spapr_scm_register_types(void) { /* qemu/scm specific hcalls */ @@ -475,6 +510,7 @@ static void spapr_scm_register_types(void) spapr_register_hypercall(H_SCM_BIND_MEM, h_scm_bind_mem); spapr_register_hypercall(H_SCM_UNBIND_MEM, h_scm_unbind_mem); spapr_register_hypercall(H_SCM_UNBIND_ALL, h_scm_unbind_all); + spapr_register_hypercall(H_SCM_HEALTH, h_scm_health); } type_init(spapr_scm_register_types) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index bf7cab7a2c..d2b5a9bdf9 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -538,8 +538,9 @@ struct SpaprMachineState { #define H_SCM_BIND_MEM 0x3EC #define H_SCM_UNBIND_MEM 0x3F0 #define H_SCM_UNBIND_ALL 0x3FC +#define H_SCM_HEALTH 0x400 -#define MAX_HCALL_OPCODE H_SCM_UNBIND_ALL +#define MAX_HCALL_OPCODE H_SCM_HEALTH /* The hcalls above are standardized in PAPR and implemented by pHyp * as well. From 8c8a7ed50ca538f743810cda8d06010498ef1f62 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 6 Apr 2021 13:09:44 +0800 Subject: [PATCH 0259/3028] roms/Makefile: Update ppce500 u-boot build directory name Currently building ppce500 u-boot image results in modified: roms/u-boot (untracked content) As roms/u-boot/.gitignore indicates, update the build directory name to build-e500 to eliminate this message. Signed-off-by: Bin Meng Signed-off-by: David Gibson --- roms/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/roms/Makefile b/roms/Makefile index 5ffe3317ac..eeb5970348 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -154,10 +154,10 @@ slof: cp SLOF/boot_rom.bin ../pc-bios/slof.bin u-boot.e500: - $(MAKE) -C u-boot O=build.e500 qemu-ppce500_config + $(MAKE) -C u-boot O=build-e500 qemu-ppce500_config $(MAKE) -C u-boot CROSS_COMPILE=$(powerpc_cross_prefix) \ - O=build.e500 - $(powerpc_cross_prefix)strip u-boot/build.e500/u-boot -o \ + O=build-e500 + $(powerpc_cross_prefix)strip u-boot/build-e500/u-boot -o \ ../pc-bios/u-boot.e500 u-boot.sam460: @@ -205,7 +205,7 @@ clean: $(MAKE) -C ipxe/src veryclean $(MAKE) -C edk2/BaseTools clean $(MAKE) -C SLOF clean - rm -rf u-boot/build.e500 + rm -rf u-boot/build-e500 $(MAKE) -C u-boot-sam460ex distclean $(MAKE) -C skiboot clean $(MAKE) -f Makefile.edk2 clean From 335b6389374a53e012382f4dd9338f9ab61ff902 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 6 Apr 2021 12:40:16 +0800 Subject: [PATCH 0260/3028] roms/u-boot: Bump ppce500 u-boot to v2021.04 to fix broken pci support When QEMU originally supported the ppce500 machine back in Jan 2014, it was created with a 1:1 mapping of PCI bus address. Things seemed to change rapidly that in Nov 2014 with the following QEMU commits: commit e6b4e5f4795b ("PPC: e500: Move CCSR and MMIO space to upper end of address space") and commit cb3778a0455a ("PPC: e500 pci host: Add support for ATMUs") the PCI memory and IO physical address were moved to beyond 4 GiB, but PCI bus address remained below 4 GiB, hence a non-identity mapping was created. Unfortunately corresponding U-Boot updates were missed along with the QEMU changes and the U-Boot QEMU ppce500 PCI support has been broken since then, until this issue was fixed recently in U-Boot mainline v2021.04 release, specifically by the following U-Boot series: http://patchwork.ozlabs.org/project/uboot/list/?series=230985&state=* The cross-compilation toolchain used to build the U-Boot image is: https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/10.1.0/x86_64-gcc-10.1.0-nolibc-powerpc-linux.tar.xz Signed-off-by: Bin Meng Signed-off-by: David Gibson --- pc-bios/u-boot.e500 | Bin 349148 -> 406920 bytes roms/u-boot | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/u-boot.e500 b/pc-bios/u-boot.e500 index 732660f348f6123d24144ee29ef38611428dc2d9..d2e29f81d648e4fa7e010ab7c44f2d22154094aa 100644 GIT binary patch literal 406920 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 BEhzv1 literal 349148 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�OuHk*2B&?CXquv$9K-&FX;TI>FJF_q9>r;b&?-lCv%4oGWS#ZV8M{B!m}D<6H9k zX0Z*`tHBNDcSo|Z3)$F(Z0tgILl1jK-=}z|r?MZ%B=>W!Gw;bhg?gkf@Al>0zP#JF zp$BsZ-FT+kO`d$qedE4J9?$c5p2zdNh90s{l=+{YGAl6rDXZ(yeX{qJHQbYL*6uHp zIUchncc1Lz3m@E)%#E$8yc63<94d1KeK)iI>7w&And|9hCqns^K4_FE1y;_a>cu(E z&HR4!u=r)MNLTi=gEs~4+q(fzH{j{k(BoqGt%5tAvaUJ5&&s`hpJ`pg+}GYRu|1ai z+&;@K|5HCv>)&Vf^`OJ`<*73+;n8WFhatKm$(xO5$hGLggNi@l!|HFNN9xtS&Msj6 zN*m064XZh~%PY3nZrz)&=pwfIqA~ycd&s4KZyEDDZ%Muv+3=PoE`Kn&KZ^24OXK<( z$rZqNr;*nS(q};9Z>E+r$@6))z%pPMd1>1zd@lbMcJVIG6YaV^czf3o{bl{WJ-b2p zv3_|#yDZ7q>zAD;Kde!^bZmRD?3nYO)X_<-;@d?%U9pyZ?RSVhj)(e(kHN#o;NfHN z@G*F+9y?UeykxDa7a4J_8=A@9i2qL6mp~9NHkyKGWPKK4fB=_~OI|`x#$a$FZeg23{ZiY0JA&vwth+ zw+?}ahrlyK;F%!;bFPZzWhJvEoH$v(#HLz`Gvc?0KvT>^h9J~;nZ z({3y?Cmol$?lALKmt)&G!;wV{iDzG~44^SQSq!^82*QWB&=x zW;Zg=@5*;@qAhCYkFK}1@dvR;Y5dB!CGJ>oR^_wn;gRvwWbE)4qsLam8^QQ`6(a|< zG1c+-`itS0SX}U*^j}xu*Dgx6AHz2aX+0~GFie9k%R<_Ry`cxObbMO%kK#Ls*MPN2 zXtAs`-twySCw-^jo&OIfMxTE`@adkHYFpwcVDHrd_7$|TV!=j*_b~D^=3;rV{JZiO z0I$GUQJq;pt=(RHVEio)>lfmy{9~vcL4Q~!+x9`T%k4RW!!$Jy2tLc;`GqOCfTi=7 zVd?pc6fEMKFxFMjM(SI>3YX*l1zgr&ip$KKlenBr`)h%D{Y5xjRT@7x>wm^!my771 z*+zfxH!6w0@!)UVCHTwTC2LHy>S+8(Y-U@&WkowqF8lP$ILUlO;pDusUxE|-uDIa8 zt^S(vF1D`D_jWwMGKx zMY>t>n!swlvQJ_^DKq;h*5crATa zTie*x(s+;VqSF`fZc_dl@H-cNHLsoj|HNwhOTRY&6|I>_aP6hD_HI^EgUzS5f+@3-?Z z@)l&Tp>};=Bm8fT6M2juq0O4gYuHbCB=dSrm)h>wdC{Nff3;_jcAtIxm3^tc?8LTx z(OL zchNoAP--bZZ>_|>Nxz~qWvz5dR-`}l|B;K{|0}Un-9_*3S31gh|HMV_FXesKzkR9w zn$-JFyfi@7zB=&kn{pAn>pHdv5A2nizhqpeOWev?HzQN+SI2qYKE6!GcWvq!@ujLi z|8lM@E^$%J>HF=EEhk^)179`sDv3c;HDJ^SrD~JRf7~Qzf!2yoDLEG3^ICeWTC0go z68`@@Y5QCoBxgfidp>KidnDIl$Jme7sr?E_?N{e7e2v1F8v74%rS{8rP;*Cj|3R(W z3=G9@9!U*W;>1geUiGeV_?hJR#edem%Qthy?=+{2Ug`SMfCWNRmrwT9o_CX`(eD*f zuP1$9949gN(4%gFRukPgQfeS%y?fgHKWMcD#hUEbA!`!5@V~5o&z#a#{A2bm8}v?; zd5smtzjVnO#Cn;_@clt@N}mlif2L~pGNY5829{4(hcs8eWuL1WXcw^5ioY!}P1*4g z{jCswsyqEV18R!}-hOuNG`a3i`s3f3!v0&S{>UF~8ZcjAa=Ezzk83?wm*i2k+PRAck#~)5_=)t}RPYSHe0gmx&)DrR?{?9Up zR+_;)zT4lRX;r~-b?Dm63113X=r_G)^g^q z99d}fU|$Z(c&VL!AKyU(<`KXNza~Z@XUiNpdt=rX7df7kY!T-pZUvLk3>`5B+8twI!elPRuzyJ+c|9sg>sn1Y4@_A}i)H=7zdd)6Wd+82PLya1&jw;>IGY&C-g>!2FQ0IZRZ&^mq!iFYzEAC^1bZ2rL(`P)R>BF zjF7rWr*5a|?}72)#-_GX)qCcxORm$d;hW5PKH}H$YA&cT;MZJB&Z(T=s_0JYsAVo* z=3f*p&sR!q96Y&Uz|#_25`)nv{mI-;ZRKF}u+5wwaVq!R^Y{(#>k1C~W$%HJ;P(OI zE~S%zah=3qq9-EP!~fUA|JTF+*EjSi=#1>7SA*a4A4fY^tGHG2@}=?4KX+;nwL0N- zXqKt!KNCkkmixezAvhJB(6>k6PCox@^^1&iv&(E77csswPap58=9LspK7LYs1-{+T zj=!U_u5U-|X>{jIRYOFlm1$Vj4?F&QeB%wY^Uj3I|H{NLvJ;aeG-zgX21 zdQ$mV^vFW^KU?fA_)+sV*hOSNXOXNS^kKj8YyYflz%z*>*n5}cRqvz57g|d#VH&iS zTA|mI_tR2qE*QJi)1_eOp6XlrQ~hIO#HNam0&PW3>MOrZ{iEb48`x8PIeawRWzIvX z(U!7pyfYcubd!&%Rr4mY?=kHFgI3uM8gzwTU7=T3=+(8M2XZQFVU&MCU+ZL?&iHPS z^%ONSZ_FO1(Eg)yN!n8zgB_oMjsqsg#(!|HPsQU>@0c3To}#Vftz;ZB9?q)j<%_X5 z3VH-syu_GYeaq6Nj#$lSmd4ZOiLWGZGKNJecdfY;zw!GZ`q9@>KRV~1pS%N_?1C>w zU92YsUpyPb*kYVfA^T5wUno-RHq(4tU9ovX(xkS^wIBihhNPv}ZFPyfCHENosJlZ? zaLHJK$+h5E3NPQO2Nv=I?Ydgp2Zl@H59(s@iB&y~oZk?S!1O@#Ed4KfY0TaD2+d+;*J4evCY|s@oMF5WEULOB07T!>30UJg$Yc~+h-qZ{s!;PQ@Ow?l7BrsOX)f0Fr*!4z99Rr)ZA%xOH=E2u3yoi z|0${dRo}A4O4g_RlX*gk2@;2I7C2(UzcR1=7&=t;uqFpr4cyh0%uzrWe6bNSe{k_S zOxReh6A_tA`I%0;hp6>U*JxLlxpK*UD?btbA>Xaqg12?*4`hBK)0|CCxbL^~&6=V6 z%$ktY7Zo#x21nLkTM6B-+X5`2*BQr%He0ud@w77E*=x8VwVLQR9ld_t1pc^QAvzLS zlJjcY)&sy}VpmUuv^ReNpNPF7N0=S1dYXNRzH?l!90ML@E;9GmtZ&HEsVk57 zeN(UMnKF}OYv#Rd?2;ZmqV0{IZSny-wf%`Q^H+VJifw4eli*O`5PV4vSzwp;lDJB> zcL7`QmcSKV@ms@uMDP)xLLVADqt@TSW7>lw2YfbQcKl;-5(K z)Ean(IZLZso?3Tq*D4+=WG;vGO=|xi$?wbAQQs@?3Kp~|9Zen?f6?VVA~1{ZDQ)xq>SViR z_#!&^(xBHB_T~~j(8|2)(uC|;+J*IP_2dl8(A{0&sXCrX{c$ZgQg+&$-B)x*HuG&B zS*+USI@azyMj{Vx^1lNd;BCvEQi|Ip@0+GOv+FSWT> z;%|#sS@fOo7&<#k(X&$Xh(9T7rRMbp_IgdtmG!?CANGB819m`gCv)<|2Om>wESpJCbV%b0n4(zZd%_ag~QLzAH2lon6NmnXgz;NuT%=YA)KT>$omFbUyW- z>f1y@Xe;0IZcJbhyvS920htRK@NA-)@ojSSQer)8U8II?Z3=fXKEZE_CNeJIXjQak zucAtR(}(CrnKwP&1AjPj%%fEB{k12bxcE9hk&gcLH_BJShNM7g}pY=XOe?Kf2524Fz*lbm$9RV z-SSRH9m{W#)l*zExi%r=8R$N5zs{1!8HU~~(V<<9c_dFa@BbG5NvK$4_crn}NPr(^V*GR2!tGdU#Y7E(-GPREgGG?yi|04mzoHR)ErY>VDZEe05 zUgJAti{HvGN$LgZQ}ja{&G1DO&4fRYP4l3dUsUtf(9BEBl5M`*$ei&Y9e+KW-x=ns z^!1+FSB6+5t1Xtk=3KD*OsB z+$VCO^i93CmiOGgeVq5ZjQt9BYHH1(*mU1c@bPRPy^h!q8U3B~qwq!y=r88H(UJHB z{LfsZTdwn8RlaS$zUZ2 z8~A@5eYlxBWdA;8=SRg7&>Wo0nQ3xf75<~_U+a~c2d?SK_p)h=vqe>`(-U}fXhXeA zuT${b7r=9x>uIhhQncFYQhevo>K*7rekWDW%X=yQ8?SVb*5zYj&P;`S%lo~U4 zzXDl~zbv`}oQ0FHF!#p%Zng4hiz`-mzXxoZS#wC$nhMR7o=jYDCBKusmceP_6nnF& zJVNq+S)=52_VDpEwBcnawmrqe)LE#r(WMr$Mff=W-Q*Yxg%2eDS9(-xt=Mulwj6td ze!~7qovnAkEY4*{=R+4Y2h7zcI+C+3LhN2g)^MJ~09_*c+plbrdC-C6H@pO{eMEV18`w^Fw1!cTdpu5C<}$ZrB2g)ZQIx5QC0 zM&9Y3vJGN$fln9zB(?6PwDt451zyQ1vG<{@$51wb_$()dBmAJOy5(a3TYIK(6XPDZ z@F@H!+;qJ~Y^Su1TxXFt>?AY`-|LJSJfOQm3|%o;!3=xRLln;pa^E>Y?0A{&w<^k-j2Xyf*fw?FNN3r-1qED?M@ASuSOqbk-^kr{8 zgx>u01=%A()gMX!t)F$~{WQ@*_&>5Q1##my`XQsTmRD-i9DBYEpDpP(fQM|U*#_6x zmrqAxU$TYYz_si_;4y!U{-kaEr_?@AUih^w$Fz01v(`Yhhit)T6OyoxQhu_+OLKR* zhnDkyx!F^u+NBRAXV?LW-6e(>S(E;-Z}fF8pK)Lht~M^AAGS!@q?d0LnU;Bp zl}SClNb#1|=@-}(6~n+AuCU?#9=foWd)f1PBeQptJJ`ncTFsl(lgoJKw#E=2IeM~= zchHf8QaUomb8I)Z+<87t;UC}D$?Jac_hkPPyY-}|L)O3Q$eEj~>|s#s*av+Pd$GBt zrVKngKC;RSfA&}8yesl|LcUQkN_}FSRZt3E6FUMw#*p?PuWK?*IJ@;ng7m3~NCu4#a ziFw(V1wAHfJN$iBJg3ebk!Se)l2=sw=Lr7^4+u|m^lj+t<_>)+eUR+y+GJlj7xk4T zeIbMDOt62oA9Ge;V=I1?_}0kX0O>>J&Rb8W>PZTO@0EYidh*?*uJbs4H2Skz(L$}A zba?p6b>PdgElqs#JLn+auU!D10!8S| zd)_nxF3sH^d&GuUaYLfPDrow>>Vq|#qW|HSVwEFk{aEGkk?H#6JH`B8r*wg$ zRpwmcRPmu6V4VMpe*S26>|fK*d)wMd(N^@m*g9f?>PZsMe*8$1ww`wTe)6a49_JM# zb9TN!ql&|`<+ojru1Oryi4SFekxb#W($E@ZMZ;|l?+Qfl*9+T^LH6rYTS&=E$|C}!XsJu zr0mgnjc(f4aOMXwN?&-s$Qf_Q)uWNNl{{~GU&+v5SsSKuTG%A>g7WQJ1J_VjOn=Gz zgGc7q0@#1ro3`MB>gT>T*;jd`#O>lgp)<$Dh@YHX(}jUz=Vkw7$5lc=>Vj`hWl1KN0kEGAlgIs`|IhPQd>hPS{Uct%pYRx0DA?uIu0UW>J znCuIeZU5#Yqs=#v_wfxxM=Lx2W&c3p0Yx|P?ZmF+)&$2%KP^LO&$k!Fu!?V*+F%mh zE3|UfLOHrO5x*HY1vfb=h7;cspTd#R^W7Eg>{JZfomgD8+3x%NkK=4o{?ETY&O}xU z){yHD%f(ixdTQ)N?3otHj}hyFQ|2?Mj~JTd*})2zkD}|*6Ec6H@CRJV-XU)n`&uGf ziXUAW(^CDl#pJ}d$_FB!TADbPJVQm>MZJe+Kl_HvDXTecHJ_<`v2)iaeH6E>n-Tso zx9%-dxzc5c^YFw#1!om&b>J(}qsYN5u?^B@Qpep#J)p#l89W;&`678nu9Lpl&p>o7 z^XB}P{SFFEsU1{(H?Qv4xA`9ZGLO@qPi^TX{R!`L{^UX#w-X~=-ac;lP2sfK$#=n{ z_^lt#6P$`KB{($i#U|6=MR*i_J5v6Y_(43&P0E%RA6tB^ z&jlZfpL)0ZPsto{yL`cOZ9J-c_r!8=C;60o#iPU`9eGpmDZaXo^DV_EbNuu8TA@?O z)ph?R_ys4>$D{1D=tZRukBTl7TWvrukBmidBlv}XWnU+yC*iFzDh8AIv&|>Ep!UH6 z&&p<}zU8|K@*Q~CB{Y#5bMV)wbgJxW)%szw_BQdl&_Konyq*+3MV1s#rF0*-5SU9_ zkNCyk3k=7fSlTFl*I=bv1s>74tsf}+FFc;K`6@Q!{@;^))M0Mlz1B{6%0yOVFQmX> z<=d=9uEob`vm@vbZ<4me(dTai=jyyL^c{YFi^|~wi^!hJi#lU*k1>}bW8g8Qt+-qK zCds1+@2YpnwMoB%AN2mGa%JqwZb=?r=2}yI%3LM!=i7ouu^WOHyShZq&M=Zb0sfP+ zS?;7AO!}N%_NL@Kq&@$Rzb`p_+OUR{5Q8*IOd@-s$b8PH@OXoK3mnwHsJyH4H@Lq( z={u|q%w&FZNU7oInZznb*C%QvN5gk*vJi6pUiN=fafjrki9J&IqduUeJ3OYw0sNVg zTXlG~OTOqG;#gOQx`}qVKqre{5xuSC13oTI92qJ6ChdU}u|Ga(%fbI;``hfdim4Lp zLxC(4pE5+_7_uh*NwFSoN;rp?`-ZU{(X4L_F#BYaeu#C<|+pzjCtm~I(Q>~ zPVJL|-c)=uqMCg?&5>6b>`yJ{2fFzkmbqVQQqpBE6~998n@xV0y^LDaIT_~GoU)L% z-V$Ay?0Yi%$}jmDe_@pfP4&nFQB=Q@6Z@Vaj@c$$OEczJh9r(a7> zndQRSNto*D)chXI?j%f73LHK`I{rh6kv3I6LhCmt+6BShr{Sb^CF6{u%8Q`9!%kMfwsu-OpMX;EHu37x+B=y`t&X)MCzi z^Xv1tU&np=bp?))hkTZpeyPh7SS@?!dcSAomFTgqjBSdRRXvh8X*T;|VtA9ba zu5B(`K%4VuU-$)^m7)Aq{9$;|)sK6UZ}qzsuZ>%996NxX*$5u71Nnk0WJ&kWW#9g( z=fJ_3V*eCH57xPP1da@A%3UIJb4@pE^QJPU`^W0`(R2EOkMOxKS97B2)LeUG$FR?@ zf}dmfc8rPN{rK(Sx8xj*q(55=y}JlMFwbg+XM4ZrhsJ^@k#h?g4=dKjgEJMU${xzp zOq{Y~YW_Nt@%OVI&lkOv&6u;nq1s0R{CeuTG7m9Z>&N{Z`r8zq;^4n-H88yjj~oL} zU8x7n!*`pl+VgPLXw%C*^qp!~zl5jY&$>BIYylob2cPm6Bj4~Ed@1MJWWonJSC8-m z`|Zj30dD@!kXWAo*YW>)t{b>+;`uWEU&a4xQ@*s&LE4q~JI4LwHYJX3v>q+i{gbqH zA_qQ=zZiWNtNGjv`vbo^JFI$=wk+^8He|NiOYLX&)65S%N1N*8n+)ty;#j8GqZAIX`}vN~=hXGfx0llMe1_;XiLb5f zJ02mYEwSxj<|eg3Z6XnI181jUy7EWs!9gv0wn_At7ks%EDjYs4bGEM9>Q(4CH@Pv+ zF}E9=b#rNNYNDDm%~`!Od;bLgZ0z4N?ZggaW*?I>%K@WsR0ubp*SSyTb4t{bPCc3e8is z0-H5*jvk#d->9xpbM?NW&e_b_&o}(;Y5!EUKDW;2Om|<*h|{KQ@dx*)kvVrCfREAGg*@|Gu3&^OVimNk3gi z)4#wmj4SWFyDDGc@a_D;RRV{cab$()L&3xO@NV9DyY*Iq#kccGmx5;}@Lvqi!6}sv zJd5^!9Xzoe#Cs!H9}i5`=~{l#j~~B9;POvB`(H)PzsR$uw!`N?Ickmr<5<0D29wLc z=%0Gm3kp|LFNSffPCmDvz&PZi*>?+!fy6(y*olkbY|)1_PpuO;1Bsq}1Ws8u_+`Ac z=+#G9R|1T|_gWVTd%HgT)!jpB&SO*^cG|fbh3V>_{JR5F+B;tdlfWaen5Tvr(QYX^&CrX^CRzjz z|4IKafx|ipU%)rPtj8XCtXgy48*6_0fM5Jy$gM>>Y{^um0js1(~JeBPC;k)=2uKZ}SxJzclizF_h^+77<<~1u@zmH^R(X`-6=3CoaBI$5aUez z(9Jm6&%ft#DV2%P`aN+4(=2wk^g?&cI*oypbo%HAC&ru=))bh3YLv`XMBnz}ilWZ3iJL4mIzbMXf$9u>VDT?nkeH^g)AT?&8c*F7h&6=a&t zDLxhW0-ifx5%>yg;@?&9b>6Yofv^1Dj_~S>P*NnYUlyE8O{!k{{pB zH|Lp6clfLbv{CxyIX&XeSG;OnUFx&G2W?+Mr|>*dQWjJ^S|0G3XVFdj&^bJhD%HJa21%EbX5!(Cx9b z&-1qS1GJwd^V77?^S1Uc(7x0h*OwS}0>0s$wm#D7qX;`uLmzX&E$_AUGa}%#rec3< z=!ZE+>BpSIyR+#B+}g)l^oqo)pnar;bBONnnLAtHqdtZ;d!inh3yz+hs9Ur9`l185 z=C&B~@k6XBV|D-aZ~Q4TwJd0^?xR}|jMc3v=Y7%9TyrNH^YK@#+&pJYH-fXgNo;k& zwPdUjolf7o2kG9^cm9D!)2d`D(JyJ^881 zzQo7ywbWb@TV#^Q$t3pBsm+r3PmdISvXy!Sz2f+F(SSw0KRiG0ZqA#p(n5X5X~pJD z=J=o8>+FBZ91l6BapFe@*kix6^>3}jbD7S3(HA4tSp+H{^~Hm>{|z;Fr{@3fY|(G5 z*M^w&?9sxxs})E7zD2&tT9If7*W?c}7x&T4l`VRVc%qsyR1YQBK%S7f3NJMp*=n5y zwL0V``$_Cizcu8DlJlK^d!!wPGku%PrF4a~@%v##I=OxvT8sC|_+iOkER04}n-jRGL z@BKoq{AMlanVYE_%S^pX4MQ2frOqzQvyqb9;yrRoXS$2uOgov*-2R@G;KDhB40yRe zCbiB)`T-B^wK1)GvVi;ha-Xr*FxFU+_b0bZ$nEP=bD_(%pUvy7xr@9f{~CB-b5F?q z?d)XjbViYP(Z&h62jfzAz&n{m-poN0a>M^2`8a;7xl-}r!B-8xJ^YamX`R=eACIrb z?~jGF&qmR&li!7Q#0lyQ0hyO1R#58-Wc{g%ub?~ct8)kfz#JG#zVul&fAaw2?3S80 z3Te-sqt-xjEjx%Qr7l6$wIugTmi>d*%6Ao;Ij?TB>~RUtFuo3RMsCSL%eS&-lK1Nu z{7K=+l=vT9t(E-UsHIZhrfIj4OJNKR{%qnR>MdEL_mtpoi!*02BG9O5*HNRd^69fB z_Dr0%KVUu5l(aA9WLjU7x`=g~w-F~zW}m$yT#1b;)5#-^ zASacLj2+SXRgEBiN+$<7g1p~kv3KMI1O7)A4_P?2%J$FK!#z#~Mb4v(*RZ#p=8OL7VXkY8=-G8X z+uuhod~$4+ujY}((X-Eyuc*=k_40ooy&^j&7(KF4FW+%0XzlM~*!4588@qfJ{!>BQ z^RQw4{b7C|(#tR81nsQtx>>)QcQ*Kn_Rw#AAH%=rk;Ua_dAI&yy`o1>P-<=MU!v3c zZ#1ku4Zgyfu~pWd-G=mC;h~Q`^jSk&{dVitj)z&FvmJOEeHHb{WFzlwH)qT?>VH#0ZsIZUO7PvIIMRb)`#3Mw#uw&Xu}I|(f%Pl zau7N&mgu+{(0y2PY8&U{Nqc<8tBSo9V6ZP<7_-gb-J(@8GKL8*4 z&iT-8kYQ&EzWFZG>l@OK?=rWm?-Z?|Z~2{kmkFKDz5zW;jA*YaXo)ZJH^ILn2|uhd3I=|(+@6_dnDg*4_JE6- z&~GO2z|Zz(@PZr(KSxfU3Kl-icbf+p(VjEld%oMe-H48uuUBkl+yi$T_&`Pk`4##{ z2ZEQW_{n!abRe2NM=u!t(Q@mEyz_<;nacZDRzcf`jq*V`LBXxauK10?%O5&m&hJCK zLi>Y|Q}-dmIyFO&jt1ZE14g)x_uYIydIr8uixDlGua^&GOzwvcSS1s|=Nv=6wMvc~ zkrKw84{w~r*UDX@I(MKkB<6$5jE@?Nwjw7z|Y zA#x;miVp0fm#60h1uxObgW$(E40B}x*U?IL!Zq%ox$=M!oXnU$*=-a|r>~VIMtCLt z+yP$qR2k+@`28kegPzu&`Q&WigIjq2&4(4P?VIEs_~o-1oL9|v)8~*EfFIuA8}JpK zK7%-8tWoqK^m%xR?mr2fSIRqmjPOy$KVUaFf7mEG%6Onpbo6d?z(%9|5#WaB)%*U3 zmFz^Xs6vk{;r~2zbCoXgQ(gvs(P@IK^6Ahg3)qks>u*aO`XDn(Uh?NapZUnd8;0Q7 zIypxVW;}F2a3^wNeVU}tPvxBgMIVtD!K3Xtpy=c9o9Ocvqv#)uhc*@7%jBIyN=~8= zEph0xKSiG<#0AF{4x?99srT)h;Qz6Gkc;`c;7jBuIvxH-e#)-|9`K}iZLA|d)+g{9 zd@b^04-y?z)j@v17xE+c5syQKP5k-mpJnC4)g(EiocPcqE^O} z!gnuuCn-Mz=74jNj}m1!Z2ug+=p*?0cKSnRMAj9Jek$)AFoZ@*ZU%zKfmM1@(-T=0 z`S9n-O$P;Eg8S&dGrj?g6W$QnvIi`HeswlM)-EqK_yf0q{vj{bK1_tHiGZqlqa&}x#C55y8J2!zt(4u z8`dYa#5ucsO8!KaMo&l1&^4o>8S)mrYNjJ|Jq%xTdaci_83diCD>*89?};q`o=pcu zmPC%kmPMyy&vrbKB{DD1qK`06=piy&{t*2Re3&?*0J>MB&tpDokKq%1hzweLUPCrZ zjOZf^_!}lPm#6EnaJT-Lv)D9qdjnXQYNPnBQElZ97YGuRI*oel<`7C zkv(O%{tezm_ZD4Xyzs1|?;v!M=;V&{MK+^X;A>vFOVL;95s}Z6j1$?64ua0mR>|m1 zF-4E)X!amRPJ<6TktMPz^iwhkeMKe}eMduI=o$RacKX^kp#$y!&*0rU=g?Q-PvjT+ z+J5MZ?4m=IZHwLkeLe1A^oNF`ugIy;S7ftjze8VCc8Ttx7L~gA;)kA@Xj!C)xf3?Ms{N2d=X-vzI_CmPW_WZZomddGaCBdn8m7)2rY2Rq>}L56oj-}`Cn zB(!~~)@L0@KjdLAOEw~NgSd`WvM2Udav(){Ph^Sg`Ex}c4jGaQiyY(o{1QDn?Q!_J z&Zp!cb2_rV2t1dN7l9VJ;5H#TWH<6&>r-|(F&&$Wd?BAAyUMnrpG7w91bn_@_aw#V zd$#S1j&9-pXd`ORaBL;?w-e~(1ab}@MK>1xdG{od)#$($bpEz|7SEYCF~mNI%+jW^ zlXk-4A+fQ_PVU@2DLUQxCVHK``HThk>8uH$&u|q@85Uw6Ek(#w~bIHi;Zr(d)p* z*kwF2c9BWN`^cmkKXUdZ9Q*^G@i68NI1oE2I8Z(%I1riZh=Zd2e1rUT#DU15j9>Ye zf&-DU4mc<}z&9de9dUqvsc?Xt2@dSdyT6QsfAWp^m>qDS{7l9#GAB5&rVitqb{rJF z3*MAGwc|j^74#QhQ{lirns3_qKxC)rHSpFE2gs4&KzKl8No?zvaPSWOh`e;*10^>} z9uV0{jo&K4uZItcc72%#tO{rRGWO_M!58!w-3k5eQ!R=Y$m+B42qWDVa4Vix^Dxr@l$o;Vys{QCl-YIDzf4RgE`Ir2n(hKDC z&13Kq{&(~x`pHEGa+XLP7&L(1xi6~m0hb8X5|d@p$}$#Kd2F~8e#T>Rgb-{OD0$otA06LQ}_ zC3DIAR(q~=%%@5&mHes7W04CzLLOD^`y*=_B7w`cs5(PxrubGPkCVxB_DCV8%2jF% z$ww9U4UnUJmV6C$oPoQk_aO%)Ydp*u2UttD@zwS{pFVleP8`55-_2ZSq9H(j%5EWt zRM^74@8kr@C$dL5xy(;);hd`>=8|3HQ4=RBKKT2V@QVCFSu3eCCI%*ldNr{6ICC^B zl}j}z9rzdWsT&I=Hy6_W`)8> z4P`&3JP$hlvMv0dK|bpHe5xcCN%`B$?v(Pu20qUCE|<8)wvfJY1(q< z>LNGlj^u6+axYE(=h}&PGPtJmj$Au)KO_0hW%57wy6{dWS2yp-wJZ0@=c;zP$^YED zoOg7t8N4Ic?%coUp9=~a`-yX_!nw?ox942C8i*&`r!m^JP@w8BW<-e4qmRgk=$ zj~pHQIF|_BJh4uKU!TaU{LU`Q9X7|GJ7AHO`!F%jMm3+v+(4GhH_@I)Y80eh`7LvG ze4|I5t2>f&iar(vt**2s?YhfEj@AE`J754yrsXCrei+;w_2QQVkbm|r?<94Ss{YAi z-OBsJspC6Z=PN4t>G#d1Vd%RN^Q@9Q-E11ImxuNS%S%=Tt!|@@@{qu-+Rv1^%E%3i zg3(&8z+rVMFd{i+*!NWb)Y`bcGIsXR579SsAqLP=k z`Ag3K4gW{yo?c!_`#=7Yf38$|w3t4<^cPFxIW;C) zA0v`Z+|n&gorPe}Nz)_U=nr@z>GTIY=8@s_7oxA7JjOHEZQf16eC(vRMb=FsoWhxGD##*u@6QM)Q=L*Mdx z=uaFT9S0tI4%5S*(#IOE$LZsC#(kV|3>M{PP^) zg;hR($(lvtiwIrO9eVkyy+JDryS&PWpGjZvvZ(<>A-IzJ@U+}Fn}GYc@R9iUcR+_U zHK!S!v&OJ%)AXWmURf=D``vfBtP=XlDN(W(eO7Ur5uPKwMQ&;iu;-@1 z7xcsZiaFqk`_a6^jKN2Y$oD0~jUrF>APe5~yJu}NyW#V%?gKvv3}UWl|4_EYD^PBl;NSdEkk>L-`u$F`H+r z>0=~)t|lnj_uz2JIUB zyDRBq^n8B9x1*8g>{G$$IPODpv;Gjjh30*X=n8aLvG|6|e9>hg?ej?$6j zLX9vwD|!RDl`f2h{=?`hmG=O4(N)ox_?~_$Uc684>lG`EpgA8OeZ`AgqToIJ;x3h= z4zHLNbbdF*%^Hc(h?B`H!T>scURC{HOz?I+Z4Cl#DTNc@Qm+QhI~a=p4?)-@EkRRw?1l3-A!CB z_6gWt;F<^Bv15@O;oo6KxE9!MfxlO4X(kr%GJ=YlilBGNC z#2b2a&U1PNdco?+bs=ztpF;=0j|-76cs^SDoE}~UT=Wwbo_CK%PHtpwAqQSZ50*U6 zd<1Y{*CNNE6>=H*6nM~wz)>VBPR*qS~DD7 z;Z?faDtVq56+b$GUg)-q=h%X)r=cg%58ayL(KWR5bMSS1h90>eIMr`~4;p43Cx1Pf zI*BwR_+Q^WCgUu4so%d_;X{UXbBP{41HQsskHKTBON{UtAG!crdghd>b*VTGkI`Pm z8Sq7W*45_?OK*nfbNE9iVLL^qmH!-gh?mNzfIrb&Q-F*1%5OG;l3yv$1upd)xM)8* zeGqwB^kY}%VAhrVoU;vqt7eTgIL)x1Jfw%81g^nc>w#<2AtU^x*b?kwTz4bFRzK5$K!nCiIZTw}q#I z=2iGIH!TX<3zqP^j2t!i9fz)qgnaBJ!5_L6+sJ*r{B2;Fo~D;KAahrPtA?g{c@}uW zcPZC^>7|L(Uh{tza!UKrmmX&RH;-!?u~f0op4-P5^5lQC__Asbi2jRc=-|0ryTD)K zGitzfl<&s_*M$PT+*}kivkviFba0wsdC6h*TjUd6Yig5-@$paUfu|APs^|Tq$fWog zjp!+9CkAYPc~LKa>^|py47j)--ABAj&8hhtST3b^*A=|DzwhLIY2tSJQz@ z+R;RR0@pI&I(bjO45ef3<3mFMa2O<}&nMF>uZ0 zdJAx&qaww?wGw(Z0vG!;ie8oW!i~U1dv+{f*mHfrBsc@E+&uIuaCw2NCQq-p9=K?y z!V6rqQ{Di7b>6O*{~5TrU)~`4mUcYk`#gEN{Q>fgUNzUY7=;_wb@Fw-VV9*1(<5Hs zTFW&DxZJ~xh!xJ0*xfQxo2 zibbabS0ixc?AFVhfQ$R(jmRSR)f|9-m~M@tp0U@~JFU5k@VV^2STS-^P3XM)ki{5R z8=ZPxi&1``4;?hj2(LmGPqgUawdk&liTp+u!L?b7PK}{ciIXgMC!=CKGDuBY1$IWk zGv0xxLIa-A8+wJ?fu}-C!ZViny0OFH$rgN=CFB^nqVKKifbW`}jXw9~pNsz{{=an{ zSBYu5p`&8pt0c{c2)@Kd)j~(XBlwbWn#(3pJ2oC%dHFjJ&x#!ZU(0|GonNsA_@td> zz(+e3Uf{d`fL@UYd~)9_Iu(4)d`@cf^yvM_xY&(*mKa5My}ioUZQiX?LmzGgu6rDv zYIa4Z!uR;4$R%*)l{hgE?L{=;qCG2yu79=|m~tGrlukv@GyoSmHT)`YNjnX|MLQM6 zz_t3gUNI85xL;8$Iu*D!V{h0q(~dDOS9IBK8K*yY((UGT=n(Q@;n{nG=5<^bK*yVy zZ=UT#51~Uxo(e|CFF`J#qZc?wmZ8_Mvl1s=SBAeip1<=(&-*xSKul<#BcbE8b|T9?MJzP8E}1P5Wj(ICvc7IWLS4-z*Nj1x@<1(u(qIl zB=GG-zm7wX&BpeO6MP*qDmL90v|fE!uUKuU_A6G4uBRQz4ea6D*?Gp0U*7OX8E2rr z+brv*K8EPc2r-j&6W7Pk_xODgVkYw_@EtrAlzPwbtBX`W;e*hTe#|V^W?z+$t}o*c zxZL=fVtY*Rl}kH6ndY=(ie3e-3+OM_UsN0gf3#n5LG&uL8oiylZPBX}jUn^Wq)uIa#4)5nNp0awi-#}1)aC5NEk#STe(=D||V1`s=>IdCbx z3Z8BPU+C5H>|H?v@brJ zb&}_|q!~k=xVM|RG9Nll51VW8@2TAl9|SJ+eRvmitQ`hl0hb&8q9!Y)@1?(RJ#f*V zW%f0!2fWbG$Di1tVaOJAtOq{yeR(bL(N1~2=+{F=c_H{>9YuK#{3Z7bfs6a%6G|<* z=^kVZsr!%nEq6%x{!dm$8a@kpvk*FFIKI6-2R&5?TqVG@3AoU!;zKKVHmYEEPbzN!F4`$S2t8>>`C!Y|=;DK^`yKo*t5D)>@xK`3T;O|h{=>ek zezVMmL3(8TUi>evKZd_98)QVr1J}+p{0iVY$o+Bf7yehIxXkgtH1ui)eu>ie*rb|4 z9sI9BdijUbR6EN5q8;Ub?Zp3j^gic)48G^S<9`i8w~l3w(Caf_FE9%CJ=fs7tZBKj zL$SR<^L6aUY~T|6A@))1huFvOl;{9 zw4?m5F5C6;zW^8amH)+k$NxgFK8B1RWsE2K7=_K-NBO!uKFu1BzSF?h39gp|*X3ie z&){n+bo7F+pKu?&D(ywQWeQ%i0loTq2)G1i@K?!L$6qbp#q+UxMJaI6j`F`~NBLhj z?$*mc0xs?=|BL&M|HZd!hZ#kW{N({_Zkf+N_4enj7;rw0J}d=a_|uUQs~mk?3chO4 zqaU66zudild{ou7_kSh{VFFR39W`ixAW;*DAt<(!AA|v-9SHRfnh;dfAZUZ)ZLHj< zW1Y!NNQ4CO-b5$`1qoNMU@gT~@1+(5pIQs8-iP*DFIroJq6D-pTF?NQneY3v&lwUB z+TQ1TzyEyynAbV8&pCUqz4rRG*Is*V?AXgZ)gP~{2+zNh|KMxsEy3{UvY`C6;d_hu zr3U3&q1;n@FZkm9+PMv;p4xk%d+Mnj9IS{`{s#NH-Yy?(%lnA2!}!)hu0H(A!54C>wgtG5$2Bd$B|95GocuC1EdluSGJLzx)JJv5XK>bn zjC~b5+5(>S;0xJbyP?6ZXT2@&Yx98XF6^(%!I$dKv*o>Qe(*A9!&XQ;QBuJ8vwrUMNU7Q8VsW|LL1OU z8%7$rD*aRY0r}Zex2m%D98T7Ze`tb{Lmxks-Gq9 zYab3hjO<2k8lTC-Tt_jEgOGcU&!navxU^pbJrqs@fA!$21suD<(SVuQ&~^NfvDmBf zdr|n@ zsX^@zsgW<|T&|0N>w4ts66oty+m{pCb@iEjIsc5jnF`LP5^rT)jeQSX_W+L@xq3J7 z{SrNNxA2AB`w%^ZAF~!cr1IJi1=rP%{RO@b-5D(Z&9JYipWavJyTdn>1|>JE(}C*- zt{EGRy<43QeH8#-`r$tNp89Ii0~M+-^fY>Cv(IZ}^s5h`hmeg^f#-@{JfDhh1iIgi z{JcVP6}T1w7xsE>8*ouxy9l@_x9u;!ZA%H3|L2wdaKTLA`qs2?(VfB2ho$Hr;40$! zb>R91a_VmIbpW`oKWyZxd?u=|=6c|wzHmBv=v?#=HhBoR*gJ&13cf!CF4?OGfJ^m! z2tQKKjO&35Kj@6F0vF{ou7@8fx9utp29V(_(;dandui|+K)Tmf7k0_T+h#upra6~D<1$Oy^k1HiRGc2=op#=u=X zztb}#6S$~n#z62zJu|*uPkq>6-w0NO5AgpRg6rGRCHB`+`t)_?9v_$FgbpzG_;cou zLw`bFo|odO{vmMvi7Wn`a92vO`iJ1l;=3Yr%|Ob30o`|V-36Qj(NnvC@4zJ1A+Eu; z55SYac3_gRyX2>s5d}W?B=j|Kxsms|;LEYUOu6Qdl%KS}T9G~Opf`Lj@MYcbme>8v zRHKKw7{_zbHy?p7^h8Y;_(D&F{=@4H*WY5V(GB8y2)O*nw?hHw`$l*Mxj)r!Xg_Ip zh26J!W_+LVya&4fzUZF%9sw@dUrWFnKa_SZAt4vt@N>l)F0$-Te)hwu%f zj2@~U3|u!{=BZ}hp?N{|VDQxfF8{cLU{@vG)OdwL$lFN@l1YuXp@4!3`QK`~lwx zWkAyh_aH02X|Fr|2V<0$f-e51r{*B*-+uxo(g^5z%|YPO^Gy%YKhZokbiqh;G4K?D z+l#?H_0>v-39dW`u1dkhJhlLNF~z}GrGu}rz_h!R`h4DS9=dXD%dV1wAobqj34df! zM!jj^>$@+qF6<@F8hoV*UoU#9F9tTswFaZ|@cvZrC7G{&-Wsf_!e5N1;`rz|N*aVw{P%@lAp z8vdEW7~Ts`UcvT$75)NeGc>nN+v?Tx8N!*KXZ(~t2C*s7L*Q&i9&NK1QgzkN1AisI z#CL)ZrGzmnKtHm#(9qRb){TZNW#Gau zTA!-f5A9}f6|IRM_k%aC@~>(wx4QcMiygOyfD~^AFT0(g|?hxEj9GQw~-;1*R18gfXo#P z(3RFLbYGJOJkXDkTjoFTa5b?AAHj>pKXEJb8f=vUXsZQyrrd~rcHm*YJt6Vx{qkMS zXu%KAMo4ZV_^IlM^d9%jSPopQ6*u02znmC=8Q>-Kqfwslr|5zkw|ZxQAL8i^TrXb~Vzo@ZV!=pki*oN|Y8({j(veD@ z9O#DoY;pz}TI4<_^zfF!#i&mH*@Hg1>yziCrUJZNopzE;w4sGvd{zpF6wY#t8S><8z-F zFuS0BsS~@FGd_2C^X!7RzR$DV@wvBl%`SL-2={r!%Vqt49MfiUrS-+MEj!v5)AqZo z{=S&D-wpUXW7_indogXx>g`yqfA8#zX}kTt|Dl++aZU`||1V3Sit zZaGfe+eNyk>|)-@<(kbqx(=Z{*Lmj>-BWfc@8ogSd9At*r997hXPE9O8*Y!uzbTJx zLx}ygJ7!yiRl^3cm&^(y@a*wd@m-F-@vF_rM zrSZhVU$N)*`@~r$e8o}pI=RTo<@0a8*P7N`Wd)>vBip-sB8i@!BKGw*a;6LC2b@cc zWqw;axe}ituJTnYg?wPetxuCHbwi+7XRk2V#?Qh$d!v{A0GvDYQ{U!B^7(7ObK93J z*T3FmrGySt7L$7{Kwhb=$ETQ_doIqDZfMwOWlda|y1e1X)_INoWjaf6Tx7{gANd2a zY12h}E^K?XLwp}?H;MhE`6KT&Nz24&Od>+l5x%SB}L<= zv21*x-Smfj>g6Rz!Pf=R0C|7Ck=9mUXzM~x=!c^`&|tfAhlH=GBKAA=>3`1!Yej(>Vt@JtH2Na{&IFJ43s;9Ur_~_3q*P1$=GV{Q;3&N;Xh|SlUr?dyj?isyk~MC##>B3*C+d# zAZN{)`$_xROMr!3X0gZTSuXBVxTgH`T~_Lo^Q=^!hwi_Iyl~(`xd@zh6P(qe{E{x- zwMKLPcj-KG*qz_g2u}UVH?01Iel*(P_2~<&lz+=mUlKiyV_#%%h`YRWEI9(M0mmDb zcjV}id>YC~S z)~(RFPx;j%m**FUKFDWIzl8GMZs>C+@x*oTrJm>ZJtuBSeDe@|^V59JBJR!Oom}`e z6Ive3H{$`tb0UvF9C zeLj~t%SvS#l%*5HKZW~TcJ@!g`5k3uUTLG^acgwCxUU5)NJS?R>qi<>b2HYzWut=8EIx&9@)- zmijoSgtC&TcfXxD)aAb(TLo>n8Xwktp41fP=MU6AlwMIv`;oQnQ zvj1Rw>8G# zxsK=0S8wQP$HZRoBKT}K zc3r)F_9A>5ZOT^;z|SrYD(~n|`k@$pvrhvC$k4Th!o#ce0vpPjph2&-~P!qv*)j zOwQTPCYO-TQq1+jAKuQ(i#b2U$YPV%TIYO{V^z7#+t-pibhYJE8G!?frGA4~>MC&tbXzK&zN=W?zH=kg?a`CjK`95(ZTmywO+J7*7#a!}Pb z-QkSu5vvb38M&)U+>pk_wl+$s-cT&MltN&56U{D6@PH^MX0ndEt>MobhFsjYr3WkMqd2HY_~y zQqFp2+_2GU!=;=;)OjA?w$Q(wrtOvsx6Cd`eDcyn%RTzx3xDX{e@Hp87TB^arQt=& zt20#Bt&%4`)fcYxn|wefH<@*d2VHV_^dnCD_tO5o=wSM#dP8+pD?)Royh(2CK=qvH zu+W@a4NN81p$~Y6m>|XgSbVNqy&Db%^uG=H+4>9U=YW;fHZXDIk*_C?YmN4i#fcM- zd@s@4c>Rr@)?Xw(edItQ*0wkiZ~Z#<(cO=!>@SUr9w!a~f6c~!_3-V{(5w7^^x8T<0;P5Ua82YV>_#kJNcStnU3 zzI1G}@+3V7C#T?J6!^#xK4L3XPv}q?ep358=wf~N%D`r0cd_;sg4QTg&L}fi_q)D! z6?URObid)x<+fbAXk+syR!*6P>_vZL!#vwG);_nz$gZ*Mhcxz}YdJir^IQf~o(X)J z@SxRHalEd1I%Be8WU$O4@6>Zv+QLtGM!qqg&5hjrpTULGk+*9tZ{ttDAEZ2o^7`f- zR{6pwkI(0SF8>>v;>Q;>{o%Nt=kdRKVdL=t_xaq<4z1QphoE1L-Vl!cR?+qnYxpCSn{z6j zb8((PgfsGZhiB_()1~oH8GP1m?+1>5TzaGBYW)p4!XIK%`f7JE^8W&UVW3z zTrb*jzT?LL2HMZ6Z5>#lF;kt7b(r&e_Sdf7SD`a`^$faoM;80!2g!m~d#R%Zn6^g;*zfwmN#6_TMow%-r_Iah=KgAE<>uJFWMbh+L4*kRN6Po2IW zNcO#yzQ;QI_qlfQFXHrBG@NyRMvBhw$}JheSs1h}=c14e@* z-;>9W0JrGV$2I*V`~%(K+_m1u!|^?O$NNp@L-SIfj_!cw(IuhxeVd*6YGL$YE61^Q zbLp2ax&a^1qI|=%-lsX|V+Xlf_mAD|$T~On&^F%7YS?Yy&KKO_0h0~f?faP9u&>{5 z6&#In-^9K8p>HGg>c=GJjmOLT!9B1K?kvG=IdF^r{ubPMr@@{7KLGdmv%`I?1(@7| zx8Jz6{~fgLTQ}UgB+}X?8kva!?cn zr9j^%>k)3otgr@5e6nXIZKjFG&~tU*Xb?8QptIWmRsekw=litU*2GKl?}DpVuFB7< ztIjvYUv8bFHfmY#MW1jE@MlYFHx6v9-H!iyb!9Qn(Tm6C+Wq+atnv@MwlWTW>YBzk z8CBp+`eR$>b<=#03H-Yz54>!F_uz)M}p@Bzi%gjG%b^Z9A)2YTN%_tnt# zmr91G9QLlY8f;tS;8l#z@=#D`{CzGPrcX)m|P@!>16F?^dimKGxl=L@@_OVUd{da+(YNCGgRwn6JeE@z7y0~=WlYj9G zFC`JH0le1r!%c?Q##434+LXiLR$_^36Wd3YuDRCgy#5KzQ zCd!33x`Un?1CeTDISNjRb}so~+1ipcM(IZRwvBlJ_x z8qaIG>KW(D1%R)*q|93A47-!|;Uw9{ui3c#%d>wAm(EzkM316H!B5^d&6BW26O~Rqw*7ZT867Y5 z+I|o(xiiZ}AK~F;qKh2HVSePm34>d3ngaeMgVMh<(3&ZnV~5ny@44hlD_1OfRpP_% z*tlgb`-yOSq=EM@(3o;QmDZ1^jeeYUL40p#n=hF&bw@rDtV-;=S#x5|lg(V1d0aE| zxMt>YRf$iE!F{#XD1~$Myumqgp*ZaJ^@P(Mod4`qqdjjS#&j(o2>5K2omaxt=+b=wWy0sNRg z<3F&hi_vSjz?AD-*wf9`hYg#_T(lUREU0l0tN_=3aQ-FX931(@YvM7=JWd(<<0RgQ z%hEdN-^5!3u;>0YyxDYixc6-R(-^=*@2G9ra_XnrjkNmMg8=^0CkZ|ubT>0O2LH3T zKU{Y<*l6<<+zYQs+&lO!tV$eadJ)?Rc}Xg4&z(YrbH?Rf2zB}zKfl^z+faX8FCGU!tu_t( z$;kgR%e8oy-LF5rp*qTLVeO8!omCe@kB*$+%=BuWxgGxNkqz@V?3dL|=M$Im;;w+^ z4T}FjmuP;LWA3>!Hu?O|3a#1`(3~Lj-OCK@l(+b;p&uk|M8+g5()xbT;hEes`k@w2 z8YWr5yV;Jd z@8G2V@4$)1J;$-@i-9j!c(uppkAF@6?d%7`C4!;M*eid`!#{P>j}?uX{<=6{wwPa` z__$-Jm5;p6if$*?2j5h*gEQ5>1wB5IuUv55p@(w=Rk8WI<)hVis!!kI=St(vtiOp7DT3H~)!QJfwRMzBAS{xaZ2fTfQ>J&#QGFuEmsPMM`o5rriykp{}_d z?;B$@9Gyl!kOZ}l;54_>y{BN(bzzZf@Gv(&tE#+b63vdlBL;>o`3(zn=M9{I`JMp`LtldV+70pF>WdH)ovi$3Rb zj^663__W{aoZ%?%hDTQEjQdm0slVUPI)1J-i1)LpXHZ+JH5i{gXE))uE|}!uxm(Y? z=FCy-vVs21wmeE4;TdsLJY((3`1w=&J)3ID*XgD_CDMjnw>l98o=))9KtI~G9_M#m zTM~|1SG=^(nx=jpK#&4yPA8&6Ph*N9l%20 z^0Z!Saw9&)+08FoneFSq3qB|On#V${Pfv^*TRShxvt;aIly|f?3U9d>Yn@xtcb*H& zYxJLfFYOU6g{rc2lRYg4*syF+o@|1vHJHE7d1h1>|@9ZeSJt) zs4W*>buCZQrPd^|tzE>kWTOLHHNRrabxyX4w{&3EdSlk<@G`%#;e}>dv(F4)UnO|! zqZ_f&cIm821Mf@&8#*4?uxE=|=PU4xWvw+l)%8XaX7i4H)@D9FaIF_@F)`a$68l(C zoE4gv8#o1KbT;!n!Q3L4fp>o&j<22$on$5PDxA`G-q0y_y~^#?K99J)P5AY9v&M4} zA5#W4Ipe@OZ8FaKu)gOk6^r%zlV`86PHjc!F?PIH6}!9mBn>q&Mx3h|)jBih5E**n z4DhP>4ZD%qX~S1r9`3h;N2|og`IpFgewoNY)^Yb0afNp&*VWL>lAYAO$E>46%hWe6 z^x&nz(Bsf3^%{K!{cxU>;(zS(+{rEKx0ZxzPcScAy|>8m)#XG+{tDmcT@O3w%4dc` zZx!*q%Z`spsGY9rIRiemWyIJE;kW3HiALV#DMxB(!r-9jGqirR&gS7yvKXW8rYln1O%uVUnp-E)nKUyuh|{g(G(p25S3`O8PdwlqK&l7V(#iwj=bmr~f#l#+jg1ueKzs(GGk z`Wgh+k_Z1jI{39H@B(KU_%<-D-71`CmQjwsCBOCUIg1Ma1v;=P zB^wyF0fVcFHcDovV8^~63^z#@w!VgJE1dYx#M}IIS5b5&{6as?xl@Vw{qk?a6Zy^< zwL9-v{oeVS-a+o|1P=ARQ}l25Ys~Z=(5`cKlhIj<$wA()Eb(E7PcdRYTIto~3 zHQiyC)y*L`3mWH)rTx5{8XkGmitwQ6Z$_GZzHq_xH^T+l)6xIg)R#&8L<;S`!y2=$ zdx@JgxqPul(nR0La*xj5s)|?NB^sa{d1vV0kMDNhn?5uz?s;I>_{``7Q>Hz>$1D-F;2+7vW$)_U>&#s+))o>Q|z}EZ2``m_LyE3 zHo6-f37nN3O}5U^T6<_Ku)cduFm$vmxbS_}*NJ17zp*Md`-PIp*brY~-ZaI;D0X5W zrbV8rS`pbk<;}=;#uA%BvS2uP0j$@CcH0W95)8E&*Z!>Y!58mJNG+~1}wpFpy4^xNQS6}-2aPs?$_}&?}_dMuCc<-yfH@F54zm@y7$V2aW z+8<)v`r0t~1^%Qg$~?(CUUVwFM4j1sUvg0UCOGdcZP`k6F!T;j_-s3}IU0Fhaz4g9 zzbn91XR|xFx_ym}tJoF?R~sijX07jsr@}Mi>D00EJ;@x!zzvP`;U@2|;f8Ozli%3* zxc+tFW1+#v@bQfgK#vb3@nPz9=q-Lk-;G(#I)(H@!P~YR04Ecl?CnNg8GaM*nfUQ9 z!sY8vduJH4+%wbN=hs1JzJu||iMZ^K6RmE=2h^)TE!@b+Lgtgh&EywhqzN9qXx{R|_jE#fMkw`p>PLqv- z?Xy3!gq-}uDYHLm7S~L>?};vb$9V0Po@)Mgcx#P;rCj|N{TMqdcFPa&)%A+5y*sV( z;BZ!C@m|?o<4SUQ2VPt?-tfW^*`eYQ?1)wBmu&s^Z`ryEUfJ4IYNa*Fu3~QX=pg1M zTD%r5xoW5nM zZ@`qfauYCZ`Y71OfNB1}YKocn$d;+IY4Y-$MU&h2S+i=!`c+CZ0;ltK%e9AnYiSiH+Il}*|tUaOOu(;RNjod@HsYal6Q<8 z$BvNv4$9wC`ZD?;cJp)ciwc*GiU%!!YqQ2Gf*&iA_OoE)&wh-Ja`U4zwhoL(GX7KY zU}jSZV`XdrtFm?u>ppWV-{|HPOFk!WU5e4ItZfYe|9XF%#;7Vj@h<4K6MEgMakX_s zc$%5_B#y31)(O3Ak*^S3Vndqmt^#J^{gpAxRPM@NSaJN7$eQ|d8)Xl^{dtNF>}*r&dAw%;w$5Lvm$V(qQIb|~|>|J7aO@KK&wL)!3tXyf?2&uNms(_kC$h+hnSeAh3Y&WyC`xfRfN zTr(es=T%=R@9LiUQ+6Zx5MJzg)3NEaxw7%+KMwZoT|T_s#$PXY94x zru}*HJvFkHNX*YB;MjO-fB*ct-QQR{{cSgNo`}geV*9$7YoUkpjIWQmy>y%AHk#K! zE1AeR@vv9(tft!-=X?6(y~bK|AnM&CyO#X##xB%coVi~&_8Ge3+d2cowB>i@8oL#n zA=Ahl=2L1Lef5SpV*@`1cz5%EZ!{jCi~s8#<5vUEe(TD8;#K+McqcEiCR;Kfhj+R{ z&D{a%^ib#$;sCDvNhEQJhy4$6`d|U0yDXN7aaPIRQ0O>5=jx$?OL*{G57qUY@;{H&bE?YF-5R;caL z2ZbZ}a~8g^J&}yA&9;27W<^!kmC!u)3GE+_JpEB{A#E(&hYt&Tq#3(Q`!kv+;*Xr& zclI`YJbCUmc$?38$^)b?;lU7nc{YUaSM4W#fWYybV2mWP$@7)VndxSoV4C;etTOde z^vgNQgLtpayVDvpbUbH1Kiz$i>L3r8iTMxBImQ@$D}(cyGvrHR3^U7G5}%cxV12vs zcz5IepVHqe_5q7{KZ~-DrE4jB-SqQv`iZWf{K$X5k5|agP#3oFze~;`$m2yMz2sDykrmmvm%L)RxJF(@t%b*9q(QEpQGdY__Z!8R(X6Q;Lipe(L*z>$dQJ z9OB$n!{2&0MY65ayh|L!ruP*)@kT5EL))4*bHA&x`6JM zzhtM;9Uq4Wb!`q`JIfzH~SNKUw+iX;a2&_bH3BC#7eE6 zcYQ@*-YZ3cd6R|(=IuOJe5&y>zTAaYr4vh8-Zbol*?-AA+SR(BeZQlw=PVmvk@o$D zr-Ci$#P)y>|#f=_)_(T!!PN3Z%d-LggrH(#Ush@V(>dlv8HB! zWXmY6vk^C@_pDT{8!z2Y+>z7H7uv8A`)fvCUy+n2(?`BiG=1cxVbe$MJokpEmHY5l z<%=gz)To*l1*d_Hd{H%1_&=5Z`F_UuZ$AfTI=9I9`$BWFd!T2JaD@K*34G&8wy$TB z1!`OGpF!SjqukaFFI(B1lVxP1{HLN{>QzkSZscH^7y8z`Px7iN_7A_c<^2LvZ)pCd z#x8(HtrEUdJIcopm7ZuR79D4Y?;g1#oS$ucj^WCi-wge7Y!>z654U5wtJ}_tE9Pc; z1~FavRp8{jcwm#eob$`dwRh0i2b|9ZU7CGaj7xT8k>U#yyC`G*Lu(A!&8?=rJX6+U z)*!OOdD&T^U1PIC2LfhYE_`nR=c4sAR=4yt2A=6*ta}UR7+@QFN%)N7F-IPQJ_jzxkqJ z*8VK!QJdijVqTEh{n|jcO2>93$Jg%~(jJCLN z!L~KJJX?16s*%W!*~l(4um0wO{_Uc(yYwAx?NM7zBU7CG8AHy;_DLjR7QFKLHdUO+ z>KK`F3asn}cXdoou|myLBon&(`keiG|L>_=ezt^D5BYk|SWlYPkyoO`s7p4Bp;!EJ z+H+1j$iO<*Obd)1{*U5I=*o*szsXxiEVK6LwJApMeBFCQzx*%e-ravKR^v$d1Kzsx zBp*NK9vLZn9(>eU=kWiVwEr6IpR}3Gx*+QT=se^f>w|_b;;%<{(D%?GPiQSaa39*9 zPdvc1=S(?yA=`Ow^GU;D>f344&c)9e-vM?J^;BwHJDSkne>jo7@TC(up@+~(_@EcY z8P6Bt$G6Z+y=7YSafP!d8y`R^I0`+{vsr6A(0O(f-_wq-Z~oITt0WJ3Sdd;pf3ha7 zNo_UzcE2q7@*{k&#&*k%xPKOmEPg+@FogcWE;agpt(B@d1vr@Q%(IFg<9WF3xF`93 z@?E{x+J@|G!PZJ7M#!$zdyG+v@}O(pjeRi_*fplJ!nYomzutP}8Dhvr5=YV2&0Gil z%5!+8xOEABDCUQuZ-dL_#NNfGbx4nCo)Fyz?l&Crv~v|Mutk*l%ZJ3*$S_QrFGE@_bXd!HE@V+a-K@!ngQ0hie0y@1JVqOQCJI z#}}OXUgG0Z-(xKYya+!X)JMIqo%a5=e(&SAX6@pXb`x4x-`OMR?Dw zAI+cJ%6dWao95wt{GoUp=ezrCI}!bI>Cb}8cn3IFpM;A!1u|;fncyl*1FrYa443Rm zr~Y%C`ion?+Yc6CO!lDEcN5R|_2J(2NjdCyUGSjhl9IiWnMs)}A60l{?q>80 zYeiO|tVOb=Ycq0BF}Xgit9zqb%iOm)vf~guf9%56HH_tiuFcYm$_Gf9i+5bcwn_9H zZANY@4j%g?B^m3%JD)@%2RAoOKu?bM2ONFoK`-WZOi0lhJoDds)3n!l)dZu%CG(9A z@w?97zGEHpvNa=5u5`K5E&IiTFYJ1{tr7;IEMP_we4W)cp$W6GA)I&0jf_p7p{d*o@G9kNFhEV9!!n{deCCdET48U*V}lf zx-qTUf$OuHJ{UinqJD%rh(k=+eWwq*tLLRxguZcUQ1zQQD%nHOncd&dZVT_f-o$0` zEr^2EckrES~ooTK7n$)I*@F4?jCGWqE~jh~g|!?rww6OFz0$a9`>N@fzr`1Lya z#^cDtW$RcM9AUW~Jc=gj$-$Qbeze}3*YDk%nH+Y76}~_Nw~6V+8%hRyBS*`AXitCfEVI zW&E`6SJnkhPfp3S*JZ5g(5`EO@=^8owSiApXdd%Kt>ccY!sl?;9_^npzASuLS~oDT z?CQ{kTv{e5N3(_~AVd_S^J@S_uZ z_H1~{O~KH-z$vk5!dHpU=utBtA_tS1OP#^bcsL0+?fTSD>?6y25WZ+Na)Gl4h@Ard zM=Q~t*dKyl>psAoMf=Ky#s5D4mk6dK0)KeCHharBmGq!v}<&z_zrz(^rz+v;4HT)R`F}oR=nV4+fK$0 zfDKRi<)U@z0>3pUc(RU((5rl~%}$ISK33j+RO?yPS7~Hbj3a%R$3*U6F1@D9ip2H= z%p9f5;4Rmzq0arCk;T{uiK^IyKiYC6@rG#=p7UFGD(2IMyUF&sPl#G8RqveDE23JH zjqG6E2!C~CE%Oh_u-Ns#kL>6sCWqK7V@upA8aF%$uN6y%tQx^QkMZN0Q8L2vBZG2y zmMPy1|FgxT?d#Zk`ZD~wk63gUIglojQ(}aPhxGcb^N%tngR0`gzf+a?^R?7}xVrTh z6&jc7<^vVgOP;C-JvGTw-7=6oyf=DseraXoY_QTbUZGc+lRbQyCuhI)di8;4;yK^5 z1}XkMXQMR$-&pZVc*^7z|Hai8LQ5X+JQEXp(sz>cq4m1ii#E?nss4cPKj8acu)m{w zl!q8pa#xl;xN^66F!9>Zfz~d&NpGylu! zwqEBxO)w4psx?S!S>Zvx06bc}DntAH5+QxZI|KMuvW-~4L|3_Gxkz>T)$*?I{d|0# z<*Kt5t)1;|8CiGW*{@0t&AxY0r()COYg8;4G@7IQhS(>bpHd!rh4|NT zuHox=cZ2sLXnH{C)c`pOUCTLJfa?@b^{Xuvfv2OxsyDP$gsW(8YImUKwqI1#%sNm} zbH`Jh^L2>1)N%Y;11p9WSm}y$9oh!Ymx7mR;BcxxFmwWRGu0}tO=Oj>nw&T>^fqgN za;7N;Nbf5TIPbn*GnH>f=^N^7s|#>{PRUa6*_`ODDcBvS-a%?BJS`AVebf~rzSjP3 ziP7c7;X;1^nN_@MBsyiX{7mt!qG9l#1ODr5eVV=@^!?Gnmt0oe{WC2e^lSU&#iNRK zJyvF7&BNoWIH&0*t%qdQAG8Kt!#a5+drH;=-?6f4SEN5rxx03?RsKMmMI5}VZj5rO z@n35uxvzrPdtL2i<-||19_pGVy&JykR%fmf`y(-N*mGKEZw;;yCdCsV(Ys6=q0>D6gE$=9%p+?8tVNOoGRFPJj|`q8hp@Adk&62`1>eMb*f?ij_8N31@f%5;m!$H&d}P36 zzV9Me#2Lqn96IuWF^+Fxekw3(kye1MpF%Ds{1ZYw;JeK!{H7MK`- ztoipu(c{n-W1plo=|-pT3j}|OkKdX5SAY6Astw`BwBzg7PCe~_um0^gZB+K@-djT_ z$8EShZs4Rr=VnG8_lb|P+Hxpo?K3?5JpRunw45_)=nib7SJ;2=OFkE~~gSY890sBjBIXQfRU5 z8h9L?Nngg<`vgu?0ij$fp6C`(BPb%I^QZ_{ndj z?h>AnVR`JqzlwJ}T(!5#I~%)>ayQp3#hNK^bP4%%c|Mx=@TDjAaG%S4A=i<*db<;Q zst@2pUW|WyjTM52RCghDNRMvgik+T#o~w`Rv+O+?B%09KHRRsj(|VA83{32)aZ^XD zl>y&$5szYNeMdQw(5*$l)~Og3a>%;8AM|g}RqyRG?ak-gQQD`BUHVFEf;z9UQh;fo zd=lE{-87tBdk3;gSH4T#+Q$eFYYmS%1Nzh2qdo&)EAORwyV>)RFz~;_UXwxM^$>Zh zy$67IBXwU6ytd!mhL9<;s>@-UhoWVvkh)DPU5!E`#o^0dWBos(w@O6V`}1sR>!;b9dfdZchZ=* zB=On>jB_VGnYMuIJg)N{Iu#vXF4}Ip$)<06K9)Aq&^fm7s@u?QZpya{uDTa)l_H z!oB$DYqSv^vq)o?k_nxRfW}!%Pf4Txeqt;^PUh6#bMH8<{CR6qbaHW+HhsZujV+WsJKktP4 z^<~_da4WhB`)@KdWczrJZPL7kZ>Nb4;NxWddr$ozpAWvF2lC~$S@+@hSqg4__g`oE z7^n0|!LRJtGUmIXExygw>-SYCM||js+|9~|t@#BpkS;Ga9(qW7oymJcTp05K%2LJ0 z%x~vQR@V5_x2(edqVp__-w>LYkGCZEu!-G_G|QfH%|~an`>mRs=oWaT-AV(ViH!dR z8uKLIK;v1mNBa2YC~?z?t)VvNj)}xf^#NK-sktG23;p^s{JNBN7awxiZTeIPzL@j2 zK85`PKUP0u_bYsBVDqXeJi9etR~OG+r#(w?o)NP^e;4FB^gPZ05Vt!c8Jkd*zg&2Dpz2spkFPRPj z1hD~Ap(D-JGfX^0@tA)hAN<%$6bq60cn3Be{y~+M{8{!Xv43ixT#>XbA5tQmv2*j9 zK{m~WZ@MWcUM#r@eS580^B#z8_c6Y;oVGjQ&n4nxD<8VF`Ivd1kzrGa;~qtyW_2r9 zFLn2RZ0L8C*j_*ajNHgyJ$4J< zOFpSDd1v}Q+RFHM3Qlrd(ryWBLd5^6AKkRS;P3f9^l-d^@0I)V^zZ8#hf1gYFY@gv z@DCiPdVC9yb=TyjDd+F})9TxM+J858kXegA)ra-jewE8UQhWk75$oWFCw{9K1op^z z6h8&-HFt7*BiMtpm8W<5$9$LcYve;ashT?(8cO;#UUvK%)Qew3F^iS>AiU6QEVxvlmq*`D9`Xgd6|p*`p3E?eUIhQNTLountT|i!Jl^;94TLbV;y-95L8XUlP z23Q_FGc4@07LL}rsyjxweDu?$Si)5!Tsd~1T|-Moxa!-RT!roHT*d7#yYSbza<%7? z@_g^ht{iXF<&lr5-Q}9wzRyL@H&=PbL{}y6<)M@0uaf^N)A*6%=iXd0n>nNLeFZ|x zN5l=TCBsyw>H?N=g2Ab?k~&IGtK&lIF!2O_&Y;yehg*ryvOYVCTvNRKAmLLsFh1yU ziV;DEU5M@H3B7;K3i6g`DEGJgG2yAm6Zr^G>hOk%zv=HY3};LZhTb$uK{>V1- z1^7e0y7qO3Ul_Z@`N&>(l(~ZNDwx6pfMK9jiOkP-;tvCw+k_|IgkSN7Ej+_FVdZ)c zvYx!iiylk76TW`>oAQGak0#x}jdLtgc)pvtc^C4yOZKe(^K6gyVRDs!->f~026xPc zo>}MZxE%c;-wS?Gb8b(p;C}f=frWU+#3A6oH*iC)@zv80LvM-15cU?hBTL}-b$mqD@Zj4M(e}E|&*Y*Ou z)i18i0`|VRHXF}JZk8NM;#uE{H_#cDXhd*v?)PT~s*zI7tV{ zORZbT2Pt|8eZV@zp;PFg-q1tpWawd9C(lF=-jXSaJ>eHu&!&ivpsJJ>e@x zyczm1_oA?Stf7%m8!>S164A+e);v=9PISU~gf^Y%KhL&0bh0uz9)9c7V_(E?;_|-} zzvCSI3eUoCeRW&SOVurbQGt1ZQCe>mQ}4=>OFiR3QUxnxYTaVjDfEeuzE{tw8V4 zcV<=Wiig7!F7YUit_|509^@0P2)BjadHkQiUe>iHo-lLFS~J%>>FaQO5L#aopCtTN zm7Cli@XGwb%EaW8sIw2Zw^T)m0M6K@{YJ73gU3CUtdu6!~N zzRjFaXPsBp;yN{O;D=KLzH zQO*)vl3~D{jed4(%?%luy^4G3UC9Xgnrr;bBNsL39G&n;`FIvJDDF?Os?~GSDsG5c zxf=!{v&n}79k%QFUwbz>wtcc9G36w#!7X)`3%|*APt~t)!bZm&zFd7v>KMj;z4S~6 zvV!}q_VvUx=YOHOR-EwjOulX9EEuP<{r#aayZiJ>#%%<%^WqEE(W zH9x^O&`0xi@Oh^@-QJ%t;=b|N20U-qd}wxo+X|NtDH@-fo)+o7#53ELD`}c*l{Lwp z!lsSoeT{dCv3)7UQpv99mTi{_USTgeG?1UcH$96vEl@eAy+w3^(|1+mqvA(p@=tVbu(R4%;@ zO%Tt2B2X0{uv_cvl8LH={^`7%Oz&*gym_}{1lJ1cwC}af|FY=NZ+&&Auz zfBL7BV^xvZszG@2GFOR> zTGw=Yyw}V*3bF&E+rHEapLm<&3GLCbRRXpvFq95o!)#=|jXD_S6 zN7whZ-=jXnH_`4%yVr01@dwNqE={hh8~R{f9s4MUdS^0TIa-@%&HU%~*j&GU9X5yT zYhciv>tp^CAK;c=?IPAdaVF{9zrp;06vURapszQQdxbUcTsE6{@dEb!V)Hh~ z6NNWK(?&$Y;+2!%*J$6e%KX*^+r_II2aSQltLt?I=2yI{@s~L~R)$~3Zw>3<-4yM~ zc#eLmPVtm@1zY7@{4DH0%{{7hWS*J)0sQ|U$(PFY!T;YXmdQLfYqz;S_gj}7HSs8l zUnPc@cb+rx6~v(eBm0Nr{bct?KNxS#S*Y`mX1i~iBY(VT)0{YSC)Sb9Wej zb~^ri+m|2v?sX3B6Nh7B?vDnIkCPz$@zP&AFOXTFYY2$NmPlYZ+vkP1X$HKLV z6N#-jMt%(0hwkRvPeg^AvWPXXDmJ`?cglrh-W#wo0*>V?XZ{h1^#l}S8%eOgKS8eF z*zmUT)>j6E%iiqW6iDYa#A>erP4})-S~a z&Fm>=Z%;ijb8{Eop4bcj_!m~3Xr*sUn=9gb77jbn9$C9nKKZOx=#SVe`Ft~J3%~rN zz5LI4WQXCKci`ov{7=Wfs5td}?sYDhiId~n%750TU3T7r#3#R}FB>U4kFo3IdOpwG zTr=UNF4m5QM}BDH1#;k*T*XM6crejo;*)hHUDj~z4TL9C%)Zyyuxm9&;gSbgS7Q%l zi}hu-<-jqHHa_OwOZhd_9~B+z+r~LhK&w_g<&$_vF@L$lk-zHr!zqi6blcmsW(aI){v74?eti1mI@v69t_qayB0dc=RSZtXqBS5*f6 zb1jBOm``Ya+kK(l+0n$=U(MFXNjfq575N73jH`;}ywxALTu_XAVZmzVZgg=OR-IN29?QgT~- zKwr*bf9q>aF8mul_liMN46gQzAN-C$>Mkb8JtzN4jWOpRIHNx-?2+Z z^x-mIh(2ggOg;KNZQ_&ha<0g#IOkzmtl=kC8r?fA@dkcZbl-_O=sV3@_oY_F(i2DY zgXSLk(K+B#^~c8TklSS2qHE26zje`?@wqP7?1FUGa+zZw|ItUv`LV#p&4{rjxvAY| ztbsE$r)mW{Cy)M&du*TVk|FmS8)`bZhEU_&OJ92fda z|FbE(im{pR#b0OSQq)TIMqEj|Gh6uR7@@NOdgf{U&cL$Ms-(`zWpkiuXeRRY-vxOm z+izX`PuLPU(I9phxqJN9Al3nTPx?Up*86W68Nk?{v{7%5zXqRq9GhgRu}NaN&}V!B z^m4o%8sUDI=qAd0NjtWmZ^M~OydQ>EHtrZ<$G%f%WmW94M@4tgL??Aw*yRgUPgU$+ zOl~RUy?E2iHKDtIYLBR`#8Td0ulYk+C*Ry2Z+G~{)!rtV^-&G)ypbH&=7Y(xy}0Sr zvGu%s%GhG>oI19{Ys}bcUUKT#=9Bx8vAy^^MjqN@SLl>A^(!lO%I@n|HqI%#*%^0- zE-s#8=mMG$Z7@#HX}leK(xvg{yKH`p^Jh&>rB(|4e$Cjyj1^-GJi|6nZjsB;E&7i< zbx1iX-Pjo$;WOF0nch`NTkxV^>s{Fy+EW$z$&@1XQGPvQ3O=@J@uC;BUk6=nXi2oi z^K8+RO-mORXxznD;sw8T?rqLk&SET0J{-Sw&JWC3JV8!L_G{Sh4g59o*yp!OmzU(; zR|n2z;}$jzi#ODaBG(KuqXXC?8>bf`o9Cko4%>Qd-+0laXi<8gj|Yd+#)$=z`A&Yx zTGh%Kaw&JxI0e&7TxA8@eSMqOm7G# z!J_w*^v?5amCJW>`m-CN{pagl{pNr1ZZrP_o+j4Y1V^&I)4rK_k{>JVZ`$X5;az90 z*mWVgU%8A<#>SvOa-)AZv6Zpf#yEck{OlyZ@l{-3sY<*#8{NO9Ifng%J&2yjm%O*_ zY0vqNuE}mrkk4+saNNUqCEh9Pf_|9eiXO-hXmAoX{)l(Klf;2DPIey)Z2OA(HJ{RY z$H}-#@aEVq@7^pwZqj!v9+xjy^(6ED$nJ&)#`&%EtJ)?K$IE&P>%A9+3s|F@sF*%; z9qe2)o$EQe$_A7k#-6$mI6B+Nw}hS{w;Zt~cUTvP3nt?S;QKo?cQe-^{lDWIANVu# zKeIP4=6S)vPd>QZCA^X2_qW`?COOXiZtnMp|GD3;Z^dKww_mDZPF^l}(3L^SGTBbH z@9Ha2!6vwfg=9a?#Si04@2R>5R;!sytOSlX z9QdxqW;{gsa=Wboo74yNWfZ)4?#Dk2z0}eEg$@pE+#3A+RooP+KcWZOU7GLO>oE!W z8TQ(3fAAC9m4DzJ1E;~)2OB8U9LJ%7-`9l60fe5=9))oo(6Yu~G%EUY>?o5%RCLl@ zapI(oz!#ZXlp}d^V2bG3H5AgGSCux4IzQ=zAEE*&9m}Teaxpt2k(Dq=%bsKcRJB%~$i0aa)XkX##vW z3R=O&qP((Wkf9saB(I&Rb*Lug$Y0{~0q+s&@&V6QaO>#c-yIWfRrgEl965UXi7miZ zDLmUcKHjY>aajL^uMA)EiDx6N%2{YtNAHww9%^V_F<^GyhSRCwh#|uQ<`WFdpx&iY*?$@DIJ#!k2o}nBR8EX92z@(%!X2mx4d=#U?ST6#=pfJ7mKyKad6(OKK#m*cR?9vY{Ga?9+tA3ks>J{Kxx?$3+W*M27Yx1d zt#r9!TkwCE7@8@!<)nBD)A!fFG^i?em_4`gUdFrszlc&BS#HwJnZ-|#~$XrZ1A_Y zkEix-_;1u%)346ogF~O+8oRn*o!AeSPyIc`wumjB+ebHhuLVY}|Csey(GTBC_Pe>} zst-2&?;bSQSj!O6Pcnxw?a5c*;P$@`o{rn(m}zX_Wp}i(H!q3b8yq{vw#WYK2T9q+ zJNcrYs#x<6B;)vB$i11TQitZL-9>AmTZbMf%b&OcT@@95vaa-GZ*f&@@CJ=3G^#x) z&{lD)Z-t@b8j}l|`qhrsoRaXEHK$l(fbkfsckKQSzRjs;7v++D4xPUlOTwFk(S~{9 zG5dWpuj}pyW3B^-<-j+zp%?kz~3L>e>XWavFEUrj4yf{ zHgFESDZY{I^lU$v<|SdWVF};dRMBhZc7oC29row;W(qFsTU%CwhpO1ZiF#Ldpq@)_ z=zo$oz%hP>-f_G)L~sKq{+Xk{ckXk!-;lI%%{rcV(yZad;U5EM7w`N4ctz_Dz5Mnk z>PH{VB*vMwCi;~elO&CtPQxnK`G4@5pZXjb_}h8Bmn}buco7`1wo!f^_&Q?N+JHki z15VLkws!jahB{mRU(|Wu8S0z@uY~^I zI{U`ujS$~^MPk)v+D$mr0Epz^}B*`!EhvqlfC%tvRm$mFr z(he#Nh&I}nNPnN#0Z+{3omt|Op%YTO%eqp#!v!Z+7(WKFBuQR0-%y`mf{(SwOuRZh z$s>|gDiiK(KIuO<{mnYTC3r-~$c6dRl@9-6+w}&TZbz>5TW{t6w33W;%h+!jnYt2p zdI59tY~8zoFO#z=WKYhPy(SrxgymFzjmf5PWZZ9tB=N&|H3*)nSmO}k3LJTDo3eLi zlrgm9M=kW+=f|MqaV5;zIeX$U@tfqHWU1d8ordgNP!&th_)s}&8lYLo2ub7tbN3a~8`WkQ=B59NOq4+7VqC zXXYc_U$OljOu+8tw;g=caEreuwpo1!naqRS?-BS*8y)<2coAj1Z1D5tn^{jd2L0O- zJRnaAWsMiygD&@oeF}TbCgPicH@=?n_}2c61@iUkql)!>J8}PUanc^#@;vdE$^3zy z{KRqbt;L*Ed1d-X*em99Kah2@K@;!5pUFBdUi-In_BR|Sduln)^ElB3`_(?5&R$=9 ztI%=AT-i_i4D)_5_pGtndraf+oyk~Zug@76EN3sn#ENzfOaa>=9D<10FQcWz}(RCwq`IcLc_nk92J?H){9`ct>qrl*Up3w>g{XB`52 z0Qbaq9fEGwP!=-Y8?t}@fVMk`Jw*E=o+ftdmnq|T(msce$YAicS=;HbVQ-1^oTJp1 zcQ|+MHpb^~Y*4V}bn@LKxMq0lA1(qv-810?AB10SC2w#P#1aTPd;z4W-a=&OcSd%cD|)Um(! zJ?}Bbu(Q{bqi;Dbe%^*Y(?~yX+iqY=JHZk3kJI@!!dkU`w>tKI&W-0?rnHH17ahQE z%S$)!-fDQD$kkGpvUp`n#pw9 zLVX`{KajcyasO6Q-KW9(21{K6hiy-*UhtX9o8IT#M%sXFV8B}Z53s)sxK8j1KS9A8 z?%C5(s_q{Sp225Cujc;CN!E1Do4Nm5Y@h4_?GV1hb5})Y+RYm0)-o=vQ}Dbofy-}R z%^E<4X@Ax;3EuGH>c~f&!-;*1HjdY0#hSQ`lbqWq-)WJxwAI54^*17K?vMX4ILufc zs*U%V#y3ZYOx&-Iul+6eTNxMX7Mv7(lRki7U-6Ai@#j+8SF3^BZ&8D`b*jPlPgSST z7HB*xH_?_CKHHt9aYna;I`*vd!`F}(%(uwY0Xff7f0se_ubxsYXPEAg^WDYIKyYc@ zs;C<_oTF;Gsr%$<2AhTwIp2|K7j-D`3UJxYroM|Klpm!^|YP#egrf_Y%DjVqbJHdD_x zLv@>T_csqWvWL*V_}rQO$mR?QGxz-dG;pxcnZwqw7D!)M zbK89kZFbjX#tvr;k)h>#HZ~uzWryeA#^+h{B*`cE$y~D^8d_iLW!-etU^&;(J$DV5 z?}S%gA^2y@Il^~@fBrBjt^wI#I%}Sq&s228H%Nc%@kMX@2zw9hL3abc<{P;|>_;7& zD&ntPjc$lP7V@xN2fTg@W2SA=GMA9r~Tm4QQ+~D_IvD{9d}j4 zUw#cZXn9KTGa2@7o07&u;>y%Ok*~K@bp39lowt`MQ|vX0GXlD_P792%xpmx2n>V}V z^4^h2`DWrKaB-X6mt&-Vj}O&0rdo&Jti7IR>v ztt+r*Ej;wlnX;}YamX3H7;}p&em07^P+%uE*^XKxH+OAb*VT0gaGr`SQpq_Fq!T>c zDc`!Pi2s4JmB7J^J9brc20wz9_H+M)=!QJ+1IGPH50CiA7reV;oy23K3r~`@B<+hIe`Kw!Vas}m z_*^k2BkcJ`f9tLyo?E^aJ}daB*Sddd&NI`#IvroJ)(#I`4DUNj@55nE`))1IGG2#- z2d}Cb zPcdowakB5*-9roRP1iiWU$39TyY+gs@CK;|7{Be(B6CIUl0MUfre&{#@K-6zxwq{f zB~Dpo>KVVZ&1tXZH}Uui;D2zNU-z{~{vmyqvU@1+=d8l5`T! z7=K8)>$!r1ZaZ_to-Fgn^|V*oDQz}w{Wmy$#I`OxLR+QH_;>3zqbGLAyz%lRXn}FJ zkhwC3% zH8zYo{&mZL->xS=IdZ%H^{}+7+Zf+LoA$`~t_Als4(RdKYo^-1z&m6aExR#qcgh*6 zj_;WGA87ai&pj0#|2kjV3E$5}&glgXjIi?x56oSAVW*VeCHr0G=BOz*bL|P%YcB2_ zT+z9gb?i?3UH4{5o4}8~z)i+(ujriM=3p5!#x7fI>azEjG^-fX=}9GQ)RoMP_(;z;=a46r%S<9Hc5aBym~z(v|8=VS>#lf699$3T($cpgOmMTSqq zXEYtTvERC`j)RlZ*o!TG8dtE_fPG+cu8^$JtS+k-9d^vRdyqRh3vA7;omNH1p|SFg z>k60GvMwfZ^1U$P-HEvx59j=5;4#ql^&2BJE;1|gduEv$yv^Ptg6`(Pe79%SU8CD} zukEu5+P%Z!JK%wQr%CUj)qWx1L0}1dron6boMiUhOZzANR0+H`vU72N&tNXDxEN7ky;aDZs4# zZq2i{s4zTh3uO$p`I+#q>B7GRueg4R+|9S*@%>xdN6W_74dptm7iHSKGINBilUH#NL_ zFH?@-;Xtkf1ZQQ8@h8e8Xu9S)xOUZ1k8>SDur8X6p0*X;X)9|xm*U4H^zK0h>i9e; zx+Le}=`$xT`DjpNbxzt1+Si9VM5jQnE0aAwlQ|FhlK7y=CGoTyCT~R+WL;I{M>*?> zaK;t5x9Idg2`(8=<_+gl?qI03Tk_ z`RZyJuO!~P8GCUv{4c=T)PBh$eU*G-2VUjpjJUhM2FDLR%lkXT2Etk~`|j{JyGQeA zp{oIuVO5D5e@qbF!P~ST0oj5cz^Kcq_wQ$4k>;`DWockCr?fsEOj$Izv=3O)RD z-d+>MFZ_{q5{Vj7#d>nd!_yssT;^CKc`{5JPe!Jbe50m$6o@)5QW+UfA-pDAg9Nht2=_C4%;JNs9qAT`A z_Ia84Fk7FS&o}Q1luWvV(Aq)C zFZMR(o=oPVn-b-*4mPdhKphNI;rrB)OVe+q`Y@I_p{d|+rJ;m+RdD_Db3h@ zDeGf_!6h3l;VIbuI`w|OB$$){lU#v`oDC-50!)UB@NW(K4<@%6xPOivptBEiGB%m` zdhz>5j$xiT?m)M+%t4=H3yQC2twH##|Nkf`ns-8`Ib#4yb|As zm+;-j7JU{xfqvk_3tvGVd6#(~o+G>kID)tBzp~3&W0%ugY&as*P|kSD;hT~j`=$TJ zCm}u`djj?{-KI*(W7jJ@dLrX`1#w-pBb)Z>IYZ_enIoO{Ft6Uoy{wfraP2Gdpp;Ge zOp&W)>?Td`Uf8i86HG5zf2BQ1e#Sdq+YSDLPkJr^ zUi$m5B7Xv#?@Hg98%NNm=@p$X+|PK)SoLG91_-{Jv3f7Ud;Hs9xK8@0+lu@<#H-tT zX3u###6EA!XFJXn+>w0J5yu9?_9uzCC(+sB=Kv3orFtg#PuR#wD!ohD_OF*!6;#zV#>F(!w! zJyFJly^e=S`=uEh)^(v7`io8P(S2NNwT~S#HqXzmxfQ<))?IA8k~Xauy;A0U@N9(m zbaGY;GDO+L)#pr~C^7``f}h~-qu4_`4sgE^JhyBa`=GX8#UBky+if2Q8IQ%a>&tS< zWA;@(-pO}V=(CQy{!C;0>TI_2js=D`{=9Q1FnvzeAiyUSY3<7QWd=oWO+#N_Vd{KCm+W74bip zuDi8sC-B%~!#!3Je}sJ{odL7<{g>C|TMv}KQ}9RDSY%9fd*koFv~~*P7uRymfQkFD zYdisuS*!Jkeu6K0p9^a|A}^p54bi-Wd9WgW;O4a#c1EUJ{bWsFe4e!act79v+X~Hz z|10;W==C#AQ%^`AbAe|X>tTcJwVR1DCI)t&V4pGTHX4TXF`4fP9SQHNh(A>TES@mB z`Tdi24^<<8Ly6FY*cjR0Bs#F*jO_anJ$O3&c{+Pr#v^C+!QaKK3wM0*0rl-f=G6XG zwr|#6dmMTh_{5)^%$Uo!D<-m6Rp6)h!N%Voy8SklLFhY~HA^X1{Dkd2x0#nb_A2u8 z2OGfkL;9Wgmv(&63Y_fq?cFPWb{lJQvL^h~_{Xw7sQrcGyFCIMaBsEtLxpCH9P+^= z?I$Sv596U{tm2lBwLXGDh={E+t*9q-fM&gbYyUwG`X zJhxK+F5+I)vgX|)_xJvA)twcb%ka=5I}c;fxq~z>OFMxT=eDXe?d#x_8-Hl5#zFSj zl6JGEMex(cLvXb72GOOtZZWo;14U*&?pH-W`cQ5k=?CxiIuz@lvevV6DswLN?(yWP z-f||v#MPWz)$!hwq(71OH`(v^@*X(2@3->)B;KQIIPkyk!QJ3c0{)#hNZX9O(Hpx{ z=NN`8wo4w>I3H^sY1 z!`X1X-qLd1t?Z-Kd)j(EGx}#b&o1(?zTL_9?V%^=54i;WuJfjZpG4XXYrosMUi{2u zpW}60dB2UgE4H2^`(M_4cg=_JUC!IF-`y+akVfl(cKfBh|1s@N6ZrPhX@I@dCF`;> zPlGdhUl?)g?J};=*C`Gh(nLOatD^InwQDvDf9>2~5r6PkTn`Wz)btNb*Ll!0llXw} z07nL@h`%{RU<*G2ASqXtSEXuB-DdEe~{jST1nc zbcwURB>i{_xvlGtHIH{5q~CH*r#?q$)%uDb4_V(EnfIzE>F*)ZU7gHh4XyUsyoK?D z$Mzx3mlg5tTeq^u+2&QyM(2mbcaWEL$5+m`^NSwx1axTY{J+eTITboI^3jEz_X->x zJ0Y;xDX?#J6p~DI>n$k)s%MDT6(R z4;(LaEoCsqtEflT@7FLUn>DY)AIiv@?|&g{!q~4XDeus_$2*bByR@7pa{S@)=Kb3L zowANG^TFGTsBeVGi_DM6828`Ic>9ce*}2)sH(lAp%ihgg(iX_KVnvrGF8F_!ExX2( zKM%ak5V^9Vb2s}hJ2z4OMB=~Wz=N?tuI!p(WXNru62Ip0uIYmBChm&2rHsk@!IRG2 z>A-3~=}U}^x$PzH%ZLa6HQ!2;d_u<+9S6Q5?k>SG83P#$jjOyPz6V-=jc?6%(&s(w zvFzM3X}T(P%HsK6@%^UEJ11EK6nK9F@a;Qs4ZLu8#g9+R8NfR8;3}C%C*`20K_le( zp~>@Bko#@$Ds?|~gTo_|`LFQagdFy7?40rB?|qCIS}MMUS|7?@wWO+G)%x6mRer*H z&O>MaK(fA0*VV)goUddt*ENhNkoVB@exlvKZ!G`H+JaTy?1EJr30}(Q49mmH_u1vI z8(bjorTn!ouy5-h@m-f59e?7|(eY<4t%yH&>C*U%mtGZr`O;s;_gwlyeD9_Ih`+V& z==lD1qvHqGu`zPp()h>gu8JRA_e*g4h4`0ij#hov{eussF(0k=EYRz^YZQAbRoWJU zzBV?*>KgrRt&zH*FBooFQCIH?EyZu4t}fhI7i;l^q5)6LSLbPHXz@jfZ;aM8_?ET! zJPk@keX+V&pkA3WLJf7{7D-qaZLJT58+>-WlpT#Vgj-_*u!eA5eK;Ij)>cO@o_(?A zx+cn@(7O5+bsO7d_nmm!ikluio?LQ~q(_?cli&?m6_k4S!lU@20?sPu#V%VdYo#ogY8%yK>IL zw1N8qeZAhP$9?_9G5xN7&I(PwFwoj>)JU*21=@AN|Tmvh&g`^IyF zJTLEl@X(H-!=Kqc@8%mH`QveSKDP7LoxQUAU6Ee*z`g;$9r4l8_g}s$Jm&by=J~%o z&GY2cyvE;bDtc>K-;3T%+hx6a)2PhXKHa$C{)@i%;BWfgd0_W#XYASe;r~2;RNMHk z)N$9`)&IwXZ#wqfM~_)@N#4|8zn=seu1j0!{p+D~moBaM1cvM_@NJl_>OcSF#=e0c z+?jUjlZX0Udfqd~eev6U+k90YJ#@m~cRqgAsw*Duc;~dY>&x^0{GIkyfBK=Xa?gL} zdmfnehjSk+jHz9>zgO_+o}xS7Ip>WV_f8Ey^U59nIrRFUmVD$d?${R^Kl6&FU%k9@ z@t>o4eM&w!t@jyql^ORuzv`H`r(Bd?bx%>Rk(rrCKYp1t;Q6cvo6p<6A#C;E)A;ah z2Rwf`_N%{Kc+>Oya)#aX^0pm!z45z~rfxrf?J+y@Cog>LpDoW~Pa7{-`RB|R&w0Bk{LaH)ef8<%*Azeg&`Gadvu*K*x4-`S#n->G^_i#kPOSd? zojIR1J^D)1dAol8cHaljs+jOV*`G%rv$yipj9>rjoZb@_uk2Iw^rws8nfp%DU7ubP z8oT0g|I8n5_q=e*y2f2wUJYkWc(1wo#^nQE?0xppk3Kx8*RV0Cr_X(S@*~e?AN|+^ zKe}MY=srufFZ@OPji<)`@#P1vx^-XfY4`nQ!M3Lwes=oj-j6rmzN9td`e3iS`}W^_ z)`VmKv7zaxmJ`oY>6f0f`^JGQcfNPu==*;#@zmc8_}MkD{^*#;U;E&pPv2TK^qn`4 z-t+38E}QY*p3lDA{&sU{-Jier(xAuJE;#++f4#eWTX^}|4-Nk71^upwEIBUz`^kM9 z7apB49-4N}l2`6~>w?$!H6H!W^n;W4e!u3vU3Wiw>!W|U$lhZ{PrCq(kHz9$n|~Scq!++ztrw-+BZCZW#jgp=Xjp!b!zjX8%BpmegE;J zcWk|8z|*I`lYYU~pZ3ZV#_tU_OpW=XF)J@*4I6QhFW6eQ)YlU71@sg%%sTyaOOgex z!`@kW)(DwtWGbp_QA(0E_yV34Q^%@$PisR9^VHO_W6vB{P@n=~PeZiM=WPy8RV}28 zcw)^{$AlxXF`>q&MCja&{(x_4YkAPqPbJ}A!v1(?`eH&XC3O7frg-Osz46ZP4<_UirVz;UebRn^72z%d{COfgbYdBS zxQRRBT^IE;q4ni>mxN_Q2&;%|=IFNu!i$8xhlh)+;$6w%Qu0c;cp-tj7sujVm#io3 zigz`UHYHGgQ}=K$aY>A@K+97+I6gy zI@XR(s^f`8c#oiv{yanQ<16A5dS${cFVDDX~SUv=l=-$wqn zw%>I*ThF61TvRq7~3mzTy$7<^@B5RX!&>j>(@_OH+cIGZolA9k3GG) zJ^ub*M%0fl?qdy1YxryIcO`e!Zn$&FgB2UHZ|wiUKfn0nv-iGs^@N(!TLvB9w_w>D zjsKc=KBXZJsD{n?7E=07_5m!|}N zzUuPI0}G$c9X6%+fW++Lu0l`=wuvdhF<{n{O$<_$Q&?T=?4TL(@*oANSpJ zkB!7{`}Fa5-u`39?o)qVc-#5cwq19{+Pm-n{nmfHGT_O)&t|_H&RnCm7CdFWU)5)N zR%GVlrgaZrf79*%+5YFJr~YZk`IMA7}mNyH|bnv%SB3^wFQ5(|SSelJBn^l=0aqFOS+@_@mDJPmX&#@Y1Zu?)lYK zw|sc@^Q%q|9JR2avUJM-Ea2q=Uy1g zzkb>S$G-C2gDOq+Qk+ex($!I_zdA-8uTEA&)mT-eJZi0a65V2Lue9E2ebV}-^-CLo zvN1T#N-Id4p0+qmV|S)9|Bff;3H&>ee*^jV9sUjC-%0!%%)gWQcMAVb<=+tgoyNcE zYI-L7K2AzcOFJ=L9e-+iX4>)TD*fd2K55_KGdicGPfz20@4@N4(gvohp+nNGv=h=* z|5MWYr433~Yp17!y?iH!{AACI3+;r}vfop3~A7Oa4BC(|b$)u|v`eB>yp| zqz{n%PfC8f?|tcgKl-1cjs^zD(U%ix_o?c8YPcG$&QOz8v8qvC6;8Gj)nFIT&=m|%Wqo0Zp3MlP~%%do=pIS_?c;3QQ(yt**=XpQx`*J^@Fqr2} zCmuyj{Zt!aBF`@$e-th0rUXg-$4Dv z+^-}Q^1O%oPvm|HVHD3hxC%V+TT$ome2Dz%+|MHnnhtEK{|xSz5hn2dMe09}`$od) zJm1Sz;C&fkCeI&}zd!dE628mbX6pBHe=%Vi&u>xxsoaMM`8@C9dMx1@!fc*9?D0RB z=i}-BI(z&t;(09ZpQ3zeuZO_7OzMBQrV-W>ig`cPRs-@{elwSiE|^WVuY z@6i8i_V_O$jnMytTm_z25`_N0 zAis?Nk?8*=d;A+oBlQ0(t^)7N2txm#kYC2%q5oU#@ptI|ZF~G3`hSeH$@Jf8kN=VA z|7psX_B!-`JNL=-|32@fJr4a}-;MtNWRJg}G(!K|xk`IC5`_NS$uHx1B>I2B9)BNc zg#LfYRp7OOAoTwa^2_);^#3z^{2ls#(;k0^{vRc6GX4LD{4)MWqW|C7;Us~YM|4;1kcj*5Od;A^xe~7fn^#5=2OMi|;|9`Z{zlk(L|G(xc^<7R7 z`u~*t0#AqjZ?nhWq5pU6@ptHdH))gUKW@uDjtrE^Y;FFDB;-g#jzr{0MIsqxs^`@+ z{EEyZ96{RA7hFlFe|?~_-oUvRxRyqJ?q5;B-xLb^LNTkf&FhQA{Na!)Zt=(bUQfU( z4@Fv&UzGUjTbr7EEf&W1h~tq`9qemyI4U?_4yg9 z*wY&IHCXj4tn9{?aL@{Rqb)gwmXfPA)hcMqDws&Kx|brIiTFbqsyq~pwX}MrvzC{t zd{)FmpI2BkKHQR_N<1--^P)A{{0(nYvdw6X($+-L_CkbHs=TgdF~aI0{yeJp_4FdS zsSVPsdP=dI=@!`23sYjZ)XAl#cG)c}HF{QYP4!d*PpiK?R2Mjp8TxUo^T^vGCuxQX zrVOAr+zNul!eOh~-_)F;YL@yV3`CRVZEa~0+|y9Y1v;_TmXN%Nh0Q1mb|qr#Jzzuf zt5Kt@@<71Xq){&c_)()W6tAjU{L3(#HGwM09k<`s3J!OVuWAW5wRnP7u|~WENz7o_ z9HjpyY!+Iu$tVeJBVIv&D+;O6(yRtGe7IFAs8(qC?dE%%JuMzD)MJgDIue9m24;Ec z13pVunXF-1(P0^qtJo778MA_(Kp;$+LIM~l^&4HD0214eKv1%{rQ{0Agud$6;?_K(F|y(x@cCRWvTOus%MwaKD!X4UeX%XP4X=B_yf9AX8lfvQuB{` zpd0Xonqtk;rz!mCE}iGm$WUlCVJ=caZA)l{7D4#Zk!ZC|gy$qF6R9z*gL$eK{ z`4|F8Hra~CJO&z`CXWz)nV-IdR=`eHNafL37&g`#3yXag&NQyUk_A1hKz{YpsIwL< zbm0_^_%Pf800ET7FhL7e1N~l~6^;13{zllQ<|PUy7KztYDLr!*g6nC#Ax zyW2}al2*{kPH=eU*ougtbp9C_fvjv_8<2}x!{+AAU=)VsKtk2kbE-A&35tbnkb-db zEKm=6c!^&ct@DTKg3T)xhAWnQeJ#rb^D(?zHiEVInt-?9AlCA%fTqEfK7FS#Y$glF zF<%J4mY7kjZSnamJ*QN{RlF-KZE=@5j44H!krdtx6Ngas

cULUbAe`rToX#%6E% zqZ(m7(mIuhgY+V@SnX?YA~i2hNi9`|m-$+jGe^)^VFNw4yFL)EPim?LW1&^TzzMB1 z`WX|ZwO~U)rq&*d$Ph@%FbEu5qnZ;lJ4y@O!iO6`9I+KgB$`B)>NXJ9Td-*J+u7mx;ZoJD$8fg zEUB%VGq1F|vgrH-pOA$X!S1N4rB6-%WxkMIGE6N<#WvKVt&vE$B?eMtd&63qISZtu zzm*gqAn}J_Bh{W@gFm|T8<54y&qr2)J}Uj8);6IzCy$0khB~h$Olc{R)=b@$Z>cWW z4Z1zzs;PdAp#&vuZfU5K`ByQ)>89r;lb0=1F#b+AorVdQmN91%0fY3dlx-<9EZuR{ z)G-rQ4+ISkfj>G{I7KVy1Pe`~H)Zptn9$x4+B8?=Vp1js!HNVtFkYd}h}|~uCaD9- z$)yu+D${(y>L55|HR`q|7U|Ud@+xIRLCQ1SQg@lBxgm#W1s8ayUl;@z5huW8>0@FK zdGS1n`YanUYtFB!n=xlj?X0@W(%Bg*D_Ur^x+NKjPS1O@m@KX8(wfp*78gA&h#g^g zn^$lhQOF)S7xFfOT0qq1LP*Eq)<6o$8~&UGu_3c$HP(0s(nF^iL-E3^QfN{Kz*) zp0Uplx3Sb!S43mJ;LxENwP7&Z$R({Y_?FIC-|7d7tm+A~w8wB(70|7ko7Er!4mVsZm21uO zwM6walhu%))sSmt8-W?7QA`sgt?x`0dgUkR<)R-Z$geGdsf@WHGYvvAq1IqMvkMTG zc7P^QWYE(l<0Nn^mYL5g)_kxPc|>ZqTa}eJK5ES>TbXOA44Ni?#ls>_6jxT1l+Rmat6Sp&ZFIMC ztU$yn$ummT8RM)9{|pD-g9w!;@)W45B`~CL5pXS6A~lQ}p+fVSk&8xxtSB44nDB2W z+KHMQ!n4H_@-kRA1lH-s1^z^NAUt-{AZmoPWfjN~tzS~qQuHUJ23oilT0Y4sSi zaw$SUniU1pX9!Uc6II!^_?@GeU<{j(8=0cB^2UyfYArl}Vj#d|-x%;jn@t*XE2;Ed zxUmrtUPYOa%zJ$&ul>Pb3;umkpN1ZZo1)4eiZ!j1Z zb&E(O;K=<(e39AGa6-}*CA~(!3;IJc5V=;1*U*kgm7%bzZCRnkEqGBII4#xy7ym^C zgCB%j5Ies?JhnwUEj*yzhN6v3>QX2|Q>-N%kf~(0FE*p5L=>YYU*0%NWFnYNw#~+2 zjAnw*G0higOZS_89I3=ANWq%)4MhZl;m{ZXT(B-2&G)LIfVvP2ompOMCJ`eVC%CxC z2evL6l-W>3d!d)q*$_tm4XvuKEuB?!#72>E1`QI}*gD0LWqt#RxuHb+iXdvtHC~Jr zKAHF!KqJbTxoM`6CZ!k9rOm_aVJpO}BvTe{q)yFx9;GuzwU-xWW)&@|hiF&$2#0!j zJEx|H$fD}vvL2#k>>cLAYg=7#xV&kEJ7X8bKArT$(@1Kp_oU) z5U<7Di$D-tA&p5b${vNJ#H4ZAn^<_z#q7p(mwru4lQbl^FCpJ@C(~hxgh3`mtr!|X zcLak^7@^s)Ci?*y*a4N`w4hKpYS0z7tEDN;8XYAfL*ZiVOk~~OfQB~IK@?%D8l_#v zvaIdAaLdxDNVr;}5D`2{ic5+&I2vn=MS2j_=Gny<5F}B$U8u{cN`V6IZ82+BQL%#< zT7B|{BYvg`VIT7>>^m?@y6!Lrr+kUis-?UTPNI8j%px-L$a|VERGXZ|=~54=#pz8o zGvyV^46bh+m?*UPsG_k!Pjsm&6oapYlXnYZvOl7ld1)!vY^0j>vlO76wqqgv9F8^X zezY*R&?uv0xV^}pE>K6VaR+8LGbg;Rv~s2)(Ok`Tu3{;NX!Qa zPmWd1wUU{!jutZg=1tU$87|R#qBD%Z#qod27@dZR>Cd zlCcv;CyK8q6SgI1He52<`s!-~6J^lcNZ{8L3X3R#oE-4iO97(O!_7mO;9}uyn@A9r zF}*m}H>X--vthDq$hWEjS}As;GNeJ0$4R`*@3DqS1rlLRv7@IAb0*UKjG}sQm$ooN z1j8z+^^og)tjFEkFVT>yor@j>mnL^Y{B7AlB7$gk4zh+ULBQ;U87Fm>b~t-QoX*N@ zCZcwZ)e!bYWma#*F2pPt^`b?2n-MZ;Vhtvw6}eV9?RV62IuDz|bBp=))mcWwZ%0A@F;Ey9=?i>|i3=me4EVi7lzi-l`SzeU=& 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 m%`1){|GRG|>Fy)`liuw Date: Tue, 6 Apr 2021 15:38:16 +0800 Subject: [PATCH 0261/3028] docs/system: ppc: Add documentation for ppce500 machine This adds detailed documentation for PowerPC `ppce500` machine, including the following information: - Supported devices - Hardware configuration information - Boot options - Running Linux kernel - Running U-Boot Signed-off-by: Bin Meng Signed-off-by: David Gibson --- docs/system/ppc/ppce500.rst | 156 ++++++++++++++++++++++++++++++++++++ docs/system/target-ppc.rst | 1 + 2 files changed, 157 insertions(+) create mode 100644 docs/system/ppc/ppce500.rst diff --git a/docs/system/ppc/ppce500.rst b/docs/system/ppc/ppce500.rst new file mode 100644 index 0000000000..7a815c1881 --- /dev/null +++ b/docs/system/ppc/ppce500.rst @@ -0,0 +1,156 @@ +ppce500 generic platform (``ppce500``) +====================================== + +QEMU for PPC supports a special ``ppce500`` machine designed for emulation and +virtualization purposes. + +Supported devices +----------------- + +The ``ppce500`` machine supports the following devices: + +* PowerPC e500 series core (e500v2/e500mc/e5500/e6500) +* Configuration, Control, and Status Register (CCSR) +* Multicore Programmable Interrupt Controller (MPIC) with MSI support +* 1 16550A UART device +* 1 Freescale MPC8xxx I2C controller +* 1 Pericom pt7c4338 RTC via I2C +* 1 Freescale MPC8xxx GPIO controller +* Power-off functionality via one GPIO pin +* 1 Freescale MPC8xxx PCI host controller +* VirtIO devices via PCI bus + +Hardware configuration information +---------------------------------- + +The ``ppce500`` machine automatically generates a device tree blob ("dtb") +which it passes to the guest, if there is no ``-dtb`` option. This provides +information about the addresses, interrupt lines and other configuration of +the various devices in the system. + +If users want to provide their own DTB, they can use the ``-dtb`` option. +These DTBs should have the following requirements: + +* The number of subnodes under /cpus node should match QEMU's ``-smp`` option +* The /memory reg size should match QEMU’s selected ram_size via ``-m`` + +Both ``qemu-system-ppc`` and ``qemu-system-ppc64`` provide emulation for the +following 32-bit PowerPC CPUs: + +* e500v2 +* e500mc + +Additionally ``qemu-system-ppc64`` provides support for the following 64-bit +PowerPC CPUs: + +* e5500 +* e6500 + +The CPU type can be specified via the ``-cpu`` command line. If not specified, +it creates a machine with e500v2 core. The following example shows an e6500 +based machine creation: + +.. code-block:: bash + + $ qemu-system-ppc64 -nographic -M ppce500 -cpu e6500 + +Boot options +------------ + +The ``ppce500`` machine can start using the standard -kernel functionality +for loading a payload like an OS kernel (e.g.: Linux), or U-Boot firmware. + +When -bios is omitted, the default pc-bios/u-boot.e500 firmware image is used +as the BIOS. QEMU follows below truth table to select which payload to execute: + +===== ========== ======= +-bios -kernel payload +===== ========== ======= + N N u-boot + N Y kernel + Y don't care u-boot +===== ========== ======= + +When both -bios and -kernel are present, QEMU loads U-Boot and U-Boot in turns +automatically loads the kernel image specified by the -kernel parameter via +U-Boot's built-in "bootm" command, hence a legacy uImage format is required in +such senario. + +Running Linux kernel +-------------------- + +Linux mainline v5.11 release is tested at the time of writing. To build a +Linux mainline kernel that can be booted by the ``ppce500`` machine in +64-bit mode, simply configure the kernel using the defconfig configuration: + +.. code-block:: bash + + $ export ARCH=powerpc + $ export CROSS_COMPILE=powerpc-linux- + $ make corenet64_smp_defconfig + $ make menuconfig + +then manually select the following configuration: + + Platform support > Freescale Book-E Machine Type > QEMU generic e500 platform + +To boot the newly built Linux kernel in QEMU with the ``ppce500`` machine: + +.. code-block:: bash + + $ qemu-system-ppc64 -M ppce500 -cpu e5500 -smp 4 -m 2G \ + -display none -serial stdio \ + -kernel vmlinux \ + -initrd /path/to/rootfs.cpio \ + -append "root=/dev/ram" + +To build a Linux mainline kernel that can be booted by the ``ppce500`` machine +in 32-bit mode, use the same 64-bit configuration steps except the defconfig +file should use corenet32_smp_defconfig. + +To boot the 32-bit Linux kernel: + +.. code-block:: bash + + $ qemu-system-ppc{64|32} -M ppce500 -cpu e500mc -smp 4 -m 2G \ + -display none -serial stdio \ + -kernel vmlinux \ + -initrd /path/to/rootfs.cpio \ + -append "root=/dev/ram" + +Running U-Boot +-------------- + +U-Boot mainline v2021.04 release is tested at the time of writing. To build a +U-Boot mainline bootloader that can be booted by the ``ppce500`` machine, use +the qemu-ppce500_defconfig with similar commands as described above for Linux: + +.. code-block:: bash + + $ export CROSS_COMPILE=powerpc-linux- + $ make qemu-ppce500_defconfig + +You will get u-boot file in the build tree. + +When U-Boot boots, you will notice the following if using with ``-cpu e6500``: + +.. code-block:: none + + CPU: Unknown, Version: 0.0, (0x00000000) + Core: e6500, Version: 2.0, (0x80400020) + +This is because we only specified a core name to QEMU and it does not have a +meaningful SVR value which represents an actual SoC that integrates such core. +You can specify a real world SoC device that QEMU has built-in support but all +these SoCs are e500v2 based MPC85xx series, hence you cannot test anything +built for P4080 (e500mc), P5020 (e5500) and T2080 (e6500). + +By default a VirtIO standard PCI networking device is connected as an ethernet +interface at PCI address 0.1.0, but we can switch that to an e1000 NIC by: + +.. code-block:: bash + + $ qemu-system-ppc -M ppce500 -smp 4 -m 2G \ + -display none -serial stdio \ + -bios u-boot \ + -nic tap,ifname=tap0,script=no,downscript=no,model=e1000 diff --git a/docs/system/target-ppc.rst b/docs/system/target-ppc.rst index 67905b8f2a..4f6eb93b17 100644 --- a/docs/system/target-ppc.rst +++ b/docs/system/target-ppc.rst @@ -20,5 +20,6 @@ help``. ppc/embedded ppc/powermac ppc/powernv + ppc/ppce500 ppc/prep ppc/pseries From 9827f20863df9583efb8abfa89d8cb1a4eda4884 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 15 Apr 2021 15:42:24 +1000 Subject: [PATCH 0262/3028] target/ppc: Fix POWER9 radix guest HV interrupt AIL behaviour ISA v3.0 radix guest execution has a quirk in AIL behaviour such that the LPCR[AIL] value can apply to hypervisor interrupts. This affects machines that emulate HV=1 mode (i.e., powernv9). Signed-off-by: Nicholas Piggin Message-Id: <20210415054227.1793812-2-npiggin@gmail.com> Reviewed-by: Fabiano Rosas Signed-off-by: David Gibson --- target/ppc/excp_helper.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 5c95e0c103..344af66f66 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -791,14 +791,23 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) #endif /* - * AIL only works if there is no HV transition and we are running - * with translations enabled + * AIL only works if MSR[IR] and MSR[DR] are both enabled. */ - if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1) || - ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { + if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1)) { ail = 0; } + /* + * AIL does not work if there is a MSR[HV] 0->1 transition and the + * partition is in HPT mode. For radix guests, such interrupts are + * allowed to be delivered to the hypervisor in ail mode. + */ + if ((new_msr & MSR_HVB) && !(msr & MSR_HVB)) { + if (!(env->spr[SPR_LPCR] & LPCR_HR)) { + ail = 0; + } + } + vector = env->excp_vectors[excp]; if (vector == (target_ulong)-1ULL) { cpu_abort(cs, "Raised an exception without defined vector %d\n", From 98a6a3658805213a259b98687a84d37db8f43b01 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 15 Apr 2021 15:42:25 +1000 Subject: [PATCH 0263/3028] target/ppc: POWER10 supports scv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This must have slipped through the cracks between adding POWER10 support and scv support. Signed-off-by: Nicholas Piggin Message-Id: <20210415054227.1793812-3-npiggin@gmail.com> Reviewed-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/translate_init.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index 049d76cfd1..06686489a0 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -9323,7 +9323,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data) pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | - POWERPC_FLAG_VSX | POWERPC_FLAG_TM; + POWERPC_FLAG_VSX | POWERPC_FLAG_TM | POWERPC_FLAG_SCV; pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; From a7913d5e3fb35572f9ff033e7c1c7f1af6f5f0f7 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Mon, 12 Apr 2021 17:14:32 +0530 Subject: [PATCH 0264/3028] ppc: Rename current DAWR macros and variables Power10 is introducing second DAWR. Use real register names (with suffix 0) from ISA for current macros and variables used by Qemu. One exception to this is KVM_REG_PPC_DAWR[X]. This is from kernel uapi header and thus not changed in kernel as well as Qemu. Signed-off-by: Ravi Bangoria Reviewed-by: Greg Kurz Reviewed-by: David Gibson Message-Id: <20210412114433.129702-3-ravi.bangoria@linux.ibm.com> Signed-off-by: David Gibson --- include/hw/ppc/spapr.h | 2 +- target/ppc/cpu.h | 4 ++-- target/ppc/translate_init.c.inc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index d2b5a9bdf9..49a79fbf96 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -363,7 +363,7 @@ struct SpaprMachineState { /* Values for 2nd argument to H_SET_MODE */ #define H_SET_MODE_RESOURCE_SET_CIABR 1 -#define H_SET_MODE_RESOURCE_SET_DAWR 2 +#define H_SET_MODE_RESOURCE_SET_DAWR0 2 #define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE 3 #define H_SET_MODE_RESOURCE_LE 4 diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 69fc9a2831..8c18bb0762 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1489,10 +1489,10 @@ typedef PowerPCCPU ArchCPU; #define SPR_MPC_BAR (0x09F) #define SPR_PSPB (0x09F) #define SPR_DPDES (0x0B0) -#define SPR_DAWR (0x0B4) +#define SPR_DAWR0 (0x0B4) #define SPR_RPR (0x0BA) #define SPR_CIABR (0x0BB) -#define SPR_DAWRX (0x0BC) +#define SPR_DAWRX0 (0x0BC) #define SPR_HFSCR (0x0BE) #define SPR_VRSAVE (0x100) #define SPR_USPRG0 (0x100) diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index 06686489a0..58473c4c09 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -7748,12 +7748,12 @@ static void gen_spr_book3s_dbg(CPUPPCState *env) static void gen_spr_book3s_207_dbg(CPUPPCState *env) { - spr_register_kvm_hv(env, SPR_DAWR, "DAWR", + spr_register_kvm_hv(env, SPR_DAWR0, "DAWR0", SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, KVM_REG_PPC_DAWR, 0x00000000); - spr_register_kvm_hv(env, SPR_DAWRX, "DAWRX", + spr_register_kvm_hv(env, SPR_DAWRX0, "DAWRX0", SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, From 5642e4513e60b46473422902d7cc34e894e8793d Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 8 Apr 2021 17:40:48 -0300 Subject: [PATCH 0265/3028] spapr.c: do not use MachineClass::max_cpus to limit CPUs Up to this patch, 'max_cpus' value is hardcoded to 1024 (commit 6244bb7e5811). In theory this patch would simply bump it to 2048, since it's the default NR_CPUS kernel setting for ppc64 servers nowadays, but the whole mechanic of MachineClass:max_cpus is flawed for the pSeries machine. The two supported accelerators, KVM and TCG, can live without it. TCG guests don't have a theoretical limit. The user must be free to emulate as many CPUs as the hardware is capable of. And even if there were a limit, max_cpus is not the proper way to report it since it's a common value checked by SMP code in machine_smp_parse() for KVM as well. For KVM guests, the proper way to limit KVM CPUs is by host configuration via NR_CPUS, not a QEMU hardcoded value. There is no technical reason for a pSeries QEMU guest to forcefully stay below NR_CPUS. This hardcoded value also disregard hosts that might have a lower NR_CPUS limit, say 512. In this case, machine.c:machine_smp_parse() will allow a 1024 value to pass, but then kvm_init() will complain about it because it will exceed NR_CPUS: Number of SMP cpus requested (1024) exceeds the maximum cpus supported by KVM (512) A better 'max_cpus' value would consider host settings, but MachineClass::max_cpus is defined well before machine_init() and kvm_init(). We can't check for KVM limits because it's too soon, so we end up making a guess. This patch makes MachineClass:max_cpus settings innocuous by setting it to INT32_MAX. machine.c:machine_smp_parse() will not fail the verification based on max_cpus, letting kvm_init() do the checking with actual host settings. And TCG guests get to do whatever the hardware is capable of emulating. Signed-off-by: Daniel Henrique Barboza Message-Id: <20210408204049.221802-2-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index fd53615df0..b37ceb8ee8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4487,7 +4487,16 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->init = spapr_machine_init; mc->reset = spapr_machine_reset; mc->block_default_type = IF_SCSI; - mc->max_cpus = 1024; + + /* + * Setting max_cpus to INT32_MAX. Both KVM and TCG max_cpus values + * should be limited by the host capability instead of hardcoded. + * max_cpus for KVM guests will be checked in kvm_init(), and TCG + * guests are welcome to have as many CPUs as the host are capable + * of emulate. + */ + mc->max_cpus = INT32_MAX; + mc->no_parallel = 1; mc->default_boot_order = ""; mc->default_ram_size = 512 * MiB; From b7573092ab6749bff4b50a7b291a74d1cbb42f57 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 8 Apr 2021 17:40:49 -0300 Subject: [PATCH 0266/3028] spapr.h: increase FDT_MAX_SIZE Certain SMP topologies stress, e.g. 1 thread/core, 2048 cores and 1 socket, stress the current maximum size of the pSeries FDT: Calling ibm,client-architecture-support...qemu-system-ppc64: error creating device tree: (fdt_setprop(fdt, offset, "ibm,processor-segment-sizes", segs, sizeof(segs))): FDT_ERR_NOSPACE 2048 is the default NR_CPUS value for the pSeries kernel. It's expected that users will want QEMU to be able to handle this kind of configuration. Bumping FDT_MAX_SIZE to 2MB is enough for these setups to be created. Signed-off-by: Daniel Henrique Barboza Message-Id: <20210408204049.221802-3-danielhb413@gmail.com> Signed-off-by: David Gibson --- include/hw/ppc/spapr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 49a79fbf96..7f40a158f4 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -95,7 +95,7 @@ typedef enum { #define SPAPR_CAP_FIXED_CCD 0x03 #define SPAPR_CAP_FIXED_NA 0x10 /* Lets leave a bit of a gap... */ -#define FDT_MAX_SIZE 0x100000 +#define FDT_MAX_SIZE 0x200000 /* * NUMA related macros. MAX_DISTANCE_REF_POINTS was taken From 87758fed7a7a7c00c1bd0c965ae8b94e04ea9359 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 20 Apr 2021 13:51:00 -0300 Subject: [PATCH 0267/3028] spapr_drc.c: handle hotunplug errors in drc_unisolate_logical() At this moment, PAPR does not provide a way to report errors during a device removal operation. This led the pSeries machine to implement extra mechanisms to try to fallback and recover from an error that might have happened during the hotunplug in the guest side. This started to change a bit with commit fe1831eff8a4 ("spapr_drc.c: use DRC reconfiguration to cleanup DIMM unplug state"), where one way to fallback from a memory removal error was introduced. Around the same time, in [1], the idea of using RTAS set-indicator for this role was first introduced. The RTAS set-indicator call, when attempting to UNISOLATE a DRC that is already UNISOLATED or CONFIGURED, returns RTAS_OK and does nothing else for both QEMU and phyp. This gives us an opportunity to use this behavior to signal the hypervisor layer when a device removal errir happens, allowing QEMU/phyp to do a proper error handling. Using set-indicator to report HP errors isn't strange to PAPR, as per R1-13.5.3.4-4. of table 13.7 of current PAPR [2]: "For all DR options: If this is a DR operation that involves the user insert- ing a DR entity, then if the firmware can determine that the inserted entity would cause a system disturbance, then the set-indicator RTAS call must not unisolate the entity and must return an error status which is unique to the particular error." A change was proposed to the pSeries Linux kernel to call set-indicator to move a DRC to 'unisolate' in the case of a hotunplug error in the guest side [3]. Setting a DRC that is already unisolated or configured to 'unisolate' is a no-op (returns RTAS_OK) for QEMU and also for phyp. Being a benign change for hypervisors that doesn't care about handling such errors, we expect the kernel to accept this change at some point. This patch prepares the pSeries machine for this new kernel feature by changing drc_unisolate_logical() to handle guest side hotunplug errors. For CPUs it's a simple matter of setting drc->unplug_requested to 'false', while for LMBs the process is similar to the rollback that is done in rtas_ibm_configure_connector(). [1] https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg06395.html [2] https://openpowerfoundation.org/wp-content/uploads/2020/07/LoPAR-20200611.pdf [3] https://patchwork.ozlabs.org/project/linuxppc-dev/patch/20210416210216.380291-3-danielhb413@gmail.com/ Reviewed-by: David Gibson Signed-off-by: Daniel Henrique Barboza Message-Id: <20210420165100.108368-2-danielhb413@gmail.com> Signed-off-by: David Gibson --- hw/ppc/spapr_drc.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 9e16505fa1..6918e0c9d1 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -151,9 +151,32 @@ static uint32_t drc_isolate_logical(SpaprDrc *drc) static uint32_t drc_unisolate_logical(SpaprDrc *drc) { + SpaprMachineState *spapr = NULL; + switch (drc->state) { case SPAPR_DRC_STATE_LOGICAL_UNISOLATE: case SPAPR_DRC_STATE_LOGICAL_CONFIGURED: + /* + * Unisolating a logical DRC that was marked for unplug + * means that the kernel is refusing the removal. + */ + if (drc->unplug_requested && drc->dev) { + if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB) { + spapr = SPAPR_MACHINE(qdev_get_machine()); + + spapr_memory_unplug_rollback(spapr, drc->dev); + } + + drc->unplug_requested = false; + error_report("Device hotunplug rejected by the guest " + "for device %s", drc->dev->id); + + /* + * TODO: send a QAPI DEVICE_UNPLUG_ERROR event when + * it is implemented. + */ + } + return RTAS_OUT_SUCCESS; /* Nothing to do */ case SPAPR_DRC_STATE_LOGICAL_AVAILABLE: break; /* see below */ From 35a5d74e8248c09e66deefa82f8af5ffc83be5ef Mon Sep 17 00:00:00 2001 From: "Bruno Larsen (billionai)" Date: Mon, 26 Apr 2021 15:47:06 -0300 Subject: [PATCH 0268/3028] target/ppc: code motion from translate_init.c.inc to gdbstub.c All the code related to gdb has been moved from translate_init.c.inc file to the gdbstub.c file, where it makes more sense. Version 4 fixes the omission of internal.h in gdbstub, mentioned in <87sg3d2gf5.fsf@linux.ibm.com>, and the extra blank line. Signed-off-by: Bruno Larsen (billionai) Suggested-by: Fabiano Rosas Message-Id: <20210426184706.48040-1-bruno.larsen@eldorado.org.br> Signed-off-by: David Gibson --- target/ppc/gdbstub.c | 258 ++++++++++++++++++++++++++++++++ target/ppc/internal.h | 5 + target/ppc/translate_init.c.inc | 254 +------------------------------ 3 files changed, 264 insertions(+), 253 deletions(-) diff --git a/target/ppc/gdbstub.c b/target/ppc/gdbstub.c index c28319fb97..94a7273ee0 100644 --- a/target/ppc/gdbstub.c +++ b/target/ppc/gdbstub.c @@ -20,6 +20,8 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/gdbstub.h" +#include "exec/helper-proto.h" +#include "internal.h" static int ppc_gdb_register_len_apple(int n) { @@ -387,3 +389,259 @@ const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name) return NULL; } #endif + +static bool avr_need_swap(CPUPPCState *env) +{ +#ifdef HOST_WORDS_BIGENDIAN + return msr_le; +#else + return !msr_le; +#endif +} + +#if !defined(CONFIG_USER_ONLY) +static int gdb_find_spr_idx(CPUPPCState *env, int n) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { + ppc_spr_t *spr = &env->spr_cb[i]; + + if (spr->name && spr->gdb_id == n) { + return i; + } + } + return -1; +} + +static int gdb_get_spr_reg(CPUPPCState *env, GByteArray *buf, int n) +{ + int reg; + int len; + + reg = gdb_find_spr_idx(env, n); + if (reg < 0) { + return 0; + } + + len = TARGET_LONG_SIZE; + gdb_get_regl(buf, env->spr[reg]); + ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, len), len); + return len; +} + +static int gdb_set_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n) +{ + int reg; + int len; + + reg = gdb_find_spr_idx(env, n); + if (reg < 0) { + return 0; + } + + len = TARGET_LONG_SIZE; + ppc_maybe_bswap_register(env, mem_buf, len); + env->spr[reg] = ldn_p(mem_buf, len); + + return len; +} +#endif + +static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n) +{ + uint8_t *mem_buf; + if (n < 32) { + gdb_get_reg64(buf, *cpu_fpr_ptr(env, n)); + mem_buf = gdb_get_reg_ptr(buf, 8); + ppc_maybe_bswap_register(env, mem_buf, 8); + return 8; + } + if (n == 32) { + gdb_get_reg32(buf, env->fpscr); + mem_buf = gdb_get_reg_ptr(buf, 4); + ppc_maybe_bswap_register(env, mem_buf, 4); + return 4; + } + return 0; +} + +static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n) +{ + if (n < 32) { + ppc_maybe_bswap_register(env, mem_buf, 8); + *cpu_fpr_ptr(env, n) = ldq_p(mem_buf); + return 8; + } + if (n == 32) { + ppc_maybe_bswap_register(env, mem_buf, 4); + store_fpscr(env, ldl_p(mem_buf), 0xffffffff); + return 4; + } + return 0; +} + +static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n) +{ + uint8_t *mem_buf; + + if (n < 32) { + ppc_avr_t *avr = cpu_avr_ptr(env, n); + if (!avr_need_swap(env)) { + gdb_get_reg128(buf, avr->u64[0] , avr->u64[1]); + } else { + gdb_get_reg128(buf, avr->u64[1] , avr->u64[0]); + } + mem_buf = gdb_get_reg_ptr(buf, 16); + ppc_maybe_bswap_register(env, mem_buf, 8); + ppc_maybe_bswap_register(env, mem_buf + 8, 8); + return 16; + } + if (n == 32) { + gdb_get_reg32(buf, helper_mfvscr(env)); + mem_buf = gdb_get_reg_ptr(buf, 4); + ppc_maybe_bswap_register(env, mem_buf, 4); + return 4; + } + if (n == 33) { + gdb_get_reg32(buf, (uint32_t)env->spr[SPR_VRSAVE]); + mem_buf = gdb_get_reg_ptr(buf, 4); + ppc_maybe_bswap_register(env, mem_buf, 4); + return 4; + } + return 0; +} + +static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n) +{ + if (n < 32) { + ppc_avr_t *avr = cpu_avr_ptr(env, n); + ppc_maybe_bswap_register(env, mem_buf, 8); + ppc_maybe_bswap_register(env, mem_buf + 8, 8); + if (!avr_need_swap(env)) { + avr->u64[0] = ldq_p(mem_buf); + avr->u64[1] = ldq_p(mem_buf + 8); + } else { + avr->u64[1] = ldq_p(mem_buf); + avr->u64[0] = ldq_p(mem_buf + 8); + } + return 16; + } + if (n == 32) { + ppc_maybe_bswap_register(env, mem_buf, 4); + helper_mtvscr(env, ldl_p(mem_buf)); + return 4; + } + if (n == 33) { + ppc_maybe_bswap_register(env, mem_buf, 4); + env->spr[SPR_VRSAVE] = (target_ulong)ldl_p(mem_buf); + return 4; + } + return 0; +} + +static int gdb_get_spe_reg(CPUPPCState *env, GByteArray *buf, int n) +{ + if (n < 32) { +#if defined(TARGET_PPC64) + gdb_get_reg32(buf, env->gpr[n] >> 32); + ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4); +#else + gdb_get_reg32(buf, env->gprh[n]); +#endif + return 4; + } + if (n == 32) { + gdb_get_reg64(buf, env->spe_acc); + ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8); + return 8; + } + if (n == 33) { + gdb_get_reg32(buf, env->spe_fscr); + ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4); + return 4; + } + return 0; +} + +static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n) +{ + if (n < 32) { +#if defined(TARGET_PPC64) + target_ulong lo = (uint32_t)env->gpr[n]; + target_ulong hi; + + ppc_maybe_bswap_register(env, mem_buf, 4); + + hi = (target_ulong)ldl_p(mem_buf) << 32; + env->gpr[n] = lo | hi; +#else + env->gprh[n] = ldl_p(mem_buf); +#endif + return 4; + } + if (n == 32) { + ppc_maybe_bswap_register(env, mem_buf, 8); + env->spe_acc = ldq_p(mem_buf); + return 8; + } + if (n == 33) { + ppc_maybe_bswap_register(env, mem_buf, 4); + env->spe_fscr = ldl_p(mem_buf); + return 4; + } + return 0; +} + +static int gdb_get_vsx_reg(CPUPPCState *env, GByteArray *buf, int n) +{ + if (n < 32) { + gdb_get_reg64(buf, *cpu_vsrl_ptr(env, n)); + ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8); + return 8; + } + return 0; +} + +static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n) +{ + if (n < 32) { + ppc_maybe_bswap_register(env, mem_buf, 8); + *cpu_vsrl_ptr(env, n) = ldq_p(mem_buf); + return 8; + } + return 0; +} + +gchar *ppc_gdb_arch_name(CPUState *cs) +{ +#if defined(TARGET_PPC64) + return g_strdup("powerpc:common64"); +#else + return g_strdup("powerpc:common"); +#endif +} + +void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *pcc) +{ + if (pcc->insns_flags & PPC_FLOAT) { + gdb_register_coprocessor(cs, gdb_get_float_reg, gdb_set_float_reg, + 33, "power-fpu.xml", 0); + } + if (pcc->insns_flags & PPC_ALTIVEC) { + gdb_register_coprocessor(cs, gdb_get_avr_reg, gdb_set_avr_reg, + 34, "power-altivec.xml", 0); + } + if (pcc->insns_flags & PPC_SPE) { + gdb_register_coprocessor(cs, gdb_get_spe_reg, gdb_set_spe_reg, + 34, "power-spe.xml", 0); + } + if (pcc->insns_flags2 & PPC2_VSX) { + gdb_register_coprocessor(cs, gdb_get_vsx_reg, gdb_set_vsx_reg, + 32, "power-vsx.xml", 0); + } +#ifndef CONFIG_USER_ONLY + gdb_register_coprocessor(cs, gdb_get_spr_reg, gdb_set_spr_reg, + pcc->gdb_num_sprs, "power-spr.xml", 0); +#endif +} diff --git a/target/ppc/internal.h b/target/ppc/internal.h index d547448065..c401658e8d 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -215,4 +215,9 @@ void helper_compute_fprf_float128(CPUPPCState *env, float128 arg); void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); + +/* gdbstub.c */ +void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc); +gchar *ppc_gdb_arch_name(CPUState *cs); + #endif /* PPC_INTERNAL_H */ diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index 58473c4c09..9ab2c32cc4 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -9895,230 +9895,6 @@ static void dump_ppc_insns(CPUPPCState *env) } } #endif - -static bool avr_need_swap(CPUPPCState *env) -{ -#ifdef HOST_WORDS_BIGENDIAN - return msr_le; -#else - return !msr_le; -#endif -} - -#if !defined(CONFIG_USER_ONLY) -static int gdb_find_spr_idx(CPUPPCState *env, int n) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) { - ppc_spr_t *spr = &env->spr_cb[i]; - - if (spr->name && spr->gdb_id == n) { - return i; - } - } - return -1; -} - -static int gdb_get_spr_reg(CPUPPCState *env, GByteArray *buf, int n) -{ - int reg; - int len; - - reg = gdb_find_spr_idx(env, n); - if (reg < 0) { - return 0; - } - - len = TARGET_LONG_SIZE; - gdb_get_regl(buf, env->spr[reg]); - ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, len), len); - return len; -} - -static int gdb_set_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n) -{ - int reg; - int len; - - reg = gdb_find_spr_idx(env, n); - if (reg < 0) { - return 0; - } - - len = TARGET_LONG_SIZE; - ppc_maybe_bswap_register(env, mem_buf, len); - env->spr[reg] = ldn_p(mem_buf, len); - - return len; -} -#endif - -static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n) -{ - uint8_t *mem_buf; - if (n < 32) { - gdb_get_reg64(buf, *cpu_fpr_ptr(env, n)); - mem_buf = gdb_get_reg_ptr(buf, 8); - ppc_maybe_bswap_register(env, mem_buf, 8); - return 8; - } - if (n == 32) { - gdb_get_reg32(buf, env->fpscr); - mem_buf = gdb_get_reg_ptr(buf, 4); - ppc_maybe_bswap_register(env, mem_buf, 4); - return 4; - } - return 0; -} - -static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n) -{ - if (n < 32) { - ppc_maybe_bswap_register(env, mem_buf, 8); - *cpu_fpr_ptr(env, n) = ldq_p(mem_buf); - return 8; - } - if (n == 32) { - ppc_maybe_bswap_register(env, mem_buf, 4); - helper_store_fpscr(env, ldl_p(mem_buf), 0xffffffff); - return 4; - } - return 0; -} - -static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n) -{ - uint8_t *mem_buf; - - if (n < 32) { - ppc_avr_t *avr = cpu_avr_ptr(env, n); - if (!avr_need_swap(env)) { - gdb_get_reg128(buf, avr->u64[0] , avr->u64[1]); - } else { - gdb_get_reg128(buf, avr->u64[1] , avr->u64[0]); - } - mem_buf = gdb_get_reg_ptr(buf, 16); - ppc_maybe_bswap_register(env, mem_buf, 8); - ppc_maybe_bswap_register(env, mem_buf + 8, 8); - return 16; - } - if (n == 32) { - gdb_get_reg32(buf, helper_mfvscr(env)); - mem_buf = gdb_get_reg_ptr(buf, 4); - ppc_maybe_bswap_register(env, mem_buf, 4); - return 4; - } - if (n == 33) { - gdb_get_reg32(buf, (uint32_t)env->spr[SPR_VRSAVE]); - mem_buf = gdb_get_reg_ptr(buf, 4); - ppc_maybe_bswap_register(env, mem_buf, 4); - return 4; - } - return 0; -} - -static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n) -{ - if (n < 32) { - ppc_avr_t *avr = cpu_avr_ptr(env, n); - ppc_maybe_bswap_register(env, mem_buf, 8); - ppc_maybe_bswap_register(env, mem_buf + 8, 8); - if (!avr_need_swap(env)) { - avr->u64[0] = ldq_p(mem_buf); - avr->u64[1] = ldq_p(mem_buf + 8); - } else { - avr->u64[1] = ldq_p(mem_buf); - avr->u64[0] = ldq_p(mem_buf + 8); - } - return 16; - } - if (n == 32) { - ppc_maybe_bswap_register(env, mem_buf, 4); - helper_mtvscr(env, ldl_p(mem_buf)); - return 4; - } - if (n == 33) { - ppc_maybe_bswap_register(env, mem_buf, 4); - env->spr[SPR_VRSAVE] = (target_ulong)ldl_p(mem_buf); - return 4; - } - return 0; -} - -static int gdb_get_spe_reg(CPUPPCState *env, GByteArray *buf, int n) -{ - if (n < 32) { -#if defined(TARGET_PPC64) - gdb_get_reg32(buf, env->gpr[n] >> 32); - ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4); -#else - gdb_get_reg32(buf, env->gprh[n]); -#endif - return 4; - } - if (n == 32) { - gdb_get_reg64(buf, env->spe_acc); - ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8); - return 8; - } - if (n == 33) { - gdb_get_reg32(buf, env->spe_fscr); - ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4); - return 4; - } - return 0; -} - -static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n) -{ - if (n < 32) { -#if defined(TARGET_PPC64) - target_ulong lo = (uint32_t)env->gpr[n]; - target_ulong hi; - - ppc_maybe_bswap_register(env, mem_buf, 4); - - hi = (target_ulong)ldl_p(mem_buf) << 32; - env->gpr[n] = lo | hi; -#else - env->gprh[n] = ldl_p(mem_buf); -#endif - return 4; - } - if (n == 32) { - ppc_maybe_bswap_register(env, mem_buf, 8); - env->spe_acc = ldq_p(mem_buf); - return 8; - } - if (n == 33) { - ppc_maybe_bswap_register(env, mem_buf, 4); - env->spe_fscr = ldl_p(mem_buf); - return 4; - } - return 0; -} - -static int gdb_get_vsx_reg(CPUPPCState *env, GByteArray *buf, int n) -{ - if (n < 32) { - gdb_get_reg64(buf, *cpu_vsrl_ptr(env, n)); - ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8); - return 8; - } - return 0; -} - -static int gdb_set_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n) -{ - if (n < 32) { - ppc_maybe_bswap_register(env, mem_buf, 8); - *cpu_vsrl_ptr(env, n) = ldq_p(mem_buf); - return 8; - } - return 0; -} - static int ppc_fixup_cpu(PowerPCCPU *cpu) { CPUPPCState *env = &cpu->env; @@ -10174,26 +9950,7 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp) } init_ppc_proc(cpu); - if (pcc->insns_flags & PPC_FLOAT) { - gdb_register_coprocessor(cs, gdb_get_float_reg, gdb_set_float_reg, - 33, "power-fpu.xml", 0); - } - if (pcc->insns_flags & PPC_ALTIVEC) { - gdb_register_coprocessor(cs, gdb_get_avr_reg, gdb_set_avr_reg, - 34, "power-altivec.xml", 0); - } - if (pcc->insns_flags & PPC_SPE) { - gdb_register_coprocessor(cs, gdb_get_spe_reg, gdb_set_spe_reg, - 34, "power-spe.xml", 0); - } - if (pcc->insns_flags2 & PPC2_VSX) { - gdb_register_coprocessor(cs, gdb_get_vsx_reg, gdb_set_vsx_reg, - 32, "power-vsx.xml", 0); - } -#ifndef CONFIG_USER_ONLY - gdb_register_coprocessor(cs, gdb_get_spr_reg, gdb_set_spr_reg, - pcc->gdb_num_sprs, "power-spr.xml", 0); -#endif + ppc_gdb_init(cs, pcc); qemu_init_vcpu(cs); pcc->parent_realize(dev, errp); @@ -10835,15 +10592,6 @@ static bool ppc_pvr_match_default(PowerPCCPUClass *pcc, uint32_t pvr) return pcc->pvr == pvr; } -static gchar *ppc_gdb_arch_name(CPUState *cs) -{ -#if defined(TARGET_PPC64) - return g_strdup("powerpc:common64"); -#else - return g_strdup("powerpc:common"); -#endif -} - static void ppc_disas_set_info(CPUState *cs, disassemble_info *info) { PowerPCCPU *cpu = POWERPC_CPU(cs); From 7468e2c8428d5455ae3efff929dc152bbbe8e6e9 Mon Sep 17 00:00:00 2001 From: "Bruno Larsen (billionai)" Date: Thu, 29 Apr 2021 13:21:24 -0300 Subject: [PATCH 0269/3028] target/ppc: move opcode table logic to translate.c code motion to remove opcode callback table from translate_init.c.inc to translate.c in preparation to remove the #include from translate.c. Also created destroy_ppc_opcodes and removed that logic from ppc_cpu_unrealize Signed-off-by: Bruno Larsen (billionai) Message-Id: <20210429162130.2412-2-bruno.larsen@eldorado.org.br> Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target/ppc/internal.h | 8 + target/ppc/translate.c | 394 ++++++++++++++++++++++++++++++++ target/ppc/translate_init.c.inc | 391 +------------------------------ 3 files changed, 403 insertions(+), 390 deletions(-) diff --git a/target/ppc/internal.h b/target/ppc/internal.h index c401658e8d..184ba6d6b3 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -216,6 +216,14 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); +/* translate.c */ + +/* #define PPC_DUMP_CPU */ + +int ppc_fixup_cpu(PowerPCCPU *cpu); +void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp); +void destroy_ppc_opcodes(PowerPCCPU *cpu); + /* gdbstub.c */ void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc); gchar *ppc_gdb_arch_name(CPUState *cs); diff --git a/target/ppc/translate.c b/target/ppc/translate.c index a53463b9b8..a7c568ca9c 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7825,6 +7825,400 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags) #undef RFPL } +/*****************************************************************************/ +/* Opcode types */ +enum { + PPC_DIRECT = 0, /* Opcode routine */ + PPC_INDIRECT = 1, /* Indirect opcode table */ +}; + +#define PPC_OPCODE_MASK 0x3 + +static inline int is_indirect_opcode(void *handler) +{ + return ((uintptr_t)handler & PPC_OPCODE_MASK) == PPC_INDIRECT; +} + +static inline opc_handler_t **ind_table(void *handler) +{ + return (opc_handler_t **)((uintptr_t)handler & ~PPC_OPCODE_MASK); +} + +/* Instruction table creation */ +/* Opcodes tables creation */ +static void fill_new_table(opc_handler_t **table, int len) +{ + int i; + + for (i = 0; i < len; i++) { + table[i] = &invalid_handler; + } +} + +static int create_new_table(opc_handler_t **table, unsigned char idx) +{ + opc_handler_t **tmp; + + tmp = g_new(opc_handler_t *, PPC_CPU_INDIRECT_OPCODES_LEN); + fill_new_table(tmp, PPC_CPU_INDIRECT_OPCODES_LEN); + table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT); + + return 0; +} + +static int insert_in_table(opc_handler_t **table, unsigned char idx, + opc_handler_t *handler) +{ + if (table[idx] != &invalid_handler) { + return -1; + } + table[idx] = handler; + + return 0; +} + +static int register_direct_insn(opc_handler_t **ppc_opcodes, + unsigned char idx, opc_handler_t *handler) +{ + if (insert_in_table(ppc_opcodes, idx, handler) < 0) { + printf("*** ERROR: opcode %02x already assigned in main " + "opcode table\n", idx); +#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) + printf(" Registered handler '%s' - new handler '%s'\n", + ppc_opcodes[idx]->oname, handler->oname); +#endif + return -1; + } + + return 0; +} + +static int register_ind_in_table(opc_handler_t **table, + unsigned char idx1, unsigned char idx2, + opc_handler_t *handler) +{ + if (table[idx1] == &invalid_handler) { + if (create_new_table(table, idx1) < 0) { + printf("*** ERROR: unable to create indirect table " + "idx=%02x\n", idx1); + return -1; + } + } else { + if (!is_indirect_opcode(table[idx1])) { + printf("*** ERROR: idx %02x already assigned to a direct " + "opcode\n", idx1); +#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) + printf(" Registered handler '%s' - new handler '%s'\n", + ind_table(table[idx1])[idx2]->oname, handler->oname); +#endif + return -1; + } + } + if (handler != NULL && + insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { + printf("*** ERROR: opcode %02x already assigned in " + "opcode table %02x\n", idx2, idx1); +#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) + printf(" Registered handler '%s' - new handler '%s'\n", + ind_table(table[idx1])[idx2]->oname, handler->oname); +#endif + return -1; + } + + return 0; +} + +static int register_ind_insn(opc_handler_t **ppc_opcodes, + unsigned char idx1, unsigned char idx2, + opc_handler_t *handler) +{ + return register_ind_in_table(ppc_opcodes, idx1, idx2, handler); +} + +static int register_dblind_insn(opc_handler_t **ppc_opcodes, + unsigned char idx1, unsigned char idx2, + unsigned char idx3, opc_handler_t *handler) +{ + if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { + printf("*** ERROR: unable to join indirect table idx " + "[%02x-%02x]\n", idx1, idx2); + return -1; + } + if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3, + handler) < 0) { + printf("*** ERROR: unable to insert opcode " + "[%02x-%02x-%02x]\n", idx1, idx2, idx3); + return -1; + } + + return 0; +} + +static int register_trplind_insn(opc_handler_t **ppc_opcodes, + unsigned char idx1, unsigned char idx2, + unsigned char idx3, unsigned char idx4, + opc_handler_t *handler) +{ + opc_handler_t **table; + + if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { + printf("*** ERROR: unable to join indirect table idx " + "[%02x-%02x]\n", idx1, idx2); + return -1; + } + table = ind_table(ppc_opcodes[idx1]); + if (register_ind_in_table(table, idx2, idx3, NULL) < 0) { + printf("*** ERROR: unable to join 2nd-level indirect table idx " + "[%02x-%02x-%02x]\n", idx1, idx2, idx3); + return -1; + } + table = ind_table(table[idx2]); + if (register_ind_in_table(table, idx3, idx4, handler) < 0) { + printf("*** ERROR: unable to insert opcode " + "[%02x-%02x-%02x-%02x]\n", idx1, idx2, idx3, idx4); + return -1; + } + return 0; +} +static int register_insn(opc_handler_t **ppc_opcodes, opcode_t *insn) +{ + if (insn->opc2 != 0xFF) { + if (insn->opc3 != 0xFF) { + if (insn->opc4 != 0xFF) { + if (register_trplind_insn(ppc_opcodes, insn->opc1, insn->opc2, + insn->opc3, insn->opc4, + &insn->handler) < 0) { + return -1; + } + } else { + if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, + insn->opc3, &insn->handler) < 0) { + return -1; + } + } + } else { + if (register_ind_insn(ppc_opcodes, insn->opc1, + insn->opc2, &insn->handler) < 0) { + return -1; + } + } + } else { + if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) { + return -1; + } + } + + return 0; +} + +static int test_opcode_table(opc_handler_t **table, int len) +{ + int i, count, tmp; + + for (i = 0, count = 0; i < len; i++) { + /* Consistency fixup */ + if (table[i] == NULL) { + table[i] = &invalid_handler; + } + if (table[i] != &invalid_handler) { + if (is_indirect_opcode(table[i])) { + tmp = test_opcode_table(ind_table(table[i]), + PPC_CPU_INDIRECT_OPCODES_LEN); + if (tmp == 0) { + free(table[i]); + table[i] = &invalid_handler; + } else { + count++; + } + } else { + count++; + } + } + } + + return count; +} + +static void fix_opcode_tables(opc_handler_t **ppc_opcodes) +{ + if (test_opcode_table(ppc_opcodes, PPC_CPU_OPCODES_LEN) == 0) { + printf("*** WARNING: no opcode defined !\n"); + } +} + +/*****************************************************************************/ +void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) +{ + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + opcode_t *opc; + + fill_new_table(cpu->opcodes, PPC_CPU_OPCODES_LEN); + for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) { + if (((opc->handler.type & pcc->insns_flags) != 0) || + ((opc->handler.type2 & pcc->insns_flags2) != 0)) { + if (register_insn(cpu->opcodes, opc) < 0) { + error_setg(errp, "ERROR initializing PowerPC instruction " + "0x%02x 0x%02x 0x%02x", opc->opc1, opc->opc2, + opc->opc3); + return; + } + } + } + fix_opcode_tables(cpu->opcodes); + fflush(stdout); + fflush(stderr); +} + +void destroy_ppc_opcodes(PowerPCCPU *cpu) +{ + opc_handler_t **table, **table_2; + int i, j, k; + + for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) { + if (cpu->opcodes[i] == &invalid_handler) { + continue; + } + if (is_indirect_opcode(cpu->opcodes[i])) { + table = ind_table(cpu->opcodes[i]); + for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) { + if (table[j] == &invalid_handler) { + continue; + } + if (is_indirect_opcode(table[j])) { + table_2 = ind_table(table[j]); + for (k = 0; k < PPC_CPU_INDIRECT_OPCODES_LEN; k++) { + if (table_2[k] != &invalid_handler && + is_indirect_opcode(table_2[k])) { + g_free((opc_handler_t *)((uintptr_t)table_2[k] & + ~PPC_INDIRECT)); + } + } + g_free((opc_handler_t *)((uintptr_t)table[j] & + ~PPC_INDIRECT)); + } + } + g_free((opc_handler_t *)((uintptr_t)cpu->opcodes[i] & + ~PPC_INDIRECT)); + } + } +} + +#if defined(PPC_DUMP_CPU) +static void dump_ppc_insns(CPUPPCState *env) +{ + opc_handler_t **table, *handler; + const char *p, *q; + uint8_t opc1, opc2, opc3, opc4; + + printf("Instructions set:\n"); + /* opc1 is 6 bits long */ + for (opc1 = 0x00; opc1 < PPC_CPU_OPCODES_LEN; opc1++) { + table = env->opcodes; + handler = table[opc1]; + if (is_indirect_opcode(handler)) { + /* opc2 is 5 bits long */ + for (opc2 = 0; opc2 < PPC_CPU_INDIRECT_OPCODES_LEN; opc2++) { + table = env->opcodes; + handler = env->opcodes[opc1]; + table = ind_table(handler); + handler = table[opc2]; + if (is_indirect_opcode(handler)) { + table = ind_table(handler); + /* opc3 is 5 bits long */ + for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN; + opc3++) { + handler = table[opc3]; + if (is_indirect_opcode(handler)) { + table = ind_table(handler); + /* opc4 is 5 bits long */ + for (opc4 = 0; opc4 < PPC_CPU_INDIRECT_OPCODES_LEN; + opc4++) { + handler = table[opc4]; + if (handler->handler != &gen_invalid) { + printf("INSN: %02x %02x %02x %02x -- " + "(%02d %04d %02d) : %s\n", + opc1, opc2, opc3, opc4, + opc1, (opc3 << 5) | opc2, opc4, + handler->oname); + } + } + } else { + if (handler->handler != &gen_invalid) { + /* Special hack to properly dump SPE insns */ + p = strchr(handler->oname, '_'); + if (p == NULL) { + printf("INSN: %02x %02x %02x (%02d %04d) : " + "%s\n", + opc1, opc2, opc3, opc1, + (opc3 << 5) | opc2, + handler->oname); + } else { + q = "speundef"; + if ((p - handler->oname) != strlen(q) + || (memcmp(handler->oname, q, strlen(q)) + != 0)) { + /* First instruction */ + printf("INSN: %02x %02x %02x" + "(%02d %04d) : %.*s\n", + opc1, opc2 << 1, opc3, opc1, + (opc3 << 6) | (opc2 << 1), + (int)(p - handler->oname), + handler->oname); + } + if (strcmp(p + 1, q) != 0) { + /* Second instruction */ + printf("INSN: %02x %02x %02x " + "(%02d %04d) : %s\n", opc1, + (opc2 << 1) | 1, opc3, opc1, + (opc3 << 6) | (opc2 << 1) | 1, + p + 1); + } + } + } + } + } + } else { + if (handler->handler != &gen_invalid) { + printf("INSN: %02x %02x -- (%02d %04d) : %s\n", + opc1, opc2, opc1, opc2, handler->oname); + } + } + } + } else { + if (handler->handler != &gen_invalid) { + printf("INSN: %02x -- -- (%02d ----) : %s\n", + opc1, opc1, handler->oname); + } + } + } +} +#endif +int ppc_fixup_cpu(PowerPCCPU *cpu) +{ + CPUPPCState *env = &cpu->env; + + /* + * TCG doesn't (yet) emulate some groups of instructions that are + * implemented on some otherwise supported CPUs (e.g. VSX and + * decimal floating point instructions on POWER7). We remove + * unsupported instruction groups from the cpu state's instruction + * masks and hope the guest can cope. For at least the pseries + * machine, the unavailability of these instructions can be + * advertised to the guest via the device tree. + */ + if ((env->insns_flags & ~PPC_TCG_INSNS) + || (env->insns_flags2 & ~PPC_TCG_INSNS2)) { + warn_report("Disabling some instructions which are not " + "emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")", + env->insns_flags & ~PPC_TCG_INSNS, + env->insns_flags2 & ~PPC_TCG_INSNS2); + } + env->insns_flags &= PPC_TCG_INSNS; + env->insns_flags2 &= PPC_TCG_INSNS2; + return 0; +} + + void ppc_cpu_dump_statistics(CPUState *cs, int flags) { #if defined(DO_PPC_STATISTICS) diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index 9ab2c32cc4..42b3a4fd57 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -42,7 +42,6 @@ #include "fpu/softfloat.h" #include "qapi/qapi-commands-machine-target.h" -/* #define PPC_DUMP_CPU */ /* #define PPC_DEBUG_SPR */ /* #define PPC_DUMP_SPR_ACCESSES */ /* #define USE_APPLE_GDB */ @@ -9560,366 +9559,6 @@ static void dump_ppc_sprs(CPUPPCState *env) } #endif -/*****************************************************************************/ - -/* Opcode types */ -enum { - PPC_DIRECT = 0, /* Opcode routine */ - PPC_INDIRECT = 1, /* Indirect opcode table */ -}; - -#define PPC_OPCODE_MASK 0x3 - -static inline int is_indirect_opcode(void *handler) -{ - return ((uintptr_t)handler & PPC_OPCODE_MASK) == PPC_INDIRECT; -} - -static inline opc_handler_t **ind_table(void *handler) -{ - return (opc_handler_t **)((uintptr_t)handler & ~PPC_OPCODE_MASK); -} - -/* Instruction table creation */ -/* Opcodes tables creation */ -static void fill_new_table(opc_handler_t **table, int len) -{ - int i; - - for (i = 0; i < len; i++) { - table[i] = &invalid_handler; - } -} - -static int create_new_table(opc_handler_t **table, unsigned char idx) -{ - opc_handler_t **tmp; - - tmp = g_new(opc_handler_t *, PPC_CPU_INDIRECT_OPCODES_LEN); - fill_new_table(tmp, PPC_CPU_INDIRECT_OPCODES_LEN); - table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT); - - return 0; -} - -static int insert_in_table(opc_handler_t **table, unsigned char idx, - opc_handler_t *handler) -{ - if (table[idx] != &invalid_handler) { - return -1; - } - table[idx] = handler; - - return 0; -} - -static int register_direct_insn(opc_handler_t **ppc_opcodes, - unsigned char idx, opc_handler_t *handler) -{ - if (insert_in_table(ppc_opcodes, idx, handler) < 0) { - printf("*** ERROR: opcode %02x already assigned in main " - "opcode table\n", idx); -#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) - printf(" Registered handler '%s' - new handler '%s'\n", - ppc_opcodes[idx]->oname, handler->oname); -#endif - return -1; - } - - return 0; -} - -static int register_ind_in_table(opc_handler_t **table, - unsigned char idx1, unsigned char idx2, - opc_handler_t *handler) -{ - if (table[idx1] == &invalid_handler) { - if (create_new_table(table, idx1) < 0) { - printf("*** ERROR: unable to create indirect table " - "idx=%02x\n", idx1); - return -1; - } - } else { - if (!is_indirect_opcode(table[idx1])) { - printf("*** ERROR: idx %02x already assigned to a direct " - "opcode\n", idx1); -#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) - printf(" Registered handler '%s' - new handler '%s'\n", - ind_table(table[idx1])[idx2]->oname, handler->oname); -#endif - return -1; - } - } - if (handler != NULL && - insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { - printf("*** ERROR: opcode %02x already assigned in " - "opcode table %02x\n", idx2, idx1); -#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU) - printf(" Registered handler '%s' - new handler '%s'\n", - ind_table(table[idx1])[idx2]->oname, handler->oname); -#endif - return -1; - } - - return 0; -} - -static int register_ind_insn(opc_handler_t **ppc_opcodes, - unsigned char idx1, unsigned char idx2, - opc_handler_t *handler) -{ - return register_ind_in_table(ppc_opcodes, idx1, idx2, handler); -} - -static int register_dblind_insn(opc_handler_t **ppc_opcodes, - unsigned char idx1, unsigned char idx2, - unsigned char idx3, opc_handler_t *handler) -{ - if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { - printf("*** ERROR: unable to join indirect table idx " - "[%02x-%02x]\n", idx1, idx2); - return -1; - } - if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3, - handler) < 0) { - printf("*** ERROR: unable to insert opcode " - "[%02x-%02x-%02x]\n", idx1, idx2, idx3); - return -1; - } - - return 0; -} - -static int register_trplind_insn(opc_handler_t **ppc_opcodes, - unsigned char idx1, unsigned char idx2, - unsigned char idx3, unsigned char idx4, - opc_handler_t *handler) -{ - opc_handler_t **table; - - if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { - printf("*** ERROR: unable to join indirect table idx " - "[%02x-%02x]\n", idx1, idx2); - return -1; - } - table = ind_table(ppc_opcodes[idx1]); - if (register_ind_in_table(table, idx2, idx3, NULL) < 0) { - printf("*** ERROR: unable to join 2nd-level indirect table idx " - "[%02x-%02x-%02x]\n", idx1, idx2, idx3); - return -1; - } - table = ind_table(table[idx2]); - if (register_ind_in_table(table, idx3, idx4, handler) < 0) { - printf("*** ERROR: unable to insert opcode " - "[%02x-%02x-%02x-%02x]\n", idx1, idx2, idx3, idx4); - return -1; - } - return 0; -} -static int register_insn(opc_handler_t **ppc_opcodes, opcode_t *insn) -{ - if (insn->opc2 != 0xFF) { - if (insn->opc3 != 0xFF) { - if (insn->opc4 != 0xFF) { - if (register_trplind_insn(ppc_opcodes, insn->opc1, insn->opc2, - insn->opc3, insn->opc4, - &insn->handler) < 0) { - return -1; - } - } else { - if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, - insn->opc3, &insn->handler) < 0) { - return -1; - } - } - } else { - if (register_ind_insn(ppc_opcodes, insn->opc1, - insn->opc2, &insn->handler) < 0) { - return -1; - } - } - } else { - if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) { - return -1; - } - } - - return 0; -} - -static int test_opcode_table(opc_handler_t **table, int len) -{ - int i, count, tmp; - - for (i = 0, count = 0; i < len; i++) { - /* Consistency fixup */ - if (table[i] == NULL) { - table[i] = &invalid_handler; - } - if (table[i] != &invalid_handler) { - if (is_indirect_opcode(table[i])) { - tmp = test_opcode_table(ind_table(table[i]), - PPC_CPU_INDIRECT_OPCODES_LEN); - if (tmp == 0) { - free(table[i]); - table[i] = &invalid_handler; - } else { - count++; - } - } else { - count++; - } - } - } - - return count; -} - -static void fix_opcode_tables(opc_handler_t **ppc_opcodes) -{ - if (test_opcode_table(ppc_opcodes, PPC_CPU_OPCODES_LEN) == 0) { - printf("*** WARNING: no opcode defined !\n"); - } -} - -/*****************************************************************************/ -static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp) -{ - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - opcode_t *opc; - - fill_new_table(cpu->opcodes, PPC_CPU_OPCODES_LEN); - for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) { - if (((opc->handler.type & pcc->insns_flags) != 0) || - ((opc->handler.type2 & pcc->insns_flags2) != 0)) { - if (register_insn(cpu->opcodes, opc) < 0) { - error_setg(errp, "ERROR initializing PowerPC instruction " - "0x%02x 0x%02x 0x%02x", opc->opc1, opc->opc2, - opc->opc3); - return; - } - } - } - fix_opcode_tables(cpu->opcodes); - fflush(stdout); - fflush(stderr); -} - -#if defined(PPC_DUMP_CPU) -static void dump_ppc_insns(CPUPPCState *env) -{ - opc_handler_t **table, *handler; - const char *p, *q; - uint8_t opc1, opc2, opc3, opc4; - - printf("Instructions set:\n"); - /* opc1 is 6 bits long */ - for (opc1 = 0x00; opc1 < PPC_CPU_OPCODES_LEN; opc1++) { - table = env->opcodes; - handler = table[opc1]; - if (is_indirect_opcode(handler)) { - /* opc2 is 5 bits long */ - for (opc2 = 0; opc2 < PPC_CPU_INDIRECT_OPCODES_LEN; opc2++) { - table = env->opcodes; - handler = env->opcodes[opc1]; - table = ind_table(handler); - handler = table[opc2]; - if (is_indirect_opcode(handler)) { - table = ind_table(handler); - /* opc3 is 5 bits long */ - for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN; - opc3++) { - handler = table[opc3]; - if (is_indirect_opcode(handler)) { - table = ind_table(handler); - /* opc4 is 5 bits long */ - for (opc4 = 0; opc4 < PPC_CPU_INDIRECT_OPCODES_LEN; - opc4++) { - handler = table[opc4]; - if (handler->handler != &gen_invalid) { - printf("INSN: %02x %02x %02x %02x -- " - "(%02d %04d %02d) : %s\n", - opc1, opc2, opc3, opc4, - opc1, (opc3 << 5) | opc2, opc4, - handler->oname); - } - } - } else { - if (handler->handler != &gen_invalid) { - /* Special hack to properly dump SPE insns */ - p = strchr(handler->oname, '_'); - if (p == NULL) { - printf("INSN: %02x %02x %02x (%02d %04d) : " - "%s\n", - opc1, opc2, opc3, opc1, - (opc3 << 5) | opc2, - handler->oname); - } else { - q = "speundef"; - if ((p - handler->oname) != strlen(q) - || (memcmp(handler->oname, q, strlen(q)) - != 0)) { - /* First instruction */ - printf("INSN: %02x %02x %02x" - "(%02d %04d) : %.*s\n", - opc1, opc2 << 1, opc3, opc1, - (opc3 << 6) | (opc2 << 1), - (int)(p - handler->oname), - handler->oname); - } - if (strcmp(p + 1, q) != 0) { - /* Second instruction */ - printf("INSN: %02x %02x %02x " - "(%02d %04d) : %s\n", opc1, - (opc2 << 1) | 1, opc3, opc1, - (opc3 << 6) | (opc2 << 1) | 1, - p + 1); - } - } - } - } - } - } else { - if (handler->handler != &gen_invalid) { - printf("INSN: %02x %02x -- (%02d %04d) : %s\n", - opc1, opc2, opc1, opc2, handler->oname); - } - } - } - } else { - if (handler->handler != &gen_invalid) { - printf("INSN: %02x -- -- (%02d ----) : %s\n", - opc1, opc1, handler->oname); - } - } - } -} -#endif -static int ppc_fixup_cpu(PowerPCCPU *cpu) -{ - CPUPPCState *env = &cpu->env; - - /* - * TCG doesn't (yet) emulate some groups of instructions that are - * implemented on some otherwise supported CPUs (e.g. VSX and - * decimal floating point instructions on POWER7). We remove - * unsupported instruction groups from the cpu state's instruction - * masks and hope the guest can cope. For at least the pseries - * machine, the unavailability of these instructions can be - * advertised to the guest via the device tree. - */ - if ((env->insns_flags & ~PPC_TCG_INSNS) - || (env->insns_flags2 & ~PPC_TCG_INSNS2)) { - warn_report("Disabling some instructions which are not " - "emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")", - env->insns_flags & ~PPC_TCG_INSNS, - env->insns_flags2 & ~PPC_TCG_INSNS2); - } - env->insns_flags &= PPC_TCG_INSNS; - env->insns_flags2 &= PPC_TCG_INSNS2; - return 0; -} - static void ppc_cpu_realize(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -10131,40 +9770,12 @@ static void ppc_cpu_unrealize(DeviceState *dev) { PowerPCCPU *cpu = POWERPC_CPU(dev); PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - opc_handler_t **table, **table_2; - int i, j, k; pcc->parent_unrealize(dev); cpu_remove_sync(CPU(cpu)); - for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) { - if (cpu->opcodes[i] == &invalid_handler) { - continue; - } - if (is_indirect_opcode(cpu->opcodes[i])) { - table = ind_table(cpu->opcodes[i]); - for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) { - if (table[j] == &invalid_handler) { - continue; - } - if (is_indirect_opcode(table[j])) { - table_2 = ind_table(table[j]); - for (k = 0; k < PPC_CPU_INDIRECT_OPCODES_LEN; k++) { - if (table_2[k] != &invalid_handler && - is_indirect_opcode(table_2[k])) { - g_free((opc_handler_t *)((uintptr_t)table_2[k] & - ~PPC_INDIRECT)); - } - } - g_free((opc_handler_t *)((uintptr_t)table[j] & - ~PPC_INDIRECT)); - } - } - g_free((opc_handler_t *)((uintptr_t)cpu->opcodes[i] & - ~PPC_INDIRECT)); - } - } + destroy_ppc_opcodes(cpu); } static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b) From 8b7e6b07a46809a75b857d30ae47e697e0f9b724 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 1 May 2021 17:24:34 +1000 Subject: [PATCH 0270/3028] target/ppc: rework AIL logic in interrupt delivery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AIL logic is becoming unmanageable spread all over powerpc_excp(), and it is slated to get even worse with POWER10 support. Move it all to a new helper function. Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Signed-off-by: Nicholas Piggin Message-Id: <20210501072436.145444-2-npiggin@gmail.com> [dwg: Corrected tab indenting] Signed-off-by: David Gibson --- hw/ppc/spapr_hcall.c | 3 +- target/ppc/cpu.h | 8 -- target/ppc/excp_helper.c | 165 ++++++++++++++++++++------------ target/ppc/translate_init.c.inc | 2 +- 4 files changed, 108 insertions(+), 70 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 7b5cd3553c..2fbe04a689 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1395,7 +1395,8 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu, return H_P4; } - if (mflags == AIL_RESERVED) { + if (mflags == 1) { + /* AIL=1 is reserved */ return H_UNSUPPORTED_FLAG; } diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 8c18bb0762..be24a501fc 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -2405,14 +2405,6 @@ enum { HMER_XSCOM_STATUS_MASK = PPC_BITMASK(21, 23), }; -/* Alternate Interrupt Location (AIL) */ -enum { - AIL_NONE = 0, - AIL_RESERVED = 1, - AIL_0001_8000 = 2, - AIL_C000_0000_0000_4000 = 3, -}; - /*****************************************************************************/ #define is_isa300(ctx) (!!(ctx->insns_flags2 & PPC2_ISA300)) diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 344af66f66..15b2813253 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -136,25 +136,111 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, return POWERPC_EXCP_RESET; } -static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail) +/* + * AIL - Alternate Interrupt Location, a mode that allows interrupts to be + * taken with the MMU on, and which uses an alternate location (e.g., so the + * kernel/hv can map the vectors there with an effective address). + * + * An interrupt is considered to be taken "with AIL" or "AIL applies" if they + * are delivered in this way. AIL requires the LPCR to be set to enable this + * mode, and then a number of conditions have to be true for AIL to apply. + * + * First of all, SRESET, MCE, and HMI are always delivered without AIL, because + * they specifically want to be in real mode (e.g., the MCE might be signaling + * a SLB multi-hit which requires SLB flush before the MMU can be enabled). + * + * After that, behaviour depends on the current MSR[IR], MSR[DR], MSR[HV], + * whether or not the interrupt changes MSR[HV] from 0 to 1, and the current + * radix mode (LPCR[HR]). + * + * POWER8, POWER9 with LPCR[HR]=0 + * | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL | + * +-----------+-------------+---------+-------------+-----+ + * | a | 00/01/10 | x | x | 0 | + * | a | 11 | 0 | 1 | 0 | + * | a | 11 | 1 | 1 | a | + * | a | 11 | 0 | 0 | a | + * +-------------------------------------------------------+ + * + * POWER9 with LPCR[HR]=1 + * | LPCR[AIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL | + * +-----------+-------------+---------+-------------+-----+ + * | a | 00/01/10 | x | x | 0 | + * | a | 11 | x | x | a | + * +-------------------------------------------------------+ + * + * The difference with POWER9 being that MSR[HV] 0->1 interrupts can be sent to + * the hypervisor in AIL mode if the guest is radix. + */ +static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp, + target_ulong msr, + target_ulong *new_msr, + target_ulong *vector) { - uint64_t offset = 0; +#if defined(TARGET_PPC64) + CPUPPCState *env = &cpu->env; + bool mmu_all_on = ((msr >> MSR_IR) & 1) && ((msr >> MSR_DR) & 1); + bool hv_escalation = !(msr & MSR_HVB) && (*new_msr & MSR_HVB); + int ail = 0; - switch (ail) { - case AIL_NONE: - break; - case AIL_0001_8000: - offset = 0x18000; - break; - case AIL_C000_0000_0000_4000: - offset = 0xc000000000004000ull; - break; - default: - cpu_abort(cs, "Invalid AIL combination %d\n", ail); - break; + if (excp == POWERPC_EXCP_MCHECK || + excp == POWERPC_EXCP_RESET || + excp == POWERPC_EXCP_HV_MAINT) { + /* SRESET, MCE, HMI never apply AIL */ + return; } - return offset; + if (excp_model == POWERPC_EXCP_POWER8 || + excp_model == POWERPC_EXCP_POWER9) { + if (!mmu_all_on) { + /* AIL only works if MSR[IR] and MSR[DR] are both enabled. */ + return; + } + if (hv_escalation && !(env->spr[SPR_LPCR] & LPCR_HR)) { + /* + * AIL does not work if there is a MSR[HV] 0->1 transition and the + * partition is in HPT mode. For radix guests, such interrupts are + * allowed to be delivered to the hypervisor in ail mode. + */ + return; + } + + ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; + if (ail == 0) { + return; + } + if (ail == 1) { + /* AIL=1 is reserved, treat it like AIL=0 */ + return; + } + } else { + /* Other processors do not support AIL */ + return; + } + + /* + * AIL applies, so the new MSR gets IR and DR set, and an offset applied + * to the new IP. + */ + *new_msr |= (1 << MSR_IR) | (1 << MSR_DR); + + if (excp != POWERPC_EXCP_SYSCALL_VECTORED) { + if (ail == 2) { + *vector |= 0x0000000000018000ull; + } else if (ail == 3) { + *vector |= 0xc000000000004000ull; + } + } else { + /* + * scv AIL is a little different. AIL=2 does not change the address, + * only the MSR. AIL=3 replaces the 0x17000 base with 0xc...3000. + */ + if (ail == 3) { + *vector &= ~0x0000000000017000ull; /* Un-apply the base offset */ + *vector |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */ + } + } +#endif } static inline void powerpc_set_excp_state(PowerPCCPU *cpu, @@ -197,7 +283,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; target_ulong msr, new_msr, vector; - int srr0, srr1, asrr0, asrr1, lev = -1, ail; + int srr0, srr1, asrr0, asrr1, lev = -1; bool lpes0; qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx @@ -238,25 +324,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) * * On anything else, we behave as if LPES0 is 1 * (externals don't alter MSR:HV) - * - * AIL is initialized here but can be cleared by - * selected exceptions */ #if defined(TARGET_PPC64) if (excp_model == POWERPC_EXCP_POWER7 || excp_model == POWERPC_EXCP_POWER8 || excp_model == POWERPC_EXCP_POWER9) { lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); - if (excp_model != POWERPC_EXCP_POWER7) { - ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; - } else { - ail = 0; - } } else #endif /* defined(TARGET_PPC64) */ { lpes0 = true; - ail = 0; } /* @@ -315,7 +392,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) */ new_msr |= (target_ulong)MSR_HVB; } - ail = 0; /* machine check exceptions don't have ME set */ new_msr &= ~((target_ulong)1 << MSR_ME); @@ -519,7 +595,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) "exception %d with no HV support\n", excp); } } - ail = 0; break; case POWERPC_EXCP_DSEG: /* Data segment exception */ case POWERPC_EXCP_ISEG: /* Instruction segment exception */ @@ -790,24 +865,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } #endif - /* - * AIL only works if MSR[IR] and MSR[DR] are both enabled. - */ - if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1)) { - ail = 0; - } - - /* - * AIL does not work if there is a MSR[HV] 0->1 transition and the - * partition is in HPT mode. For radix guests, such interrupts are - * allowed to be delivered to the hypervisor in ail mode. - */ - if ((new_msr & MSR_HVB) && !(msr & MSR_HVB)) { - if (!(env->spr[SPR_LPCR] & LPCR_HR)) { - ail = 0; - } - } - vector = env->excp_vectors[excp]; if (vector == (target_ulong)-1ULL) { cpu_abort(cs, "Raised an exception without defined vector %d\n", @@ -848,23 +905,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) /* Save MSR */ env->spr[srr1] = msr; - /* Handle AIL */ - if (ail) { - new_msr |= (1 << MSR_IR) | (1 << MSR_DR); - vector |= ppc_excp_vector_offset(cs, ail); - } - #if defined(TARGET_PPC64) } else { - /* scv AIL is a little different */ - if (ail) { - new_msr |= (1 << MSR_IR) | (1 << MSR_DR); - } - if (ail == AIL_C000_0000_0000_4000) { - vector |= 0xc000000000003000ull; - } else { - vector |= 0x0000000000017000ull; - } vector += lev * 0x20; env->lr = env->nip; @@ -872,6 +914,9 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) #endif } + /* This can update new_msr and vector if AIL applies */ + ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector); + powerpc_set_excp_state(cpu, vector, new_msr); } diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index 42b3a4fd57..65906c7e6d 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -3456,7 +3456,7 @@ static void init_excp_POWER9(CPUPPCState *env) #if !defined(CONFIG_USER_ONLY) env->excp_vectors[POWERPC_EXCP_HVIRT] = 0x00000EA0; - env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00000000; + env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00017000; #endif } From 526cdce771fa27c37b68fd235ff9f1caa0bdd563 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Sat, 1 May 2021 17:24:35 +1000 Subject: [PATCH 0271/3028] target/ppc: Add POWER10 exception model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit POWER10 adds a new bit that modifies interrupt behaviour, LPCR[HAIL], and it removes support for the LPCR[AIL]=0b10 mode. Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater Signed-off-by: Nicholas Piggin Message-Id: <20210501072436.145444-3-npiggin@gmail.com> [dwg: Corrected tab indenting] Signed-off-by: David Gibson --- hw/ppc/spapr_hcall.c | 7 ++++- target/ppc/cpu-qom.h | 2 ++ target/ppc/cpu.h | 5 +-- target/ppc/excp_helper.c | 54 +++++++++++++++++++++++++++++++-- target/ppc/translate.c | 3 +- target/ppc/translate_init.c.inc | 2 +- 6 files changed, 65 insertions(+), 8 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 2fbe04a689..7275d0bba1 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1396,7 +1396,12 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu, } if (mflags == 1) { - /* AIL=1 is reserved */ + /* AIL=1 is reserved in POWER8/POWER9/POWER10 */ + return H_UNSUPPORTED_FLAG; + } + + if (mflags == 2 && (pcc->insns_flags2 & PPC2_ISA310)) { + /* AIL=2 is reserved in POWER10 (ISA v3.1) */ return H_UNSUPPORTED_FLAG; } diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h index 118baf8d41..06b6571bc9 100644 --- a/target/ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h @@ -116,6 +116,8 @@ enum powerpc_excp_t { POWERPC_EXCP_POWER8, /* POWER9 exception model */ POWERPC_EXCP_POWER9, + /* POWER10 exception model */ + POWERPC_EXCP_POWER10, }; /*****************************************************************************/ diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index be24a501fc..8a076fab48 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -354,10 +354,11 @@ typedef struct ppc_v3_pate_t { #define LPCR_PECE_U_SHIFT (63 - 19) #define LPCR_PECE_U_MASK (0x7ull << LPCR_PECE_U_SHIFT) #define LPCR_HVEE PPC_BIT(17) /* Hypervisor Virt Exit Enable */ -#define LPCR_RMLS_SHIFT (63 - 37) +#define LPCR_RMLS_SHIFT (63 - 37) /* RMLS (removed in ISA v3.0) */ #define LPCR_RMLS (0xfull << LPCR_RMLS_SHIFT) +#define LPCR_HAIL PPC_BIT(37) /* ISA v3.1 HV AIL=3 equivalent */ #define LPCR_ILE PPC_BIT(38) -#define LPCR_AIL_SHIFT (63 - 40) /* Alternate interrupt location */ +#define LPCR_AIL_SHIFT (63 - 40) /* Alternate interrupt location */ #define LPCR_AIL (3ull << LPCR_AIL_SHIFT) #define LPCR_UPRT PPC_BIT(41) /* Use Process Table */ #define LPCR_EVIRT PPC_BIT(42) /* Enhanced Virtualisation */ diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 15b2813253..f4f15279eb 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -170,7 +170,27 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp, * +-------------------------------------------------------+ * * The difference with POWER9 being that MSR[HV] 0->1 interrupts can be sent to - * the hypervisor in AIL mode if the guest is radix. + * the hypervisor in AIL mode if the guest is radix. This is good for + * performance but allows the guest to influence the AIL of hypervisor + * interrupts using its MSR, and also the hypervisor must disallow guest + * interrupts (MSR[HV] 0->0) from using AIL if the hypervisor does not want to + * use AIL for its MSR[HV] 0->1 interrupts. + * + * POWER10 addresses those issues with a new LPCR[HAIL] bit that is applied to + * interrupts that begin execution with MSR[HV]=1 (so both MSR[HV] 0->1 and + * MSR[HV] 1->1). + * + * HAIL=1 is equivalent to AIL=3, for interrupts delivered with MSR[HV]=1. + * + * POWER10 behaviour is + * | LPCR[AIL] | LPCR[HAIL] | MSR[IR||DR] | MSR[HV] | new MSR[HV] | AIL | + * +-----------+------------+-------------+---------+-------------+-----+ + * | a | h | 00/01/10 | 0 | 0 | 0 | + * | a | h | 11 | 0 | 0 | a | + * | a | h | x | 0 | 1 | h | + * | a | h | 00/01/10 | 1 | 1 | 0 | + * | a | h | 11 | 1 | 1 | h | + * +--------------------------------------------------------------------+ */ static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp, target_ulong msr, @@ -213,6 +233,32 @@ static inline void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp, /* AIL=1 is reserved, treat it like AIL=0 */ return; } + + } else if (excp_model == POWERPC_EXCP_POWER10) { + if (!mmu_all_on && !hv_escalation) { + /* + * AIL works for HV interrupts even with guest MSR[IR/DR] disabled. + * Guest->guest and HV->HV interrupts do require MMU on. + */ + return; + } + + if (*new_msr & MSR_HVB) { + if (!(env->spr[SPR_LPCR] & LPCR_HAIL)) { + /* HV interrupts depend on LPCR[HAIL] */ + return; + } + ail = 3; /* HAIL=1 gives AIL=3 behaviour for HV interrupts */ + } else { + ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT; + } + if (ail == 0) { + return; + } + if (ail == 1 || ail == 2) { + /* AIL=1 and AIL=2 are reserved, treat them like AIL=0 */ + return; + } } else { /* Other processors do not support AIL */ return; @@ -328,7 +374,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) #if defined(TARGET_PPC64) if (excp_model == POWERPC_EXCP_POWER7 || excp_model == POWERPC_EXCP_POWER8 || - excp_model == POWERPC_EXCP_POWER9) { + excp_model == POWERPC_EXCP_POWER9 || + excp_model == POWERPC_EXCP_POWER10) { lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); } else #endif /* defined(TARGET_PPC64) */ @@ -848,7 +895,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } else if (env->spr[SPR_LPCR] & LPCR_ILE) { new_msr |= (target_ulong)1 << MSR_LE; } - } else if (excp_model == POWERPC_EXCP_POWER9) { + } else if (excp_model == POWERPC_EXCP_POWER9 || + excp_model == POWERPC_EXCP_POWER10) { if (new_msr & MSR_HVB) { if (env->spr[SPR_HID0] & HID0_POWER9_HILE) { new_msr |= (target_ulong)1 << MSR_LE; diff --git a/target/ppc/translate.c b/target/ppc/translate.c index a7c568ca9c..a6381208a5 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -7731,7 +7731,8 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags) #if defined(TARGET_PPC64) if (env->excp_model == POWERPC_EXCP_POWER7 || env->excp_model == POWERPC_EXCP_POWER8 || - env->excp_model == POWERPC_EXCP_POWER9) { + env->excp_model == POWERPC_EXCP_POWER9 || + env->excp_model == POWERPC_EXCP_POWER10) { qemu_fprintf(f, "HSRR0 " TARGET_FMT_lx " HSRR1 " TARGET_FMT_lx "\n", env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); } diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index 65906c7e6d..f92656b2f2 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -9316,7 +9316,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data) pcc->radix_page_info = &POWER10_radix_page_info; pcc->lrg_decr_bits = 56; #endif - pcc->excp_model = POWERPC_EXCP_POWER9; + pcc->excp_model = POWERPC_EXCP_POWER10; pcc->bus_model = PPC_FLAGS_INPUT_POWER9; pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | From 61135639821566fe347332e8a01812df2fdd0237 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 30 Apr 2021 19:29:22 -0700 Subject: [PATCH 0272/3028] target/ppc: Clean up _spr_register et al Introduce 3 helper macros to elide arguments that we cannot supply. This reduces the repetition required to get the job done. Signed-off-by: Richard Henderson Message-Id: <20210501022923.1179736-2-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/translate_init.c.inc | 154 +++++++++++++++----------------- 1 file changed, 74 insertions(+), 80 deletions(-) diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index f92656b2f2..5cee94f16d 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -720,104 +720,98 @@ static inline void vscr_init(CPUPPCState *env, uint32_t val) helper_mtvscr(env, val); } -#ifdef CONFIG_USER_ONLY -#define spr_register_kvm(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, one_reg_id, initial_value) \ - _spr_register(env, num, name, uea_read, uea_write, initial_value) -#define spr_register_kvm_hv(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, hea_read, hea_write, \ - one_reg_id, initial_value) \ - _spr_register(env, num, name, uea_read, uea_write, initial_value) +/** + * _spr_register + * + * Register an SPR with all the callbacks required for tcg, + * and the ID number for KVM. + * + * The reason for the conditional compilation is that the tcg functions + * may be compiled out, and the system kvm header may not be available + * for supplying the ID numbers. This is ugly, but the best we can do. + */ + +#ifdef CONFIG_TCG +# define USR_ARG(X) X, +# ifdef CONFIG_USER_ONLY +# define SYS_ARG(X) +# else +# define SYS_ARG(X) X, +# endif #else -#if !defined(CONFIG_KVM) -#define spr_register_kvm(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, one_reg_id, initial_value) \ - _spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, oea_read, oea_write, initial_value) -#define spr_register_kvm_hv(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, hea_read, hea_write, \ - one_reg_id, initial_value) \ - _spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, hea_read, hea_write, initial_value) +# define USR_ARG(X) +# define SYS_ARG(X) +#endif +#ifdef CONFIG_KVM +# define KVM_ARG(X) X, #else -#define spr_register_kvm(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, one_reg_id, initial_value) \ - _spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, oea_read, oea_write, \ - one_reg_id, initial_value) -#define spr_register_kvm_hv(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, hea_read, hea_write, \ - one_reg_id, initial_value) \ - _spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, hea_read, hea_write, \ - one_reg_id, initial_value) -#endif +# define KVM_ARG(X) #endif -#define spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, initial_value) \ - spr_register_kvm(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, 0, initial_value) +typedef void spr_callback(DisasContext *, int, int); -#define spr_register_hv(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, hea_read, hea_write, \ - initial_value) \ - spr_register_kvm_hv(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, hea_read, hea_write, \ - 0, initial_value) - -static inline void _spr_register(CPUPPCState *env, int num, - const char *name, - void (*uea_read)(DisasContext *ctx, - int gprn, int sprn), - void (*uea_write)(DisasContext *ctx, - int sprn, int gprn), -#if !defined(CONFIG_USER_ONLY) - - void (*oea_read)(DisasContext *ctx, - int gprn, int sprn), - void (*oea_write)(DisasContext *ctx, - int sprn, int gprn), - void (*hea_read)(DisasContext *opaque, - int gprn, int sprn), - void (*hea_write)(DisasContext *opaque, - int sprn, int gprn), -#endif -#if defined(CONFIG_KVM) - uint64_t one_reg_id, -#endif - target_ulong initial_value) +static void _spr_register(CPUPPCState *env, int num, const char *name, + USR_ARG(spr_callback *uea_read) + USR_ARG(spr_callback *uea_write) + SYS_ARG(spr_callback *oea_read) + SYS_ARG(spr_callback *oea_write) + SYS_ARG(spr_callback *hea_read) + SYS_ARG(spr_callback *hea_write) + KVM_ARG(uint64_t one_reg_id) + target_ulong initial_value) { - ppc_spr_t *spr; + ppc_spr_t *spr = &env->spr_cb[num]; + + /* No SPR should be registered twice. */ + assert(spr->name == NULL); + assert(name != NULL); - spr = &env->spr_cb[num]; - if (spr->name != NULL || env->spr[num] != 0x00000000 || -#if !defined(CONFIG_USER_ONLY) - spr->oea_read != NULL || spr->oea_write != NULL || -#endif - spr->uea_read != NULL || spr->uea_write != NULL) { - printf("Error: Trying to register SPR %d (%03x) twice !\n", num, num); - exit(1); - } -#if defined(PPC_DEBUG_SPR) - printf("*** register spr %d (%03x) %s val " TARGET_FMT_lx "\n", num, num, - name, initial_value); -#endif spr->name = name; + spr->default_value = initial_value; + env->spr[num] = initial_value; + +#ifdef CONFIG_TCG spr->uea_read = uea_read; spr->uea_write = uea_write; -#if !defined(CONFIG_USER_ONLY) +# ifndef CONFIG_USER_ONLY spr->oea_read = oea_read; spr->oea_write = oea_write; spr->hea_read = hea_read; spr->hea_write = hea_write; +# endif #endif -#if defined(CONFIG_KVM) - spr->one_reg_id = one_reg_id, +#ifdef CONFIG_KVM + spr->one_reg_id = one_reg_id; #endif - env->spr[num] = spr->default_value = initial_value; } +/* spr_register_kvm_hv passes all required arguments. */ +#define spr_register_kvm_hv(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + one_reg_id, initial_value) \ + _spr_register(env, num, name, \ + USR_ARG(uea_read) USR_ARG(uea_write) \ + SYS_ARG(oea_read) SYS_ARG(oea_write) \ + SYS_ARG(hea_read) SYS_ARG(hea_write) \ + KVM_ARG(one_reg_id) initial_value) + +/* spr_register_kvm duplicates the oea callbacks to the hea callbacks. */ +#define spr_register_kvm(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, one_reg_id, ival) \ + spr_register_kvm_hv(env, num, name, uea_read, uea_write, oea_read, \ + oea_write, oea_read, oea_write, one_reg_id, ival) + +/* spr_register_hv and spr_register are similar, except there is no kvm id. */ +#define spr_register_hv(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, ival) \ + spr_register_kvm_hv(env, num, name, uea_read, uea_write, oea_read, \ + oea_write, hea_read, hea_write, 0, ival) + +#define spr_register(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, ival) \ + spr_register_kvm(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, 0, ival) + /* Generic PowerPC SPRs */ static void gen_spr_generic(CPUPPCState *env) { From 72369f5c959bfdade757d89248b260bc6c648130 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 30 Apr 2021 19:29:23 -0700 Subject: [PATCH 0273/3028] target/ppc: Reduce the size of ppc_spr_t We elide values when registering sprs, we might as well save space in the array as well. Signed-off-by: Richard Henderson Message-Id: <20210501022923.1179736-3-richard.henderson@linaro.org> Signed-off-by: David Gibson --- target/ppc/cpu.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 8a076fab48..733a2168c4 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -192,17 +192,21 @@ typedef struct ppc_hash_pte64 ppc_hash_pte64_t; /* SPR access micro-ops generations callbacks */ struct ppc_spr_t { + const char *name; + target_ulong default_value; +#ifndef CONFIG_USER_ONLY + unsigned int gdb_id; +#endif +#ifdef CONFIG_TCG void (*uea_read)(DisasContext *ctx, int gpr_num, int spr_num); void (*uea_write)(DisasContext *ctx, int spr_num, int gpr_num); -#if !defined(CONFIG_USER_ONLY) +# ifndef CONFIG_USER_ONLY void (*oea_read)(DisasContext *ctx, int gpr_num, int spr_num); void (*oea_write)(DisasContext *ctx, int spr_num, int gpr_num); void (*hea_read)(DisasContext *ctx, int gpr_num, int spr_num); void (*hea_write)(DisasContext *ctx, int spr_num, int gpr_num); - unsigned int gdb_id; +# endif #endif - const char *name; - target_ulong default_value; #ifdef CONFIG_KVM /* * We (ab)use the fact that all the SPRs will have ids for the From f350982f5e1715875e547f639baea8c1c9e60bba Mon Sep 17 00:00:00 2001 From: "Bruno Larsen (billionai)" Date: Fri, 30 Apr 2021 16:35:31 -0300 Subject: [PATCH 0274/3028] target/ppc: removed VSCR from SPR registration Since vscr is not an spr, its initialization was removed from the spr registration functions, and moved to the relevant init_procs. We may look into adding vscr to the reset path instead of the init path (as suggested by David Gibson), but this looked like a good enough solution for now. Signed-off-by: Bruno Larsen (billionai) Message-Id: <20210430193533.82136-6-bruno.larsen@eldorado.org.br> Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- target/ppc/translate_init.c.inc | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc index 5cee94f16d..66e6a4a746 100644 --- a/target/ppc/translate_init.c.inc +++ b/target/ppc/translate_init.c.inc @@ -1693,8 +1693,6 @@ static void gen_spr_74xx(CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, spr_access_nop, 0x00000000); - /* Not strictly an SPR */ - vscr_init(env, 0x00010000); } static void gen_l3_ctrl(CPUPPCState *env) @@ -6618,6 +6616,7 @@ static void init_proc_7400(CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + vscr_init(env, 0x00010000); /* XXX : not implemented */ spr_register(env, SPR_UBAMR, "UBAMR", &spr_read_ureg, SPR_NOACCESS, @@ -6697,6 +6696,7 @@ static void init_proc_7410(CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + vscr_init(env, 0x00010000); /* XXX : not implemented */ spr_register(env, SPR_UBAMR, "UBAMR", &spr_read_ureg, SPR_NOACCESS, @@ -6782,6 +6782,7 @@ static void init_proc_7440(CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + vscr_init(env, 0x00010000); /* XXX : not implemented */ spr_register(env, SPR_UBAMR, "UBAMR", &spr_read_ureg, SPR_NOACCESS, @@ -6890,6 +6891,7 @@ static void init_proc_7450(CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + vscr_init(env, 0x00010000); /* Level 3 cache control */ gen_l3_ctrl(env); /* L3ITCR1 */ @@ -7024,6 +7026,7 @@ static void init_proc_7445(CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + vscr_init(env, 0x00010000); /* LDSTCR */ /* XXX : not implemented */ spr_register(env, SPR_LDSTCR, "LDSTCR", @@ -7161,6 +7164,7 @@ static void init_proc_7455(CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + vscr_init(env, 0x00010000); /* Level 3 cache control */ gen_l3_ctrl(env); /* LDSTCR */ @@ -7300,6 +7304,7 @@ static void init_proc_7457(CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + vscr_init(env, 0x00010000); /* Level 3 cache control */ gen_l3_ctrl(env); /* L3ITCR1 */ @@ -7463,6 +7468,7 @@ static void init_proc_e600(CPUPPCState *env) gen_tbl(env); /* 74xx specific SPR */ gen_spr_74xx(env); + vscr_init(env, 0x00010000); /* XXX : not implemented */ spr_register(env, SPR_UBAMR, "UBAMR", &spr_read_ureg, SPR_NOACCESS, @@ -7713,11 +7719,6 @@ static void gen_spr_book3s_altivec(CPUPPCState *env) &spr_read_generic, &spr_write_generic, KVM_REG_PPC_VRSAVE, 0x00000000); - /* - * Can't find information on what this should be on reset. This - * value is the one used by 74xx processors. - */ - vscr_init(env, 0x00010000); } static void gen_spr_book3s_dbg(CPUPPCState *env) @@ -8415,6 +8416,11 @@ static void init_proc_book3s_common(CPUPPCState *env) gen_spr_book3s_pmu_sup(env); gen_spr_book3s_pmu_user(env); gen_spr_book3s_ctrl(env); + /* + * Can't find information on what this should be on reset. This + * value is the one used by 74xx processors. + */ + vscr_init(env, 0x00010000); } static void init_proc_970(CPUPPCState *env) From b2df46fd80d9cebc8d9cd3690ec425273c55b434 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 May 2021 16:18:47 +0100 Subject: [PATCH 0275/3028] hw/intc/spapr_xive: Use device_cold_reset() instead of device_legacy_reset() The h_int_reset() function resets the XIVE interrupt controller via device_legacy_reset(). We know that the interrupt controller does not have a qbus of its own, so the new device_cold_reset() function (which resets both the device and its child buses) is equivalent here to device_legacy_reset() and we can just switch to the new API. Signed-off-by: Peter Maydell Message-Id: <20210503151849.8766-2-peter.maydell@linaro.org> Signed-off-by: David Gibson --- hw/intc/spapr_xive.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 801bc19341..89cfa018f5 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -1798,7 +1798,7 @@ static target_ulong h_int_reset(PowerPCCPU *cpu, return H_PARAMETER; } - device_legacy_reset(DEVICE(xive)); + device_cold_reset(DEVICE(xive)); if (spapr_xive_in_kernel(xive)) { Error *local_err = NULL; From 3e1c8ba98844254cbf2e8134697c3f20faf461d4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 May 2021 16:18:48 +0100 Subject: [PATCH 0276/3028] hw/ppc/spapr_vio: Reset TCE table object with device_cold_reset() The spapr_vio_quiesce_one() function resets the TCE table object (TYPE_SPAPR_TCE_TABLE) via device_legacy_reset(). We know that objects of that type do not have a qbus of their own, so the new device_cold_reset() function (which resets both the device and its child buses) is equivalent here to device_legacy_reset() and we can just switch to the new API. Signed-off-by: Peter Maydell Message-Id: <20210503151849.8766-3-peter.maydell@linaro.org> Signed-off-by: David Gibson --- hw/ppc/spapr_vio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index ef06e0362c..b59452bcd6 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -310,7 +310,7 @@ int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq) static void spapr_vio_quiesce_one(SpaprVioDevice *dev) { if (dev->tcet) { - device_legacy_reset(DEVICE(dev->tcet)); + device_cold_reset(DEVICE(dev->tcet)); } free_crq(dev); } From 4bb32cd7b1e42c46d274b727c8be8e45b4df3814 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 May 2021 16:18:49 +0100 Subject: [PATCH 0277/3028] hw/ppc/pnv_psi: Use device_cold_reset() instead of device_legacy_reset() The pnv_psi.c code uses device_legacy_reset() for two purposes: * to reset itself from its qemu_register_reset() handler * to reset a XiveSource object it has Neither it nor the XiveSource have any qbuses, so the new device_cold_reset() function (which resets both the device and its child buses) is equivalent here to device_legacy_reset() and we can just switch to the new API. Signed-off-by: Peter Maydell Message-Id: <20210503151849.8766-4-peter.maydell@linaro.org> Signed-off-by: David Gibson --- hw/ppc/pnv_psi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 3e868c8c8d..292b373f93 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -466,7 +466,7 @@ static void pnv_psi_reset(DeviceState *dev) static void pnv_psi_reset_handler(void *dev) { - device_legacy_reset(DEVICE(dev)); + device_cold_reset(DEVICE(dev)); } static void pnv_psi_realize(DeviceState *dev, Error **errp) @@ -710,7 +710,7 @@ static void pnv_psi_p9_mmio_write(void *opaque, hwaddr addr, break; case PSIHB9_INTERRUPT_CONTROL: if (val & PSIHB9_IRQ_RESET) { - device_legacy_reset(DEVICE(&psi9->source)); + device_cold_reset(DEVICE(&psi9->source)); } psi->regs[reg] = val; break; From 1081607bfab94a0b6149c4a2195737107aed265f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 25 Apr 2021 00:41:09 +0200 Subject: [PATCH 0278/3028] hw/usb/host-stub: Remove unused header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210424224110.3442424-2-f4bug@amsat.org> Signed-off-by: Gerd Hoffmann --- hw/usb/host-stub.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/usb/host-stub.c b/hw/usb/host-stub.c index 538ed29684..80809ceba5 100644 --- a/hw/usb/host-stub.c +++ b/hw/usb/host-stub.c @@ -31,7 +31,6 @@ */ #include "qemu/osdep.h" -#include "ui/console.h" #include "hw/usb.h" #include "monitor/monitor.h" From 9c3c834bdda5ca6d58c0e61508737683d12968b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 25 Apr 2021 00:41:10 +0200 Subject: [PATCH 0279/3028] hw/usb: Do not build USB subsystem if not required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the Kconfig 'USB' value is not selected, it is pointless to build the USB core components. Add a stub for the HMP commands and usbdevice_create() which is called by usb_device_add in softmmu/vl.c. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210424224110.3442424-3-f4bug@amsat.org> Signed-off-by: Gerd Hoffmann --- MAINTAINERS | 1 + hw/usb/meson.build | 9 +++------ stubs/meson.build | 1 + stubs/usb-dev-stub.c | 25 +++++++++++++++++++++++++ 4 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 stubs/usb-dev-stub.c diff --git a/MAINTAINERS b/MAINTAINERS index 4c05ff8bba..6f7e5db3b1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1804,6 +1804,7 @@ USB M: Gerd Hoffmann S: Maintained F: hw/usb/* +F: stubs/usb-dev-stub.c F: tests/qtest/usb-*-test.c F: docs/usb2.txt F: docs/usb-storage.txt diff --git a/hw/usb/meson.build b/hw/usb/meson.build index fb7a74e73a..f357270d0b 100644 --- a/hw/usb/meson.build +++ b/hw/usb/meson.build @@ -1,17 +1,14 @@ hw_usb_modules = {} # usb subsystem core -softmmu_ss.add(files( +softmmu_ss.add(when: 'CONFIG_USB', if_true: files( 'bus.c', 'combined-packet.c', 'core.c', - 'pcap.c', - 'libhw.c' -)) - -softmmu_ss.add(when: 'CONFIG_USB', if_true: files( 'desc.c', 'desc-msos.c', + 'libhw.c', + 'pcap.c', )) # usb host adapters diff --git a/stubs/meson.build b/stubs/meson.build index be6f6d609e..3faef16892 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -50,6 +50,7 @@ if have_block endif if have_system stub_ss.add(files('semihost.c')) + stub_ss.add(files('usb-dev-stub.c')) stub_ss.add(files('xen-hw-stub.c')) else stub_ss.add(files('qdev.c')) diff --git a/stubs/usb-dev-stub.c b/stubs/usb-dev-stub.c new file mode 100644 index 0000000000..b1adeeb454 --- /dev/null +++ b/stubs/usb-dev-stub.c @@ -0,0 +1,25 @@ +/* + * QEMU USB device emulation stubs + * + * Copyright (C) 2021 Philippe Mathieu-Daudé + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "monitor/monitor.h" +#include "hw/usb.h" + +USBDevice *usbdevice_create(const char *driver) +{ + error_report("Support for USB devices not built-in"); + + return NULL; +} + +void hmp_info_usb(Monitor *mon, const QDict *qdict) +{ + monitor_printf(mon, "Support for USB devices not built-in\n"); +} From 3f67e2e7f135b8be4117f3c2960e78d894feaa03 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 3 May 2021 15:29:11 +0200 Subject: [PATCH 0280/3028] usb/hid: avoid dynamic stack allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use autofree heap allocation instead. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20210503132915.2335822-2-kraxel@redhat.com> --- hw/usb/dev-hid.c | 2 +- hw/usb/dev-wacom.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index fc39bab79f..1c7ae97c30 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -656,7 +656,7 @@ static void usb_hid_handle_data(USBDevice *dev, USBPacket *p) { USBHIDState *us = USB_HID(dev); HIDState *hs = &us->hid; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); int len = 0; switch (p->pid) { diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index b595048635..ed687bc9f1 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -301,7 +301,7 @@ static void usb_wacom_handle_control(USBDevice *dev, USBPacket *p, static void usb_wacom_handle_data(USBDevice *dev, USBPacket *p) { USBWacomState *s = (USBWacomState *) dev; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); int len = 0; switch (p->pid) { From 7ec54f9eb62b5d177e30eb8b1cad795a5f8d8986 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 3 May 2021 15:29:12 +0200 Subject: [PATCH 0281/3028] usb/redir: avoid dynamic stack allocation (CVE-2021-3527) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use autofree heap allocation instead. Fixes: 4f4321c11ff ("usb: use iovecs in USBPacket") Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Gerd Hoffmann Tested-by: Philippe Mathieu-Daudé Message-Id: <20210503132915.2335822-3-kraxel@redhat.com> --- hw/usb/redirect.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 17f06f3417..6a75b0dc4a 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -620,7 +620,7 @@ static void usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, .endpoint = ep, .length = p->iov.size }; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); /* No id, we look at the ep when receiving a status back */ usb_packet_copy(p, buf, p->iov.size); usbredirparser_send_iso_packet(dev->parser, 0, &iso_packet, @@ -818,7 +818,7 @@ static void usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, usbredirparser_send_bulk_packet(dev->parser, p->id, &bulk_packet, NULL, 0); } else { - uint8_t buf[size]; + g_autofree uint8_t *buf = g_malloc(size); usb_packet_copy(p, buf, size); usbredir_log_data(dev, "bulk data out:", buf, size); usbredirparser_send_bulk_packet(dev->parser, p->id, @@ -923,7 +923,7 @@ static void usbredir_handle_interrupt_out_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { struct usb_redir_interrupt_packet_header interrupt_packet; - uint8_t buf[p->iov.size]; + g_autofree uint8_t *buf = g_malloc(p->iov.size); DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); From 06aa50c06c6392084244f8169d34b8e2d9c43ef2 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 3 May 2021 15:29:13 +0200 Subject: [PATCH 0282/3028] usb/mtp: avoid dynamic stack allocation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use autofree heap allocation instead. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-Id: <20210503132915.2335822-4-kraxel@redhat.com> --- hw/usb/dev-mtp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index bbb8274344..2a895a73b0 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -907,7 +907,8 @@ static MTPData *usb_mtp_get_object_handles(MTPState *s, MTPControl *c, MTPObject *o) { MTPData *d = usb_mtp_data_alloc(c); - uint32_t i = 0, handles[o->nchildren]; + uint32_t i = 0; + g_autofree uint32_t *handles = g_new(uint32_t, o->nchildren); MTPObject *iter; trace_usb_mtp_op_get_object_handles(s->dev.addr, o->handle, o->path); From dab346986e1e91dfd28671e9fb97970a9eb15fca Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 Jan 2021 18:12:17 +0300 Subject: [PATCH 0283/3028] simplebench: bench_one(): add slow_limit argument Sometimes one of cells in a testing table runs too slow. And we really don't want to wait so long. Limit number of runs in this case. Signed-off-by: Vladimir Sementsov-Ogievskiy --- scripts/simplebench/simplebench.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/simplebench/simplebench.py b/scripts/simplebench/simplebench.py index f61513af90..0a3035732c 100644 --- a/scripts/simplebench/simplebench.py +++ b/scripts/simplebench/simplebench.py @@ -19,9 +19,11 @@ # import statistics +import time -def bench_one(test_func, test_env, test_case, count=5, initial_run=True): +def bench_one(test_func, test_env, test_case, count=5, initial_run=True, + slow_limit=100): """Benchmark one test-case test_func -- benchmarking function with prototype @@ -36,6 +38,8 @@ def bench_one(test_func, test_env, test_case, count=5, initial_run=True): test_case -- test case - opaque second argument for test_func count -- how many times to call test_func, to calculate average initial_run -- do initial run of test_func, which don't get into result + slow_limit -- stop at slow run (that exceedes the slow_limit by seconds). + (initial run is not measured) Returns dict with the following fields: 'runs': list of test_func results @@ -53,11 +57,19 @@ def bench_one(test_func, test_env, test_case, count=5, initial_run=True): runs = [] for i in range(count): + t = time.time() + print(' #run {}'.format(i+1)) res = test_func(test_env, test_case) print(' ', res) runs.append(res) + if time.time() - t > slow_limit: + print(' - run is too slow, stop here') + break + + count = len(runs) + result = {'runs': runs} succeeded = [r for r in runs if ('seconds' in r or 'iops' in r)] From 27eacb390e289edde4854f8bdface596572b0d8d Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 Jan 2021 18:13:48 +0300 Subject: [PATCH 0284/3028] simplebench: bench_one(): support count=1 statistics.stdev raises if sequence length is less than two. Support that case by hand. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow --- scripts/simplebench/simplebench.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/simplebench/simplebench.py b/scripts/simplebench/simplebench.py index 0a3035732c..27bc4d4715 100644 --- a/scripts/simplebench/simplebench.py +++ b/scripts/simplebench/simplebench.py @@ -83,7 +83,10 @@ def bench_one(test_func, test_env, test_case, count=5, initial_run=True, dim = 'seconds' result['dimension'] = dim result['average'] = statistics.mean(r[dim] for r in succeeded) - result['stdev'] = statistics.stdev(r[dim] for r in succeeded) + if len(succeeded) == 1: + result['stdev'] = 0 + else: + result['stdev'] = statistics.stdev(r[dim] for r in succeeded) if len(succeeded) < count: result['n-failed'] = count - len(succeeded) From af2ac8514f57fc690849369ad1d6f9d65b1e9437 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 28 Jan 2021 13:22:40 +0300 Subject: [PATCH 0285/3028] simplebench/bench-backup: add --compressed option Allow bench compressed backup. Signed-off-by: Vladimir Sementsov-Ogievskiy --- scripts/simplebench/bench-backup.py | 55 ++++++++++++++++++-------- scripts/simplebench/bench_block_job.py | 23 +++++++++++ 2 files changed, 62 insertions(+), 16 deletions(-) diff --git a/scripts/simplebench/bench-backup.py b/scripts/simplebench/bench-backup.py index 33a1ecfefa..72eae85bb1 100755 --- a/scripts/simplebench/bench-backup.py +++ b/scripts/simplebench/bench-backup.py @@ -23,7 +23,7 @@ import json import simplebench from results_to_text import results_to_text -from bench_block_job import bench_block_copy, drv_file, drv_nbd +from bench_block_job import bench_block_copy, drv_file, drv_nbd, drv_qcow2 def bench_func(env, case): @@ -37,29 +37,41 @@ def bench_func(env, case): def bench(args): test_cases = [] - sources = {} - targets = {} - for d in args.dir: - label, path = d.split(':') # paths with colon not supported - sources[label] = drv_file(path + '/test-source') - targets[label] = drv_file(path + '/test-target') + # paths with colon not supported, so we just split by ':' + dirs = dict(d.split(':') for d in args.dir) + nbd_drv = None if args.nbd: nbd = args.nbd.split(':') host = nbd[0] port = '10809' if len(nbd) == 1 else nbd[1] - drv = drv_nbd(host, port) - sources['nbd'] = drv - targets['nbd'] = drv + nbd_drv = drv_nbd(host, port) for t in args.test: src, dst = t.split(':') - test_cases.append({ - 'id': t, - 'source': sources[src], - 'target': targets[dst] - }) + if src == 'nbd' and dst == 'nbd': + raise ValueError("Can't use 'nbd' label for both src and dst") + + if (src == 'nbd' or dst == 'nbd') and not nbd_drv: + raise ValueError("'nbd' label used but --nbd is not given") + + if src == 'nbd': + source = nbd_drv + else: + source = drv_file(dirs[src] + '/test-source') + + if dst == 'nbd': + test_cases.append({'id': t, 'source': source, 'target': nbd_drv}) + continue + + fname = dirs[dst] + '/test-target' + if args.compressed: + fname += '.qcow2' + target = drv_file(fname) + if args.compressed: + target = drv_qcow2(target) + test_cases.append({'id': t, 'source': source, 'target': target}) binaries = [] # list of (

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 From bdbe824b7e92bd42205aa0ccb58a70c1e9cb9564 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Apr 2021 17:08:17 +0200 Subject: [PATCH 0337/3028] qemu-edid: use qemu_edid_size() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So we only write out that part of the edid blob which has been filled with data. Also use a larger buffer for the blob. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-id: 20210427150824.638359-1-kraxel@redhat.com Message-Id: <20210427150824.638359-2-kraxel@redhat.com> --- qemu-edid.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qemu-edid.c b/qemu-edid.c index 1cd6a95172..c3a9fba10d 100644 --- a/qemu-edid.c +++ b/qemu-edid.c @@ -41,7 +41,8 @@ static void usage(FILE *out) int main(int argc, char *argv[]) { FILE *outfile = NULL; - uint8_t blob[256]; + uint8_t blob[512]; + size_t size; uint32_t dpi = 100; int rc; @@ -119,7 +120,8 @@ int main(int argc, char *argv[]) memset(blob, 0, sizeof(blob)); qemu_edid_generate(blob, sizeof(blob), &info); - fwrite(blob, sizeof(blob), 1, outfile); + size = qemu_edid_size(blob); + fwrite(blob, size, 1, outfile); fflush(outfile); exit(0); From ed7f17a640853f3a13f48ca9d68f4db790a88f08 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Apr 2021 17:08:18 +0200 Subject: [PATCH 0338/3028] edid: edid_desc_next MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add helper function to find the next free desc block. Needed when we start to use the dta descriptor entries. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-id: 20210427150824.638359-1-kraxel@redhat.com Message-Id: <20210427150824.638359-3-kraxel@redhat.com> --- hw/display/edid-generate.c | 41 ++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index a1bea9a3aa..ae34999f9e 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -144,6 +144,17 @@ static void edid_checksum(uint8_t *edid) } } +static uint8_t *edid_desc_next(uint8_t *edid, uint8_t *dta, uint8_t *desc) +{ + if (desc == NULL) { + return NULL; + } + if (desc + 18 + 18 < edid + 127) { + return desc + 18; + } + return NULL; +} + static void edid_desc_type(uint8_t *desc, uint8_t type) { desc[0] = 0; @@ -300,7 +311,7 @@ uint32_t qemu_edid_dpi_to_mm(uint32_t dpi, uint32_t res) void qemu_edid_generate(uint8_t *edid, size_t size, qemu_edid_info *info) { - uint32_t desc = 54; + uint8_t *desc = edid + 54; uint8_t *xtra3 = NULL; uint8_t *dta = NULL; uint32_t width_mm, height_mm; @@ -401,32 +412,32 @@ void qemu_edid_generate(uint8_t *edid, size_t size, /* =============== descriptor blocks =============== */ - edid_desc_timing(edid + desc, info->prefx, info->prefy, + edid_desc_timing(desc, info->prefx, info->prefy, width_mm, height_mm); - desc += 18; + desc = edid_desc_next(edid, dta, desc); - edid_desc_ranges(edid + desc); - desc += 18; + edid_desc_ranges(desc); + desc = edid_desc_next(edid, dta, desc); if (info->name) { - edid_desc_text(edid + desc, 0xfc, info->name); - desc += 18; + edid_desc_text(desc, 0xfc, info->name); + desc = edid_desc_next(edid, dta, desc); } if (info->serial) { - edid_desc_text(edid + desc, 0xff, info->serial); - desc += 18; + edid_desc_text(desc, 0xff, info->serial); + desc = edid_desc_next(edid, dta, desc); } - if (desc < 126) { - xtra3 = edid + desc; + if (desc) { + xtra3 = desc; edid_desc_xtra3_std(xtra3); - desc += 18; + desc = edid_desc_next(edid, dta, desc); } - while (desc < 126) { - edid_desc_dummy(edid + desc); - desc += 18; + while (desc) { + edid_desc_dummy(desc); + desc = edid_desc_next(edid, dta, desc); } /* =============== finish up =============== */ From ec70aec8dca96fba10eba432b2adc22f49b87750 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Apr 2021 17:08:19 +0200 Subject: [PATCH 0339/3028] edid: move xtra3 descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize the "Established timings III" block earlier. Also move up edid_fill_modes(). That'll make sure the offset for the additional descriptors in the dta block don't move any more, which in turn makes it easier to actually use them. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-id: 20210427150824.638359-1-kraxel@redhat.com Message-Id: <20210427150824.638359-4-kraxel@redhat.com> --- hw/display/edid-generate.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index ae34999f9e..25f790c7bd 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -416,25 +416,28 @@ void qemu_edid_generate(uint8_t *edid, size_t size, width_mm, height_mm); desc = edid_desc_next(edid, dta, desc); + xtra3 = desc; + edid_desc_xtra3_std(xtra3); + desc = edid_desc_next(edid, dta, desc); + edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy); + /* + * dta video data block is finished at thus point, + * so dta descriptor offsets don't move any more. + */ + edid_desc_ranges(desc); desc = edid_desc_next(edid, dta, desc); - if (info->name) { + if (desc && info->name) { edid_desc_text(desc, 0xfc, info->name); desc = edid_desc_next(edid, dta, desc); } - if (info->serial) { + if (desc && info->serial) { edid_desc_text(desc, 0xff, info->serial); desc = edid_desc_next(edid, dta, desc); } - if (desc) { - xtra3 = desc; - edid_desc_xtra3_std(xtra3); - desc = edid_desc_next(edid, dta, desc); - } - while (desc) { edid_desc_dummy(desc); desc = edid_desc_next(edid, dta, desc); @@ -442,7 +445,6 @@ void qemu_edid_generate(uint8_t *edid, size_t size, /* =============== finish up =============== */ - edid_fill_modes(edid, xtra3, dta, info->maxx, info->maxy); edid_checksum(edid); if (dta) { edid_checksum(dta); From 4f9e268637f334d639a3d3ab5f1f06dfe6e93bc0 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 27 Apr 2021 17:08:20 +0200 Subject: [PATCH 0340/3028] edid: use dta extension block descriptors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the 4 descriptors in the base edid block are filled, jump to the dta extension block. This allows for more than four descriptors. Happens for example when generating an edid blob with a serial number (qemu-edid -s $serial). Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-id: 20210427150824.638359-1-kraxel@redhat.com Message-Id: <20210427150824.638359-5-kraxel@redhat.com> --- hw/display/edid-generate.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index 25f790c7bd..42a130f0ff 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -152,6 +152,14 @@ static uint8_t *edid_desc_next(uint8_t *edid, uint8_t *dta, uint8_t *desc) if (desc + 18 + 18 < edid + 127) { return desc + 18; } + if (dta) { + if (desc < edid + 127) { + return dta + dta[2]; + } + if (desc + 18 + 18 < dta + 127) { + return desc + 18; + } + } return NULL; } From fce39fa737afba09811efeceee973e3039d926c4 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 27 Apr 2021 17:08:21 +0200 Subject: [PATCH 0341/3028] edid: Make refresh rate configurable Signed-off-by: Akihiko Odaki Signed-off-by: Gerd Hoffmann Message-id: 20210427150824.638359-1-kraxel@redhat.com Message-Id: <20210427150824.638359-6-kraxel@redhat.com> --- hw/display/edid-generate.c | 9 +++++---- include/hw/display/edid.h | 12 +++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index 42a130f0ff..8662218822 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -223,7 +223,7 @@ static void edid_desc_dummy(uint8_t *desc) edid_desc_type(desc, 0x10); } -static void edid_desc_timing(uint8_t *desc, +static void edid_desc_timing(uint8_t *desc, uint32_t refresh_rate, uint32_t xres, uint32_t yres, uint32_t xmm, uint32_t ymm) { @@ -236,9 +236,9 @@ static void edid_desc_timing(uint8_t *desc, uint32_t ysync = yres * 5 / 1000; uint32_t yblank = yres * 35 / 1000; - uint32_t clock = 75 * (xres + xblank) * (yres + yblank); + uint64_t clock = (uint64_t)refresh_rate * (xres + xblank) * (yres + yblank); - stl_le_p(desc, clock / 10000); + stl_le_p(desc, clock / 10000000); desc[2] = xres & 0xff; desc[3] = xblank & 0xff; @@ -323,6 +323,7 @@ void qemu_edid_generate(uint8_t *edid, size_t size, uint8_t *xtra3 = NULL; uint8_t *dta = NULL; uint32_t width_mm, height_mm; + uint32_t refresh_rate = info->refresh_rate ? info->refresh_rate : 75000; uint32_t dpi = 100; /* if no width_mm/height_mm */ /* =============== set defaults =============== */ @@ -420,7 +421,7 @@ void qemu_edid_generate(uint8_t *edid, size_t size, /* =============== descriptor blocks =============== */ - edid_desc_timing(desc, info->prefx, info->prefy, + edid_desc_timing(desc, refresh_rate, info->prefx, info->prefy, width_mm, height_mm); desc = edid_desc_next(edid, dta, desc); diff --git a/include/hw/display/edid.h b/include/hw/display/edid.h index 1f8fc9b375..520f8ec202 100644 --- a/include/hw/display/edid.h +++ b/include/hw/display/edid.h @@ -11,6 +11,7 @@ typedef struct qemu_edid_info { uint32_t prefy; uint32_t maxx; uint32_t maxy; + uint32_t refresh_rate; } qemu_edid_info; void qemu_edid_generate(uint8_t *edid, size_t size, @@ -21,10 +22,11 @@ void qemu_edid_region_io(MemoryRegion *region, Object *owner, uint32_t qemu_edid_dpi_to_mm(uint32_t dpi, uint32_t res); -#define DEFINE_EDID_PROPERTIES(_state, _edid_info) \ - DEFINE_PROP_UINT32("xres", _state, _edid_info.prefx, 0), \ - DEFINE_PROP_UINT32("yres", _state, _edid_info.prefy, 0), \ - DEFINE_PROP_UINT32("xmax", _state, _edid_info.maxx, 0), \ - DEFINE_PROP_UINT32("ymax", _state, _edid_info.maxy, 0) +#define DEFINE_EDID_PROPERTIES(_state, _edid_info) \ + DEFINE_PROP_UINT32("xres", _state, _edid_info.prefx, 0), \ + DEFINE_PROP_UINT32("yres", _state, _edid_info.prefy, 0), \ + DEFINE_PROP_UINT32("xmax", _state, _edid_info.maxx, 0), \ + DEFINE_PROP_UINT32("ymax", _state, _edid_info.maxy, 0), \ + DEFINE_PROP_UINT32("refresh_rate", _state, _edid_info.refresh_rate, 0) #endif /* EDID_H */ From 850dc61f5fd320a8d566b7da9365fd723511b7c3 Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Tue, 27 Apr 2021 17:08:22 +0200 Subject: [PATCH 0342/3028] edid: move timing generation into a separate function The timing generation is currently performed inside the function that fills in the DTD. The DisplayID generation needs it as well, so moving it out to a separate function. Based-on: <20210303152948.59943-2-akihiko.odaki@gmail.com> Signed-off-by: Konstantin Nazarov Message-Id: <20210315114639.91953-1-mail@knazarov.com> Signed-off-by: Gerd Hoffmann Message-id: 20210427150824.638359-1-kraxel@redhat.com Message-Id: <20210427150824.638359-7-kraxel@redhat.com> --- hw/display/edid-generate.c | 68 ++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index 8662218822..b70ab1557e 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -45,6 +45,35 @@ static const struct edid_mode { { .xres = 640, .yres = 480, .byte = 35, .bit = 5 }, }; +typedef struct Timings { + uint32_t xfront; + uint32_t xsync; + uint32_t xblank; + + uint32_t yfront; + uint32_t ysync; + uint32_t yblank; + + uint64_t clock; +} Timings; + +static void generate_timings(Timings *timings, uint32_t refresh_rate, + uint32_t xres, uint32_t yres) +{ + /* pull some realistic looking timings out of thin air */ + timings->xfront = xres * 25 / 100; + timings->xsync = xres * 3 / 100; + timings->xblank = xres * 35 / 100; + + timings->yfront = yres * 5 / 1000; + timings->ysync = yres * 5 / 1000; + timings->yblank = yres * 35 / 1000; + + timings->clock = ((uint64_t)refresh_rate * + (xres + timings->xblank) * + (yres + timings->yblank)) / 10000000; +} + static void edid_ext_dta(uint8_t *dta) { dta[0] = 0x02; @@ -227,38 +256,29 @@ static void edid_desc_timing(uint8_t *desc, uint32_t refresh_rate, uint32_t xres, uint32_t yres, uint32_t xmm, uint32_t ymm) { - /* pull some realistic looking timings out of thin air */ - uint32_t xfront = xres * 25 / 100; - uint32_t xsync = xres * 3 / 100; - uint32_t xblank = xres * 35 / 100; - - uint32_t yfront = yres * 5 / 1000; - uint32_t ysync = yres * 5 / 1000; - uint32_t yblank = yres * 35 / 1000; - - uint64_t clock = (uint64_t)refresh_rate * (xres + xblank) * (yres + yblank); - - stl_le_p(desc, clock / 10000000); + Timings timings; + generate_timings(&timings, refresh_rate, xres, yres); + stl_le_p(desc, timings.clock); desc[2] = xres & 0xff; - desc[3] = xblank & 0xff; + desc[3] = timings.xblank & 0xff; desc[4] = (((xres & 0xf00) >> 4) | - ((xblank & 0xf00) >> 8)); + ((timings.xblank & 0xf00) >> 8)); desc[5] = yres & 0xff; - desc[6] = yblank & 0xff; + desc[6] = timings.yblank & 0xff; desc[7] = (((yres & 0xf00) >> 4) | - ((yblank & 0xf00) >> 8)); + ((timings.yblank & 0xf00) >> 8)); - desc[8] = xfront & 0xff; - desc[9] = xsync & 0xff; + desc[8] = timings.xfront & 0xff; + desc[9] = timings.xsync & 0xff; - desc[10] = (((yfront & 0x00f) << 4) | - ((ysync & 0x00f) << 0)); - desc[11] = (((xfront & 0x300) >> 2) | - ((xsync & 0x300) >> 4) | - ((yfront & 0x030) >> 2) | - ((ysync & 0x030) >> 4)); + desc[10] = (((timings.yfront & 0x00f) << 4) | + ((timings.ysync & 0x00f) << 0)); + desc[11] = (((timings.xfront & 0x300) >> 2) | + ((timings.xsync & 0x300) >> 4) | + ((timings.yfront & 0x030) >> 2) | + ((timings.ysync & 0x030) >> 4)); desc[12] = xmm & 0xff; desc[13] = ymm & 0xff; From 5a4e88cf3b64c4a5c92e43a90260c34a6a52d011 Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Tue, 27 Apr 2021 17:08:23 +0200 Subject: [PATCH 0343/3028] edid: allow arbitrary-length checksums Some of the EDID extensions like DisplayID do checksums of their subsections. Currently checksums can be only applied to the whole extension blocks which are 128 bytes. This patch allows to checksum arbitrary parts of EDID, and not only whole extension blocks. Based-on: <20210303152948.59943-2-akihiko.odaki@gmail.com> Signed-off-by: Konstantin Nazarov Message-Id: <20210315114639.91953-2-mail@knazarov.com> Signed-off-by: Gerd Hoffmann Message-id: 20210427150824.638359-1-kraxel@redhat.com Message-Id: <20210427150824.638359-8-kraxel@redhat.com> --- hw/display/edid-generate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index b70ab1557e..bdd01571fc 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -159,17 +159,17 @@ static void edid_fill_modes(uint8_t *edid, uint8_t *xtra3, uint8_t *dta, } } -static void edid_checksum(uint8_t *edid) +static void edid_checksum(uint8_t *edid, size_t len) { uint32_t sum = 0; int i; - for (i = 0; i < 127; i++) { + for (i = 0; i < len; i++) { sum += edid[i]; } sum &= 0xff; if (sum) { - edid[127] = 0x100 - sum; + edid[len] = 0x100 - sum; } } @@ -474,9 +474,9 @@ void qemu_edid_generate(uint8_t *edid, size_t size, /* =============== finish up =============== */ - edid_checksum(edid); + edid_checksum(edid, 127); if (dta) { - edid_checksum(dta); + edid_checksum(dta, 127); } } From 35f171a2eb25fcdf1b719c58a61a7da15b4fe078 Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Tue, 27 Apr 2021 17:08:24 +0200 Subject: [PATCH 0344/3028] edid: add support for DisplayID extension (5k resolution) The Detailed Timing Descriptor has only 12 bits to store the resolution. This limits the guest to 4095 pixels. This patch adds support for the DisplayID extension, that has 2 full bytes for that purpose, thus allowing 5k resolutions and above. Based-on: <20210303152948.59943-2-akihiko.odaki@gmail.com> Signed-off-by: Konstantin Nazarov Message-Id: <20210315114639.91953-3-mail@knazarov.com> [ kraxel: minor workflow tweaks ] Signed-off-by: Gerd Hoffmann Message-id: 20210427150824.638359-1-kraxel@redhat.com Message-Id: <20210427150824.638359-9-kraxel@redhat.com> --- hw/display/edid-generate.c | 78 +++++++++++++++++++++++++++++++++++--- hw/display/vga-pci.c | 2 +- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c index bdd01571fc..f2b874d5e3 100644 --- a/hw/display/edid-generate.c +++ b/hw/display/edid-generate.c @@ -229,8 +229,8 @@ static void edid_desc_ranges(uint8_t *desc) desc[7] = 30; desc[8] = 160; - /* max dot clock (1200 MHz) */ - desc[9] = 1200 / 10; + /* max dot clock (2550 MHz) */ + desc[9] = 2550 / 10; /* no extended timing information */ desc[10] = 0x01; @@ -336,15 +336,61 @@ uint32_t qemu_edid_dpi_to_mm(uint32_t dpi, uint32_t res) return res * 254 / 10 / dpi; } +static void init_displayid(uint8_t *did) +{ + did[0] = 0x70; /* display id extension */ + did[1] = 0x13; /* version 1.3 */ + did[2] = 4; /* length */ + did[3] = 0x03; /* product type (0x03 == standalone display device) */ + edid_checksum(did + 1, did[2] + 4); +} + +static void qemu_displayid_generate(uint8_t *did, uint32_t refresh_rate, + uint32_t xres, uint32_t yres, + uint32_t xmm, uint32_t ymm) +{ + Timings timings; + generate_timings(&timings, refresh_rate, xres, yres); + + did[0] = 0x70; /* display id extension */ + did[1] = 0x13; /* version 1.3 */ + did[2] = 23; /* length */ + did[3] = 0x03; /* product type (0x03 == standalone display device) */ + + did[5] = 0x03; /* Detailed Timings Data Block */ + did[6] = 0x00; /* revision */ + did[7] = 0x14; /* block length */ + + did[8] = timings.clock & 0xff; + did[9] = (timings.clock & 0xff00) >> 8; + did[10] = (timings.clock & 0xff0000) >> 16; + + did[11] = 0x88; /* leave aspect ratio undefined */ + + stw_le_p(did + 12, 0xffff & (xres - 1)); + stw_le_p(did + 14, 0xffff & (timings.xblank - 1)); + stw_le_p(did + 16, 0xffff & (timings.xfront - 1)); + stw_le_p(did + 18, 0xffff & (timings.xsync - 1)); + + stw_le_p(did + 20, 0xffff & (yres - 1)); + stw_le_p(did + 22, 0xffff & (timings.yblank - 1)); + stw_le_p(did + 24, 0xffff & (timings.yfront - 1)); + stw_le_p(did + 26, 0xffff & (timings.ysync - 1)); + + edid_checksum(did + 1, did[2] + 4); +} + void qemu_edid_generate(uint8_t *edid, size_t size, qemu_edid_info *info) { uint8_t *desc = edid + 54; uint8_t *xtra3 = NULL; uint8_t *dta = NULL; + uint8_t *did = NULL; uint32_t width_mm, height_mm; uint32_t refresh_rate = info->refresh_rate ? info->refresh_rate : 75000; uint32_t dpi = 100; /* if no width_mm/height_mm */ + uint32_t large_screen = 0; /* =============== set defaults =============== */ @@ -360,6 +406,9 @@ void qemu_edid_generate(uint8_t *edid, size_t size, if (!info->prefy) { info->prefy = 768; } + if (info->prefx >= 4096 || info->prefy >= 4096) { + large_screen = 1; + } if (info->width_mm && info->height_mm) { width_mm = info->width_mm; height_mm = info->height_mm; @@ -377,6 +426,12 @@ void qemu_edid_generate(uint8_t *edid, size_t size, edid_ext_dta(dta); } + if (size >= 384 && large_screen) { + did = edid + 256; + edid[126]++; + init_displayid(did); + } + /* =============== header information =============== */ /* fixed */ @@ -441,9 +496,12 @@ void qemu_edid_generate(uint8_t *edid, size_t size, /* =============== descriptor blocks =============== */ - edid_desc_timing(desc, refresh_rate, info->prefx, info->prefy, - width_mm, height_mm); - desc = edid_desc_next(edid, dta, desc); + if (!large_screen) { + /* The DTD section has only 12 bits to store the resolution */ + edid_desc_timing(desc, refresh_rate, info->prefx, info->prefy, + width_mm, height_mm); + desc = edid_desc_next(edid, dta, desc); + } xtra3 = desc; edid_desc_xtra3_std(xtra3); @@ -472,12 +530,22 @@ void qemu_edid_generate(uint8_t *edid, size_t size, desc = edid_desc_next(edid, dta, desc); } + /* =============== display id extensions =============== */ + + if (did && large_screen) { + qemu_displayid_generate(did, refresh_rate, info->prefx, info->prefy, + width_mm, height_mm); + } + /* =============== finish up =============== */ edid_checksum(edid, 127); if (dta) { edid_checksum(dta, 127); } + if (did) { + edid_checksum(did, 127); + } } size_t qemu_edid_size(uint8_t *edid) diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index 48d29630ab..62fb5c38c1 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -49,7 +49,7 @@ struct PCIVGAState { qemu_edid_info edid_info; MemoryRegion mmio; MemoryRegion mrs[4]; - uint8_t edid[256]; + uint8_t edid[384]; }; #define TYPE_PCI_VGA "pci-vga" From 9049f8bc445d50c0b5fe5500c0ec51fcc821c2ef Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 6 May 2021 11:10:01 +0200 Subject: [PATCH 0345/3028] virtio-gpu: handle partial maps properly dma_memory_map() may map only a part of the request. Happens if the request can't be mapped in one go, for example due to a iommu creating a linear dma mapping for scattered physical pages. Should that be the case virtio-gpu must call dma_memory_map() again with the remaining range instead of simply throwing an error. Note that this change implies the number of iov entries may differ from the number of mapping entries sent by the guest. Therefore the iov_len bookkeeping needs some updates too, we have to explicitly pass around the iov length now. Reported-by: Auger Eric Signed-off-by: Gerd Hoffmann Message-id: 20210506091001.1301250-1-kraxel@redhat.com Reviewed-by: Eric Auger Tested-by: Eric Auger Message-Id: <20210506091001.1301250-1-kraxel@redhat.com> --- hw/display/virtio-gpu-3d.c | 7 ++-- hw/display/virtio-gpu.c | 76 ++++++++++++++++++++-------------- include/hw/virtio/virtio-gpu.h | 3 +- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c index d98964858e..72c14d9132 100644 --- a/hw/display/virtio-gpu-3d.c +++ b/hw/display/virtio-gpu-3d.c @@ -283,22 +283,23 @@ static void virgl_resource_attach_backing(VirtIOGPU *g, { struct virtio_gpu_resource_attach_backing att_rb; struct iovec *res_iovs; + uint32_t res_niov; int ret; VIRTIO_GPU_FILL_CMD(att_rb); trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id); - ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs); + ret = virtio_gpu_create_mapping_iov(g, &att_rb, cmd, NULL, &res_iovs, &res_niov); if (ret != 0) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; return; } ret = virgl_renderer_resource_attach_iov(att_rb.resource_id, - res_iovs, att_rb.nr_entries); + res_iovs, res_niov); if (ret != 0) - virtio_gpu_cleanup_mapping_iov(g, res_iovs, att_rb.nr_entries); + virtio_gpu_cleanup_mapping_iov(g, res_iovs, res_niov); } static void virgl_resource_detach_backing(VirtIOGPU *g, diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index c9f5e36fd0..6f3791deb3 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -608,11 +608,12 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, int virtio_gpu_create_mapping_iov(VirtIOGPU *g, struct virtio_gpu_resource_attach_backing *ab, struct virtio_gpu_ctrl_command *cmd, - uint64_t **addr, struct iovec **iov) + uint64_t **addr, struct iovec **iov, + uint32_t *niov) { struct virtio_gpu_mem_entry *ents; size_t esize, s; - int i; + int e, v; if (ab->nr_entries > 16384) { qemu_log_mask(LOG_GUEST_ERROR, @@ -633,37 +634,53 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g, return -1; } - *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries); + *iov = NULL; if (addr) { - *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries); + *addr = NULL; } - for (i = 0; i < ab->nr_entries; i++) { - uint64_t a = le64_to_cpu(ents[i].addr); - uint32_t l = le32_to_cpu(ents[i].length); - hwaddr len = l; - (*iov)[i].iov_base = dma_memory_map(VIRTIO_DEVICE(g)->dma_as, - a, &len, DMA_DIRECTION_TO_DEVICE); - (*iov)[i].iov_len = len; - if (addr) { - (*addr)[i] = a; - } - if (!(*iov)[i].iov_base || len != l) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" - " resource %d element %d\n", - __func__, ab->resource_id, i); - if ((*iov)[i].iov_base) { - i++; /* cleanup the 'i'th map */ + for (e = 0, v = 0; e < ab->nr_entries; e++) { + uint64_t a = le64_to_cpu(ents[e].addr); + uint32_t l = le32_to_cpu(ents[e].length); + hwaddr len; + void *map; + + do { + len = l; + map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as, + a, &len, DMA_DIRECTION_TO_DEVICE); + if (!map) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" + " resource %d element %d\n", + __func__, ab->resource_id, e); + virtio_gpu_cleanup_mapping_iov(g, *iov, v); + g_free(ents); + *iov = NULL; + if (addr) { + g_free(*addr); + *addr = NULL; + } + return -1; } - virtio_gpu_cleanup_mapping_iov(g, *iov, i); - g_free(ents); - *iov = NULL; + + if (!(v % 16)) { + *iov = g_realloc(*iov, sizeof(struct iovec) * (v + 16)); + if (addr) { + *addr = g_realloc(*addr, sizeof(uint64_t) * (v + 16)); + } + } + (*iov)[v].iov_base = map; + (*iov)[v].iov_len = len; if (addr) { - g_free(*addr); - *addr = NULL; + (*addr)[v] = a; } - return -1; - } + + a += len; + l -= len; + v += 1; + } while (l > 0); } + *niov = v; + g_free(ents); return 0; } @@ -717,13 +734,12 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g, return; } - ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs, &res->iov); + ret = virtio_gpu_create_mapping_iov(g, &ab, cmd, &res->addrs, + &res->iov, &res->iov_cnt); if (ret != 0) { cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC; return; } - - res->iov_cnt = ab.nr_entries; } static void diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index fae149235c..0d15af41d9 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -209,7 +209,8 @@ void virtio_gpu_get_edid(VirtIOGPU *g, int virtio_gpu_create_mapping_iov(VirtIOGPU *g, struct virtio_gpu_resource_attach_backing *ab, struct virtio_gpu_ctrl_command *cmd, - uint64_t **addr, struct iovec **iov); + uint64_t **addr, struct iovec **iov, + uint32_t *niov); void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g, struct iovec *iov, uint32_t count); void virtio_gpu_process_cmdq(VirtIOGPU *g); From 7d2ad4e1e8b63babac11de42bf2a000e40ab4e89 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:32 +0200 Subject: [PATCH 0346/3028] virtio-gpu: rename virgl source file. "3d" -> "virgl" as 3d is a rather broad term. Hopefully a bit less confusing. Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-2-kraxel@redhat.com> --- hw/display/meson.build | 2 +- hw/display/{virtio-gpu-3d.c => virtio-gpu-virgl.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename hw/display/{virtio-gpu-3d.c => virtio-gpu-virgl.c} (100%) diff --git a/hw/display/meson.build b/hw/display/meson.build index 9d79e3951d..8e465731b8 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -58,7 +58,7 @@ if config_all_devices.has_key('CONFIG_VIRTIO_GPU') virtio_gpu_ss.add(when: 'CONFIG_VIRTIO_GPU', if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman, virgl]) virtio_gpu_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL'], - if_true: [files('virtio-gpu-3d.c'), pixman, virgl]) + if_true: [files('virtio-gpu-virgl.c'), pixman, virgl]) virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c')) hw_display_modules += {'virtio-gpu': virtio_gpu_ss} endif diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-virgl.c similarity index 100% rename from hw/display/virtio-gpu-3d.c rename to hw/display/virtio-gpu-virgl.c From 063cd34a03e2a12bf338137410cb972250fe5027 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:33 +0200 Subject: [PATCH 0347/3028] virtio-gpu: add virtio-gpu-gl-device Just a skeleton for starters, following patches will add more code. Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-3-kraxel@redhat.com> --- hw/display/meson.build | 2 +- hw/display/virtio-gpu-gl.c | 41 ++++++++++++++++++++++++++++++++++ include/hw/virtio/virtio-gpu.h | 7 ++++++ util/module.c | 1 + 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 hw/display/virtio-gpu-gl.c diff --git a/hw/display/meson.build b/hw/display/meson.build index 8e465731b8..5161efa08a 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -58,7 +58,7 @@ if config_all_devices.has_key('CONFIG_VIRTIO_GPU') virtio_gpu_ss.add(when: 'CONFIG_VIRTIO_GPU', if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman, virgl]) virtio_gpu_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL'], - if_true: [files('virtio-gpu-virgl.c'), pixman, virgl]) + if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl]) virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c')) hw_display_modules += {'virtio-gpu': virtio_gpu_ss} endif diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c new file mode 100644 index 0000000000..a477cbe186 --- /dev/null +++ b/hw/display/virtio-gpu-gl.c @@ -0,0 +1,41 @@ +/* + * Virtio GPU Device + * + * Copyright Red Hat, Inc. 2013-2014 + * + * Authors: + * Dave Airlie + * Gerd Hoffmann + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/iov.h" +#include "qemu/module.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-gpu-bswap.h" +#include "hw/virtio/virtio-gpu-pixman.h" +#include "hw/qdev-properties.h" + +static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) +{ +} + +static const TypeInfo virtio_gpu_gl_info = { + .name = TYPE_VIRTIO_GPU_GL, + .parent = TYPE_VIRTIO_GPU, + .instance_size = sizeof(VirtIOGPUGL), + .class_init = virtio_gpu_gl_class_init, +}; + +static void virtio_register_types(void) +{ + type_register_static(&virtio_gpu_gl_info); +} + +type_init(virtio_register_types) diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 0d15af41d9..5b2d011b49 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -31,6 +31,9 @@ OBJECT_DECLARE_TYPE(VirtIOGPUBase, VirtIOGPUBaseClass, #define TYPE_VIRTIO_GPU "virtio-gpu-device" OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPU, VIRTIO_GPU) +#define TYPE_VIRTIO_GPU_GL "virtio-gpu-gl-device" +OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUGL, VIRTIO_GPU_GL) + #define TYPE_VHOST_USER_GPU "vhost-user-gpu" OBJECT_DECLARE_SIMPLE_TYPE(VhostUserGPU, VHOST_USER_GPU) @@ -163,6 +166,10 @@ struct VirtIOGPU { } stats; }; +struct VirtIOGPUGL { + struct VirtIOGPU parent_obj; +}; + struct VhostUserGPU { VirtIOGPUBase parent_obj; diff --git a/util/module.c b/util/module.c index 7661d0f623..47bba11828 100644 --- a/util/module.c +++ b/util/module.c @@ -301,6 +301,7 @@ static struct { { "qxl-vga", "hw-", "display-qxl" }, { "qxl", "hw-", "display-qxl" }, { "virtio-gpu-device", "hw-", "display-virtio-gpu" }, + { "virtio-gpu-gl-device", "hw-", "display-virtio-gpu" }, { "vhost-user-gpu", "hw-", "display-virtio-gpu" }, { "virtio-gpu-pci-base", "hw-", "display-virtio-gpu-pci" }, { "virtio-gpu-pci", "hw-", "display-virtio-gpu-pci" }, From 37f86af087397688c7de4ea4ddf05449d48e6ee0 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:34 +0200 Subject: [PATCH 0348/3028] virtio-gpu: move virgl realize + properties Move device init (realize) and properties. Drop the virgl property, the virtio-gpu-gl-device has virgl enabled no matter what. Just use virtio-gpu-device instead if you don't want enable virgl and opengl. This simplifies the logic and reduces the test matrix. Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-4-kraxel@redhat.com> --- hw/display/virtio-gpu-gl.c | 33 +++++++++++++++++++++++++++++++++ hw/display/virtio-gpu.c | 23 +---------------------- include/hw/virtio/virtio-gpu.h | 1 + 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index a477cbe186..9b7b5f00d7 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -16,14 +16,47 @@ #include "qemu/module.h" #include "qemu/error-report.h" #include "qapi/error.h" +#include "sysemu/sysemu.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-gpu-bswap.h" #include "hw/virtio/virtio-gpu-pixman.h" #include "hw/qdev-properties.h" +static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) +{ + VirtIOGPU *g = VIRTIO_GPU(qdev); + +#if defined(HOST_WORDS_BIGENDIAN) + error_setg(errp, "virgl is not supported on bigendian platforms"); + return; +#endif + + if (!display_opengl) { + error_setg(errp, "opengl is not available"); + return; + } + + g->parent_obj.conf.flags |= (1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); + VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = + virtio_gpu_virgl_get_num_capsets(g); + + virtio_gpu_device_realize(qdev, errp); +} + +static Property virtio_gpu_gl_properties[] = { + DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags, + VIRTIO_GPU_FLAG_STATS_ENABLED, false), + DEFINE_PROP_END_OF_LIST(), +}; + static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + + vdc->realize = virtio_gpu_gl_device_realize; + device_class_set_props(dc, virtio_gpu_gl_properties); } static const TypeInfo virtio_gpu_gl_info = { diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 6f3791deb3..461b7769b4 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1121,25 +1121,10 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size, return 0; } -static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) +void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(qdev); VirtIOGPU *g = VIRTIO_GPU(qdev); - bool have_virgl; - -#if !defined(CONFIG_VIRGL) || defined(HOST_WORDS_BIGENDIAN) - have_virgl = false; -#else - have_virgl = display_opengl; -#endif - if (!have_virgl) { - g->parent_obj.conf.flags &= ~(1 << VIRTIO_GPU_FLAG_VIRGL_ENABLED); - } else { -#if defined(CONFIG_VIRGL) - VIRTIO_GPU_BASE(g)->virtio_config.num_capsets = - virtio_gpu_virgl_get_num_capsets(g); -#endif - } if (!virtio_gpu_base_device_realize(qdev, virtio_gpu_handle_ctrl_cb, @@ -1251,12 +1236,6 @@ static Property virtio_gpu_properties[] = { VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf), DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem, 256 * MiB), -#ifdef CONFIG_VIRGL - DEFINE_PROP_BIT("virgl", VirtIOGPU, parent_obj.conf.flags, - VIRTIO_GPU_FLAG_VIRGL_ENABLED, true), - DEFINE_PROP_BIT("stats", VirtIOGPU, parent_obj.conf.flags, - VIRTIO_GPU_FLAG_STATS_ENABLED, false), -#endif DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 5b2d011b49..7430f3cd99 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -221,6 +221,7 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g, void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g, struct iovec *iov, uint32_t count); void virtio_gpu_process_cmdq(VirtIOGPU *g); +void virtio_gpu_device_realize(DeviceState *qdev, Error **errp); /* virtio-gpu-3d.c */ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, From 76fa8b359b4c0c24f390ea4b788242cc627b966f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:35 +0200 Subject: [PATCH 0349/3028] virtio-gpu: move virgl reset Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-5-kraxel@redhat.com> --- hw/display/virtio-gpu-gl.c | 17 +++++++++++++++++ hw/display/virtio-gpu.c | 19 +------------------ include/hw/virtio/virtio-gpu.h | 1 + 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 9b7b5f00d7..c3e562f835 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -23,6 +23,22 @@ #include "hw/virtio/virtio-gpu-pixman.h" #include "hw/qdev-properties.h" +static void virtio_gpu_gl_reset(VirtIODevice *vdev) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + + virtio_gpu_reset(vdev); + + if (g->parent_obj.use_virgl_renderer) { + if (g->parent_obj.renderer_blocked) { + g->renderer_reset = true; + } else { + virtio_gpu_virgl_reset(g); + } + g->parent_obj.use_virgl_renderer = false; + } +} + static void virtio_gpu_gl_device_realize(DeviceState *qdev, Error **errp) { VirtIOGPU *g = VIRTIO_GPU(qdev); @@ -56,6 +72,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); vdc->realize = virtio_gpu_gl_device_realize; + vdc->reset = virtio_gpu_gl_reset; device_class_set_props(dc, virtio_gpu_gl_properties); } diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 461b7769b4..b500f86b20 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1142,18 +1142,12 @@ void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) QTAILQ_INIT(&g->fenceq); } -static void virtio_gpu_reset(VirtIODevice *vdev) +void virtio_gpu_reset(VirtIODevice *vdev) { VirtIOGPU *g = VIRTIO_GPU(vdev); struct virtio_gpu_simple_resource *res, *tmp; struct virtio_gpu_ctrl_command *cmd; -#ifdef CONFIG_VIRGL - if (g->parent_obj.use_virgl_renderer) { - virtio_gpu_virgl_reset(g); - } -#endif - QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) { virtio_gpu_resource_destroy(g, res); } @@ -1171,17 +1165,6 @@ static void virtio_gpu_reset(VirtIODevice *vdev) g_free(cmd); } -#ifdef CONFIG_VIRGL - if (g->parent_obj.use_virgl_renderer) { - if (g->parent_obj.renderer_blocked) { - g->renderer_reset = true; - } else { - virtio_gpu_virgl_reset(g); - } - g->parent_obj.use_virgl_renderer = false; - } -#endif - virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev)); } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7430f3cd99..7130e41685 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -222,6 +222,7 @@ void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g, struct iovec *iov, uint32_t count); void virtio_gpu_process_cmdq(VirtIOGPU *g); void virtio_gpu_device_realize(DeviceState *qdev, Error **errp); +void virtio_gpu_reset(VirtIODevice *vdev); /* virtio-gpu-3d.c */ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, From cabbe8e588f57e95d568f0238135839d7335249b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:36 +0200 Subject: [PATCH 0350/3028] virtio-gpu: use class function for ctrl queue handlers Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-6-kraxel@redhat.com> --- hw/display/virtio-gpu.c | 12 +++++++++--- include/hw/virtio/virtio-gpu.h | 8 +++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index b500f86b20..f25b079a9d 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -909,7 +909,9 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) static void virtio_gpu_ctrl_bh(void *opaque) { VirtIOGPU *g = opaque; - virtio_gpu_handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq); + VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g); + + vgc->handle_ctrl(&g->parent_obj.parent_obj, g->ctrl_vq); } static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) @@ -1226,9 +1228,12 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - VirtIOGPUBaseClass *vgc = VIRTIO_GPU_BASE_CLASS(klass); + VirtIOGPUBaseClass *vbc = VIRTIO_GPU_BASE_CLASS(klass); + VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass); + + vbc->gl_flushed = virtio_gpu_gl_flushed; + vgc->handle_ctrl = virtio_gpu_handle_ctrl; - vgc->gl_flushed = virtio_gpu_gl_flushed; vdc->realize = virtio_gpu_device_realize; vdc->reset = virtio_gpu_reset; vdc->get_config = virtio_gpu_get_config; @@ -1242,6 +1247,7 @@ static const TypeInfo virtio_gpu_info = { .name = TYPE_VIRTIO_GPU, .parent = TYPE_VIRTIO_GPU_BASE, .instance_size = sizeof(VirtIOGPU), + .class_size = sizeof(VirtIOGPUClass), .class_init = virtio_gpu_class_init, }; diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7130e41685..7ac9229c63 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -29,7 +29,7 @@ OBJECT_DECLARE_TYPE(VirtIOGPUBase, VirtIOGPUBaseClass, VIRTIO_GPU_BASE) #define TYPE_VIRTIO_GPU "virtio-gpu-device" -OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPU, VIRTIO_GPU) +OBJECT_DECLARE_TYPE(VirtIOGPU, VirtIOGPUClass, VIRTIO_GPU) #define TYPE_VIRTIO_GPU_GL "virtio-gpu-gl-device" OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUGL, VIRTIO_GPU_GL) @@ -166,6 +166,12 @@ struct VirtIOGPU { } stats; }; +struct VirtIOGPUClass { + VirtIOGPUBaseClass parent; + + void (*handle_ctrl)(VirtIODevice *vdev, VirtQueue *vq); +}; + struct VirtIOGPUGL { struct VirtIOGPU parent_obj; }; From ce537a4fc991d856511cbbbb32dd7105dda55b7a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:37 +0200 Subject: [PATCH 0351/3028] virtio-gpu: move virgl handle_ctrl Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-7-kraxel@redhat.com> --- hw/display/virtio-gpu-gl.c | 33 +++++++++++++++++++++++++++++++++ hw/display/virtio-gpu.c | 13 ------------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index c3e562f835..6d0ce5bcd6 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -23,6 +23,36 @@ #include "hw/virtio/virtio-gpu-pixman.h" #include "hw/qdev-properties.h" +static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOGPU *g = VIRTIO_GPU(vdev); + struct virtio_gpu_ctrl_command *cmd; + + if (!virtio_queue_ready(vq)) { + return; + } + + if (!g->renderer_inited && g->parent_obj.use_virgl_renderer) { + virtio_gpu_virgl_init(g); + g->renderer_inited = true; + } + + cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); + while (cmd) { + cmd->vq = vq; + cmd->error = 0; + cmd->finished = false; + QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next); + cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); + } + + virtio_gpu_process_cmdq(g); + + if (g->parent_obj.use_virgl_renderer) { + virtio_gpu_virgl_fence_poll(g); + } +} + static void virtio_gpu_gl_reset(VirtIODevice *vdev) { VirtIOGPU *g = VIRTIO_GPU(vdev); @@ -70,6 +100,9 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass); + + vgc->handle_ctrl = virtio_gpu_gl_handle_ctrl; vdc->realize = virtio_gpu_gl_device_realize; vdc->reset = virtio_gpu_gl_reset; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index f25b079a9d..dfb6c0a9ef 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -881,13 +881,6 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) return; } -#ifdef CONFIG_VIRGL - if (!g->renderer_inited && g->parent_obj.use_virgl_renderer) { - virtio_gpu_virgl_init(g); - g->renderer_inited = true; - } -#endif - cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); while (cmd) { cmd->vq = vq; @@ -898,12 +891,6 @@ static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } virtio_gpu_process_cmdq(g); - -#ifdef CONFIG_VIRGL - if (g->parent_obj.use_virgl_renderer) { - virtio_gpu_virgl_fence_poll(g); - } -#endif } static void virtio_gpu_ctrl_bh(void *opaque) From 3e48b7a31a755b570851090904c4d0f4d0906832 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:38 +0200 Subject: [PATCH 0352/3028] virtio-gpu: move virgl gl_flushed Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-8-kraxel@redhat.com> --- hw/display/virtio-gpu-gl.c | 13 +++++++++++++ hw/display/virtio-gpu.c | 15 --------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 6d0ce5bcd6..e976fb8d04 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -23,6 +23,17 @@ #include "hw/virtio/virtio-gpu-pixman.h" #include "hw/qdev-properties.h" +static void virtio_gpu_gl_flushed(VirtIOGPUBase *b) +{ + VirtIOGPU *g = VIRTIO_GPU(b); + + if (g->renderer_reset) { + g->renderer_reset = false; + virtio_gpu_virgl_reset(g); + } + virtio_gpu_process_cmdq(g); +} + static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIOGPU *g = VIRTIO_GPU(vdev); @@ -100,8 +111,10 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + VirtIOGPUBaseClass *vbc = VIRTIO_GPU_BASE_CLASS(klass); VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass); + vbc->gl_flushed = virtio_gpu_gl_flushed; vgc->handle_ctrl = virtio_gpu_gl_handle_ctrl; vdc->realize = virtio_gpu_gl_device_realize; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index dfb6c0a9ef..9be486bb81 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -859,19 +859,6 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) g->processing_cmdq = false; } -static void virtio_gpu_gl_flushed(VirtIOGPUBase *b) -{ - VirtIOGPU *g = VIRTIO_GPU(b); - -#ifdef CONFIG_VIRGL - if (g->renderer_reset) { - g->renderer_reset = false; - virtio_gpu_virgl_reset(g); - } -#endif - virtio_gpu_process_cmdq(g); -} - static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIOGPU *g = VIRTIO_GPU(vdev); @@ -1215,10 +1202,8 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - VirtIOGPUBaseClass *vbc = VIRTIO_GPU_BASE_CLASS(klass); VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass); - vbc->gl_flushed = virtio_gpu_gl_flushed; vgc->handle_ctrl = virtio_gpu_handle_ctrl; vdc->realize = virtio_gpu_device_realize; From 2f47691a0f8dbb4661216cba2c687efc28b1bcf5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:39 +0200 Subject: [PATCH 0353/3028] virtio-gpu: move virgl process_cmd Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-9-kraxel@redhat.com> --- hw/display/virtio-gpu-gl.c | 11 +++++++++++ hw/display/virtio-gpu.c | 9 +++++---- include/hw/virtio/virtio-gpu.h | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index e976fb8d04..792cc0b412 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -23,6 +23,16 @@ #include "hw/virtio/virtio-gpu-pixman.h" #include "hw/qdev-properties.h" +static void virtio_gpu_gl_process_cmd(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) +{ + if (g->parent_obj.use_virgl_renderer) { + virtio_gpu_virgl_process_cmd(g, cmd); + return; + } + virtio_gpu_simple_process_cmd(g, cmd); +} + static void virtio_gpu_gl_flushed(VirtIOGPUBase *b) { VirtIOGPU *g = VIRTIO_GPU(b); @@ -116,6 +126,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) vbc->gl_flushed = virtio_gpu_gl_flushed; vgc->handle_ctrl = virtio_gpu_gl_handle_ctrl; + vgc->process_cmd = virtio_gpu_gl_process_cmd; vdc->realize = virtio_gpu_gl_device_realize; vdc->reset = virtio_gpu_gl_reset; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 9be486bb81..7c65c3ffe8 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -763,8 +763,8 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g, virtio_gpu_cleanup_mapping(g, res); } -static void virtio_gpu_simple_process_cmd(VirtIOGPU *g, - struct virtio_gpu_ctrl_command *cmd) +void virtio_gpu_simple_process_cmd(VirtIOGPU *g, + struct virtio_gpu_ctrl_command *cmd) { VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr); @@ -822,6 +822,7 @@ static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq) void virtio_gpu_process_cmdq(VirtIOGPU *g) { struct virtio_gpu_ctrl_command *cmd; + VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g); if (g->processing_cmdq) { return; @@ -835,8 +836,7 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g) } /* process command */ - VIRGL(g, virtio_gpu_virgl_process_cmd, virtio_gpu_simple_process_cmd, - g, cmd); + vgc->process_cmd(g, cmd); QTAILQ_REMOVE(&g->cmdq, cmd, next); if (virtio_gpu_stats_enabled(g->parent_obj.conf)) { @@ -1205,6 +1205,7 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data) VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass); vgc->handle_ctrl = virtio_gpu_handle_ctrl; + vgc->process_cmd = virtio_gpu_simple_process_cmd; vdc->realize = virtio_gpu_device_realize; vdc->reset = virtio_gpu_reset; diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 7ac9229c63..c7bc925998 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -170,6 +170,7 @@ struct VirtIOGPUClass { VirtIOGPUBaseClass parent; void (*handle_ctrl)(VirtIODevice *vdev, VirtQueue *vq); + void (*process_cmd)(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd); }; struct VirtIOGPUGL { @@ -229,6 +230,7 @@ void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g, void virtio_gpu_process_cmdq(VirtIOGPU *g); void virtio_gpu_device_realize(DeviceState *qdev, Error **errp); void virtio_gpu_reset(VirtIODevice *vdev); +void virtio_gpu_simple_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd); /* virtio-gpu-3d.c */ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, From 2c267d66fde11c8813d5b6d91871fc501e891122 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:40 +0200 Subject: [PATCH 0354/3028] virtio-gpu: move update_cursor_data Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-10-kraxel@redhat.com> --- hw/display/virtio-gpu-gl.c | 30 +++++++++++++++++++++++++++ hw/display/virtio-gpu.c | 38 ++++++---------------------------- include/hw/virtio/virtio-gpu.h | 6 ++++++ 3 files changed, 42 insertions(+), 32 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 792cc0b412..b4303cc5bb 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -23,6 +23,35 @@ #include "hw/virtio/virtio-gpu-pixman.h" #include "hw/qdev-properties.h" +#include + +static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g, + struct virtio_gpu_scanout *s, + uint32_t resource_id) +{ + uint32_t width, height; + uint32_t pixels, *data; + + if (g->parent_obj.use_virgl_renderer) { + data = virgl_renderer_get_cursor_data(resource_id, &width, &height); + if (!data) { + return; + } + + if (width != s->current_cursor->width || + height != s->current_cursor->height) { + free(data); + return; + } + + pixels = s->current_cursor->width * s->current_cursor->height; + memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t)); + free(data); + return; + } + virtio_gpu_update_cursor_data(g, s, resource_id); +} + static void virtio_gpu_gl_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { @@ -127,6 +156,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) vbc->gl_flushed = virtio_gpu_gl_flushed; vgc->handle_ctrl = virtio_gpu_gl_handle_ctrl; vgc->process_cmd = virtio_gpu_gl_process_cmd; + vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data; vdc->realize = virtio_gpu_gl_device_realize; vdc->reset = virtio_gpu_gl_reset; diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 7c65c3ffe8..921a8212a7 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -56,9 +56,9 @@ static void virtio_gpu_cleanup_mapping(VirtIOGPU *g, } while (0) #endif -static void update_cursor_data_simple(VirtIOGPU *g, - struct virtio_gpu_scanout *s, - uint32_t resource_id) +void virtio_gpu_update_cursor_data(VirtIOGPU *g, + struct virtio_gpu_scanout *s, + uint32_t resource_id) { struct virtio_gpu_simple_resource *res; uint32_t pixels; @@ -79,36 +79,10 @@ static void update_cursor_data_simple(VirtIOGPU *g, pixels * sizeof(uint32_t)); } -#ifdef CONFIG_VIRGL - -static void update_cursor_data_virgl(VirtIOGPU *g, - struct virtio_gpu_scanout *s, - uint32_t resource_id) -{ - uint32_t width, height; - uint32_t pixels, *data; - - data = virgl_renderer_get_cursor_data(resource_id, &width, &height); - if (!data) { - return; - } - - if (width != s->current_cursor->width || - height != s->current_cursor->height) { - free(data); - return; - } - - pixels = s->current_cursor->width * s->current_cursor->height; - memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t)); - free(data); -} - -#endif - static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) { struct virtio_gpu_scanout *s; + VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g); bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR; if (cursor->pos.scanout_id >= g->parent_obj.conf.max_outputs) { @@ -131,8 +105,7 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor) s->current_cursor->hot_y = cursor->hot_y; if (cursor->resource_id > 0) { - VIRGL(g, update_cursor_data_virgl, update_cursor_data_simple, - g, s, cursor->resource_id); + vgc->update_cursor_data(g, s, cursor->resource_id); } dpy_cursor_define(s->con, s->current_cursor); @@ -1206,6 +1179,7 @@ static void virtio_gpu_class_init(ObjectClass *klass, void *data) vgc->handle_ctrl = virtio_gpu_handle_ctrl; vgc->process_cmd = virtio_gpu_simple_process_cmd; + vgc->update_cursor_data = virtio_gpu_update_cursor_data; vdc->realize = virtio_gpu_device_realize; vdc->reset = virtio_gpu_reset; diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index c7bc925998..b897917168 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -171,6 +171,9 @@ struct VirtIOGPUClass { void (*handle_ctrl)(VirtIODevice *vdev, VirtQueue *vq); void (*process_cmd)(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd); + void (*update_cursor_data)(VirtIOGPU *g, + struct virtio_gpu_scanout *s, + uint32_t resource_id); }; struct VirtIOGPUGL { @@ -231,6 +234,9 @@ void virtio_gpu_process_cmdq(VirtIOGPU *g); void virtio_gpu_device_realize(DeviceState *qdev, Error **errp); void virtio_gpu_reset(VirtIODevice *vdev); void virtio_gpu_simple_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd); +void virtio_gpu_update_cursor_data(VirtIOGPU *g, + struct virtio_gpu_scanout *s, + uint32_t resource_id); /* virtio-gpu-3d.c */ void virtio_gpu_virgl_process_cmd(VirtIOGPU *g, From d42d0d34b9463ce3c11cc19d1dd22def5eb1257e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:41 +0200 Subject: [PATCH 0355/3028] virtio-gpu: drop VIRGL() macro Drops last virgl/opengl dependency from virtio-gpu-device. Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-11-kraxel@redhat.com> --- hw/display/virtio-gpu.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 921a8212a7..db56f0454a 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -39,23 +39,6 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); static void virtio_gpu_cleanup_mapping(VirtIOGPU *g, struct virtio_gpu_simple_resource *res); -#ifdef CONFIG_VIRGL -#include -#define VIRGL(_g, _virgl, _simple, ...) \ - do { \ - if (_g->parent_obj.use_virgl_renderer) { \ - _virgl(__VA_ARGS__); \ - } else { \ - _simple(__VA_ARGS__); \ - } \ - } while (0) -#else -#define VIRGL(_g, _virgl, _simple, ...) \ - do { \ - _simple(__VA_ARGS__); \ - } while (0) -#endif - void virtio_gpu_update_cursor_data(VirtIOGPU *g, struct virtio_gpu_scanout *s, uint32_t resource_id) From e349693a2838bbfe84b010d9ca1a964da69fcb13 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:42 +0200 Subject: [PATCH 0356/3028] virtio-gpu: move virtio-gpu-gl-device to separate module Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-12-kraxel@redhat.com> --- hw/display/meson.build | 9 ++++++--- util/module.c | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/hw/display/meson.build b/hw/display/meson.build index 5161efa08a..3c3e47c47e 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -56,11 +56,14 @@ softmmu_ss.add(when: [pixman, 'CONFIG_ATI_VGA'], if_true: files('ati.c', 'ati_2d if config_all_devices.has_key('CONFIG_VIRTIO_GPU') virtio_gpu_ss = ss.source_set() virtio_gpu_ss.add(when: 'CONFIG_VIRTIO_GPU', - if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman, virgl]) - virtio_gpu_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL'], - if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl]) + if_true: [files('virtio-gpu-base.c', 'virtio-gpu.c'), pixman]) virtio_gpu_ss.add(when: 'CONFIG_VHOST_USER_GPU', if_true: files('vhost-user-gpu.c')) hw_display_modules += {'virtio-gpu': virtio_gpu_ss} + + virtio_gpu_gl_ss = ss.source_set() + virtio_gpu_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRGL', opengl], + if_true: [files('virtio-gpu-gl.c', 'virtio-gpu-virgl.c'), pixman, virgl]) + hw_display_modules += {'virtio-gpu-gl': virtio_gpu_gl_ss} endif if config_all_devices.has_key('CONFIG_VIRTIO_PCI') diff --git a/util/module.c b/util/module.c index 47bba11828..c8f3e5a0a7 100644 --- a/util/module.c +++ b/util/module.c @@ -182,6 +182,8 @@ static const struct { { "ui-spice-app", "ui-spice-core" }, { "ui-spice-app", "chardev-spice" }, + { "hw-display-virtio-gpu-gl", "hw-display-virtio-gpu" }, + #ifdef CONFIG_OPENGL { "ui-egl-headless", "ui-opengl" }, { "ui-gtk", "ui-opengl" }, @@ -301,7 +303,7 @@ static struct { { "qxl-vga", "hw-", "display-qxl" }, { "qxl", "hw-", "display-qxl" }, { "virtio-gpu-device", "hw-", "display-virtio-gpu" }, - { "virtio-gpu-gl-device", "hw-", "display-virtio-gpu" }, + { "virtio-gpu-gl-device", "hw-", "display-virtio-gpu-gl" }, { "vhost-user-gpu", "hw-", "display-virtio-gpu" }, { "virtio-gpu-pci-base", "hw-", "display-virtio-gpu-pci" }, { "virtio-gpu-pci", "hw-", "display-virtio-gpu-pci" }, From 49afbca3b00e8e517d54964229a794b51768deaf Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:43 +0200 Subject: [PATCH 0357/3028] virtio-gpu: drop use_virgl_renderer Now that we have separated the gl and non-gl code flows to two different devices there is little reason turn on and off virglrenderer usage at runtime. The gl code can simply use virglrenderer unconditionally. So drop use_virgl_renderer field and just do that. Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-13-kraxel@redhat.com> --- hw/display/virtio-gpu-base.c | 6 +---- hw/display/virtio-gpu-gl.c | 44 ++++++++++------------------------ include/hw/virtio/virtio-gpu.h | 1 - 3 files changed, 14 insertions(+), 37 deletions(-) diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index 25f8920fdb..afb3ee7d9a 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -25,7 +25,6 @@ virtio_gpu_base_reset(VirtIOGPUBase *g) int i; g->enable = 0; - g->use_virgl_renderer = false; for (i = 0; i < g->conf.max_outputs; i++) { g->scanout[i].resource_id = 0; @@ -162,7 +161,6 @@ virtio_gpu_base_device_realize(DeviceState *qdev, return false; } - g->use_virgl_renderer = false; if (virtio_gpu_virgl_enabled(g->conf)) { error_setg(&g->migration_blocker, "virgl is not yet migratable"); if (migrate_add_blocker(g->migration_blocker, errp) < 0) { @@ -218,10 +216,8 @@ static void virtio_gpu_base_set_features(VirtIODevice *vdev, uint64_t features) { static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL); - VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev); - g->use_virgl_renderer = ((features & virgl) == virgl); - trace_virtio_gpu_features(g->use_virgl_renderer); + trace_virtio_gpu_features(((features & virgl) == virgl)); } static void diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index b4303cc5bb..1642a97354 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -32,34 +32,20 @@ static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g, uint32_t width, height; uint32_t pixels, *data; - if (g->parent_obj.use_virgl_renderer) { - data = virgl_renderer_get_cursor_data(resource_id, &width, &height); - if (!data) { - return; - } + data = virgl_renderer_get_cursor_data(resource_id, &width, &height); + if (!data) { + return; + } - if (width != s->current_cursor->width || - height != s->current_cursor->height) { - free(data); - return; - } - - pixels = s->current_cursor->width * s->current_cursor->height; - memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t)); + if (width != s->current_cursor->width || + height != s->current_cursor->height) { free(data); return; } - virtio_gpu_update_cursor_data(g, s, resource_id); -} -static void virtio_gpu_gl_process_cmd(VirtIOGPU *g, - struct virtio_gpu_ctrl_command *cmd) -{ - if (g->parent_obj.use_virgl_renderer) { - virtio_gpu_virgl_process_cmd(g, cmd); - return; - } - virtio_gpu_simple_process_cmd(g, cmd); + pixels = s->current_cursor->width * s->current_cursor->height; + memcpy(s->current_cursor->data, data, pixels * sizeof(uint32_t)); + free(data); } static void virtio_gpu_gl_flushed(VirtIOGPUBase *b) @@ -82,7 +68,7 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) return; } - if (!g->renderer_inited && g->parent_obj.use_virgl_renderer) { + if (!g->renderer_inited) { virtio_gpu_virgl_init(g); g->renderer_inited = true; } @@ -97,10 +83,7 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } virtio_gpu_process_cmdq(g); - - if (g->parent_obj.use_virgl_renderer) { - virtio_gpu_virgl_fence_poll(g); - } + virtio_gpu_virgl_fence_poll(g); } static void virtio_gpu_gl_reset(VirtIODevice *vdev) @@ -109,13 +92,12 @@ static void virtio_gpu_gl_reset(VirtIODevice *vdev) virtio_gpu_reset(vdev); - if (g->parent_obj.use_virgl_renderer) { + if (g->renderer_inited) { if (g->parent_obj.renderer_blocked) { g->renderer_reset = true; } else { virtio_gpu_virgl_reset(g); } - g->parent_obj.use_virgl_renderer = false; } } @@ -155,7 +137,7 @@ static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) vbc->gl_flushed = virtio_gpu_gl_flushed; vgc->handle_ctrl = virtio_gpu_gl_handle_ctrl; - vgc->process_cmd = virtio_gpu_gl_process_cmd; + vgc->process_cmd = virtio_gpu_virgl_process_cmd; vgc->update_cursor_data = virtio_gpu_gl_update_cursor_data; vdc->realize = virtio_gpu_gl_device_realize; diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index b897917168..0d402aef7c 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -111,7 +111,6 @@ struct VirtIOGPUBase { struct virtio_gpu_config virtio_config; const GraphicHwOps *hw_ops; - bool use_virgl_renderer; int renderer_blocked; int enable; From eff6fa1735a59639806f2a375964f8ac3b72c7f5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:44 +0200 Subject: [PATCH 0358/3028] virtio-gpu: move fields to struct VirtIOGPUGL Move two virglrenderer state variables to struct VirtIOGPUGL. Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-14-kraxel@redhat.com> --- hw/display/virtio-gpu-gl.c | 15 +++++++++------ include/hw/virtio/virtio-gpu.h | 5 +++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 1642a97354..d971b48080 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -51,9 +51,10 @@ static void virtio_gpu_gl_update_cursor_data(VirtIOGPU *g, static void virtio_gpu_gl_flushed(VirtIOGPUBase *b) { VirtIOGPU *g = VIRTIO_GPU(b); + VirtIOGPUGL *gl = VIRTIO_GPU_GL(b); - if (g->renderer_reset) { - g->renderer_reset = false; + if (gl->renderer_reset) { + gl->renderer_reset = false; virtio_gpu_virgl_reset(g); } virtio_gpu_process_cmdq(g); @@ -62,15 +63,16 @@ static void virtio_gpu_gl_flushed(VirtIOGPUBase *b) static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { VirtIOGPU *g = VIRTIO_GPU(vdev); + VirtIOGPUGL *gl = VIRTIO_GPU_GL(vdev); struct virtio_gpu_ctrl_command *cmd; if (!virtio_queue_ready(vq)) { return; } - if (!g->renderer_inited) { + if (!gl->renderer_inited) { virtio_gpu_virgl_init(g); - g->renderer_inited = true; + gl->renderer_inited = true; } cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command)); @@ -89,12 +91,13 @@ static void virtio_gpu_gl_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) static void virtio_gpu_gl_reset(VirtIODevice *vdev) { VirtIOGPU *g = VIRTIO_GPU(vdev); + VirtIOGPUGL *gl = VIRTIO_GPU_GL(vdev); virtio_gpu_reset(vdev); - if (g->renderer_inited) { + if (gl->renderer_inited) { if (g->parent_obj.renderer_blocked) { - g->renderer_reset = true; + gl->renderer_reset = true; } else { virtio_gpu_virgl_reset(g); } diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h index 0d402aef7c..8ca2c55d9a 100644 --- a/include/hw/virtio/virtio-gpu.h +++ b/include/hw/virtio/virtio-gpu.h @@ -151,8 +151,6 @@ struct VirtIOGPU { uint64_t hostmem; bool processing_cmdq; - bool renderer_inited; - bool renderer_reset; QEMUTimer *fence_poll; QEMUTimer *print_stats; @@ -177,6 +175,9 @@ struct VirtIOGPUClass { struct VirtIOGPUGL { struct VirtIOGPU parent_obj; + + bool renderer_inited; + bool renderer_reset; }; struct VhostUserGPU { From 17cdac0b51bc4ad7a68c3e5e0b1718729b74d512 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:45 +0200 Subject: [PATCH 0359/3028] virtio-gpu: add virtio-gpu-gl-pci Add pci proxy for virtio-gpu-gl-device. Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-15-kraxel@redhat.com> --- hw/display/meson.build | 5 ++++ hw/display/virtio-gpu-pci-gl.c | 55 ++++++++++++++++++++++++++++++++++ util/module.c | 2 ++ 3 files changed, 62 insertions(+) create mode 100644 hw/display/virtio-gpu-pci-gl.c diff --git a/hw/display/meson.build b/hw/display/meson.build index 3c3e47c47e..8ca2e7ab63 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -73,6 +73,11 @@ if config_all_devices.has_key('CONFIG_VIRTIO_PCI') virtio_gpu_pci_ss.add(when: ['CONFIG_VHOST_USER_GPU', 'CONFIG_VIRTIO_PCI'], if_true: files('vhost-user-gpu-pci.c')) hw_display_modules += {'virtio-gpu-pci': virtio_gpu_pci_ss} + + virtio_gpu_pci_gl_ss = ss.source_set() + virtio_gpu_pci_gl_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_PCI', 'CONFIG_VIRGL', opengl], + if_true: [files('virtio-gpu-pci-gl.c'), pixman]) + hw_display_modules += {'virtio-gpu-pci-gl': virtio_gpu_pci_gl_ss} endif if config_all_devices.has_key('CONFIG_VIRTIO_VGA') diff --git a/hw/display/virtio-gpu-pci-gl.c b/hw/display/virtio-gpu-pci-gl.c new file mode 100644 index 0000000000..902dda3452 --- /dev/null +++ b/hw/display/virtio-gpu-pci-gl.c @@ -0,0 +1,55 @@ +/* + * Virtio video device + * + * Copyright Red Hat + * + * Authors: + * Dave Airlie + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-gpu-pci.h" +#include "qom/object.h" + +#define TYPE_VIRTIO_GPU_GL_PCI "virtio-gpu-gl-pci" +typedef struct VirtIOGPUGLPCI VirtIOGPUGLPCI; +DECLARE_INSTANCE_CHECKER(VirtIOGPUGLPCI, VIRTIO_GPU_GL_PCI, + TYPE_VIRTIO_GPU_GL_PCI) + +struct VirtIOGPUGLPCI { + VirtIOGPUPCIBase parent_obj; + VirtIOGPUGL vdev; +}; + +static void virtio_gpu_gl_initfn(Object *obj) +{ + VirtIOGPUGLPCI *dev = VIRTIO_GPU_GL_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_GPU_GL); + VIRTIO_GPU_PCI_BASE(obj)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); +} + +static const VirtioPCIDeviceTypeInfo virtio_gpu_gl_pci_info = { + .generic_name = TYPE_VIRTIO_GPU_GL_PCI, + .parent = TYPE_VIRTIO_GPU_PCI_BASE, + .instance_size = sizeof(VirtIOGPUGLPCI), + .instance_init = virtio_gpu_gl_initfn, +}; + +static void virtio_gpu_gl_pci_register_types(void) +{ + virtio_pci_types_register(&virtio_gpu_gl_pci_info); +} + +type_init(virtio_gpu_gl_pci_register_types) diff --git a/util/module.c b/util/module.c index c8f3e5a0a7..fc545c35bc 100644 --- a/util/module.c +++ b/util/module.c @@ -183,6 +183,7 @@ static const struct { { "ui-spice-app", "chardev-spice" }, { "hw-display-virtio-gpu-gl", "hw-display-virtio-gpu" }, + { "hw-display-virtio-gpu-pci-gl", "hw-display-virtio-gpu-pci" }, #ifdef CONFIG_OPENGL { "ui-egl-headless", "ui-opengl" }, @@ -307,6 +308,7 @@ static struct { { "vhost-user-gpu", "hw-", "display-virtio-gpu" }, { "virtio-gpu-pci-base", "hw-", "display-virtio-gpu-pci" }, { "virtio-gpu-pci", "hw-", "display-virtio-gpu-pci" }, + { "virtio-gpu-gl-pci", "hw-", "display-virtio-gpu-pci-gl" }, { "vhost-user-gpu-pci", "hw-", "display-virtio-gpu-pci" }, { "virtio-gpu-ccw", "hw-", "s390x-virtio-gpu-ccw" }, { "virtio-vga-base", "hw-", "display-virtio-vga" }, From 48ecfbf12c1f51281aaabaf8e03494291a18862c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:46 +0200 Subject: [PATCH 0360/3028] modules: add have_vga Introduce a symbol which can be used to prevent display modules which need vga support being loaded into system emulators with CONFIG_VGA=n. Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-16-kraxel@redhat.com> --- hw/display/vga.c | 2 ++ include/hw/display/vga.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/hw/display/vga.c b/hw/display/vga.c index 836ad50c7b..28a90e30d0 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -39,6 +39,8 @@ //#define DEBUG_VGA_MEM //#define DEBUG_VGA_REG +bool have_vga = true; + /* 16 state changes per vertical frame @60 Hz */ #define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60) diff --git a/include/hw/display/vga.h b/include/hw/display/vga.h index ca0003dbfd..5f7825e0e3 100644 --- a/include/hw/display/vga.h +++ b/include/hw/display/vga.h @@ -11,6 +11,12 @@ #include "exec/hwaddr.h" +/* + * modules can reference this symbol to avoid being loaded + * into system emulators without vga support + */ +extern bool have_vga; + enum vga_retrace_method { VGA_RETRACE_DUMB, VGA_RETRACE_PRECISE From b36eb8860f8f4a9c6f131c3fd380116a3017e022 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 30 Apr 2021 13:35:47 +0200 Subject: [PATCH 0361/3028] virtio-gpu: add virtio-vga-gl Add pci proxy for virtio-gpu-gl-device, with vga compatibility. Signed-off-by: Gerd Hoffmann Message-id: 20210430113547.1816178-1-kraxel@redhat.com Message-Id: <20210430113547.1816178-17-kraxel@redhat.com> --- hw/display/meson.build | 5 ++++ hw/display/virtio-vga-gl.c | 47 ++++++++++++++++++++++++++++++++++++++ util/module.c | 2 ++ 3 files changed, 54 insertions(+) create mode 100644 hw/display/virtio-vga-gl.c diff --git a/hw/display/meson.build b/hw/display/meson.build index 8ca2e7ab63..612cd6582d 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -87,6 +87,11 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA') virtio_vga_ss.add(when: 'CONFIG_VHOST_USER_VGA', if_true: files('vhost-user-vga.c')) hw_display_modules += {'virtio-vga': virtio_vga_ss} + + virtio_vga_gl_ss = ss.source_set() + virtio_vga_gl_ss.add(when: ['CONFIG_VIRTIO_VGA', 'CONFIG_VIRGL', opengl], + if_true: [files('virtio-vga-gl.c'), pixman]) + hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss} endif specific_ss.add(when: [x11, opengl, 'CONFIG_MILKYMIST_TMU2'], if_true: files('milkymist-tmu2.c')) diff --git a/hw/display/virtio-vga-gl.c b/hw/display/virtio-vga-gl.c new file mode 100644 index 0000000000..c971340ebb --- /dev/null +++ b/hw/display/virtio-vga-gl.c @@ -0,0 +1,47 @@ +#include "qemu/osdep.h" +#include "hw/pci/pci.h" +#include "hw/qdev-properties.h" +#include "hw/virtio/virtio-gpu.h" +#include "hw/display/vga.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "virtio-vga.h" +#include "qom/object.h" + +#define TYPE_VIRTIO_VGA_GL "virtio-vga-gl" + +typedef struct VirtIOVGAGL VirtIOVGAGL; +DECLARE_INSTANCE_CHECKER(VirtIOVGAGL, VIRTIO_VGA_GL, + TYPE_VIRTIO_VGA_GL) + +struct VirtIOVGAGL { + VirtIOVGABase parent_obj; + + VirtIOGPUGL vdev; +}; + +static void virtio_vga_gl_inst_initfn(Object *obj) +{ + VirtIOVGAGL *dev = VIRTIO_VGA_GL(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_GPU_GL); + VIRTIO_VGA_BASE(dev)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); +} + + +static VirtioPCIDeviceTypeInfo virtio_vga_gl_info = { + .generic_name = TYPE_VIRTIO_VGA_GL, + .parent = TYPE_VIRTIO_VGA_BASE, + .instance_size = sizeof(VirtIOVGAGL), + .instance_init = virtio_vga_gl_inst_initfn, +}; + +static void virtio_vga_register_types(void) +{ + if (have_vga) { + virtio_pci_types_register(&virtio_vga_gl_info); + } +} + +type_init(virtio_vga_register_types) diff --git a/util/module.c b/util/module.c index fc545c35bc..eee8ff2de1 100644 --- a/util/module.c +++ b/util/module.c @@ -184,6 +184,7 @@ static const struct { { "hw-display-virtio-gpu-gl", "hw-display-virtio-gpu" }, { "hw-display-virtio-gpu-pci-gl", "hw-display-virtio-gpu-pci" }, + { "hw-display-virtio-vga-gl", "hw-display-virtio-vga" }, #ifdef CONFIG_OPENGL { "ui-egl-headless", "ui-opengl" }, @@ -313,6 +314,7 @@ static struct { { "virtio-gpu-ccw", "hw-", "s390x-virtio-gpu-ccw" }, { "virtio-vga-base", "hw-", "display-virtio-vga" }, { "virtio-vga", "hw-", "display-virtio-vga" }, + { "virtio-vga-gl", "hw-", "display-virtio-vga-gl" }, { "vhost-user-vga", "hw-", "display-virtio-vga" }, { "chardev-braille", "chardev-", "baum" }, { "chardev-spicevmc", "chardev-", "spice" }, From 5f1fffa0a6575cfb39834d36c52e973a95dfb275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 28 Apr 2021 14:13:16 +0100 Subject: [PATCH 0362/3028] docs: fix link in sbsa description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A trailing _ makes all the difference to the rendered link. Signed-off-by: Alex Bennée Message-id: 20210428131316.31390-1-alex.bennee@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- docs/system/arm/sbsa.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/system/arm/sbsa.rst b/docs/system/arm/sbsa.rst index b8ecfdb62f..27b0999aac 100644 --- a/docs/system/arm/sbsa.rst +++ b/docs/system/arm/sbsa.rst @@ -4,7 +4,7 @@ Arm Server Base System Architecture Reference board (``sbsa-ref``) While the `virt` board is a generic board platform that doesn't match any real hardware the `sbsa-ref` board intends to look like real hardware. The `Server Base System Architecture -` defines a +`_ defines a minimum base line of hardware support and importantly how the firmware reports that to any operating system. It is a static system that reports a very minimal DT to the firmware for non-discoverable From 68948d18224b93361e2880e2946ab268d0c650d7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 27 Apr 2021 14:41:08 -0700 Subject: [PATCH 0363/3028] linux-user/aarch64: Enable hwcap for RND, BTI, and MTE These three features are already enabled by TCG, but are missing their hwcap bits. Update HWCAP2 from linux v5.12. Cc: qemu-stable@nongnu.org (for 6.0.1) Buglink: https://bugs.launchpad.net/bugs/1926044 Signed-off-by: Richard Henderson Message-id: 20210427214108.88503-1-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- linux-user/elfload.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index c6731013fd..fc9c4f12be 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -586,6 +586,16 @@ enum { ARM_HWCAP2_A64_SVESM4 = 1 << 6, ARM_HWCAP2_A64_FLAGM2 = 1 << 7, ARM_HWCAP2_A64_FRINT = 1 << 8, + ARM_HWCAP2_A64_SVEI8MM = 1 << 9, + ARM_HWCAP2_A64_SVEF32MM = 1 << 10, + ARM_HWCAP2_A64_SVEF64MM = 1 << 11, + ARM_HWCAP2_A64_SVEBF16 = 1 << 12, + ARM_HWCAP2_A64_I8MM = 1 << 13, + ARM_HWCAP2_A64_BF16 = 1 << 14, + ARM_HWCAP2_A64_DGH = 1 << 15, + ARM_HWCAP2_A64_RNG = 1 << 16, + ARM_HWCAP2_A64_BTI = 1 << 17, + ARM_HWCAP2_A64_MTE = 1 << 18, }; #define ELF_HWCAP get_elf_hwcap() @@ -640,6 +650,9 @@ static uint32_t get_elf_hwcap2(void) GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP); GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2); GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT); + GET_FEATURE_ID(aa64_rndr, ARM_HWCAP2_A64_RNG); + GET_FEATURE_ID(aa64_bti, ARM_HWCAP2_A64_BTI); + GET_FEATURE_ID(aa64_mte, ARM_HWCAP2_A64_MTE); return hwcaps; } From eb849d8fd542329b299be5a894d7e272eed16a49 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 20 Apr 2021 13:31:06 +0100 Subject: [PATCH 0364/3028] target/arm: Fix tlbbits calculation in tlbi_aa64_vae2is_write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In tlbi_aa64_vae2is_write() the calculation bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_E2 : ARMMMUIdx_SE2, pageaddr) has the two arms of the ?: expression reversed. Fix the bug. Fixes: b6ad6062f1e5 Reported-by: Rebecca Cran Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Rémi Denis-Courmont Reviewed-by: Rebecca Cran Message-id: 20210420123106.10861-1-peter.maydell@linaro.org --- target/arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 9b1b98705f..3b365a78cb 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4742,7 +4742,7 @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t pageaddr = sextract64(value << 12, 0, 56); bool secure = arm_is_secure_below_el3(env); int mask = secure ? ARMMMUIdxBit_SE2 : ARMMMUIdxBit_E2; - int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_E2 : ARMMMUIdx_SE2, + int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_SE2 : ARMMMUIdx_E2, pageaddr); tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits); From b5aa664679510645fa01f55590db60ca2657f7fc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:28 +0100 Subject: [PATCH 0365/3028] target/arm: Move constant expanders to translate.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the constant expanders defined in translate.c are generically useful and will be used by the separate C files for VFP and Neon once they are created; move the expander definitions to translate.h. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-2-peter.maydell@linaro.org --- target/arm/translate.c | 24 ------------------------ target/arm/translate.h | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 43ff0d4b8a..bb9e228d1a 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -109,30 +109,6 @@ static void arm_gen_condlabel(DisasContext *s) } } -/* - * Constant expanders for the decoders. - */ - -static int negate(DisasContext *s, int x) -{ - return -x; -} - -static int plus_2(DisasContext *s, int x) -{ - return x + 2; -} - -static int times_2(DisasContext *s, int x) -{ - return x * 2; -} - -static int times_4(DisasContext *s, int x) -{ - return x * 4; -} - /* Flags for the disas_set_da_iss info argument: * lower bits hold the Rt register number, higher bits are flags. */ diff --git a/target/arm/translate.h b/target/arm/translate.h index ccf60c96d8..b5b2161959 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -118,6 +118,30 @@ extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF; extern TCGv_i64 cpu_exclusive_addr; extern TCGv_i64 cpu_exclusive_val; +/* + * Constant expanders for the decoders. + */ + +static inline int negate(DisasContext *s, int x) +{ + return -x; +} + +static inline int plus_2(DisasContext *s, int x) +{ + return x + 2; +} + +static inline int times_2(DisasContext *s, int x) +{ + return x * 2; +} + +static inline int times_4(DisasContext *s, int x) +{ + return x * 4; +} + static inline int arm_dc_feature(DisasContext *dc, int feature) { return (dc->features & (1ULL << feature)) != 0; From d9318a5f9c32225a9d5365758ae5a329b55de2fe Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:29 +0100 Subject: [PATCH 0366/3028] target/arm: Share unallocated_encoding() and gen_exception_insn() The unallocated_encoding() function is the same in both translate-a64.c and translate.c; make the translate.c function global and drop the translate-a64.c version. To do this we need to also share gen_exception_insn(), which currently exists in two slightly different versions for A32 and A64: merge those into a single function that can work for both. This will be useful for splitting up translate.c, which will require unallocated_encoding() to no longer be file-local. It's also hopefully less confusing to have only one version of the function rather than two. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-3-peter.maydell@linaro.org --- target/arm/translate-a64.c | 15 --------------- target/arm/translate-a64.h | 2 -- target/arm/translate.c | 14 +++++++++----- target/arm/translate.h | 3 +++ 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 95897e63af..0c80d0b505 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -359,14 +359,6 @@ static void gen_exception_internal_insn(DisasContext *s, uint64_t pc, int excp) s->base.is_jmp = DISAS_NORETURN; } -static void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, - uint32_t syndrome, uint32_t target_el) -{ - gen_a64_set_pc_im(pc); - gen_exception(excp, syndrome, target_el); - s->base.is_jmp = DISAS_NORETURN; -} - static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syndrome) { TCGv_i32 tcg_syn; @@ -437,13 +429,6 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) } } -void unallocated_encoding(DisasContext *s) -{ - /* Unallocated and reserved encodings are uncategorized */ - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(), - default_exception_el(s)); -} - static void init_tmp_a64_array(DisasContext *s) { #ifdef CONFIG_DEBUG_TCG diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h index 868d355048..89437276e7 100644 --- a/target/arm/translate-a64.h +++ b/target/arm/translate-a64.h @@ -18,8 +18,6 @@ #ifndef TARGET_ARM_TRANSLATE_A64_H #define TARGET_ARM_TRANSLATE_A64_H -void unallocated_encoding(DisasContext *s); - #define unsupported_encoding(s, insn) \ do { \ qemu_log_mask(LOG_UNIMP, \ diff --git a/target/arm/translate.c b/target/arm/translate.c index bb9e228d1a..8b71b1c41b 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -1069,11 +1069,15 @@ static void gen_exception_internal_insn(DisasContext *s, uint32_t pc, int excp) s->base.is_jmp = DISAS_NORETURN; } -static void gen_exception_insn(DisasContext *s, uint32_t pc, int excp, - int syn, uint32_t target_el) +void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, + uint32_t syn, uint32_t target_el) { - gen_set_condexec(s); - gen_set_pc_im(s, pc); + if (s->aarch64) { + gen_a64_set_pc_im(pc); + } else { + gen_set_condexec(s); + gen_set_pc_im(s, pc); + } gen_exception(excp, syn, target_el); s->base.is_jmp = DISAS_NORETURN; } @@ -1090,7 +1094,7 @@ static void gen_exception_bkpt_insn(DisasContext *s, uint32_t syn) s->base.is_jmp = DISAS_NORETURN; } -static void unallocated_encoding(DisasContext *s) +void unallocated_encoding(DisasContext *s) { /* Unallocated and reserved encodings are uncategorized */ gen_exception_insn(s, s->pc_curr, EXCP_UDEF, syn_uncategorized(), diff --git a/target/arm/translate.h b/target/arm/translate.h index b5b2161959..8130a3be29 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -229,6 +229,9 @@ void arm_free_cc(DisasCompare *cmp); void arm_jump_cc(DisasCompare *cmp, TCGLabel *label); void arm_gen_test_cc(int cc, TCGLabel *label); MemOp pow2_align(unsigned i); +void unallocated_encoding(DisasContext *s); +void gen_exception_insn(DisasContext *s, uint64_t pc, int excp, + uint32_t syn, uint32_t target_el); /* Return state of Alternate Half-precision flag, caller frees result */ static inline TCGv_i32 get_ahp_flag(void) From 5ce389f2e76e8aa318ec734cc12c0f0e657a9e0e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:30 +0100 Subject: [PATCH 0367/3028] target/arm: Make functions used by m-nocp global We want to split out the .c.inc files which are currently included into translate.c so they are separate compilation units. To do this we need to make some functions which are currently file-local to translate.c have global scope; create a translate-a32.h paralleling the existing translate-a64.h as a place for these declarations to live, so that code moved into the new compilation units can call them. The functions made global here are those required by the m-nocp.decode functions, except that I have converted the whole family of {read,write}_neon_element* and also both the load_cpu and store_cpu functions for consistency, even though m-nocp only wants a few functions from each. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-4-peter.maydell@linaro.org --- target/arm/translate-a32.h | 57 ++++++++++++++++++++++++++++++++++ target/arm/translate-vfp.c.inc | 2 +- target/arm/translate.c | 39 +++++------------------ 3 files changed, 65 insertions(+), 33 deletions(-) create mode 100644 target/arm/translate-a32.h diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h new file mode 100644 index 0000000000..c5d937b27e --- /dev/null +++ b/target/arm/translate-a32.h @@ -0,0 +1,57 @@ +/* + * AArch32 translation, common definitions. + * + * Copyright (c) 2021 Linaro, Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef TARGET_ARM_TRANSLATE_A64_H +#define TARGET_ARM_TRANSLATE_A64_H + +void load_reg_var(DisasContext *s, TCGv_i32 var, int reg); +void arm_gen_condlabel(DisasContext *s); +bool vfp_access_check(DisasContext *s); +void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop); +void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop); +void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop); +void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop); + +static inline TCGv_i32 load_cpu_offset(int offset) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_ld_i32(tmp, cpu_env, offset); + return tmp; +} + +#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name)) + +static inline void store_cpu_offset(TCGv_i32 var, int offset) +{ + tcg_gen_st_i32(var, cpu_env, offset); + tcg_temp_free_i32(var); +} + +#define store_cpu_field(var, name) \ + store_cpu_offset(var, offsetof(CPUARMState, name)) + +/* Create a new temporary and set it to the value of a CPU register. */ +static inline TCGv_i32 load_reg(DisasContext *s, int reg) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + load_reg_var(s, tmp, reg); + return tmp; +} + +#endif diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c.inc index e20d9c7ba6..c368ada877 100644 --- a/target/arm/translate-vfp.c.inc +++ b/target/arm/translate-vfp.c.inc @@ -191,7 +191,7 @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled) * The most usual kind of VFP access check, for everything except * FMXR/FMRX to the always-available special registers. */ -static bool vfp_access_check(DisasContext *s) +bool vfp_access_check(DisasContext *s) { return full_vfp_access_check(s, false); } diff --git a/target/arm/translate.c b/target/arm/translate.c index 8b71b1c41b..3c1d52279b 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -50,6 +50,7 @@ #define ENABLE_ARCH_8 arm_dc_feature(s, ARM_FEATURE_V8) #include "translate.h" +#include "translate-a32.h" #if defined(CONFIG_USER_ONLY) #define IS_USER(s) 1 @@ -101,7 +102,7 @@ void arm_translate_init(void) } /* Generate a label used for skipping this instruction */ -static void arm_gen_condlabel(DisasContext *s) +void arm_gen_condlabel(DisasContext *s) { if (!s->condjmp) { s->condlabel = gen_new_label(); @@ -187,24 +188,6 @@ static inline int get_a32_user_mem_index(DisasContext *s) } } -static inline TCGv_i32 load_cpu_offset(int offset) -{ - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_ld_i32(tmp, cpu_env, offset); - return tmp; -} - -#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name)) - -static inline void store_cpu_offset(TCGv_i32 var, int offset) -{ - tcg_gen_st_i32(var, cpu_env, offset); - tcg_temp_free_i32(var); -} - -#define store_cpu_field(var, name) \ - store_cpu_offset(var, offsetof(CPUARMState, name)) - /* The architectural value of PC. */ static uint32_t read_pc(DisasContext *s) { @@ -212,7 +195,7 @@ static uint32_t read_pc(DisasContext *s) } /* Set a variable to the value of a CPU register. */ -static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg) +void load_reg_var(DisasContext *s, TCGv_i32 var, int reg) { if (reg == 15) { tcg_gen_movi_i32(var, read_pc(s)); @@ -221,14 +204,6 @@ static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg) } } -/* Create a new temporary and set it to the value of a CPU register. */ -static inline TCGv_i32 load_reg(DisasContext *s, int reg) -{ - TCGv_i32 tmp = tcg_temp_new_i32(); - load_reg_var(s, tmp, reg); - return tmp; -} - /* * Create a new temp, REG + OFS, except PC is ALIGN(PC, 4). * This is used for load/store for which use of PC implies (literal), @@ -1208,7 +1183,7 @@ static inline void vfp_store_reg32(TCGv_i32 var, int reg) tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg)); } -static void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop) +void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop) { long off = neon_element_offset(reg, ele, memop); @@ -1234,7 +1209,7 @@ static void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop) } } -static void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop) +void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop) { long off = neon_element_offset(reg, ele, memop); @@ -1253,7 +1228,7 @@ static void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop) } } -static void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop) +void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop) { long off = neon_element_offset(reg, ele, memop); @@ -1272,7 +1247,7 @@ static void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop) } } -static void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop) +void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop) { long off = neon_element_offset(reg, ele, memop); From 9a5071abbce614c52d0e72bdbd688cd4e2a9ee46 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:31 +0100 Subject: [PATCH 0368/3028] target/arm: Split m-nocp trans functions into their own file Currently the trans functions for m-nocp.decode all live in translate-vfp.inc.c; move them out into their own translation unit, translate-m-nocp.c. The trans_* functions here are pure code motion with no changes. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-5-peter.maydell@linaro.org --- target/arm/meson.build | 3 +- target/arm/translate-a32.h | 3 + target/arm/translate-m-nocp.c | 221 +++++++++++++++++++++++++++++++++ target/arm/translate-vfp.c.inc | 196 ----------------------------- target/arm/translate.c | 1 - 5 files changed, 226 insertions(+), 198 deletions(-) create mode 100644 target/arm/translate-m-nocp.c diff --git a/target/arm/meson.build b/target/arm/meson.build index 15b936c101..bbee1325bc 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -5,7 +5,7 @@ gen = [ decodetree.process('neon-ls.decode', extra_args: '--static-decode=disas_neon_ls'), decodetree.process('vfp.decode', extra_args: '--static-decode=disas_vfp'), decodetree.process('vfp-uncond.decode', extra_args: '--static-decode=disas_vfp_uncond'), - decodetree.process('m-nocp.decode', extra_args: '--static-decode=disas_m_nocp'), + decodetree.process('m-nocp.decode', extra_args: '--decode=disas_m_nocp'), decodetree.process('a32.decode', extra_args: '--static-decode=disas_a32'), decodetree.process('a32-uncond.decode', extra_args: '--static-decode=disas_a32_uncond'), decodetree.process('t32.decode', extra_args: '--static-decode=disas_t32'), @@ -26,6 +26,7 @@ arm_ss.add(files( 'op_helper.c', 'tlb_helper.c', 'translate.c', + 'translate-m-nocp.c', 'vec_helper.c', 'vfp_helper.c', 'cpu_tcg.c', diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h index c5d937b27e..cb451f70a4 100644 --- a/target/arm/translate-a32.h +++ b/target/arm/translate-a32.h @@ -20,6 +20,9 @@ #ifndef TARGET_ARM_TRANSLATE_A64_H #define TARGET_ARM_TRANSLATE_A64_H +/* Prototypes for autogenerated disassembler functions */ +bool disas_m_nocp(DisasContext *dc, uint32_t insn); + void load_reg_var(DisasContext *s, TCGv_i32 var, int reg); void arm_gen_condlabel(DisasContext *s); bool vfp_access_check(DisasContext *s); diff --git a/target/arm/translate-m-nocp.c b/target/arm/translate-m-nocp.c new file mode 100644 index 0000000000..d47eb8e153 --- /dev/null +++ b/target/arm/translate-m-nocp.c @@ -0,0 +1,221 @@ +/* + * ARM translation: M-profile NOCP special-case instructions + * + * Copyright (c) 2020 Linaro, Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "tcg/tcg-op.h" +#include "translate.h" +#include "translate-a32.h" + +#include "decode-m-nocp.c.inc" + +/* + * Decode VLLDM and VLSTM are nonstandard because: + * * if there is no FPU then these insns must NOP in + * Secure state and UNDEF in Nonsecure state + * * if there is an FPU then these insns do not have + * the usual behaviour that vfp_access_check() provides of + * being controlled by CPACR/NSACR enable bits or the + * lazy-stacking logic. + */ +static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a) +{ + TCGv_i32 fptr; + + if (!arm_dc_feature(s, ARM_FEATURE_M) || + !arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + + if (a->op) { + /* + * T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not + * to take the IMPDEF option to make memory accesses to the stack + * slots that correspond to the D16-D31 registers (discarding + * read data and writing UNKNOWN values), so for us the T2 + * encoding behaves identically to the T1 encoding. + */ + if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { + return false; + } + } else { + /* + * T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs. + * This is currently architecturally impossible, but we add the + * check to stay in line with the pseudocode. Note that we must + * emit code for the UNDEF so it takes precedence over the NOCP. + */ + if (dc_isar_feature(aa32_simd_r32, s)) { + unallocated_encoding(s); + return true; + } + } + + /* + * If not secure, UNDEF. We must emit code for this + * rather than returning false so that this takes + * precedence over the m-nocp.decode NOCP fallback. + */ + if (!s->v8m_secure) { + unallocated_encoding(s); + return true; + } + /* If no fpu, NOP. */ + if (!dc_isar_feature(aa32_vfp, s)) { + return true; + } + + fptr = load_reg(s, a->rn); + if (a->l) { + gen_helper_v7m_vlldm(cpu_env, fptr); + } else { + gen_helper_v7m_vlstm(cpu_env, fptr); + } + tcg_temp_free_i32(fptr); + + /* End the TB, because we have updated FP control bits */ + s->base.is_jmp = DISAS_UPDATE_EXIT; + return true; +} + +static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a) +{ + int btmreg, topreg; + TCGv_i64 zero; + TCGv_i32 aspen, sfpa; + + if (!dc_isar_feature(aa32_m_sec_state, s)) { + /* Before v8.1M, fall through in decode to NOCP check */ + return false; + } + + /* Explicitly UNDEF because this takes precedence over NOCP */ + if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) { + unallocated_encoding(s); + return true; + } + + if (!dc_isar_feature(aa32_vfp_simd, s)) { + /* NOP if we have neither FP nor MVE */ + return true; + } + + /* + * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no + * active floating point context so we must NOP (without doing + * any lazy state preservation or the NOCP check). + */ + aspen = load_cpu_field(v7m.fpccr[M_REG_S]); + sfpa = load_cpu_field(v7m.control[M_REG_S]); + tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); + tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); + tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK); + tcg_gen_or_i32(sfpa, sfpa, aspen); + arm_gen_condlabel(s); + tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel); + + if (s->fp_excp_el != 0) { + gen_exception_insn(s, s->pc_curr, EXCP_NOCP, + syn_uncategorized(), s->fp_excp_el); + return true; + } + + topreg = a->vd + a->imm - 1; + btmreg = a->vd; + + /* Convert to Sreg numbers if the insn specified in Dregs */ + if (a->size == 3) { + topreg = topreg * 2 + 1; + btmreg *= 2; + } + + if (topreg > 63 || (topreg > 31 && !(topreg & 1))) { + /* UNPREDICTABLE: we choose to undef */ + unallocated_encoding(s); + return true; + } + + /* Silently ignore requests to clear D16-D31 if they don't exist */ + if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) { + topreg = 31; + } + + if (!vfp_access_check(s)) { + return true; + } + + /* Zero the Sregs from btmreg to topreg inclusive. */ + zero = tcg_const_i64(0); + if (btmreg & 1) { + write_neon_element64(zero, btmreg >> 1, 1, MO_32); + btmreg++; + } + for (; btmreg + 1 <= topreg; btmreg += 2) { + write_neon_element64(zero, btmreg >> 1, 0, MO_64); + } + if (btmreg == topreg) { + write_neon_element64(zero, btmreg >> 1, 0, MO_32); + btmreg++; + } + assert(btmreg == topreg + 1); + /* TODO: when MVE is implemented, zero VPR here */ + return true; +} + +static bool trans_NOCP(DisasContext *s, arg_nocp *a) +{ + /* + * Handle M-profile early check for disabled coprocessor: + * all we need to do here is emit the NOCP exception if + * the coprocessor is disabled. Otherwise we return false + * and the real VFP/etc decode will handle the insn. + */ + assert(arm_dc_feature(s, ARM_FEATURE_M)); + + if (a->cp == 11) { + a->cp = 10; + } + if (arm_dc_feature(s, ARM_FEATURE_V8_1M) && + (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) { + /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */ + a->cp = 10; + } + + if (a->cp != 10) { + gen_exception_insn(s, s->pc_curr, EXCP_NOCP, + syn_uncategorized(), default_exception_el(s)); + return true; + } + + if (s->fp_excp_el != 0) { + gen_exception_insn(s, s->pc_curr, EXCP_NOCP, + syn_uncategorized(), s->fp_excp_el); + return true; + } + + return false; +} + +static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a) +{ + /* This range needs a coprocessor check for v8.1M and later only */ + if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { + return false; + } + return trans_NOCP(s, a); +} diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c.inc index c368ada877..500492f02f 100644 --- a/target/arm/translate-vfp.c.inc +++ b/target/arm/translate-vfp.c.inc @@ -3800,202 +3800,6 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a) return true; } -/* - * Decode VLLDM and VLSTM are nonstandard because: - * * if there is no FPU then these insns must NOP in - * Secure state and UNDEF in Nonsecure state - * * if there is an FPU then these insns do not have - * the usual behaviour that vfp_access_check() provides of - * being controlled by CPACR/NSACR enable bits or the - * lazy-stacking logic. - */ -static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a) -{ - TCGv_i32 fptr; - - if (!arm_dc_feature(s, ARM_FEATURE_M) || - !arm_dc_feature(s, ARM_FEATURE_V8)) { - return false; - } - - if (a->op) { - /* - * T2 encoding ({D0-D31} reglist): v8.1M and up. We choose not - * to take the IMPDEF option to make memory accesses to the stack - * slots that correspond to the D16-D31 registers (discarding - * read data and writing UNKNOWN values), so for us the T2 - * encoding behaves identically to the T1 encoding. - */ - if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { - return false; - } - } else { - /* - * T1 encoding ({D0-D15} reglist); undef if we have 32 Dregs. - * This is currently architecturally impossible, but we add the - * check to stay in line with the pseudocode. Note that we must - * emit code for the UNDEF so it takes precedence over the NOCP. - */ - if (dc_isar_feature(aa32_simd_r32, s)) { - unallocated_encoding(s); - return true; - } - } - - /* - * If not secure, UNDEF. We must emit code for this - * rather than returning false so that this takes - * precedence over the m-nocp.decode NOCP fallback. - */ - if (!s->v8m_secure) { - unallocated_encoding(s); - return true; - } - /* If no fpu, NOP. */ - if (!dc_isar_feature(aa32_vfp, s)) { - return true; - } - - fptr = load_reg(s, a->rn); - if (a->l) { - gen_helper_v7m_vlldm(cpu_env, fptr); - } else { - gen_helper_v7m_vlstm(cpu_env, fptr); - } - tcg_temp_free_i32(fptr); - - /* End the TB, because we have updated FP control bits */ - s->base.is_jmp = DISAS_UPDATE_EXIT; - return true; -} - -static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a) -{ - int btmreg, topreg; - TCGv_i64 zero; - TCGv_i32 aspen, sfpa; - - if (!dc_isar_feature(aa32_m_sec_state, s)) { - /* Before v8.1M, fall through in decode to NOCP check */ - return false; - } - - /* Explicitly UNDEF because this takes precedence over NOCP */ - if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) { - unallocated_encoding(s); - return true; - } - - if (!dc_isar_feature(aa32_vfp_simd, s)) { - /* NOP if we have neither FP nor MVE */ - return true; - } - - /* - * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no - * active floating point context so we must NOP (without doing - * any lazy state preservation or the NOCP check). - */ - aspen = load_cpu_field(v7m.fpccr[M_REG_S]); - sfpa = load_cpu_field(v7m.control[M_REG_S]); - tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); - tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK); - tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK); - tcg_gen_or_i32(sfpa, sfpa, aspen); - arm_gen_condlabel(s); - tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel); - - if (s->fp_excp_el != 0) { - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), s->fp_excp_el); - return true; - } - - topreg = a->vd + a->imm - 1; - btmreg = a->vd; - - /* Convert to Sreg numbers if the insn specified in Dregs */ - if (a->size == 3) { - topreg = topreg * 2 + 1; - btmreg *= 2; - } - - if (topreg > 63 || (topreg > 31 && !(topreg & 1))) { - /* UNPREDICTABLE: we choose to undef */ - unallocated_encoding(s); - return true; - } - - /* Silently ignore requests to clear D16-D31 if they don't exist */ - if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) { - topreg = 31; - } - - if (!vfp_access_check(s)) { - return true; - } - - /* Zero the Sregs from btmreg to topreg inclusive. */ - zero = tcg_const_i64(0); - if (btmreg & 1) { - write_neon_element64(zero, btmreg >> 1, 1, MO_32); - btmreg++; - } - for (; btmreg + 1 <= topreg; btmreg += 2) { - write_neon_element64(zero, btmreg >> 1, 0, MO_64); - } - if (btmreg == topreg) { - write_neon_element64(zero, btmreg >> 1, 0, MO_32); - btmreg++; - } - assert(btmreg == topreg + 1); - /* TODO: when MVE is implemented, zero VPR here */ - return true; -} - -static bool trans_NOCP(DisasContext *s, arg_nocp *a) -{ - /* - * Handle M-profile early check for disabled coprocessor: - * all we need to do here is emit the NOCP exception if - * the coprocessor is disabled. Otherwise we return false - * and the real VFP/etc decode will handle the insn. - */ - assert(arm_dc_feature(s, ARM_FEATURE_M)); - - if (a->cp == 11) { - a->cp = 10; - } - if (arm_dc_feature(s, ARM_FEATURE_V8_1M) && - (a->cp == 8 || a->cp == 9 || a->cp == 14 || a->cp == 15)) { - /* in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */ - a->cp = 10; - } - - if (a->cp != 10) { - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), default_exception_el(s)); - return true; - } - - if (s->fp_excp_el != 0) { - gen_exception_insn(s, s->pc_curr, EXCP_NOCP, - syn_uncategorized(), s->fp_excp_el); - return true; - } - - return false; -} - -static bool trans_NOCP_8_1(DisasContext *s, arg_nocp *a) -{ - /* This range needs a coprocessor check for v8.1M and later only */ - if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { - return false; - } - return trans_NOCP(s, a); -} - static bool trans_VINS(DisasContext *s, arg_VINS *a) { TCGv_i32 rd, rm; diff --git a/target/arm/translate.c b/target/arm/translate.c index 3c1d52279b..46f6dfcf42 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -1273,7 +1273,6 @@ static TCGv_ptr vfp_reg_ptr(bool dp, int reg) #define ARM_CP_RW_BIT (1 << 20) /* Include the VFP and Neon decoders */ -#include "decode-m-nocp.c.inc" #include "translate-vfp.c.inc" #include "translate-neon.c.inc" From 73d2f5d2bbbfbe1be6930ae388f92946e913dcc9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:32 +0100 Subject: [PATCH 0369/3028] target/arm: Move gen_aa32 functions to translate-a32.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the various gen_aa32* functions and macros out of translate.c and into translate-a32.h. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-6-peter.maydell@linaro.org --- target/arm/translate-a32.h | 53 ++++++++++++++++++++++++++++++++++++++ target/arm/translate.c | 51 ++++++++++++------------------------ 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h index cb451f70a4..522aa83636 100644 --- a/target/arm/translate-a32.h +++ b/target/arm/translate-a32.h @@ -57,4 +57,57 @@ static inline TCGv_i32 load_reg(DisasContext *s, int reg) return tmp; } +void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val, + TCGv_i32 a32, int index, MemOp opc); +void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, + TCGv_i32 a32, int index, MemOp opc); +void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index, MemOp opc); +void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index, MemOp opc); +void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, + int index, MemOp opc); +void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, + int index, MemOp opc); +void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, + int index, MemOp opc); +void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, + int index, MemOp opc); + +#define DO_GEN_LD(SUFF, OPC) \ + static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \ + TCGv_i32 a32, int index) \ + { \ + gen_aa32_ld_i32(s, val, a32, index, OPC); \ + } + +#define DO_GEN_ST(SUFF, OPC) \ + static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \ + TCGv_i32 a32, int index) \ + { \ + gen_aa32_st_i32(s, val, a32, index, OPC); \ + } + +static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index) +{ + gen_aa32_ld_i64(s, val, a32, index, MO_Q); +} + +static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index) +{ + gen_aa32_st_i64(s, val, a32, index, MO_Q); +} + +DO_GEN_LD(8u, MO_UB) +DO_GEN_LD(16u, MO_UW) +DO_GEN_LD(32u, MO_UL) +DO_GEN_ST(8, MO_UB) +DO_GEN_ST(16, MO_UW) +DO_GEN_ST(32, MO_UL) + +#undef DO_GEN_LD +#undef DO_GEN_ST + #endif diff --git a/target/arm/translate.c b/target/arm/translate.c index 46f6dfcf42..5113cd2fea 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -899,24 +899,24 @@ static TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op) * Internal routines are used for NEON cases where the endianness * and/or alignment has already been taken into account and manipulated. */ -static void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val, - TCGv_i32 a32, int index, MemOp opc) +void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val, + TCGv_i32 a32, int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); tcg_gen_qemu_ld_i32(val, addr, index, opc); tcg_temp_free(addr); } -static void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, - TCGv_i32 a32, int index, MemOp opc) +void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, + TCGv_i32 a32, int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); tcg_gen_qemu_st_i32(val, addr, index, opc); tcg_temp_free(addr); } -static void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, - TCGv_i32 a32, int index, MemOp opc) +void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); @@ -929,8 +929,8 @@ static void gen_aa32_ld_internal_i64(DisasContext *s, TCGv_i64 val, tcg_temp_free(addr); } -static void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, - TCGv_i32 a32, int index, MemOp opc) +void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, + TCGv_i32 a32, int index, MemOp opc) { TCGv addr = gen_aa32_addr(s, a32, opc); @@ -946,26 +946,26 @@ static void gen_aa32_st_internal_i64(DisasContext *s, TCGv_i64 val, tcg_temp_free(addr); } -static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, - int index, MemOp opc) +void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, + int index, MemOp opc) { gen_aa32_ld_internal_i32(s, val, a32, index, finalize_memop(s, opc)); } -static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, - int index, MemOp opc) +void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, + int index, MemOp opc) { gen_aa32_st_internal_i32(s, val, a32, index, finalize_memop(s, opc)); } -static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, - int index, MemOp opc) +void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, + int index, MemOp opc) { gen_aa32_ld_internal_i64(s, val, a32, index, finalize_memop(s, opc)); } -static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, - int index, MemOp opc) +void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, + int index, MemOp opc) { gen_aa32_st_internal_i64(s, val, a32, index, finalize_memop(s, opc)); } @@ -984,25 +984,6 @@ static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32, gen_aa32_st_i32(s, val, a32, index, OPC); \ } -static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val, - TCGv_i32 a32, int index) -{ - gen_aa32_ld_i64(s, val, a32, index, MO_Q); -} - -static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val, - TCGv_i32 a32, int index) -{ - gen_aa32_st_i64(s, val, a32, index, MO_Q); -} - -DO_GEN_LD(8u, MO_UB) -DO_GEN_LD(16u, MO_UW) -DO_GEN_LD(32u, MO_UL) -DO_GEN_ST(8, MO_UB) -DO_GEN_ST(16, MO_UW) -DO_GEN_ST(32, MO_UL) - static inline void gen_hvc(DisasContext *s, int imm16) { /* The pre HVC helper handles cases when HVC gets trapped From 06085d6a10e11fb9df871648668b072905936566 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:33 +0100 Subject: [PATCH 0370/3028] target/arm: Move vfp_{load, store}_reg{32, 64} to translate-vfp.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions vfp_load_reg32(), vfp_load_reg64(), vfp_store_reg32() and vfp_store_reg64() are used only in translate-vfp.c.inc. Move them to that file. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-7-peter.maydell@linaro.org --- target/arm/translate-vfp.c.inc | 20 ++++++++++++++++++++ target/arm/translate.c | 20 -------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c.inc index 500492f02f..1004d1fd09 100644 --- a/target/arm/translate-vfp.c.inc +++ b/target/arm/translate-vfp.c.inc @@ -30,6 +30,26 @@ #include "decode-vfp.c.inc" #include "decode-vfp-uncond.c.inc" +static inline void vfp_load_reg64(TCGv_i64 var, int reg) +{ + tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(true, reg)); +} + +static inline void vfp_store_reg64(TCGv_i64 var, int reg) +{ + tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(true, reg)); +} + +static inline void vfp_load_reg32(TCGv_i32 var, int reg) +{ + tcg_gen_ld_i32(var, cpu_env, vfp_reg_offset(false, reg)); +} + +static inline void vfp_store_reg32(TCGv_i32 var, int reg) +{ + tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg)); +} + /* * The imm8 encodes the sign bit, enough bits to represent an exponent in * the range 01....1xx to 10....0xx, and the most significant 4 bits of diff --git a/target/arm/translate.c b/target/arm/translate.c index 5113cd2fea..c8b9cedfcf 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -1144,26 +1144,6 @@ static long vfp_reg_offset(bool dp, unsigned reg) } } -static inline void vfp_load_reg64(TCGv_i64 var, int reg) -{ - tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(true, reg)); -} - -static inline void vfp_store_reg64(TCGv_i64 var, int reg) -{ - tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(true, reg)); -} - -static inline void vfp_load_reg32(TCGv_i32 var, int reg) -{ - tcg_gen_ld_i32(var, cpu_env, vfp_reg_offset(false, reg)); -} - -static inline void vfp_store_reg32(TCGv_i32 var, int reg) -{ - tcg_gen_st_i32(var, cpu_env, vfp_reg_offset(false, reg)); -} - void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop) { long off = neon_element_offset(reg, ele, memop); From 4a800a739d6c7760a35b4be6a01bb3819de51030 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:34 +0100 Subject: [PATCH 0371/3028] target/arm: Make functions used by translate-vfp global MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the remaining functions which are needed by translate-vfp.c.inc global. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-8-peter.maydell@linaro.org --- target/arm/translate-a32.h | 18 ++++++++++++++++++ target/arm/translate.c | 25 ++++++++----------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h index 522aa83636..326cbafe99 100644 --- a/target/arm/translate-a32.h +++ b/target/arm/translate-a32.h @@ -30,6 +30,13 @@ void read_neon_element32(TCGv_i32 dest, int reg, int ele, MemOp memop); void read_neon_element64(TCGv_i64 dest, int reg, int ele, MemOp memop); void write_neon_element32(TCGv_i32 src, int reg, int ele, MemOp memop); void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop); +TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs); +void gen_set_cpsr(TCGv_i32 var, uint32_t mask); +void gen_set_condexec(DisasContext *s); +void gen_set_pc_im(DisasContext *s, target_ulong val); +void gen_lookup_tb(DisasContext *s); +long vfp_reg_offset(bool dp, unsigned reg); +long neon_full_reg_offset(unsigned reg); static inline TCGv_i32 load_cpu_offset(int offset) { @@ -57,6 +64,8 @@ static inline TCGv_i32 load_reg(DisasContext *s, int reg) return tmp; } +void store_reg(DisasContext *s, int reg, TCGv_i32 var); + void gen_aa32_ld_internal_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32, int index, MemOp opc); void gen_aa32_st_internal_i32(DisasContext *s, TCGv_i32 val, @@ -110,4 +119,13 @@ DO_GEN_ST(32, MO_UL) #undef DO_GEN_LD #undef DO_GEN_ST +#if defined(CONFIG_USER_ONLY) +#define IS_USER(s) 1 +#else +#define IS_USER(s) (s->user) +#endif + +/* Set NZCV flags from the high 4 bits of var. */ +#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) + #endif diff --git a/target/arm/translate.c b/target/arm/translate.c index c8b9cedfcf..c83f2205b6 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -52,12 +52,6 @@ #include "translate.h" #include "translate-a32.h" -#if defined(CONFIG_USER_ONLY) -#define IS_USER(s) 1 -#else -#define IS_USER(s) (s->user) -#endif - /* These are TCG temporaries used only by the legacy iwMMXt decoder */ static TCGv_i64 cpu_V0, cpu_V1, cpu_M0; /* These are TCG globals which alias CPUARMState fields */ @@ -209,7 +203,7 @@ void load_reg_var(DisasContext *s, TCGv_i32 var, int reg) * This is used for load/store for which use of PC implies (literal), * or ADD that implies ADR. */ -static TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs) +TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -223,7 +217,7 @@ static TCGv_i32 add_reg_for_lit(DisasContext *s, int reg, int ofs) /* Set a CPU register. The source must be a temporary and will be marked as dead. */ -static void store_reg(DisasContext *s, int reg, TCGv_i32 var) +void store_reg(DisasContext *s, int reg, TCGv_i32 var) { if (reg == 15) { /* In Thumb mode, we must ignore bit 0. @@ -264,15 +258,12 @@ static void store_sp_checked(DisasContext *s, TCGv_i32 var) #define gen_sxtb16(var) gen_helper_sxtb16(var, var) #define gen_uxtb16(var) gen_helper_uxtb16(var, var) - -static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask) +void gen_set_cpsr(TCGv_i32 var, uint32_t mask) { TCGv_i32 tmp_mask = tcg_const_i32(mask); gen_helper_cpsr_write(cpu_env, var, tmp_mask); tcg_temp_free_i32(tmp_mask); } -/* Set NZCV flags from the high 4 bits of var. */ -#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) static void gen_exception_internal(int excp) { @@ -697,7 +688,7 @@ void arm_gen_test_cc(int cc, TCGLabel *label) arm_free_cc(&cmp); } -static inline void gen_set_condexec(DisasContext *s) +void gen_set_condexec(DisasContext *s) { if (s->condexec_mask) { uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1); @@ -707,7 +698,7 @@ static inline void gen_set_condexec(DisasContext *s) } } -static inline void gen_set_pc_im(DisasContext *s, target_ulong val) +void gen_set_pc_im(DisasContext *s, target_ulong val) { tcg_gen_movi_i32(cpu_R[15], val); } @@ -1074,7 +1065,7 @@ static void gen_exception_el(DisasContext *s, int excp, uint32_t syn, } /* Force a TB lookup after an instruction that changes the CPU state. */ -static inline void gen_lookup_tb(DisasContext *s) +void gen_lookup_tb(DisasContext *s) { tcg_gen_movi_i32(cpu_R[15], s->base.pc_next); s->base.is_jmp = DISAS_EXIT; @@ -1109,7 +1100,7 @@ static inline void gen_hlt(DisasContext *s, int imm) /* * Return the offset of a "full" NEON Dreg. */ -static long neon_full_reg_offset(unsigned reg) +long neon_full_reg_offset(unsigned reg) { return offsetof(CPUARMState, vfp.zregs[reg >> 1].d[reg & 1]); } @@ -1135,7 +1126,7 @@ static long neon_element_offset(int reg, int element, MemOp memop) } /* Return the offset of a VFP Dreg (dp = true) or VFP Sreg (dp = false). */ -static long vfp_reg_offset(bool dp, unsigned reg) +long vfp_reg_offset(bool dp, unsigned reg) { if (dp) { return neon_element_offset(reg, 0, MO_64); From 45fbd5a96733c61a7bf85a382809bd9839afde94 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:35 +0100 Subject: [PATCH 0372/3028] target/arm: Make translate-vfp.c.inc its own compilation unit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch translate-vfp.c.inc from being #included into translate.c to being its own compilation unit. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-9-peter.maydell@linaro.org --- target/arm/meson.build | 5 +++-- target/arm/translate-a32.h | 2 ++ target/arm/{translate-vfp.c.inc => translate-vfp.c} | 12 +++++++----- target/arm/translate.c | 3 +-- 4 files changed, 13 insertions(+), 9 deletions(-) rename target/arm/{translate-vfp.c.inc => translate-vfp.c} (99%) diff --git a/target/arm/meson.build b/target/arm/meson.build index bbee1325bc..f6360f33f1 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -3,8 +3,8 @@ gen = [ decodetree.process('neon-shared.decode', extra_args: '--static-decode=disas_neon_shared'), decodetree.process('neon-dp.decode', extra_args: '--static-decode=disas_neon_dp'), decodetree.process('neon-ls.decode', extra_args: '--static-decode=disas_neon_ls'), - decodetree.process('vfp.decode', extra_args: '--static-decode=disas_vfp'), - decodetree.process('vfp-uncond.decode', extra_args: '--static-decode=disas_vfp_uncond'), + decodetree.process('vfp.decode', extra_args: '--decode=disas_vfp'), + decodetree.process('vfp-uncond.decode', extra_args: '--decode=disas_vfp_uncond'), decodetree.process('m-nocp.decode', extra_args: '--decode=disas_m_nocp'), decodetree.process('a32.decode', extra_args: '--static-decode=disas_a32'), decodetree.process('a32-uncond.decode', extra_args: '--static-decode=disas_a32_uncond'), @@ -27,6 +27,7 @@ arm_ss.add(files( 'tlb_helper.c', 'translate.c', 'translate-m-nocp.c', + 'translate-vfp.c', 'vec_helper.c', 'vfp_helper.c', 'cpu_tcg.c', diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h index 326cbafe99..e767366f69 100644 --- a/target/arm/translate-a32.h +++ b/target/arm/translate-a32.h @@ -22,6 +22,8 @@ /* Prototypes for autogenerated disassembler functions */ bool disas_m_nocp(DisasContext *dc, uint32_t insn); +bool disas_vfp(DisasContext *s, uint32_t insn); +bool disas_vfp_uncond(DisasContext *s, uint32_t insn); void load_reg_var(DisasContext *s, TCGv_i32 var, int reg); void arm_gen_condlabel(DisasContext *s); diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c similarity index 99% rename from target/arm/translate-vfp.c.inc rename to target/arm/translate-vfp.c index 1004d1fd09..3da84f30a0 100644 --- a/target/arm/translate-vfp.c.inc +++ b/target/arm/translate-vfp.c @@ -20,11 +20,13 @@ * License along with this library; if not, see . */ -/* - * This file is intended to be included from translate.c; it uses - * some macros and definitions provided by that file. - * It might be possible to convert it to a standalone .c file eventually. - */ +#include "qemu/osdep.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "exec/exec-all.h" +#include "exec/gen-icount.h" +#include "translate.h" +#include "translate-a32.h" /* Include the generated VFP decoder */ #include "decode-vfp.c.inc" diff --git a/target/arm/translate.c b/target/arm/translate.c index c83f2205b6..6aec494e81 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -1224,8 +1224,7 @@ static TCGv_ptr vfp_reg_ptr(bool dp, int reg) #define ARM_CP_RW_BIT (1 << 20) -/* Include the VFP and Neon decoders */ -#include "translate-vfp.c.inc" +/* Include the Neon decoder */ #include "translate-neon.c.inc" static inline void iwmmxt_load_reg(TCGv_i64 var, int reg) From eb554d612d6a7718154babfc9e2b36694397b443 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:36 +0100 Subject: [PATCH 0373/3028] target/arm: Move vfp_reg_ptr() to translate-neon.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function vfp_reg_ptr() is used only in translate-neon.c.inc; move it there. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-10-peter.maydell@linaro.org --- target/arm/translate-neon.c.inc | 7 +++++++ target/arm/translate.c | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c.inc index a02b8369a1..73bf376ed3 100644 --- a/target/arm/translate-neon.c.inc +++ b/target/arm/translate-neon.c.inc @@ -60,6 +60,13 @@ static inline int neon_3same_fp_size(DisasContext *s, int x) #include "decode-neon-ls.c.inc" #include "decode-neon-shared.c.inc" +static TCGv_ptr vfp_reg_ptr(bool dp, int reg) +{ + TCGv_ptr ret = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg)); + return ret; +} + static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) { long offset = neon_element_offset(reg, ele, mop & MO_SIZE); diff --git a/target/arm/translate.c b/target/arm/translate.c index 6aec494e81..095b5c509e 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -1215,13 +1215,6 @@ void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop) } } -static TCGv_ptr vfp_reg_ptr(bool dp, int reg) -{ - TCGv_ptr ret = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(ret, cpu_env, vfp_reg_offset(dp, reg)); - return ret; -} - #define ARM_CP_RW_BIT (1 << 20) /* Include the Neon decoder */ From 8e30454fed1e45d709942836f2e299c8d9b00837 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:37 +0100 Subject: [PATCH 0374/3028] target/arm: Delete unused typedef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VFPGenFixPointFn typedef is unused; delete it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210430132740.10391-11-peter.maydell@linaro.org --- target/arm/translate.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 095b5c509e..58cb3e8aaf 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -69,8 +69,6 @@ static const char * const regnames[] = /* Function prototypes for gen_ functions calling Neon helpers. */ typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32, TCGv_i32); -/* Function prototypes for gen_ functions for fix point conversions */ -typedef void VFPGenFixPointFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); /* initialize TCG globals. */ void arm_translate_init(void) From 9194a9cbc75e7af63eff26c87b995bdc52078ca6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:38 +0100 Subject: [PATCH 0375/3028] target/arm: Move NeonGenThreeOpEnvFn typedef to translate.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the NeonGenThreeOpEnvFn typedef to translate.h together with the other similar typedefs. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210430132740.10391-12-peter.maydell@linaro.org --- target/arm/translate.c | 3 --- target/arm/translate.h | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 58cb3e8aaf..7ff0425c75 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -66,9 +66,6 @@ static const char * const regnames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" }; -/* Function prototypes for gen_ functions calling Neon helpers. */ -typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32, - TCGv_i32, TCGv_i32); /* initialize TCG globals. */ void arm_translate_init(void) diff --git a/target/arm/translate.h b/target/arm/translate.h index 8130a3be29..12c28b0d32 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -409,6 +409,8 @@ typedef void NeonGenOneOpFn(TCGv_i32, TCGv_i32); typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32); typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32); typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32); +typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32, + TCGv_i32, TCGv_i32); typedef void NeonGenTwo64OpFn(TCGv_i64, TCGv_i64, TCGv_i64); typedef void NeonGenTwo64OpEnvFn(TCGv_i64, TCGv_ptr, TCGv_i64, TCGv_i64); typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); From b5c8a457fab78e08d0ab5f9ca242b85b31c72c87 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:39 +0100 Subject: [PATCH 0376/3028] target/arm: Make functions used by translate-neon global MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the remaining functions needed by the translate-neon code global. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-13-peter.maydell@linaro.org --- target/arm/translate-a32.h | 8 ++++++++ target/arm/translate.c | 10 ++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h index e767366f69..3ddb76b76b 100644 --- a/target/arm/translate-a32.h +++ b/target/arm/translate-a32.h @@ -39,6 +39,8 @@ void gen_set_pc_im(DisasContext *s, target_ulong val); void gen_lookup_tb(DisasContext *s); long vfp_reg_offset(bool dp, unsigned reg); long neon_full_reg_offset(unsigned reg); +long neon_element_offset(int reg, int element, MemOp memop); +void gen_rev16(TCGv_i32 dest, TCGv_i32 var); static inline TCGv_i32 load_cpu_offset(int offset) { @@ -130,4 +132,10 @@ DO_GEN_ST(32, MO_UL) /* Set NZCV flags from the high 4 bits of var. */ #define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) +/* Swap low and high halfwords. */ +static inline void gen_swap_half(TCGv_i32 dest, TCGv_i32 var) +{ + tcg_gen_rotri_i32(dest, var, 16); +} + #endif diff --git a/target/arm/translate.c b/target/arm/translate.c index 7ff0425c75..18de16ebd0 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -325,7 +325,7 @@ static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b) } /* Byteswap each halfword. */ -static void gen_rev16(TCGv_i32 dest, TCGv_i32 var) +void gen_rev16(TCGv_i32 dest, TCGv_i32 var) { TCGv_i32 tmp = tcg_temp_new_i32(); TCGv_i32 mask = tcg_const_i32(0x00ff00ff); @@ -346,12 +346,6 @@ static void gen_revsh(TCGv_i32 dest, TCGv_i32 var) tcg_gen_ext16s_i32(dest, var); } -/* Swap low and high halfwords. */ -static void gen_swap_half(TCGv_i32 dest, TCGv_i32 var) -{ - tcg_gen_rotri_i32(dest, var, 16); -} - /* Dual 16-bit add. Result placed in t0 and t1 is marked as dead. tmp = (t0 ^ t1) & 0x8000; t0 &= ~0x8000; @@ -1104,7 +1098,7 @@ long neon_full_reg_offset(unsigned reg) * Return the offset of a 2**SIZE piece of a NEON register, at index ELE, * where 0 is the least significant end of the register. */ -static long neon_element_offset(int reg, int element, MemOp memop) +long neon_element_offset(int reg, int element, MemOp memop) { int element_size = 1 << (memop & MO_SIZE); int ofs = element * element_size; From 4800b852b8099187d2186c213626c298a60b775c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 14:27:40 +0100 Subject: [PATCH 0377/3028] target/arm: Make translate-neon.c.inc its own compilation unit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch translate-neon.c.inc from being #included into translate.c to being its own compilation unit. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20210430132740.10391-14-peter.maydell@linaro.org --- target/arm/meson.build | 7 ++++--- target/arm/translate-a32.h | 3 +++ .../arm/{translate-neon.c.inc => translate-neon.c} | 12 +++++++----- target/arm/translate.c | 3 --- 4 files changed, 14 insertions(+), 11 deletions(-) rename target/arm/{translate-neon.c.inc => translate-neon.c} (99%) diff --git a/target/arm/meson.build b/target/arm/meson.build index f6360f33f1..5bfaf43b50 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -1,8 +1,8 @@ gen = [ decodetree.process('sve.decode', extra_args: '--decode=disas_sve'), - decodetree.process('neon-shared.decode', extra_args: '--static-decode=disas_neon_shared'), - decodetree.process('neon-dp.decode', extra_args: '--static-decode=disas_neon_dp'), - decodetree.process('neon-ls.decode', extra_args: '--static-decode=disas_neon_ls'), + decodetree.process('neon-shared.decode', extra_args: '--decode=disas_neon_shared'), + decodetree.process('neon-dp.decode', extra_args: '--decode=disas_neon_dp'), + decodetree.process('neon-ls.decode', extra_args: '--decode=disas_neon_ls'), decodetree.process('vfp.decode', extra_args: '--decode=disas_vfp'), decodetree.process('vfp-uncond.decode', extra_args: '--decode=disas_vfp_uncond'), decodetree.process('m-nocp.decode', extra_args: '--decode=disas_m_nocp'), @@ -27,6 +27,7 @@ arm_ss.add(files( 'tlb_helper.c', 'translate.c', 'translate-m-nocp.c', + 'translate-neon.c', 'translate-vfp.c', 'vec_helper.c', 'vfp_helper.c', diff --git a/target/arm/translate-a32.h b/target/arm/translate-a32.h index 3ddb76b76b..c997f4e321 100644 --- a/target/arm/translate-a32.h +++ b/target/arm/translate-a32.h @@ -24,6 +24,9 @@ bool disas_m_nocp(DisasContext *dc, uint32_t insn); bool disas_vfp(DisasContext *s, uint32_t insn); bool disas_vfp_uncond(DisasContext *s, uint32_t insn); +bool disas_neon_dp(DisasContext *s, uint32_t insn); +bool disas_neon_ls(DisasContext *s, uint32_t insn); +bool disas_neon_shared(DisasContext *s, uint32_t insn); void load_reg_var(DisasContext *s, TCGv_i32 var, int reg); void arm_gen_condlabel(DisasContext *s); diff --git a/target/arm/translate-neon.c.inc b/target/arm/translate-neon.c similarity index 99% rename from target/arm/translate-neon.c.inc rename to target/arm/translate-neon.c index 73bf376ed3..658bd275da 100644 --- a/target/arm/translate-neon.c.inc +++ b/target/arm/translate-neon.c @@ -20,11 +20,13 @@ * License along with this library; if not, see . */ -/* - * This file is intended to be included from translate.c; it uses - * some macros and definitions provided by that file. - * It might be possible to convert it to a standalone .c file eventually. - */ +#include "qemu/osdep.h" +#include "tcg/tcg-op.h" +#include "tcg/tcg-op-gvec.h" +#include "exec/exec-all.h" +#include "exec/gen-icount.h" +#include "translate.h" +#include "translate-a32.h" static inline int plus1(DisasContext *s, int x) { diff --git a/target/arm/translate.c b/target/arm/translate.c index 18de16ebd0..455352bcf6 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -1206,9 +1206,6 @@ void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop) #define ARM_CP_RW_BIT (1 << 20) -/* Include the Neon decoder */ -#include "translate-neon.c.inc" - static inline void iwmmxt_load_reg(TCGv_i64 var, int reg) { tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg])); From 5b2c8af89b82a671137a2765b09ad24d0653661c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 17:22:12 +0100 Subject: [PATCH 0378/3028] target/arm: Make WFI a NOP for userspace emulators The WFI insn is not system-mode only, though it doesn't usually make a huge amount of sense for userspace code to execute it. Currently if you try it in qemu-arm then the helper function will raise an EXCP_HLT exception, which is not covered by the switch in cpu_loop() and results in an abort: qemu: unhandled CPU exception 0x10001 - aborting R00=00000001 R01=408003e4 R02=408003ec R03=000102ec R04=00010a28 R05=00010158 R06=00087460 R07=00010158 R08=00000000 R09=00000000 R10=00085b7c R11=408002a4 R12=408002b8 R13=408002a0 R14=0001057c R15=000102f8 PSR=60000010 -ZC- A usr32 qemu:handle_cpu_signal received signal outside vCPU context @ pc=0x7fcbfa4f0a12 Make the WFI helper function return immediately in the usermode emulator. This turns WFI into a NOP, which is OK because: * architecturally "WFI is a NOP" is a permitted implementation * aarch64 Linux kernels use the SCTLR_EL1.nTWI bit to trap userspace WFI and NOP it (though aarch32 kernels currently just let WFI do whatever it would do) We could in theory make the translate.c code special case user-mode emulation and NOP the insn entirely rather than making the helper do nothing, but because no real world code will be trying to execute WFI we don't care about efficiency and the helper provides a single place where we can make the change rather than having to touch multiple places in translate.c and translate-a64.c. Fixes: https://bugs.launchpad.net/qemu/+bug/1926759 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210430162212.825-1-peter.maydell@linaro.org --- target/arm/op_helper.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 78b831f181..efcb600992 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -228,6 +228,7 @@ void HELPER(setend)(CPUARMState *env) arm_rebuild_hflags(env); } +#ifndef CONFIG_USER_ONLY /* Function checks whether WFx (WFI/WFE) instructions are set up to be trapped. * The function returns the target EL (1-3) if the instruction is to be trapped; * otherwise it returns 0 indicating it is not trapped. @@ -282,9 +283,21 @@ static inline int check_wfx_trap(CPUARMState *env, bool is_wfe) return 0; } +#endif void HELPER(wfi)(CPUARMState *env, uint32_t insn_len) { +#ifdef CONFIG_USER_ONLY + /* + * WFI in the user-mode emulator is technically permitted but not + * something any real-world code would do. AArch64 Linux kernels + * trap it via SCTRL_EL1.nTWI and make it an (expensive) NOP; + * AArch32 kernels don't trap it so it will delay a bit. + * For QEMU, make it NOP here, because trying to raise EXCP_HLT + * would trigger an abort. + */ + return; +#else CPUState *cs = env_cpu(env); int target_el = check_wfx_trap(env, false); @@ -309,6 +322,7 @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len) cs->exception_index = EXCP_HLT; cs->halted = 1; cpu_loop_exit(cs); +#endif } void HELPER(wfe)(CPUARMState *env) From 3e81a71c9f3d23002b1e0dfff902c155d6c8d224 Mon Sep 17 00:00:00 2001 From: Igor Druzhinin Date: Tue, 20 Apr 2021 04:35:02 +0100 Subject: [PATCH 0379/3028] xen-mapcache: avoid a race on memory map while using MAP_FIXED When we're replacing the existing mapping there is possibility of a race on memory map with other threads doing mmap operations - the address being unmapped/re-mapped could be occupied by another thread in between. Linux mmap man page recommends keeping the existing mappings in place to reserve the place and instead utilize the fact that the next mmap operation with MAP_FIXED flag passed will implicitly destroy the existing mappings behind the chosen address. This behavior is guaranteed by POSIX / BSD and therefore is portable. Note that it wouldn't make the replacement atomic for parallel accesses to the replaced region - those might still fail with SIGBUS due to xenforeignmemory_map not being atomic. So we're still not expecting those. Tested-by: Anthony PERARD Signed-off-by: Igor Druzhinin Reviewed-by: Paul Durrant Message-Id: <1618889702-13104-1-git-send-email-igor.druzhinin@citrix.com> Signed-off-by: Anthony PERARD --- hw/i386/xen/xen-mapcache.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c index 5b120ed44b..e82b7dcdd2 100644 --- a/hw/i386/xen/xen-mapcache.c +++ b/hw/i386/xen/xen-mapcache.c @@ -171,7 +171,20 @@ static void xen_remap_bucket(MapCacheEntry *entry, if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) { ram_block_notify_remove(entry->vaddr_base, entry->size); } - if (munmap(entry->vaddr_base, entry->size) != 0) { + + /* + * If an entry is being replaced by another mapping and we're using + * MAP_FIXED flag for it - there is possibility of a race for vaddr + * address with another thread doing an mmap call itself + * (see man 2 mmap). To avoid that we skip explicit unmapping here + * and allow the kernel to destroy the previous mappings by replacing + * them in mmap call later. + * + * Non-identical replacements are not allowed therefore. + */ + assert(!vaddr || (entry->vaddr_base == vaddr && entry->size == size)); + + if (!vaddr && munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); exit(-1); } From f1e43b6026500690fc402828fa7cc735175b93b6 Mon Sep 17 00:00:00 2001 From: Anthony PERARD Date: Fri, 30 Apr 2021 17:37:42 +0100 Subject: [PATCH 0380/3028] xen: Free xenforeignmemory_resource at exit Because Coverity complains about it and this is one leak that Valgrind reports. Signed-off-by: Anthony PERARD Acked-by: Paul Durrant Message-Id: <20210430163742.469739-1-anthony.perard@citrix.com> Signed-off-by: Anthony PERARD --- hw/i386/xen/xen-hvm.c | 9 ++++++--- include/hw/xen/xen_common.h | 6 ++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index c53fa17c50..9b432773f0 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -108,6 +108,7 @@ typedef struct XenIOState { shared_iopage_t *shared_page; shared_vmport_iopage_t *shared_vmport_page; buffered_iopage_t *buffered_io_page; + xenforeignmemory_resource_handle *fres; QEMUTimer *buffered_io_timer; CPUState **cpu_by_vcpu_id; /* the evtchn port for polling the notification, */ @@ -1253,6 +1254,9 @@ static void xen_exit_notifier(Notifier *n, void *data) XenIOState *state = container_of(n, XenIOState, exit); xen_destroy_ioreq_server(xen_domid, state->ioservid); + if (state->fres != NULL) { + xenforeignmemory_unmap_resource(xen_fmem, state->fres); + } xenevtchn_close(state->xce_handle); xs_daemon_close(state->xenstore); @@ -1320,7 +1324,6 @@ static void xen_wakeup_notifier(Notifier *notifier, void *data) static int xen_map_ioreq_server(XenIOState *state) { void *addr = NULL; - xenforeignmemory_resource_handle *fres; xen_pfn_t ioreq_pfn; xen_pfn_t bufioreq_pfn; evtchn_port_t bufioreq_evtchn; @@ -1332,12 +1335,12 @@ static int xen_map_ioreq_server(XenIOState *state) */ QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_bufioreq != 0); QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_ioreq(0) != 1); - fres = xenforeignmemory_map_resource(xen_fmem, xen_domid, + state->fres = xenforeignmemory_map_resource(xen_fmem, xen_domid, XENMEM_resource_ioreq_server, state->ioservid, 0, 2, &addr, PROT_READ | PROT_WRITE, 0); - if (fres != NULL) { + if (state->fres != NULL) { trace_xen_map_resource_ioreq(state->ioservid, addr); state->buffered_io_page = addr; state->shared_page = addr + TARGET_PAGE_SIZE; diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h index 82e56339dd..a8118b41ac 100644 --- a/include/hw/xen/xen_common.h +++ b/include/hw/xen/xen_common.h @@ -134,6 +134,12 @@ static inline xenforeignmemory_resource_handle *xenforeignmemory_map_resource( return NULL; } +static inline int xenforeignmemory_unmap_resource( + xenforeignmemory_handle *fmem, xenforeignmemory_resource_handle *fres) +{ + return 0; +} + #endif /* CONFIG_XEN_CTRL_INTERFACE_VERSION < 41100 */ #if CONFIG_XEN_CTRL_INTERFACE_VERSION < 41000 From 1898293990702c5601e225dac9afd2402fc46e2d Mon Sep 17 00:00:00 2001 From: Anthony PERARD Date: Fri, 30 Apr 2021 17:34:32 +0100 Subject: [PATCH 0381/3028] xen-block: Use specific blockdev driver ... when a xen-block backend instance is created via xenstore. Following 8d17adf34f50 ("block: remove support for using "file" driver with block/char devices"), using the "file" blockdev driver for everything doesn't work anymore, we need to use the "host_device" driver when the disk image is a block device and "file" driver when it is a regular file. Signed-off-by: Anthony PERARD Acked-by: Paul Durrant Message-Id: <20210430163432.468894-1-anthony.perard@citrix.com> Signed-off-by: Anthony PERARD --- hw/block/xen-block.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 83754a4344..674953f1ad 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -728,6 +728,8 @@ static XenBlockDrive *xen_block_drive_create(const char *id, XenBlockDrive *drive = NULL; QDict *file_layer; QDict *driver_layer; + struct stat st; + int rc; if (params) { char **v = g_strsplit(params, ":", 2); @@ -761,7 +763,17 @@ static XenBlockDrive *xen_block_drive_create(const char *id, file_layer = qdict_new(); driver_layer = qdict_new(); - qdict_put_str(file_layer, "driver", "file"); + rc = stat(filename, &st); + if (rc) { + error_setg_errno(errp, errno, "Could not stat file '%s'", filename); + goto done; + } + if (S_ISBLK(st.st_mode)) { + qdict_put_str(file_layer, "driver", "host_device"); + } else { + qdict_put_str(file_layer, "driver", "file"); + } + qdict_put_str(file_layer, "filename", filename); g_free(filename); From f16a3bf81b8b01c53144167f6cc12fb126028972 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 30 Apr 2021 23:23:48 +0100 Subject: [PATCH 0382/3028] hw/sd/omap_mmc: Use device_cold_reset() instead of device_legacy_reset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The omap_mmc_reset() function resets its SD card via device_legacy_reset(). We know that the SD card does not have a qbus of its own, so the new device_cold_reset() function (which resets both the device and its child buses) is equivalent here to device_legacy_reset() and we can just switch to the new API. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210430222348.8514-1-peter.maydell@linaro.org --- hw/sd/omap_mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index 1f946908fe..b67def6381 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -318,7 +318,7 @@ void omap_mmc_reset(struct omap_mmc_s *host) * into any bus, and we must reset it manually. When omap_mmc is * QOMified this must move into the QOM reset function. */ - device_legacy_reset(DEVICE(host->card)); + device_cold_reset(DEVICE(host->card)); } static uint64_t omap_mmc_read(void *opaque, hwaddr offset, From 415a9fb880c6bf383d649643a4ce65ea3bc9b084 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 16 Apr 2021 14:55:41 +0100 Subject: [PATCH 0383/3028] osdep: Make os-win32.h and os-posix.h handle 'extern "C"' themselves Both os-win32.h and os-posix.h include system header files. Instead of having osdep.h include them inside its 'extern "C"' block, make these headers handle that themselves, so that we don't include the system headers inside 'extern "C"'. This doesn't fix any current problems, but it's conceptually the right way to handle system headers. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- include/qemu/osdep.h | 8 ++++---- include/sysemu/os-posix.h | 8 ++++++++ include/sysemu/os-win32.h | 8 ++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index cb2a07e472..4c6f2390be 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -131,10 +131,6 @@ QEMU_EXTERN_C int daemon(int, int); */ #include "glib-compat.h" -#ifdef __cplusplus -extern "C" { -#endif - #ifdef _WIN32 #include "sysemu/os-win32.h" #endif @@ -143,6 +139,10 @@ extern "C" { #include "sysemu/os-posix.h" #endif +#ifdef __cplusplus +extern "C" { +#endif + #include "qemu/typedefs.h" /* diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h index 629c8c648b..2edf33658a 100644 --- a/include/sysemu/os-posix.h +++ b/include/sysemu/os-posix.h @@ -38,6 +38,10 @@ #include #endif +#ifdef __cplusplus +extern "C" { +#endif + void os_set_line_buffering(void); void os_set_proc_name(const char *s); void os_setup_signal_handling(void); @@ -92,4 +96,8 @@ static inline void qemu_funlockfile(FILE *f) funlockfile(f); } +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h index 5346d51e89..43f569b5c2 100644 --- a/include/sysemu/os-win32.h +++ b/include/sysemu/os-win32.h @@ -30,6 +30,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + #if defined(_WIN64) /* On w64, setjmp is implemented by _setjmp which needs a second parameter. * If this parameter is NULL, longjump does no stack unwinding. @@ -194,4 +198,8 @@ ssize_t qemu_recv_wrap(int sockfd, void *buf, size_t len, int flags); ssize_t qemu_recvfrom_wrap(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen); +#ifdef __cplusplus +} +#endif + #endif From b30a8c241fe22b9cbd0ad015809fc92688fee4ff Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 16 Apr 2021 14:55:42 +0100 Subject: [PATCH 0384/3028] include/qemu/bswap.h: Handle being included outside extern "C" block Make bswap.h handle being included outside an 'extern "C"' block: all system headers are included first, then all declarations are put inside an 'extern "C"' block. This requires a little rearrangement as currently we have an ifdef ladder that has some system includes and some local declarations or definitions, and we need to separate those out. We want to do this because dis-asm.h includes bswap.h, dis-asm.h may need to be included from C++ files, and system headers should not be included within 'extern "C"' blocks. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- include/qemu/bswap.h | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index 4aaf992b5d..2d3bb8bbed 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -1,8 +1,6 @@ #ifndef BSWAP_H #define BSWAP_H -#include "fpu/softfloat-types.h" - #ifdef CONFIG_MACHINE_BSWAP_H # include # include @@ -12,7 +10,18 @@ # include #elif defined(CONFIG_BYTESWAP_H) # include +#define BSWAP_FROM_BYTESWAP +# else +#define BSWAP_FROM_FALLBACKS +#endif /* ! CONFIG_MACHINE_BSWAP_H */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "fpu/softfloat-types.h" + +#ifdef BSWAP_FROM_BYTESWAP static inline uint16_t bswap16(uint16_t x) { return bswap_16(x); @@ -27,7 +36,9 @@ static inline uint64_t bswap64(uint64_t x) { return bswap_64(x); } -# else +#endif + +#ifdef BSWAP_FROM_FALLBACKS static inline uint16_t bswap16(uint16_t x) { return (((x & 0x00ff) << 8) | @@ -53,7 +64,10 @@ static inline uint64_t bswap64(uint64_t x) ((x & 0x00ff000000000000ULL) >> 40) | ((x & 0xff00000000000000ULL) >> 56)); } -#endif /* ! CONFIG_MACHINE_BSWAP_H */ +#endif + +#undef BSWAP_FROM_BYTESWAP +#undef BSWAP_FROM_FALLBACKS static inline void bswap16s(uint16_t *s) { @@ -494,4 +508,8 @@ DO_STN_LDN_P(be) #undef le_bswaps #undef be_bswaps +#ifdef __cplusplus +} +#endif + #endif /* BSWAP_H */ From 2c316f9af4752369ac86be85cd8846d6365e4e68 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 16 Apr 2021 14:55:43 +0100 Subject: [PATCH 0385/3028] include/disas/dis-asm.h: Handle being included outside 'extern "C"' Make dis-asm.h handle being included outside an 'extern "C"' block; this allows us to remove the 'extern "C"' blocks that our two C++ files that include it are using. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- disas/arm-a64.cc | 2 -- disas/nanomips.cpp | 2 -- include/disas/dis-asm.h | 12 ++++++++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/disas/arm-a64.cc b/disas/arm-a64.cc index 27613d4b25..a1402a2e07 100644 --- a/disas/arm-a64.cc +++ b/disas/arm-a64.cc @@ -18,9 +18,7 @@ */ #include "qemu/osdep.h" -extern "C" { #include "disas/dis-asm.h" -} #include "vixl/a64/disasm-a64.h" diff --git a/disas/nanomips.cpp b/disas/nanomips.cpp index 8ddef897f0..9be8df75dd 100644 --- a/disas/nanomips.cpp +++ b/disas/nanomips.cpp @@ -28,9 +28,7 @@ */ #include "qemu/osdep.h" -extern "C" { #include "disas/dis-asm.h" -} #include #include diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index 13fa1edd41..4701445e80 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -9,6 +9,12 @@ #ifndef DISAS_DIS_ASM_H #define DISAS_DIS_ASM_H +#include "qemu/bswap.h" + +#ifdef __cplusplus +extern "C" { +#endif + typedef void *PTR; typedef uint64_t bfd_vma; typedef int64_t bfd_signed_vma; @@ -479,8 +485,6 @@ bool cap_disas_plugin(disassemble_info *info, uint64_t pc, size_t size); /* from libbfd */ -#include "qemu/bswap.h" - static inline bfd_vma bfd_getl64(const bfd_byte *addr) { return ldq_le_p(addr); @@ -508,4 +512,8 @@ static inline bfd_vma bfd_getb16(const bfd_byte *addr) typedef bool bfd_boolean; +#ifdef __cplusplus +} +#endif + #endif /* DISAS_DIS_ASM_H */ From f463684fbf859e39fcdbd0327a8bcbe8fbcbfab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 8 Apr 2021 00:56:08 +0200 Subject: [PATCH 0386/3028] hw/arm/imx25_pdk: Fix error message for invalid RAM size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The i.MX25 PDK board has 2 banks for SDRAM, each can address up to 256 MiB. So the total RAM usable for this board is 512M. When we ask for more we get a misleading error message: $ qemu-system-arm -M imx25-pdk -m 513M qemu-system-arm: Invalid RAM size, should be 128 MiB Update the error message to better match the reality: $ qemu-system-arm -M imx25-pdk -m 513M qemu-system-arm: RAM size more than 512 MiB is not supported Fixes: bf350daae02 ("arm/imx25_pdk: drop RAM size fixup") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Igor Mammedov Message-id: 20210407225608.1882855-1-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/imx25_pdk.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/arm/imx25_pdk.c b/hw/arm/imx25_pdk.c index 11426e5ec0..bd16acd4d9 100644 --- a/hw/arm/imx25_pdk.c +++ b/hw/arm/imx25_pdk.c @@ -65,7 +65,6 @@ static struct arm_boot_info imx25_pdk_binfo; static void imx25_pdk_init(MachineState *machine) { - MachineClass *mc = MACHINE_GET_CLASS(machine); IMX25PDK *s = g_new0(IMX25PDK, 1); unsigned int ram_size; unsigned int alias_offset; @@ -77,8 +76,8 @@ static void imx25_pdk_init(MachineState *machine) /* We need to initialize our memory */ if (machine->ram_size > (FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE)) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); + char *sz = size_to_str(FSL_IMX25_SDRAM0_SIZE + FSL_IMX25_SDRAM1_SIZE); + error_report("RAM size more than %s is not supported", sz); g_free(sz); exit(EXIT_FAILURE); } From c52c266d24b10f1482602e6d22938d9e21f874f5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 4 May 2021 13:09:10 +0100 Subject: [PATCH 0387/3028] hw/misc/mps2-scc: Add "QEMU interface" comment The MPS2 SCC device doesn't have any documentation of its properties; add a "QEMU interface" format comment describing them. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20210504120912.23094-2-peter.maydell@linaro.org --- include/hw/misc/mps2-scc.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/hw/misc/mps2-scc.h b/include/hw/misc/mps2-scc.h index 49d070616a..ea261ea30d 100644 --- a/include/hw/misc/mps2-scc.h +++ b/include/hw/misc/mps2-scc.h @@ -9,6 +9,18 @@ * (at your option) any later version. */ +/* + * This is a model of the Serial Communication Controller (SCC) + * block found in most MPS FPGA images. + * + * QEMU interface: + * + sysbus MMIO region 0: the register bank + * + QOM property "scc-cfg4": value of the read-only CFG4 register + * + QOM property "scc-aid": value of the read-only SCC_AID register + * + QOM property "scc-id": value of the read-only SCC_ID register + * + QOM property array "oscclk": reset values of the OSCCLK registers + * (which are accessed via the SYS_CFG channel provided by this device) + */ #ifndef MPS2_SCC_H #define MPS2_SCC_H From 5bddf92e689c0a3da57f4fd17b83d4eb1e436b80 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 4 May 2021 13:09:11 +0100 Subject: [PATCH 0388/3028] hw/misc/mps2-scc: Support using CFG0 bit 0 for remapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some boards, SCC config register CFG0 bit 0 controls whether parts of the board memory map are remapped. Support this with: * a device property scc-cfg0 so the board can specify the initial value of the CFG0 register * an outbound GPIO line which tracks bit 0 and which the board can wire up to provide the remapping Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210504120912.23094-3-peter.maydell@linaro.org --- hw/misc/mps2-scc.c | 13 ++++++++++--- include/hw/misc/mps2-scc.h | 9 +++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c index c56aca86ad..b3b42a792c 100644 --- a/hw/misc/mps2-scc.c +++ b/hw/misc/mps2-scc.c @@ -23,6 +23,7 @@ #include "qemu/bitops.h" #include "trace.h" #include "hw/sysbus.h" +#include "hw/irq.h" #include "migration/vmstate.h" #include "hw/registerfields.h" #include "hw/misc/mps2-scc.h" @@ -186,10 +187,13 @@ static void mps2_scc_write(void *opaque, hwaddr offset, uint64_t value, switch (offset) { case A_CFG0: /* - * TODO on some boards bit 0 controls RAM remapping; - * on others bit 1 is CPU_WAIT. + * On some boards bit 0 controls board-specific remapping; + * we always reflect bit 0 in the 'remap' GPIO output line, + * and let the board wire it up or not as it chooses. + * TODO on some boards bit 1 is CPU_WAIT. */ s->cfg0 = value; + qemu_set_irq(s->remap, s->cfg0 & 1); break; case A_CFG1: s->cfg1 = value; @@ -283,7 +287,7 @@ static void mps2_scc_reset(DeviceState *dev) int i; trace_mps2_scc_reset(); - s->cfg0 = 0; + s->cfg0 = s->cfg0_reset; s->cfg1 = 0; s->cfg2 = 0; s->cfg5 = 0; @@ -308,6 +312,7 @@ static void mps2_scc_init(Object *obj) memory_region_init_io(&s->iomem, obj, &mps2_scc_ops, s, "mps2-scc", 0x1000); sysbus_init_mmio(sbd, &s->iomem); + qdev_init_gpio_out_named(DEVICE(obj), &s->remap, "remap", 1); } static void mps2_scc_realize(DeviceState *dev, Error **errp) @@ -353,6 +358,8 @@ static Property mps2_scc_properties[] = { DEFINE_PROP_UINT32("scc-cfg4", MPS2SCC, cfg4, 0), DEFINE_PROP_UINT32("scc-aid", MPS2SCC, aid, 0), DEFINE_PROP_UINT32("scc-id", MPS2SCC, id, 0), + /* Reset value for CFG0 register */ + DEFINE_PROP_UINT32("scc-cfg0", MPS2SCC, cfg0_reset, 0), /* * These are the initial settings for the source clocks on the board. * In hardware they can be configured via a config file read by the diff --git a/include/hw/misc/mps2-scc.h b/include/hw/misc/mps2-scc.h index ea261ea30d..3b2d13ac9c 100644 --- a/include/hw/misc/mps2-scc.h +++ b/include/hw/misc/mps2-scc.h @@ -18,8 +18,14 @@ * + QOM property "scc-cfg4": value of the read-only CFG4 register * + QOM property "scc-aid": value of the read-only SCC_AID register * + QOM property "scc-id": value of the read-only SCC_ID register + * + QOM property "scc-cfg0": reset value of the CFG0 register * + QOM property array "oscclk": reset values of the OSCCLK registers * (which are accessed via the SYS_CFG channel provided by this device) + * + named GPIO output "remap": this tracks the value of CFG0 register + * bit 0. Boards where this bit controls memory remapping should + * connect this GPIO line to a function performing that mapping. + * Boards where bit 0 has no special function should leave the GPIO + * output disconnected. */ #ifndef MPS2_SCC_H #define MPS2_SCC_H @@ -55,6 +61,9 @@ struct MPS2SCC { uint32_t num_oscclk; uint32_t *oscclk; uint32_t *oscclk_reset; + uint32_t cfg0_reset; + + qemu_irq remap; }; #endif From f1dfab0d9b77b8649d60ded3d96870f88d0baccd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 4 May 2021 13:09:12 +0100 Subject: [PATCH 0389/3028] hw/arm/mps2-tz: Implement AN524 memory remapping via machine property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AN524 FPGA image supports two memory maps, which differ in where the QSPI and BRAM are. In the default map, the BRAM is at 0x0000_0000, and the QSPI at 0x2800_0000. In the second map, they are the other way around. In hardware, the initial mapping can be selected by the user by writing either "REMAP: BRAM" (the default) or "REMAP: QSPI" in the board configuration file. The board config file is acted on by the "Motherboard Configuration Controller", which is an entirely separate microcontroller on the dev board but outside the FPGA. The guest can also dynamically change the mapping via the SCC CFG_REG0 register. Implement this functionality for QEMU, using a machine property "remap" with valid values "BRAM" and "QSPI" to allow the user to set the initial mapping, in the same way they can on the FPGA, and wiring up the bit from the SCC register to also switch the mapping. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20210504120912.23094-4-peter.maydell@linaro.org --- docs/system/arm/mps2.rst | 10 ++++ hw/arm/mps2-tz.c | 108 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/docs/system/arm/mps2.rst b/docs/system/arm/mps2.rst index f83b151787..8a75beb3a0 100644 --- a/docs/system/arm/mps2.rst +++ b/docs/system/arm/mps2.rst @@ -45,3 +45,13 @@ Differences between QEMU and real hardware: flash, but only as simple ROM, so attempting to rewrite the flash from the guest will fail - QEMU does not model the USB controller in MPS3 boards + +Machine-specific options +"""""""""""""""""""""""" + +The following machine-specific options are supported: + +remap + Supported for ``mps3-an524`` only. + Set ``BRAM``/``QSPI`` to select the initial memory mapping. The + default is ``BRAM``. diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 25016e464d..70aa31a7f6 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -55,6 +55,7 @@ #include "hw/boards.h" #include "exec/address-spaces.h" #include "sysemu/sysemu.h" +#include "sysemu/reset.h" #include "hw/misc/unimp.h" #include "hw/char/cmsdk-apb-uart.h" #include "hw/timer/cmsdk-apb-timer.h" @@ -72,6 +73,7 @@ #include "hw/core/split-irq.h" #include "hw/qdev-clock.h" #include "qom/object.h" +#include "hw/irq.h" #define MPS2TZ_NUMIRQ_MAX 96 #define MPS2TZ_RAM_MAX 5 @@ -153,6 +155,9 @@ struct MPS2TZMachineState { SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ_MAX]; Clock *sysclk; Clock *s32kclk; + + bool remap; + qemu_irq remap_irq; }; #define TYPE_MPS2TZ_MACHINE "mps2tz" @@ -228,6 +233,10 @@ static const RAMInfo an505_raminfo[] = { { }, }; +/* + * Note that the addresses and MPC numbering here should match up + * with those used in remap_memory(), which can swap the BRAM and QSPI. + */ static const RAMInfo an524_raminfo[] = { { .name = "bram", .base = 0x00000000, @@ -457,6 +466,7 @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque, object_initialize_child(OBJECT(mms), "scc", scc, TYPE_MPS2_SCC); sccdev = DEVICE(scc); + qdev_prop_set_uint32(sccdev, "scc-cfg0", mms->remap ? 1 : 0); qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008); qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); @@ -573,6 +583,52 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque, return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0); } +static hwaddr boot_mem_base(MPS2TZMachineState *mms) +{ + /* + * Return the canonical address of the block which will be mapped + * at address 0x0 (i.e. where the vector table is). + * This is usually 0, but if the AN524 alternate memory map is + * enabled it will be the base address of the QSPI block. + */ + return mms->remap ? 0x28000000 : 0; +} + +static void remap_memory(MPS2TZMachineState *mms, int map) +{ + /* + * Remap the memory for the AN524. 'map' is the value of + * SCC CFG_REG0 bit 0, i.e. 0 for the default map and 1 + * for the "option 1" mapping where QSPI is at address 0. + * + * Effectively we need to swap around the "upstream" ends of + * MPC 0 and MPC 1. + */ + MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); + int i; + + if (mmc->fpga_type != FPGA_AN524) { + return; + } + + memory_region_transaction_begin(); + for (i = 0; i < 2; i++) { + TZMPC *mpc = &mms->mpc[i]; + MemoryRegion *upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1); + hwaddr addr = (i ^ map) ? 0x28000000 : 0; + + memory_region_set_address(upstream, addr); + } + memory_region_transaction_commit(); +} + +static void remap_irq_fn(void *opaque, int n, int level) +{ + MPS2TZMachineState *mms = opaque; + + remap_memory(mms, level); +} + static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque, const char *name, hwaddr size, const int *irqs) @@ -711,7 +767,7 @@ static uint32_t boot_ram_size(MPS2TZMachineState *mms) MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms); for (p = mmc->raminfo; p->name; p++) { - if (p->base == 0) { + if (p->base == boot_mem_base(mms)) { return p->size; } } @@ -1095,6 +1151,16 @@ static void mps2tz_common_init(MachineState *machine) create_non_mpc_ram(mms); + if (mmc->fpga_type == FPGA_AN524) { + /* + * Connect the line from the SCC so that we can remap when the + * guest updates that register. + */ + mms->remap_irq = qemu_allocate_irq(remap_irq_fn, mms, 0); + qdev_connect_gpio_out_named(DEVICE(&mms->scc), "remap", 0, + mms->remap_irq); + } + armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, boot_ram_size(mms)); } @@ -1117,12 +1183,47 @@ static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address, *iregion = region; } +static char *mps2_get_remap(Object *obj, Error **errp) +{ + MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj); + const char *val = mms->remap ? "QSPI" : "BRAM"; + return g_strdup(val); +} + +static void mps2_set_remap(Object *obj, const char *value, Error **errp) +{ + MPS2TZMachineState *mms = MPS2TZ_MACHINE(obj); + + if (!strcmp(value, "BRAM")) { + mms->remap = false; + } else if (!strcmp(value, "QSPI")) { + mms->remap = true; + } else { + error_setg(errp, "Invalid remap value"); + error_append_hint(errp, "Valid values are BRAM and QSPI.\n"); + } +} + +static void mps2_machine_reset(MachineState *machine) +{ + MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); + + /* + * Set the initial memory mapping before triggering the reset of + * the rest of the system, so that the guest image loader and CPU + * reset see the correct mapping. + */ + remap_memory(mms, mms->remap); + qemu_devices_reset(); +} + static void mps2tz_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc); mc->init = mps2tz_common_init; + mc->reset = mps2_machine_reset; iic->check = mps2_tz_idau_check; } @@ -1225,6 +1326,11 @@ static void mps3tz_an524_class_init(ObjectClass *oc, void *data) mmc->raminfo = an524_raminfo; mmc->armsse_type = TYPE_SSE200; mps2tz_set_default_ram_info(mmc); + + object_class_property_add_str(oc, "remap", mps2_get_remap, mps2_set_remap); + object_class_property_set_description(oc, "remap", + "Set memory mapping. Valid values " + "are BRAM (default) and QSPI."); } static void mps3tz_an547_class_init(ObjectClass *oc, void *data) From c3080fbdaa381012666428fef2e5f7ce422ecfee Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 4 May 2021 05:41:40 -0700 Subject: [PATCH 0390/3028] hw/arm/xlnx: Fix PHY address for xilinx-zynq-a9 Commit dfc388797cc4 ("hw/arm: xlnx: Set all boards' GEM 'phy-addr' property value to 23") configured the PHY address for xilinx-zynq-a9 to 23. When trying to boot xilinx-zynq-a9 with zynq-zc702.dtb or zynq-zc706.dtb, this results in the following error message when trying to use the Ethernet interface. macb e000b000.ethernet eth0: Could not attach PHY (-19) The devicetree files for ZC702 and ZC706 configure PHY address 7. The documentation for the ZC702 and ZC706 evaluation boards suggest that the PHY address is 7, not 23. Other boards use PHY address 0, 1, 3, or 7. I was unable to find a documentation or a devicetree file suggesting or using PHY address 23. The Ethernet interface starts working with zynq-zc702.dtb and zynq-zc706.dtb when setting the PHY address to 7, so let's use it. Cc: Bin Meng Signed-off-by: Guenter Roeck Reviewed-by: Bin Meng Acked-by: Edgar E. Iglesias Message-id: 20210504124140.1100346-1-linux@roeck-us.net Signed-off-by: Peter Maydell --- hw/arm/xilinx_zynq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 85f25d15db..81af32dc42 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -118,7 +118,7 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(dev, nd); } - object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort); + object_property_set_int(OBJECT(dev), "phy-addr", 7, &error_abort); s = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(s, &error_fatal); sysbus_mmio_map(s, 0, base); From e3a69234540d40b12c7d8f242fd8e21aadc2b81f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 Mar 2021 14:27:38 +0100 Subject: [PATCH 0391/3028] target/i386: Rename helper_fldt, helper_fstt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the prefix from "helper" to "do". The former should be reserved for those functions that are called from TCG; the latter is in use within the file already for those functions that are called from the helper functions, adding a "retaddr" argument. Signed-off-by: Richard Henderson Reviewed-by: Claudio Fontana Tested-by: Claudio Fontana Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-Id: <20210322132800.7470-3-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/tcg/fpu_helper.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 60ed93520a..3d9b192901 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -117,8 +117,7 @@ static inline void fpop(CPUX86State *env) env->fpstt = (env->fpstt + 1) & 7; } -static inline floatx80 helper_fldt(CPUX86State *env, target_ulong ptr, - uintptr_t retaddr) +static floatx80 do_fldt(CPUX86State *env, target_ulong ptr, uintptr_t retaddr) { CPU_LDoubleU temp; @@ -127,8 +126,8 @@ static inline floatx80 helper_fldt(CPUX86State *env, target_ulong ptr, return temp.d; } -static inline void helper_fstt(CPUX86State *env, floatx80 f, target_ulong ptr, - uintptr_t retaddr) +static void do_fstt(CPUX86State *env, floatx80 f, target_ulong ptr, + uintptr_t retaddr) { CPU_LDoubleU temp; @@ -405,14 +404,14 @@ void helper_fldt_ST0(CPUX86State *env, target_ulong ptr) int new_fpstt; new_fpstt = (env->fpstt - 1) & 7; - env->fpregs[new_fpstt].d = helper_fldt(env, ptr, GETPC()); + env->fpregs[new_fpstt].d = do_fldt(env, ptr, GETPC()); env->fpstt = new_fpstt; env->fptags[new_fpstt] = 0; /* validate stack entry */ } void helper_fstt_ST0(CPUX86State *env, target_ulong ptr) { - helper_fstt(env, ST0, ptr, GETPC()); + do_fstt(env, ST0, ptr, GETPC()); } void helper_fpush(CPUX86State *env) @@ -2468,7 +2467,7 @@ void helper_fsave(CPUX86State *env, target_ulong ptr, int data32) ptr += (14 << data32); for (i = 0; i < 8; i++) { tmp = ST(i); - helper_fstt(env, tmp, ptr, GETPC()); + do_fstt(env, tmp, ptr, GETPC()); ptr += 10; } @@ -2495,7 +2494,7 @@ void helper_frstor(CPUX86State *env, target_ulong ptr, int data32) ptr += (14 << data32); for (i = 0; i < 8; i++) { - tmp = helper_fldt(env, ptr, GETPC()); + tmp = do_fldt(env, ptr, GETPC()); ST(i) = tmp; ptr += 10; } @@ -2539,7 +2538,7 @@ static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) addr = ptr + XO(legacy.fpregs); for (i = 0; i < 8; i++) { floatx80 tmp = ST(i); - helper_fstt(env, tmp, addr, ra); + do_fstt(env, tmp, addr, ra); addr += 16; } } @@ -2703,7 +2702,7 @@ static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra) addr = ptr + XO(legacy.fpregs); for (i = 0; i < 8; i++) { - floatx80 tmp = helper_fldt(env, addr, ra); + floatx80 tmp = do_fldt(env, addr, ra); ST(i) = tmp; addr += 16; } From 0ac2b197430ebf19b5575ea48fe3b76d62110ab9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 Mar 2021 14:27:39 +0100 Subject: [PATCH 0392/3028] target/i386: Split out do_fsave, do_frstor, do_fxsave, do_fxrstor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The helper_* functions must use GETPC() to unwind from TCG. The cpu_x86_* functions cannot, and directly calling the helper_* functions is a bug. Split out new functions that perform the work and can be used by both. Signed-off-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Claudio Fontana Tested-by: Claudio Fontana Reviewed-by: Alex Bennée Message-Id: <20210322132800.7470-4-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/tcg/fpu_helper.c | 50 ++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 3d9b192901..20e4d2e715 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -2457,17 +2457,18 @@ void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32) do_fldenv(env, ptr, data32, GETPC()); } -void helper_fsave(CPUX86State *env, target_ulong ptr, int data32) +static void do_fsave(CPUX86State *env, target_ulong ptr, int data32, + uintptr_t retaddr) { floatx80 tmp; int i; - do_fstenv(env, ptr, data32, GETPC()); + do_fstenv(env, ptr, data32, retaddr); ptr += (14 << data32); for (i = 0; i < 8; i++) { tmp = ST(i); - do_fstt(env, tmp, ptr, GETPC()); + do_fstt(env, tmp, ptr, retaddr); ptr += 10; } @@ -2485,30 +2486,41 @@ void helper_fsave(CPUX86State *env, target_ulong ptr, int data32) env->fptags[7] = 1; } -void helper_frstor(CPUX86State *env, target_ulong ptr, int data32) +void helper_fsave(CPUX86State *env, target_ulong ptr, int data32) +{ + do_fsave(env, ptr, data32, GETPC()); +} + +static void do_frstor(CPUX86State *env, target_ulong ptr, int data32, + uintptr_t retaddr) { floatx80 tmp; int i; - do_fldenv(env, ptr, data32, GETPC()); + do_fldenv(env, ptr, data32, retaddr); ptr += (14 << data32); for (i = 0; i < 8; i++) { - tmp = do_fldt(env, ptr, GETPC()); + tmp = do_fldt(env, ptr, retaddr); ST(i) = tmp; ptr += 10; } } +void helper_frstor(CPUX86State *env, target_ulong ptr, int data32) +{ + do_frstor(env, ptr, data32, GETPC()); +} + #if defined(CONFIG_USER_ONLY) void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32) { - helper_fsave(env, ptr, data32); + do_fsave(env, ptr, data32, 0); } void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32) { - helper_frstor(env, ptr, data32); + do_frstor(env, ptr, data32, 0); } #endif @@ -2593,10 +2605,8 @@ static void do_xsave_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra) cpu_stq_data_ra(env, ptr, env->pkru, ra); } -void helper_fxsave(CPUX86State *env, target_ulong ptr) +static void do_fxsave(CPUX86State *env, target_ulong ptr, uintptr_t ra) { - uintptr_t ra = GETPC(); - /* The operand must be 16 byte aligned */ if (ptr & 0xf) { raise_exception_ra(env, EXCP0D_GPF, ra); @@ -2615,6 +2625,11 @@ void helper_fxsave(CPUX86State *env, target_ulong ptr) } } +void helper_fxsave(CPUX86State *env, target_ulong ptr) +{ + do_fxsave(env, ptr, GETPC()); +} + static uint64_t get_xinuse(CPUX86State *env) { uint64_t inuse = -1; @@ -2757,10 +2772,8 @@ static void do_xrstor_pkru(CPUX86State *env, target_ulong ptr, uintptr_t ra) env->pkru = cpu_ldq_data_ra(env, ptr, ra); } -void helper_fxrstor(CPUX86State *env, target_ulong ptr) +static void do_fxrstor(CPUX86State *env, target_ulong ptr, uintptr_t ra) { - uintptr_t ra = GETPC(); - /* The operand must be 16 byte aligned */ if (ptr & 0xf) { raise_exception_ra(env, EXCP0D_GPF, ra); @@ -2779,15 +2792,20 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr) } } +void helper_fxrstor(CPUX86State *env, target_ulong ptr) +{ + do_fxrstor(env, ptr, GETPC()); +} + #if defined(CONFIG_USER_ONLY) void cpu_x86_fxsave(CPUX86State *env, target_ulong ptr) { - helper_fxsave(env, ptr); + do_fxsave(env, ptr, 0); } void cpu_x86_fxrstor(CPUX86State *env, target_ulong ptr) { - helper_fxrstor(env, ptr); + do_fxrstor(env, ptr, 0); } #endif From f5cc5a5c168674f84bf061cdb307c2d25fba5448 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:40 +0100 Subject: [PATCH 0393/3028] i386: split cpu accelerators from cpu.c, using AccelCPUClass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i386 is the first user of AccelCPUClass, allowing to split cpu.c into: cpu.c cpuid and common x86 cpu functionality host-cpu.c host x86 cpu functions and "host" cpu type kvm/kvm-cpu.c KVM x86 AccelCPUClass hvf/hvf-cpu.c HVF x86 AccelCPUClass tcg/tcg-cpu.c TCG x86 AccelCPUClass Signed-off-by: Claudio Fontana Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson [claudio]: Rebased on commit b8184135 ("target/i386: allow modifying TCG phys-addr-bits") Signed-off-by: Claudio Fontana Message-Id: <20210322132800.7470-5-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 +- hw/i386/pc_piix.c | 1 + target/i386/cpu.c | 383 ++++-------------------------------- target/i386/cpu.h | 20 +- target/i386/host-cpu.c | 201 +++++++++++++++++++ target/i386/host-cpu.h | 19 ++ target/i386/hvf/hvf-cpu.c | 68 +++++++ target/i386/hvf/meson.build | 1 + target/i386/kvm/kvm-cpu.c | 151 ++++++++++++++ target/i386/kvm/kvm-cpu.h | 41 ++++ target/i386/kvm/kvm.c | 3 +- target/i386/kvm/meson.build | 7 +- target/i386/meson.build | 6 +- target/i386/tcg/tcg-cpu.c | 113 ++++++++++- target/i386/tcg/tcg-cpu.h | 15 -- 15 files changed, 652 insertions(+), 379 deletions(-) create mode 100644 target/i386/host-cpu.c create mode 100644 target/i386/host-cpu.h create mode 100644 target/i386/hvf/hvf-cpu.c create mode 100644 target/i386/kvm/kvm-cpu.c create mode 100644 target/i386/kvm/kvm-cpu.h delete mode 100644 target/i386/tcg/tcg-cpu.h diff --git a/MAINTAINERS b/MAINTAINERS index b692c8fbee..c2723b32cb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -351,7 +351,7 @@ M: Paolo Bonzini M: Richard Henderson M: Eduardo Habkost S: Maintained -F: target/i386/ +F: target/i386/tcg/ F: tests/tcg/i386/ F: tests/tcg/x86_64/ F: hw/i386/ diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 5ac2edbf1f..30b8bd6ea9 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -61,6 +61,7 @@ #include "hw/hyperv/vmbus-bridge.h" #include "hw/mem/nvdimm.h" #include "hw/i386/acpi-build.h" +#include "kvm/kvm-cpu.h" #define MAX_IDE_BUS 2 diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ad99cad0e7..da4142a69f 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -22,38 +22,25 @@ #include "qemu/cutils.h" #include "qemu/bitops.h" #include "qemu/qemu-print.h" - #include "cpu.h" -#include "tcg/tcg-cpu.h" #include "tcg/helper-tcg.h" #include "exec/exec-all.h" #include "sysemu/kvm.h" #include "sysemu/reset.h" #include "sysemu/hvf.h" -#include "sysemu/cpus.h" +#include "hw/core/accel-cpu.h" #include "sysemu/xen.h" #include "sysemu/whpx.h" #include "kvm/kvm_i386.h" #include "sev_i386.h" - -#include "qemu/error-report.h" #include "qemu/module.h" -#include "qemu/option.h" -#include "qemu/config-file.h" -#include "qapi/error.h" #include "qapi/qapi-visit-machine.h" #include "qapi/qapi-visit-run-state.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" -#include "qapi/visitor.h" #include "qom/qom-qobject.h" -#include "sysemu/arch_init.h" #include "qapi/qapi-commands-machine-target.h" - #include "standard-headers/asm-x86/kvm_para.h" - -#include "sysemu/sysemu.h" -#include "sysemu/tcg.h" #include "hw/qdev-properties.h" #include "hw/i386/topology.h" #ifndef CONFIG_USER_ONLY @@ -595,8 +582,8 @@ static CPUCacheInfo legacy_l3_cache = { #define INTEL_PT_CYCLE_BITMAP 0x1fff /* Support 0,2^(0~11) */ #define INTEL_PT_PSB_BITMAP (0x003f << 16) /* Support 2K,4K,8K,16K,32K,64K */ -static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, - uint32_t vendor2, uint32_t vendor3) +void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + uint32_t vendor2, uint32_t vendor3) { int i; for (i = 0; i < 4; i++) { @@ -1589,25 +1576,6 @@ void host_cpuid(uint32_t function, uint32_t count, *edx = vec[3]; } -void host_vendor_fms(char *vendor, int *family, int *model, int *stepping) -{ - uint32_t eax, ebx, ecx, edx; - - host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); - x86_cpu_vendor_words2str(vendor, ebx, edx, ecx); - - host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); - if (family) { - *family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF); - } - if (model) { - *model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12); - } - if (stepping) { - *stepping = eax & 0x0F; - } -} - /* CPU class name definitions: */ /* Return type name for a given CPU model name @@ -1632,10 +1600,6 @@ static char *x86_cpu_class_get_model_name(X86CPUClass *cc) strlen(class_name) - strlen(X86_CPU_TYPE_SUFFIX)); } -typedef struct PropValue { - const char *prop, *value; -} PropValue; - typedef struct X86CPUVersionDefinition { X86CPUVersion version; const char *alias; @@ -4249,32 +4213,6 @@ static X86CPUDefinition builtin_x86_defs[] = { }, }; -/* KVM-specific features that are automatically added/removed - * from all CPU models when KVM is enabled. - */ -static PropValue kvm_default_props[] = { - { "kvmclock", "on" }, - { "kvm-nopiodelay", "on" }, - { "kvm-asyncpf", "on" }, - { "kvm-steal-time", "on" }, - { "kvm-pv-eoi", "on" }, - { "kvmclock-stable-bit", "on" }, - { "x2apic", "on" }, - { "kvm-msi-ext-dest-id", "off" }, - { "acpi", "off" }, - { "monitor", "off" }, - { "svm", "off" }, - { NULL, NULL }, -}; - -/* TCG-specific defaults that override all CPU models when using TCG - */ -static PropValue tcg_default_props[] = { - { "vme", "off" }, - { NULL, NULL }, -}; - - /* * We resolve CPU model aliases using -v1 when using "-machine * none", but this is just for compatibility while libvirt isn't @@ -4316,61 +4254,6 @@ static X86CPUVersion x86_cpu_model_resolve_version(const X86CPUModel *model) return v; } -void x86_cpu_change_kvm_default(const char *prop, const char *value) -{ - PropValue *pv; - for (pv = kvm_default_props; pv->prop; pv++) { - if (!strcmp(pv->prop, prop)) { - pv->value = value; - break; - } - } - - /* It is valid to call this function only for properties that - * are already present in the kvm_default_props table. - */ - assert(pv->prop); -} - -static bool lmce_supported(void) -{ - uint64_t mce_cap = 0; - -#ifdef CONFIG_KVM - if (kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) { - return false; - } -#endif - - return !!(mce_cap & MCG_LMCE_P); -} - -#define CPUID_MODEL_ID_SZ 48 - -/** - * cpu_x86_fill_model_id: - * Get CPUID model ID string from host CPU. - * - * @str should have at least CPUID_MODEL_ID_SZ bytes - * - * The function does NOT add a null terminator to the string - * automatically. - */ -static int cpu_x86_fill_model_id(char *str) -{ - uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; - int i; - - for (i = 0; i < 3; i++) { - host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx); - memcpy(str + i * 16 + 0, &eax, 4); - memcpy(str + i * 16 + 4, &ebx, 4); - memcpy(str + i * 16 + 8, &ecx, 4); - memcpy(str + i * 16 + 12, &edx, 4); - } - return 0; -} - static Property max_x86_cpu_properties[] = { DEFINE_PROP_BOOL("migratable", X86CPU, migratable, true), DEFINE_PROP_BOOL("host-cache-info", X86CPU, cache_info_passthrough, false), @@ -4393,62 +4276,25 @@ static void max_x86_cpu_class_init(ObjectClass *oc, void *data) static void max_x86_cpu_initfn(Object *obj) { X86CPU *cpu = X86_CPU(obj); - CPUX86State *env = &cpu->env; - KVMState *s = kvm_state; /* We can't fill the features array here because we don't know yet if * "migratable" is true or false. */ cpu->max_features = true; - - if (accel_uses_host_cpuid()) { - char vendor[CPUID_VENDOR_SZ + 1] = { 0 }; - char model_id[CPUID_MODEL_ID_SZ + 1] = { 0 }; - int family, model, stepping; - - host_vendor_fms(vendor, &family, &model, &stepping); - cpu_x86_fill_model_id(model_id); - - object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); - object_property_set_int(OBJECT(cpu), "family", family, &error_abort); - object_property_set_int(OBJECT(cpu), "model", model, &error_abort); - object_property_set_int(OBJECT(cpu), "stepping", stepping, - &error_abort); - object_property_set_str(OBJECT(cpu), "model-id", model_id, - &error_abort); - - if (kvm_enabled()) { - env->cpuid_min_level = - kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX); - env->cpuid_min_xlevel = - kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX); - env->cpuid_min_xlevel2 = - kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); - } else { - env->cpuid_min_level = - hvf_get_supported_cpuid(0x0, 0, R_EAX); - env->cpuid_min_xlevel = - hvf_get_supported_cpuid(0x80000000, 0, R_EAX); - env->cpuid_min_xlevel2 = - hvf_get_supported_cpuid(0xC0000000, 0, R_EAX); - } - - if (lmce_supported()) { - object_property_set_bool(OBJECT(cpu), "lmce", true, &error_abort); - } - object_property_set_bool(OBJECT(cpu), "host-phys-bits", true, &error_abort); - } else { - object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD, - &error_abort); - object_property_set_int(OBJECT(cpu), "family", 6, &error_abort); - object_property_set_int(OBJECT(cpu), "model", 6, &error_abort); - object_property_set_int(OBJECT(cpu), "stepping", 3, &error_abort); - object_property_set_str(OBJECT(cpu), "model-id", - "QEMU TCG CPU version " QEMU_HW_VERSION, - &error_abort); - } - object_property_set_bool(OBJECT(cpu), "pmu", true, &error_abort); + + /* + * these defaults are used for TCG and all other accelerators + * besides KVM and HVF, which overwrite these values + */ + object_property_set_str(OBJECT(cpu), "vendor", CPUID_VENDOR_AMD, + &error_abort); + object_property_set_int(OBJECT(cpu), "family", 6, &error_abort); + object_property_set_int(OBJECT(cpu), "model", 6, &error_abort); + object_property_set_int(OBJECT(cpu), "stepping", 3, &error_abort); + object_property_set_str(OBJECT(cpu), "model-id", + "QEMU TCG CPU version " QEMU_HW_VERSION, + &error_abort); } static const TypeInfo max_x86_cpu_type_info = { @@ -4458,31 +4304,6 @@ static const TypeInfo max_x86_cpu_type_info = { .class_init = max_x86_cpu_class_init, }; -#if defined(CONFIG_KVM) || defined(CONFIG_HVF) -static void host_x86_cpu_class_init(ObjectClass *oc, void *data) -{ - X86CPUClass *xcc = X86_CPU_CLASS(oc); - - xcc->host_cpuid_required = true; - xcc->ordering = 8; - -#if defined(CONFIG_KVM) - xcc->model_description = - "KVM processor with all supported host features "; -#elif defined(CONFIG_HVF) - xcc->model_description = - "HVF processor with all supported host features "; -#endif -} - -static const TypeInfo host_x86_cpu_type_info = { - .name = X86_CPU_TYPE_NAME("host"), - .parent = X86_CPU_TYPE_NAME("max"), - .class_init = host_x86_cpu_class_init, -}; - -#endif - static char *feature_word_description(FeatureWordInfo *f, uint32_t bit) { assert(f->type == CPUID_FEATURE_WORD || f->type == MSR_FEATURE_WORD); @@ -5201,7 +5022,7 @@ static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w, return r; } -static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) +void x86_cpu_apply_props(X86CPU *cpu, PropValue *props) { PropValue *pv; for (pv = props; pv->prop; pv++) { @@ -5248,8 +5069,6 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) { X86CPUDefinition *def = model->cpudef; CPUX86State *env = &cpu->env; - const char *vendor; - char host_vendor[CPUID_VENDOR_SZ + 1]; FeatureWord w; /*NOTE: any property set by this function should be returned by @@ -5276,20 +5095,6 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) /* legacy-cache defaults to 'off' if CPU model provides cache info */ cpu->legacy_cache = !def->cache_info; - /* Special cases not set in the X86CPUDefinition structs: */ - /* TODO: in-kernel irqchip for hvf */ - if (kvm_enabled()) { - if (!kvm_irqchip_in_kernel()) { - x86_cpu_change_kvm_default("x2apic", "off"); - } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) { - x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on"); - } - - x86_cpu_apply_props(cpu, kvm_default_props); - } else if (tcg_enabled()) { - x86_cpu_apply_props(cpu, tcg_default_props); - } - env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR; /* sysenter isn't supported in compatibility mode on AMD, @@ -5299,15 +5104,12 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) * KVM's sysenter/syscall emulation in compatibility mode and * when doing cross vendor migration */ - vendor = def->vendor; - if (accel_uses_host_cpuid()) { - uint32_t ebx = 0, ecx = 0, edx = 0; - host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); - x86_cpu_vendor_words2str(host_vendor, ebx, edx, ecx); - vendor = host_vendor; - } - object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); + /* + * vendor property is set here but then overloaded with the + * host cpu vendor for KVM and HVF. + */ + object_property_set_str(OBJECT(cpu), "vendor", def->vendor, &error_abort); x86_cpu_apply_version_props(cpu, model); @@ -6338,53 +6140,12 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) apic_mmio_map_once = true; } } - -static void x86_cpu_machine_done(Notifier *n, void *unused) -{ - X86CPU *cpu = container_of(n, X86CPU, machine_done); - MemoryRegion *smram = - (MemoryRegion *) object_resolve_path("/machine/smram", NULL); - - if (smram) { - cpu->smram = g_new(MemoryRegion, 1); - memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram", - smram, 0, 4 * GiB); - memory_region_set_enabled(cpu->smram, true); - memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->smram, 1); - } -} #else static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) { } #endif -/* Note: Only safe for use on x86(-64) hosts */ -static uint32_t x86_host_phys_bits(void) -{ - uint32_t eax; - uint32_t host_phys_bits; - - host_cpuid(0x80000000, 0, &eax, NULL, NULL, NULL); - if (eax >= 0x80000008) { - host_cpuid(0x80000008, 0, &eax, NULL, NULL, NULL); - /* Note: According to AMD doc 25481 rev 2.34 they have a field - * at 23:16 that can specify a maximum physical address bits for - * the guest that can override this value; but I've not seen - * anything with that set. - */ - host_phys_bits = eax & 0xff; - } else { - /* It's an odd 64 bit machine that doesn't have the leaf for - * physical address bits; fall back to 36 that's most older - * Intel. - */ - host_phys_bits = 36; - } - - return host_phys_bits; -} - static void x86_cpu_adjust_level(X86CPU *cpu, uint32_t *min, uint32_t value) { if (*min < value) { @@ -6696,33 +6457,22 @@ static void x86_cpu_hyperv_realize(X86CPU *cpu) static void x86_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); + CPUClass *cc = CPU_GET_CLASS(cs); X86CPU *cpu = X86_CPU(dev); X86CPUClass *xcc = X86_CPU_GET_CLASS(dev); CPUX86State *env = &cpu->env; Error *local_err = NULL; static bool ht_warned; - if (xcc->host_cpuid_required) { - if (!accel_uses_host_cpuid()) { - g_autofree char *name = x86_cpu_class_get_model_name(xcc); - error_setg(&local_err, "CPU model '%s' requires KVM", name); - goto out; - } + /* The accelerator realizefn needs to be called first. */ + if (cc->accel_cpu) { + cc->accel_cpu->cpu_realizefn(cs, errp); } - if (cpu->max_features && accel_uses_host_cpuid()) { - if (enable_cpu_pm) { - host_cpuid(5, 0, &cpu->mwait.eax, &cpu->mwait.ebx, - &cpu->mwait.ecx, &cpu->mwait.edx); - env->features[FEAT_1_ECX] |= CPUID_EXT_MONITOR; - if (kvm_enabled() && kvm_has_waitpkg()) { - env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_WAITPKG; - } - } - if (kvm_enabled() && cpu->ucode_rev == 0) { - cpu->ucode_rev = kvm_arch_get_supported_msr_feature(kvm_state, - MSR_IA32_UCODE_REV); - } + if (xcc->host_cpuid_required && !accel_uses_host_cpuid()) { + g_autofree char *name = x86_cpu_class_get_model_name(xcc); + error_setg(&local_err, "CPU model '%s' requires KVM or HVF", name); + goto out; } if (cpu->ucode_rev == 0) { @@ -6774,30 +6524,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) * consumer AMD devices but nothing else. */ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { - if (accel_uses_host_cpuid()) { - uint32_t host_phys_bits = x86_host_phys_bits(); - static bool warned; - - /* Print a warning if the user set it to a value that's not the - * host value. - */ - if (cpu->phys_bits != host_phys_bits && cpu->phys_bits != 0 && - !warned) { - warn_report("Host physical bits (%u)" - " does not match phys-bits property (%u)", - host_phys_bits, cpu->phys_bits); - warned = true; - } - - if (cpu->host_phys_bits) { - /* The user asked for us to use the host physical bits */ - cpu->phys_bits = host_phys_bits; - if (cpu->host_phys_bits_limit && - cpu->phys_bits > cpu->host_phys_bits_limit) { - cpu->phys_bits = cpu->host_phys_bits_limit; - } - } - } if (cpu->phys_bits && (cpu->phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || cpu->phys_bits < 32)) { @@ -6806,9 +6532,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) TARGET_PHYS_ADDR_SPACE_BITS, cpu->phys_bits); return; } - /* 0 means it was not explicitly set by the user (or by machine - * compat_props or by the host code above). In this case, the default - * is the value used by TCG (40). + /* + * 0 means it was not explicitly set by the user (or by machine + * compat_props or by the host code in host-cpu.c). + * In this case, the default is the value used by TCG (40). */ if (cpu->phys_bits == 0) { cpu->phys_bits = TCG_PHYS_ADDR_BITS; @@ -6880,33 +6607,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) mce_init(cpu); -#ifndef CONFIG_USER_ONLY - if (tcg_enabled()) { - cpu->cpu_as_mem = g_new(MemoryRegion, 1); - cpu->cpu_as_root = g_new(MemoryRegion, 1); - - /* Outer container... */ - memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull); - memory_region_set_enabled(cpu->cpu_as_root, true); - - /* ... with two regions inside: normal system memory with low - * priority, and... - */ - memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory", - get_system_memory(), 0, ~0ull); - memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); - memory_region_set_enabled(cpu->cpu_as_mem, true); - - cs->num_ases = 2; - cpu_address_space_init(cs, 0, "cpu-memory", cs->memory); - cpu_address_space_init(cs, 1, "cpu-smm", cpu->cpu_as_root); - - /* ... SMRAM with higher priority, linked from /machine/smram. */ - cpu->machine_done.notify = x86_cpu_machine_done; - qemu_add_machine_init_done_notifier(&cpu->machine_done); - } -#endif - qemu_init_vcpu(cs); /* @@ -7106,6 +6806,8 @@ static void x86_cpu_initfn(Object *obj) { X86CPU *cpu = X86_CPU(obj); X86CPUClass *xcc = X86_CPU_GET_CLASS(obj); + CPUClass *cc = CPU_CLASS(xcc); + CPUX86State *env = &cpu->env; env->nr_dies = 1; @@ -7153,6 +6855,11 @@ static void x86_cpu_initfn(Object *obj) if (xcc->model) { x86_cpu_load_model(cpu, xcc->model); } + + /* if required, do the accelerator-specific cpu initialization */ + if (cc->accel_cpu) { + cc->accel_cpu->cpu_instance_init(CPU(obj)); + } } static int64_t x86_cpu_get_arch_id(CPUState *cs) @@ -7410,11 +7117,6 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->class_by_name = x86_cpu_class_by_name; cc->parse_features = x86_cpu_parse_featurestr; cc->has_work = x86_cpu_has_work; - -#ifdef CONFIG_TCG - tcg_cpu_common_class_init(cc); -#endif /* CONFIG_TCG */ - cc->dump_state = x86_cpu_dump_state; cc->set_pc = x86_cpu_set_pc; cc->gdb_read_register = x86_cpu_gdb_read_register; @@ -7525,9 +7227,6 @@ static void x86_cpu_register_types(void) } type_register_static(&max_x86_cpu_type_info); type_register_static(&x86_base_cpu_type_info); -#if defined(CONFIG_KVM) || defined(CONFIG_HVF) - type_register_static(&host_x86_cpu_type_info); -#endif } type_init(x86_cpu_register_types) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 1bc300ce85..4776daad23 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1926,13 +1926,20 @@ int cpu_x86_signal_handler(int host_signum, void *pinfo, void *puc); /* cpu.c */ +void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, + uint32_t vendor2, uint32_t vendor3); +typedef struct PropValue { + const char *prop, *value; +} PropValue; +void x86_cpu_apply_props(X86CPU *cpu, PropValue *props); + +/* cpu.c other functions (cpuid) */ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); void cpu_clear_apic_feature(CPUX86State *env); void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); -void host_vendor_fms(char *vendor, int *family, int *model, int *stepping); /* helper.c */ void x86_cpu_set_a20(X86CPU *cpu, int a20_state); @@ -2137,17 +2144,6 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip, TPRAccess access); - -/* Change the value of a KVM-specific default - * - * If value is NULL, no default will be set and the original - * value from the CPU model table will be kept. - * - * It is valid to call this function only for properties that - * are already present in the kvm_default_props table. - */ -void x86_cpu_change_kvm_default(const char *prop, const char *value); - /* Special values for X86CPUVersion: */ /* Resolve to latest CPU version */ diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c new file mode 100644 index 0000000000..9cfe56ce41 --- /dev/null +++ b/target/i386/host-cpu.c @@ -0,0 +1,201 @@ +/* + * x86 host CPU functions, and "host" cpu type initialization + * + * Copyright 2021 SUSE LLC + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "host-cpu.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" + +/* Note: Only safe for use on x86(-64) hosts */ +static uint32_t host_cpu_phys_bits(void) +{ + uint32_t eax; + uint32_t host_phys_bits; + + host_cpuid(0x80000000, 0, &eax, NULL, NULL, NULL); + if (eax >= 0x80000008) { + host_cpuid(0x80000008, 0, &eax, NULL, NULL, NULL); + /* + * Note: According to AMD doc 25481 rev 2.34 they have a field + * at 23:16 that can specify a maximum physical address bits for + * the guest that can override this value; but I've not seen + * anything with that set. + */ + host_phys_bits = eax & 0xff; + } else { + /* + * It's an odd 64 bit machine that doesn't have the leaf for + * physical address bits; fall back to 36 that's most older + * Intel. + */ + host_phys_bits = 36; + } + + return host_phys_bits; +} + +static void host_cpu_enable_cpu_pm(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + + host_cpuid(5, 0, &cpu->mwait.eax, &cpu->mwait.ebx, + &cpu->mwait.ecx, &cpu->mwait.edx); + env->features[FEAT_1_ECX] |= CPUID_EXT_MONITOR; +} + +static uint32_t host_cpu_adjust_phys_bits(X86CPU *cpu, Error **errp) +{ + uint32_t host_phys_bits = host_cpu_phys_bits(); + uint32_t phys_bits = cpu->phys_bits; + static bool warned; + + /* + * Print a warning if the user set it to a value that's not the + * host value. + */ + if (phys_bits != host_phys_bits && phys_bits != 0 && + !warned) { + warn_report("Host physical bits (%u)" + " does not match phys-bits property (%u)", + host_phys_bits, phys_bits); + warned = true; + } + + if (cpu->host_phys_bits) { + /* The user asked for us to use the host physical bits */ + phys_bits = host_phys_bits; + if (cpu->host_phys_bits_limit && + phys_bits > cpu->host_phys_bits_limit) { + phys_bits = cpu->host_phys_bits_limit; + } + } + + if (phys_bits && + (phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || + phys_bits < 32)) { + error_setg(errp, "phys-bits should be between 32 and %u " + " (but is %u)", + TARGET_PHYS_ADDR_SPACE_BITS, phys_bits); + } + + return phys_bits; +} + +void host_cpu_realizefn(CPUState *cs, Error **errp) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + if (cpu->max_features && enable_cpu_pm) { + host_cpu_enable_cpu_pm(cpu); + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { + cpu->phys_bits = host_cpu_adjust_phys_bits(cpu, errp); + } +} + +#define CPUID_MODEL_ID_SZ 48 +/** + * cpu_x86_fill_model_id: + * Get CPUID model ID string from host CPU. + * + * @str should have at least CPUID_MODEL_ID_SZ bytes + * + * The function does NOT add a null terminator to the string + * automatically. + */ +static int host_cpu_fill_model_id(char *str) +{ + uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; + int i; + + for (i = 0; i < 3; i++) { + host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx); + memcpy(str + i * 16 + 0, &eax, 4); + memcpy(str + i * 16 + 4, &ebx, 4); + memcpy(str + i * 16 + 8, &ecx, 4); + memcpy(str + i * 16 + 12, &edx, 4); + } + return 0; +} + +void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping) +{ + uint32_t eax, ebx, ecx, edx; + + host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); + x86_cpu_vendor_words2str(vendor, ebx, edx, ecx); + + host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); + if (family) { + *family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF); + } + if (model) { + *model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12); + } + if (stepping) { + *stepping = eax & 0x0F; + } +} + +void host_cpu_instance_init(X86CPU *cpu) +{ + uint32_t ebx = 0, ecx = 0, edx = 0; + char vendor[CPUID_VENDOR_SZ + 1]; + + host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); + x86_cpu_vendor_words2str(vendor, ebx, edx, ecx); + + object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); +} + +void host_cpu_max_instance_init(X86CPU *cpu) +{ + char vendor[CPUID_VENDOR_SZ + 1] = { 0 }; + char model_id[CPUID_MODEL_ID_SZ + 1] = { 0 }; + int family, model, stepping; + + /* Use max host physical address bits if -cpu max option is applied */ + object_property_set_bool(OBJECT(cpu), "host-phys-bits", true, &error_abort); + + host_cpu_vendor_fms(vendor, &family, &model, &stepping); + host_cpu_fill_model_id(model_id); + + object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); + object_property_set_int(OBJECT(cpu), "family", family, &error_abort); + object_property_set_int(OBJECT(cpu), "model", model, &error_abort); + object_property_set_int(OBJECT(cpu), "stepping", stepping, + &error_abort); + object_property_set_str(OBJECT(cpu), "model-id", model_id, + &error_abort); +} + +static void host_cpu_class_init(ObjectClass *oc, void *data) +{ + X86CPUClass *xcc = X86_CPU_CLASS(oc); + + xcc->host_cpuid_required = true; + xcc->ordering = 8; + xcc->model_description = + g_strdup_printf("processor with all supported host features "); +} + +static const TypeInfo host_cpu_type_info = { + .name = X86_CPU_TYPE_NAME("host"), + .parent = X86_CPU_TYPE_NAME("max"), + .class_init = host_cpu_class_init, +}; + +static void host_cpu_type_init(void) +{ + type_register_static(&host_cpu_type_info); +} + +type_init(host_cpu_type_init); diff --git a/target/i386/host-cpu.h b/target/i386/host-cpu.h new file mode 100644 index 0000000000..b47bc0943f --- /dev/null +++ b/target/i386/host-cpu.h @@ -0,0 +1,19 @@ +/* + * x86 host CPU type initialization and host CPU functions + * + * Copyright 2021 SUSE LLC + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef HOST_CPU_H +#define HOST_CPU_H + +void host_cpu_instance_init(X86CPU *cpu); +void host_cpu_max_instance_init(X86CPU *cpu); +void host_cpu_realizefn(CPUState *cs, Error **errp); + +void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping); + +#endif /* HOST_CPU_H */ diff --git a/target/i386/hvf/hvf-cpu.c b/target/i386/hvf/hvf-cpu.c new file mode 100644 index 0000000000..8fbc423888 --- /dev/null +++ b/target/i386/hvf/hvf-cpu.c @@ -0,0 +1,68 @@ +/* + * x86 HVF CPU type initialization + * + * Copyright 2021 SUSE LLC + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "host-cpu.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "sysemu/hvf.h" +#include "hw/core/accel-cpu.h" + +static void hvf_cpu_max_instance_init(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + + host_cpu_max_instance_init(cpu); + + env->cpuid_min_level = + hvf_get_supported_cpuid(0x0, 0, R_EAX); + env->cpuid_min_xlevel = + hvf_get_supported_cpuid(0x80000000, 0, R_EAX); + env->cpuid_min_xlevel2 = + hvf_get_supported_cpuid(0xC0000000, 0, R_EAX); +} + +static void hvf_cpu_instance_init(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + + host_cpu_instance_init(cpu); + + /* Special cases not set in the X86CPUDefinition structs: */ + /* TODO: in-kernel irqchip for hvf */ + + if (cpu->max_features) { + hvf_cpu_max_instance_init(cpu); + } +} + +static void hvf_cpu_accel_class_init(ObjectClass *oc, void *data) +{ + AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); + + acc->cpu_realizefn = host_cpu_realizefn; + acc->cpu_instance_init = hvf_cpu_instance_init; +} + +static const TypeInfo hvf_cpu_accel_type_info = { + .name = ACCEL_CPU_NAME("hvf"), + + .parent = TYPE_ACCEL_CPU, + .class_init = hvf_cpu_accel_class_init, + .abstract = true, +}; + +static void hvf_cpu_accel_register_types(void) +{ + type_register_static(&hvf_cpu_accel_type_info); +} + +type_init(hvf_cpu_accel_register_types); diff --git a/target/i386/hvf/meson.build b/target/i386/hvf/meson.build index e9eb5a5da8..d253d5fd10 100644 --- a/target/i386/hvf/meson.build +++ b/target/i386/hvf/meson.build @@ -10,4 +10,5 @@ i386_softmmu_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files( 'x86_mmu.c', 'x86_task.c', 'x86hvf.c', + 'hvf-cpu.c', )) diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c new file mode 100644 index 0000000000..c23bbe6c50 --- /dev/null +++ b/target/i386/kvm/kvm-cpu.c @@ -0,0 +1,151 @@ +/* + * x86 KVM CPU type initialization + * + * Copyright 2021 SUSE LLC + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "host-cpu.h" +#include "kvm-cpu.h" +#include "qapi/error.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" + +#include "kvm_i386.h" +#include "hw/core/accel-cpu.h" + +static void kvm_cpu_realizefn(CPUState *cs, Error **errp) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + /* + * The realize order is important, since x86_cpu_realize() checks if + * nothing else has been set by the user (or by accelerators) in + * cpu->ucode_rev and cpu->phys_bits. + * + * realize order: + * kvm_cpu -> host_cpu -> x86_cpu + */ + if (cpu->max_features) { + if (enable_cpu_pm && kvm_has_waitpkg()) { + env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_WAITPKG; + } + if (cpu->ucode_rev == 0) { + cpu->ucode_rev = + kvm_arch_get_supported_msr_feature(kvm_state, + MSR_IA32_UCODE_REV); + } + } + host_cpu_realizefn(cs, errp); +} + +/* + * KVM-specific features that are automatically added/removed + * from all CPU models when KVM is enabled. + */ +static PropValue kvm_default_props[] = { + { "kvmclock", "on" }, + { "kvm-nopiodelay", "on" }, + { "kvm-asyncpf", "on" }, + { "kvm-steal-time", "on" }, + { "kvm-pv-eoi", "on" }, + { "kvmclock-stable-bit", "on" }, + { "x2apic", "on" }, + { "kvm-msi-ext-dest-id", "off" }, + { "acpi", "off" }, + { "monitor", "off" }, + { "svm", "off" }, + { NULL, NULL }, +}; + +void x86_cpu_change_kvm_default(const char *prop, const char *value) +{ + PropValue *pv; + for (pv = kvm_default_props; pv->prop; pv++) { + if (!strcmp(pv->prop, prop)) { + pv->value = value; + break; + } + } + + /* + * It is valid to call this function only for properties that + * are already present in the kvm_default_props table. + */ + assert(pv->prop); +} + +static bool lmce_supported(void) +{ + uint64_t mce_cap = 0; + + if (kvm_ioctl(kvm_state, KVM_X86_GET_MCE_CAP_SUPPORTED, &mce_cap) < 0) { + return false; + } + return !!(mce_cap & MCG_LMCE_P); +} + +static void kvm_cpu_max_instance_init(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + KVMState *s = kvm_state; + + host_cpu_max_instance_init(cpu); + + if (lmce_supported()) { + object_property_set_bool(OBJECT(cpu), "lmce", true, &error_abort); + } + + env->cpuid_min_level = + kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX); + env->cpuid_min_xlevel = + kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX); + env->cpuid_min_xlevel2 = + kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); +} + +static void kvm_cpu_instance_init(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + + host_cpu_instance_init(cpu); + + if (!kvm_irqchip_in_kernel()) { + x86_cpu_change_kvm_default("x2apic", "off"); + } else if (kvm_irqchip_is_split() && kvm_enable_x2apic()) { + x86_cpu_change_kvm_default("kvm-msi-ext-dest-id", "on"); + } + + /* Special cases not set in the X86CPUDefinition structs: */ + + x86_cpu_apply_props(cpu, kvm_default_props); + + if (cpu->max_features) { + kvm_cpu_max_instance_init(cpu); + } +} + +static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) +{ + AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); + + acc->cpu_realizefn = kvm_cpu_realizefn; + acc->cpu_instance_init = kvm_cpu_instance_init; +} +static const TypeInfo kvm_cpu_accel_type_info = { + .name = ACCEL_CPU_NAME("kvm"), + + .parent = TYPE_ACCEL_CPU, + .class_init = kvm_cpu_accel_class_init, + .abstract = true, +}; +static void kvm_cpu_accel_register_types(void) +{ + type_register_static(&kvm_cpu_accel_type_info); +} +type_init(kvm_cpu_accel_register_types); diff --git a/target/i386/kvm/kvm-cpu.h b/target/i386/kvm/kvm-cpu.h new file mode 100644 index 0000000000..e858ca21e5 --- /dev/null +++ b/target/i386/kvm/kvm-cpu.h @@ -0,0 +1,41 @@ +/* + * i386 KVM CPU type and functions + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef KVM_CPU_H +#define KVM_CPU_H + +#ifdef CONFIG_KVM +/* + * Change the value of a KVM-specific default + * + * If value is NULL, no default will be set and the original + * value from the CPU model table will be kept. + * + * It is valid to call this function only for properties that + * are already present in the kvm_default_props table. + */ +void x86_cpu_change_kvm_default(const char *prop, const char *value); + +#else /* !CONFIG_KVM */ + +#define x86_cpu_change_kvm_default(a, b) + +#endif /* CONFIG_KVM */ + +#endif /* KVM_CPU_H */ diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 7fe9f52710..d972eb4705 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -22,6 +22,7 @@ #include "standard-headers/asm-x86/kvm_para.h" #include "cpu.h" +#include "host-cpu.h" #include "sysemu/sysemu.h" #include "sysemu/hw_accel.h" #include "sysemu/kvm_int.h" @@ -288,7 +289,7 @@ static bool host_tsx_broken(void) int family, model, stepping;\ char vendor[CPUID_VENDOR_SZ + 1]; - host_vendor_fms(vendor, &family, &model, &stepping); + host_cpu_vendor_fms(vendor, &family, &model, &stepping); /* Check if we are running on a Haswell host known to have broken TSX */ return !strcmp(vendor, CPUID_VENDOR_INTEL) && diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build index 1d66559187..0a533411ca 100644 --- a/target/i386/kvm/meson.build +++ b/target/i386/kvm/meson.build @@ -1,3 +1,8 @@ i386_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) -i386_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c')) + +i386_softmmu_ss.add(when: 'CONFIG_KVM', if_true: files( + 'kvm.c', + 'kvm-cpu.c', +)) + i386_softmmu_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c')) diff --git a/target/i386/meson.build b/target/i386/meson.build index b0c04f3d89..6f3b0255c0 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build @@ -6,7 +6,11 @@ i386_ss.add(files( 'xsave_helper.c', 'cpu-dump.c', )) -i386_ss.add(when: 'CONFIG_SEV', if_true: files('sev.c'), if_false: files('sev-stub.c')) +i386_ss.add(when: 'CONFIG_SEV', if_true: files('host-cpu.c', 'sev.c'), if_false: files('sev-stub.c')) + +# x86 cpu type +i386_ss.add(when: 'CONFIG_KVM', if_true: files('host-cpu.c')) +i386_ss.add(when: 'CONFIG_HVF', if_true: files('host-cpu.c')) i386_softmmu_ss = ss.source_set() i386_softmmu_ss.add(files( diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 1e125d2175..1d3d6d1c6a 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -19,13 +19,14 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "tcg-cpu.h" -#include "exec/exec-all.h" -#include "sysemu/runstate.h" #include "helper-tcg.h" +#include "qemu/accel.h" +#include "hw/core/accel-cpu.h" -#if !defined(CONFIG_USER_ONLY) -#include "hw/i386/apic.h" +#ifndef CONFIG_USER_ONLY +#include "sysemu/sysemu.h" +#include "qemu/units.h" +#include "exec/address-spaces.h" #endif /* Frob eflags into and out of the CPU temporary format. */ @@ -72,7 +73,107 @@ static struct TCGCPUOps x86_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -void tcg_cpu_common_class_init(CPUClass *cc) +static void tcg_cpu_class_init(CPUClass *cc) { cc->tcg_ops = &x86_tcg_ops; } + +#ifndef CONFIG_USER_ONLY + +static void x86_cpu_machine_done(Notifier *n, void *unused) +{ + X86CPU *cpu = container_of(n, X86CPU, machine_done); + MemoryRegion *smram = + (MemoryRegion *) object_resolve_path("/machine/smram", NULL); + + if (smram) { + cpu->smram = g_new(MemoryRegion, 1); + memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram", + smram, 0, 4 * GiB); + memory_region_set_enabled(cpu->smram, true); + memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, + cpu->smram, 1); + } +} + +static void tcg_cpu_realizefn(CPUState *cs, Error **errp) +{ + X86CPU *cpu = X86_CPU(cs); + + /* + * The realize order is important, since x86_cpu_realize() checks if + * nothing else has been set by the user (or by accelerators) in + * cpu->ucode_rev and cpu->phys_bits, and the memory regions + * initialized here are needed for the vcpu initialization. + * + * realize order: + * tcg_cpu -> host_cpu -> x86_cpu + */ + cpu->cpu_as_mem = g_new(MemoryRegion, 1); + cpu->cpu_as_root = g_new(MemoryRegion, 1); + + /* Outer container... */ + memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull); + memory_region_set_enabled(cpu->cpu_as_root, true); + + /* + * ... with two regions inside: normal system memory with low + * priority, and... + */ + memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory", + get_system_memory(), 0, ~0ull); + memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); + memory_region_set_enabled(cpu->cpu_as_mem, true); + + cs->num_ases = 2; + cpu_address_space_init(cs, 0, "cpu-memory", cs->memory); + cpu_address_space_init(cs, 1, "cpu-smm", cpu->cpu_as_root); + + /* ... SMRAM with higher priority, linked from /machine/smram. */ + cpu->machine_done.notify = x86_cpu_machine_done; + qemu_add_machine_init_done_notifier(&cpu->machine_done); +} + +#else /* CONFIG_USER_ONLY */ + +static void tcg_cpu_realizefn(CPUState *cs, Error **errp) +{ +} + +#endif /* !CONFIG_USER_ONLY */ + +/* + * TCG-specific defaults that override all CPU models when using TCG + */ +static PropValue tcg_default_props[] = { + { "vme", "off" }, + { NULL, NULL }, +}; + +static void tcg_cpu_instance_init(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + /* Special cases not set in the X86CPUDefinition structs: */ + x86_cpu_apply_props(cpu, tcg_default_props); +} + +static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data) +{ + AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); + + acc->cpu_realizefn = tcg_cpu_realizefn; + acc->cpu_class_init = tcg_cpu_class_init; + acc->cpu_instance_init = tcg_cpu_instance_init; +} +static const TypeInfo tcg_cpu_accel_type_info = { + .name = ACCEL_CPU_NAME("tcg"), + + .parent = TYPE_ACCEL_CPU, + .class_init = tcg_cpu_accel_class_init, + .abstract = true, +}; +static void tcg_cpu_accel_register_types(void) +{ + type_register_static(&tcg_cpu_accel_type_info); +} +type_init(tcg_cpu_accel_register_types); diff --git a/target/i386/tcg/tcg-cpu.h b/target/i386/tcg/tcg-cpu.h deleted file mode 100644 index 81f02e562e..0000000000 --- a/target/i386/tcg/tcg-cpu.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * i386 TCG CPU class initialization - * - * Copyright 2020 SUSE LLC - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#ifndef TCG_CPU_H -#define TCG_CPU_H - -void tcg_cpu_common_class_init(CPUClass *cc); - -#endif /* TCG_CPU_H */ From 30565f10e90778cb52bcf4d798195d18d7aa80d7 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:41 +0100 Subject: [PATCH 0394/3028] cpu: call AccelCPUClass::cpu_realizefn in cpu_exec_realizefn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit move the call to accel_cpu->cpu_realizefn to the general cpu_exec_realizefn from target/i386, so it does not need to be called for every target explicitly as we enable more targets. Signed-off-by: Claudio Fontana Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-6-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- cpu.c | 6 ++++++ target/i386/cpu.c | 20 +++++++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cpu.c b/cpu.c index bfbe5a66f9..ba5d272c1e 100644 --- a/cpu.c +++ b/cpu.c @@ -36,6 +36,7 @@ #include "sysemu/replay.h" #include "exec/translate-all.h" #include "exec/log.h" +#include "hw/core/accel-cpu.h" uintptr_t qemu_host_page_size; intptr_t qemu_host_page_mask; @@ -130,6 +131,11 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp) cpu_list_add(cpu); + if (cc->accel_cpu) { + /* NB: errp parameter is unused currently */ + cc->accel_cpu->cpu_realizefn(cpu, errp); + } + #ifdef CONFIG_TCG /* NB: errp parameter is unused currently */ if (tcg_enabled()) { diff --git a/target/i386/cpu.c b/target/i386/cpu.c index da4142a69f..fb7a7be2fd 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6457,16 +6457,19 @@ static void x86_cpu_hyperv_realize(X86CPU *cpu) static void x86_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); - CPUClass *cc = CPU_GET_CLASS(cs); X86CPU *cpu = X86_CPU(dev); X86CPUClass *xcc = X86_CPU_GET_CLASS(dev); CPUX86State *env = &cpu->env; Error *local_err = NULL; static bool ht_warned; - /* The accelerator realizefn needs to be called first. */ - if (cc->accel_cpu) { - cc->accel_cpu->cpu_realizefn(cs, errp); + /* Process Hyper-V enlightenments */ + x86_cpu_hyperv_realize(cpu); + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; } if (xcc->host_cpuid_required && !accel_uses_host_cpuid()) { @@ -6584,15 +6587,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) env->cache_info_amd.l3_cache = &legacy_l3_cache; } - /* Process Hyper-V enlightenments */ - x86_cpu_hyperv_realize(cpu); - - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - #ifndef CONFIG_USER_ONLY MachineState *ms = MACHINE(qdev_get_machine()); qemu_register_reset(x86_cpu_machine_reset_cb, cpu); From bb883fd67707fd7f1bf04369aafd7ea7ad5b01b0 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:42 +0100 Subject: [PATCH 0395/3028] accel: introduce new accessor functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit avoid open coding the accesses to cpu->accel_cpu interfaces, and instead introduce: accel_cpu_instance_init, accel_cpu_realizefn to be used by the targets/ initfn code, and by cpu_exec_realizefn respectively. Signed-off-by: Claudio Fontana Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-7-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- accel/accel-common.c | 19 +++++++++++++++++++ cpu.c | 6 +----- include/qemu/accel.h | 13 +++++++++++++ target/i386/cpu.c | 9 ++------- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/accel/accel-common.c b/accel/accel-common.c index 9901b0531c..0f6fb4fb66 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -89,6 +89,25 @@ void accel_init_interfaces(AccelClass *ac) accel_init_cpu_interfaces(ac); } +void accel_cpu_instance_init(CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->accel_cpu && cc->accel_cpu->cpu_instance_init) { + cc->accel_cpu->cpu_instance_init(cpu); + } +} + +void accel_cpu_realizefn(CPUState *cpu, Error **errp) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->accel_cpu && cc->accel_cpu->cpu_realizefn) { + /* NB: errp parameter is unused currently */ + cc->accel_cpu->cpu_realizefn(cpu, errp); + } +} + static const TypeInfo accel_cpu_type = { .name = TYPE_ACCEL_CPU, .parent = TYPE_OBJECT, diff --git a/cpu.c b/cpu.c index ba5d272c1e..25e6fbfa2c 100644 --- a/cpu.c +++ b/cpu.c @@ -130,11 +130,7 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp) CPUClass *cc = CPU_GET_CLASS(cpu); cpu_list_add(cpu); - - if (cc->accel_cpu) { - /* NB: errp parameter is unused currently */ - cc->accel_cpu->cpu_realizefn(cpu, errp); - } + accel_cpu_realizefn(cpu, errp); #ifdef CONFIG_TCG /* NB: errp parameter is unused currently */ diff --git a/include/qemu/accel.h b/include/qemu/accel.h index b9d6d69eb8..da0c8ab523 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -78,4 +78,17 @@ int accel_init_machine(AccelState *accel, MachineState *ms); void accel_setup_post(MachineState *ms); #endif /* !CONFIG_USER_ONLY */ +/** + * accel_cpu_instance_init: + * @cpu: The CPU that needs to do accel-specific object initializations. + */ +void accel_cpu_instance_init(CPUState *cpu); + +/** + * accel_cpu_realizefn: + * @cpu: The CPU that needs to call accel-specific cpu realization. + * @errp: currently unused. + */ +void accel_cpu_realizefn(CPUState *cpu, Error **errp); + #endif /* QEMU_ACCEL_H */ diff --git a/target/i386/cpu.c b/target/i386/cpu.c index fb7a7be2fd..010db23379 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -28,7 +28,6 @@ #include "sysemu/kvm.h" #include "sysemu/reset.h" #include "sysemu/hvf.h" -#include "hw/core/accel-cpu.h" #include "sysemu/xen.h" #include "sysemu/whpx.h" #include "kvm/kvm_i386.h" @@ -6800,8 +6799,6 @@ static void x86_cpu_initfn(Object *obj) { X86CPU *cpu = X86_CPU(obj); X86CPUClass *xcc = X86_CPU_GET_CLASS(obj); - CPUClass *cc = CPU_CLASS(xcc); - CPUX86State *env = &cpu->env; env->nr_dies = 1; @@ -6850,10 +6847,8 @@ static void x86_cpu_initfn(Object *obj) x86_cpu_load_model(cpu, xcc->model); } - /* if required, do the accelerator-specific cpu initialization */ - if (cc->accel_cpu) { - cc->accel_cpu->cpu_instance_init(CPU(obj)); - } + /* if required, do accelerator-specific cpu initializations */ + accel_cpu_instance_init(CPU(obj)); } static int64_t x86_cpu_get_arch_id(CPUState *cs) From ce21726525da53053432b19e27e9fd2a49086d78 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:43 +0100 Subject: [PATCH 0396/3028] target/i386: fix host_cpu_adjust_phys_bits error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit move the check for phys_bits outside of host_cpu_adjust_phys_bits, because otherwise it is impossible to return an error condition explicitly. Signed-off-by: Claudio Fontana Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-8-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/host-cpu.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c index 9cfe56ce41..d07d41c34c 100644 --- a/target/i386/host-cpu.c +++ b/target/i386/host-cpu.c @@ -50,7 +50,7 @@ static void host_cpu_enable_cpu_pm(X86CPU *cpu) env->features[FEAT_1_ECX] |= CPUID_EXT_MONITOR; } -static uint32_t host_cpu_adjust_phys_bits(X86CPU *cpu, Error **errp) +static uint32_t host_cpu_adjust_phys_bits(X86CPU *cpu) { uint32_t host_phys_bits = host_cpu_phys_bits(); uint32_t phys_bits = cpu->phys_bits; @@ -77,14 +77,6 @@ static uint32_t host_cpu_adjust_phys_bits(X86CPU *cpu, Error **errp) } } - if (phys_bits && - (phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || - phys_bits < 32)) { - error_setg(errp, "phys-bits should be between 32 and %u " - " (but is %u)", - TARGET_PHYS_ADDR_SPACE_BITS, phys_bits); - } - return phys_bits; } @@ -97,7 +89,17 @@ void host_cpu_realizefn(CPUState *cs, Error **errp) host_cpu_enable_cpu_pm(cpu); } if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { - cpu->phys_bits = host_cpu_adjust_phys_bits(cpu, errp); + uint32_t phys_bits = host_cpu_adjust_phys_bits(cpu); + + if (phys_bits && + (phys_bits > TARGET_PHYS_ADDR_SPACE_BITS || + phys_bits < 32)) { + error_setg(errp, "phys-bits should be between 32 and %u " + " (but is %u)", + TARGET_PHYS_ADDR_SPACE_BITS, phys_bits); + return; + } + cpu->phys_bits = phys_bits; } } From 9ea057dc641b150ecbfd45acfe18fe043641a551 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:44 +0100 Subject: [PATCH 0397/3028] accel-cpu: make cpu_realizefn return a bool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit overall, all devices' realize functions take an Error **errp, but return void. hw/core/qdev.c code, which realizes devices, therefore does: local_err = NULL; dc->realize(dev, &local_err); if (local_err != NULL) { goto fail; } However, we can improve at least accel_cpu to return a meaningful bool value. Signed-off-by: Claudio Fontana Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-9-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- accel/accel-common.c | 6 +++--- cpu.c | 5 +++-- include/hw/core/accel-cpu.h | 2 +- include/qemu/accel.h | 2 +- target/i386/host-cpu.c | 5 +++-- target/i386/host-cpu.h | 2 +- target/i386/kvm/kvm-cpu.c | 4 ++-- target/i386/tcg/tcg-cpu.c | 6 ++++-- 8 files changed, 18 insertions(+), 14 deletions(-) diff --git a/accel/accel-common.c b/accel/accel-common.c index 0f6fb4fb66..d77c09d7b5 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -98,14 +98,14 @@ void accel_cpu_instance_init(CPUState *cpu) } } -void accel_cpu_realizefn(CPUState *cpu, Error **errp) +bool accel_cpu_realizefn(CPUState *cpu, Error **errp) { CPUClass *cc = CPU_GET_CLASS(cpu); if (cc->accel_cpu && cc->accel_cpu->cpu_realizefn) { - /* NB: errp parameter is unused currently */ - cc->accel_cpu->cpu_realizefn(cpu, errp); + return cc->accel_cpu->cpu_realizefn(cpu, errp); } + return true; } static const TypeInfo accel_cpu_type = { diff --git a/cpu.c b/cpu.c index 25e6fbfa2c..34a0484bf4 100644 --- a/cpu.c +++ b/cpu.c @@ -130,8 +130,9 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp) CPUClass *cc = CPU_GET_CLASS(cpu); cpu_list_add(cpu); - accel_cpu_realizefn(cpu, errp); - + if (!accel_cpu_realizefn(cpu, errp)) { + return; + } #ifdef CONFIG_TCG /* NB: errp parameter is unused currently */ if (tcg_enabled()) { diff --git a/include/hw/core/accel-cpu.h b/include/hw/core/accel-cpu.h index 24a6697412..5dbfd79955 100644 --- a/include/hw/core/accel-cpu.h +++ b/include/hw/core/accel-cpu.h @@ -32,7 +32,7 @@ typedef struct AccelCPUClass { void (*cpu_class_init)(CPUClass *cc); void (*cpu_instance_init)(CPUState *cpu); - void (*cpu_realizefn)(CPUState *cpu, Error **errp); + bool (*cpu_realizefn)(CPUState *cpu, Error **errp); } AccelCPUClass; #endif /* ACCEL_CPU_H */ diff --git a/include/qemu/accel.h b/include/qemu/accel.h index da0c8ab523..4f4c283f6f 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -89,6 +89,6 @@ void accel_cpu_instance_init(CPUState *cpu); * @cpu: The CPU that needs to call accel-specific cpu realization. * @errp: currently unused. */ -void accel_cpu_realizefn(CPUState *cpu, Error **errp); +bool accel_cpu_realizefn(CPUState *cpu, Error **errp); #endif /* QEMU_ACCEL_H */ diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c index d07d41c34c..4ea9e354ea 100644 --- a/target/i386/host-cpu.c +++ b/target/i386/host-cpu.c @@ -80,7 +80,7 @@ static uint32_t host_cpu_adjust_phys_bits(X86CPU *cpu) return phys_bits; } -void host_cpu_realizefn(CPUState *cs, Error **errp) +bool host_cpu_realizefn(CPUState *cs, Error **errp) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; @@ -97,10 +97,11 @@ void host_cpu_realizefn(CPUState *cs, Error **errp) error_setg(errp, "phys-bits should be between 32 and %u " " (but is %u)", TARGET_PHYS_ADDR_SPACE_BITS, phys_bits); - return; + return false; } cpu->phys_bits = phys_bits; } + return true; } #define CPUID_MODEL_ID_SZ 48 diff --git a/target/i386/host-cpu.h b/target/i386/host-cpu.h index b47bc0943f..6a9bc918ba 100644 --- a/target/i386/host-cpu.h +++ b/target/i386/host-cpu.h @@ -12,7 +12,7 @@ void host_cpu_instance_init(X86CPU *cpu); void host_cpu_max_instance_init(X86CPU *cpu); -void host_cpu_realizefn(CPUState *cs, Error **errp); +bool host_cpu_realizefn(CPUState *cs, Error **errp); void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping); diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index c23bbe6c50..c660ad4293 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -18,7 +18,7 @@ #include "kvm_i386.h" #include "hw/core/accel-cpu.h" -static void kvm_cpu_realizefn(CPUState *cs, Error **errp) +static bool kvm_cpu_realizefn(CPUState *cs, Error **errp) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; @@ -41,7 +41,7 @@ static void kvm_cpu_realizefn(CPUState *cs, Error **errp) MSR_IA32_UCODE_REV); } } - host_cpu_realizefn(cs, errp); + return host_cpu_realizefn(cs, errp); } /* diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 1d3d6d1c6a..23e1f5f0c3 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -96,7 +96,7 @@ static void x86_cpu_machine_done(Notifier *n, void *unused) } } -static void tcg_cpu_realizefn(CPUState *cs, Error **errp) +static bool tcg_cpu_realizefn(CPUState *cs, Error **errp) { X86CPU *cpu = X86_CPU(cs); @@ -132,12 +132,14 @@ static void tcg_cpu_realizefn(CPUState *cs, Error **errp) /* ... SMRAM with higher priority, linked from /machine/smram. */ cpu->machine_done.notify = x86_cpu_machine_done; qemu_add_machine_init_done_notifier(&cpu->machine_done); + return true; } #else /* CONFIG_USER_ONLY */ -static void tcg_cpu_realizefn(CPUState *cs, Error **errp) +static bool tcg_cpu_realizefn(CPUState *cs, Error **errp) { + return true; } #endif /* !CONFIG_USER_ONLY */ From 222f3e6f190c01c764be51ec7e9beb695cd11e1c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 May 2021 11:20:23 -0400 Subject: [PATCH 0398/3028] i386: split off sysemu-only functionality in tcg-cpu Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-11-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/meson.build | 2 + target/i386/tcg/meson.build | 3 ++ target/i386/tcg/sysemu/meson.build | 3 ++ target/i386/tcg/sysemu/tcg-cpu.c | 83 ++++++++++++++++++++++++++++++ target/i386/tcg/tcg-cpu.c | 75 ++------------------------- target/i386/tcg/tcg-cpu.h | 24 +++++++++ target/i386/tcg/user/meson.build | 2 + 7 files changed, 121 insertions(+), 71 deletions(-) create mode 100644 target/i386/tcg/sysemu/meson.build create mode 100644 target/i386/tcg/sysemu/tcg-cpu.c create mode 100644 target/i386/tcg/tcg-cpu.h create mode 100644 target/i386/tcg/user/meson.build diff --git a/target/i386/meson.build b/target/i386/meson.build index 6f3b0255c0..94571317f6 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build @@ -19,6 +19,7 @@ i386_softmmu_ss.add(files( 'machine.c', 'monitor.c', )) +i386_user_ss = ss.source_set() subdir('kvm') subdir('hax') @@ -29,3 +30,4 @@ subdir('tcg') target_arch += {'i386': i386_ss} target_softmmu_arch += {'i386': i386_softmmu_ss} +target_user_arch += {'i386': i386_user_ss} diff --git a/target/i386/tcg/meson.build b/target/i386/tcg/meson.build index 6a1a73cdbf..320bcd1e46 100644 --- a/target/i386/tcg/meson.build +++ b/target/i386/tcg/meson.build @@ -12,3 +12,6 @@ i386_ss.add(when: 'CONFIG_TCG', if_true: files( 'svm_helper.c', 'tcg-cpu.c', 'translate.c'), if_false: files('tcg-stub.c')) + +subdir('sysemu') +subdir('user') diff --git a/target/i386/tcg/sysemu/meson.build b/target/i386/tcg/sysemu/meson.build new file mode 100644 index 0000000000..4ab30cc32e --- /dev/null +++ b/target/i386/tcg/sysemu/meson.build @@ -0,0 +1,3 @@ +i386_softmmu_ss.add(when: ['CONFIG_TCG', 'CONFIG_SOFTMMU'], if_true: files( + 'tcg-cpu.c', +)) diff --git a/target/i386/tcg/sysemu/tcg-cpu.c b/target/i386/tcg/sysemu/tcg-cpu.c new file mode 100644 index 0000000000..c223c0fe9b --- /dev/null +++ b/target/i386/tcg/sysemu/tcg-cpu.c @@ -0,0 +1,83 @@ +/* + * i386 TCG cpu class initialization functions specific to sysemu + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "tcg/helper-tcg.h" + +#include "sysemu/sysemu.h" +#include "qemu/units.h" +#include "exec/address-spaces.h" + +#include "tcg/tcg-cpu.h" + +static void tcg_cpu_machine_done(Notifier *n, void *unused) +{ + X86CPU *cpu = container_of(n, X86CPU, machine_done); + MemoryRegion *smram = + (MemoryRegion *) object_resolve_path("/machine/smram", NULL); + + if (smram) { + cpu->smram = g_new(MemoryRegion, 1); + memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram", + smram, 0, 4 * GiB); + memory_region_set_enabled(cpu->smram, true); + memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, + cpu->smram, 1); + } +} + +bool tcg_cpu_realizefn(CPUState *cs, Error **errp) +{ + X86CPU *cpu = X86_CPU(cs); + + /* + * The realize order is important, since x86_cpu_realize() checks if + * nothing else has been set by the user (or by accelerators) in + * cpu->ucode_rev and cpu->phys_bits, and the memory regions + * initialized here are needed for the vcpu initialization. + * + * realize order: + * tcg_cpu -> host_cpu -> x86_cpu + */ + cpu->cpu_as_mem = g_new(MemoryRegion, 1); + cpu->cpu_as_root = g_new(MemoryRegion, 1); + + /* Outer container... */ + memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull); + memory_region_set_enabled(cpu->cpu_as_root, true); + + /* + * ... with two regions inside: normal system memory with low + * priority, and... + */ + memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory", + get_system_memory(), 0, ~0ull); + memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); + memory_region_set_enabled(cpu->cpu_as_mem, true); + + cs->num_ases = 2; + cpu_address_space_init(cs, 0, "cpu-memory", cs->memory); + cpu_address_space_init(cs, 1, "cpu-smm", cpu->cpu_as_root); + + /* ... SMRAM with higher priority, linked from /machine/smram. */ + cpu->machine_done.notify = tcg_cpu_machine_done; + qemu_add_machine_init_done_notifier(&cpu->machine_done); + return true; +} diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 23e1f5f0c3..e311f52855 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -23,11 +23,7 @@ #include "qemu/accel.h" #include "hw/core/accel-cpu.h" -#ifndef CONFIG_USER_ONLY -#include "sysemu/sysemu.h" -#include "qemu/units.h" -#include "exec/address-spaces.h" -#endif +#include "tcg-cpu.h" /* Frob eflags into and out of the CPU temporary format. */ @@ -78,72 +74,6 @@ static void tcg_cpu_class_init(CPUClass *cc) cc->tcg_ops = &x86_tcg_ops; } -#ifndef CONFIG_USER_ONLY - -static void x86_cpu_machine_done(Notifier *n, void *unused) -{ - X86CPU *cpu = container_of(n, X86CPU, machine_done); - MemoryRegion *smram = - (MemoryRegion *) object_resolve_path("/machine/smram", NULL); - - if (smram) { - cpu->smram = g_new(MemoryRegion, 1); - memory_region_init_alias(cpu->smram, OBJECT(cpu), "smram", - smram, 0, 4 * GiB); - memory_region_set_enabled(cpu->smram, true); - memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, - cpu->smram, 1); - } -} - -static bool tcg_cpu_realizefn(CPUState *cs, Error **errp) -{ - X86CPU *cpu = X86_CPU(cs); - - /* - * The realize order is important, since x86_cpu_realize() checks if - * nothing else has been set by the user (or by accelerators) in - * cpu->ucode_rev and cpu->phys_bits, and the memory regions - * initialized here are needed for the vcpu initialization. - * - * realize order: - * tcg_cpu -> host_cpu -> x86_cpu - */ - cpu->cpu_as_mem = g_new(MemoryRegion, 1); - cpu->cpu_as_root = g_new(MemoryRegion, 1); - - /* Outer container... */ - memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull); - memory_region_set_enabled(cpu->cpu_as_root, true); - - /* - * ... with two regions inside: normal system memory with low - * priority, and... - */ - memory_region_init_alias(cpu->cpu_as_mem, OBJECT(cpu), "memory", - get_system_memory(), 0, ~0ull); - memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); - memory_region_set_enabled(cpu->cpu_as_mem, true); - - cs->num_ases = 2; - cpu_address_space_init(cs, 0, "cpu-memory", cs->memory); - cpu_address_space_init(cs, 1, "cpu-smm", cpu->cpu_as_root); - - /* ... SMRAM with higher priority, linked from /machine/smram. */ - cpu->machine_done.notify = x86_cpu_machine_done; - qemu_add_machine_init_done_notifier(&cpu->machine_done); - return true; -} - -#else /* CONFIG_USER_ONLY */ - -static bool tcg_cpu_realizefn(CPUState *cs, Error **errp) -{ - return true; -} - -#endif /* !CONFIG_USER_ONLY */ - /* * TCG-specific defaults that override all CPU models when using TCG */ @@ -163,7 +93,10 @@ static void tcg_cpu_accel_class_init(ObjectClass *oc, void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); +#ifndef CONFIG_USER_ONLY acc->cpu_realizefn = tcg_cpu_realizefn; +#endif /* CONFIG_USER_ONLY */ + acc->cpu_class_init = tcg_cpu_class_init; acc->cpu_instance_init = tcg_cpu_instance_init; } diff --git a/target/i386/tcg/tcg-cpu.h b/target/i386/tcg/tcg-cpu.h new file mode 100644 index 0000000000..36bd300af0 --- /dev/null +++ b/target/i386/tcg/tcg-cpu.h @@ -0,0 +1,24 @@ +/* + * i386 TCG cpu class initialization functions + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef TCG_CPU_H +#define TCG_CPU_H + +bool tcg_cpu_realizefn(CPUState *cs, Error **errp); + +#endif /* TCG_CPU_H */ diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build new file mode 100644 index 0000000000..7aecc53155 --- /dev/null +++ b/target/i386/tcg/user/meson.build @@ -0,0 +1,2 @@ +i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], if_true: files( +)) From a93b55ec223f07c7ca74a748e607db48cab945f6 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:47 +0100 Subject: [PATCH 0399/3028] i386: split smm helper (sysemu) smm is only really useful for sysemu, split in two modules around the CONFIG_USER_ONLY, in order to remove the ifdef and use the build system instead. add cpu_abort() when detecting attempts to enter SMM mode via SMI interrupt in user-mode, and assert that the cpu is not in SMM mode while translating RSM instructions. Signed-off-by: Claudio Fontana Cc: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-12-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/helper.h | 4 ++++ target/i386/tcg/meson.build | 1 - target/i386/tcg/seg_helper.c | 4 ++++ target/i386/tcg/sysemu/meson.build | 1 + target/i386/tcg/{ => sysemu}/smm_helper.c | 19 ++----------------- target/i386/tcg/translate.c | 5 +++++ 6 files changed, 16 insertions(+), 18 deletions(-) rename target/i386/tcg/{ => sysemu}/smm_helper.c (98%) diff --git a/target/i386/helper.h b/target/i386/helper.h index c2ae2f7e61..8ffda4cdc6 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -70,7 +70,11 @@ DEF_HELPER_1(clac, void, env) DEF_HELPER_1(stac, void, env) DEF_HELPER_3(boundw, void, env, tl, int) DEF_HELPER_3(boundl, void, env, tl, int) + +#ifndef CONFIG_USER_ONLY DEF_HELPER_1(rsm, void, env) +#endif /* !CONFIG_USER_ONLY */ + DEF_HELPER_2(into, void, env, int) DEF_HELPER_2(cmpxchg8b_unlocked, void, env, tl) DEF_HELPER_2(cmpxchg8b, void, env, tl) diff --git a/target/i386/tcg/meson.build b/target/i386/tcg/meson.build index 320bcd1e46..449d9719ef 100644 --- a/target/i386/tcg/meson.build +++ b/target/i386/tcg/meson.build @@ -8,7 +8,6 @@ i386_ss.add(when: 'CONFIG_TCG', if_true: files( 'misc_helper.c', 'mpx_helper.c', 'seg_helper.c', - 'smm_helper.c', 'svm_helper.c', 'tcg-cpu.c', 'translate.c'), if_false: files('tcg-stub.c')) diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index d180a381d1..b6230ebdf4 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -1351,7 +1351,11 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) case CPU_INTERRUPT_SMI: cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0, 0); cs->interrupt_request &= ~CPU_INTERRUPT_SMI; +#ifdef CONFIG_USER_ONLY + cpu_abort(CPU(cpu), "SMI interrupt: cannot enter SMM in user-mode"); +#else do_smm_enter(cpu); +#endif /* CONFIG_USER_ONLY */ break; case CPU_INTERRUPT_NMI: cpu_svm_check_intercept_param(env, SVM_EXIT_NMI, 0, 0); diff --git a/target/i386/tcg/sysemu/meson.build b/target/i386/tcg/sysemu/meson.build index 4ab30cc32e..35ba16dc3d 100644 --- a/target/i386/tcg/sysemu/meson.build +++ b/target/i386/tcg/sysemu/meson.build @@ -1,3 +1,4 @@ i386_softmmu_ss.add(when: ['CONFIG_TCG', 'CONFIG_SOFTMMU'], if_true: files( 'tcg-cpu.c', + 'smm_helper.c', )) diff --git a/target/i386/tcg/smm_helper.c b/target/i386/tcg/sysemu/smm_helper.c similarity index 98% rename from target/i386/tcg/smm_helper.c rename to target/i386/tcg/sysemu/smm_helper.c index 62d027abd3..a45b5651c3 100644 --- a/target/i386/tcg/smm_helper.c +++ b/target/i386/tcg/sysemu/smm_helper.c @@ -1,5 +1,5 @@ /* - * x86 SMM helpers + * x86 SMM helpers (sysemu-only) * * Copyright (c) 2003 Fabrice Bellard * @@ -18,27 +18,14 @@ */ #include "qemu/osdep.h" -#include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/log.h" -#include "helper-tcg.h" +#include "tcg/helper-tcg.h" /* SMM support */ -#if defined(CONFIG_USER_ONLY) - -void do_smm_enter(X86CPU *cpu) -{ -} - -void helper_rsm(CPUX86State *env) -{ -} - -#else - #ifdef TARGET_X86_64 #define SMM_REVISION_ID 0x00020064 #else @@ -330,5 +317,3 @@ void helper_rsm(CPUX86State *env) qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n"); log_cpu_state_mask(CPU_LOG_INT, CPU(cpu), CPU_DUMP_CCOP); } - -#endif /* !CONFIG_USER_ONLY */ diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 880bc45561..b02bdf5ea2 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -8325,9 +8325,14 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM); if (!(s->flags & HF_SMM_MASK)) goto illegal_op; +#ifdef CONFIG_USER_ONLY + /* we should not be in SMM mode */ + g_assert_not_reached(); +#else gen_update_cc_op(s); gen_jmp_im(s, s->pc - s->cs_base); gen_helper_rsm(cpu_env); +#endif /* CONFIG_USER_ONLY */ gen_eob(s); break; case 0x1b8: /* SSE4.2 popcnt */ From e7f2670f2a7cc259cc98d3a4a7ad4dc36389d60b Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:48 +0100 Subject: [PATCH 0400/3028] i386: split tcg excp_helper into sysemu and user parts Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson [claudio]: Rebased on commit b8184135 ("target/i386: allow modifying TCG phys-addr-bits") Signed-off-by: Claudio Fontana Message-Id: <20210322132800.7470-13-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/tcg/excp_helper.c | 573 -------------------------- target/i386/tcg/sysemu/excp_helper.c | 582 +++++++++++++++++++++++++++ target/i386/tcg/sysemu/meson.build | 1 + target/i386/tcg/user/excp_helper.c | 39 ++ target/i386/tcg/user/meson.build | 1 + 5 files changed, 623 insertions(+), 573 deletions(-) create mode 100644 target/i386/tcg/sysemu/excp_helper.c create mode 100644 target/i386/tcg/user/excp_helper.c diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c index 1e71e44510..0183f3932e 100644 --- a/target/i386/tcg/excp_helper.c +++ b/target/i386/tcg/excp_helper.c @@ -137,576 +137,3 @@ void raise_exception_ra(CPUX86State *env, int exception_index, uintptr_t retaddr { raise_interrupt2(env, exception_index, 0, 0, 0, retaddr); } - -#if !defined(CONFIG_USER_ONLY) -static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, - int *prot) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); - uint64_t ptep, pte; - uint64_t exit_info_1 = 0; - target_ulong pde_addr, pte_addr; - uint32_t page_offset; - int page_size; - - if (likely(!(env->hflags2 & HF2_NPT_MASK))) { - return gphys; - } - - if (!(env->nested_pg_mode & SVM_NPT_NXE)) { - rsvd_mask |= PG_NX_MASK; - } - - if (env->nested_pg_mode & SVM_NPT_PAE) { - uint64_t pde, pdpe; - target_ulong pdpe_addr; - -#ifdef TARGET_X86_64 - if (env->nested_pg_mode & SVM_NPT_LMA) { - uint64_t pml5e; - uint64_t pml4e_addr, pml4e; - - pml5e = env->nested_cr3; - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - - pml4e_addr = (pml5e & PG_ADDRESS_MASK) + - (((gphys >> 39) & 0x1ff) << 3); - pml4e = x86_ldq_phys(cs, pml4e_addr); - if (!(pml4e & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pml4e & (rsvd_mask | PG_PSE_MASK)) { - goto do_fault_rsvd; - } - if (!(pml4e & PG_ACCESSED_MASK)) { - pml4e |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); - } - ptep &= pml4e ^ PG_NX_MASK; - pdpe_addr = (pml4e & PG_ADDRESS_MASK) + - (((gphys >> 30) & 0x1ff) << 3); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pdpe & rsvd_mask) { - goto do_fault_rsvd; - } - ptep &= pdpe ^ PG_NX_MASK; - if (!(pdpe & PG_ACCESSED_MASK)) { - pdpe |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); - } - if (pdpe & PG_PSE_MASK) { - /* 1 GB page */ - page_size = 1024 * 1024 * 1024; - pte_addr = pdpe_addr; - pte = pdpe; - goto do_check_protect; - } - } else -#endif - { - pdpe_addr = (env->nested_cr3 & ~0x1f) + ((gphys >> 27) & 0x18); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; - } - rsvd_mask |= PG_HI_USER_MASK; - if (pdpe & (rsvd_mask | PG_NX_MASK)) { - goto do_fault_rsvd; - } - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - } - - pde_addr = (pdpe & PG_ADDRESS_MASK) + (((gphys >> 21) & 0x1ff) << 3); - pde = x86_ldq_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pde & rsvd_mask) { - goto do_fault_rsvd; - } - ptep &= pde ^ PG_NX_MASK; - if (pde & PG_PSE_MASK) { - /* 2 MB page */ - page_size = 2048 * 1024; - pte_addr = pde_addr; - pte = pde; - goto do_check_protect; - } - /* 4 KB page */ - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); - } - pte_addr = (pde & PG_ADDRESS_MASK) + (((gphys >> 12) & 0x1ff) << 3); - pte = x86_ldq_phys(cs, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pte & rsvd_mask) { - goto do_fault_rsvd; - } - /* combine pde and pte nx, user and rw protections */ - ptep &= pte ^ PG_NX_MASK; - page_size = 4096; - } else { - uint32_t pde; - - /* page directory entry */ - pde_addr = (env->nested_cr3 & ~0xfff) + ((gphys >> 20) & 0xffc); - pde = x86_ldl_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - goto do_fault; - } - ptep = pde | PG_NX_MASK; - - /* if host cr4 PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & SVM_NPT_PSE)) { - page_size = 4096 * 1024; - pte_addr = pde_addr; - - /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. - * Leave bits 20-13 in place for setting accessed/dirty bits below. - */ - pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); - rsvd_mask = 0x200000; - goto do_check_protect_pse36; - } - - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); - } - - /* page directory entry */ - pte_addr = (pde & ~0xfff) + ((gphys >> 10) & 0xffc); - pte = x86_ldl_phys(cs, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - goto do_fault; - } - /* combine pde and pte user and rw protections */ - ptep &= pte | PG_NX_MASK; - page_size = 4096; - rsvd_mask = 0; - } - - do_check_protect: - rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; - do_check_protect_pse36: - if (pte & rsvd_mask) { - goto do_fault_rsvd; - } - ptep ^= PG_NX_MASK; - - if (!(ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - if (ptep & PG_NX_MASK) { - if (access_type == MMU_INST_FETCH) { - goto do_fault_protect; - } - *prot &= ~PAGE_EXEC; - } - if (!(ptep & PG_RW_MASK)) { - if (access_type == MMU_DATA_STORE) { - goto do_fault_protect; - } - *prot &= ~PAGE_WRITE; - } - - pte &= PG_ADDRESS_MASK & ~(page_size - 1); - page_offset = gphys & (page_size - 1); - return pte + page_offset; - - do_fault_rsvd: - exit_info_1 |= SVM_NPTEXIT_RSVD; - do_fault_protect: - exit_info_1 |= SVM_NPTEXIT_P; - do_fault: - x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), - gphys); - exit_info_1 |= SVM_NPTEXIT_US; - if (access_type == MMU_DATA_STORE) { - exit_info_1 |= SVM_NPTEXIT_RW; - } else if (access_type == MMU_INST_FETCH) { - exit_info_1 |= SVM_NPTEXIT_ID; - } - if (prot) { - exit_info_1 |= SVM_NPTEXIT_GPA; - } else { /* page table access */ - exit_info_1 |= SVM_NPTEXIT_GPT; - } - cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr); -} - -/* return value: - * -1 = cannot handle fault - * 0 = nothing more to do - * 1 = generate PF fault - */ -static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, - int is_write1, int mmu_idx) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - uint64_t ptep, pte; - int32_t a20_mask; - target_ulong pde_addr, pte_addr; - int error_code = 0; - int is_dirty, prot, page_size, is_write, is_user; - hwaddr paddr; - uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); - uint32_t page_offset; - target_ulong vaddr; - uint32_t pkr; - - is_user = mmu_idx == MMU_USER_IDX; -#if defined(DEBUG_MMU) - printf("MMU fault: addr=%" VADDR_PRIx " w=%d u=%d eip=" TARGET_FMT_lx "\n", - addr, is_write1, is_user, env->eip); -#endif - is_write = is_write1 & 1; - - a20_mask = x86_get_a20_mask(env); - if (!(env->cr[0] & CR0_PG_MASK)) { - pte = addr; -#ifdef TARGET_X86_64 - if (!(env->hflags & HF_LMA_MASK)) { - /* Without long mode we can only address 32bits in real mode */ - pte = (uint32_t)pte; - } -#endif - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - page_size = 4096; - goto do_mapping; - } - - if (!(env->efer & MSR_EFER_NXE)) { - rsvd_mask |= PG_NX_MASK; - } - - if (env->cr[4] & CR4_PAE_MASK) { - uint64_t pde, pdpe; - target_ulong pdpe_addr; - -#ifdef TARGET_X86_64 - if (env->hflags & HF_LMA_MASK) { - bool la57 = env->cr[4] & CR4_LA57_MASK; - uint64_t pml5e_addr, pml5e; - uint64_t pml4e_addr, pml4e; - int32_t sext; - - /* test virtual address sign extension */ - sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47; - if (sext != 0 && sext != -1) { - env->error_code = 0; - cs->exception_index = EXCP0D_GPF; - return 1; - } - - if (la57) { - pml5e_addr = ((env->cr[3] & ~0xfff) + - (((addr >> 48) & 0x1ff) << 3)) & a20_mask; - pml5e_addr = get_hphys(cs, pml5e_addr, MMU_DATA_STORE, NULL); - pml5e = x86_ldq_phys(cs, pml5e_addr); - if (!(pml5e & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pml5e & (rsvd_mask | PG_PSE_MASK)) { - goto do_fault_rsvd; - } - if (!(pml5e & PG_ACCESSED_MASK)) { - pml5e |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pml5e_addr, pml5e); - } - ptep = pml5e ^ PG_NX_MASK; - } else { - pml5e = env->cr[3]; - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - } - - pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + - (((addr >> 39) & 0x1ff) << 3)) & a20_mask; - pml4e_addr = get_hphys(cs, pml4e_addr, MMU_DATA_STORE, false); - pml4e = x86_ldq_phys(cs, pml4e_addr); - if (!(pml4e & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pml4e & (rsvd_mask | PG_PSE_MASK)) { - goto do_fault_rsvd; - } - if (!(pml4e & PG_ACCESSED_MASK)) { - pml4e |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); - } - ptep &= pml4e ^ PG_NX_MASK; - pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & - a20_mask; - pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, NULL); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pdpe & rsvd_mask) { - goto do_fault_rsvd; - } - ptep &= pdpe ^ PG_NX_MASK; - if (!(pdpe & PG_ACCESSED_MASK)) { - pdpe |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); - } - if (pdpe & PG_PSE_MASK) { - /* 1 GB page */ - page_size = 1024 * 1024 * 1024; - pte_addr = pdpe_addr; - pte = pdpe; - goto do_check_protect; - } - } else -#endif - { - /* XXX: load them when cr3 is loaded ? */ - pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & - a20_mask; - pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, false); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; - } - rsvd_mask |= PG_HI_USER_MASK; - if (pdpe & (rsvd_mask | PG_NX_MASK)) { - goto do_fault_rsvd; - } - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - } - - pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & - a20_mask; - pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); - pde = x86_ldq_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pde & rsvd_mask) { - goto do_fault_rsvd; - } - ptep &= pde ^ PG_NX_MASK; - if (pde & PG_PSE_MASK) { - /* 2 MB page */ - page_size = 2048 * 1024; - pte_addr = pde_addr; - pte = pde; - goto do_check_protect; - } - /* 4 KB page */ - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); - } - pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & - a20_mask; - pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL); - pte = x86_ldq_phys(cs, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pte & rsvd_mask) { - goto do_fault_rsvd; - } - /* combine pde and pte nx, user and rw protections */ - ptep &= pte ^ PG_NX_MASK; - page_size = 4096; - } else { - uint32_t pde; - - /* page directory entry */ - pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & - a20_mask; - pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); - pde = x86_ldl_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - goto do_fault; - } - ptep = pde | PG_NX_MASK; - - /* if PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - page_size = 4096 * 1024; - pte_addr = pde_addr; - - /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. - * Leave bits 20-13 in place for setting accessed/dirty bits below. - */ - pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); - rsvd_mask = 0x200000; - goto do_check_protect_pse36; - } - - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); - } - - /* page directory entry */ - pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & - a20_mask; - pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL); - pte = x86_ldl_phys(cs, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - goto do_fault; - } - /* combine pde and pte user and rw protections */ - ptep &= pte | PG_NX_MASK; - page_size = 4096; - rsvd_mask = 0; - } - -do_check_protect: - rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; -do_check_protect_pse36: - if (pte & rsvd_mask) { - goto do_fault_rsvd; - } - ptep ^= PG_NX_MASK; - - /* can the page can be put in the TLB? prot will tell us */ - if (is_user && !(ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - - prot = 0; - if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { - prot |= PAGE_READ; - if ((ptep & PG_RW_MASK) || (!is_user && !(env->cr[0] & CR0_WP_MASK))) { - prot |= PAGE_WRITE; - } - } - if (!(ptep & PG_NX_MASK) && - (mmu_idx == MMU_USER_IDX || - !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) { - prot |= PAGE_EXEC; - } - - if (!(env->hflags & HF_LMA_MASK)) { - pkr = 0; - } else if (ptep & PG_USER_MASK) { - pkr = env->cr[4] & CR4_PKE_MASK ? env->pkru : 0; - } else { - pkr = env->cr[4] & CR4_PKS_MASK ? env->pkrs : 0; - } - if (pkr) { - uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; - uint32_t pkr_ad = (pkr >> pk * 2) & 1; - uint32_t pkr_wd = (pkr >> pk * 2) & 2; - uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - - if (pkr_ad) { - pkr_prot &= ~(PAGE_READ | PAGE_WRITE); - } else if (pkr_wd && (is_user || env->cr[0] & CR0_WP_MASK)) { - pkr_prot &= ~PAGE_WRITE; - } - - prot &= pkr_prot; - if ((pkr_prot & (1 << is_write1)) == 0) { - assert(is_write1 != 2); - error_code |= PG_ERROR_PK_MASK; - goto do_fault_protect; - } - } - - if ((prot & (1 << is_write1)) == 0) { - goto do_fault_protect; - } - - /* yes, it can! */ - is_dirty = is_write && !(pte & PG_DIRTY_MASK); - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { - pte |= PG_ACCESSED_MASK; - if (is_dirty) { - pte |= PG_DIRTY_MASK; - } - x86_stl_phys_notdirty(cs, pte_addr, pte); - } - - if (!(pte & PG_DIRTY_MASK)) { - /* only set write access if already dirty... otherwise wait - for dirty access */ - assert(!is_write); - prot &= ~PAGE_WRITE; - } - - do_mapping: - pte = pte & a20_mask; - - /* align to page_size */ - pte &= PG_ADDRESS_MASK & ~(page_size - 1); - page_offset = addr & (page_size - 1); - paddr = get_hphys(cs, pte + page_offset, is_write1, &prot); - - /* Even if 4MB pages, we map only one 4KB page in the cache to - avoid filling it too fast */ - vaddr = addr & TARGET_PAGE_MASK; - paddr &= TARGET_PAGE_MASK; - - assert(prot & (1 << is_write1)); - tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env), - prot, mmu_idx, page_size); - return 0; - do_fault_rsvd: - error_code |= PG_ERROR_RSVD_MASK; - do_fault_protect: - error_code |= PG_ERROR_P_MASK; - do_fault: - error_code |= (is_write << PG_ERROR_W_BIT); - if (is_user) - error_code |= PG_ERROR_U_MASK; - if (is_write1 == 2 && - (((env->efer & MSR_EFER_NXE) && - (env->cr[4] & CR4_PAE_MASK)) || - (env->cr[4] & CR4_SMEP_MASK))) - error_code |= PG_ERROR_I_D_MASK; - if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { - /* cr2 is not modified in case of exceptions */ - x86_stq_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), - addr); - } else { - env->cr[2] = addr; - } - env->error_code = error_code; - cs->exception_index = EXCP0E_PAGE; - return 1; -} -#endif - -bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - -#ifdef CONFIG_USER_ONLY - /* user mode only emulation */ - env->cr[2] = addr; - env->error_code = (access_type == MMU_DATA_STORE) << PG_ERROR_W_BIT; - env->error_code |= PG_ERROR_U_MASK; - cs->exception_index = EXCP0E_PAGE; - env->exception_is_int = 0; - env->exception_next_eip = -1; - cpu_loop_exit_restore(cs, retaddr); -#else - env->retaddr = retaddr; - if (handle_mmu_fault(cs, addr, size, access_type, mmu_idx)) { - /* FIXME: On error in get_hphys we have already jumped out. */ - g_assert(!probe); - raise_exception_err_ra(env, cs->exception_index, - env->error_code, retaddr); - } - return true; -#endif -} diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c new file mode 100644 index 0000000000..1fcac51a32 --- /dev/null +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -0,0 +1,582 @@ +/* + * x86 exception helpers - sysemu code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "tcg/helper-tcg.h" + +static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, + int *prot) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); + uint64_t ptep, pte; + uint64_t exit_info_1 = 0; + target_ulong pde_addr, pte_addr; + uint32_t page_offset; + int page_size; + + if (likely(!(env->hflags2 & HF2_NPT_MASK))) { + return gphys; + } + + if (!(env->nested_pg_mode & SVM_NPT_NXE)) { + rsvd_mask |= PG_NX_MASK; + } + + if (env->nested_pg_mode & SVM_NPT_PAE) { + uint64_t pde, pdpe; + target_ulong pdpe_addr; + +#ifdef TARGET_X86_64 + if (env->nested_pg_mode & SVM_NPT_LMA) { + uint64_t pml5e; + uint64_t pml4e_addr, pml4e; + + pml5e = env->nested_cr3; + ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; + + pml4e_addr = (pml5e & PG_ADDRESS_MASK) + + (((gphys >> 39) & 0x1ff) << 3); + pml4e = x86_ldq_phys(cs, pml4e_addr); + if (!(pml4e & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pml4e & (rsvd_mask | PG_PSE_MASK)) { + goto do_fault_rsvd; + } + if (!(pml4e & PG_ACCESSED_MASK)) { + pml4e |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); + } + ptep &= pml4e ^ PG_NX_MASK; + pdpe_addr = (pml4e & PG_ADDRESS_MASK) + + (((gphys >> 30) & 0x1ff) << 3); + pdpe = x86_ldq_phys(cs, pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pdpe & rsvd_mask) { + goto do_fault_rsvd; + } + ptep &= pdpe ^ PG_NX_MASK; + if (!(pdpe & PG_ACCESSED_MASK)) { + pdpe |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); + } + if (pdpe & PG_PSE_MASK) { + /* 1 GB page */ + page_size = 1024 * 1024 * 1024; + pte_addr = pdpe_addr; + pte = pdpe; + goto do_check_protect; + } + } else +#endif + { + pdpe_addr = (env->nested_cr3 & ~0x1f) + ((gphys >> 27) & 0x18); + pdpe = x86_ldq_phys(cs, pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + goto do_fault; + } + rsvd_mask |= PG_HI_USER_MASK; + if (pdpe & (rsvd_mask | PG_NX_MASK)) { + goto do_fault_rsvd; + } + ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; + } + + pde_addr = (pdpe & PG_ADDRESS_MASK) + (((gphys >> 21) & 0x1ff) << 3); + pde = x86_ldq_phys(cs, pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pde & rsvd_mask) { + goto do_fault_rsvd; + } + ptep &= pde ^ PG_NX_MASK; + if (pde & PG_PSE_MASK) { + /* 2 MB page */ + page_size = 2048 * 1024; + pte_addr = pde_addr; + pte = pde; + goto do_check_protect; + } + /* 4 KB page */ + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pde_addr, pde); + } + pte_addr = (pde & PG_ADDRESS_MASK) + (((gphys >> 12) & 0x1ff) << 3); + pte = x86_ldq_phys(cs, pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pte & rsvd_mask) { + goto do_fault_rsvd; + } + /* combine pde and pte nx, user and rw protections */ + ptep &= pte ^ PG_NX_MASK; + page_size = 4096; + } else { + uint32_t pde; + + /* page directory entry */ + pde_addr = (env->nested_cr3 & ~0xfff) + ((gphys >> 20) & 0xffc); + pde = x86_ldl_phys(cs, pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + goto do_fault; + } + ptep = pde | PG_NX_MASK; + + /* if host cr4 PSE bit is set, then we use a 4MB page */ + if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & SVM_NPT_PSE)) { + page_size = 4096 * 1024; + pte_addr = pde_addr; + + /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. + * Leave bits 20-13 in place for setting accessed/dirty bits below. + */ + pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); + rsvd_mask = 0x200000; + goto do_check_protect_pse36; + } + + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pde_addr, pde); + } + + /* page directory entry */ + pte_addr = (pde & ~0xfff) + ((gphys >> 10) & 0xffc); + pte = x86_ldl_phys(cs, pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + goto do_fault; + } + /* combine pde and pte user and rw protections */ + ptep &= pte | PG_NX_MASK; + page_size = 4096; + rsvd_mask = 0; + } + + do_check_protect: + rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; + do_check_protect_pse36: + if (pte & rsvd_mask) { + goto do_fault_rsvd; + } + ptep ^= PG_NX_MASK; + + if (!(ptep & PG_USER_MASK)) { + goto do_fault_protect; + } + if (ptep & PG_NX_MASK) { + if (access_type == MMU_INST_FETCH) { + goto do_fault_protect; + } + *prot &= ~PAGE_EXEC; + } + if (!(ptep & PG_RW_MASK)) { + if (access_type == MMU_DATA_STORE) { + goto do_fault_protect; + } + *prot &= ~PAGE_WRITE; + } + + pte &= PG_ADDRESS_MASK & ~(page_size - 1); + page_offset = gphys & (page_size - 1); + return pte + page_offset; + + do_fault_rsvd: + exit_info_1 |= SVM_NPTEXIT_RSVD; + do_fault_protect: + exit_info_1 |= SVM_NPTEXIT_P; + do_fault: + x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), + gphys); + exit_info_1 |= SVM_NPTEXIT_US; + if (access_type == MMU_DATA_STORE) { + exit_info_1 |= SVM_NPTEXIT_RW; + } else if (access_type == MMU_INST_FETCH) { + exit_info_1 |= SVM_NPTEXIT_ID; + } + if (prot) { + exit_info_1 |= SVM_NPTEXIT_GPA; + } else { /* page table access */ + exit_info_1 |= SVM_NPTEXIT_GPT; + } + cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr); +} + +/* return value: + * -1 = cannot handle fault + * 0 = nothing more to do + * 1 = generate PF fault + */ +static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, + int is_write1, int mmu_idx) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + uint64_t ptep, pte; + int32_t a20_mask; + target_ulong pde_addr, pte_addr; + int error_code = 0; + int is_dirty, prot, page_size, is_write, is_user; + hwaddr paddr; + uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); + uint32_t page_offset; + target_ulong vaddr; + uint32_t pkr; + + is_user = mmu_idx == MMU_USER_IDX; +#if defined(DEBUG_MMU) + printf("MMU fault: addr=%" VADDR_PRIx " w=%d u=%d eip=" TARGET_FMT_lx "\n", + addr, is_write1, is_user, env->eip); +#endif + is_write = is_write1 & 1; + + a20_mask = x86_get_a20_mask(env); + if (!(env->cr[0] & CR0_PG_MASK)) { + pte = addr; +#ifdef TARGET_X86_64 + if (!(env->hflags & HF_LMA_MASK)) { + /* Without long mode we can only address 32bits in real mode */ + pte = (uint32_t)pte; + } +#endif + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + page_size = 4096; + goto do_mapping; + } + + if (!(env->efer & MSR_EFER_NXE)) { + rsvd_mask |= PG_NX_MASK; + } + + if (env->cr[4] & CR4_PAE_MASK) { + uint64_t pde, pdpe; + target_ulong pdpe_addr; + +#ifdef TARGET_X86_64 + if (env->hflags & HF_LMA_MASK) { + bool la57 = env->cr[4] & CR4_LA57_MASK; + uint64_t pml5e_addr, pml5e; + uint64_t pml4e_addr, pml4e; + int32_t sext; + + /* test virtual address sign extension */ + sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47; + if (sext != 0 && sext != -1) { + env->error_code = 0; + cs->exception_index = EXCP0D_GPF; + return 1; + } + + if (la57) { + pml5e_addr = ((env->cr[3] & ~0xfff) + + (((addr >> 48) & 0x1ff) << 3)) & a20_mask; + pml5e_addr = get_hphys(cs, pml5e_addr, MMU_DATA_STORE, NULL); + pml5e = x86_ldq_phys(cs, pml5e_addr); + if (!(pml5e & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pml5e & (rsvd_mask | PG_PSE_MASK)) { + goto do_fault_rsvd; + } + if (!(pml5e & PG_ACCESSED_MASK)) { + pml5e |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pml5e_addr, pml5e); + } + ptep = pml5e ^ PG_NX_MASK; + } else { + pml5e = env->cr[3]; + ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; + } + + pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + + (((addr >> 39) & 0x1ff) << 3)) & a20_mask; + pml4e_addr = get_hphys(cs, pml4e_addr, MMU_DATA_STORE, false); + pml4e = x86_ldq_phys(cs, pml4e_addr); + if (!(pml4e & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pml4e & (rsvd_mask | PG_PSE_MASK)) { + goto do_fault_rsvd; + } + if (!(pml4e & PG_ACCESSED_MASK)) { + pml4e |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); + } + ptep &= pml4e ^ PG_NX_MASK; + pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & + a20_mask; + pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, NULL); + pdpe = x86_ldq_phys(cs, pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pdpe & rsvd_mask) { + goto do_fault_rsvd; + } + ptep &= pdpe ^ PG_NX_MASK; + if (!(pdpe & PG_ACCESSED_MASK)) { + pdpe |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); + } + if (pdpe & PG_PSE_MASK) { + /* 1 GB page */ + page_size = 1024 * 1024 * 1024; + pte_addr = pdpe_addr; + pte = pdpe; + goto do_check_protect; + } + } else +#endif + { + /* XXX: load them when cr3 is loaded ? */ + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & + a20_mask; + pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, false); + pdpe = x86_ldq_phys(cs, pdpe_addr); + if (!(pdpe & PG_PRESENT_MASK)) { + goto do_fault; + } + rsvd_mask |= PG_HI_USER_MASK; + if (pdpe & (rsvd_mask | PG_NX_MASK)) { + goto do_fault_rsvd; + } + ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; + } + + pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & + a20_mask; + pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); + pde = x86_ldq_phys(cs, pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pde & rsvd_mask) { + goto do_fault_rsvd; + } + ptep &= pde ^ PG_NX_MASK; + if (pde & PG_PSE_MASK) { + /* 2 MB page */ + page_size = 2048 * 1024; + pte_addr = pde_addr; + pte = pde; + goto do_check_protect; + } + /* 4 KB page */ + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pde_addr, pde); + } + pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & + a20_mask; + pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL); + pte = x86_ldq_phys(cs, pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pte & rsvd_mask) { + goto do_fault_rsvd; + } + /* combine pde and pte nx, user and rw protections */ + ptep &= pte ^ PG_NX_MASK; + page_size = 4096; + } else { + uint32_t pde; + + /* page directory entry */ + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & + a20_mask; + pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); + pde = x86_ldl_phys(cs, pde_addr); + if (!(pde & PG_PRESENT_MASK)) { + goto do_fault; + } + ptep = pde | PG_NX_MASK; + + /* if PSE bit is set, then we use a 4MB page */ + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + page_size = 4096 * 1024; + pte_addr = pde_addr; + + /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. + * Leave bits 20-13 in place for setting accessed/dirty bits below. + */ + pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); + rsvd_mask = 0x200000; + goto do_check_protect_pse36; + } + + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + x86_stl_phys_notdirty(cs, pde_addr, pde); + } + + /* page directory entry */ + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & + a20_mask; + pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL); + pte = x86_ldl_phys(cs, pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + goto do_fault; + } + /* combine pde and pte user and rw protections */ + ptep &= pte | PG_NX_MASK; + page_size = 4096; + rsvd_mask = 0; + } + +do_check_protect: + rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; +do_check_protect_pse36: + if (pte & rsvd_mask) { + goto do_fault_rsvd; + } + ptep ^= PG_NX_MASK; + + /* can the page can be put in the TLB? prot will tell us */ + if (is_user && !(ptep & PG_USER_MASK)) { + goto do_fault_protect; + } + + prot = 0; + if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { + prot |= PAGE_READ; + if ((ptep & PG_RW_MASK) || (!is_user && !(env->cr[0] & CR0_WP_MASK))) { + prot |= PAGE_WRITE; + } + } + if (!(ptep & PG_NX_MASK) && + (mmu_idx == MMU_USER_IDX || + !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) { + prot |= PAGE_EXEC; + } + + if (!(env->hflags & HF_LMA_MASK)) { + pkr = 0; + } else if (ptep & PG_USER_MASK) { + pkr = env->cr[4] & CR4_PKE_MASK ? env->pkru : 0; + } else { + pkr = env->cr[4] & CR4_PKS_MASK ? env->pkrs : 0; + } + if (pkr) { + uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; + uint32_t pkr_ad = (pkr >> pk * 2) & 1; + uint32_t pkr_wd = (pkr >> pk * 2) & 2; + uint32_t pkr_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + + if (pkr_ad) { + pkr_prot &= ~(PAGE_READ | PAGE_WRITE); + } else if (pkr_wd && (is_user || env->cr[0] & CR0_WP_MASK)) { + pkr_prot &= ~PAGE_WRITE; + } + + prot &= pkr_prot; + if ((pkr_prot & (1 << is_write1)) == 0) { + assert(is_write1 != 2); + error_code |= PG_ERROR_PK_MASK; + goto do_fault_protect; + } + } + + if ((prot & (1 << is_write1)) == 0) { + goto do_fault_protect; + } + + /* yes, it can! */ + is_dirty = is_write && !(pte & PG_DIRTY_MASK); + if (!(pte & PG_ACCESSED_MASK) || is_dirty) { + pte |= PG_ACCESSED_MASK; + if (is_dirty) { + pte |= PG_DIRTY_MASK; + } + x86_stl_phys_notdirty(cs, pte_addr, pte); + } + + if (!(pte & PG_DIRTY_MASK)) { + /* only set write access if already dirty... otherwise wait + for dirty access */ + assert(!is_write); + prot &= ~PAGE_WRITE; + } + + do_mapping: + pte = pte & a20_mask; + + /* align to page_size */ + pte &= PG_ADDRESS_MASK & ~(page_size - 1); + page_offset = addr & (page_size - 1); + paddr = get_hphys(cs, pte + page_offset, is_write1, &prot); + + /* Even if 4MB pages, we map only one 4KB page in the cache to + avoid filling it too fast */ + vaddr = addr & TARGET_PAGE_MASK; + paddr &= TARGET_PAGE_MASK; + + assert(prot & (1 << is_write1)); + tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env), + prot, mmu_idx, page_size); + return 0; + do_fault_rsvd: + error_code |= PG_ERROR_RSVD_MASK; + do_fault_protect: + error_code |= PG_ERROR_P_MASK; + do_fault: + error_code |= (is_write << PG_ERROR_W_BIT); + if (is_user) + error_code |= PG_ERROR_U_MASK; + if (is_write1 == 2 && + (((env->efer & MSR_EFER_NXE) && + (env->cr[4] & CR4_PAE_MASK)) || + (env->cr[4] & CR4_SMEP_MASK))) + error_code |= PG_ERROR_I_D_MASK; + if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { + /* cr2 is not modified in case of exceptions */ + x86_stq_phys(cs, + env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), + addr); + } else { + env->cr[2] = addr; + } + env->error_code = error_code; + cs->exception_index = EXCP0E_PAGE; + return 1; +} + +bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + env->retaddr = retaddr; + if (handle_mmu_fault(cs, addr, size, access_type, mmu_idx)) { + /* FIXME: On error in get_hphys we have already jumped out. */ + g_assert(!probe); + raise_exception_err_ra(env, cs->exception_index, + env->error_code, retaddr); + } + return true; +} diff --git a/target/i386/tcg/sysemu/meson.build b/target/i386/tcg/sysemu/meson.build index 35ba16dc3d..6d0a0a0fee 100644 --- a/target/i386/tcg/sysemu/meson.build +++ b/target/i386/tcg/sysemu/meson.build @@ -1,4 +1,5 @@ i386_softmmu_ss.add(when: ['CONFIG_TCG', 'CONFIG_SOFTMMU'], if_true: files( 'tcg-cpu.c', 'smm_helper.c', + 'excp_helper.c', )) diff --git a/target/i386/tcg/user/excp_helper.c b/target/i386/tcg/user/excp_helper.c new file mode 100644 index 0000000000..a89b5228fd --- /dev/null +++ b/target/i386/tcg/user/excp_helper.c @@ -0,0 +1,39 @@ +/* + * x86 exception helpers - user-mode specific code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "tcg/helper-tcg.h" + +bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + env->cr[2] = addr; + env->error_code = (access_type == MMU_DATA_STORE) << PG_ERROR_W_BIT; + env->error_code |= PG_ERROR_U_MASK; + cs->exception_index = EXCP0E_PAGE; + env->exception_is_int = 0; + env->exception_next_eip = -1; + cpu_loop_exit_restore(cs, retaddr); +} diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build index 7aecc53155..e0ef0f02e2 100644 --- a/target/i386/tcg/user/meson.build +++ b/target/i386/tcg/user/meson.build @@ -1,2 +1,3 @@ i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], if_true: files( + 'excp_helper.c', )) From 6d8d1a031ad70122c47d23902f7c3e60f7e1d61e Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:49 +0100 Subject: [PATCH 0401/3028] i386: move TCG bpt_helper into sysemu/ for user-mode, assert that the hidden IOBPT flags are not set while attempting to generate io_bpt helpers. Signed-off-by: Claudio Fontana Cc: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-14-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/helper.h | 7 + target/i386/tcg/bpt_helper.c | 276 -------------------------- target/i386/tcg/helper-tcg.h | 3 + target/i386/tcg/sysemu/bpt_helper.c | 293 ++++++++++++++++++++++++++++ target/i386/tcg/sysemu/meson.build | 1 + target/i386/tcg/translate.c | 8 +- 6 files changed, 311 insertions(+), 277 deletions(-) create mode 100644 target/i386/tcg/sysemu/bpt_helper.c diff --git a/target/i386/helper.h b/target/i386/helper.h index 8ffda4cdc6..095520f81f 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -46,7 +46,11 @@ DEF_HELPER_2(read_crN, tl, env, int) DEF_HELPER_3(write_crN, void, env, int, tl) DEF_HELPER_2(lmsw, void, env, tl) DEF_HELPER_1(clts, void, env) + +#ifndef CONFIG_USER_ONLY DEF_HELPER_FLAGS_3(set_dr, TCG_CALL_NO_WG, void, env, int, tl) +#endif /* !CONFIG_USER_ONLY */ + DEF_HELPER_FLAGS_2(get_dr, TCG_CALL_NO_WG, tl, env, int) DEF_HELPER_2(invlpg, void, env, tl) @@ -100,7 +104,10 @@ DEF_HELPER_3(outw, void, env, i32, i32) DEF_HELPER_2(inw, tl, env, i32) DEF_HELPER_3(outl, void, env, i32, i32) DEF_HELPER_2(inl, tl, env, i32) + +#ifndef CONFIG_USER_ONLY DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl) +#endif /* !CONFIG_USER_ONLY */ DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64) DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32) diff --git a/target/i386/tcg/bpt_helper.c b/target/i386/tcg/bpt_helper.c index 979230ac12..fb2a65ac9c 100644 --- a/target/i386/tcg/bpt_helper.c +++ b/target/i386/tcg/bpt_helper.c @@ -19,223 +19,9 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "helper-tcg.h" - -#ifndef CONFIG_USER_ONLY -static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index) -{ - return (dr7 >> (index * 2)) & 1; -} - -static inline bool hw_global_breakpoint_enabled(unsigned long dr7, int index) -{ - return (dr7 >> (index * 2)) & 2; - -} -static inline bool hw_breakpoint_enabled(unsigned long dr7, int index) -{ - return hw_global_breakpoint_enabled(dr7, index) || - hw_local_breakpoint_enabled(dr7, index); -} - -static inline int hw_breakpoint_type(unsigned long dr7, int index) -{ - return (dr7 >> (DR7_TYPE_SHIFT + (index * 4))) & 3; -} - -static inline int hw_breakpoint_len(unsigned long dr7, int index) -{ - int len = ((dr7 >> (DR7_LEN_SHIFT + (index * 4))) & 3); - return (len == 2) ? 8 : len + 1; -} - -static int hw_breakpoint_insert(CPUX86State *env, int index) -{ - CPUState *cs = env_cpu(env); - target_ulong dr7 = env->dr[7]; - target_ulong drN = env->dr[index]; - int err = 0; - - switch (hw_breakpoint_type(dr7, index)) { - case DR7_TYPE_BP_INST: - if (hw_breakpoint_enabled(dr7, index)) { - err = cpu_breakpoint_insert(cs, drN, BP_CPU, - &env->cpu_breakpoint[index]); - } - break; - - case DR7_TYPE_IO_RW: - /* Notice when we should enable calls to bpt_io. */ - return hw_breakpoint_enabled(env->dr[7], index) - ? HF_IOBPT_MASK : 0; - - case DR7_TYPE_DATA_WR: - if (hw_breakpoint_enabled(dr7, index)) { - err = cpu_watchpoint_insert(cs, drN, - hw_breakpoint_len(dr7, index), - BP_CPU | BP_MEM_WRITE, - &env->cpu_watchpoint[index]); - } - break; - - case DR7_TYPE_DATA_RW: - if (hw_breakpoint_enabled(dr7, index)) { - err = cpu_watchpoint_insert(cs, drN, - hw_breakpoint_len(dr7, index), - BP_CPU | BP_MEM_ACCESS, - &env->cpu_watchpoint[index]); - } - break; - } - if (err) { - env->cpu_breakpoint[index] = NULL; - } - return 0; -} - -static void hw_breakpoint_remove(CPUX86State *env, int index) -{ - CPUState *cs = env_cpu(env); - - switch (hw_breakpoint_type(env->dr[7], index)) { - case DR7_TYPE_BP_INST: - if (env->cpu_breakpoint[index]) { - cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]); - env->cpu_breakpoint[index] = NULL; - } - break; - - case DR7_TYPE_DATA_WR: - case DR7_TYPE_DATA_RW: - if (env->cpu_breakpoint[index]) { - cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]); - env->cpu_breakpoint[index] = NULL; - } - break; - - case DR7_TYPE_IO_RW: - /* HF_IOBPT_MASK cleared elsewhere. */ - break; - } -} - -void cpu_x86_update_dr7(CPUX86State *env, uint32_t new_dr7) -{ - target_ulong old_dr7 = env->dr[7]; - int iobpt = 0; - int i; - - new_dr7 |= DR7_FIXED_1; - - /* If nothing is changing except the global/local enable bits, - then we can make the change more efficient. */ - if (((old_dr7 ^ new_dr7) & ~0xff) == 0) { - /* Fold the global and local enable bits together into the - global fields, then xor to show which registers have - changed collective enable state. */ - int mod = ((old_dr7 | old_dr7 * 2) ^ (new_dr7 | new_dr7 * 2)) & 0xff; - - for (i = 0; i < DR7_MAX_BP; i++) { - if ((mod & (2 << i * 2)) && !hw_breakpoint_enabled(new_dr7, i)) { - hw_breakpoint_remove(env, i); - } - } - env->dr[7] = new_dr7; - for (i = 0; i < DR7_MAX_BP; i++) { - if (mod & (2 << i * 2) && hw_breakpoint_enabled(new_dr7, i)) { - iobpt |= hw_breakpoint_insert(env, i); - } else if (hw_breakpoint_type(new_dr7, i) == DR7_TYPE_IO_RW - && hw_breakpoint_enabled(new_dr7, i)) { - iobpt |= HF_IOBPT_MASK; - } - } - } else { - for (i = 0; i < DR7_MAX_BP; i++) { - hw_breakpoint_remove(env, i); - } - env->dr[7] = new_dr7; - for (i = 0; i < DR7_MAX_BP; i++) { - iobpt |= hw_breakpoint_insert(env, i); - } - } - - env->hflags = (env->hflags & ~HF_IOBPT_MASK) | iobpt; -} - -static bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update) -{ - target_ulong dr6; - int reg; - bool hit_enabled = false; - - dr6 = env->dr[6] & ~0xf; - for (reg = 0; reg < DR7_MAX_BP; reg++) { - bool bp_match = false; - bool wp_match = false; - - switch (hw_breakpoint_type(env->dr[7], reg)) { - case DR7_TYPE_BP_INST: - if (env->dr[reg] == env->eip) { - bp_match = true; - } - break; - case DR7_TYPE_DATA_WR: - case DR7_TYPE_DATA_RW: - if (env->cpu_watchpoint[reg] && - env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) { - wp_match = true; - } - break; - case DR7_TYPE_IO_RW: - break; - } - if (bp_match || wp_match) { - dr6 |= 1 << reg; - if (hw_breakpoint_enabled(env->dr[7], reg)) { - hit_enabled = true; - } - } - } - - if (hit_enabled || force_dr6_update) { - env->dr[6] = dr6; - } - - return hit_enabled; -} - -void breakpoint_handler(CPUState *cs) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - CPUBreakpoint *bp; - - if (cs->watchpoint_hit) { - if (cs->watchpoint_hit->flags & BP_CPU) { - cs->watchpoint_hit = NULL; - if (check_hw_breakpoints(env, false)) { - raise_exception(env, EXCP01_DB); - } else { - cpu_loop_exit_noexc(cs); - } - } - } else { - QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { - if (bp->pc == env->eip) { - if (bp->flags & BP_CPU) { - check_hw_breakpoints(env, true); - raise_exception(env, EXCP01_DB); - } - break; - } - } - } -} -#endif - void helper_single_step(CPUX86State *env) { #ifndef CONFIG_USER_ONLY @@ -252,41 +38,6 @@ void helper_rechecking_single_step(CPUX86State *env) } } -void helper_set_dr(CPUX86State *env, int reg, target_ulong t0) -{ -#ifndef CONFIG_USER_ONLY - switch (reg) { - case 0: case 1: case 2: case 3: - if (hw_breakpoint_enabled(env->dr[7], reg) - && hw_breakpoint_type(env->dr[7], reg) != DR7_TYPE_IO_RW) { - hw_breakpoint_remove(env, reg); - env->dr[reg] = t0; - hw_breakpoint_insert(env, reg); - } else { - env->dr[reg] = t0; - } - return; - case 4: - if (env->cr[4] & CR4_DE_MASK) { - break; - } - /* fallthru */ - case 6: - env->dr[6] = t0 | DR6_FIXED_1; - return; - case 5: - if (env->cr[4] & CR4_DE_MASK) { - break; - } - /* fallthru */ - case 7: - cpu_x86_update_dr7(env, t0); - return; - } - raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); -#endif -} - target_ulong helper_get_dr(CPUX86State *env, int reg) { switch (reg) { @@ -307,30 +58,3 @@ target_ulong helper_get_dr(CPUX86State *env, int reg) } raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); } - -/* Check if Port I/O is trapped by a breakpoint. */ -void helper_bpt_io(CPUX86State *env, uint32_t port, - uint32_t size, target_ulong next_eip) -{ -#ifndef CONFIG_USER_ONLY - target_ulong dr7 = env->dr[7]; - int i, hit = 0; - - for (i = 0; i < DR7_MAX_BP; ++i) { - if (hw_breakpoint_type(dr7, i) == DR7_TYPE_IO_RW - && hw_breakpoint_enabled(dr7, i)) { - int bpt_len = hw_breakpoint_len(dr7, i); - if (port + size - 1 >= env->dr[i] - && port <= env->dr[i] + bpt_len - 1) { - hit |= 1 << i; - } - } - } - - if (hit) { - env->dr[6] = (env->dr[6] & ~0xf) | hit; - env->eip = next_eip; - raise_exception(env, EXCP01_DB); - } -#endif -} diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index bcdfca06f6..ff2b99886c 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -88,4 +88,7 @@ void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw); /* smm_helper.c */ void do_smm_enter(X86CPU *cpu); +/* bpt_helper.c */ +bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update); + #endif /* I386_HELPER_TCG_H */ diff --git a/target/i386/tcg/sysemu/bpt_helper.c b/target/i386/tcg/sysemu/bpt_helper.c new file mode 100644 index 0000000000..9bdf7e170b --- /dev/null +++ b/target/i386/tcg/sysemu/bpt_helper.c @@ -0,0 +1,293 @@ +/* + * i386 breakpoint helpers - sysemu code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/helper-proto.h" +#include "tcg/helper-tcg.h" + + +static inline bool hw_local_breakpoint_enabled(unsigned long dr7, int index) +{ + return (dr7 >> (index * 2)) & 1; +} + +static inline bool hw_global_breakpoint_enabled(unsigned long dr7, int index) +{ + return (dr7 >> (index * 2)) & 2; + +} +static inline bool hw_breakpoint_enabled(unsigned long dr7, int index) +{ + return hw_global_breakpoint_enabled(dr7, index) || + hw_local_breakpoint_enabled(dr7, index); +} + +static inline int hw_breakpoint_type(unsigned long dr7, int index) +{ + return (dr7 >> (DR7_TYPE_SHIFT + (index * 4))) & 3; +} + +static inline int hw_breakpoint_len(unsigned long dr7, int index) +{ + int len = ((dr7 >> (DR7_LEN_SHIFT + (index * 4))) & 3); + return (len == 2) ? 8 : len + 1; +} + +static int hw_breakpoint_insert(CPUX86State *env, int index) +{ + CPUState *cs = env_cpu(env); + target_ulong dr7 = env->dr[7]; + target_ulong drN = env->dr[index]; + int err = 0; + + switch (hw_breakpoint_type(dr7, index)) { + case DR7_TYPE_BP_INST: + if (hw_breakpoint_enabled(dr7, index)) { + err = cpu_breakpoint_insert(cs, drN, BP_CPU, + &env->cpu_breakpoint[index]); + } + break; + + case DR7_TYPE_IO_RW: + /* Notice when we should enable calls to bpt_io. */ + return hw_breakpoint_enabled(env->dr[7], index) + ? HF_IOBPT_MASK : 0; + + case DR7_TYPE_DATA_WR: + if (hw_breakpoint_enabled(dr7, index)) { + err = cpu_watchpoint_insert(cs, drN, + hw_breakpoint_len(dr7, index), + BP_CPU | BP_MEM_WRITE, + &env->cpu_watchpoint[index]); + } + break; + + case DR7_TYPE_DATA_RW: + if (hw_breakpoint_enabled(dr7, index)) { + err = cpu_watchpoint_insert(cs, drN, + hw_breakpoint_len(dr7, index), + BP_CPU | BP_MEM_ACCESS, + &env->cpu_watchpoint[index]); + } + break; + } + if (err) { + env->cpu_breakpoint[index] = NULL; + } + return 0; +} + +static void hw_breakpoint_remove(CPUX86State *env, int index) +{ + CPUState *cs = env_cpu(env); + + switch (hw_breakpoint_type(env->dr[7], index)) { + case DR7_TYPE_BP_INST: + if (env->cpu_breakpoint[index]) { + cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]); + env->cpu_breakpoint[index] = NULL; + } + break; + + case DR7_TYPE_DATA_WR: + case DR7_TYPE_DATA_RW: + if (env->cpu_breakpoint[index]) { + cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]); + env->cpu_breakpoint[index] = NULL; + } + break; + + case DR7_TYPE_IO_RW: + /* HF_IOBPT_MASK cleared elsewhere. */ + break; + } +} + +void cpu_x86_update_dr7(CPUX86State *env, uint32_t new_dr7) +{ + target_ulong old_dr7 = env->dr[7]; + int iobpt = 0; + int i; + + new_dr7 |= DR7_FIXED_1; + + /* If nothing is changing except the global/local enable bits, + then we can make the change more efficient. */ + if (((old_dr7 ^ new_dr7) & ~0xff) == 0) { + /* Fold the global and local enable bits together into the + global fields, then xor to show which registers have + changed collective enable state. */ + int mod = ((old_dr7 | old_dr7 * 2) ^ (new_dr7 | new_dr7 * 2)) & 0xff; + + for (i = 0; i < DR7_MAX_BP; i++) { + if ((mod & (2 << i * 2)) && !hw_breakpoint_enabled(new_dr7, i)) { + hw_breakpoint_remove(env, i); + } + } + env->dr[7] = new_dr7; + for (i = 0; i < DR7_MAX_BP; i++) { + if (mod & (2 << i * 2) && hw_breakpoint_enabled(new_dr7, i)) { + iobpt |= hw_breakpoint_insert(env, i); + } else if (hw_breakpoint_type(new_dr7, i) == DR7_TYPE_IO_RW + && hw_breakpoint_enabled(new_dr7, i)) { + iobpt |= HF_IOBPT_MASK; + } + } + } else { + for (i = 0; i < DR7_MAX_BP; i++) { + hw_breakpoint_remove(env, i); + } + env->dr[7] = new_dr7; + for (i = 0; i < DR7_MAX_BP; i++) { + iobpt |= hw_breakpoint_insert(env, i); + } + } + + env->hflags = (env->hflags & ~HF_IOBPT_MASK) | iobpt; +} + +bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update) +{ + target_ulong dr6; + int reg; + bool hit_enabled = false; + + dr6 = env->dr[6] & ~0xf; + for (reg = 0; reg < DR7_MAX_BP; reg++) { + bool bp_match = false; + bool wp_match = false; + + switch (hw_breakpoint_type(env->dr[7], reg)) { + case DR7_TYPE_BP_INST: + if (env->dr[reg] == env->eip) { + bp_match = true; + } + break; + case DR7_TYPE_DATA_WR: + case DR7_TYPE_DATA_RW: + if (env->cpu_watchpoint[reg] && + env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) { + wp_match = true; + } + break; + case DR7_TYPE_IO_RW: + break; + } + if (bp_match || wp_match) { + dr6 |= 1 << reg; + if (hw_breakpoint_enabled(env->dr[7], reg)) { + hit_enabled = true; + } + } + } + + if (hit_enabled || force_dr6_update) { + env->dr[6] = dr6; + } + + return hit_enabled; +} + +void breakpoint_handler(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + CPUBreakpoint *bp; + + if (cs->watchpoint_hit) { + if (cs->watchpoint_hit->flags & BP_CPU) { + cs->watchpoint_hit = NULL; + if (check_hw_breakpoints(env, false)) { + raise_exception(env, EXCP01_DB); + } else { + cpu_loop_exit_noexc(cs); + } + } + } else { + QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { + if (bp->pc == env->eip) { + if (bp->flags & BP_CPU) { + check_hw_breakpoints(env, true); + raise_exception(env, EXCP01_DB); + } + break; + } + } + } +} + +void helper_set_dr(CPUX86State *env, int reg, target_ulong t0) +{ + switch (reg) { + case 0: case 1: case 2: case 3: + if (hw_breakpoint_enabled(env->dr[7], reg) + && hw_breakpoint_type(env->dr[7], reg) != DR7_TYPE_IO_RW) { + hw_breakpoint_remove(env, reg); + env->dr[reg] = t0; + hw_breakpoint_insert(env, reg); + } else { + env->dr[reg] = t0; + } + return; + case 4: + if (env->cr[4] & CR4_DE_MASK) { + break; + } + /* fallthru */ + case 6: + env->dr[6] = t0 | DR6_FIXED_1; + return; + case 5: + if (env->cr[4] & CR4_DE_MASK) { + break; + } + /* fallthru */ + case 7: + cpu_x86_update_dr7(env, t0); + return; + } + raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); +} + +/* Check if Port I/O is trapped by a breakpoint. */ +void helper_bpt_io(CPUX86State *env, uint32_t port, + uint32_t size, target_ulong next_eip) +{ + target_ulong dr7 = env->dr[7]; + int i, hit = 0; + + for (i = 0; i < DR7_MAX_BP; ++i) { + if (hw_breakpoint_type(dr7, i) == DR7_TYPE_IO_RW + && hw_breakpoint_enabled(dr7, i)) { + int bpt_len = hw_breakpoint_len(dr7, i); + if (port + size - 1 >= env->dr[i] + && port <= env->dr[i] + bpt_len - 1) { + hit |= 1 << i; + } + } + } + + if (hit) { + env->dr[6] = (env->dr[6] & ~0xf) | hit; + env->eip = next_eip; + raise_exception(env, EXCP01_DB); + } +} diff --git a/target/i386/tcg/sysemu/meson.build b/target/i386/tcg/sysemu/meson.build index 6d0a0a0fee..1580950141 100644 --- a/target/i386/tcg/sysemu/meson.build +++ b/target/i386/tcg/sysemu/meson.build @@ -2,4 +2,5 @@ i386_softmmu_ss.add(when: ['CONFIG_TCG', 'CONFIG_SOFTMMU'], if_true: files( 'tcg-cpu.c', 'smm_helper.c', 'excp_helper.c', + 'bpt_helper.c', )) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index b02bdf5ea2..db56a48343 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -1117,16 +1117,20 @@ static inline void gen_cmps(DisasContext *s, MemOp ot) static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot) { if (s->flags & HF_IOBPT_MASK) { +#ifdef CONFIG_USER_ONLY + /* user-mode cpu should not be in IOBPT mode */ + g_assert_not_reached(); +#else TCGv_i32 t_size = tcg_const_i32(1 << ot); TCGv t_next = tcg_const_tl(s->pc - s->cs_base); gen_helper_bpt_io(cpu_env, t_port, t_size, t_next); tcg_temp_free_i32(t_size); tcg_temp_free(t_next); +#endif /* CONFIG_USER_ONLY */ } } - static inline void gen_ins(DisasContext *s, MemOp ot) { gen_string_movl_A0_EDI(s); @@ -8061,6 +8065,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (s->cpl != 0) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { +#ifndef CONFIG_USER_ONLY modrm = x86_ldub_code(env, s); /* Ignore the mod bits (assume (modrm&0xc0)==0xc0). * AMD documentation (24594.pdf) and testing of @@ -8089,6 +8094,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_helper_get_dr(s->T0, cpu_env, s->tmp2_i32); gen_op_mov_reg_v(s, ot, rm, s->T0); } +#endif /* !CONFIG_USER_ONLY */ } break; case 0x106: /* clts */ From a4b1f4e61129613fadd2c00422df31405b4925e8 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:50 +0100 Subject: [PATCH 0402/3028] i386: split misc helper user stubs and sysemu part Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson [claudio]: Rebased on da3f3b02("target/i386: fail if toggling LA57 in 64-bitmode") Signed-off-by: Claudio Fontana Message-Id: <20210322132800.7470-15-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/tcg/misc_helper.c | 467 --------------------------- target/i386/tcg/sysemu/meson.build | 1 + target/i386/tcg/sysemu/misc_helper.c | 442 +++++++++++++++++++++++++ target/i386/tcg/user/meson.build | 1 + target/i386/tcg/user/misc_stubs.c | 75 +++++ 5 files changed, 519 insertions(+), 467 deletions(-) create mode 100644 target/i386/tcg/sysemu/misc_helper.c create mode 100644 target/i386/tcg/user/misc_stubs.c diff --git a/target/i386/tcg/misc_helper.c b/target/i386/tcg/misc_helper.c index a25428c36e..a30379283e 100644 --- a/target/i386/tcg/misc_helper.c +++ b/target/i386/tcg/misc_helper.c @@ -18,12 +18,9 @@ */ #include "qemu/osdep.h" -#include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" -#include "exec/address-spaces.h" #include "helper-tcg.h" /* @@ -39,69 +36,6 @@ void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask) (eflags & update_mask) | 0x2; } -void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "outb: port=0x%04x, data=%02x\n", port, data); -#else - address_space_stb(&address_space_io, port, data, - cpu_get_mem_attrs(env), NULL); -#endif -} - -target_ulong helper_inb(CPUX86State *env, uint32_t port) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "inb: port=0x%04x\n", port); - return 0; -#else - return address_space_ldub(&address_space_io, port, - cpu_get_mem_attrs(env), NULL); -#endif -} - -void helper_outw(CPUX86State *env, uint32_t port, uint32_t data) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "outw: port=0x%04x, data=%04x\n", port, data); -#else - address_space_stw(&address_space_io, port, data, - cpu_get_mem_attrs(env), NULL); -#endif -} - -target_ulong helper_inw(CPUX86State *env, uint32_t port) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "inw: port=0x%04x\n", port); - return 0; -#else - return address_space_lduw(&address_space_io, port, - cpu_get_mem_attrs(env), NULL); -#endif -} - -void helper_outl(CPUX86State *env, uint32_t port, uint32_t data) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "outl: port=0x%04x, data=%08x\n", port, data); -#else - address_space_stl(&address_space_io, port, data, - cpu_get_mem_attrs(env), NULL); -#endif -} - -target_ulong helper_inl(CPUX86State *env, uint32_t port) -{ -#ifdef CONFIG_USER_ONLY - fprintf(stderr, "inl: port=0x%04x\n", port); - return 0; -#else - return address_space_ldl(&address_space_io, port, - cpu_get_mem_attrs(env), NULL); -#endif -} - void helper_into(CPUX86State *env, int next_eip_addend) { int eflags; @@ -126,68 +60,6 @@ void helper_cpuid(CPUX86State *env) env->regs[R_EDX] = edx; } -#if defined(CONFIG_USER_ONLY) -target_ulong helper_read_crN(CPUX86State *env, int reg) -{ - return 0; -} - -void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) -{ -} -#else -target_ulong helper_read_crN(CPUX86State *env, int reg) -{ - target_ulong val; - - cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC()); - switch (reg) { - default: - val = env->cr[reg]; - break; - case 8: - if (!(env->hflags2 & HF2_VINTR_MASK)) { - val = cpu_get_apic_tpr(env_archcpu(env)->apic_state); - } else { - val = env->v_tpr; - } - break; - } - return val; -} - -void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) -{ - cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC()); - switch (reg) { - case 0: - cpu_x86_update_cr0(env, t0); - break; - case 3: - cpu_x86_update_cr3(env, t0); - break; - case 4: - if (((t0 ^ env->cr[4]) & CR4_LA57_MASK) && - (env->hflags & HF_CS64_MASK)) { - raise_exception_ra(env, EXCP0D_GPF, GETPC()); - } - cpu_x86_update_cr4(env, t0); - break; - case 8: - if (!(env->hflags2 & HF2_VINTR_MASK)) { - qemu_mutex_lock_iothread(); - cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0); - qemu_mutex_unlock_iothread(); - } - env->v_tpr = t0 & 0x0f; - break; - default: - env->cr[reg] = t0; - break; - } -} -#endif - void helper_lmsw(CPUX86State *env, target_ulong t0) { /* only 4 lower bits of CR0 are modified. PE cannot be set to zero @@ -237,345 +109,6 @@ void helper_rdpmc(CPUX86State *env) raise_exception_err(env, EXCP06_ILLOP, 0); } -#if defined(CONFIG_USER_ONLY) -void helper_wrmsr(CPUX86State *env) -{ -} - -void helper_rdmsr(CPUX86State *env) -{ -} -#else -void helper_wrmsr(CPUX86State *env) -{ - uint64_t val; - CPUState *cs = env_cpu(env); - - cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC()); - - val = ((uint32_t)env->regs[R_EAX]) | - ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32); - - switch ((uint32_t)env->regs[R_ECX]) { - case MSR_IA32_SYSENTER_CS: - env->sysenter_cs = val & 0xffff; - break; - case MSR_IA32_SYSENTER_ESP: - env->sysenter_esp = val; - break; - case MSR_IA32_SYSENTER_EIP: - env->sysenter_eip = val; - break; - case MSR_IA32_APICBASE: - cpu_set_apic_base(env_archcpu(env)->apic_state, val); - break; - case MSR_EFER: - { - uint64_t update_mask; - - update_mask = 0; - if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) { - update_mask |= MSR_EFER_SCE; - } - if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { - update_mask |= MSR_EFER_LME; - } - if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) { - update_mask |= MSR_EFER_FFXSR; - } - if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) { - update_mask |= MSR_EFER_NXE; - } - if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) { - update_mask |= MSR_EFER_SVME; - } - if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) { - update_mask |= MSR_EFER_FFXSR; - } - cpu_load_efer(env, (env->efer & ~update_mask) | - (val & update_mask)); - } - break; - case MSR_STAR: - env->star = val; - break; - case MSR_PAT: - env->pat = val; - break; - case MSR_IA32_PKRS: - if (val & 0xFFFFFFFF00000000ull) { - goto error; - } - env->pkrs = val; - tlb_flush(cs); - break; - case MSR_VM_HSAVE_PA: - env->vm_hsave = val; - break; -#ifdef TARGET_X86_64 - case MSR_LSTAR: - env->lstar = val; - break; - case MSR_CSTAR: - env->cstar = val; - break; - case MSR_FMASK: - env->fmask = val; - break; - case MSR_FSBASE: - env->segs[R_FS].base = val; - break; - case MSR_GSBASE: - env->segs[R_GS].base = val; - break; - case MSR_KERNELGSBASE: - env->kernelgsbase = val; - break; -#endif - case MSR_MTRRphysBase(0): - case MSR_MTRRphysBase(1): - case MSR_MTRRphysBase(2): - case MSR_MTRRphysBase(3): - case MSR_MTRRphysBase(4): - case MSR_MTRRphysBase(5): - case MSR_MTRRphysBase(6): - case MSR_MTRRphysBase(7): - env->mtrr_var[((uint32_t)env->regs[R_ECX] - - MSR_MTRRphysBase(0)) / 2].base = val; - break; - case MSR_MTRRphysMask(0): - case MSR_MTRRphysMask(1): - case MSR_MTRRphysMask(2): - case MSR_MTRRphysMask(3): - case MSR_MTRRphysMask(4): - case MSR_MTRRphysMask(5): - case MSR_MTRRphysMask(6): - case MSR_MTRRphysMask(7): - env->mtrr_var[((uint32_t)env->regs[R_ECX] - - MSR_MTRRphysMask(0)) / 2].mask = val; - break; - case MSR_MTRRfix64K_00000: - env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - - MSR_MTRRfix64K_00000] = val; - break; - case MSR_MTRRfix16K_80000: - case MSR_MTRRfix16K_A0000: - env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - - MSR_MTRRfix16K_80000 + 1] = val; - break; - case MSR_MTRRfix4K_C0000: - case MSR_MTRRfix4K_C8000: - case MSR_MTRRfix4K_D0000: - case MSR_MTRRfix4K_D8000: - case MSR_MTRRfix4K_E0000: - case MSR_MTRRfix4K_E8000: - case MSR_MTRRfix4K_F0000: - case MSR_MTRRfix4K_F8000: - env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - - MSR_MTRRfix4K_C0000 + 3] = val; - break; - case MSR_MTRRdefType: - env->mtrr_deftype = val; - break; - case MSR_MCG_STATUS: - env->mcg_status = val; - break; - case MSR_MCG_CTL: - if ((env->mcg_cap & MCG_CTL_P) - && (val == 0 || val == ~(uint64_t)0)) { - env->mcg_ctl = val; - } - break; - case MSR_TSC_AUX: - env->tsc_aux = val; - break; - case MSR_IA32_MISC_ENABLE: - env->msr_ia32_misc_enable = val; - break; - case MSR_IA32_BNDCFGS: - /* FIXME: #GP if reserved bits are set. */ - /* FIXME: Extend highest implemented bit of linear address. */ - env->msr_bndcfgs = val; - cpu_sync_bndcs_hflags(env); - break; - default: - if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL - && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL + - (4 * env->mcg_cap & 0xff)) { - uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL; - if ((offset & 0x3) != 0 - || (val == 0 || val == ~(uint64_t)0)) { - env->mce_banks[offset] = val; - } - break; - } - /* XXX: exception? */ - break; - } - return; -error: - raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); -} - -void helper_rdmsr(CPUX86State *env) -{ - X86CPU *x86_cpu = env_archcpu(env); - uint64_t val; - - cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC()); - - switch ((uint32_t)env->regs[R_ECX]) { - case MSR_IA32_SYSENTER_CS: - val = env->sysenter_cs; - break; - case MSR_IA32_SYSENTER_ESP: - val = env->sysenter_esp; - break; - case MSR_IA32_SYSENTER_EIP: - val = env->sysenter_eip; - break; - case MSR_IA32_APICBASE: - val = cpu_get_apic_base(env_archcpu(env)->apic_state); - break; - case MSR_EFER: - val = env->efer; - break; - case MSR_STAR: - val = env->star; - break; - case MSR_PAT: - val = env->pat; - break; - case MSR_IA32_PKRS: - val = env->pkrs; - break; - case MSR_VM_HSAVE_PA: - val = env->vm_hsave; - break; - case MSR_IA32_PERF_STATUS: - /* tsc_increment_by_tick */ - val = 1000ULL; - /* CPU multiplier */ - val |= (((uint64_t)4ULL) << 40); - break; -#ifdef TARGET_X86_64 - case MSR_LSTAR: - val = env->lstar; - break; - case MSR_CSTAR: - val = env->cstar; - break; - case MSR_FMASK: - val = env->fmask; - break; - case MSR_FSBASE: - val = env->segs[R_FS].base; - break; - case MSR_GSBASE: - val = env->segs[R_GS].base; - break; - case MSR_KERNELGSBASE: - val = env->kernelgsbase; - break; - case MSR_TSC_AUX: - val = env->tsc_aux; - break; -#endif - case MSR_SMI_COUNT: - val = env->msr_smi_count; - break; - case MSR_MTRRphysBase(0): - case MSR_MTRRphysBase(1): - case MSR_MTRRphysBase(2): - case MSR_MTRRphysBase(3): - case MSR_MTRRphysBase(4): - case MSR_MTRRphysBase(5): - case MSR_MTRRphysBase(6): - case MSR_MTRRphysBase(7): - val = env->mtrr_var[((uint32_t)env->regs[R_ECX] - - MSR_MTRRphysBase(0)) / 2].base; - break; - case MSR_MTRRphysMask(0): - case MSR_MTRRphysMask(1): - case MSR_MTRRphysMask(2): - case MSR_MTRRphysMask(3): - case MSR_MTRRphysMask(4): - case MSR_MTRRphysMask(5): - case MSR_MTRRphysMask(6): - case MSR_MTRRphysMask(7): - val = env->mtrr_var[((uint32_t)env->regs[R_ECX] - - MSR_MTRRphysMask(0)) / 2].mask; - break; - case MSR_MTRRfix64K_00000: - val = env->mtrr_fixed[0]; - break; - case MSR_MTRRfix16K_80000: - case MSR_MTRRfix16K_A0000: - val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - - MSR_MTRRfix16K_80000 + 1]; - break; - case MSR_MTRRfix4K_C0000: - case MSR_MTRRfix4K_C8000: - case MSR_MTRRfix4K_D0000: - case MSR_MTRRfix4K_D8000: - case MSR_MTRRfix4K_E0000: - case MSR_MTRRfix4K_E8000: - case MSR_MTRRfix4K_F0000: - case MSR_MTRRfix4K_F8000: - val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - - MSR_MTRRfix4K_C0000 + 3]; - break; - case MSR_MTRRdefType: - val = env->mtrr_deftype; - break; - case MSR_MTRRcap: - if (env->features[FEAT_1_EDX] & CPUID_MTRR) { - val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | - MSR_MTRRcap_WC_SUPPORTED; - } else { - /* XXX: exception? */ - val = 0; - } - break; - case MSR_MCG_CAP: - val = env->mcg_cap; - break; - case MSR_MCG_CTL: - if (env->mcg_cap & MCG_CTL_P) { - val = env->mcg_ctl; - } else { - val = 0; - } - break; - case MSR_MCG_STATUS: - val = env->mcg_status; - break; - case MSR_IA32_MISC_ENABLE: - val = env->msr_ia32_misc_enable; - break; - case MSR_IA32_BNDCFGS: - val = env->msr_bndcfgs; - break; - case MSR_IA32_UCODE_REV: - val = x86_cpu->ucode_rev; - break; - default: - if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL - && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL + - (4 * env->mcg_cap & 0xff)) { - uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL; - val = env->mce_banks[offset]; - break; - } - /* XXX: exception? */ - val = 0; - break; - } - env->regs[R_EAX] = (uint32_t)(val); - env->regs[R_EDX] = (uint32_t)(val >> 32); -} -#endif - static void do_pause(X86CPU *cpu) { CPUState *cs = CPU(cpu); diff --git a/target/i386/tcg/sysemu/meson.build b/target/i386/tcg/sysemu/meson.build index 1580950141..b2aaab6eef 100644 --- a/target/i386/tcg/sysemu/meson.build +++ b/target/i386/tcg/sysemu/meson.build @@ -3,4 +3,5 @@ i386_softmmu_ss.add(when: ['CONFIG_TCG', 'CONFIG_SOFTMMU'], if_true: files( 'smm_helper.c', 'excp_helper.c', 'bpt_helper.c', + 'misc_helper.c', )) diff --git a/target/i386/tcg/sysemu/misc_helper.c b/target/i386/tcg/sysemu/misc_helper.c new file mode 100644 index 0000000000..66e7939537 --- /dev/null +++ b/target/i386/tcg/sysemu/misc_helper.c @@ -0,0 +1,442 @@ +/* + * x86 misc helpers - sysemu code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/cpu_ldst.h" +#include "exec/address-spaces.h" +#include "tcg/helper-tcg.h" + +void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) +{ + address_space_stb(&address_space_io, port, data, + cpu_get_mem_attrs(env), NULL); +} + +target_ulong helper_inb(CPUX86State *env, uint32_t port) +{ + return address_space_ldub(&address_space_io, port, + cpu_get_mem_attrs(env), NULL); +} + +void helper_outw(CPUX86State *env, uint32_t port, uint32_t data) +{ + address_space_stw(&address_space_io, port, data, + cpu_get_mem_attrs(env), NULL); +} + +target_ulong helper_inw(CPUX86State *env, uint32_t port) +{ + return address_space_lduw(&address_space_io, port, + cpu_get_mem_attrs(env), NULL); +} + +void helper_outl(CPUX86State *env, uint32_t port, uint32_t data) +{ + address_space_stl(&address_space_io, port, data, + cpu_get_mem_attrs(env), NULL); +} + +target_ulong helper_inl(CPUX86State *env, uint32_t port) +{ + return address_space_ldl(&address_space_io, port, + cpu_get_mem_attrs(env), NULL); +} + +target_ulong helper_read_crN(CPUX86State *env, int reg) +{ + target_ulong val; + + cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC()); + switch (reg) { + default: + val = env->cr[reg]; + break; + case 8: + if (!(env->hflags2 & HF2_VINTR_MASK)) { + val = cpu_get_apic_tpr(env_archcpu(env)->apic_state); + } else { + val = env->v_tpr; + } + break; + } + return val; +} + +void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) +{ + cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC()); + switch (reg) { + case 0: + cpu_x86_update_cr0(env, t0); + break; + case 3: + cpu_x86_update_cr3(env, t0); + break; + case 4: + if (((t0 ^ env->cr[4]) & CR4_LA57_MASK) && + (env->hflags & HF_CS64_MASK)) { + raise_exception_ra(env, EXCP0D_GPF, GETPC()); + } + cpu_x86_update_cr4(env, t0); + break; + case 8: + if (!(env->hflags2 & HF2_VINTR_MASK)) { + qemu_mutex_lock_iothread(); + cpu_set_apic_tpr(env_archcpu(env)->apic_state, t0); + qemu_mutex_unlock_iothread(); + } + env->v_tpr = t0 & 0x0f; + break; + default: + env->cr[reg] = t0; + break; + } +} + +void helper_wrmsr(CPUX86State *env) +{ + uint64_t val; + CPUState *cs = env_cpu(env); + + cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC()); + + val = ((uint32_t)env->regs[R_EAX]) | + ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32); + + switch ((uint32_t)env->regs[R_ECX]) { + case MSR_IA32_SYSENTER_CS: + env->sysenter_cs = val & 0xffff; + break; + case MSR_IA32_SYSENTER_ESP: + env->sysenter_esp = val; + break; + case MSR_IA32_SYSENTER_EIP: + env->sysenter_eip = val; + break; + case MSR_IA32_APICBASE: + cpu_set_apic_base(env_archcpu(env)->apic_state, val); + break; + case MSR_EFER: + { + uint64_t update_mask; + + update_mask = 0; + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) { + update_mask |= MSR_EFER_SCE; + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { + update_mask |= MSR_EFER_LME; + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) { + update_mask |= MSR_EFER_FFXSR; + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) { + update_mask |= MSR_EFER_NXE; + } + if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) { + update_mask |= MSR_EFER_SVME; + } + if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) { + update_mask |= MSR_EFER_FFXSR; + } + cpu_load_efer(env, (env->efer & ~update_mask) | + (val & update_mask)); + } + break; + case MSR_STAR: + env->star = val; + break; + case MSR_PAT: + env->pat = val; + break; + case MSR_IA32_PKRS: + if (val & 0xFFFFFFFF00000000ull) { + goto error; + } + env->pkrs = val; + tlb_flush(cs); + break; + case MSR_VM_HSAVE_PA: + env->vm_hsave = val; + break; +#ifdef TARGET_X86_64 + case MSR_LSTAR: + env->lstar = val; + break; + case MSR_CSTAR: + env->cstar = val; + break; + case MSR_FMASK: + env->fmask = val; + break; + case MSR_FSBASE: + env->segs[R_FS].base = val; + break; + case MSR_GSBASE: + env->segs[R_GS].base = val; + break; + case MSR_KERNELGSBASE: + env->kernelgsbase = val; + break; +#endif + case MSR_MTRRphysBase(0): + case MSR_MTRRphysBase(1): + case MSR_MTRRphysBase(2): + case MSR_MTRRphysBase(3): + case MSR_MTRRphysBase(4): + case MSR_MTRRphysBase(5): + case MSR_MTRRphysBase(6): + case MSR_MTRRphysBase(7): + env->mtrr_var[((uint32_t)env->regs[R_ECX] - + MSR_MTRRphysBase(0)) / 2].base = val; + break; + case MSR_MTRRphysMask(0): + case MSR_MTRRphysMask(1): + case MSR_MTRRphysMask(2): + case MSR_MTRRphysMask(3): + case MSR_MTRRphysMask(4): + case MSR_MTRRphysMask(5): + case MSR_MTRRphysMask(6): + case MSR_MTRRphysMask(7): + env->mtrr_var[((uint32_t)env->regs[R_ECX] - + MSR_MTRRphysMask(0)) / 2].mask = val; + break; + case MSR_MTRRfix64K_00000: + env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - + MSR_MTRRfix64K_00000] = val; + break; + case MSR_MTRRfix16K_80000: + case MSR_MTRRfix16K_A0000: + env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - + MSR_MTRRfix16K_80000 + 1] = val; + break; + case MSR_MTRRfix4K_C0000: + case MSR_MTRRfix4K_C8000: + case MSR_MTRRfix4K_D0000: + case MSR_MTRRfix4K_D8000: + case MSR_MTRRfix4K_E0000: + case MSR_MTRRfix4K_E8000: + case MSR_MTRRfix4K_F0000: + case MSR_MTRRfix4K_F8000: + env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - + MSR_MTRRfix4K_C0000 + 3] = val; + break; + case MSR_MTRRdefType: + env->mtrr_deftype = val; + break; + case MSR_MCG_STATUS: + env->mcg_status = val; + break; + case MSR_MCG_CTL: + if ((env->mcg_cap & MCG_CTL_P) + && (val == 0 || val == ~(uint64_t)0)) { + env->mcg_ctl = val; + } + break; + case MSR_TSC_AUX: + env->tsc_aux = val; + break; + case MSR_IA32_MISC_ENABLE: + env->msr_ia32_misc_enable = val; + break; + case MSR_IA32_BNDCFGS: + /* FIXME: #GP if reserved bits are set. */ + /* FIXME: Extend highest implemented bit of linear address. */ + env->msr_bndcfgs = val; + cpu_sync_bndcs_hflags(env); + break; + default: + if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL + && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL + + (4 * env->mcg_cap & 0xff)) { + uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL; + if ((offset & 0x3) != 0 + || (val == 0 || val == ~(uint64_t)0)) { + env->mce_banks[offset] = val; + } + break; + } + /* XXX: exception? */ + break; + } + return; +error: + raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC()); +} + +void helper_rdmsr(CPUX86State *env) +{ + X86CPU *x86_cpu = env_archcpu(env); + uint64_t val; + + cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC()); + + switch ((uint32_t)env->regs[R_ECX]) { + case MSR_IA32_SYSENTER_CS: + val = env->sysenter_cs; + break; + case MSR_IA32_SYSENTER_ESP: + val = env->sysenter_esp; + break; + case MSR_IA32_SYSENTER_EIP: + val = env->sysenter_eip; + break; + case MSR_IA32_APICBASE: + val = cpu_get_apic_base(env_archcpu(env)->apic_state); + break; + case MSR_EFER: + val = env->efer; + break; + case MSR_STAR: + val = env->star; + break; + case MSR_PAT: + val = env->pat; + break; + case MSR_IA32_PKRS: + val = env->pkrs; + break; + case MSR_VM_HSAVE_PA: + val = env->vm_hsave; + break; + case MSR_IA32_PERF_STATUS: + /* tsc_increment_by_tick */ + val = 1000ULL; + /* CPU multiplier */ + val |= (((uint64_t)4ULL) << 40); + break; +#ifdef TARGET_X86_64 + case MSR_LSTAR: + val = env->lstar; + break; + case MSR_CSTAR: + val = env->cstar; + break; + case MSR_FMASK: + val = env->fmask; + break; + case MSR_FSBASE: + val = env->segs[R_FS].base; + break; + case MSR_GSBASE: + val = env->segs[R_GS].base; + break; + case MSR_KERNELGSBASE: + val = env->kernelgsbase; + break; + case MSR_TSC_AUX: + val = env->tsc_aux; + break; +#endif + case MSR_SMI_COUNT: + val = env->msr_smi_count; + break; + case MSR_MTRRphysBase(0): + case MSR_MTRRphysBase(1): + case MSR_MTRRphysBase(2): + case MSR_MTRRphysBase(3): + case MSR_MTRRphysBase(4): + case MSR_MTRRphysBase(5): + case MSR_MTRRphysBase(6): + case MSR_MTRRphysBase(7): + val = env->mtrr_var[((uint32_t)env->regs[R_ECX] - + MSR_MTRRphysBase(0)) / 2].base; + break; + case MSR_MTRRphysMask(0): + case MSR_MTRRphysMask(1): + case MSR_MTRRphysMask(2): + case MSR_MTRRphysMask(3): + case MSR_MTRRphysMask(4): + case MSR_MTRRphysMask(5): + case MSR_MTRRphysMask(6): + case MSR_MTRRphysMask(7): + val = env->mtrr_var[((uint32_t)env->regs[R_ECX] - + MSR_MTRRphysMask(0)) / 2].mask; + break; + case MSR_MTRRfix64K_00000: + val = env->mtrr_fixed[0]; + break; + case MSR_MTRRfix16K_80000: + case MSR_MTRRfix16K_A0000: + val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - + MSR_MTRRfix16K_80000 + 1]; + break; + case MSR_MTRRfix4K_C0000: + case MSR_MTRRfix4K_C8000: + case MSR_MTRRfix4K_D0000: + case MSR_MTRRfix4K_D8000: + case MSR_MTRRfix4K_E0000: + case MSR_MTRRfix4K_E8000: + case MSR_MTRRfix4K_F0000: + case MSR_MTRRfix4K_F8000: + val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] - + MSR_MTRRfix4K_C0000 + 3]; + break; + case MSR_MTRRdefType: + val = env->mtrr_deftype; + break; + case MSR_MTRRcap: + if (env->features[FEAT_1_EDX] & CPUID_MTRR) { + val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | + MSR_MTRRcap_WC_SUPPORTED; + } else { + /* XXX: exception? */ + val = 0; + } + break; + case MSR_MCG_CAP: + val = env->mcg_cap; + break; + case MSR_MCG_CTL: + if (env->mcg_cap & MCG_CTL_P) { + val = env->mcg_ctl; + } else { + val = 0; + } + break; + case MSR_MCG_STATUS: + val = env->mcg_status; + break; + case MSR_IA32_MISC_ENABLE: + val = env->msr_ia32_misc_enable; + break; + case MSR_IA32_BNDCFGS: + val = env->msr_bndcfgs; + break; + case MSR_IA32_UCODE_REV: + val = x86_cpu->ucode_rev; + break; + default: + if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL + && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL + + (4 * env->mcg_cap & 0xff)) { + uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL; + val = env->mce_banks[offset]; + break; + } + /* XXX: exception? */ + val = 0; + break; + } + env->regs[R_EAX] = (uint32_t)(val); + env->regs[R_EDX] = (uint32_t)(val >> 32); +} diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build index e0ef0f02e2..2ab8bd903c 100644 --- a/target/i386/tcg/user/meson.build +++ b/target/i386/tcg/user/meson.build @@ -1,3 +1,4 @@ i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], if_true: files( 'excp_helper.c', + 'misc_stubs.c', )) diff --git a/target/i386/tcg/user/misc_stubs.c b/target/i386/tcg/user/misc_stubs.c new file mode 100644 index 0000000000..84df4e65ff --- /dev/null +++ b/target/i386/tcg/user/misc_stubs.c @@ -0,0 +1,75 @@ +/* + * x86 misc helpers + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" + +void helper_outb(CPUX86State *env, uint32_t port, uint32_t data) +{ + g_assert_not_reached(); +} + +target_ulong helper_inb(CPUX86State *env, uint32_t port) +{ + g_assert_not_reached(); + return 0; +} + +void helper_outw(CPUX86State *env, uint32_t port, uint32_t data) +{ + g_assert_not_reached(); +} + +target_ulong helper_inw(CPUX86State *env, uint32_t port) +{ + g_assert_not_reached(); + return 0; +} + +void helper_outl(CPUX86State *env, uint32_t port, uint32_t data) +{ + g_assert_not_reached(); +} + +target_ulong helper_inl(CPUX86State *env, uint32_t port) +{ + g_assert_not_reached(); + return 0; +} + +target_ulong helper_read_crN(CPUX86State *env, int reg) +{ + g_assert_not_reached(); +} + +void helper_write_crN(CPUX86State *env, int reg, target_ulong t0) +{ + g_assert_not_reached(); +} + +void helper_wrmsr(CPUX86State *env) +{ + g_assert_not_reached(); +} + +void helper_rdmsr(CPUX86State *env) +{ + g_assert_not_reached(); +} From 83a3d9c7402065ca28160e6b524d53ae1eaeba8d Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:51 +0100 Subject: [PATCH 0403/3028] i386: separate fpu_helper sysemu-only parts create a separate tcg/sysemu/fpu_helper.c for the sysemu-only parts. For user mode, some small #ifdefs remain in tcg/fpu_helper.c which do not seem worth splitting into their own user-mode module. Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-16-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 3 ++ target/i386/tcg/fpu_helper.c | 41 +-------------------- target/i386/tcg/sysemu/fpu_helper.c | 57 +++++++++++++++++++++++++++++ target/i386/tcg/sysemu/meson.build | 1 + 4 files changed, 63 insertions(+), 39 deletions(-) create mode 100644 target/i386/tcg/sysemu/fpu_helper.c diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 4776daad23..5aae3ec0f4 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1817,7 +1817,10 @@ int cpu_x86_support_mca_broadcast(CPUX86State *env); int cpu_get_pic_interrupt(CPUX86State *s); /* MSDOS compatibility mode FPU exception support */ void x86_register_ferr_irq(qemu_irq irq); +void fpu_check_raise_ferr_irq(CPUX86State *s); void cpu_set_ignne(void); +void cpu_clear_ignne(void); + /* mpx_helper.c */ void cpu_sync_bndcs_hflags(CPUX86State *env); diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index 20e4d2e715..1b30f1bb73 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -21,17 +21,10 @@ #include #include "cpu.h" #include "exec/helper-proto.h" -#include "qemu/host-utils.h" -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" #include "fpu/softfloat.h" #include "fpu/softfloat-macros.h" #include "helper-tcg.h" -#ifdef CONFIG_SOFTMMU -#include "hw/irq.h" -#endif - /* float macros */ #define FT0 (env->ft0) #define ST0 (env->fpregs[env->fpstt].d) @@ -75,36 +68,6 @@ #define floatx80_ln2_d make_floatx80(0x3ffe, 0xb17217f7d1cf79abLL) #define floatx80_pi_d make_floatx80(0x4000, 0xc90fdaa22168c234LL) -#if !defined(CONFIG_USER_ONLY) -static qemu_irq ferr_irq; - -void x86_register_ferr_irq(qemu_irq irq) -{ - ferr_irq = irq; -} - -static void cpu_clear_ignne(void) -{ - CPUX86State *env = &X86_CPU(first_cpu)->env; - env->hflags2 &= ~HF2_IGNNE_MASK; -} - -void cpu_set_ignne(void) -{ - CPUX86State *env = &X86_CPU(first_cpu)->env; - env->hflags2 |= HF2_IGNNE_MASK; - /* - * We get here in response to a write to port F0h. The chipset should - * deassert FP_IRQ and FERR# instead should stay signaled until FPSW_SE is - * cleared, because FERR# and FP_IRQ are two separate pins on real - * hardware. However, we don't model FERR# as a qemu_irq, so we just - * do directly what the chipset would do, i.e. deassert FP_IRQ. - */ - qemu_irq_lower(ferr_irq); -} -#endif - - static inline void fpush(CPUX86State *env) { env->fpstt = (env->fpstt - 1) & 7; @@ -202,8 +165,8 @@ static void fpu_raise_exception(CPUX86State *env, uintptr_t retaddr) raise_exception_ra(env, EXCP10_COPR, retaddr); } #if !defined(CONFIG_USER_ONLY) - else if (ferr_irq && !(env->hflags2 & HF2_IGNNE_MASK)) { - qemu_irq_raise(ferr_irq); + else { + fpu_check_raise_ferr_irq(env); } #endif } diff --git a/target/i386/tcg/sysemu/fpu_helper.c b/target/i386/tcg/sysemu/fpu_helper.c new file mode 100644 index 0000000000..1c3610da3b --- /dev/null +++ b/target/i386/tcg/sysemu/fpu_helper.c @@ -0,0 +1,57 @@ +/* + * x86 FPU, MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4/PNI helpers (sysemu code) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "hw/irq.h" + +static qemu_irq ferr_irq; + +void x86_register_ferr_irq(qemu_irq irq) +{ + ferr_irq = irq; +} + +void fpu_check_raise_ferr_irq(CPUX86State *env) +{ + if (ferr_irq && !(env->hflags2 & HF2_IGNNE_MASK)) { + qemu_irq_raise(ferr_irq); + return; + } +} + +void cpu_clear_ignne(void) +{ + CPUX86State *env = &X86_CPU(first_cpu)->env; + env->hflags2 &= ~HF2_IGNNE_MASK; +} + +void cpu_set_ignne(void) +{ + CPUX86State *env = &X86_CPU(first_cpu)->env; + env->hflags2 |= HF2_IGNNE_MASK; + /* + * We get here in response to a write to port F0h. The chipset should + * deassert FP_IRQ and FERR# instead should stay signaled until FPSW_SE is + * cleared, because FERR# and FP_IRQ are two separate pins on real + * hardware. However, we don't model FERR# as a qemu_irq, so we just + * do directly what the chipset would do, i.e. deassert FP_IRQ. + */ + qemu_irq_lower(ferr_irq); +} diff --git a/target/i386/tcg/sysemu/meson.build b/target/i386/tcg/sysemu/meson.build index b2aaab6eef..f84519a213 100644 --- a/target/i386/tcg/sysemu/meson.build +++ b/target/i386/tcg/sysemu/meson.build @@ -4,4 +4,5 @@ i386_softmmu_ss.add(when: ['CONFIG_TCG', 'CONFIG_SOFTMMU'], if_true: files( 'excp_helper.c', 'bpt_helper.c', 'misc_helper.c', + 'fpu_helper.c', )) From b39030942dc62a937f5746acf346830d711f4afa Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:52 +0100 Subject: [PATCH 0404/3028] i386: split svm_helper into sysemu and stub-only user For now we just copy over the previous user stubs, but really, everything that requires s->cpl == 0 should be impossible to trigger from user-mode emulation. Later on we should add a check that asserts this easily f.e.: static bool check_cpl0(DisasContext *s) { int cpl = s->cpl; #ifdef CONFIG_USER_ONLY assert(cpl == 3); #endif if (cpl != 0) { gen_exception(s, EXCP0D_GPF, s->pc_start - s->cs_base); return false; } return true; } Signed-off-by: Claudio Fontana Cc: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-17-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/tcg/meson.build | 1 - target/i386/tcg/sysemu/meson.build | 1 + target/i386/tcg/{ => sysemu}/svm_helper.c | 62 +----------------- target/i386/tcg/user/meson.build | 1 + target/i386/tcg/user/svm_stubs.c | 76 +++++++++++++++++++++++ 5 files changed, 80 insertions(+), 61 deletions(-) rename target/i386/tcg/{ => sysemu}/svm_helper.c (96%) create mode 100644 target/i386/tcg/user/svm_stubs.c diff --git a/target/i386/tcg/meson.build b/target/i386/tcg/meson.build index 449d9719ef..f9110e890c 100644 --- a/target/i386/tcg/meson.build +++ b/target/i386/tcg/meson.build @@ -8,7 +8,6 @@ i386_ss.add(when: 'CONFIG_TCG', if_true: files( 'misc_helper.c', 'mpx_helper.c', 'seg_helper.c', - 'svm_helper.c', 'tcg-cpu.c', 'translate.c'), if_false: files('tcg-stub.c')) diff --git a/target/i386/tcg/sysemu/meson.build b/target/i386/tcg/sysemu/meson.build index f84519a213..126528d0c9 100644 --- a/target/i386/tcg/sysemu/meson.build +++ b/target/i386/tcg/sysemu/meson.build @@ -5,4 +5,5 @@ i386_softmmu_ss.add(when: ['CONFIG_TCG', 'CONFIG_SOFTMMU'], if_true: files( 'bpt_helper.c', 'misc_helper.c', 'fpu_helper.c', + 'svm_helper.c', )) diff --git a/target/i386/tcg/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c similarity index 96% rename from target/i386/tcg/svm_helper.c rename to target/i386/tcg/sysemu/svm_helper.c index 0145afceae..d6c2cccda6 100644 --- a/target/i386/tcg/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -1,5 +1,5 @@ /* - * x86 SVM helpers + * x86 SVM helpers (sysemu only) * * Copyright (c) 2003 Fabrice Bellard * @@ -22,66 +22,10 @@ #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" -#include "helper-tcg.h" +#include "tcg/helper-tcg.h" /* Secure Virtual Machine helpers */ -#if defined(CONFIG_USER_ONLY) - -void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) -{ -} - -void helper_vmmcall(CPUX86State *env) -{ -} - -void helper_vmload(CPUX86State *env, int aflag) -{ -} - -void helper_vmsave(CPUX86State *env, int aflag) -{ -} - -void helper_stgi(CPUX86State *env) -{ -} - -void helper_clgi(CPUX86State *env) -{ -} - -void helper_skinit(CPUX86State *env) -{ -} - -void helper_invlpga(CPUX86State *env, int aflag) -{ -} - -void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1, - uintptr_t retaddr) -{ - assert(0); -} - -void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, - uint64_t param) -{ -} - -void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, - uint64_t param, uintptr_t retaddr) -{ -} - -void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, - uint32_t next_eip_addend) -{ -} -#else - static inline void svm_save_seg(CPUX86State *env, hwaddr addr, const SegmentCache *sc) { @@ -796,5 +740,3 @@ void do_vmexit(CPUX86State *env) host's code segment or non-canonical (in the case of long mode), a #GP fault is delivered inside the host. */ } - -#endif diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build index 2ab8bd903c..3edaee7402 100644 --- a/target/i386/tcg/user/meson.build +++ b/target/i386/tcg/user/meson.build @@ -1,4 +1,5 @@ i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], if_true: files( 'excp_helper.c', 'misc_stubs.c', + 'svm_stubs.c', )) diff --git a/target/i386/tcg/user/svm_stubs.c b/target/i386/tcg/user/svm_stubs.c new file mode 100644 index 0000000000..97528b56ad --- /dev/null +++ b/target/i386/tcg/user/svm_stubs.c @@ -0,0 +1,76 @@ +/* + * x86 SVM helpers (user-mode) + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "tcg/helper-tcg.h" + +void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) +{ +} + +void helper_vmmcall(CPUX86State *env) +{ +} + +void helper_vmload(CPUX86State *env, int aflag) +{ +} + +void helper_vmsave(CPUX86State *env, int aflag) +{ +} + +void helper_stgi(CPUX86State *env) +{ +} + +void helper_clgi(CPUX86State *env) +{ +} + +void helper_skinit(CPUX86State *env) +{ +} + +void helper_invlpga(CPUX86State *env, int aflag) +{ +} + +void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1, + uintptr_t retaddr) +{ + assert(0); +} + +void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type, + uint64_t param) +{ +} + +void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type, + uint64_t param, uintptr_t retaddr) +{ +} + +void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param, + uint32_t next_eip_addend) +{ +} From 30493a030ff154fc9ea5f91a848c6ec7a018efa1 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:53 +0100 Subject: [PATCH 0405/3028] i386: split seg_helper into user-only and sysemu parts Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson [claudio]: Rebased on commit 68775856 ("target/i386: svm: do not discard high 32 bits") Signed-off-by: Claudio Fontana Message-Id: <20210322132800.7470-18-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/tcg/helper-tcg.h | 5 + target/i386/tcg/seg_helper.c | 233 +--------------------------- target/i386/tcg/seg_helper.h | 66 ++++++++ target/i386/tcg/sysemu/meson.build | 1 + target/i386/tcg/sysemu/seg_helper.c | 125 +++++++++++++++ target/i386/tcg/user/meson.build | 1 + target/i386/tcg/user/seg_helper.c | 109 +++++++++++++ 7 files changed, 311 insertions(+), 229 deletions(-) create mode 100644 target/i386/tcg/seg_helper.h create mode 100644 target/i386/tcg/sysemu/seg_helper.c create mode 100644 target/i386/tcg/user/seg_helper.c diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index ff2b99886c..97fb7a226a 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -84,6 +84,11 @@ void do_vmexit(CPUX86State *env); /* seg_helper.c */ void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw); +void do_interrupt_all(X86CPU *cpu, int intno, int is_int, + int error_code, target_ulong next_eip, int is_hw); +void handle_even_inj(CPUX86State *env, int intno, int is_int, + int error_code, int is_hw, int rm); +int exception_has_error_code(int intno); /* smm_helper.c */ void do_smm_enter(X86CPU *cpu); diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index b6230ebdf4..cf3f051524 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -26,49 +26,7 @@ #include "exec/cpu_ldst.h" #include "exec/log.h" #include "helper-tcg.h" - -//#define DEBUG_PCALL - -#ifdef DEBUG_PCALL -# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) -# define LOG_PCALL_STATE(cpu) \ - log_cpu_state_mask(CPU_LOG_PCALL, (cpu), CPU_DUMP_CCOP) -#else -# define LOG_PCALL(...) do { } while (0) -# define LOG_PCALL_STATE(cpu) do { } while (0) -#endif - -/* - * TODO: Convert callers to compute cpu_mmu_index_kernel once - * and use *_mmuidx_ra directly. - */ -#define cpu_ldub_kernel_ra(e, p, r) \ - cpu_ldub_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) -#define cpu_lduw_kernel_ra(e, p, r) \ - cpu_lduw_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) -#define cpu_ldl_kernel_ra(e, p, r) \ - cpu_ldl_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) -#define cpu_ldq_kernel_ra(e, p, r) \ - cpu_ldq_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) - -#define cpu_stb_kernel_ra(e, p, v, r) \ - cpu_stb_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) -#define cpu_stw_kernel_ra(e, p, v, r) \ - cpu_stw_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) -#define cpu_stl_kernel_ra(e, p, v, r) \ - cpu_stl_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) -#define cpu_stq_kernel_ra(e, p, v, r) \ - cpu_stq_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) - -#define cpu_ldub_kernel(e, p) cpu_ldub_kernel_ra(e, p, 0) -#define cpu_lduw_kernel(e, p) cpu_lduw_kernel_ra(e, p, 0) -#define cpu_ldl_kernel(e, p) cpu_ldl_kernel_ra(e, p, 0) -#define cpu_ldq_kernel(e, p) cpu_ldq_kernel_ra(e, p, 0) - -#define cpu_stb_kernel(e, p, v) cpu_stb_kernel_ra(e, p, v, 0) -#define cpu_stw_kernel(e, p, v) cpu_stw_kernel_ra(e, p, v, 0) -#define cpu_stl_kernel(e, p, v) cpu_stl_kernel_ra(e, p, v, 0) -#define cpu_stq_kernel(e, p, v) cpu_stq_kernel_ra(e, p, v, 0) +#include "seg_helper.h" /* return non zero if error */ static inline int load_segment_ra(CPUX86State *env, uint32_t *e1_ptr, @@ -531,7 +489,7 @@ static inline unsigned int get_sp_mask(unsigned int e2) } } -static int exception_has_error_code(int intno) +int exception_has_error_code(int intno) { switch (intno) { case 8: @@ -976,72 +934,6 @@ static void do_interrupt64(CPUX86State *env, int intno, int is_int, } #endif -#ifdef TARGET_X86_64 -#if defined(CONFIG_USER_ONLY) -void helper_syscall(CPUX86State *env, int next_eip_addend) -{ - CPUState *cs = env_cpu(env); - - cs->exception_index = EXCP_SYSCALL; - env->exception_is_int = 0; - env->exception_next_eip = env->eip + next_eip_addend; - cpu_loop_exit(cs); -} -#else -void helper_syscall(CPUX86State *env, int next_eip_addend) -{ - int selector; - - if (!(env->efer & MSR_EFER_SCE)) { - raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); - } - selector = (env->star >> 32) & 0xffff; - if (env->hflags & HF_LMA_MASK) { - int code64; - - env->regs[R_ECX] = env->eip + next_eip_addend; - env->regs[11] = cpu_compute_eflags(env) & ~RF_MASK; - - code64 = env->hflags & HF_CS64_MASK; - - env->eflags &= ~(env->fmask | RF_MASK); - cpu_load_eflags(env, env->eflags, 0); - cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | - DESC_L_MASK); - cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_W_MASK | DESC_A_MASK); - if (code64) { - env->eip = env->lstar; - } else { - env->eip = env->cstar; - } - } else { - env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend); - - env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); - cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); - cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, - 0, 0xffffffff, - DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | - DESC_S_MASK | - DESC_W_MASK | DESC_A_MASK); - env->eip = (uint32_t)env->star; - } -} -#endif -#endif - #ifdef TARGET_X86_64 void helper_sysret(CPUX86State *env, int dflag) { @@ -1136,84 +1028,13 @@ static void do_interrupt_real(CPUX86State *env, int intno, int is_int, env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); } -#if defined(CONFIG_USER_ONLY) -/* fake user mode interrupt. is_int is TRUE if coming from the int - * instruction. next_eip is the env->eip value AFTER the interrupt - * instruction. It is only relevant if is_int is TRUE or if intno - * is EXCP_SYSCALL. - */ -static void do_interrupt_user(CPUX86State *env, int intno, int is_int, - int error_code, target_ulong next_eip) -{ - if (is_int) { - SegmentCache *dt; - target_ulong ptr; - int dpl, cpl, shift; - uint32_t e2; - - dt = &env->idt; - if (env->hflags & HF_LMA_MASK) { - shift = 4; - } else { - shift = 3; - } - ptr = dt->base + (intno << shift); - e2 = cpu_ldl_kernel(env, ptr + 4); - - dpl = (e2 >> DESC_DPL_SHIFT) & 3; - cpl = env->hflags & HF_CPL_MASK; - /* check privilege if software int */ - if (dpl < cpl) { - raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2); - } - } - - /* Since we emulate only user space, we cannot do more than - exiting the emulation with the suitable exception and error - code. So update EIP for INT 0x80 and EXCP_SYSCALL. */ - if (is_int || intno == EXCP_SYSCALL) { - env->eip = next_eip; - } -} - -#else - -static void handle_even_inj(CPUX86State *env, int intno, int is_int, - int error_code, int is_hw, int rm) -{ - CPUState *cs = env_cpu(env); - uint32_t event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - control.event_inj)); - - if (!(event_inj & SVM_EVTINJ_VALID)) { - int type; - - if (is_int) { - type = SVM_EVTINJ_TYPE_SOFT; - } else { - type = SVM_EVTINJ_TYPE_EXEPT; - } - event_inj = intno | type | SVM_EVTINJ_VALID; - if (!rm && exception_has_error_code(intno)) { - event_inj |= SVM_EVTINJ_VALID_ERR; - x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, - control.event_inj_err), - error_code); - } - x86_stl_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, control.event_inj), - event_inj); - } -} -#endif - /* * Begin execution of an interruption. is_int is TRUE if coming from * the int instruction. next_eip is the env->eip value AFTER the interrupt * instruction. It is only relevant if is_int is TRUE. */ -static void do_interrupt_all(X86CPU *cpu, int intno, int is_int, - int error_code, target_ulong next_eip, int is_hw) +void do_interrupt_all(X86CPU *cpu, int intno, int is_int, + int error_code, target_ulong next_eip, int is_hw) { CPUX86State *env = &cpu->env; @@ -1289,36 +1110,6 @@ static void do_interrupt_all(X86CPU *cpu, int intno, int is_int, #endif } -void x86_cpu_do_interrupt(CPUState *cs) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - -#if defined(CONFIG_USER_ONLY) - /* if user mode only, we simulate a fake exception - which will be handled outside the cpu execution - loop */ - do_interrupt_user(env, cs->exception_index, - env->exception_is_int, - env->error_code, - env->exception_next_eip); - /* successfully delivered */ - env->old_exception = -1; -#else - if (cs->exception_index == EXCP_VMEXIT) { - assert(env->old_exception == -1); - do_vmexit(env); - } else { - do_interrupt_all(cpu, cs->exception_index, - env->exception_is_int, - env->error_code, - env->exception_next_eip, 0); - /* successfully delivered */ - env->old_exception = -1; - } -#endif -} - void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw) { do_interrupt_all(env_archcpu(env), intno, 0, 0, 0, is_hw); @@ -2626,22 +2417,6 @@ void helper_verw(CPUX86State *env, target_ulong selector1) CC_SRC = eflags | CC_Z; } -#if defined(CONFIG_USER_ONLY) -void cpu_x86_load_seg(CPUX86State *env, X86Seg seg_reg, int selector) -{ - if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { - int dpl = (env->eflags & VM_MASK) ? 3 : 0; - selector &= 0xffff; - cpu_x86_load_seg_cache(env, seg_reg, selector, - (selector << 4), 0xffff, - DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | - DESC_A_MASK | (dpl << DESC_DPL_SHIFT)); - } else { - helper_load_seg(env, seg_reg, selector); - } -} -#endif - /* check if Port I/O is allowed in TSS */ static inline void check_io(CPUX86State *env, int addr, int size, uintptr_t retaddr) diff --git a/target/i386/tcg/seg_helper.h b/target/i386/tcg/seg_helper.h new file mode 100644 index 0000000000..ebf1035277 --- /dev/null +++ b/target/i386/tcg/seg_helper.h @@ -0,0 +1,66 @@ +/* + * x86 segmentation related helpers macros + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef SEG_HELPER_H +#define SEG_HELPER_H + +//#define DEBUG_PCALL + +#ifdef DEBUG_PCALL +# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) +# define LOG_PCALL_STATE(cpu) \ + log_cpu_state_mask(CPU_LOG_PCALL, (cpu), CPU_DUMP_CCOP) +#else +# define LOG_PCALL(...) do { } while (0) +# define LOG_PCALL_STATE(cpu) do { } while (0) +#endif + +/* + * TODO: Convert callers to compute cpu_mmu_index_kernel once + * and use *_mmuidx_ra directly. + */ +#define cpu_ldub_kernel_ra(e, p, r) \ + cpu_ldub_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) +#define cpu_lduw_kernel_ra(e, p, r) \ + cpu_lduw_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) +#define cpu_ldl_kernel_ra(e, p, r) \ + cpu_ldl_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) +#define cpu_ldq_kernel_ra(e, p, r) \ + cpu_ldq_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) + +#define cpu_stb_kernel_ra(e, p, v, r) \ + cpu_stb_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) +#define cpu_stw_kernel_ra(e, p, v, r) \ + cpu_stw_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) +#define cpu_stl_kernel_ra(e, p, v, r) \ + cpu_stl_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) +#define cpu_stq_kernel_ra(e, p, v, r) \ + cpu_stq_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) + +#define cpu_ldub_kernel(e, p) cpu_ldub_kernel_ra(e, p, 0) +#define cpu_lduw_kernel(e, p) cpu_lduw_kernel_ra(e, p, 0) +#define cpu_ldl_kernel(e, p) cpu_ldl_kernel_ra(e, p, 0) +#define cpu_ldq_kernel(e, p) cpu_ldq_kernel_ra(e, p, 0) + +#define cpu_stb_kernel(e, p, v) cpu_stb_kernel_ra(e, p, v, 0) +#define cpu_stw_kernel(e, p, v) cpu_stw_kernel_ra(e, p, v, 0) +#define cpu_stl_kernel(e, p, v) cpu_stl_kernel_ra(e, p, v, 0) +#define cpu_stq_kernel(e, p, v) cpu_stq_kernel_ra(e, p, v, 0) + +#endif /* SEG_HELPER_H */ diff --git a/target/i386/tcg/sysemu/meson.build b/target/i386/tcg/sysemu/meson.build index 126528d0c9..2e444e766a 100644 --- a/target/i386/tcg/sysemu/meson.build +++ b/target/i386/tcg/sysemu/meson.build @@ -6,4 +6,5 @@ i386_softmmu_ss.add(when: ['CONFIG_TCG', 'CONFIG_SOFTMMU'], if_true: files( 'misc_helper.c', 'fpu_helper.c', 'svm_helper.c', + 'seg_helper.c', )) diff --git a/target/i386/tcg/sysemu/seg_helper.c b/target/i386/tcg/sysemu/seg_helper.c new file mode 100644 index 0000000000..e0d7b32b82 --- /dev/null +++ b/target/i386/tcg/sysemu/seg_helper.c @@ -0,0 +1,125 @@ +/* + * x86 segmentation related helpers: (sysemu-only code) + * TSS, interrupts, system calls, jumps and call/task gates, descriptors + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/cpu_ldst.h" +#include "tcg/helper-tcg.h" + +#ifdef TARGET_X86_64 +void helper_syscall(CPUX86State *env, int next_eip_addend) +{ + int selector; + + if (!(env->efer & MSR_EFER_SCE)) { + raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC()); + } + selector = (env->star >> 32) & 0xffff; + if (env->hflags & HF_LMA_MASK) { + int code64; + + env->regs[R_ECX] = env->eip + next_eip_addend; + env->regs[11] = cpu_compute_eflags(env) & ~RF_MASK; + + code64 = env->hflags & HF_CS64_MASK; + + env->eflags &= ~(env->fmask | RF_MASK); + cpu_load_eflags(env, env->eflags, 0); + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | + DESC_L_MASK); + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + if (code64) { + env->eip = env->lstar; + } else { + env->eip = env->cstar; + } + } else { + env->regs[R_ECX] = (uint32_t)(env->eip + next_eip_addend); + + env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK); + cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, + 0, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + env->eip = (uint32_t)env->star; + } +} +#endif /* TARGET_X86_64 */ + +void handle_even_inj(CPUX86State *env, int intno, int is_int, + int error_code, int is_hw, int rm) +{ + CPUState *cs = env_cpu(env); + uint32_t event_inj = x86_ldl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, + control.event_inj)); + + if (!(event_inj & SVM_EVTINJ_VALID)) { + int type; + + if (is_int) { + type = SVM_EVTINJ_TYPE_SOFT; + } else { + type = SVM_EVTINJ_TYPE_EXEPT; + } + event_inj = intno | type | SVM_EVTINJ_VALID; + if (!rm && exception_has_error_code(intno)) { + event_inj |= SVM_EVTINJ_VALID_ERR; + x86_stl_phys(cs, env->vm_vmcb + offsetof(struct vmcb, + control.event_inj_err), + error_code); + } + x86_stl_phys(cs, + env->vm_vmcb + offsetof(struct vmcb, control.event_inj), + event_inj); + } +} + +void x86_cpu_do_interrupt(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + if (cs->exception_index == EXCP_VMEXIT) { + assert(env->old_exception == -1); + do_vmexit(env); + } else { + do_interrupt_all(cpu, cs->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip, 0); + /* successfully delivered */ + env->old_exception = -1; + } +} diff --git a/target/i386/tcg/user/meson.build b/target/i386/tcg/user/meson.build index 3edaee7402..9eac0e69ca 100644 --- a/target/i386/tcg/user/meson.build +++ b/target/i386/tcg/user/meson.build @@ -2,4 +2,5 @@ i386_user_ss.add(when: ['CONFIG_TCG', 'CONFIG_USER_ONLY'], if_true: files( 'excp_helper.c', 'misc_stubs.c', 'svm_stubs.c', + 'seg_helper.c', )) diff --git a/target/i386/tcg/user/seg_helper.c b/target/i386/tcg/user/seg_helper.c new file mode 100644 index 0000000000..67481b0aa8 --- /dev/null +++ b/target/i386/tcg/user/seg_helper.c @@ -0,0 +1,109 @@ +/* + * x86 segmentation related helpers (user-mode code): + * TSS, interrupts, system calls, jumps and call/task gates, descriptors + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "tcg/helper-tcg.h" +#include "tcg/seg_helper.h" + +#ifdef TARGET_X86_64 +void helper_syscall(CPUX86State *env, int next_eip_addend) +{ + CPUState *cs = env_cpu(env); + + cs->exception_index = EXCP_SYSCALL; + env->exception_is_int = 0; + env->exception_next_eip = env->eip + next_eip_addend; + cpu_loop_exit(cs); +} +#endif /* TARGET_X86_64 */ + +/* + * fake user mode interrupt. is_int is TRUE if coming from the int + * instruction. next_eip is the env->eip value AFTER the interrupt + * instruction. It is only relevant if is_int is TRUE or if intno + * is EXCP_SYSCALL. + */ +static void do_interrupt_user(CPUX86State *env, int intno, int is_int, + int error_code, target_ulong next_eip) +{ + if (is_int) { + SegmentCache *dt; + target_ulong ptr; + int dpl, cpl, shift; + uint32_t e2; + + dt = &env->idt; + if (env->hflags & HF_LMA_MASK) { + shift = 4; + } else { + shift = 3; + } + ptr = dt->base + (intno << shift); + e2 = cpu_ldl_kernel(env, ptr + 4); + + dpl = (e2 >> DESC_DPL_SHIFT) & 3; + cpl = env->hflags & HF_CPL_MASK; + /* check privilege if software int */ + if (dpl < cpl) { + raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2); + } + } + + /* Since we emulate only user space, we cannot do more than + exiting the emulation with the suitable exception and error + code. So update EIP for INT 0x80 and EXCP_SYSCALL. */ + if (is_int || intno == EXCP_SYSCALL) { + env->eip = next_eip; + } +} + +void x86_cpu_do_interrupt(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + + /* if user mode only, we simulate a fake exception + which will be handled outside the cpu execution + loop */ + do_interrupt_user(env, cs->exception_index, + env->exception_is_int, + env->error_code, + env->exception_next_eip); + /* successfully delivered */ + env->old_exception = -1; +} + +void cpu_x86_load_seg(CPUX86State *env, X86Seg seg_reg, int selector) +{ + if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { + int dpl = (env->eflags & VM_MASK) ? 3 : 0; + selector &= 0xffff; + cpu_x86_load_seg_cache(env, seg_reg, selector, + (selector << 4), 0xffff, + DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | + DESC_A_MASK | (dpl << DESC_DPL_SHIFT)); + } else { + helper_load_seg(env, seg_reg, selector); + } +} From 79f1a68ab3a85d90a2fc0b1e166200ba9ea45670 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:54 +0100 Subject: [PATCH 0406/3028] i386: split off sysemu part of cpu.c Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-19-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/cpu-internal.h | 70 +++++++ target/i386/cpu-sysemu.c | 352 +++++++++++++++++++++++++++++++++ target/i386/cpu.c | 385 +------------------------------------ target/i386/meson.build | 1 + 4 files changed, 429 insertions(+), 379 deletions(-) create mode 100644 target/i386/cpu-internal.h create mode 100644 target/i386/cpu-sysemu.c diff --git a/target/i386/cpu-internal.h b/target/i386/cpu-internal.h new file mode 100644 index 0000000000..9baac5c0b4 --- /dev/null +++ b/target/i386/cpu-internal.h @@ -0,0 +1,70 @@ +/* + * i386 CPU internal definitions to be shared between cpu.c and cpu-sysemu.c + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef I386_CPU_INTERNAL_H +#define I386_CPU_INTERNAL_H + +typedef enum FeatureWordType { + CPUID_FEATURE_WORD, + MSR_FEATURE_WORD, +} FeatureWordType; + +typedef struct FeatureWordInfo { + FeatureWordType type; + /* feature flags names are taken from "Intel Processor Identification and + * the CPUID Instruction" and AMD's "CPUID Specification". + * In cases of disagreement between feature naming conventions, + * aliases may be added. + */ + const char *feat_names[64]; + union { + /* If type==CPUID_FEATURE_WORD */ + struct { + uint32_t eax; /* Input EAX for CPUID */ + bool needs_ecx; /* CPUID instruction uses ECX as input */ + uint32_t ecx; /* Input ECX value for CPUID */ + int reg; /* output register (R_* constant) */ + } cpuid; + /* If type==MSR_FEATURE_WORD */ + struct { + uint32_t index; + } msr; + }; + uint64_t tcg_features; /* Feature flags supported by TCG */ + uint64_t unmigratable_flags; /* Feature flags known to be unmigratable */ + uint64_t migratable_flags; /* Feature flags known to be migratable */ + /* Features that shouldn't be auto-enabled by "-cpu host" */ + uint64_t no_autoenable_flags; +} FeatureWordInfo; + +extern FeatureWordInfo feature_word_info[]; + +void x86_cpu_expand_features(X86CPU *cpu, Error **errp); + +#ifndef CONFIG_USER_ONLY +GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs); +void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, + const char *name, void *opaque, Error **errp); + +void x86_cpu_apic_create(X86CPU *cpu, Error **errp); +void x86_cpu_apic_realize(X86CPU *cpu, Error **errp); +void x86_cpu_machine_reset_cb(void *opaque); +#endif /* !CONFIG_USER_ONLY */ + +#endif /* I386_CPU_INTERNAL_H */ diff --git a/target/i386/cpu-sysemu.c b/target/i386/cpu-sysemu.c new file mode 100644 index 0000000000..6477584313 --- /dev/null +++ b/target/i386/cpu-sysemu.c @@ -0,0 +1,352 @@ +/* + * i386 CPUID, CPU class, definitions, models: sysemu-only code + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "sysemu/xen.h" +#include "sysemu/whpx.h" +#include "kvm/kvm_i386.h" +#include "qapi/error.h" +#include "qapi/qapi-visit-run-state.h" +#include "qapi/qmp/qdict.h" +#include "qom/qom-qobject.h" +#include "qapi/qapi-commands-machine-target.h" +#include "hw/qdev-properties.h" + +#include "exec/address-spaces.h" +#include "hw/i386/apic_internal.h" + +#include "cpu-internal.h" + +/* Return a QDict containing keys for all properties that can be included + * in static expansion of CPU models. All properties set by x86_cpu_load_model() + * must be included in the dictionary. + */ +static QDict *x86_cpu_static_props(void) +{ + FeatureWord w; + int i; + static const char *props[] = { + "min-level", + "min-xlevel", + "family", + "model", + "stepping", + "model-id", + "vendor", + "lmce", + NULL, + }; + static QDict *d; + + if (d) { + return d; + } + + d = qdict_new(); + for (i = 0; props[i]; i++) { + qdict_put_null(d, props[i]); + } + + for (w = 0; w < FEATURE_WORDS; w++) { + FeatureWordInfo *fi = &feature_word_info[w]; + int bit; + for (bit = 0; bit < 64; bit++) { + if (!fi->feat_names[bit]) { + continue; + } + qdict_put_null(d, fi->feat_names[bit]); + } + } + + return d; +} + +/* Add an entry to @props dict, with the value for property. */ +static void x86_cpu_expand_prop(X86CPU *cpu, QDict *props, const char *prop) +{ + QObject *value = object_property_get_qobject(OBJECT(cpu), prop, + &error_abort); + + qdict_put_obj(props, prop, value); +} + +/* Convert CPU model data from X86CPU object to a property dictionary + * that can recreate exactly the same CPU model. + */ +static void x86_cpu_to_dict(X86CPU *cpu, QDict *props) +{ + QDict *sprops = x86_cpu_static_props(); + const QDictEntry *e; + + for (e = qdict_first(sprops); e; e = qdict_next(sprops, e)) { + const char *prop = qdict_entry_key(e); + x86_cpu_expand_prop(cpu, props, prop); + } +} + +/* Convert CPU model data from X86CPU object to a property dictionary + * that can recreate exactly the same CPU model, including every + * writeable QOM property. + */ +static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props) +{ + ObjectPropertyIterator iter; + ObjectProperty *prop; + + object_property_iter_init(&iter, OBJECT(cpu)); + while ((prop = object_property_iter_next(&iter))) { + /* skip read-only or write-only properties */ + if (!prop->get || !prop->set) { + continue; + } + + /* "hotplugged" is the only property that is configurable + * on the command-line but will be set differently on CPUs + * created using "-cpu ... -smp ..." and by CPUs created + * on the fly by x86_cpu_from_model() for querying. Skip it. + */ + if (!strcmp(prop->name, "hotplugged")) { + continue; + } + x86_cpu_expand_prop(cpu, props, prop->name); + } +} + +static void object_apply_props(Object *obj, QDict *props, Error **errp) +{ + const QDictEntry *prop; + + for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) { + if (!object_property_set_qobject(obj, qdict_entry_key(prop), + qdict_entry_value(prop), errp)) { + break; + } + } +} + +/* Create X86CPU object according to model+props specification */ +static X86CPU *x86_cpu_from_model(const char *model, QDict *props, Error **errp) +{ + X86CPU *xc = NULL; + X86CPUClass *xcc; + Error *err = NULL; + + xcc = X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU, model)); + if (xcc == NULL) { + error_setg(&err, "CPU model '%s' not found", model); + goto out; + } + + xc = X86_CPU(object_new_with_class(OBJECT_CLASS(xcc))); + if (props) { + object_apply_props(OBJECT(xc), props, &err); + if (err) { + goto out; + } + } + + x86_cpu_expand_features(xc, &err); + if (err) { + goto out; + } + +out: + if (err) { + error_propagate(errp, err); + object_unref(OBJECT(xc)); + xc = NULL; + } + return xc; +} + +CpuModelExpansionInfo * +qmp_query_cpu_model_expansion(CpuModelExpansionType type, + CpuModelInfo *model, + Error **errp) +{ + X86CPU *xc = NULL; + Error *err = NULL; + CpuModelExpansionInfo *ret = g_new0(CpuModelExpansionInfo, 1); + QDict *props = NULL; + const char *base_name; + + xc = x86_cpu_from_model(model->name, + model->has_props ? + qobject_to(QDict, model->props) : + NULL, &err); + if (err) { + goto out; + } + + props = qdict_new(); + ret->model = g_new0(CpuModelInfo, 1); + ret->model->props = QOBJECT(props); + ret->model->has_props = true; + + switch (type) { + case CPU_MODEL_EXPANSION_TYPE_STATIC: + /* Static expansion will be based on "base" only */ + base_name = "base"; + x86_cpu_to_dict(xc, props); + break; + case CPU_MODEL_EXPANSION_TYPE_FULL: + /* As we don't return every single property, full expansion needs + * to keep the original model name+props, and add extra + * properties on top of that. + */ + base_name = model->name; + x86_cpu_to_dict_full(xc, props); + break; + default: + error_setg(&err, "Unsupported expansion type"); + goto out; + } + + x86_cpu_to_dict(xc, props); + + ret->model->name = g_strdup(base_name); + +out: + object_unref(OBJECT(xc)); + if (err) { + error_propagate(errp, err); + qapi_free_CpuModelExpansionInfo(ret); + ret = NULL; + } + return ret; +} + +void cpu_clear_apic_feature(CPUX86State *env) +{ + env->features[FEAT_1_EDX] &= ~CPUID_APIC; +} + +bool cpu_is_bsp(X86CPU *cpu) +{ + return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP; +} + +/* TODO: remove me, when reset over QOM tree is implemented */ +void x86_cpu_machine_reset_cb(void *opaque) +{ + X86CPU *cpu = opaque; + cpu_reset(CPU(cpu)); +} + +APICCommonClass *apic_get_class(void) +{ + const char *apic_type = "apic"; + + /* TODO: in-kernel irqchip for hvf */ + if (kvm_apic_in_kernel()) { + apic_type = "kvm-apic"; + } else if (xen_enabled()) { + apic_type = "xen-apic"; + } else if (whpx_apic_in_platform()) { + apic_type = "whpx-apic"; + } + + return APIC_COMMON_CLASS(object_class_by_name(apic_type)); +} + +void x86_cpu_apic_create(X86CPU *cpu, Error **errp) +{ + APICCommonState *apic; + ObjectClass *apic_class = OBJECT_CLASS(apic_get_class()); + + cpu->apic_state = DEVICE(object_new_with_class(apic_class)); + + object_property_add_child(OBJECT(cpu), "lapic", + OBJECT(cpu->apic_state)); + object_unref(OBJECT(cpu->apic_state)); + + qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id); + /* TODO: convert to link<> */ + apic = APIC_COMMON(cpu->apic_state); + apic->cpu = cpu; + apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE; +} + +void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) +{ + APICCommonState *apic; + static bool apic_mmio_map_once; + + if (cpu->apic_state == NULL) { + return; + } + qdev_realize(DEVICE(cpu->apic_state), NULL, errp); + + /* Map APIC MMIO area */ + apic = APIC_COMMON(cpu->apic_state); + if (!apic_mmio_map_once) { + memory_region_add_subregion_overlap(get_system_memory(), + apic->apicbase & + MSR_IA32_APICBASE_BASE, + &apic->io_memory, + 0x1000); + apic_mmio_map_once = true; + } +} + +GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + GuestPanicInformation *panic_info = NULL; + + if (env->features[FEAT_HYPERV_EDX] & HV_GUEST_CRASH_MSR_AVAILABLE) { + panic_info = g_malloc0(sizeof(GuestPanicInformation)); + + panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V; + + assert(HV_CRASH_PARAMS >= 5); + panic_info->u.hyper_v.arg1 = env->msr_hv_crash_params[0]; + panic_info->u.hyper_v.arg2 = env->msr_hv_crash_params[1]; + panic_info->u.hyper_v.arg3 = env->msr_hv_crash_params[2]; + panic_info->u.hyper_v.arg4 = env->msr_hv_crash_params[3]; + panic_info->u.hyper_v.arg5 = env->msr_hv_crash_params[4]; + } + + return panic_info; +} +void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + CPUState *cs = CPU(obj); + GuestPanicInformation *panic_info; + + if (!cs->crash_occurred) { + error_setg(errp, "No crash occured"); + return; + } + + panic_info = x86_cpu_get_crash_info(cs); + if (panic_info == NULL) { + error_setg(errp, "No crash information"); + return; + } + + visit_type_GuestPanicInformation(v, "crash-information", &panic_info, + errp); + qapi_free_GuestPanicInformation(panic_info); +} + diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 010db23379..c496bfa1c2 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1,5 +1,5 @@ /* - * i386 CPUID helper functions + * i386 CPUID, CPU class, definitions, models * * Copyright (c) 2003 Fabrice Bellard * @@ -20,35 +20,26 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qemu/cutils.h" -#include "qemu/bitops.h" #include "qemu/qemu-print.h" #include "cpu.h" #include "tcg/helper-tcg.h" -#include "exec/exec-all.h" -#include "sysemu/kvm.h" #include "sysemu/reset.h" #include "sysemu/hvf.h" -#include "sysemu/xen.h" -#include "sysemu/whpx.h" #include "kvm/kvm_i386.h" #include "sev_i386.h" -#include "qemu/module.h" #include "qapi/qapi-visit-machine.h" -#include "qapi/qapi-visit-run-state.h" -#include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" -#include "qom/qom-qobject.h" #include "qapi/qapi-commands-machine-target.h" #include "standard-headers/asm-x86/kvm_para.h" #include "hw/qdev-properties.h" #include "hw/i386/topology.h" #ifndef CONFIG_USER_ONLY #include "exec/address-spaces.h" -#include "hw/i386/apic_internal.h" #include "hw/boards.h" #endif #include "disas/capstone.h" +#include "cpu-internal.h" /* Helpers for building CPUID[2] descriptors: */ @@ -663,40 +654,7 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_XSAVE_XSAVEC, CPUID_XSAVE_XSAVES */ #define TCG_14_0_ECX_FEATURES 0 -typedef enum FeatureWordType { - CPUID_FEATURE_WORD, - MSR_FEATURE_WORD, -} FeatureWordType; - -typedef struct FeatureWordInfo { - FeatureWordType type; - /* feature flags names are taken from "Intel Processor Identification and - * the CPUID Instruction" and AMD's "CPUID Specification". - * In cases of disagreement between feature naming conventions, - * aliases may be added. - */ - const char *feat_names[64]; - union { - /* If type==CPUID_FEATURE_WORD */ - struct { - uint32_t eax; /* Input EAX for CPUID */ - bool needs_ecx; /* CPUID instruction uses ECX as input */ - uint32_t ecx; /* Input ECX value for CPUID */ - int reg; /* output register (R_* constant) */ - } cpuid; - /* If type==MSR_FEATURE_WORD */ - struct { - uint32_t index; - } msr; - }; - uint64_t tcg_features; /* Feature flags supported by TCG */ - uint64_t unmigratable_flags; /* Feature flags known to be unmigratable */ - uint64_t migratable_flags; /* Feature flags known to be migratable */ - /* Features that shouldn't be auto-enabled by "-cpu host" */ - uint64_t no_autoenable_flags; -} FeatureWordInfo; - -static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { +FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_1_EDX] = { .type = CPUID_FEATURE_WORD, .feat_names = { @@ -4750,7 +4708,6 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features, } } -static void x86_cpu_expand_features(X86CPU *cpu, Error **errp); static void x86_cpu_filter_features(X86CPU *cpu, bool verbose); /* Build a list with the name of all features on a feature word array */ @@ -5120,207 +5077,6 @@ static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model) memset(&env->user_features, 0, sizeof(env->user_features)); } -#ifndef CONFIG_USER_ONLY -/* Return a QDict containing keys for all properties that can be included - * in static expansion of CPU models. All properties set by x86_cpu_load_model() - * must be included in the dictionary. - */ -static QDict *x86_cpu_static_props(void) -{ - FeatureWord w; - int i; - static const char *props[] = { - "min-level", - "min-xlevel", - "family", - "model", - "stepping", - "model-id", - "vendor", - "lmce", - NULL, - }; - static QDict *d; - - if (d) { - return d; - } - - d = qdict_new(); - for (i = 0; props[i]; i++) { - qdict_put_null(d, props[i]); - } - - for (w = 0; w < FEATURE_WORDS; w++) { - FeatureWordInfo *fi = &feature_word_info[w]; - int bit; - for (bit = 0; bit < 64; bit++) { - if (!fi->feat_names[bit]) { - continue; - } - qdict_put_null(d, fi->feat_names[bit]); - } - } - - return d; -} - -/* Add an entry to @props dict, with the value for property. */ -static void x86_cpu_expand_prop(X86CPU *cpu, QDict *props, const char *prop) -{ - QObject *value = object_property_get_qobject(OBJECT(cpu), prop, - &error_abort); - - qdict_put_obj(props, prop, value); -} - -/* Convert CPU model data from X86CPU object to a property dictionary - * that can recreate exactly the same CPU model. - */ -static void x86_cpu_to_dict(X86CPU *cpu, QDict *props) -{ - QDict *sprops = x86_cpu_static_props(); - const QDictEntry *e; - - for (e = qdict_first(sprops); e; e = qdict_next(sprops, e)) { - const char *prop = qdict_entry_key(e); - x86_cpu_expand_prop(cpu, props, prop); - } -} - -/* Convert CPU model data from X86CPU object to a property dictionary - * that can recreate exactly the same CPU model, including every - * writeable QOM property. - */ -static void x86_cpu_to_dict_full(X86CPU *cpu, QDict *props) -{ - ObjectPropertyIterator iter; - ObjectProperty *prop; - - object_property_iter_init(&iter, OBJECT(cpu)); - while ((prop = object_property_iter_next(&iter))) { - /* skip read-only or write-only properties */ - if (!prop->get || !prop->set) { - continue; - } - - /* "hotplugged" is the only property that is configurable - * on the command-line but will be set differently on CPUs - * created using "-cpu ... -smp ..." and by CPUs created - * on the fly by x86_cpu_from_model() for querying. Skip it. - */ - if (!strcmp(prop->name, "hotplugged")) { - continue; - } - x86_cpu_expand_prop(cpu, props, prop->name); - } -} - -static void object_apply_props(Object *obj, QDict *props, Error **errp) -{ - const QDictEntry *prop; - - for (prop = qdict_first(props); prop; prop = qdict_next(props, prop)) { - if (!object_property_set_qobject(obj, qdict_entry_key(prop), - qdict_entry_value(prop), errp)) { - break; - } - } -} - -/* Create X86CPU object according to model+props specification */ -static X86CPU *x86_cpu_from_model(const char *model, QDict *props, Error **errp) -{ - X86CPU *xc = NULL; - X86CPUClass *xcc; - Error *err = NULL; - - xcc = X86_CPU_CLASS(cpu_class_by_name(TYPE_X86_CPU, model)); - if (xcc == NULL) { - error_setg(&err, "CPU model '%s' not found", model); - goto out; - } - - xc = X86_CPU(object_new_with_class(OBJECT_CLASS(xcc))); - if (props) { - object_apply_props(OBJECT(xc), props, &err); - if (err) { - goto out; - } - } - - x86_cpu_expand_features(xc, &err); - if (err) { - goto out; - } - -out: - if (err) { - error_propagate(errp, err); - object_unref(OBJECT(xc)); - xc = NULL; - } - return xc; -} - -CpuModelExpansionInfo * -qmp_query_cpu_model_expansion(CpuModelExpansionType type, - CpuModelInfo *model, - Error **errp) -{ - X86CPU *xc = NULL; - Error *err = NULL; - CpuModelExpansionInfo *ret = g_new0(CpuModelExpansionInfo, 1); - QDict *props = NULL; - const char *base_name; - - xc = x86_cpu_from_model(model->name, - model->has_props ? - qobject_to(QDict, model->props) : - NULL, &err); - if (err) { - goto out; - } - - props = qdict_new(); - ret->model = g_new0(CpuModelInfo, 1); - ret->model->props = QOBJECT(props); - ret->model->has_props = true; - - switch (type) { - case CPU_MODEL_EXPANSION_TYPE_STATIC: - /* Static expansion will be based on "base" only */ - base_name = "base"; - x86_cpu_to_dict(xc, props); - break; - case CPU_MODEL_EXPANSION_TYPE_FULL: - /* As we don't return every single property, full expansion needs - * to keep the original model name+props, and add extra - * properties on top of that. - */ - base_name = model->name; - x86_cpu_to_dict_full(xc, props); - break; - default: - error_setg(&err, "Unsupported expansion type"); - goto out; - } - - x86_cpu_to_dict(xc, props); - - ret->model->name = g_strdup(base_name); - -out: - object_unref(OBJECT(xc)); - if (err) { - error_propagate(errp, err); - qapi_free_CpuModelExpansionInfo(ret); - ret = NULL; - } - return ret; -} -#endif /* !CONFIG_USER_ONLY */ - static gchar *x86_gdb_arch_name(CPUState *cs) { #ifdef TARGET_X86_64 @@ -5395,15 +5151,6 @@ static void x86_register_cpudef_types(X86CPUDefinition *def) } -#if !defined(CONFIG_USER_ONLY) - -void cpu_clear_apic_feature(CPUX86State *env) -{ - env->features[FEAT_1_EDX] &= ~CPUID_APIC; -} - -#endif /* !CONFIG_USER_ONLY */ - void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) @@ -6052,20 +5799,6 @@ static void x86_cpu_reset(DeviceState *dev) #endif } -#ifndef CONFIG_USER_ONLY -bool cpu_is_bsp(X86CPU *cpu) -{ - return cpu_get_apic_base(cpu->apic_state) & MSR_IA32_APICBASE_BSP; -} - -/* TODO: remove me, when reset over QOM tree is implemented */ -static void x86_cpu_machine_reset_cb(void *opaque) -{ - X86CPU *cpu = opaque; - cpu_reset(CPU(cpu)); -} -#endif - static void mce_init(X86CPU *cpu) { CPUX86State *cenv = &cpu->env; @@ -6083,68 +5816,6 @@ static void mce_init(X86CPU *cpu) } } -#ifndef CONFIG_USER_ONLY -APICCommonClass *apic_get_class(void) -{ - const char *apic_type = "apic"; - - /* TODO: in-kernel irqchip for hvf */ - if (kvm_apic_in_kernel()) { - apic_type = "kvm-apic"; - } else if (xen_enabled()) { - apic_type = "xen-apic"; - } else if (whpx_apic_in_platform()) { - apic_type = "whpx-apic"; - } - - return APIC_COMMON_CLASS(object_class_by_name(apic_type)); -} - -static void x86_cpu_apic_create(X86CPU *cpu, Error **errp) -{ - APICCommonState *apic; - ObjectClass *apic_class = OBJECT_CLASS(apic_get_class()); - - cpu->apic_state = DEVICE(object_new_with_class(apic_class)); - - object_property_add_child(OBJECT(cpu), "lapic", - OBJECT(cpu->apic_state)); - object_unref(OBJECT(cpu->apic_state)); - - qdev_prop_set_uint32(cpu->apic_state, "id", cpu->apic_id); - /* TODO: convert to link<> */ - apic = APIC_COMMON(cpu->apic_state); - apic->cpu = cpu; - apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE; -} - -static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) -{ - APICCommonState *apic; - static bool apic_mmio_map_once; - - if (cpu->apic_state == NULL) { - return; - } - qdev_realize(DEVICE(cpu->apic_state), NULL, errp); - - /* Map APIC MMIO area */ - apic = APIC_COMMON(cpu->apic_state); - if (!apic_mmio_map_once) { - memory_region_add_subregion_overlap(get_system_memory(), - apic->apicbase & - MSR_IA32_APICBASE_BASE, - &apic->io_memory, - 0x1000); - apic_mmio_map_once = true; - } -} -#else -static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp) -{ -} -#endif - static void x86_cpu_adjust_level(X86CPU *cpu, uint32_t *min, uint32_t value) { if (*min < value) { @@ -6248,7 +5919,7 @@ static void x86_cpu_enable_xsave_components(X86CPU *cpu) /* Expand CPU configuration data, based on configured features * and host/accelerator capabilities when appropriate. */ -static void x86_cpu_expand_features(X86CPU *cpu, Error **errp) +void x86_cpu_expand_features(X86CPU *cpu, Error **errp) { CPUX86State *env = &cpu->env; FeatureWord w; @@ -6622,10 +6293,12 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) ht_warned = true; } +#ifndef CONFIG_USER_ONLY x86_cpu_apic_realize(cpu, &local_err); if (local_err != NULL) { goto out; } +#endif /* !CONFIG_USER_ONLY */ cpu_reset(cs); xcc->parent_realize(dev, &local_err); @@ -6749,52 +6422,6 @@ static void x86_cpu_register_feature_bit_props(X86CPUClass *xcc, x86_cpu_register_bit_prop(xcc, name, w, bitnr); } -#if !defined(CONFIG_USER_ONLY) -static GuestPanicInformation *x86_cpu_get_crash_info(CPUState *cs) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - GuestPanicInformation *panic_info = NULL; - - if (env->features[FEAT_HYPERV_EDX] & HV_GUEST_CRASH_MSR_AVAILABLE) { - panic_info = g_malloc0(sizeof(GuestPanicInformation)); - - panic_info->type = GUEST_PANIC_INFORMATION_TYPE_HYPER_V; - - assert(HV_CRASH_PARAMS >= 5); - panic_info->u.hyper_v.arg1 = env->msr_hv_crash_params[0]; - panic_info->u.hyper_v.arg2 = env->msr_hv_crash_params[1]; - panic_info->u.hyper_v.arg3 = env->msr_hv_crash_params[2]; - panic_info->u.hyper_v.arg4 = env->msr_hv_crash_params[3]; - panic_info->u.hyper_v.arg5 = env->msr_hv_crash_params[4]; - } - - return panic_info; -} -static void x86_cpu_get_crash_info_qom(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - CPUState *cs = CPU(obj); - GuestPanicInformation *panic_info; - - if (!cs->crash_occurred) { - error_setg(errp, "No crash occurred"); - return; - } - - panic_info = x86_cpu_get_crash_info(cs); - if (panic_info == NULL) { - error_setg(errp, "No crash information"); - return; - } - - visit_type_GuestPanicInformation(v, "crash-information", &panic_info, - errp); - qapi_free_GuestPanicInformation(panic_info); -} -#endif /* !CONFIG_USER_ONLY */ - static void x86_cpu_initfn(Object *obj) { X86CPU *cpu = X86_CPU(obj); diff --git a/target/i386/meson.build b/target/i386/meson.build index 94571317f6..dac19ec00d 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build @@ -18,6 +18,7 @@ i386_softmmu_ss.add(files( 'arch_memory_mapping.c', 'machine.c', 'monitor.c', + 'cpu-sysemu.c', )) i386_user_ss = ss.source_set() From 4d81e28514dc7f0a4a0d54ccbb8f6ced59421491 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:55 +0100 Subject: [PATCH 0407/3028] target/i386: gdbstub: introduce aux functions to read/write CS64 regs a number of registers are read as 64bit under the condition that (hflags & HF_CS64_MASK) || TARGET_X86_64) and a number of registers are written as 64bit under the condition that (hflags & HF_CS64_MASK). Provide some auxiliary functions that do that. Signed-off-by: Claudio Fontana Cc: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-20-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/gdbstub.c | 155 ++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 104 deletions(-) diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c index 41e265fc67..4ad1295425 100644 --- a/target/i386/gdbstub.c +++ b/target/i386/gdbstub.c @@ -78,6 +78,23 @@ static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; #define GDB_FORCE_64 0 #endif +static int gdb_read_reg_cs64(uint32_t hflags, GByteArray *buf, target_ulong val) +{ + if ((hflags & HF_CS64_MASK) || GDB_FORCE_64) { + return gdb_get_reg64(buf, val); + } + return gdb_get_reg32(buf, val); +} + +static int gdb_write_reg_cs64(uint32_t hflags, uint8_t *buf, target_ulong *val) +{ + if (hflags & HF_CS64_MASK) { + *val = ldq_p(buf); + return 8; + } + *val = ldl_p(buf); + return 4; +} int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { @@ -142,25 +159,14 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return gdb_get_reg32(mem_buf, env->segs[R_FS].selector); case IDX_SEG_REGS + 5: return gdb_get_reg32(mem_buf, env->segs[R_GS].selector); - case IDX_SEG_REGS + 6: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->segs[R_FS].base); - } - return gdb_get_reg32(mem_buf, env->segs[R_FS].base); - + return gdb_read_reg_cs64(env->hflags, mem_buf, env->segs[R_FS].base); case IDX_SEG_REGS + 7: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->segs[R_GS].base); - } - return gdb_get_reg32(mem_buf, env->segs[R_GS].base); + return gdb_read_reg_cs64(env->hflags, mem_buf, env->segs[R_GS].base); case IDX_SEG_REGS + 8: #ifdef TARGET_X86_64 - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->kernelgsbase); - } - return gdb_get_reg32(mem_buf, env->kernelgsbase); + return gdb_read_reg_cs64(env->hflags, mem_buf, env->kernelgsbase); #else return gdb_get_reg32(mem_buf, 0); #endif @@ -188,45 +194,23 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return gdb_get_reg32(mem_buf, env->mxcsr); case IDX_CTL_CR0_REG: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->cr[0]); - } - return gdb_get_reg32(mem_buf, env->cr[0]); - + return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[0]); case IDX_CTL_CR2_REG: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->cr[2]); - } - return gdb_get_reg32(mem_buf, env->cr[2]); - + return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[2]); case IDX_CTL_CR3_REG: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->cr[3]); - } - return gdb_get_reg32(mem_buf, env->cr[3]); - + return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[3]); case IDX_CTL_CR4_REG: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->cr[4]); - } - return gdb_get_reg32(mem_buf, env->cr[4]); - + return gdb_read_reg_cs64(env->hflags, mem_buf, env->cr[4]); case IDX_CTL_CR8_REG: -#ifdef CONFIG_SOFTMMU +#ifndef CONFIG_USER_ONLY tpr = cpu_get_apic_tpr(cpu->apic_state); #else tpr = 0; #endif - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, tpr); - } - return gdb_get_reg32(mem_buf, tpr); + return gdb_read_reg_cs64(env->hflags, mem_buf, tpr); case IDX_CTL_EFER_REG: - if ((env->hflags & HF_CS64_MASK) || GDB_FORCE_64) { - return gdb_get_reg64(mem_buf, env->efer); - } - return gdb_get_reg32(mem_buf, env->efer); + return gdb_read_reg_cs64(env->hflags, mem_buf, env->efer); } } return 0; @@ -266,7 +250,8 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; - uint32_t tmp; + target_ulong tmp; + int len; /* N.B. GDB can't deal with changes in registers or sizes in the middle of a session. So if we're in 32-bit mode on a 64-bit cpu, still act @@ -329,30 +314,13 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) return x86_cpu_gdb_load_seg(cpu, R_FS, mem_buf); case IDX_SEG_REGS + 5: return x86_cpu_gdb_load_seg(cpu, R_GS, mem_buf); - case IDX_SEG_REGS + 6: - if (env->hflags & HF_CS64_MASK) { - env->segs[R_FS].base = ldq_p(mem_buf); - return 8; - } - env->segs[R_FS].base = ldl_p(mem_buf); - return 4; - + return gdb_write_reg_cs64(env->hflags, mem_buf, &env->segs[R_FS].base); case IDX_SEG_REGS + 7: - if (env->hflags & HF_CS64_MASK) { - env->segs[R_GS].base = ldq_p(mem_buf); - return 8; - } - env->segs[R_GS].base = ldl_p(mem_buf); - return 4; - + return gdb_write_reg_cs64(env->hflags, mem_buf, &env->segs[R_GS].base); case IDX_SEG_REGS + 8: #ifdef TARGET_X86_64 - if (env->hflags & HF_CS64_MASK) { - env->kernelgsbase = ldq_p(mem_buf); - return 8; - } - env->kernelgsbase = ldl_p(mem_buf); + return gdb_write_reg_cs64(env->hflags, mem_buf, &env->kernelgsbase); #endif return 4; @@ -382,57 +350,36 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) return 4; case IDX_CTL_CR0_REG: - if (env->hflags & HF_CS64_MASK) { - cpu_x86_update_cr0(env, ldq_p(mem_buf)); - return 8; - } - cpu_x86_update_cr0(env, ldl_p(mem_buf)); - return 4; + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); + cpu_x86_update_cr0(env, tmp); + return len; case IDX_CTL_CR2_REG: - if (env->hflags & HF_CS64_MASK) { - env->cr[2] = ldq_p(mem_buf); - return 8; - } - env->cr[2] = ldl_p(mem_buf); - return 4; + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); + env->cr[2] = tmp; + return len; case IDX_CTL_CR3_REG: - if (env->hflags & HF_CS64_MASK) { - cpu_x86_update_cr3(env, ldq_p(mem_buf)); - return 8; - } - cpu_x86_update_cr3(env, ldl_p(mem_buf)); - return 4; + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); + cpu_x86_update_cr3(env, tmp); + return len; case IDX_CTL_CR4_REG: - if (env->hflags & HF_CS64_MASK) { - cpu_x86_update_cr4(env, ldq_p(mem_buf)); - return 8; - } - cpu_x86_update_cr4(env, ldl_p(mem_buf)); - return 4; + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); + cpu_x86_update_cr4(env, tmp); + return len; case IDX_CTL_CR8_REG: - if (env->hflags & HF_CS64_MASK) { -#ifdef CONFIG_SOFTMMU - cpu_set_apic_tpr(cpu->apic_state, ldq_p(mem_buf)); + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY + cpu_set_apic_tpr(cpu->apic_state, tmp); #endif - return 8; - } -#ifdef CONFIG_SOFTMMU - cpu_set_apic_tpr(cpu->apic_state, ldl_p(mem_buf)); -#endif - return 4; + return len; case IDX_CTL_EFER_REG: - if (env->hflags & HF_CS64_MASK) { - cpu_load_efer(env, ldq_p(mem_buf)); - return 8; - } - cpu_load_efer(env, ldl_p(mem_buf)); - return 4; - + len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); + cpu_load_efer(env, tmp); + return len; } } /* Unrecognised register. */ From 1852f0942c815d07f9a07d1006c17570862f517e Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:56 +0100 Subject: [PATCH 0408/3028] target/i386: gdbstub: only write CR0/CR2/CR3/EFER for sysemu Signed-off-by: Claudio Fontana Cc: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-21-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/gdbstub.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c index 4ad1295425..098a2ad15a 100644 --- a/target/i386/gdbstub.c +++ b/target/i386/gdbstub.c @@ -351,22 +351,30 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) case IDX_CTL_CR0_REG: len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY cpu_x86_update_cr0(env, tmp); +#endif return len; case IDX_CTL_CR2_REG: len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY env->cr[2] = tmp; +#endif return len; case IDX_CTL_CR3_REG: len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY cpu_x86_update_cr3(env, tmp); +#endif return len; case IDX_CTL_CR4_REG: len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY cpu_x86_update_cr4(env, tmp); +#endif return len; case IDX_CTL_CR8_REG: @@ -378,7 +386,9 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) case IDX_CTL_EFER_REG: len = gdb_write_reg_cs64(env->hflags, mem_buf, &tmp); +#ifndef CONFIG_USER_ONLY cpu_load_efer(env, tmp); +#endif return len; } } From 6308728907386a6419447e90ead3c6ee4f0fd2f2 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:57 +0100 Subject: [PATCH 0409/3028] i386: make cpu_load_efer sysemu-only cpu_load_efer is now used only for sysemu code. Therefore, move this function implementation to sysemu-only section of helper.c Signed-off-by: Claudio Fontana Reviewed-by: Richard Henderson Message-Id: <20210322132800.7470-22-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 20 +++++--------------- target/i386/helper.c | 13 +++++++++++++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 5aae3ec0f4..0b182b7a5f 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1958,6 +1958,11 @@ static inline AddressSpace *cpu_addressspace(CPUState *cs, MemTxAttrs attrs) return cpu_get_address_space(cs, cpu_asidx_from_attrs(cs, attrs)); } +/* + * load efer and update the corresponding hflags. XXX: do consistency + * checks with cpuid bits? + */ +void cpu_load_efer(CPUX86State *env, uint64_t val); uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr); uint32_t x86_lduw_phys(CPUState *cs, hwaddr addr); uint32_t x86_ldl_phys(CPUState *cs, hwaddr addr); @@ -2054,21 +2059,6 @@ static inline uint32_t cpu_compute_eflags(CPUX86State *env) return eflags; } - -/* load efer and update the corresponding hflags. XXX: do consistency - checks with cpuid bits? */ -static inline void cpu_load_efer(CPUX86State *env, uint64_t val) -{ - env->efer = val; - env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK); - if (env->efer & MSR_EFER_LMA) { - env->hflags |= HF_LMA_MASK; - } - if (env->efer & MSR_EFER_SVME) { - env->hflags |= HF_SVME_MASK; - } -} - static inline MemTxAttrs cpu_get_mem_attrs(CPUX86State *env) { return ((MemTxAttrs) { .secure = (env->hflags & HF_SMM_MASK) != 0 }); diff --git a/target/i386/helper.c b/target/i386/helper.c index 8c180b5b2b..533b29cb91 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -574,6 +574,19 @@ void do_cpu_sipi(X86CPU *cpu) #endif #ifndef CONFIG_USER_ONLY + +void cpu_load_efer(CPUX86State *env, uint64_t val) +{ + env->efer = val; + env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK); + if (env->efer & MSR_EFER_LMA) { + env->hflags |= HF_LMA_MASK; + } + if (env->efer & MSR_EFER_SVME) { + env->hflags |= HF_SVME_MASK; + } +} + uint8_t x86_ldub_phys(CPUState *cs, hwaddr addr) { X86CPU *cpu = X86_CPU(cs); From 92242f34ab08ecc68750dd118bdad6ed66e3b00e Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:58 +0100 Subject: [PATCH 0410/3028] accel: move call to accel_init_interfaces move the call for sysemu specifically in machine_run_board_init, mirror the calling sequence for user mode too. Suggested-by: Paolo Bonzini Signed-off-by: Claudio Fontana Message-Id: <20210322132800.7470-23-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- bsd-user/main.c | 2 +- hw/core/machine.c | 1 + linux-user/main.c | 2 +- softmmu/vl.c | 1 - 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 36a889d084..715129e624 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -913,8 +913,8 @@ int main(int argc, char **argv) { AccelClass *ac = ACCEL_GET_CLASS(current_accel()); - ac->init_machine(NULL); accel_init_interfaces(ac); + ac->init_machine(NULL); } cpu = cpu_create(cpu_type); env = cpu->env_ptr; diff --git a/hw/core/machine.c b/hw/core/machine.c index 0f5ce43d0c..1bf0e687b9 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -1234,6 +1234,7 @@ void machine_run_board_init(MachineState *machine) "on", false); } + accel_init_interfaces(ACCEL_GET_CLASS(machine->accelerator)); machine_class->init(machine); phase_advance(PHASE_MACHINE_INITIALIZED); } diff --git a/linux-user/main.c b/linux-user/main.c index 57ba1b45ab..7995b6e7a6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -729,8 +729,8 @@ int main(int argc, char **argv, char **envp) { AccelClass *ac = ACCEL_GET_CLASS(current_accel()); - ac->init_machine(NULL); accel_init_interfaces(ac); + ac->init_machine(NULL); } cpu = cpu_create(cpu_type); env = cpu->env_ptr; diff --git a/softmmu/vl.c b/softmmu/vl.c index 307944aef3..93e78469bc 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -3595,7 +3595,6 @@ void qemu_init(int argc, char **argv, char **envp) current_machine->cpu_type = parse_cpu_option(cpu_option); } /* NB: for machine none cpu_type could STILL be NULL here! */ - accel_init_interfaces(ACCEL_GET_CLASS(current_machine->accelerator)); qemu_resolve_machine_memdev(); parse_numa_opts(current_machine); From cc3f2be6b7ca1bb1e5d78aa355c5bdeea25c91c4 Mon Sep 17 00:00:00 2001 From: Claudio Fontana Date: Mon, 22 Mar 2021 14:27:59 +0100 Subject: [PATCH 0411/3028] accel: add init_accel_cpu for adapting accel behavior to CPU type while on x86 all CPU classes can use the same set of TCGCPUOps, on ARM the right accel behavior depends on the type of the CPU. So we need a way to specialize the accel behavior according to the CPU. Therefore, add a second initialization, after the accel_cpu->cpu_class_init, that allows to do this. Signed-off-by: Claudio Fontana Cc: Paolo Bonzini Message-Id: <20210322132800.7470-24-cfontana@suse.de> Signed-off-by: Paolo Bonzini --- accel/accel-common.c | 13 +++++++++++++ include/hw/core/cpu.h | 6 ++++++ target/i386/tcg/tcg-cpu.c | 8 +++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/accel/accel-common.c b/accel/accel-common.c index d77c09d7b5..cf07f78421 100644 --- a/accel/accel-common.c +++ b/accel/accel-common.c @@ -54,10 +54,23 @@ static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque) CPUClass *cc = CPU_CLASS(klass); AccelCPUClass *accel_cpu = opaque; + /* + * The first callback allows accel-cpu to run initializations + * for the CPU, customizing CPU behavior according to the accelerator. + * + * The second one allows the CPU to customize the accel-cpu + * behavior according to the CPU. + * + * The second is currently only used by TCG, to specialize the + * TCGCPUOps depending on the CPU type. + */ cc->accel_cpu = accel_cpu; if (accel_cpu->cpu_class_init) { accel_cpu->cpu_class_init(cc); } + if (cc->init_accel_cpu) { + cc->init_accel_cpu(accel_cpu, cc); + } } /* initialize the arch-specific accel CpuClass interfaces */ diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index c68bc3ba8a..d45f78290e 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -192,6 +192,12 @@ struct CPUClass { /* when TCG is not available, this pointer is NULL */ struct TCGCPUOps *tcg_ops; + + /* + * if not NULL, this is called in order for the CPUClass to initialize + * class data that depends on the accelerator, see accel/accel-common.c. + */ + void (*init_accel_cpu)(struct AccelCPUClass *accel_cpu, CPUClass *cc); }; /* diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index e311f52855..ba39531aa5 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -69,9 +69,15 @@ static struct TCGCPUOps x86_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; +static void tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc) +{ + /* for x86, all cpus use the same set of operations */ + cc->tcg_ops = &x86_tcg_ops; +} + static void tcg_cpu_class_init(CPUClass *cc) { - cc->tcg_ops = &x86_tcg_ops; + cc->init_accel_cpu = tcg_cpu_init_ops; } /* From 6ed6b0d38025485ddac834964f1ee25a2a809b2b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Feb 2021 10:04:11 -0500 Subject: [PATCH 0412/3028] target/i386: merge SVM_NPTEXIT_* with PF_ERROR_* constants They are the same value, and are so by design. Signed-off-by: Paolo Bonzini --- target/i386/svm.h | 5 ----- target/i386/tcg/sysemu/excp_helper.c | 10 +++++----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/target/i386/svm.h b/target/i386/svm.h index ae30fc6f79..b515b5ced4 100644 --- a/target/i386/svm.h +++ b/target/i386/svm.h @@ -137,11 +137,6 @@ #define SVM_NPT_NXE (1 << 2) #define SVM_NPT_PSE (1 << 3) -#define SVM_NPTEXIT_P (1ULL << 0) -#define SVM_NPTEXIT_RW (1ULL << 1) -#define SVM_NPTEXIT_US (1ULL << 2) -#define SVM_NPTEXIT_RSVD (1ULL << 3) -#define SVM_NPTEXIT_ID (1ULL << 4) #define SVM_NPTEXIT_GPA (1ULL << 32) #define SVM_NPTEXIT_GPT (1ULL << 33) diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 1fcac51a32..7697fa4adc 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -205,17 +205,17 @@ static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, return pte + page_offset; do_fault_rsvd: - exit_info_1 |= SVM_NPTEXIT_RSVD; + exit_info_1 |= PG_ERROR_RSVD_MASK; do_fault_protect: - exit_info_1 |= SVM_NPTEXIT_P; + exit_info_1 |= PG_ERROR_P_MASK; do_fault: x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), gphys); - exit_info_1 |= SVM_NPTEXIT_US; + exit_info_1 |= PG_ERROR_U_MASK; if (access_type == MMU_DATA_STORE) { - exit_info_1 |= SVM_NPTEXIT_RW; + exit_info_1 |= PG_ERROR_W_MASK; } else if (access_type == MMU_INST_FETCH) { - exit_info_1 |= SVM_NPTEXIT_ID; + exit_info_1 |= PG_ERROR_I_D_MASK; } if (prot) { exit_info_1 |= SVM_NPTEXIT_GPA; From 616a89eaadb5337094a4931addee8a76c85556cd Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Feb 2021 09:45:05 -0500 Subject: [PATCH 0413/3028] target/i386: move paging mode constants from SVM to cpu.h We will reuse the page walker for both SVM and regular accesses. To do so we will build a function that receives the currently active paging mode; start by including in cpu.h the constants and the function to go from cr4/hflags/efer to the paging mode. Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 8 ++++++++ target/i386/svm.h | 5 ----- target/i386/tcg/sysemu/excp_helper.c | 26 ++++++++++++++++++++++---- target/i386/tcg/sysemu/svm_helper.c | 13 +------------ 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 0b182b7a5f..dbebd67f98 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -303,6 +303,11 @@ typedef enum X86Seg { #define PG_ERROR_I_D_MASK 0x10 #define PG_ERROR_PK_MASK 0x20 +#define PG_MODE_PAE (1 << 0) +#define PG_MODE_LMA (1 << 1) +#define PG_MODE_NXE (1 << 2) +#define PG_MODE_PSE (1 << 3) + #define MCG_CTL_P (1ULL<<8) /* MCG_CAP register available */ #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ #define MCG_LMCE_P (1ULL<<27) /* Local Machine Check Supported */ @@ -2105,6 +2110,9 @@ static inline bool cpu_vmx_maybe_enabled(CPUX86State *env) ((env->cr[4] & CR4_VMXE_MASK) || (env->hflags & HF_SMM_MASK)); } +/* excp_helper.c */ +int get_pg_mode(CPUX86State *env); + /* fpu_helper.c */ void update_fp_status(CPUX86State *env); void update_mxcsr_status(CPUX86State *env); diff --git a/target/i386/svm.h b/target/i386/svm.h index b515b5ced4..87965e5bc2 100644 --- a/target/i386/svm.h +++ b/target/i386/svm.h @@ -132,11 +132,6 @@ #define SVM_NPT_ENABLED (1 << 0) -#define SVM_NPT_PAE (1 << 0) -#define SVM_NPT_LMA (1 << 1) -#define SVM_NPT_NXE (1 << 2) -#define SVM_NPT_PSE (1 << 3) - #define SVM_NPTEXIT_GPA (1ULL << 32) #define SVM_NPTEXIT_GPT (1ULL << 33) diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 7697fa4adc..e616ac6f13 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -21,6 +21,24 @@ #include "cpu.h" #include "tcg/helper-tcg.h" +int get_pg_mode(CPUX86State *env) +{ + int pg_mode = 0; + if (env->cr[4] & CR4_PAE_MASK) { + pg_mode |= PG_MODE_PAE; + } + if (env->cr[4] & CR4_PSE_MASK) { + pg_mode |= PG_MODE_PSE; + } + if (env->hflags & HF_LMA_MASK) { + pg_mode |= PG_MODE_LMA; + } + if (env->efer & MSR_EFER_NXE) { + pg_mode |= PG_MODE_NXE; + } + return pg_mode; +} + static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, int *prot) { @@ -37,16 +55,16 @@ static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, return gphys; } - if (!(env->nested_pg_mode & SVM_NPT_NXE)) { + if (!(env->nested_pg_mode & PG_MODE_NXE)) { rsvd_mask |= PG_NX_MASK; } - if (env->nested_pg_mode & SVM_NPT_PAE) { + if (env->nested_pg_mode & PG_MODE_PAE) { uint64_t pde, pdpe; target_ulong pdpe_addr; #ifdef TARGET_X86_64 - if (env->nested_pg_mode & SVM_NPT_LMA) { + if (env->nested_pg_mode & PG_MODE_LMA) { uint64_t pml5e; uint64_t pml4e_addr, pml4e; @@ -147,7 +165,7 @@ static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, ptep = pde | PG_NX_MASK; /* if host cr4 PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & SVM_NPT_PSE)) { + if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & PG_MODE_PSE)) { page_size = 4096 * 1024; pte_addr = pde_addr; diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index d6c2cccda6..4d81d341b8 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -163,18 +163,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) control.nested_cr3)); env->hflags2 |= HF2_NPT_MASK; - if (env->cr[4] & CR4_PAE_MASK) { - env->nested_pg_mode |= SVM_NPT_PAE; - } - if (env->cr[4] & CR4_PSE_MASK) { - env->nested_pg_mode |= SVM_NPT_PSE; - } - if (env->hflags & HF_LMA_MASK) { - env->nested_pg_mode |= SVM_NPT_LMA; - } - if (env->efer & MSR_EFER_NXE) { - env->nested_pg_mode |= SVM_NPT_NXE; - } + env->nested_pg_mode = get_pg_mode(env); } /* enable intercepts */ From 661ff4879eee77953836ba9843c74b202844a492 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 18 Mar 2021 10:16:35 -0400 Subject: [PATCH 0414/3028] target/i386: extract mmu_translate Extract the page table lookup out of handle_mmu_fault, which only has to invoke mmu_translate and either fill the TLB or deliver the page fault. Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/excp_helper.c | 149 +++++++++++++++------------ 1 file changed, 85 insertions(+), 64 deletions(-) diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index e616ac6f13..f1103db64f 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -243,13 +243,11 @@ static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr); } -/* return value: - * -1 = cannot handle fault - * 0 = nothing more to do - * 1 = generate PF fault - */ -static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, - int is_write1, int mmu_idx) +#define PG_ERROR_OK (-1) + +static int mmu_translate(CPUState *cs, vaddr addr, + int is_write1, int mmu_idx, + vaddr *xlat, int *page_size, int *prot) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; @@ -257,33 +255,14 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, int32_t a20_mask; target_ulong pde_addr, pte_addr; int error_code = 0; - int is_dirty, prot, page_size, is_write, is_user; - hwaddr paddr; + int is_dirty, is_write, is_user; uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); uint32_t page_offset; - target_ulong vaddr; uint32_t pkr; - is_user = mmu_idx == MMU_USER_IDX; -#if defined(DEBUG_MMU) - printf("MMU fault: addr=%" VADDR_PRIx " w=%d u=%d eip=" TARGET_FMT_lx "\n", - addr, is_write1, is_user, env->eip); -#endif + is_user = (mmu_idx == MMU_USER_IDX); is_write = is_write1 & 1; - a20_mask = x86_get_a20_mask(env); - if (!(env->cr[0] & CR0_PG_MASK)) { - pte = addr; -#ifdef TARGET_X86_64 - if (!(env->hflags & HF_LMA_MASK)) { - /* Without long mode we can only address 32bits in real mode */ - pte = (uint32_t)pte; - } -#endif - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - page_size = 4096; - goto do_mapping; - } if (!(env->efer & MSR_EFER_NXE)) { rsvd_mask |= PG_NX_MASK; @@ -361,7 +340,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, } if (pdpe & PG_PSE_MASK) { /* 1 GB page */ - page_size = 1024 * 1024 * 1024; + *page_size = 1024 * 1024 * 1024; pte_addr = pdpe_addr; pte = pdpe; goto do_check_protect; @@ -397,7 +376,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, ptep &= pde ^ PG_NX_MASK; if (pde & PG_PSE_MASK) { /* 2 MB page */ - page_size = 2048 * 1024; + *page_size = 2048 * 1024; pte_addr = pde_addr; pte = pde; goto do_check_protect; @@ -419,7 +398,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, } /* combine pde and pte nx, user and rw protections */ ptep &= pte ^ PG_NX_MASK; - page_size = 4096; + *page_size = 4096; } else { uint32_t pde; @@ -435,7 +414,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, /* if PSE bit is set, then we use a 4MB page */ if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - page_size = 4096 * 1024; + *page_size = 4096 * 1024; pte_addr = pde_addr; /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. @@ -461,12 +440,12 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, } /* combine pde and pte user and rw protections */ ptep &= pte | PG_NX_MASK; - page_size = 4096; + *page_size = 4096; rsvd_mask = 0; } do_check_protect: - rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; + rsvd_mask |= (*page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; do_check_protect_pse36: if (pte & rsvd_mask) { goto do_fault_rsvd; @@ -478,17 +457,17 @@ do_check_protect_pse36: goto do_fault_protect; } - prot = 0; + *prot = 0; if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { - prot |= PAGE_READ; + *prot |= PAGE_READ; if ((ptep & PG_RW_MASK) || (!is_user && !(env->cr[0] & CR0_WP_MASK))) { - prot |= PAGE_WRITE; + *prot |= PAGE_WRITE; } } if (!(ptep & PG_NX_MASK) && (mmu_idx == MMU_USER_IDX || !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) { - prot |= PAGE_EXEC; + *prot |= PAGE_EXEC; } if (!(env->hflags & HF_LMA_MASK)) { @@ -510,7 +489,7 @@ do_check_protect_pse36: pkr_prot &= ~PAGE_WRITE; } - prot &= pkr_prot; + *prot &= pkr_prot; if ((pkr_prot & (1 << is_write1)) == 0) { assert(is_write1 != 2); error_code |= PG_ERROR_PK_MASK; @@ -518,7 +497,7 @@ do_check_protect_pse36: } } - if ((prot & (1 << is_write1)) == 0) { + if ((*prot & (1 << is_write1)) == 0) { goto do_fault_protect; } @@ -536,26 +515,17 @@ do_check_protect_pse36: /* only set write access if already dirty... otherwise wait for dirty access */ assert(!is_write); - prot &= ~PAGE_WRITE; + *prot &= ~PAGE_WRITE; } - do_mapping: pte = pte & a20_mask; /* align to page_size */ - pte &= PG_ADDRESS_MASK & ~(page_size - 1); - page_offset = addr & (page_size - 1); - paddr = get_hphys(cs, pte + page_offset, is_write1, &prot); + pte &= PG_ADDRESS_MASK & ~(*page_size - 1); + page_offset = addr & (*page_size - 1); + *xlat = get_hphys(cs, pte + page_offset, is_write1, prot); + return PG_ERROR_OK; - /* Even if 4MB pages, we map only one 4KB page in the cache to - avoid filling it too fast */ - vaddr = addr & TARGET_PAGE_MASK; - paddr &= TARGET_PAGE_MASK; - - assert(prot & (1 << is_write1)); - tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env), - prot, mmu_idx, page_size); - return 0; do_fault_rsvd: error_code |= PG_ERROR_RSVD_MASK; do_fault_protect: @@ -566,20 +536,71 @@ do_check_protect_pse36: error_code |= PG_ERROR_U_MASK; if (is_write1 == 2 && (((env->efer & MSR_EFER_NXE) && - (env->cr[4] & CR4_PAE_MASK)) || + (env->cr[4] & CR4_PAE_MASK)) || (env->cr[4] & CR4_SMEP_MASK))) error_code |= PG_ERROR_I_D_MASK; - if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { - /* cr2 is not modified in case of exceptions */ - x86_stq_phys(cs, - env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), - addr); + return error_code; +} + +/* return value: + * -1 = cannot handle fault + * 0 = nothing more to do + * 1 = generate PF fault + */ +static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, + int is_write1, int mmu_idx) +{ + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + int error_code = PG_ERROR_OK; + int prot, page_size; + hwaddr paddr; + target_ulong vaddr; + +#if defined(DEBUG_MMU) + printf("MMU fault: addr=%" VADDR_PRIx " w=%d mmu=%d eip=" TARGET_FMT_lx "\n", + addr, is_write1, mmu_idx, env->eip); +#endif + + if (!(env->cr[0] & CR0_PG_MASK)) { + paddr = addr; +#ifdef TARGET_X86_64 + if (!(env->hflags & HF_LMA_MASK)) { + /* Without long mode we can only address 32bits in real mode */ + paddr = (uint32_t)paddr; + } +#endif + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + page_size = 4096; } else { - env->cr[2] = addr; + error_code = mmu_translate(cs, addr, is_write1, + mmu_idx, + &paddr, &page_size, &prot); + } + + if (error_code == PG_ERROR_OK) { + /* Even if 4MB pages, we map only one 4KB page in the cache to + avoid filling it too fast */ + vaddr = addr & TARGET_PAGE_MASK; + paddr &= TARGET_PAGE_MASK; + + assert(prot & (1 << is_write1)); + tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env), + prot, mmu_idx, page_size); + return 0; + } else { + if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) { + /* cr2 is not modified in case of exceptions */ + x86_stq_phys(cs, + env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), + addr); + } else { + env->cr[2] = addr; + } + env->error_code = error_code; + cs->exception_index = EXCP0E_PAGE; + return 1; } - env->error_code = error_code; - cs->exception_index = EXCP0E_PAGE; - return 1; } bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, From cd906d315d629da010e0ac6f84949c04d2ab7a08 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Feb 2021 11:31:56 -0500 Subject: [PATCH 0415/3028] target/i386: pass cr3 to mmu_translate First step in unifying the nested and regular page table walk. Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/excp_helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index f1103db64f..4cf04f4e96 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -246,7 +246,7 @@ static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, #define PG_ERROR_OK (-1) static int mmu_translate(CPUState *cs, vaddr addr, - int is_write1, int mmu_idx, + uint64_t cr3, int is_write1, int mmu_idx, vaddr *xlat, int *page_size, int *prot) { X86CPU *cpu = X86_CPU(cs); @@ -288,7 +288,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, } if (la57) { - pml5e_addr = ((env->cr[3] & ~0xfff) + + pml5e_addr = ((cr3 & ~0xfff) + (((addr >> 48) & 0x1ff) << 3)) & a20_mask; pml5e_addr = get_hphys(cs, pml5e_addr, MMU_DATA_STORE, NULL); pml5e = x86_ldq_phys(cs, pml5e_addr); @@ -304,7 +304,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, } ptep = pml5e ^ PG_NX_MASK; } else { - pml5e = env->cr[3]; + pml5e = cr3; ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; } @@ -349,7 +349,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, #endif { /* XXX: load them when cr3 is loaded ? */ - pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) & + pdpe_addr = ((cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & a20_mask; pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, false); pdpe = x86_ldq_phys(cs, pdpe_addr); @@ -403,7 +403,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, uint32_t pde; /* page directory entry */ - pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & + pde_addr = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask; pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); pde = x86_ldl_phys(cs, pde_addr); @@ -573,7 +573,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; page_size = 4096; } else { - error_code = mmu_translate(cs, addr, is_write1, + error_code = mmu_translate(cs, addr, env->cr[3], is_write1, mmu_idx, &paddr, &page_size, &prot); } From 31dd35eb2d4484b70e4462a9e4a370695cc8ce8d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Feb 2021 10:24:35 -0500 Subject: [PATCH 0416/3028] target/i386: extend pg_mode to more CR0 and CR4 bits In order to unify the two stages of page table lookup, we need mmu_translate to use either the host CR0/EFER/CR4 or the guest's. To do so, make mmu_translate use the same pg_mode constants that were used for the NPT lookup. This also prepares for adding 5-level NPT support, which however does not work yet. Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 8 +++++ target/i386/tcg/sysemu/excp_helper.c | 45 ++++++++++++++++++---------- target/i386/tcg/sysemu/svm_helper.c | 2 +- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index dbebd67f98..324ef92beb 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -307,6 +307,14 @@ typedef enum X86Seg { #define PG_MODE_LMA (1 << 1) #define PG_MODE_NXE (1 << 2) #define PG_MODE_PSE (1 << 3) +#define PG_MODE_LA57 (1 << 4) +#define PG_MODE_SVM_MASK MAKE_64BIT_MASK(0, 15) + +/* Bits of CR4 that do not affect the NPT page format. */ +#define PG_MODE_WP (1 << 16) +#define PG_MODE_PKE (1 << 17) +#define PG_MODE_PKS (1 << 18) +#define PG_MODE_SMEP (1 << 19) #define MCG_CTL_P (1ULL<<8) /* MCG_CAP register available */ #define MCG_SER_P (1ULL<<24) /* MCA recovery/new status bits */ diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 4cf04f4e96..2b7baa0193 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -24,12 +24,27 @@ int get_pg_mode(CPUX86State *env) { int pg_mode = 0; + if (env->cr[0] & CR0_WP_MASK) { + pg_mode |= PG_MODE_WP; + } if (env->cr[4] & CR4_PAE_MASK) { pg_mode |= PG_MODE_PAE; } if (env->cr[4] & CR4_PSE_MASK) { pg_mode |= PG_MODE_PSE; } + if (env->cr[4] & CR4_PKE_MASK) { + pg_mode |= PG_MODE_PKE; + } + if (env->cr[4] & CR4_PKS_MASK) { + pg_mode |= PG_MODE_PKS; + } + if (env->cr[4] & CR4_SMEP_MASK) { + pg_mode |= PG_MODE_SMEP; + } + if (env->cr[4] & CR4_LA57_MASK) { + pg_mode |= PG_MODE_LA57; + } if (env->hflags & HF_LMA_MASK) { pg_mode |= PG_MODE_LMA; } @@ -246,7 +261,7 @@ static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, #define PG_ERROR_OK (-1) static int mmu_translate(CPUState *cs, vaddr addr, - uint64_t cr3, int is_write1, int mmu_idx, + uint64_t cr3, int is_write1, int mmu_idx, int pg_mode, vaddr *xlat, int *page_size, int *prot) { X86CPU *cpu = X86_CPU(cs); @@ -264,17 +279,17 @@ static int mmu_translate(CPUState *cs, vaddr addr, is_write = is_write1 & 1; a20_mask = x86_get_a20_mask(env); - if (!(env->efer & MSR_EFER_NXE)) { + if (!(pg_mode & PG_MODE_NXE)) { rsvd_mask |= PG_NX_MASK; } - if (env->cr[4] & CR4_PAE_MASK) { + if (pg_mode & PG_MODE_PAE) { uint64_t pde, pdpe; target_ulong pdpe_addr; #ifdef TARGET_X86_64 if (env->hflags & HF_LMA_MASK) { - bool la57 = env->cr[4] & CR4_LA57_MASK; + bool la57 = pg_mode & PG_MODE_LA57; uint64_t pml5e_addr, pml5e; uint64_t pml4e_addr, pml4e; int32_t sext; @@ -413,7 +428,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, ptep = pde | PG_NX_MASK; /* if PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { + if ((pde & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) { *page_size = 4096 * 1024; pte_addr = pde_addr; @@ -460,22 +475,22 @@ do_check_protect_pse36: *prot = 0; if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { *prot |= PAGE_READ; - if ((ptep & PG_RW_MASK) || (!is_user && !(env->cr[0] & CR0_WP_MASK))) { + if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) { *prot |= PAGE_WRITE; } } if (!(ptep & PG_NX_MASK) && (mmu_idx == MMU_USER_IDX || - !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) { + !((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) { *prot |= PAGE_EXEC; } if (!(env->hflags & HF_LMA_MASK)) { pkr = 0; } else if (ptep & PG_USER_MASK) { - pkr = env->cr[4] & CR4_PKE_MASK ? env->pkru : 0; + pkr = pg_mode & PG_MODE_PKE ? env->pkru : 0; } else { - pkr = env->cr[4] & CR4_PKS_MASK ? env->pkrs : 0; + pkr = pg_mode & PG_MODE_PKS ? env->pkrs : 0; } if (pkr) { uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT; @@ -485,7 +500,7 @@ do_check_protect_pse36: if (pkr_ad) { pkr_prot &= ~(PAGE_READ | PAGE_WRITE); - } else if (pkr_wd && (is_user || env->cr[0] & CR0_WP_MASK)) { + } else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) { pkr_prot &= ~PAGE_WRITE; } @@ -535,9 +550,8 @@ do_check_protect_pse36: if (is_user) error_code |= PG_ERROR_U_MASK; if (is_write1 == 2 && - (((env->efer & MSR_EFER_NXE) && - (env->cr[4] & CR4_PAE_MASK)) || - (env->cr[4] & CR4_SMEP_MASK))) + (((pg_mode & PG_MODE_NXE) && (pg_mode & PG_MODE_PAE)) || + (pg_mode & PG_MODE_SMEP))) error_code |= PG_ERROR_I_D_MASK; return error_code; } @@ -553,7 +567,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; int error_code = PG_ERROR_OK; - int prot, page_size; + int pg_mode, prot, page_size; hwaddr paddr; target_ulong vaddr; @@ -573,8 +587,9 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; page_size = 4096; } else { + pg_mode = get_pg_mode(env); error_code = mmu_translate(cs, addr, env->cr[3], is_write1, - mmu_idx, + mmu_idx, pg_mode, &paddr, &page_size, &prot); } diff --git a/target/i386/tcg/sysemu/svm_helper.c b/target/i386/tcg/sysemu/svm_helper.c index 4d81d341b8..c4e8e717a9 100644 --- a/target/i386/tcg/sysemu/svm_helper.c +++ b/target/i386/tcg/sysemu/svm_helper.c @@ -163,7 +163,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend) control.nested_cr3)); env->hflags2 |= HF2_NPT_MASK; - env->nested_pg_mode = get_pg_mode(env); + env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK; } /* enable intercepts */ From 33ce155c6779baf3a01b22782632bda0cec352fb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 26 Feb 2021 10:31:06 -0500 Subject: [PATCH 0417/3028] target/i386: allow customizing the next phase of the translation Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/excp_helper.c | 30 +++++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 2b7baa0193..082ddbb911 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -260,7 +260,13 @@ static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, #define PG_ERROR_OK (-1) -static int mmu_translate(CPUState *cs, vaddr addr, +typedef hwaddr (*MMUTranslateFunc)(CPUState *cs, hwaddr gphys, MMUAccessType access_type, + int *prot); + +#define GET_HPHYS(cs, gpa, access_type, prot) \ + (get_hphys_func ? get_hphys_func(cs, gpa, access_type, prot) : gpa) + +static int mmu_translate(CPUState *cs, vaddr addr, MMUTranslateFunc get_hphys_func, uint64_t cr3, int is_write1, int mmu_idx, int pg_mode, vaddr *xlat, int *page_size, int *prot) { @@ -296,7 +302,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, /* test virtual address sign extension */ sext = la57 ? (int64_t)addr >> 56 : (int64_t)addr >> 47; - if (sext != 0 && sext != -1) { + if (get_hphys_func && sext != 0 && sext != -1) { env->error_code = 0; cs->exception_index = EXCP0D_GPF; return 1; @@ -305,7 +311,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, if (la57) { pml5e_addr = ((cr3 & ~0xfff) + (((addr >> 48) & 0x1ff) << 3)) & a20_mask; - pml5e_addr = get_hphys(cs, pml5e_addr, MMU_DATA_STORE, NULL); + pml5e_addr = GET_HPHYS(cs, pml5e_addr, MMU_DATA_STORE, NULL); pml5e = x86_ldq_phys(cs, pml5e_addr); if (!(pml5e & PG_PRESENT_MASK)) { goto do_fault; @@ -325,7 +331,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + (((addr >> 39) & 0x1ff) << 3)) & a20_mask; - pml4e_addr = get_hphys(cs, pml4e_addr, MMU_DATA_STORE, false); + pml4e_addr = GET_HPHYS(cs, pml4e_addr, MMU_DATA_STORE, NULL); pml4e = x86_ldq_phys(cs, pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) { goto do_fault; @@ -340,7 +346,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, ptep &= pml4e ^ PG_NX_MASK; pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & a20_mask; - pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, NULL); + pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL); pdpe = x86_ldq_phys(cs, pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { goto do_fault; @@ -366,7 +372,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, /* XXX: load them when cr3 is loaded ? */ pdpe_addr = ((cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & a20_mask; - pdpe_addr = get_hphys(cs, pdpe_addr, MMU_DATA_STORE, false); + pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL); pdpe = x86_ldq_phys(cs, pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { goto do_fault; @@ -380,7 +386,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & a20_mask; - pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); + pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL); pde = x86_ldq_phys(cs, pde_addr); if (!(pde & PG_PRESENT_MASK)) { goto do_fault; @@ -403,7 +409,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, } pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & a20_mask; - pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL); + pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL); pte = x86_ldq_phys(cs, pte_addr); if (!(pte & PG_PRESENT_MASK)) { goto do_fault; @@ -420,7 +426,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, /* page directory entry */ pde_addr = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask; - pde_addr = get_hphys(cs, pde_addr, MMU_DATA_STORE, NULL); + pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL); pde = x86_ldl_phys(cs, pde_addr); if (!(pde & PG_PRESENT_MASK)) { goto do_fault; @@ -448,7 +454,7 @@ static int mmu_translate(CPUState *cs, vaddr addr, /* page directory entry */ pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & a20_mask; - pte_addr = get_hphys(cs, pte_addr, MMU_DATA_STORE, NULL); + pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL); pte = x86_ldl_phys(cs, pte_addr); if (!(pte & PG_PRESENT_MASK)) { goto do_fault; @@ -538,7 +544,7 @@ do_check_protect_pse36: /* align to page_size */ pte &= PG_ADDRESS_MASK & ~(*page_size - 1); page_offset = addr & (*page_size - 1); - *xlat = get_hphys(cs, pte + page_offset, is_write1, prot); + *xlat = GET_HPHYS(cs, pte + page_offset, is_write1, prot); return PG_ERROR_OK; do_fault_rsvd: @@ -588,7 +594,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, page_size = 4096; } else { pg_mode = get_pg_mode(env); - error_code = mmu_translate(cs, addr, env->cr[3], is_write1, + error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], is_write1, mmu_idx, pg_mode, &paddr, &page_size, &prot); } From 68746930ae591eca3d6dd490012b59e85194ede4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 18 Mar 2021 10:31:47 -0400 Subject: [PATCH 0418/3028] target/i386: use mmu_translate for NPT walk Unify the duplicate code between get_hphys and mmu_translate, by simply making get_hphys call mmu_translate. This also fixes the support for 5-level nested page tables. Signed-off-by: Paolo Bonzini --- target/i386/tcg/sysemu/excp_helper.c | 243 ++++----------------------- 1 file changed, 36 insertions(+), 207 deletions(-) diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 082ddbb911..b6d940e04e 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -54,210 +54,6 @@ int get_pg_mode(CPUX86State *env) return pg_mode; } -static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, - int *prot) -{ - X86CPU *cpu = X86_CPU(cs); - CPUX86State *env = &cpu->env; - uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); - uint64_t ptep, pte; - uint64_t exit_info_1 = 0; - target_ulong pde_addr, pte_addr; - uint32_t page_offset; - int page_size; - - if (likely(!(env->hflags2 & HF2_NPT_MASK))) { - return gphys; - } - - if (!(env->nested_pg_mode & PG_MODE_NXE)) { - rsvd_mask |= PG_NX_MASK; - } - - if (env->nested_pg_mode & PG_MODE_PAE) { - uint64_t pde, pdpe; - target_ulong pdpe_addr; - -#ifdef TARGET_X86_64 - if (env->nested_pg_mode & PG_MODE_LMA) { - uint64_t pml5e; - uint64_t pml4e_addr, pml4e; - - pml5e = env->nested_cr3; - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - - pml4e_addr = (pml5e & PG_ADDRESS_MASK) + - (((gphys >> 39) & 0x1ff) << 3); - pml4e = x86_ldq_phys(cs, pml4e_addr); - if (!(pml4e & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pml4e & (rsvd_mask | PG_PSE_MASK)) { - goto do_fault_rsvd; - } - if (!(pml4e & PG_ACCESSED_MASK)) { - pml4e |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pml4e_addr, pml4e); - } - ptep &= pml4e ^ PG_NX_MASK; - pdpe_addr = (pml4e & PG_ADDRESS_MASK) + - (((gphys >> 30) & 0x1ff) << 3); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pdpe & rsvd_mask) { - goto do_fault_rsvd; - } - ptep &= pdpe ^ PG_NX_MASK; - if (!(pdpe & PG_ACCESSED_MASK)) { - pdpe |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pdpe_addr, pdpe); - } - if (pdpe & PG_PSE_MASK) { - /* 1 GB page */ - page_size = 1024 * 1024 * 1024; - pte_addr = pdpe_addr; - pte = pdpe; - goto do_check_protect; - } - } else -#endif - { - pdpe_addr = (env->nested_cr3 & ~0x1f) + ((gphys >> 27) & 0x18); - pdpe = x86_ldq_phys(cs, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) { - goto do_fault; - } - rsvd_mask |= PG_HI_USER_MASK; - if (pdpe & (rsvd_mask | PG_NX_MASK)) { - goto do_fault_rsvd; - } - ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; - } - - pde_addr = (pdpe & PG_ADDRESS_MASK) + (((gphys >> 21) & 0x1ff) << 3); - pde = x86_ldq_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pde & rsvd_mask) { - goto do_fault_rsvd; - } - ptep &= pde ^ PG_NX_MASK; - if (pde & PG_PSE_MASK) { - /* 2 MB page */ - page_size = 2048 * 1024; - pte_addr = pde_addr; - pte = pde; - goto do_check_protect; - } - /* 4 KB page */ - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); - } - pte_addr = (pde & PG_ADDRESS_MASK) + (((gphys >> 12) & 0x1ff) << 3); - pte = x86_ldq_phys(cs, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - goto do_fault; - } - if (pte & rsvd_mask) { - goto do_fault_rsvd; - } - /* combine pde and pte nx, user and rw protections */ - ptep &= pte ^ PG_NX_MASK; - page_size = 4096; - } else { - uint32_t pde; - - /* page directory entry */ - pde_addr = (env->nested_cr3 & ~0xfff) + ((gphys >> 20) & 0xffc); - pde = x86_ldl_phys(cs, pde_addr); - if (!(pde & PG_PRESENT_MASK)) { - goto do_fault; - } - ptep = pde | PG_NX_MASK; - - /* if host cr4 PSE bit is set, then we use a 4MB page */ - if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & PG_MODE_PSE)) { - page_size = 4096 * 1024; - pte_addr = pde_addr; - - /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. - * Leave bits 20-13 in place for setting accessed/dirty bits below. - */ - pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); - rsvd_mask = 0x200000; - goto do_check_protect_pse36; - } - - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - x86_stl_phys_notdirty(cs, pde_addr, pde); - } - - /* page directory entry */ - pte_addr = (pde & ~0xfff) + ((gphys >> 10) & 0xffc); - pte = x86_ldl_phys(cs, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - goto do_fault; - } - /* combine pde and pte user and rw protections */ - ptep &= pte | PG_NX_MASK; - page_size = 4096; - rsvd_mask = 0; - } - - do_check_protect: - rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; - do_check_protect_pse36: - if (pte & rsvd_mask) { - goto do_fault_rsvd; - } - ptep ^= PG_NX_MASK; - - if (!(ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - if (ptep & PG_NX_MASK) { - if (access_type == MMU_INST_FETCH) { - goto do_fault_protect; - } - *prot &= ~PAGE_EXEC; - } - if (!(ptep & PG_RW_MASK)) { - if (access_type == MMU_DATA_STORE) { - goto do_fault_protect; - } - *prot &= ~PAGE_WRITE; - } - - pte &= PG_ADDRESS_MASK & ~(page_size - 1); - page_offset = gphys & (page_size - 1); - return pte + page_offset; - - do_fault_rsvd: - exit_info_1 |= PG_ERROR_RSVD_MASK; - do_fault_protect: - exit_info_1 |= PG_ERROR_P_MASK; - do_fault: - x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), - gphys); - exit_info_1 |= PG_ERROR_U_MASK; - if (access_type == MMU_DATA_STORE) { - exit_info_1 |= PG_ERROR_W_MASK; - } else if (access_type == MMU_INST_FETCH) { - exit_info_1 |= PG_ERROR_I_D_MASK; - } - if (prot) { - exit_info_1 |= SVM_NPTEXIT_GPA; - } else { /* page table access */ - exit_info_1 |= SVM_NPTEXIT_GPT; - } - cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr); -} - #define PG_ERROR_OK (-1) typedef hwaddr (*MMUTranslateFunc)(CPUState *cs, hwaddr gphys, MMUAccessType access_type, @@ -266,9 +62,9 @@ typedef hwaddr (*MMUTranslateFunc)(CPUState *cs, hwaddr gphys, MMUAccessType acc #define GET_HPHYS(cs, gpa, access_type, prot) \ (get_hphys_func ? get_hphys_func(cs, gpa, access_type, prot) : gpa) -static int mmu_translate(CPUState *cs, vaddr addr, MMUTranslateFunc get_hphys_func, +static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_func, uint64_t cr3, int is_write1, int mmu_idx, int pg_mode, - vaddr *xlat, int *page_size, int *prot) + hwaddr *xlat, int *page_size, int *prot) { X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; @@ -562,6 +358,39 @@ do_check_protect_pse36: return error_code; } +static hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, + int *prot) +{ + CPUX86State *env = &X86_CPU(cs)->env; + uint64_t exit_info_1; + int page_size; + int next_prot; + hwaddr hphys; + + if (likely(!(env->hflags2 & HF2_NPT_MASK))) { + return gphys; + } + + exit_info_1 = mmu_translate(cs, gphys, NULL, env->nested_cr3, + access_type, MMU_USER_IDX, env->nested_pg_mode, + &hphys, &page_size, &next_prot); + if (exit_info_1 == PG_ERROR_OK) { + if (prot) { + *prot &= next_prot; + } + return hphys; + } + + x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), + gphys); + if (prot) { + exit_info_1 |= SVM_NPTEXIT_GPA; + } else { /* page table access */ + exit_info_1 |= SVM_NPTEXIT_GPT; + } + cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr); +} + /* return value: * -1 = cannot handle fault * 0 = nothing more to do @@ -575,7 +404,7 @@ static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, int error_code = PG_ERROR_OK; int pg_mode, prot, page_size; hwaddr paddr; - target_ulong vaddr; + hwaddr vaddr; #if defined(DEBUG_MMU) printf("MMU fault: addr=%" VADDR_PRIx " w=%d mmu=%d eip=" TARGET_FMT_lx "\n", From d3e6dd2fe73e2c91a5e9803f3d5a93a82fe829ae Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 16 Mar 2021 05:20:44 -0400 Subject: [PATCH 0419/3028] main-loop: remove dead code qemu_add_child_watch is not called anywhere since commit 2bdb920ece ("slirp: simplify fork_exec()", 2019-01-14), remove it. Signed-off-by: Paolo Bonzini --- include/qemu/main-loop.h | 18 ------------ util/main-loop.c | 61 ---------------------------------------- 2 files changed, 79 deletions(-) diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index d6892fd208..98aef5647c 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -234,24 +234,6 @@ void event_notifier_set_handler(EventNotifier *e, GSource *iohandler_get_g_source(void); AioContext *iohandler_get_aio_context(void); -#ifdef CONFIG_POSIX -/** - * qemu_add_child_watch: Register a child process for reaping. - * - * Under POSIX systems, a parent process must read the exit status of - * its child processes using waitpid, or the operating system will not - * free some of the resources attached to that process. - * - * This function directs the QEMU main loop to observe a child process - * and call waitpid as soon as it exits; the watch is then removed - * automatically. It is useful whenever QEMU forks a child process - * but will find out about its termination by other means such as a - * "broken pipe". - * - * @pid: The pid that QEMU should observe. - */ -int qemu_add_child_watch(pid_t pid); -#endif /** * qemu_mutex_iothread_locked: Return lock status of the main loop mutex. diff --git a/util/main-loop.c b/util/main-loop.c index 5188ff6540..d9c55df6f5 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -591,64 +591,3 @@ void event_notifier_set_handler(EventNotifier *e, aio_set_event_notifier(iohandler_ctx, e, false, handler, NULL); } - -/* reaping of zombies. right now we're not passing the status to - anyone, but it would be possible to add a callback. */ -#ifndef _WIN32 -typedef struct ChildProcessRecord { - int pid; - QLIST_ENTRY(ChildProcessRecord) next; -} ChildProcessRecord; - -static QLIST_HEAD(, ChildProcessRecord) child_watches = - QLIST_HEAD_INITIALIZER(child_watches); - -static QEMUBH *sigchld_bh; - -static void sigchld_handler(int signal) -{ - qemu_bh_schedule(sigchld_bh); -} - -static void sigchld_bh_handler(void *opaque) -{ - ChildProcessRecord *rec, *next; - - QLIST_FOREACH_SAFE(rec, &child_watches, next, next) { - if (waitpid(rec->pid, NULL, WNOHANG) == rec->pid) { - QLIST_REMOVE(rec, next); - g_free(rec); - } - } -} - -static void qemu_init_child_watch(void) -{ - struct sigaction act; - sigchld_bh = qemu_bh_new(sigchld_bh_handler, NULL); - - memset(&act, 0, sizeof(act)); - act.sa_handler = sigchld_handler; - act.sa_flags = SA_NOCLDSTOP; - sigaction(SIGCHLD, &act, NULL); -} - -int qemu_add_child_watch(pid_t pid) -{ - ChildProcessRecord *rec; - - if (!sigchld_bh) { - qemu_init_child_watch(); - } - - QLIST_FOREACH(rec, &child_watches, next) { - if (rec->pid == pid) { - return 1; - } - } - rec = g_malloc0(sizeof(ChildProcessRecord)); - rec->pid = pid; - QLIST_INSERT_HEAD(&child_watches, rec, next); - return 0; -} -#endif From ac12b601032e63aeb6c318e9cc9d8f2563854361 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Fri, 19 Mar 2021 12:45:29 -0700 Subject: [PATCH 0420/3028] target/riscv: Remove privilege v1.9 specific CSR related code Qemu doesn't support RISC-V privilege specification v1.9. Remove the remaining v1.9 specific references from the implementation. Signed-off-by: Atish Patra Reviewed-by: Alistair Francis Message-Id: <20210319194534.2082397-2-atish.patra@wdc.com> [Changes by AF: - Rebase on latest patches - Bump the vmstate_riscv_cpu version_id and minimum_version_id ] Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 +- target/riscv/cpu.h | 4 +--- target/riscv/cpu_bits.h | 23 --------------------- target/riscv/cpu_helper.c | 12 +++++------ target/riscv/csr.c | 42 ++++++++++----------------------------- target/riscv/machine.c | 8 +++----- target/riscv/translate.c | 4 ++-- 7 files changed, 23 insertions(+), 72 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7d6ed80f6b..86e7dbeb20 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -282,7 +282,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vscause ", env->vscause); } qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtval ", env->mtval); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stval ", env->sbadaddr); + qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stval ", env->stval); if (riscv_has_ext(env, RVH)) { qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "htval ", env->htval); qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtval2 ", env->mtval2); diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 0a33d387ba..311b1db875 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -163,10 +163,8 @@ struct CPURISCVState { target_ulong mie; target_ulong mideleg; - target_ulong sptbr; /* until: priv-1.9.1 */ target_ulong satp; /* since: priv-1.10.0 */ - target_ulong sbadaddr; - target_ulong mbadaddr; + target_ulong stval; target_ulong medeleg; target_ulong stvec; diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index caf4599207..b42dd4f8d8 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -153,12 +153,6 @@ /* 32-bit only */ #define CSR_MSTATUSH 0x310 -/* Legacy Counter Setup (priv v1.9.1) */ -/* Update to #define CSR_MCOUNTINHIBIT 0x320 for 1.11.0 */ -#define CSR_MUCOUNTEREN 0x320 -#define CSR_MSCOUNTEREN 0x321 -#define CSR_MHCOUNTEREN 0x322 - /* Machine Trap Handling */ #define CSR_MSCRATCH 0x340 #define CSR_MEPC 0x341 @@ -166,9 +160,6 @@ #define CSR_MTVAL 0x343 #define CSR_MIP 0x344 -/* Legacy Machine Trap Handling (priv v1.9.1) */ -#define CSR_MBADADDR 0x343 - /* Supervisor Trap Setup */ #define CSR_SSTATUS 0x100 #define CSR_SEDELEG 0x102 @@ -184,9 +175,6 @@ #define CSR_STVAL 0x143 #define CSR_SIP 0x144 -/* Legacy Supervisor Trap Handling (priv v1.9.1) */ -#define CSR_SBADADDR 0x143 - /* Supervisor Protection and Translation */ #define CSR_SPTBR 0x180 #define CSR_SATP 0x180 @@ -354,14 +342,6 @@ #define CSR_MHPMCOUNTER30H 0xb9e #define CSR_MHPMCOUNTER31H 0xb9f -/* Legacy Machine Protection and Translation (priv v1.9.1) */ -#define CSR_MBASE 0x380 -#define CSR_MBOUND 0x381 -#define CSR_MIBASE 0x382 -#define CSR_MIBOUND 0x383 -#define CSR_MDBASE 0x384 -#define CSR_MDBOUND 0x385 - /* mstatus CSR bits */ #define MSTATUS_UIE 0x00000001 #define MSTATUS_SIE 0x00000002 @@ -375,10 +355,8 @@ #define MSTATUS_FS 0x00006000 #define MSTATUS_XS 0x00018000 #define MSTATUS_MPRV 0x00020000 -#define MSTATUS_PUM 0x00040000 /* until: priv-1.9.1 */ #define MSTATUS_SUM 0x00040000 /* since: priv-1.10 */ #define MSTATUS_MXR 0x00080000 -#define MSTATUS_VM 0x1F000000 /* until: priv-1.9.1 */ #define MSTATUS_TVM 0x00100000 /* since: priv-1.10 */ #define MSTATUS_TW 0x00200000 /* since: priv-1.10 */ #define MSTATUS_TSR 0x00400000 /* since: priv-1.10 */ @@ -416,7 +394,6 @@ #define SSTATUS_SPP 0x00000100 #define SSTATUS_FS 0x00006000 #define SSTATUS_XS 0x00018000 -#define SSTATUS_PUM 0x00040000 /* until: priv-1.9.1 */ #define SSTATUS_SUM 0x00040000 /* since: priv-1.10 */ #define SSTATUS_MXR 0x00080000 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 21c54ef561..503c2559f8 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -136,8 +136,8 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env) env->vscause = env->scause; env->scause = env->scause_hs; - env->vstval = env->sbadaddr; - env->sbadaddr = env->stval_hs; + env->vstval = env->stval; + env->stval = env->stval_hs; env->vsatp = env->satp; env->satp = env->satp_hs; @@ -159,8 +159,8 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env) env->scause_hs = env->scause; env->scause = env->vscause; - env->stval_hs = env->sbadaddr; - env->sbadaddr = env->vstval; + env->stval_hs = env->stval; + env->stval = env->vstval; env->satp_hs = env->satp; env->satp = env->vsatp; @@ -1023,7 +1023,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->mstatus = s; env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1)); env->sepc = env->pc; - env->sbadaddr = tval; + env->stval = tval; env->htval = htval; env->pc = (env->stvec >> 2 << 2) + ((async && (env->stvec & 3) == 1) ? cause * 4 : 0); @@ -1054,7 +1054,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->mstatus = s; env->mcause = cause | ~(((target_ulong)-1) >> async); env->mepc = env->pc; - env->mbadaddr = tval; + env->mtval = tval; env->mtval2 = mtval2; env->pc = (env->mtvec >> 2 << 2) + ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); diff --git a/target/riscv/csr.c b/target/riscv/csr.c index d2585395bf..de7427d8f8 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -644,26 +644,6 @@ static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val) return 0; } -/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */ -static int read_mscounteren(CPURISCVState *env, int csrno, target_ulong *val) -{ - if (env->priv_ver < PRIV_VERSION_1_11_0) { - return -RISCV_EXCP_ILLEGAL_INST; - } - *val = env->mcounteren; - return 0; -} - -/* This regiser is replaced with CSR_MCOUNTINHIBIT in 1.11.0 */ -static int write_mscounteren(CPURISCVState *env, int csrno, target_ulong val) -{ - if (env->priv_ver < PRIV_VERSION_1_11_0) { - return -RISCV_EXCP_ILLEGAL_INST; - } - env->mcounteren = val; - return 0; -} - /* Machine Trap Handling */ static int read_mscratch(CPURISCVState *env, int csrno, target_ulong *val) { @@ -701,15 +681,15 @@ static int write_mcause(CPURISCVState *env, int csrno, target_ulong val) return 0; } -static int read_mbadaddr(CPURISCVState *env, int csrno, target_ulong *val) +static int read_mtval(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mbadaddr; + *val = env->mtval; return 0; } -static int write_mbadaddr(CPURISCVState *env, int csrno, target_ulong val) +static int write_mtval(CPURISCVState *env, int csrno, target_ulong val) { - env->mbadaddr = val; + env->mtval = val; return 0; } @@ -853,15 +833,15 @@ static int write_scause(CPURISCVState *env, int csrno, target_ulong val) return 0; } -static int read_sbadaddr(CPURISCVState *env, int csrno, target_ulong *val) +static int read_stval(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->sbadaddr; + *val = env->stval; return 0; } -static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val) +static int write_stval(CPURISCVState *env, int csrno, target_ulong val) { - env->sbadaddr = val; + env->stval = val; return 0; } @@ -1419,13 +1399,11 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MSTATUSH] = { "mstatush", any32, read_mstatush, write_mstatush }, - [CSR_MSCOUNTEREN] = { "msounteren", any, read_mscounteren, write_mscounteren }, - /* Machine Trap Handling */ [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch }, [CSR_MEPC] = { "mepc", any, read_mepc, write_mepc }, [CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause }, - [CSR_MBADADDR] = { "mbadaddr", any, read_mbadaddr, write_mbadaddr }, + [CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval }, [CSR_MIP] = { "mip", any, NULL, NULL, rmw_mip }, /* Supervisor Trap Setup */ @@ -1438,7 +1416,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch }, [CSR_SEPC] = { "sepc", smode, read_sepc, write_sepc }, [CSR_SCAUSE] = { "scause", smode, read_scause, write_scause }, - [CSR_SBADADDR] = { "sbadaddr", smode, read_sbadaddr, write_sbadaddr }, + [CSR_STVAL] = { "stval", smode, read_stval, write_stval }, [CSR_SIP] = { "sip", smode, NULL, NULL, rmw_sip }, /* Supervisor Protection and Translation */ diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 44d4015bd6..16a08302da 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -140,8 +140,8 @@ static const VMStateDescription vmstate_hyper = { const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32), @@ -165,10 +165,8 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINT32(env.miclaim, RISCVCPU), VMSTATE_UINTTL(env.mie, RISCVCPU), VMSTATE_UINTTL(env.mideleg, RISCVCPU), - VMSTATE_UINTTL(env.sptbr, RISCVCPU), VMSTATE_UINTTL(env.satp, RISCVCPU), - VMSTATE_UINTTL(env.sbadaddr, RISCVCPU), - VMSTATE_UINTTL(env.mbadaddr, RISCVCPU), + VMSTATE_UINTTL(env.stval, RISCVCPU), VMSTATE_UINTTL(env.medeleg, RISCVCPU), VMSTATE_UINTTL(env.stvec, RISCVCPU), VMSTATE_UINTTL(env.sepc, RISCVCPU), diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 2f9f5ccc62..26eccc5eb1 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -116,7 +116,7 @@ static void generate_exception(DisasContext *ctx, int excp) ctx->base.is_jmp = DISAS_NORETURN; } -static void generate_exception_mbadaddr(DisasContext *ctx, int excp) +static void generate_exception_mtval(DisasContext *ctx, int excp) { tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr)); @@ -160,7 +160,7 @@ static void gen_exception_illegal(DisasContext *ctx) static void gen_exception_inst_addr_mis(DisasContext *ctx) { - generate_exception_mbadaddr(ctx, RISCV_EXCP_INST_ADDR_MIS); + generate_exception_mtval(ctx, RISCV_EXCP_INST_ADDR_MIS); } static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) From d00d739b6640b65b46c1dfa0495186cae4e02d89 Mon Sep 17 00:00:00 2001 From: Axel Heider Date: Mon, 22 Mar 2021 19:08:09 +0100 Subject: [PATCH 0421/3028] docs/system/generic-loader.rst: Fix style Fix style to have a proper description of the parameter 'force-raw'. Signed-off-by: Axel Heider Reviewed-by: Alistair Francis Message-id: a7e50a64-1c7c-2d41-96d3-d8a417a659ac@gmx.de Signed-off-by: Alistair Francis --- docs/system/generic-loader.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/system/generic-loader.rst b/docs/system/generic-loader.rst index 6bf8a4eb48..531ddbc8e3 100644 --- a/docs/system/generic-loader.rst +++ b/docs/system/generic-loader.rst @@ -92,9 +92,12 @@ shown below: specified in the executable format header. This option should only be used for the boot image. This will also cause the image to be written to the specified CPU's address space. If not specified, the - default is CPU 0. - Setting force-raw=on forces the file - to be treated as a raw image. This can be used to load supported - executable formats as if they were raw. + default is CPU 0. + +```` + Setting 'force-raw=on' forces the file to be treated as a raw image. + This can be used to load supported executable formats as if they + were raw. All values are parsed using the standard QemuOpts parsing. This allows the user to specify any values in any format supported. By default the values From 01e723bf187974bd2b61cc6e936fa41d44fa16d2 Mon Sep 17 00:00:00 2001 From: Dylan Jhong Date: Mon, 29 Mar 2021 11:48:01 +0800 Subject: [PATCH 0422/3028] target/riscv: Align the data type of reset vector address Use target_ulong to instead of uint64_t on reset vector address to adapt on both 32/64 machine. Signed-off-by: Dylan Jhong Signed-off-by: Ruinland ChuanTzu Tsai Reviewed-by: Bin Meng Reviewed-by: Alistair Francis Message-id: 20210329034801.22667-1-dylan@andestech.com Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 86e7dbeb20..047d6344fe 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -137,7 +137,7 @@ static void set_feature(CPURISCVState *env, int feature) env->features |= (1ULL << feature); } -static void set_resetvec(CPURISCVState *env, int resetvec) +static void set_resetvec(CPURISCVState *env, target_ulong resetvec) { #ifndef CONFIG_USER_ONLY env->resetvec = resetvec; From 3de70cec77d8dffefce257b319580dc58274981f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 31 Mar 2021 18:36:12 +0800 Subject: [PATCH 0423/3028] hw/riscv: sifive_e: Add 'const' to sifive_e_memmap[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was accidentally dropped before. Add it back. Fixes: 732612856a8 ("hw/riscv: Drop 'struct MemmapEntry'") Reported-by: Emmanuel Blot Signed-off-by: Bin Meng Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20210331103612.654261-1-bmeng.cn@gmail.com Signed-off-by: Alistair Francis --- hw/riscv/sifive_e.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 3e8b44b2c0..ddc658c8d6 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -48,7 +48,7 @@ #include "sysemu/arch_init.h" #include "sysemu/sysemu.h" -static MemMapEntry sifive_e_memmap[] = { +static const MemMapEntry sifive_e_memmap[] = { [SIFIVE_E_DEV_DEBUG] = { 0x0, 0x1000 }, [SIFIVE_E_DEV_MROM] = { 0x1000, 0x2000 }, [SIFIVE_E_DEV_OTP] = { 0x20000, 0x2000 }, From 6ddc7069f563e0c01b780123ea0d9f97af55eacf Mon Sep 17 00:00:00 2001 From: Vijai Kumar K Date: Thu, 1 Apr 2021 23:44:54 +0530 Subject: [PATCH 0424/3028] target/riscv: Add Shakti C class CPU C-Class is a member of the SHAKTI family of processors from IIT-M. It is an extremely configurable and commercial-grade 5-stage in-order core supporting the standard RV64GCSUN ISA extensions. Signed-off-by: Vijai Kumar K Reviewed-by: Alistair Francis Message-id: 20210401181457.73039-2-vijai@behindbytes.com Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 1 + target/riscv/cpu.h | 1 + 2 files changed, 2 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 047d6344fe..6842626c69 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -708,6 +708,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_CPU(TYPE_RISCV_CPU_BASE64, rv64_base_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64_sifive_e_cpu_init), DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64_sifive_u_cpu_init), + DEFINE_CPU(TYPE_RISCV_CPU_SHAKTI_C, rv64_sifive_u_cpu_init), #endif }; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 311b1db875..8079da8fa8 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -38,6 +38,7 @@ #define TYPE_RISCV_CPU_BASE32 RISCV_CPU_TYPE_NAME("rv32") #define TYPE_RISCV_CPU_BASE64 RISCV_CPU_TYPE_NAME("rv64") #define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex") +#define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c") #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") #define TYPE_RISCV_CPU_SIFIVE_E34 RISCV_CPU_TYPE_NAME("sifive-e34") #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") From 7a261bafc8ee01294cc709366810798bec4fe2f7 Mon Sep 17 00:00:00 2001 From: Vijai Kumar K Date: Thu, 1 Apr 2021 23:44:55 +0530 Subject: [PATCH 0425/3028] riscv: Add initial support for Shakti C machine Add support for emulating Shakti reference platform based on C-class running on arty-100T board. https://gitlab.com/shaktiproject/cores/shakti-soc/-/blob/master/README.rst Signed-off-by: Vijai Kumar K Reviewed-by: Alistair Francis Message-id: 20210401181457.73039-3-vijai@behindbytes.com [Changes by AF: - Check for mstate->firmware before loading it ] Signed-off-by: Alistair Francis --- MAINTAINERS | 7 + default-configs/devices/riscv64-softmmu.mak | 1 + hw/riscv/Kconfig | 10 ++ hw/riscv/meson.build | 1 + hw/riscv/shakti_c.c | 173 ++++++++++++++++++++ include/hw/riscv/shakti_c.h | 73 +++++++++ 6 files changed, 265 insertions(+) create mode 100644 hw/riscv/shakti_c.c create mode 100644 include/hw/riscv/shakti_c.h diff --git a/MAINTAINERS b/MAINTAINERS index 06642d9799..bfa5adcb1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1415,6 +1415,13 @@ F: include/hw/misc/mchp_pfsoc_dmc.h F: include/hw/misc/mchp_pfsoc_ioscb.h F: include/hw/misc/mchp_pfsoc_sysreg.h +Shakti C class SoC +M: Vijai Kumar K +L: qemu-riscv@nongnu.org +S: Supported +F: hw/riscv/shakti_c.c +F: include/hw/riscv/shakti_c.h + SiFive Machines M: Alistair Francis M: Bin Meng diff --git a/default-configs/devices/riscv64-softmmu.mak b/default-configs/devices/riscv64-softmmu.mak index d5eec75f05..bc69301fa4 100644 --- a/default-configs/devices/riscv64-softmmu.mak +++ b/default-configs/devices/riscv64-softmmu.mak @@ -13,3 +13,4 @@ CONFIG_SIFIVE_E=y CONFIG_SIFIVE_U=y CONFIG_RISCV_VIRT=y CONFIG_MICROCHIP_PFSOC=y +CONFIG_SHAKTI_C=y diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 1de18cdcf1..a0225716b5 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -19,6 +19,16 @@ config OPENTITAN select IBEX select UNIMP +config SHAKTI + bool + +config SHAKTI_C + bool + select UNIMP + select SHAKTI + select SIFIVE_CLINT + select SIFIVE_PLIC + config RISCV_VIRT bool imply PCI_DEVICES diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 275c0f7eb7..a97454661c 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -4,6 +4,7 @@ riscv_ss.add(files('numa.c')) riscv_ss.add(files('riscv_hart.c')) riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c')) riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c')) +riscv_ss.add(when: 'CONFIG_SHAKTI_C', if_true: files('shakti_c.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c')) riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c')) diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c new file mode 100644 index 0000000000..6e6e63d153 --- /dev/null +++ b/hw/riscv/shakti_c.c @@ -0,0 +1,173 @@ +/* + * Shakti C-class SoC emulation + * + * Copyright (c) 2021 Vijai Kumar K + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "hw/boards.h" +#include "hw/riscv/shakti_c.h" +#include "qapi/error.h" +#include "hw/intc/sifive_plic.h" +#include "hw/intc/sifive_clint.h" +#include "sysemu/sysemu.h" +#include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "hw/riscv/boot.h" + + +static const struct MemmapEntry { + hwaddr base; + hwaddr size; +} shakti_c_memmap[] = { + [SHAKTI_C_ROM] = { 0x00001000, 0x2000 }, + [SHAKTI_C_RAM] = { 0x80000000, 0x0 }, + [SHAKTI_C_UART] = { 0x00011300, 0x00040 }, + [SHAKTI_C_GPIO] = { 0x020d0000, 0x00100 }, + [SHAKTI_C_PLIC] = { 0x0c000000, 0x20000 }, + [SHAKTI_C_CLINT] = { 0x02000000, 0xc0000 }, + [SHAKTI_C_I2C] = { 0x20c00000, 0x00100 }, +}; + +static void shakti_c_machine_state_init(MachineState *mstate) +{ + ShaktiCMachineState *sms = RISCV_SHAKTI_MACHINE(mstate); + MemoryRegion *system_memory = get_system_memory(); + MemoryRegion *main_mem = g_new(MemoryRegion, 1); + + /* Allow only Shakti C CPU for this platform */ + if (strcmp(mstate->cpu_type, TYPE_RISCV_CPU_SHAKTI_C) != 0) { + error_report("This board can only be used with Shakti C CPU"); + exit(1); + } + + /* Initialize SoC */ + object_initialize_child(OBJECT(mstate), "soc", &sms->soc, + TYPE_RISCV_SHAKTI_SOC); + qdev_realize(DEVICE(&sms->soc), NULL, &error_abort); + + /* register RAM */ + memory_region_init_ram(main_mem, NULL, "riscv.shakti.c.ram", + mstate->ram_size, &error_fatal); + memory_region_add_subregion(system_memory, + shakti_c_memmap[SHAKTI_C_RAM].base, + main_mem); + + /* ROM reset vector */ + riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus, + shakti_c_memmap[SHAKTI_C_RAM].base, + shakti_c_memmap[SHAKTI_C_ROM].base, + shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0, + NULL); + if (mstate->firmware) { + riscv_load_firmware(mstate->firmware, + shakti_c_memmap[SHAKTI_C_RAM].base, + NULL); + } +} + +static void shakti_c_machine_instance_init(Object *obj) +{ +} + +static void shakti_c_machine_class_init(ObjectClass *klass, void *data) +{ + MachineClass *mc = MACHINE_CLASS(klass); + mc->desc = "RISC-V Board compatible with Shakti SDK"; + mc->init = shakti_c_machine_state_init; + mc->default_cpu_type = TYPE_RISCV_CPU_SHAKTI_C; +} + +static const TypeInfo shakti_c_machine_type_info = { + .name = TYPE_RISCV_SHAKTI_MACHINE, + .parent = TYPE_MACHINE, + .class_init = shakti_c_machine_class_init, + .instance_init = shakti_c_machine_instance_init, + .instance_size = sizeof(ShaktiCMachineState), +}; + +static void shakti_c_machine_type_info_register(void) +{ + type_register_static(&shakti_c_machine_type_info); +} +type_init(shakti_c_machine_type_info_register) + +static void shakti_c_soc_state_realize(DeviceState *dev, Error **errp) +{ + ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(dev); + MemoryRegion *system_memory = get_system_memory(); + + sysbus_realize(SYS_BUS_DEVICE(&sss->cpus), &error_abort); + + sss->plic = sifive_plic_create(shakti_c_memmap[SHAKTI_C_PLIC].base, + (char *)SHAKTI_C_PLIC_HART_CONFIG, 0, + SHAKTI_C_PLIC_NUM_SOURCES, + SHAKTI_C_PLIC_NUM_PRIORITIES, + SHAKTI_C_PLIC_PRIORITY_BASE, + SHAKTI_C_PLIC_PENDING_BASE, + SHAKTI_C_PLIC_ENABLE_BASE, + SHAKTI_C_PLIC_ENABLE_STRIDE, + SHAKTI_C_PLIC_CONTEXT_BASE, + SHAKTI_C_PLIC_CONTEXT_STRIDE, + shakti_c_memmap[SHAKTI_C_PLIC].size); + + sifive_clint_create(shakti_c_memmap[SHAKTI_C_CLINT].base, + shakti_c_memmap[SHAKTI_C_CLINT].size, 0, 1, + SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, + SIFIVE_CLINT_TIMEBASE_FREQ, false); + + /* ROM */ + memory_region_init_rom(&sss->rom, OBJECT(dev), "riscv.shakti.c.rom", + shakti_c_memmap[SHAKTI_C_ROM].size, &error_fatal); + memory_region_add_subregion(system_memory, + shakti_c_memmap[SHAKTI_C_ROM].base, &sss->rom); +} + +static void shakti_c_soc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = shakti_c_soc_state_realize; +} + +static void shakti_c_soc_instance_init(Object *obj) +{ + ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(obj); + + object_initialize_child(obj, "cpus", &sss->cpus, TYPE_RISCV_HART_ARRAY); + + /* + * CPU type is fixed and we are not supporting passing from commandline yet. + * So let it be in instance_init. When supported should use ms->cpu_type + * instead of TYPE_RISCV_CPU_SHAKTI_C + */ + object_property_set_str(OBJECT(&sss->cpus), "cpu-type", + TYPE_RISCV_CPU_SHAKTI_C, &error_abort); + object_property_set_int(OBJECT(&sss->cpus), "num-harts", 1, + &error_abort); +} + +static const TypeInfo shakti_c_type_info = { + .name = TYPE_RISCV_SHAKTI_SOC, + .parent = TYPE_DEVICE, + .class_init = shakti_c_soc_class_init, + .instance_init = shakti_c_soc_instance_init, + .instance_size = sizeof(ShaktiCSoCState), +}; + +static void shakti_c_type_info_register(void) +{ + type_register_static(&shakti_c_type_info); +} +type_init(shakti_c_type_info_register) diff --git a/include/hw/riscv/shakti_c.h b/include/hw/riscv/shakti_c.h new file mode 100644 index 0000000000..8ffc2b0213 --- /dev/null +++ b/include/hw/riscv/shakti_c.h @@ -0,0 +1,73 @@ +/* + * Shakti C-class SoC emulation + * + * Copyright (c) 2021 Vijai Kumar K + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef HW_SHAKTI_H +#define HW_SHAKTI_H + +#include "hw/riscv/riscv_hart.h" +#include "hw/boards.h" + +#define TYPE_RISCV_SHAKTI_SOC "riscv.shakti.cclass.soc" +#define RISCV_SHAKTI_SOC(obj) \ + OBJECT_CHECK(ShaktiCSoCState, (obj), TYPE_RISCV_SHAKTI_SOC) + +typedef struct ShaktiCSoCState { + /*< private >*/ + DeviceState parent_obj; + + /*< public >*/ + RISCVHartArrayState cpus; + DeviceState *plic; + MemoryRegion rom; + +} ShaktiCSoCState; + +#define TYPE_RISCV_SHAKTI_MACHINE MACHINE_TYPE_NAME("shakti_c") +#define RISCV_SHAKTI_MACHINE(obj) \ + OBJECT_CHECK(ShaktiCMachineState, (obj), TYPE_RISCV_SHAKTI_MACHINE) +typedef struct ShaktiCMachineState { + /*< private >*/ + MachineState parent_obj; + + /*< public >*/ + ShaktiCSoCState soc; +} ShaktiCMachineState; + +enum { + SHAKTI_C_ROM, + SHAKTI_C_RAM, + SHAKTI_C_UART, + SHAKTI_C_GPIO, + SHAKTI_C_PLIC, + SHAKTI_C_CLINT, + SHAKTI_C_I2C, +}; + +#define SHAKTI_C_PLIC_HART_CONFIG "MS" +/* Including Interrupt ID 0 (no interrupt)*/ +#define SHAKTI_C_PLIC_NUM_SOURCES 28 +/* Excluding Priority 0 */ +#define SHAKTI_C_PLIC_NUM_PRIORITIES 2 +#define SHAKTI_C_PLIC_PRIORITY_BASE 0x04 +#define SHAKTI_C_PLIC_PENDING_BASE 0x1000 +#define SHAKTI_C_PLIC_ENABLE_BASE 0x2000 +#define SHAKTI_C_PLIC_ENABLE_STRIDE 0x80 +#define SHAKTI_C_PLIC_CONTEXT_BASE 0x200000 +#define SHAKTI_C_PLIC_CONTEXT_STRIDE 0x1000 + +#endif From 07f334d89d47cba59f8f47fdc8f5983234487801 Mon Sep 17 00:00:00 2001 From: Vijai Kumar K Date: Thu, 1 Apr 2021 23:44:56 +0530 Subject: [PATCH 0426/3028] hw/char: Add Shakti UART emulation This is the initial implementation of Shakti UART. Signed-off-by: Vijai Kumar K Reviewed-by: Alistair Francis Message-id: 20210401181457.73039-4-vijai@behindbytes.com Signed-off-by: Alistair Francis --- MAINTAINERS | 2 + hw/char/meson.build | 1 + hw/char/shakti_uart.c | 185 ++++++++++++++++++++++++++++++++++ hw/char/trace-events | 4 + include/hw/char/shakti_uart.h | 74 ++++++++++++++ 5 files changed, 266 insertions(+) create mode 100644 hw/char/shakti_uart.c create mode 100644 include/hw/char/shakti_uart.h diff --git a/MAINTAINERS b/MAINTAINERS index bfa5adcb1a..7aaa304b1e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1420,7 +1420,9 @@ M: Vijai Kumar K L: qemu-riscv@nongnu.org S: Supported F: hw/riscv/shakti_c.c +F: hw/char/shakti_uart.c F: include/hw/riscv/shakti_c.h +F: include/hw/char/shakti_uart.h SiFive Machines M: Alistair Francis diff --git a/hw/char/meson.build b/hw/char/meson.build index da5bb8b762..014833dded 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -19,6 +19,7 @@ softmmu_ss.add(when: 'CONFIG_SERIAL', if_true: files('serial.c')) softmmu_ss.add(when: 'CONFIG_SERIAL_ISA', if_true: files('serial-isa.c')) softmmu_ss.add(when: 'CONFIG_SERIAL_PCI', if_true: files('serial-pci.c')) softmmu_ss.add(when: 'CONFIG_SERIAL_PCI_MULTI', if_true: files('serial-pci-multi.c')) +softmmu_ss.add(when: 'CONFIG_SHAKTI', if_true: files('shakti_uart.c')) softmmu_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console.c')) softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen_console.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c')) diff --git a/hw/char/shakti_uart.c b/hw/char/shakti_uart.c new file mode 100644 index 0000000000..6870821325 --- /dev/null +++ b/hw/char/shakti_uart.c @@ -0,0 +1,185 @@ +/* + * SHAKTI UART + * + * Copyright (c) 2021 Vijai Kumar K + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/char/shakti_uart.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "qemu/log.h" + +static uint64_t shakti_uart_read(void *opaque, hwaddr addr, unsigned size) +{ + ShaktiUartState *s = opaque; + + switch (addr) { + case SHAKTI_UART_BAUD: + return s->uart_baud; + case SHAKTI_UART_RX: + qemu_chr_fe_accept_input(&s->chr); + s->uart_status &= ~SHAKTI_UART_STATUS_RX_NOT_EMPTY; + return s->uart_rx; + case SHAKTI_UART_STATUS: + return s->uart_status; + case SHAKTI_UART_DELAY: + return s->uart_delay; + case SHAKTI_UART_CONTROL: + return s->uart_control; + case SHAKTI_UART_INT_EN: + return s->uart_interrupt; + case SHAKTI_UART_IQ_CYCLES: + return s->uart_iq_cycles; + case SHAKTI_UART_RX_THRES: + return s->uart_rx_threshold; + default: + /* Also handles TX REG which is write only */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } + + return 0; +} + +static void shakti_uart_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + ShaktiUartState *s = opaque; + uint32_t value = data; + uint8_t ch; + + switch (addr) { + case SHAKTI_UART_BAUD: + s->uart_baud = value; + break; + case SHAKTI_UART_TX: + ch = value; + qemu_chr_fe_write_all(&s->chr, &ch, 1); + s->uart_status &= ~SHAKTI_UART_STATUS_TX_FULL; + break; + case SHAKTI_UART_STATUS: + s->uart_status = value; + break; + case SHAKTI_UART_DELAY: + s->uart_delay = value; + break; + case SHAKTI_UART_CONTROL: + s->uart_control = value; + break; + case SHAKTI_UART_INT_EN: + s->uart_interrupt = value; + break; + case SHAKTI_UART_IQ_CYCLES: + s->uart_iq_cycles = value; + break; + case SHAKTI_UART_RX_THRES: + s->uart_rx_threshold = value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); + } +} + +static const MemoryRegionOps shakti_uart_ops = { + .read = shakti_uart_read, + .write = shakti_uart_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = {.min_access_size = 1, .max_access_size = 4}, + .valid = {.min_access_size = 1, .max_access_size = 4}, +}; + +static void shakti_uart_reset(DeviceState *dev) +{ + ShaktiUartState *s = SHAKTI_UART(dev); + + s->uart_baud = SHAKTI_UART_BAUD_DEFAULT; + s->uart_tx = 0x0; + s->uart_rx = 0x0; + s->uart_status = 0x0000; + s->uart_delay = 0x0000; + s->uart_control = SHAKTI_UART_CONTROL_DEFAULT; + s->uart_interrupt = 0x0000; + s->uart_iq_cycles = 0x00; + s->uart_rx_threshold = 0x00; +} + +static int shakti_uart_can_receive(void *opaque) +{ + ShaktiUartState *s = opaque; + + return !(s->uart_status & SHAKTI_UART_STATUS_RX_NOT_EMPTY); +} + +static void shakti_uart_receive(void *opaque, const uint8_t *buf, int size) +{ + ShaktiUartState *s = opaque; + + s->uart_rx = *buf; + s->uart_status |= SHAKTI_UART_STATUS_RX_NOT_EMPTY; +} + +static void shakti_uart_realize(DeviceState *dev, Error **errp) +{ + ShaktiUartState *sus = SHAKTI_UART(dev); + qemu_chr_fe_set_handlers(&sus->chr, shakti_uart_can_receive, + shakti_uart_receive, NULL, NULL, sus, NULL, true); +} + +static void shakti_uart_instance_init(Object *obj) +{ + ShaktiUartState *sus = SHAKTI_UART(obj); + memory_region_init_io(&sus->mmio, + obj, + &shakti_uart_ops, + sus, + TYPE_SHAKTI_UART, + 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &sus->mmio); +} + +static Property shakti_uart_properties[] = { + DEFINE_PROP_CHR("chardev", ShaktiUartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void shakti_uart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = shakti_uart_reset; + dc->realize = shakti_uart_realize; + device_class_set_props(dc, shakti_uart_properties); +} + +static const TypeInfo shakti_uart_info = { + .name = TYPE_SHAKTI_UART, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ShaktiUartState), + .class_init = shakti_uart_class_init, + .instance_init = shakti_uart_instance_init, +}; + +static void shakti_uart_register_types(void) +{ + type_register_static(&shakti_uart_info); +} +type_init(shakti_uart_register_types) diff --git a/hw/char/trace-events b/hw/char/trace-events index 76d52938ea..c8dcade104 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -90,6 +90,10 @@ cmsdk_apb_uart_set_params(int speed) "CMSDK APB UART: params set to %d 8N1" nrf51_uart_read(uint64_t addr, uint64_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u" nrf51_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u" +# shakti_uart.c +shakti_uart_read(uint64_t addr, uint16_t r, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx16 " size %u" +shakti_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%" PRIx64 " value 0x%" PRIx64 " size %u" + # exynos4210_uart.c exynos_uart_dmabusy(uint32_t channel) "UART%d: DMA busy (Rx buffer empty)" exynos_uart_dmaready(uint32_t channel) "UART%d: DMA ready" diff --git a/include/hw/char/shakti_uart.h b/include/hw/char/shakti_uart.h new file mode 100644 index 0000000000..526c408233 --- /dev/null +++ b/include/hw/char/shakti_uart.h @@ -0,0 +1,74 @@ +/* + * SHAKTI UART + * + * Copyright (c) 2021 Vijai Kumar K + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_SHAKTI_UART_H +#define HW_SHAKTI_UART_H + +#include "hw/sysbus.h" +#include "chardev/char-fe.h" + +#define SHAKTI_UART_BAUD 0x00 +#define SHAKTI_UART_TX 0x04 +#define SHAKTI_UART_RX 0x08 +#define SHAKTI_UART_STATUS 0x0C +#define SHAKTI_UART_DELAY 0x10 +#define SHAKTI_UART_CONTROL 0x14 +#define SHAKTI_UART_INT_EN 0x18 +#define SHAKTI_UART_IQ_CYCLES 0x1C +#define SHAKTI_UART_RX_THRES 0x20 + +#define SHAKTI_UART_STATUS_TX_EMPTY (1 << 0) +#define SHAKTI_UART_STATUS_TX_FULL (1 << 1) +#define SHAKTI_UART_STATUS_RX_NOT_EMPTY (1 << 2) +#define SHAKTI_UART_STATUS_RX_FULL (1 << 3) +/* 9600 8N1 is the default setting */ +/* Reg value = (50000000 Hz)/(16 * 9600)*/ +#define SHAKTI_UART_BAUD_DEFAULT 0x0145 +#define SHAKTI_UART_CONTROL_DEFAULT 0x0100 + +#define TYPE_SHAKTI_UART "shakti-uart" +#define SHAKTI_UART(obj) \ + OBJECT_CHECK(ShaktiUartState, (obj), TYPE_SHAKTI_UART) + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + + uint32_t uart_baud; + uint32_t uart_tx; + uint32_t uart_rx; + uint32_t uart_status; + uint32_t uart_delay; + uint32_t uart_control; + uint32_t uart_interrupt; + uint32_t uart_iq_cycles; + uint32_t uart_rx_threshold; + + CharBackend chr; +} ShaktiUartState; + +#endif /* HW_SHAKTI_UART_H */ From 8a2aca3d79f8719b9cf79fdcdfbb89bc6bdb522a Mon Sep 17 00:00:00 2001 From: Vijai Kumar K Date: Thu, 1 Apr 2021 23:44:57 +0530 Subject: [PATCH 0427/3028] hw/riscv: Connect Shakti UART to Shakti platform Connect one shakti uart to the shakti_c machine. Signed-off-by: Vijai Kumar K Reviewed-by: Alistair Francis Message-id: 20210401181457.73039-5-vijai@behindbytes.com Signed-off-by: Alistair Francis --- hw/riscv/shakti_c.c | 8 ++++++++ include/hw/riscv/shakti_c.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c index 6e6e63d153..18f70fadaa 100644 --- a/hw/riscv/shakti_c.c +++ b/hw/riscv/shakti_c.c @@ -128,6 +128,13 @@ static void shakti_c_soc_state_realize(DeviceState *dev, Error **errp) SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, SIFIVE_CLINT_TIMEBASE_FREQ, false); + qdev_prop_set_chr(DEVICE(&(sss->uart)), "chardev", serial_hd(0)); + if (!sysbus_realize(SYS_BUS_DEVICE(&sss->uart), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&sss->uart), 0, + shakti_c_memmap[SHAKTI_C_UART].base); + /* ROM */ memory_region_init_rom(&sss->rom, OBJECT(dev), "riscv.shakti.c.rom", shakti_c_memmap[SHAKTI_C_ROM].size, &error_fatal); @@ -146,6 +153,7 @@ static void shakti_c_soc_instance_init(Object *obj) ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(obj); object_initialize_child(obj, "cpus", &sss->cpus, TYPE_RISCV_HART_ARRAY); + object_initialize_child(obj, "uart", &sss->uart, TYPE_SHAKTI_UART); /* * CPU type is fixed and we are not supporting passing from commandline yet. diff --git a/include/hw/riscv/shakti_c.h b/include/hw/riscv/shakti_c.h index 8ffc2b0213..50a2b79086 100644 --- a/include/hw/riscv/shakti_c.h +++ b/include/hw/riscv/shakti_c.h @@ -21,6 +21,7 @@ #include "hw/riscv/riscv_hart.h" #include "hw/boards.h" +#include "hw/char/shakti_uart.h" #define TYPE_RISCV_SHAKTI_SOC "riscv.shakti.cclass.soc" #define RISCV_SHAKTI_SOC(obj) \ @@ -33,6 +34,7 @@ typedef struct ShaktiCSoCState { /*< public >*/ RISCVHartArrayState cpus; DeviceState *plic; + ShaktiUartState uart; MemoryRegion rom; } ShaktiCSoCState; From 330d2ae32af9a278bc8aa88d598f7750ff27f3dd Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 1 Apr 2021 11:17:29 -0400 Subject: [PATCH 0428/3028] target/riscv: Convert the RISC-V exceptions to an enum Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Reviewed-by: Richard Henderson Message-id: f191dcf08bf413a822e743a7c7f824d68879a527.1617290165.git.alistair.francis@wdc.com --- target/riscv/cpu.c | 2 +- target/riscv/cpu_bits.h | 44 ++++++++++++++++++++------------------- target/riscv/cpu_helper.c | 4 ++-- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 6842626c69..e530df9385 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -358,7 +358,7 @@ static void riscv_cpu_reset(DeviceState *dev) env->pc = env->resetvec; env->two_stage_lookup = false; #endif - cs->exception_index = EXCP_NONE; + cs->exception_index = RISCV_EXCP_NONE; env->load_res = -1; set_default_nan_mode(1, &env->fp_status); } diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index b42dd4f8d8..8549d77b4f 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -504,27 +504,29 @@ #define DEFAULT_RSTVEC 0x1000 /* Exception causes */ -#define EXCP_NONE -1 /* sentinel value */ -#define RISCV_EXCP_INST_ADDR_MIS 0x0 -#define RISCV_EXCP_INST_ACCESS_FAULT 0x1 -#define RISCV_EXCP_ILLEGAL_INST 0x2 -#define RISCV_EXCP_BREAKPOINT 0x3 -#define RISCV_EXCP_LOAD_ADDR_MIS 0x4 -#define RISCV_EXCP_LOAD_ACCESS_FAULT 0x5 -#define RISCV_EXCP_STORE_AMO_ADDR_MIS 0x6 -#define RISCV_EXCP_STORE_AMO_ACCESS_FAULT 0x7 -#define RISCV_EXCP_U_ECALL 0x8 -#define RISCV_EXCP_S_ECALL 0x9 -#define RISCV_EXCP_VS_ECALL 0xa -#define RISCV_EXCP_M_ECALL 0xb -#define RISCV_EXCP_INST_PAGE_FAULT 0xc /* since: priv-1.10.0 */ -#define RISCV_EXCP_LOAD_PAGE_FAULT 0xd /* since: priv-1.10.0 */ -#define RISCV_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */ -#define RISCV_EXCP_SEMIHOST 0x10 -#define RISCV_EXCP_INST_GUEST_PAGE_FAULT 0x14 -#define RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT 0x15 -#define RISCV_EXCP_VIRT_INSTRUCTION_FAULT 0x16 -#define RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT 0x17 +typedef enum RISCVException { + RISCV_EXCP_NONE = -1, /* sentinel value */ + RISCV_EXCP_INST_ADDR_MIS = 0x0, + RISCV_EXCP_INST_ACCESS_FAULT = 0x1, + RISCV_EXCP_ILLEGAL_INST = 0x2, + RISCV_EXCP_BREAKPOINT = 0x3, + RISCV_EXCP_LOAD_ADDR_MIS = 0x4, + RISCV_EXCP_LOAD_ACCESS_FAULT = 0x5, + RISCV_EXCP_STORE_AMO_ADDR_MIS = 0x6, + RISCV_EXCP_STORE_AMO_ACCESS_FAULT = 0x7, + RISCV_EXCP_U_ECALL = 0x8, + RISCV_EXCP_S_ECALL = 0x9, + RISCV_EXCP_VS_ECALL = 0xa, + RISCV_EXCP_M_ECALL = 0xb, + RISCV_EXCP_INST_PAGE_FAULT = 0xc, /* since: priv-1.10.0 */ + RISCV_EXCP_LOAD_PAGE_FAULT = 0xd, /* since: priv-1.10.0 */ + RISCV_EXCP_STORE_PAGE_FAULT = 0xf, /* since: priv-1.10.0 */ + RISCV_EXCP_SEMIHOST = 0x10, + RISCV_EXCP_INST_GUEST_PAGE_FAULT = 0x14, + RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT = 0x15, + RISCV_EXCP_VIRT_INSTRUCTION_FAULT = 0x16, + RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT = 0x17, +} RISCVException; #define RISCV_EXCP_INT_FLAG 0x80000000 #define RISCV_EXCP_INT_MASK 0x7fffffff diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 503c2559f8..99cc388db9 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -72,7 +72,7 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env) if (irqs) { return ctz64(irqs); /* since non-zero */ } else { - return EXCP_NONE; /* indicates no pending interrupt */ + return RISCV_EXCP_NONE; /* indicates no pending interrupt */ } } #endif @@ -1069,5 +1069,5 @@ void riscv_cpu_do_interrupt(CPUState *cs) env->two_stage_lookup = false; #endif - cs->exception_index = EXCP_NONE; /* mark handled to qemu */ + cs->exception_index = RISCV_EXCP_NONE; /* mark handled to qemu */ } From 0e62f92eac4b906bda29e64ea8a8c1e72df0d302 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 1 Apr 2021 11:17:39 -0400 Subject: [PATCH 0429/3028] target/riscv: Use the RISCVException enum for CSR predicates Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Bin Meng Message-id: 187261fa671c3a77cf5aa482adb2a558c02a7cad.1617290165.git.alistair.francis@wdc.com --- target/riscv/cpu.h | 3 +- target/riscv/csr.c | 80 +++++++++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 37 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 8079da8fa8..1dd42a6bc1 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -472,7 +472,8 @@ static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno) return val; } -typedef int (*riscv_csr_predicate_fn)(CPURISCVState *env, int csrno); +typedef RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env, + int csrno); typedef int (*riscv_csr_read_fn)(CPURISCVState *env, int csrno, target_ulong *ret_value); typedef int (*riscv_csr_write_fn)(CPURISCVState *env, int csrno, diff --git a/target/riscv/csr.c b/target/riscv/csr.c index de7427d8f8..1938bdca7d 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -35,29 +35,29 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops) } /* Predicates */ -static int fs(CPURISCVState *env, int csrno) +static RISCVException fs(CPURISCVState *env, int csrno) { #if !defined(CONFIG_USER_ONLY) /* loose check condition for fcsr in vector extension */ if ((csrno == CSR_FCSR) && (env->misa & RVV)) { - return 0; + return RISCV_EXCP_NONE; } if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } #endif - return 0; + return RISCV_EXCP_NONE; } -static int vs(CPURISCVState *env, int csrno) +static RISCVException vs(CPURISCVState *env, int csrno) { if (env->misa & RVV) { - return 0; + return RISCV_EXCP_NONE; } - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } -static int ctr(CPURISCVState *env, int csrno) +static RISCVException ctr(CPURISCVState *env, int csrno) { #if !defined(CONFIG_USER_ONLY) CPUState *cs = env_cpu(env); @@ -65,7 +65,7 @@ static int ctr(CPURISCVState *env, int csrno) if (!cpu->cfg.ext_counters) { /* The Counters extensions is not enabled */ - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } if (riscv_cpu_virt_enabled(env)) { @@ -73,25 +73,25 @@ static int ctr(CPURISCVState *env, int csrno) case CSR_CYCLE: if (!get_field(env->hcounteren, HCOUNTEREN_CY) && get_field(env->mcounteren, HCOUNTEREN_CY)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_TIME: if (!get_field(env->hcounteren, HCOUNTEREN_TM) && get_field(env->mcounteren, HCOUNTEREN_TM)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_INSTRET: if (!get_field(env->hcounteren, HCOUNTEREN_IR) && get_field(env->mcounteren, HCOUNTEREN_IR)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31: if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3)) && get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3))) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; } @@ -100,93 +100,101 @@ static int ctr(CPURISCVState *env, int csrno) case CSR_CYCLEH: if (!get_field(env->hcounteren, HCOUNTEREN_CY) && get_field(env->mcounteren, HCOUNTEREN_CY)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_TIMEH: if (!get_field(env->hcounteren, HCOUNTEREN_TM) && get_field(env->mcounteren, HCOUNTEREN_TM)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_INSTRETH: if (!get_field(env->hcounteren, HCOUNTEREN_IR) && get_field(env->mcounteren, HCOUNTEREN_IR)) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H: if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3H)) && get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3H))) { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } break; } } } #endif - return 0; + return RISCV_EXCP_NONE; } -static int ctr32(CPURISCVState *env, int csrno) +static RISCVException ctr32(CPURISCVState *env, int csrno) { if (!riscv_cpu_is_32bit(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } return ctr(env, csrno); } #if !defined(CONFIG_USER_ONLY) -static int any(CPURISCVState *env, int csrno) +static RISCVException any(CPURISCVState *env, int csrno) { - return 0; + return RISCV_EXCP_NONE; } -static int any32(CPURISCVState *env, int csrno) +static RISCVException any32(CPURISCVState *env, int csrno) { if (!riscv_cpu_is_32bit(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } return any(env, csrno); } -static int smode(CPURISCVState *env, int csrno) +static RISCVException smode(CPURISCVState *env, int csrno) { - return -!riscv_has_ext(env, RVS); + if (riscv_has_ext(env, RVS)) { + return RISCV_EXCP_NONE; + } + + return RISCV_EXCP_ILLEGAL_INST; } -static int hmode(CPURISCVState *env, int csrno) +static RISCVException hmode(CPURISCVState *env, int csrno) { if (riscv_has_ext(env, RVS) && riscv_has_ext(env, RVH)) { /* Hypervisor extension is supported */ if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) || env->priv == PRV_M) { - return 0; + return RISCV_EXCP_NONE; } else { - return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } } - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } -static int hmode32(CPURISCVState *env, int csrno) +static RISCVException hmode32(CPURISCVState *env, int csrno) { if (!riscv_cpu_is_32bit(env)) { - return 0; + return RISCV_EXCP_NONE; } return hmode(env, csrno); } -static int pmp(CPURISCVState *env, int csrno) +static RISCVException pmp(CPURISCVState *env, int csrno) { - return -!riscv_feature(env, RISCV_FEATURE_PMP); + if (riscv_feature(env, RISCV_FEATURE_PMP)) { + return RISCV_EXCP_NONE; + } + + return RISCV_EXCP_ILLEGAL_INST; } #endif @@ -1293,8 +1301,8 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, return -RISCV_EXCP_ILLEGAL_INST; } ret = csr_ops[csrno].predicate(env, csrno); - if (ret < 0) { - return ret; + if (ret != RISCV_EXCP_NONE) { + return -ret; } /* execute combined read/write operation if it exists */ From d6f20dacea5147a9136ec3ecc7124440c16ba862 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 1 Apr 2021 11:17:48 -0400 Subject: [PATCH 0430/3028] target/riscv: Fix 32-bit HS mode access permissions Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Bin Meng Message-id: cb1ef2061547dc9028ce3cf4f6622588f9c09149.1617290165.git.alistair.francis@wdc.com --- target/riscv/csr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 1938bdca7d..6a39c4aa96 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -181,7 +181,11 @@ static RISCVException hmode(CPURISCVState *env, int csrno) static RISCVException hmode32(CPURISCVState *env, int csrno) { if (!riscv_cpu_is_32bit(env)) { - return RISCV_EXCP_NONE; + if (riscv_cpu_virt_enabled(env)) { + return RISCV_EXCP_ILLEGAL_INST; + } else { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } } return hmode(env, csrno); From 605def6eeee5e4b6293963aa86be6e637e48bfb3 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 1 Apr 2021 11:17:57 -0400 Subject: [PATCH 0431/3028] target/riscv: Use the RISCVException enum for CSR operations Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Bin Meng Message-id: 8566c4c271723f27f3ae8fc2429f906a459f17ce.1617290165.git.alistair.francis@wdc.com --- target/riscv/cpu.h | 14 +- target/riscv/csr.c | 629 +++++++++++++++++++++++++++------------------ 2 files changed, 382 insertions(+), 261 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 1dd42a6bc1..a7b8876ea0 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -474,12 +474,14 @@ static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno) typedef RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env, int csrno); -typedef int (*riscv_csr_read_fn)(CPURISCVState *env, int csrno, - target_ulong *ret_value); -typedef int (*riscv_csr_write_fn)(CPURISCVState *env, int csrno, - target_ulong new_value); -typedef int (*riscv_csr_op_fn)(CPURISCVState *env, int csrno, - target_ulong *ret_value, target_ulong new_value, target_ulong write_mask); +typedef RISCVException (*riscv_csr_read_fn)(CPURISCVState *env, int csrno, + target_ulong *ret_value); +typedef RISCVException (*riscv_csr_write_fn)(CPURISCVState *env, int csrno, + target_ulong new_value); +typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, + target_ulong write_mask); typedef struct { const char *name; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 6a39c4aa96..f67eaf4042 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -203,57 +203,62 @@ static RISCVException pmp(CPURISCVState *env, int csrno) #endif /* User Floating-Point CSRs */ -static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_fflags(CPURISCVState *env, int csrno, + target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } #endif *val = riscv_cpu_get_fflags(env); - return 0; + return RISCV_EXCP_NONE; } -static int write_fflags(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_fflags(CPURISCVState *env, int csrno, + target_ulong val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } env->mstatus |= MSTATUS_FS; #endif riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT)); - return 0; + return RISCV_EXCP_NONE; } -static int read_frm(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_frm(CPURISCVState *env, int csrno, + target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } #endif *val = env->frm; - return 0; + return RISCV_EXCP_NONE; } -static int write_frm(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_frm(CPURISCVState *env, int csrno, + target_ulong val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } env->mstatus |= MSTATUS_FS; #endif env->frm = val & (FSR_RD >> FSR_RD_SHIFT); - return 0; + return RISCV_EXCP_NONE; } -static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_fcsr(CPURISCVState *env, int csrno, + target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } #endif *val = (riscv_cpu_get_fflags(env) << FSR_AEXC_SHIFT) @@ -262,14 +267,15 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val) *val |= (env->vxrm << FSR_VXRM_SHIFT) | (env->vxsat << FSR_VXSAT_SHIFT); } - return 0; + return RISCV_EXCP_NONE; } -static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_fcsr(CPURISCVState *env, int csrno, + target_ulong val) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_fp_enabled(env)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } env->mstatus |= MSTATUS_FS; #endif @@ -279,59 +285,68 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val) env->vxsat = (val & FSR_VXSAT) >> FSR_VXSAT_SHIFT; } riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT); - return 0; + return RISCV_EXCP_NONE; } -static int read_vtype(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vtype(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vtype; - return 0; + return RISCV_EXCP_NONE; } -static int read_vl(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vl(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vl; - return 0; + return RISCV_EXCP_NONE; } -static int read_vxrm(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vxrm(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vxrm; - return 0; + return RISCV_EXCP_NONE; } -static int write_vxrm(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vxrm(CPURISCVState *env, int csrno, + target_ulong val) { env->vxrm = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vxsat(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vxsat(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vxsat; - return 0; + return RISCV_EXCP_NONE; } -static int write_vxsat(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vxsat(CPURISCVState *env, int csrno, + target_ulong val) { env->vxsat = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vstart(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vstart(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vstart; - return 0; + return RISCV_EXCP_NONE; } -static int write_vstart(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vstart(CPURISCVState *env, int csrno, + target_ulong val) { env->vstart = val; - return 0; + return RISCV_EXCP_NONE; } /* User Timers and Counters */ -static int read_instret(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_instret(CPURISCVState *env, int csrno, + target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (icount_enabled()) { @@ -342,10 +357,11 @@ static int read_instret(CPURISCVState *env, int csrno, target_ulong *val) #else *val = cpu_get_host_ticks(); #endif - return 0; + return RISCV_EXCP_NONE; } -static int read_instreth(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_instreth(CPURISCVState *env, int csrno, + target_ulong *val) { #if !defined(CONFIG_USER_ONLY) if (icount_enabled()) { @@ -356,46 +372,50 @@ static int read_instreth(CPURISCVState *env, int csrno, target_ulong *val) #else *val = cpu_get_host_ticks() >> 32; #endif - return 0; + return RISCV_EXCP_NONE; } #if defined(CONFIG_USER_ONLY) -static int read_time(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_time(CPURISCVState *env, int csrno, + target_ulong *val) { *val = cpu_get_host_ticks(); - return 0; + return RISCV_EXCP_NONE; } -static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_timeh(CPURISCVState *env, int csrno, + target_ulong *val) { *val = cpu_get_host_ticks() >> 32; - return 0; + return RISCV_EXCP_NONE; } #else /* CONFIG_USER_ONLY */ -static int read_time(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_time(CPURISCVState *env, int csrno, + target_ulong *val) { uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; if (!env->rdtime_fn) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } *val = env->rdtime_fn(env->rdtime_fn_arg) + delta; - return 0; + return RISCV_EXCP_NONE; } -static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_timeh(CPURISCVState *env, int csrno, + target_ulong *val) { uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0; if (!env->rdtime_fn) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } *val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32; - return 0; + return RISCV_EXCP_NONE; } /* Machine constants */ @@ -449,22 +469,26 @@ static const char valid_vm_1_10_64[16] = { }; /* Machine Information Registers */ -static int read_zero(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_zero(CPURISCVState *env, int csrno, + target_ulong *val) { - return *val = 0; + *val = 0; + return RISCV_EXCP_NONE; } -static int read_mhartid(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mhartid(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mhartid; - return 0; + return RISCV_EXCP_NONE; } /* Machine Trap Setup */ -static int read_mstatus(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mstatus(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mstatus; - return 0; + return RISCV_EXCP_NONE; } static int validate_vm(CPURISCVState *env, target_ulong vm) @@ -476,7 +500,8 @@ static int validate_vm(CPURISCVState *env, target_ulong vm) } } -static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mstatus(CPURISCVState *env, int csrno, + target_ulong val) { uint64_t mstatus = env->mstatus; uint64_t mask = 0; @@ -507,16 +532,18 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val) mstatus = set_field(mstatus, MSTATUS_SD, dirty); env->mstatus = mstatus; - return 0; + return RISCV_EXCP_NONE; } -static int read_mstatush(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mstatush(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mstatus >> 32; - return 0; + return RISCV_EXCP_NONE; } -static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mstatush(CPURISCVState *env, int csrno, + target_ulong val) { uint64_t valh = (uint64_t)val << 32; uint64_t mask = MSTATUS_MPV | MSTATUS_GVA; @@ -527,26 +554,28 @@ static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val) env->mstatus = (env->mstatus & ~mask) | (valh & mask); - return 0; + return RISCV_EXCP_NONE; } -static int read_misa(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_misa(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->misa; - return 0; + return RISCV_EXCP_NONE; } -static int write_misa(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_misa(CPURISCVState *env, int csrno, + target_ulong val) { if (!riscv_feature(env, RISCV_FEATURE_MISA)) { /* drop write to misa */ - return 0; + return RISCV_EXCP_NONE; } /* 'I' or 'E' must be present */ if (!(val & (RVI | RVE))) { /* It is not, drop write to misa */ - return 0; + return RISCV_EXCP_NONE; } /* 'E' excludes all other extensions */ @@ -554,7 +583,7 @@ static int write_misa(CPURISCVState *env, int csrno, target_ulong val) /* when we support 'E' we can do "val = RVE;" however * for now we just drop writes if 'E' is present. */ - return 0; + return RISCV_EXCP_NONE; } /* Mask extensions that are not supported by this hart */ @@ -585,55 +614,63 @@ static int write_misa(CPURISCVState *env, int csrno, target_ulong val) env->misa = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_medeleg(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_medeleg(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->medeleg; - return 0; + return RISCV_EXCP_NONE; } -static int write_medeleg(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_medeleg(CPURISCVState *env, int csrno, + target_ulong val) { env->medeleg = (env->medeleg & ~delegable_excps) | (val & delegable_excps); - return 0; + return RISCV_EXCP_NONE; } -static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mideleg(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mideleg; - return 0; + return RISCV_EXCP_NONE; } -static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mideleg(CPURISCVState *env, int csrno, + target_ulong val) { env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints); if (riscv_has_ext(env, RVH)) { env->mideleg |= VS_MODE_INTERRUPTS; } - return 0; + return RISCV_EXCP_NONE; } -static int read_mie(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mie(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mie; - return 0; + return RISCV_EXCP_NONE; } -static int write_mie(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mie(CPURISCVState *env, int csrno, + target_ulong val) { env->mie = (env->mie & ~all_ints) | (val & all_ints); - return 0; + return RISCV_EXCP_NONE; } -static int read_mtvec(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mtvec(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mtvec; - return 0; + return RISCV_EXCP_NONE; } -static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mtvec(CPURISCVState *env, int csrno, + target_ulong val) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ if ((val & 3) < 2) { @@ -641,72 +678,83 @@ static int write_mtvec(CPURISCVState *env, int csrno, target_ulong val) } else { qemu_log_mask(LOG_UNIMP, "CSR_MTVEC: reserved mode not supported\n"); } - return 0; + return RISCV_EXCP_NONE; } -static int read_mcounteren(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mcounteren(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mcounteren; - return 0; + return RISCV_EXCP_NONE; } -static int write_mcounteren(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mcounteren(CPURISCVState *env, int csrno, + target_ulong val) { env->mcounteren = val; - return 0; + return RISCV_EXCP_NONE; } /* Machine Trap Handling */ -static int read_mscratch(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mscratch(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mscratch; - return 0; + return RISCV_EXCP_NONE; } -static int write_mscratch(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mscratch(CPURISCVState *env, int csrno, + target_ulong val) { env->mscratch = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_mepc(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mepc(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mepc; - return 0; + return RISCV_EXCP_NONE; } -static int write_mepc(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mepc(CPURISCVState *env, int csrno, + target_ulong val) { env->mepc = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_mcause(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mcause(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mcause; - return 0; + return RISCV_EXCP_NONE; } -static int write_mcause(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mcause(CPURISCVState *env, int csrno, + target_ulong val) { env->mcause = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_mtval(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mtval(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mtval; - return 0; + return RISCV_EXCP_NONE; } -static int write_mtval(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mtval(CPURISCVState *env, int csrno, + target_ulong val) { env->mtval = val; - return 0; + return RISCV_EXCP_NONE; } -static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_mip(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) { RISCVCPU *cpu = env_archcpu(env); /* Allow software control of delegable interrupts not claimed by hardware */ @@ -723,42 +771,47 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, *ret_value = old_mip; } - return 0; + return RISCV_EXCP_NONE; } /* Supervisor Trap Setup */ -static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_sstatus(CPURISCVState *env, int csrno, + target_ulong *val) { target_ulong mask = (sstatus_v1_10_mask); *val = env->mstatus & mask; - return 0; + return RISCV_EXCP_NONE; } -static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_sstatus(CPURISCVState *env, int csrno, + target_ulong val) { target_ulong mask = (sstatus_v1_10_mask); target_ulong newval = (env->mstatus & ~mask) | (val & mask); return write_mstatus(env, CSR_MSTATUS, newval); } -static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vsie(CPURISCVState *env, int csrno, + target_ulong *val) { /* Shift the VS bits to their S bit location in vsie */ *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1; - return 0; + return RISCV_EXCP_NONE; } -static int read_sie(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_sie(CPURISCVState *env, int csrno, + target_ulong *val) { if (riscv_cpu_virt_enabled(env)) { read_vsie(env, CSR_VSIE, val); } else { *val = env->mie & env->mideleg; } - return 0; + return RISCV_EXCP_NONE; } -static int write_vsie(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vsie(CPURISCVState *env, int csrno, + target_ulong val) { /* Shift the S bits to their VS bit location in mie */ target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | @@ -776,16 +829,18 @@ static int write_sie(CPURISCVState *env, int csrno, target_ulong val) write_mie(env, CSR_MIE, newval); } - return 0; + return RISCV_EXCP_NONE; } -static int read_stvec(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_stvec(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->stvec; - return 0; + return RISCV_EXCP_NONE; } -static int write_stvec(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_stvec(CPURISCVState *env, int csrno, + target_ulong val) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ if ((val & 3) < 2) { @@ -793,72 +848,83 @@ static int write_stvec(CPURISCVState *env, int csrno, target_ulong val) } else { qemu_log_mask(LOG_UNIMP, "CSR_STVEC: reserved mode not supported\n"); } - return 0; + return RISCV_EXCP_NONE; } -static int read_scounteren(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_scounteren(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->scounteren; - return 0; + return RISCV_EXCP_NONE; } -static int write_scounteren(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_scounteren(CPURISCVState *env, int csrno, + target_ulong val) { env->scounteren = val; - return 0; + return RISCV_EXCP_NONE; } /* Supervisor Trap Handling */ -static int read_sscratch(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_sscratch(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->sscratch; - return 0; + return RISCV_EXCP_NONE; } -static int write_sscratch(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_sscratch(CPURISCVState *env, int csrno, + target_ulong val) { env->sscratch = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_sepc(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_sepc(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->sepc; - return 0; + return RISCV_EXCP_NONE; } -static int write_sepc(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_sepc(CPURISCVState *env, int csrno, + target_ulong val) { env->sepc = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_scause(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_scause(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->scause; - return 0; + return RISCV_EXCP_NONE; } -static int write_scause(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_scause(CPURISCVState *env, int csrno, + target_ulong val) { env->scause = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_stval(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_stval(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->stval; - return 0; + return RISCV_EXCP_NONE; } -static int write_stval(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_stval(CPURISCVState *env, int csrno, + target_ulong val) { env->stval = val; - return 0; + return RISCV_EXCP_NONE; } -static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_vsip(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) { /* Shift the S bits to their VS bit location in mip */ int ret = rmw_mip(env, 0, ret_value, new_value << 1, @@ -869,8 +935,9 @@ static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, return ret; } -static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_sip(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) { int ret; @@ -886,32 +953,34 @@ static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, } /* Supervisor Protection and Translation */ -static int read_satp(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_satp(CPURISCVState *env, int csrno, + target_ulong *val) { if (!riscv_feature(env, RISCV_FEATURE_MMU)) { *val = 0; - return 0; + return RISCV_EXCP_NONE; } if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } else { *val = env->satp; } - return 0; + return RISCV_EXCP_NONE; } -static int write_satp(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_satp(CPURISCVState *env, int csrno, + target_ulong val) { if (!riscv_feature(env, RISCV_FEATURE_MMU)) { - return 0; + return RISCV_EXCP_NONE; } if (validate_vm(env, get_field(val, SATP_MODE)) && ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN))) { if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } else { if ((val ^ env->satp) & SATP_ASID) { tlb_flush(env_cpu(env)); @@ -919,11 +988,12 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) env->satp = val; } } - return 0; + return RISCV_EXCP_NONE; } /* Hypervisor Extensions */ -static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hstatus(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hstatus; if (!riscv_cpu_is_32bit(env)) { @@ -932,10 +1002,11 @@ static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) } /* We only support little endian */ *val = set_field(*val, HSTATUS_VSBE, 0); - return 0; + return RISCV_EXCP_NONE; } -static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hstatus(CPURISCVState *env, int csrno, + target_ulong val) { env->hstatus = val; if (!riscv_cpu_is_32bit(env) && get_field(val, HSTATUS_VSXL) != 2) { @@ -944,35 +1015,40 @@ static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val) if (get_field(val, HSTATUS_VSBE) != 0) { qemu_log_mask(LOG_UNIMP, "QEMU does not support big endian guests."); } - return 0; + return RISCV_EXCP_NONE; } -static int read_hedeleg(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hedeleg(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hedeleg; - return 0; + return RISCV_EXCP_NONE; } -static int write_hedeleg(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hedeleg(CPURISCVState *env, int csrno, + target_ulong val) { env->hedeleg = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_hideleg(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hideleg(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hideleg; - return 0; + return RISCV_EXCP_NONE; } -static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hideleg(CPURISCVState *env, int csrno, + target_ulong val) { env->hideleg = val; - return 0; + return RISCV_EXCP_NONE; } -static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_hvip(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) { int ret = rmw_mip(env, 0, ret_value, new_value, write_mask & hvip_writable_mask); @@ -982,8 +1058,9 @@ static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value, return ret; } -static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_hip(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) { int ret = rmw_mip(env, 0, ret_value, new_value, write_mask & hip_writable_mask); @@ -993,103 +1070,119 @@ static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value, return ret; } -static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hie(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mie & VS_MODE_INTERRUPTS; - return 0; + return RISCV_EXCP_NONE; } -static int write_hie(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hie(CPURISCVState *env, int csrno, + target_ulong val) { target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS); return write_mie(env, CSR_MIE, newval); } -static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hcounteren(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hcounteren; - return 0; + return RISCV_EXCP_NONE; } -static int write_hcounteren(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hcounteren(CPURISCVState *env, int csrno, + target_ulong val) { env->hcounteren = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_hgeie(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hgeie(CPURISCVState *env, int csrno, + target_ulong *val) { qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); - return 0; + return RISCV_EXCP_NONE; } -static int write_hgeie(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hgeie(CPURISCVState *env, int csrno, + target_ulong val) { qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); - return 0; + return RISCV_EXCP_NONE; } -static int read_htval(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_htval(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->htval; - return 0; + return RISCV_EXCP_NONE; } -static int write_htval(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_htval(CPURISCVState *env, int csrno, + target_ulong val) { env->htval = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_htinst(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_htinst(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->htinst; - return 0; + return RISCV_EXCP_NONE; } -static int write_htinst(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_htinst(CPURISCVState *env, int csrno, + target_ulong val) { - return 0; + return RISCV_EXCP_NONE; } -static int read_hgeip(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hgeip(CPURISCVState *env, int csrno, + target_ulong *val) { qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); - return 0; + return RISCV_EXCP_NONE; } -static int write_hgeip(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hgeip(CPURISCVState *env, int csrno, + target_ulong val) { qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); - return 0; + return RISCV_EXCP_NONE; } -static int read_hgatp(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_hgatp(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->hgatp; - return 0; + return RISCV_EXCP_NONE; } -static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_hgatp(CPURISCVState *env, int csrno, + target_ulong val) { env->hgatp = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_htimedelta(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_htimedelta(CPURISCVState *env, int csrno, + target_ulong *val) { if (!env->rdtime_fn) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } *val = env->htimedelta; - return 0; + return RISCV_EXCP_NONE; } -static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_htimedelta(CPURISCVState *env, int csrno, + target_ulong val) { if (!env->rdtime_fn) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } if (riscv_cpu_is_32bit(env)) { @@ -1097,162 +1190,185 @@ static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val) } else { env->htimedelta = val; } - return 0; + return RISCV_EXCP_NONE; } -static int read_htimedeltah(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_htimedeltah(CPURISCVState *env, int csrno, + target_ulong *val) { if (!env->rdtime_fn) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } *val = env->htimedelta >> 32; - return 0; + return RISCV_EXCP_NONE; } -static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_htimedeltah(CPURISCVState *env, int csrno, + target_ulong val) { if (!env->rdtime_fn) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val); - return 0; + return RISCV_EXCP_NONE; } /* Virtual CSR Registers */ -static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vsstatus(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vsstatus; - return 0; + return RISCV_EXCP_NONE; } -static int write_vsstatus(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vsstatus(CPURISCVState *env, int csrno, + target_ulong val) { uint64_t mask = (target_ulong)-1; env->vsstatus = (env->vsstatus & ~mask) | (uint64_t)val; - return 0; + return RISCV_EXCP_NONE; } static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val) { *val = env->vstvec; - return 0; + return RISCV_EXCP_NONE; } -static int write_vstvec(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vstvec(CPURISCVState *env, int csrno, + target_ulong val) { env->vstvec = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vsscratch(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vsscratch(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vsscratch; - return 0; + return RISCV_EXCP_NONE; } -static int write_vsscratch(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vsscratch(CPURISCVState *env, int csrno, + target_ulong val) { env->vsscratch = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vsepc(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vsepc(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vsepc; - return 0; + return RISCV_EXCP_NONE; } -static int write_vsepc(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vsepc(CPURISCVState *env, int csrno, + target_ulong val) { env->vsepc = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vscause(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vscause(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vscause; - return 0; + return RISCV_EXCP_NONE; } -static int write_vscause(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vscause(CPURISCVState *env, int csrno, + target_ulong val) { env->vscause = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vstval(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vstval(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vstval; - return 0; + return RISCV_EXCP_NONE; } -static int write_vstval(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vstval(CPURISCVState *env, int csrno, + target_ulong val) { env->vstval = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_vsatp(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_vsatp(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->vsatp; - return 0; + return RISCV_EXCP_NONE; } -static int write_vsatp(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_vsatp(CPURISCVState *env, int csrno, + target_ulong val) { env->vsatp = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_mtval2(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mtval2(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mtval2; - return 0; + return RISCV_EXCP_NONE; } -static int write_mtval2(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mtval2(CPURISCVState *env, int csrno, + target_ulong val) { env->mtval2 = val; - return 0; + return RISCV_EXCP_NONE; } -static int read_mtinst(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mtinst(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mtinst; - return 0; + return RISCV_EXCP_NONE; } -static int write_mtinst(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mtinst(CPURISCVState *env, int csrno, + target_ulong val) { env->mtinst = val; - return 0; + return RISCV_EXCP_NONE; } /* Physical Memory Protection */ -static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_pmpcfg(CPURISCVState *env, int csrno, + target_ulong *val) { *val = pmpcfg_csr_read(env, csrno - CSR_PMPCFG0); - return 0; + return RISCV_EXCP_NONE; } -static int write_pmpcfg(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_pmpcfg(CPURISCVState *env, int csrno, + target_ulong val) { pmpcfg_csr_write(env, csrno - CSR_PMPCFG0, val); - return 0; + return RISCV_EXCP_NONE; } -static int read_pmpaddr(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_pmpaddr(CPURISCVState *env, int csrno, + target_ulong *val) { *val = pmpaddr_csr_read(env, csrno - CSR_PMPADDR0); - return 0; + return RISCV_EXCP_NONE; } -static int write_pmpaddr(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_pmpaddr(CPURISCVState *env, int csrno, + target_ulong val) { pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val); - return 0; + return RISCV_EXCP_NONE; } #endif @@ -1311,18 +1427,21 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, /* execute combined read/write operation if it exists */ if (csr_ops[csrno].op) { - return csr_ops[csrno].op(env, csrno, ret_value, new_value, write_mask); + ret = csr_ops[csrno].op(env, csrno, ret_value, new_value, write_mask); + if (ret != RISCV_EXCP_NONE) { + return -ret; + } + return 0; } /* if no accessor exists then return failure */ if (!csr_ops[csrno].read) { return -RISCV_EXCP_ILLEGAL_INST; } - /* read old value */ ret = csr_ops[csrno].read(env, csrno, &old_value); - if (ret < 0) { - return ret; + if (ret != RISCV_EXCP_NONE) { + return -ret; } /* write value if writable and write mask set, otherwise drop writes */ @@ -1330,8 +1449,8 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, new_value = (old_value & ~write_mask) | (new_value & write_mask); if (csr_ops[csrno].write) { ret = csr_ops[csrno].write(env, csrno, new_value); - if (ret < 0) { - return ret; + if (ret != RISCV_EXCP_NONE) { + return -ret; } } } From 533c91e8f22cf86bb7b87f12c13024291d7d66fc Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Thu, 1 Apr 2021 11:18:07 -0400 Subject: [PATCH 0432/3028] target/riscv: Use RISCVException enum for CSR access Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Bin Meng Message-id: 302b208f40373557fa11b351b5c9f43039ca8ea3.1617290165.git.alistair.francis@wdc.com --- target/riscv/cpu.h | 11 +++++++---- target/riscv/csr.c | 37 ++++++++++++++++++------------------- target/riscv/gdbstub.c | 8 ++++---- target/riscv/op_helper.c | 18 +++++++++--------- 4 files changed, 38 insertions(+), 36 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index a7b8876ea0..842d3ab810 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -454,10 +454,13 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc, *pflags = flags; } -int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask); -int riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask); +RISCVException riscv_csrrw(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask); +RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, + target_ulong write_mask); static inline void riscv_csr_write(CPURISCVState *env, int csrno, target_ulong val) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index f67eaf4042..f0a74f0eb8 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1382,10 +1382,11 @@ static RISCVException write_pmpaddr(CPURISCVState *env, int csrno, * csrrc <-> riscv_csrrw(env, csrno, ret_value, 0, value); */ -int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +RISCVException riscv_csrrw(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) { - int ret; + RISCVException ret; target_ulong old_value; RISCVCPU *cpu = env_archcpu(env); @@ -1407,41 +1408,37 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, if ((write_mask && read_only) || (!env->debugger && (effective_priv < get_field(csrno, 0x300)))) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } #endif /* ensure the CSR extension is enabled. */ if (!cpu->cfg.ext_icsr) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } /* check predicate */ if (!csr_ops[csrno].predicate) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } ret = csr_ops[csrno].predicate(env, csrno); if (ret != RISCV_EXCP_NONE) { - return -ret; + return ret; } /* execute combined read/write operation if it exists */ if (csr_ops[csrno].op) { - ret = csr_ops[csrno].op(env, csrno, ret_value, new_value, write_mask); - if (ret != RISCV_EXCP_NONE) { - return -ret; - } - return 0; + return csr_ops[csrno].op(env, csrno, ret_value, new_value, write_mask); } /* if no accessor exists then return failure */ if (!csr_ops[csrno].read) { - return -RISCV_EXCP_ILLEGAL_INST; + return RISCV_EXCP_ILLEGAL_INST; } /* read old value */ ret = csr_ops[csrno].read(env, csrno, &old_value); if (ret != RISCV_EXCP_NONE) { - return -ret; + return ret; } /* write value if writable and write mask set, otherwise drop writes */ @@ -1450,7 +1447,7 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, if (csr_ops[csrno].write) { ret = csr_ops[csrno].write(env, csrno, new_value); if (ret != RISCV_EXCP_NONE) { - return -ret; + return ret; } } } @@ -1460,17 +1457,19 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value, *ret_value = old_value; } - return 0; + return RISCV_EXCP_NONE; } /* * Debugger support. If not in user mode, set env->debugger before the * riscv_csrrw call and clear it after the call. */ -int riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, + target_ulong write_mask) { - int ret; + RISCVException ret; #if !defined(CONFIG_USER_ONLY) env->debugger = true; #endif diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index 5f96b7ea2a..ca78682cf4 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -71,7 +71,7 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n) */ result = riscv_csrrw_debug(env, n - 32, &val, 0, 0); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return gdb_get_regl(buf, val); } } @@ -94,7 +94,7 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n) */ result = riscv_csrrw_debug(env, n - 32, NULL, val, -1); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return sizeof(target_ulong); } } @@ -108,7 +108,7 @@ static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n) int result; result = riscv_csrrw_debug(env, n, &val, 0, 0); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return gdb_get_regl(buf, val); } } @@ -122,7 +122,7 @@ static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n) int result; result = riscv_csrrw_debug(env, n, NULL, val, -1); - if (result == 0) { + if (result == RISCV_EXCP_NONE) { return sizeof(target_ulong); } } diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index f0bbd73ca5..170b494227 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -41,10 +41,10 @@ target_ulong helper_csrrw(CPURISCVState *env, target_ulong src, target_ulong csr) { target_ulong val = 0; - int ret = riscv_csrrw(env, csr, &val, src, -1); + RISCVException ret = riscv_csrrw(env, csr, &val, src, -1); - if (ret < 0) { - riscv_raise_exception(env, -ret, GETPC()); + if (ret != RISCV_EXCP_NONE) { + riscv_raise_exception(env, ret, GETPC()); } return val; } @@ -53,10 +53,10 @@ target_ulong helper_csrrs(CPURISCVState *env, target_ulong src, target_ulong csr, target_ulong rs1_pass) { target_ulong val = 0; - int ret = riscv_csrrw(env, csr, &val, -1, rs1_pass ? src : 0); + RISCVException ret = riscv_csrrw(env, csr, &val, -1, rs1_pass ? src : 0); - if (ret < 0) { - riscv_raise_exception(env, -ret, GETPC()); + if (ret != RISCV_EXCP_NONE) { + riscv_raise_exception(env, ret, GETPC()); } return val; } @@ -65,10 +65,10 @@ target_ulong helper_csrrc(CPURISCVState *env, target_ulong src, target_ulong csr, target_ulong rs1_pass) { target_ulong val = 0; - int ret = riscv_csrrw(env, csr, &val, 0, rs1_pass ? src : 0); + RISCVException ret = riscv_csrrw(env, csr, &val, 0, rs1_pass ? src : 0); - if (ret < 0) { - riscv_raise_exception(env, -ret, GETPC()); + if (ret != RISCV_EXCP_NONE) { + riscv_raise_exception(env, ret, GETPC()); } return val; } From ab2c91286c0fca38e10af0908573e776c395445d Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 6 Apr 2021 18:48:25 -0400 Subject: [PATCH 0433/3028] MAINTAINERS: Update the RISC-V CPU Maintainers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the RISC-V maintainers by removing Sagar and Bastian who haven't been involved recently. Also add Bin who has been helping with reviews. Signed-off-by: Alistair Francis Acked-by: Bin Meng Acked-by: Bastian Koppelmann Reviewed-by: Philippe Mathieu-Daudé Message-id: 6564ba829c40ad9aa7d28f43be69d8eb5cf4b56b.1617749142.git.alistair.francis@wdc.com --- MAINTAINERS | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 7aaa304b1e..3ace764d29 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -295,9 +295,8 @@ F: tests/acceptance/machine_ppc.py RISC-V TCG CPUs M: Palmer Dabbelt -M: Alistair Francis -M: Sagar Karandikar -M: Bastian Koppelmann +M: Alistair Francis +M: Bin Meng L: qemu-riscv@nongnu.org S: Supported F: target/riscv/ From d4cad544992225105d88c3d744bce1b08947dd24 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 31 Mar 2021 11:00:11 -0400 Subject: [PATCH 0434/3028] hw/opentitan: Update the interrupt layout Update the OpenTitan interrupt layout to match the latest OpenTitan bitstreams. This involves changing the Ibex PLIC memory layout and the UART interrupts. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: e92b696f1809c9fa4410da2e9f23c414db5a6960.1617202791.git.alistair.francis@wdc.com --- hw/intc/ibex_plic.c | 20 ++++++++++---------- hw/riscv/opentitan.c | 8 ++++---- include/hw/riscv/opentitan.h | 16 ++++++++-------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c index c1b72fcab0..edf76e4f61 100644 --- a/hw/intc/ibex_plic.c +++ b/hw/intc/ibex_plic.c @@ -225,23 +225,23 @@ static void ibex_plic_irq_request(void *opaque, int irq, int level) static Property ibex_plic_properties[] = { DEFINE_PROP_UINT32("num-cpus", IbexPlicState, num_cpus, 1), - DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 80), + DEFINE_PROP_UINT32("num-sources", IbexPlicState, num_sources, 176), DEFINE_PROP_UINT32("pending-base", IbexPlicState, pending_base, 0), - DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 3), + DEFINE_PROP_UINT32("pending-num", IbexPlicState, pending_num, 6), - DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x0c), - DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 3), + DEFINE_PROP_UINT32("source-base", IbexPlicState, source_base, 0x18), + DEFINE_PROP_UINT32("source-num", IbexPlicState, source_num, 6), - DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x18), - DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 80), + DEFINE_PROP_UINT32("priority-base", IbexPlicState, priority_base, 0x30), + DEFINE_PROP_UINT32("priority-num", IbexPlicState, priority_num, 177), - DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x200), - DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 3), + DEFINE_PROP_UINT32("enable-base", IbexPlicState, enable_base, 0x300), + DEFINE_PROP_UINT32("enable-num", IbexPlicState, enable_num, 6), - DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x20c), + DEFINE_PROP_UINT32("threshold-base", IbexPlicState, threshold_base, 0x318), - DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x210), + DEFINE_PROP_UINT32("claim-base", IbexPlicState, claim_base, 0x31c), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index dc9dea117e..557d73726b 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -148,16 +148,16 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart), 0, memmap[IBEX_DEV_UART].base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 0, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_TX_WATERMARK_IRQ)); + IBEX_UART0_TX_WATERMARK_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 1, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_RX_WATERMARK_IRQ)); + IBEX_UART0_RX_WATERMARK_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 2, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_TX_EMPTY_IRQ)); + IBEX_UART0_TX_EMPTY_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 3, qdev_get_gpio_in(DEVICE(&s->plic), - IBEX_UART_RX_OVERFLOW_IRQ)); + IBEX_UART0_RX_OVERFLOW_IRQ)); create_unimplemented_device("riscv.lowrisc.ibex.gpio", memmap[IBEX_DEV_GPIO].base, memmap[IBEX_DEV_GPIO].size); diff --git a/include/hw/riscv/opentitan.h b/include/hw/riscv/opentitan.h index a5ea3a5e4e..aab9bc9245 100644 --- a/include/hw/riscv/opentitan.h +++ b/include/hw/riscv/opentitan.h @@ -82,14 +82,14 @@ enum { }; enum { - IBEX_UART_RX_PARITY_ERR_IRQ = 0x28, - IBEX_UART_RX_TIMEOUT_IRQ = 0x27, - IBEX_UART_RX_BREAK_ERR_IRQ = 0x26, - IBEX_UART_RX_FRAME_ERR_IRQ = 0x25, - IBEX_UART_RX_OVERFLOW_IRQ = 0x24, - IBEX_UART_TX_EMPTY_IRQ = 0x23, - IBEX_UART_RX_WATERMARK_IRQ = 0x22, - IBEX_UART_TX_WATERMARK_IRQ = 0x21, + IBEX_UART0_RX_PARITY_ERR_IRQ = 8, + IBEX_UART0_RX_TIMEOUT_IRQ = 7, + IBEX_UART0_RX_BREAK_ERR_IRQ = 6, + IBEX_UART0_RX_FRAME_ERR_IRQ = 5, + IBEX_UART0_RX_OVERFLOW_IRQ = 4, + IBEX_UART0_TX_EMPTY_IRQ = 3, + IBEX_UART0_RX_WATERMARK_IRQ = 2, + IBEX_UART0_TX_WATERMARK_IRQ = 1, }; #endif From 1742054f0bd5c0be2c5f94d8286435afd1330b2c Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Fri, 2 Apr 2021 08:42:12 -0400 Subject: [PATCH 0435/3028] hw/riscv: Enable VIRTIO_VGA for RISC-V virt machine imply VIRTIO_VGA for the virt machine, this fixes the following error when specifying `-vga virtio` as a command line argument: qemu-system-riscv64: Virtio VGA not available Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: 7ac26fafee8bd59d2a0640f3233f8ad1ab270e1e.1617367317.git.alistair.francis@wdc.com --- hw/riscv/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index a0225716b5..86957ec7b0 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -32,6 +32,7 @@ config SHAKTI_C config RISCV_VIRT bool imply PCI_DEVICES + imply VIRTIO_VGA imply TEST_DEVICES select GOLDFISH_RTC select MSI_NONBROKEN From 11c27c6ded4d41bf0d100c8b5b49d5056204c911 Mon Sep 17 00:00:00 2001 From: Jade Fink Date: Tue, 6 Apr 2021 04:31:09 -0700 Subject: [PATCH 0436/3028] riscv: don't look at SUM when accessing memory from a debugger context Previously the qemu monitor and gdbstub looked at SUM and refused to perform accesses to user memory if it is off, which was an impediment to debugging. Signed-off-by: Jade Fink Reviewed-by: Alistair Francis Message-id: 20210406113109.1031033-1-qemu@jade.fyi Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 99cc388db9..659ca8a173 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -342,12 +342,14 @@ static int get_physical_address_pmp(CPURISCVState *env, int *prot, * @first_stage: Are we in first stage translation? * Second stage is used for hypervisor guest translation * @two_stage: Are we going to perform two stage translation + * @is_debug: Is this access from a debugger or the monitor? */ static int get_physical_address(CPURISCVState *env, hwaddr *physical, int *prot, target_ulong addr, target_ulong *fault_pte_addr, int access_type, int mmu_idx, - bool first_stage, bool two_stage) + bool first_stage, bool two_stage, + bool is_debug) { /* NOTE: the env->pc value visible here will not be * correct, but the value visible to the exception handler @@ -416,7 +418,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, widened = 2; } /* status.SUM will be ignored if execute on background */ - sum = get_field(env->mstatus, MSTATUS_SUM) || use_background; + sum = get_field(env->mstatus, MSTATUS_SUM) || use_background || is_debug; switch (vm) { case VM_1_10_SV32: levels = 2; ptidxbits = 10; ptesize = 4; break; @@ -475,7 +477,8 @@ restart: /* Do the second stage translation on the base PTE address. */ int vbase_ret = get_physical_address(env, &vbase, &vbase_prot, base, NULL, MMU_DATA_LOAD, - mmu_idx, false, true); + mmu_idx, false, true, + is_debug); if (vbase_ret != TRANSLATE_SUCCESS) { if (fault_pte_addr) { @@ -666,13 +669,13 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) int mmu_idx = cpu_mmu_index(&cpu->env, false); if (get_physical_address(env, &phys_addr, &prot, addr, NULL, 0, mmu_idx, - true, riscv_cpu_virt_enabled(env))) { + true, riscv_cpu_virt_enabled(env), true)) { return -1; } if (riscv_cpu_virt_enabled(env)) { if (get_physical_address(env, &phys_addr, &prot, phys_addr, NULL, - 0, mmu_idx, false, true)) { + 0, mmu_idx, false, true, true)) { return -1; } } @@ -768,7 +771,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, /* Two stage lookup */ ret = get_physical_address(env, &pa, &prot, address, &env->guest_phys_fault_addr, access_type, - mmu_idx, true, true); + mmu_idx, true, true, false); /* * A G-stage exception may be triggered during two state lookup. @@ -790,7 +793,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, im_address = pa; ret = get_physical_address(env, &pa, &prot2, im_address, NULL, - access_type, mmu_idx, false, true); + access_type, mmu_idx, false, true, + false); qemu_log_mask(CPU_LOG_MMU, "%s 2nd-stage address=%" VADDR_PRIx " ret %d physical " @@ -825,7 +829,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, } else { /* Single stage lookup */ ret = get_physical_address(env, &pa, &prot, address, NULL, - access_type, mmu_idx, true, false); + access_type, mmu_idx, true, false, false); qemu_log_mask(CPU_LOG_MMU, "%s address=%" VADDR_PRIx " ret %d physical " From 65606f21243a796537bfe4708720a9bf4bb50169 Mon Sep 17 00:00:00 2001 From: LIU Zhiwei Date: Fri, 12 Feb 2021 23:02:21 +0800 Subject: [PATCH 0437/3028] target/riscv: Fixup saturate subtract function The overflow predication ((a - b) ^ a) & (a ^ b) & INT64_MIN is right. However, when the predication is ture and a is 0, it should return maximum. Signed-off-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-id: 20210212150256.885-4-zhiwei_liu@c-sky.com Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index a156573d28..356cef8a09 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -2451,7 +2451,7 @@ static inline int8_t ssub8(CPURISCVState *env, int vxrm, int8_t a, int8_t b) { int8_t res = a - b; if ((res ^ a) & (a ^ b) & INT8_MIN) { - res = a > 0 ? INT8_MAX : INT8_MIN; + res = a >= 0 ? INT8_MAX : INT8_MIN; env->vxsat = 0x1; } return res; @@ -2461,7 +2461,7 @@ static inline int16_t ssub16(CPURISCVState *env, int vxrm, int16_t a, int16_t b) { int16_t res = a - b; if ((res ^ a) & (a ^ b) & INT16_MIN) { - res = a > 0 ? INT16_MAX : INT16_MIN; + res = a >= 0 ? INT16_MAX : INT16_MIN; env->vxsat = 0x1; } return res; @@ -2471,7 +2471,7 @@ static inline int32_t ssub32(CPURISCVState *env, int vxrm, int32_t a, int32_t b) { int32_t res = a - b; if ((res ^ a) & (a ^ b) & INT32_MIN) { - res = a > 0 ? INT32_MAX : INT32_MIN; + res = a >= 0 ? INT32_MAX : INT32_MIN; env->vxsat = 0x1; } return res; @@ -2481,7 +2481,7 @@ static inline int64_t ssub64(CPURISCVState *env, int vxrm, int64_t a, int64_t b) { int64_t res = a - b; if ((res ^ a) & (a ^ b) & INT64_MIN) { - res = a > 0 ? INT64_MAX : INT64_MIN; + res = a >= 0 ? INT64_MAX : INT64_MIN; env->vxsat = 0x1; } return res; From 0924a423baa227fa8fb363232c20a997cb6f617b Mon Sep 17 00:00:00 2001 From: Vijai Kumar K Date: Mon, 12 Apr 2021 23:12:48 +0530 Subject: [PATCH 0438/3028] docs: Add documentation for shakti_c machine Add documentation for Shakti C reference platform. Signed-off-by: Vijai Kumar K Reviewed-by: Alistair Francis Message-id: 20210412174248.8668-1-vijai@behindbytes.com Signed-off-by: Bin Meng [ Changes from Bin Meng: - Add missing TOC Message-id: 20210430070534.1487242-1-bmeng.cn@gmail.com ] Signed-off-by: Alistair Francis --- docs/system/riscv/shakti-c.rst | 82 ++++++++++++++++++++++++++++++++++ docs/system/target-riscv.rst | 1 + 2 files changed, 83 insertions(+) create mode 100644 docs/system/riscv/shakti-c.rst diff --git a/docs/system/riscv/shakti-c.rst b/docs/system/riscv/shakti-c.rst new file mode 100644 index 0000000000..a6035d42b0 --- /dev/null +++ b/docs/system/riscv/shakti-c.rst @@ -0,0 +1,82 @@ +Shakti C Reference Platform (``shakti_c``) +========================================== + +Shakti C Reference Platform is a reference platform based on arty a7 100t +for the Shakti SoC. + +Shakti SoC is a SoC based on the Shakti C-class processor core. Shakti C +is a 64bit RV64GCSUN processor core. + +For more details on Shakti SoC, please see: +https://gitlab.com/shaktiproject/cores/shakti-soc/-/blob/master/fpga/boards/artya7-100t/c-class/README.rst + +For more info on the Shakti C-class core, please see: +https://c-class.readthedocs.io/en/latest/ + +Supported devices +----------------- + +The ``shakti_c`` machine supports the following devices: + + * 1 C-class core + * Core Level Interruptor (CLINT) + * Platform-Level Interrupt Controller (PLIC) + * 1 UART + +Boot options +------------ + +The ``shakti_c`` machine can start using the standard -bios +functionality for loading the baremetal application or opensbi. + +Boot the machine +---------------- + +Shakti SDK +~~~~~~~~~~ +Shakti SDK can be used to generate the baremetal example UART applications. + +.. code-block:: bash + + $ git clone https://gitlab.com/behindbytes/shakti-sdk.git + $ cd shakti-sdk + $ make software PROGRAM=loopback TARGET=artix7_100t + +Binary would be generated in: + software/examples/uart_applns/loopback/output/loopback.shakti + +You could also download the precompiled example applicatons using below +commands. + +.. code-block:: bash + + $ wget -c https://gitlab.com/behindbytes/shakti-binaries/-/raw/master/sdk/shakti_sdk_qemu.zip + $ unzip shakti_sdk_qemu.zip + +Then we can run the UART example using: + +.. code-block:: bash + + $ qemu-system-riscv64 -M shakti_c -nographic \ + -bios path/to/shakti_sdk_qemu/loopback.shakti + +OpenSBI +~~~~~~~ +We can also run OpenSBI with Test Payload. + +.. code-block:: bash + + $ git clone https://github.com/riscv/opensbi.git -b v0.9 + $ cd opensbi + $ wget -c https://gitlab.com/behindbytes/shakti-binaries/-/raw/master/dts/shakti.dtb + $ export CROSS_COMPILE=riscv64-unknown-elf- + $ export FW_FDT_PATH=./shakti.dtb + $ make PLATFORM=generic + +fw_payload.elf would be generated in build/platform/generic/firmware/fw_payload.elf. +Boot it using the below qemu command. + +.. code-block:: bash + + $ qemu-system-riscv64 -M shakti_c -nographic \ + -bios path/to/fw_payload.elf diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst index 8d5946fbbb..4b3c78382c 100644 --- a/docs/system/target-riscv.rst +++ b/docs/system/target-riscv.rst @@ -67,6 +67,7 @@ undocumented; you can get a complete list by running :maxdepth: 1 riscv/microchip-icicle-kit + riscv/shakti-c riscv/sifive_u RISC-V CPU features From 94c6ba83c1a1e45558bd32421b85233053a1c6f3 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 19 Apr 2021 16:16:25 +1000 Subject: [PATCH 0439/3028] target/riscv: Fix the PMP is locked check when using TOR The RISC-V spec says: if PMP entry i is locked and pmpicfg.A is set to TOR, writes to pmpaddri-1 are ignored. The current QEMU code ignores accesses to pmpaddri-1 and pmpcfgi-1 which is incorrect. Update the pmp_is_locked() function to not check the supporting fields and instead enforce the lock functionality in the pmpaddr write operation. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: 2831241458163f445a89bd59c59990247265b0c6.1618812899.git.alistair.francis@wdc.com --- target/riscv/pmp.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index cff020122a..a3b253bb15 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -59,16 +59,6 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index) return 0; } - /* In TOR mode, need to check the lock bit of the next pmp - * (if there is a next) - */ - const uint8_t a_field = - pmp_get_a_field(env->pmp_state.pmp[pmp_index + 1].cfg_reg); - if ((env->pmp_state.pmp[pmp_index + 1u].cfg_reg & PMP_LOCK) && - (PMP_AMATCH_TOR == a_field)) { - return 1; - } - return 0; } @@ -380,7 +370,23 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, target_ulong val) { trace_pmpaddr_csr_write(env->mhartid, addr_index, val); + if (addr_index < MAX_RISCV_PMPS) { + /* + * In TOR mode, need to check the lock bit of the next pmp + * (if there is a next). + */ + if (addr_index + 1 < MAX_RISCV_PMPS) { + uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg; + + if (pmp_cfg & PMP_LOCK && + PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg)) { + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpaddr write - pmpcfg + 1 locked\n"); + return; + } + } + if (!pmp_is_locked(env, addr_index)) { env->pmp_state.pmp[addr_index].addr_reg = val; pmp_update_rule(env, addr_index); From db9f1dac4854199b17121eafcb2baf512bd5bf5c Mon Sep 17 00:00:00 2001 From: Hou Weiying Date: Mon, 19 Apr 2021 16:16:38 +1000 Subject: [PATCH 0440/3028] target/riscv: Define ePMP mseccfg Use address 0x390 and 0x391 for the ePMP CSRs. Signed-off-by: Hongzheng-Li Signed-off-by: Hou Weiying Signed-off-by: Myriad-Dreamin Reviewed-by: Alistair Francis Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: 63245b559f477a9ce6d4f930136d2d7fd7f99c78.1618812899.git.alistair.francis@wdc.com [ Changes by AF: - Tidy up commit message ] Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- target/riscv/cpu_bits.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 8549d77b4f..24d89939a0 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -220,6 +220,9 @@ #define CSR_MTINST 0x34a #define CSR_MTVAL2 0x34b +/* Enhanced Physical Memory Protection (ePMP) */ +#define CSR_MSECCFG 0x390 +#define CSR_MSECCFGH 0x391 /* Physical Memory Protection */ #define CSR_PMPCFG0 0x3a0 #define CSR_PMPCFG1 0x3a1 From 4a345b2a8399b8618e319be375719e9d4d6975d3 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 19 Apr 2021 16:16:44 +1000 Subject: [PATCH 0441/3028] target/riscv: Add the ePMP feature The spec is avaliable at: https://docs.google.com/document/d/1Mh_aiHYxemL0umN3GTTw8vsbmzHZ_nxZXgjgOUzbvc8 Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: 28c8855c80b0388a08c3ae009f5467e2b3960ce0.1618812899.git.alistair.francis@wdc.com --- target/riscv/cpu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 842d3ab810..13a08b86f6 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -81,6 +81,7 @@ enum { RISCV_FEATURE_MMU, RISCV_FEATURE_PMP, + RISCV_FEATURE_EPMP, RISCV_FEATURE_MISA }; From 2582a95c3c46d2e9d7fbe4a6ff01cfe6b4875339 Mon Sep 17 00:00:00 2001 From: Hou Weiying Date: Mon, 19 Apr 2021 16:16:53 +1000 Subject: [PATCH 0442/3028] target/riscv: Add ePMP CSR access functions Signed-off-by: Hongzheng-Li Signed-off-by: Hou Weiying Signed-off-by: Myriad-Dreamin Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: 270762cb2507fba6a9eeb99a774cf49f7da9cc32.1618812899.git.alistair.francis@wdc.com [ Changes by AF: - Rebase on master - Fix build errors - Fix some style issues ] Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- target/riscv/cpu.h | 1 + target/riscv/csr.c | 24 ++++++++++++++++++++++++ target/riscv/pmp.c | 34 ++++++++++++++++++++++++++++++++++ target/riscv/pmp.h | 14 ++++++++++++++ target/riscv/trace-events | 3 +++ 5 files changed, 76 insertions(+) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 13a08b86f6..83b315e0b2 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -230,6 +230,7 @@ struct CPURISCVState { /* physical memory protection */ pmp_table_t pmp_state; + target_ulong mseccfg; /* machine specific rdtime callback */ uint64_t (*rdtime_fn)(uint32_t); diff --git a/target/riscv/csr.c b/target/riscv/csr.c index f0a74f0eb8..97ceff718f 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -200,6 +200,15 @@ static RISCVException pmp(CPURISCVState *env, int csrno) return RISCV_EXCP_ILLEGAL_INST; } + +static RISCVException epmp(CPURISCVState *env, int csrno) +{ + if (env->priv == PRV_M && riscv_feature(env, RISCV_FEATURE_EPMP)) { + return RISCV_EXCP_NONE; + } + + return RISCV_EXCP_ILLEGAL_INST; +} #endif /* User Floating-Point CSRs */ @@ -1343,6 +1352,20 @@ static RISCVException write_mtinst(CPURISCVState *env, int csrno, } /* Physical Memory Protection */ +static RISCVException read_mseccfg(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = mseccfg_csr_read(env); + return RISCV_EXCP_NONE; +} + +static RISCVException write_mseccfg(CPURISCVState *env, int csrno, + target_ulong val) +{ + mseccfg_csr_write(env, val); + return RISCV_EXCP_NONE; +} + static RISCVException read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val) { @@ -1581,6 +1604,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst }, /* Physical Memory Protection */ + [CSR_MSECCFG] = { "mseccfg", epmp, read_mseccfg, write_mseccfg }, [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPCFG2] = { "pmpcfg2", pmp, read_pmpcfg, write_pmpcfg }, diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index a3b253bb15..e35988eec2 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -419,6 +419,40 @@ target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index) return val; } +/* + * Handle a write to a mseccfg CSR + */ +void mseccfg_csr_write(CPURISCVState *env, target_ulong val) +{ + int i; + + trace_mseccfg_csr_write(env->mhartid, val); + + /* RLB cannot be enabled if it's already 0 and if any regions are locked */ + if (!MSECCFG_RLB_ISSET(env)) { + for (i = 0; i < MAX_RISCV_PMPS; i++) { + if (pmp_is_locked(env, i)) { + val &= ~MSECCFG_RLB; + break; + } + } + } + + /* Sticky bits */ + val |= (env->mseccfg & (MSECCFG_MMWP | MSECCFG_MML)); + + env->mseccfg = val; +} + +/* + * Handle a read from a mseccfg CSR + */ +target_ulong mseccfg_csr_read(CPURISCVState *env) +{ + trace_mseccfg_csr_read(env->mhartid, env->mseccfg); + return env->mseccfg; +} + /* * Calculate the TLB size if the start address or the end address of * PMP entry is presented in thie TLB page. diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h index b82a30f0d5..a9a0b363a7 100644 --- a/target/riscv/pmp.h +++ b/target/riscv/pmp.h @@ -36,6 +36,12 @@ typedef enum { PMP_AMATCH_NAPOT /* Naturally aligned power-of-two region */ } pmp_am_t; +typedef enum { + MSECCFG_MML = 1 << 0, + MSECCFG_MMWP = 1 << 1, + MSECCFG_RLB = 1 << 2 +} mseccfg_field_t; + typedef struct { target_ulong addr_reg; uint8_t cfg_reg; @@ -55,6 +61,10 @@ typedef struct { void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index, target_ulong val); target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index); + +void mseccfg_csr_write(CPURISCVState *env, target_ulong val); +target_ulong mseccfg_csr_read(CPURISCVState *env); + void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, target_ulong val); target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index); @@ -68,4 +78,8 @@ void pmp_update_rule_nums(CPURISCVState *env); uint32_t pmp_get_num_rules(CPURISCVState *env); int pmp_priv_to_page_prot(pmp_priv_t pmp_priv); +#define MSECCFG_MML_ISSET(env) get_field(env->mseccfg, MSECCFG_MML) +#define MSECCFG_MMWP_ISSET(env) get_field(env->mseccfg, MSECCFG_MMWP) +#define MSECCFG_RLB_ISSET(env) get_field(env->mseccfg, MSECCFG_RLB) + #endif diff --git a/target/riscv/trace-events b/target/riscv/trace-events index b7e371ee97..49ec4d3b7d 100644 --- a/target/riscv/trace-events +++ b/target/riscv/trace-events @@ -6,3 +6,6 @@ pmpcfg_csr_read(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRI pmpcfg_csr_write(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": write reg%" PRIu32", val: 0x%" PRIx64 pmpaddr_csr_read(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": read addr%" PRIu32", val: 0x%" PRIx64 pmpaddr_csr_write(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": write addr%" PRIu32", val: 0x%" PRIx64 + +mseccfg_csr_read(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": read mseccfg, val: 0x%" PRIx64 +mseccfg_csr_write(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": write mseccfg, val: 0x%" PRIx64 From ae39e4ce19b0292b3608bd71a1d4fcf558ea2edc Mon Sep 17 00:00:00 2001 From: Hou Weiying Date: Mon, 19 Apr 2021 16:17:11 +1000 Subject: [PATCH 0443/3028] target/riscv: Implementation of enhanced PMP (ePMP) This commit adds support for ePMP v0.9.1. The ePMP spec can be found in: https://docs.google.com/document/d/1Mh_aiHYxemL0umN3GTTw8vsbmzHZ_nxZXgjgOUzbvc8 Signed-off-by: Hongzheng-Li Signed-off-by: Hou Weiying Signed-off-by: Myriad-Dreamin Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: fef23b885f9649a4d54e7c98b168bdec5d297bb1.1618812899.git.alistair.francis@wdc.com [ Changes by AF: - Rebase on master - Update to latest spec - Use a switch case to handle ePMP MML permissions - Fix a few bugs ] Signed-off-by: Alistair Francis --- target/riscv/pmp.c | 154 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 146 insertions(+), 8 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index e35988eec2..e1f5776316 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -90,11 +90,42 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index) static void pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) { if (pmp_index < MAX_RISCV_PMPS) { - if (!pmp_is_locked(env, pmp_index)) { + bool locked = true; + + if (riscv_feature(env, RISCV_FEATURE_EPMP)) { + /* mseccfg.RLB is set */ + if (MSECCFG_RLB_ISSET(env)) { + locked = false; + } + + /* mseccfg.MML is not set */ + if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) { + locked = false; + } + + /* mseccfg.MML is set */ + if (MSECCFG_MML_ISSET(env)) { + /* not adding execute bit */ + if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) { + locked = false; + } + /* shared region and not adding X bit */ + if ((val & PMP_LOCK) != PMP_LOCK && + (val & 0x7) != (PMP_WRITE | PMP_EXEC)) { + locked = false; + } + } + } else { + if (!pmp_is_locked(env, pmp_index)) { + locked = false; + } + } + + if (locked) { + qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n"); + } else { env->pmp_state.pmp[pmp_index].cfg_reg = val; pmp_update_rule(env, pmp_index); - } else { - qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n"); } } else { qemu_log_mask(LOG_GUEST_ERROR, @@ -217,6 +248,32 @@ static bool pmp_hart_has_privs_default(CPURISCVState *env, target_ulong addr, { bool ret; + if (riscv_feature(env, RISCV_FEATURE_EPMP)) { + if (MSECCFG_MMWP_ISSET(env)) { + /* + * The Machine Mode Whitelist Policy (mseccfg.MMWP) is set + * so we default to deny all, even for M-mode. + */ + *allowed_privs = 0; + return false; + } else if (MSECCFG_MML_ISSET(env)) { + /* + * The Machine Mode Lockdown (mseccfg.MML) bit is set + * so we can only execute code in M-mode with an applicable + * rule. Other modes are disabled. + */ + if (mode == PRV_M && !(privs & PMP_EXEC)) { + ret = true; + *allowed_privs = PMP_READ | PMP_WRITE; + } else { + ret = false; + *allowed_privs = 0; + } + + return ret; + } + } + if ((!riscv_feature(env, RISCV_FEATURE_PMP)) || (mode == PRV_M)) { /* * Privileged spec v1.10 states if HW doesn't implement any PMP entry @@ -294,13 +351,94 @@ bool pmp_hart_has_privs(CPURISCVState *env, target_ulong addr, pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg); /* - * If the PMP entry is not off and the address is in range, do the priv - * check + * Convert the PMP permissions to match the truth table in the + * ePMP spec. */ + const uint8_t epmp_operation = + ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) | + ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) | + (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) | + ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2); + if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) { - *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; - if ((mode != PRV_M) || pmp_is_locked(env, i)) { - *allowed_privs &= env->pmp_state.pmp[i].cfg_reg; + /* + * If the PMP entry is not off and the address is in range, + * do the priv check + */ + if (!MSECCFG_MML_ISSET(env)) { + /* + * If mseccfg.MML Bit is not set, do pmp priv check + * This will always apply to regular PMP. + */ + *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; + if ((mode != PRV_M) || pmp_is_locked(env, i)) { + *allowed_privs &= env->pmp_state.pmp[i].cfg_reg; + } + } else { + /* + * If mseccfg.MML Bit set, do the enhanced pmp priv check + */ + if (mode == PRV_M) { + switch (epmp_operation) { + case 0: + case 1: + case 4: + case 5: + case 6: + case 7: + case 8: + *allowed_privs = 0; + break; + case 2: + case 3: + case 14: + *allowed_privs = PMP_READ | PMP_WRITE; + break; + case 9: + case 10: + *allowed_privs = PMP_EXEC; + break; + case 11: + case 13: + *allowed_privs = PMP_READ | PMP_EXEC; + break; + case 12: + case 15: + *allowed_privs = PMP_READ; + break; + } + } else { + switch (epmp_operation) { + case 0: + case 8: + case 9: + case 12: + case 13: + case 14: + *allowed_privs = 0; + break; + case 1: + case 10: + case 11: + *allowed_privs = PMP_EXEC; + break; + case 2: + case 4: + case 15: + *allowed_privs = PMP_READ; + break; + case 3: + case 6: + *allowed_privs = PMP_READ | PMP_WRITE; + break; + case 5: + *allowed_privs = PMP_READ | PMP_EXEC; + break; + case 7: + *allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC; + break; + } + } } ret = ((privs & *allowed_privs) == privs); From 5da9514e965fcdccd3745d0e216feb507a0b9dd1 Mon Sep 17 00:00:00 2001 From: Hou Weiying Date: Mon, 19 Apr 2021 16:17:25 +1000 Subject: [PATCH 0444/3028] target/riscv: Add a config option for ePMP Add a config option to enable experimental support for ePMP. This is disabled by default and can be enabled with 'x-epmp=true'. Signed-off-by: Hongzheng-Li Signed-off-by: Hou Weiying Signed-off-by: Myriad-Dreamin Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: a22ccdaf9314078bc735d3b323f966623f8af020.1618812899.git.alistair.francis@wdc.com Signed-off-by: Alistair Francis Reviewed-by: Bin Meng --- target/riscv/cpu.c | 10 ++++++++++ target/riscv/cpu.h | 1 + 2 files changed, 11 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index e530df9385..66787d019c 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -412,6 +412,14 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) if (cpu->cfg.pmp) { set_feature(env, RISCV_FEATURE_PMP); + + /* + * Enhanced PMP should only be available + * on harts with PMP support + */ + if (cpu->cfg.epmp) { + set_feature(env, RISCV_FEATURE_EPMP); + } } set_resetvec(env, cpu->cfg.resetvec); @@ -554,6 +562,8 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), + DEFINE_PROP_BOOL("x-epmp", RISCVCPU, cfg.epmp, false), + DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC), DEFINE_PROP_END_OF_LIST(), }; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 83b315e0b2..add734bbbd 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -304,6 +304,7 @@ struct RISCVCPU { uint16_t elen; bool mmu; bool pmp; + bool epmp; uint64_t resetvec; } cfg; }; From 8ab6d3fbfe1523c6cf53e6a38a62bff3c5e6ff3c Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 19 Apr 2021 16:17:35 +1000 Subject: [PATCH 0445/3028] target/riscv/pmp: Remove outdated comment Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: 10387eec21d2f17c499a78fdba85280cab4dd27f.1618812899.git.alistair.francis@wdc.com --- target/riscv/pmp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index e1f5776316..78203291de 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -19,10 +19,6 @@ * this program. If not, see . */ -/* - * PMP (Physical Memory Protection) is as-of-yet unused and needs testing. - */ - #include "qemu/osdep.h" #include "qemu/log.h" #include "qapi/error.h" From ed6eebaaafd3b96cc4ef3dcc30eb3a26c20ece57 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Mon, 19 Apr 2021 16:18:06 +1000 Subject: [PATCH 0446/3028] target/riscv: Add ePMP support for the Ibex CPU The physical Ibex CPU has ePMP support and it's enabled for the OpenTitan machine so let's enable ePMP support for the Ibex CPU in QEMU. Signed-off-by: Alistair Francis Reviewed-by: Bin Meng Message-id: d426baabab0c9361ed2e989dbe416e417a551fd1.1618812899.git.alistair.francis@wdc.com --- target/riscv/cpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 66787d019c..4bf6a00636 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -202,6 +202,7 @@ static void rv32_ibex_cpu_init(Object *obj) set_misa(env, RV32 | RVI | RVM | RVC | RVU); set_priv_version(env, PRIV_VERSION_1_10_0); qdev_prop_set_bit(DEVICE(obj), "mmu", false); + qdev_prop_set_bit(DEVICE(obj), "x-epmp", true); } static void rv32_imafcu_nommu_cpu_init(Object *obj) From b11e84b883bf9b790732a03703559bf4797ad272 Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Mon, 19 Apr 2021 14:03:01 +0800 Subject: [PATCH 0447/3028] target/riscv: fix vrgather macro index variable type bug ETYPE may be type of uint64_t, thus index variable has to be declared as type of uint64_t, too. Otherwise the value read from vs1 register may be truncated to type of uint32_t. Signed-off-by: Frank Chang Reviewed-by: Richard Henderson Message-id: 20210419060302.14075-1-frank.chang@sifive.com Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 356cef8a09..4651a1e224 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -4796,7 +4796,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ - uint32_t index, i; \ + uint64_t index; \ + uint32_t i; \ \ for (i = 0; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, mlen, i)) { \ @@ -4826,7 +4827,8 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vlmax = env_archcpu(env)->cfg.vlen / mlen; \ uint32_t vm = vext_vm(desc); \ uint32_t vl = env->vl; \ - uint32_t index = s1, i; \ + uint64_t index = s1; \ + uint32_t i; \ \ for (i = 0; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, mlen, i)) { \ From f9e580c13ae0d42cf8989063254300c59166ffed Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Fri, 16 Apr 2021 16:17:11 +0200 Subject: [PATCH 0448/3028] target/riscv: fix exception index on instruction access fault When no MMU is used and the guest code attempts to fetch an instruction from an invalid memory location, the exception index defaults to a data load access fault, rather an instruction access fault. Signed-off-by: Emmanuel Blot Reviewed-by: Alistair Francis Message-id: FB9EA197-B018-4879-AB0F-922C2047A08B@sifive.com Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 659ca8a173..1018c0036d 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -694,8 +694,10 @@ void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, if (access_type == MMU_DATA_STORE) { cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT; - } else { + } else if (access_type == MMU_DATA_LOAD) { cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT; + } else { + cs->exception_index = RISCV_EXCP_INST_ACCESS_FAULT; } env->badaddr = addr; From d11e316d843b2d370a547700407947356e4117cb Mon Sep 17 00:00:00 2001 From: Alexander Wagner Date: Tue, 20 Apr 2021 10:00:08 +0200 Subject: [PATCH 0449/3028] hw/riscv: Fix OT IBEX reset vector The IBEX documentation [1] specifies the reset vector to be "the most significant 3 bytes of the boot address and the reset value (0x80) as the least significant byte". [1] https://github.com/lowRISC/ibex/blob/master/doc/03_reference/exception_interrupts.rst Signed-off-by: Alexander Wagner Reviewed-by: Alistair Francis Message-id: 20210420080008.119798-1-alexander.wagner@ulal.de Signed-off-by: Alistair Francis --- hw/riscv/opentitan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 557d73726b..7545dcda9c 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -119,7 +119,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) &error_abort); object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus, &error_abort); - object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8090, &error_abort); + object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8080, &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); /* Boot ROM */ From 3a7f7757ba95a374f73ed08cd5a9af366299ef81 Mon Sep 17 00:00:00 2001 From: Frank Chang Date: Tue, 20 Apr 2021 09:31:48 +0800 Subject: [PATCH 0450/3028] fpu/softfloat: set invalid excp flag for RISC-V muladd instructions In IEEE 754-2008 spec: Invalid operation exception is signaled when doing: fusedMultiplyAdd(0, Inf, c) or fusedMultiplyAdd(Inf, 0, c) unless c is a quiet NaN; if c is a quiet NaN then it is implementation defined whether the invalid operation exception is signaled. In RISC-V Unprivileged ISA spec: The fused multiply-add instructions must set the invalid operation exception flag when the multiplicands are Inf and zero, even when the addend is a quiet NaN. This commit set invalid operation execption flag for RISC-V when multiplicands of muladd instructions are Inf and zero. Signed-off-by: Frank Chang Reviewed-by: Richard Henderson Message-id: 20210420013150.21992-1-frank.chang@sifive.com Signed-off-by: Alistair Francis --- fpu/softfloat-specialize.c.inc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 9ea318f3e2..78f699d6f8 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -627,6 +627,12 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls, } else { return 1; } +#elif defined(TARGET_RISCV) + /* For RISC-V, InvalidOp is set when multiplicands are Inf and zero */ + if (infzero) { + float_raise(float_flag_invalid, status); + } + return 3; /* default NaN */ #elif defined(TARGET_XTENSA) /* * For Xtensa, the (inf,zero,nan) case sets InvalidOp and returns From 6cfcf77573fb9714afd09b9b9ead05e002102243 Mon Sep 17 00:00:00 2001 From: Emmanuel Blot Date: Wed, 21 Apr 2021 15:32:36 +0200 Subject: [PATCH 0451/3028] target/riscv: fix a typo with interrupt names Interrupt names have been swapped in 205377f8 and do not follow IRQ_*_EXT definition order. Signed-off-by: Emmanuel Blot Reviewed-by: Alistair Francis Message-id: 20210421133236.11323-1-emmanuel.blot@sifive.com Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 4bf6a00636..04ac03f8c9 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -88,8 +88,8 @@ const char * const riscv_intr_names[] = { "vs_timer", "m_timer", "u_external", + "s_external", "vs_external", - "h_external", "m_external", "reserved", "reserved", From 3820602f8059dfd4034d38bb727cdbc8759631db Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 24 Apr 2021 13:28:33 +1000 Subject: [PATCH 0452/3028] target/riscv: Remove the hardcoded RVXLEN macro Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Bin Meng Message-id: a07bc0c6dc4958681b4f93cbc5d0acc31ed3344a.1619234854.git.alistair.francis@wdc.com --- target/riscv/cpu.c | 6 +++++- target/riscv/cpu.h | 6 ------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 04ac03f8c9..3191fd0082 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -147,7 +147,11 @@ static void set_resetvec(CPURISCVState *env, target_ulong resetvec) static void riscv_any_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; - set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU); +#if defined(TARGET_RISCV32) + set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVU); +#elif defined(TARGET_RISCV64) + set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVU); +#endif set_priv_version(env, PRIV_VERSION_1_11_0); } diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index add734bbbd..7e879fb9ca 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -54,12 +54,6 @@ #define RV32 ((target_ulong)1 << (TARGET_LONG_BITS - 2)) #define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2)) -#if defined(TARGET_RISCV32) -#define RVXLEN RV32 -#elif defined(TARGET_RISCV64) -#define RVXLEN RV64 -#endif - #define RV(x) ((target_ulong)1 << (x - 'A')) #define RVI RV('I') From 5f10e6d8959cff77e79119bcc93d8d7806c28654 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 24 Apr 2021 13:29:50 +1000 Subject: [PATCH 0453/3028] target/riscv: Remove the hardcoded SSTATUS_SD macro This also ensures that the SD bit is not writable. Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Bin Meng Message-id: 9ea842309f0fd7adff172790f5b5fc058b40f2f1.1619234854.git.alistair.francis@wdc.com --- target/riscv/cpu_bits.h | 6 ------ target/riscv/csr.c | 9 ++++++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 24d89939a0..3a0e79e545 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -403,12 +403,6 @@ #define SSTATUS32_SD 0x80000000 #define SSTATUS64_SD 0x8000000000000000ULL -#if defined(TARGET_RISCV32) -#define SSTATUS_SD SSTATUS32_SD -#elif defined(TARGET_RISCV64) -#define SSTATUS_SD SSTATUS64_SD -#endif - /* hstatus CSR bits */ #define HSTATUS_VSBE 0x00000020 #define HSTATUS_GVA 0x00000040 diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 97ceff718f..41951a0a84 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -459,7 +459,7 @@ static const target_ulong delegable_excps = (1ULL << (RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT)); static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | - SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD; + SSTATUS_SUM | SSTATUS_MXR; static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; static const target_ulong hip_writable_mask = MIP_VSSIP; static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; @@ -788,6 +788,13 @@ static RISCVException read_sstatus(CPURISCVState *env, int csrno, target_ulong *val) { target_ulong mask = (sstatus_v1_10_mask); + + if (riscv_cpu_is_32bit(env)) { + mask |= SSTATUS32_SD; + } else { + mask |= SSTATUS64_SD; + } + *val = env->mstatus & mask; return RISCV_EXCP_NONE; } From 994b6bb2db8d9d21207aa3a9991b9789c3d3d1ca Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 24 Apr 2021 13:31:55 +1000 Subject: [PATCH 0454/3028] target/riscv: Remove the hardcoded HGATP_MODE macro Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Bin Meng Message-id: 665f624bfdc2e3ca64265004b07de7489c77a766.1619234854.git.alistair.francis@wdc.com --- target/riscv/cpu_bits.h | 11 ----------- target/riscv/cpu_helper.c | 24 +++++++++++++++--------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 3a0e79e545..d738e2fdbd 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -195,17 +195,6 @@ #define CSR_HTIMEDELTA 0x605 #define CSR_HTIMEDELTAH 0x615 -#if defined(TARGET_RISCV32) -#define HGATP_MODE SATP32_MODE -#define HGATP_VMID SATP32_ASID -#define HGATP_PPN SATP32_PPN -#endif -#if defined(TARGET_RISCV64) -#define HGATP_MODE SATP64_MODE -#define HGATP_VMID SATP64_ASID -#define HGATP_PPN SATP64_PPN -#endif - /* Virtual CSRs */ #define CSR_VSSTATUS 0x200 #define CSR_VSIE 0x204 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 1018c0036d..d9defbdd34 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -413,8 +413,13 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, } widened = 0; } else { - base = (hwaddr)get_field(env->hgatp, HGATP_PPN) << PGSHIFT; - vm = get_field(env->hgatp, HGATP_MODE); + if (riscv_cpu_is_32bit(env)) { + base = (hwaddr)get_field(env->hgatp, SATP32_PPN) << PGSHIFT; + vm = get_field(env->hgatp, SATP32_MODE); + } else { + base = (hwaddr)get_field(env->hgatp, SATP64_PPN) << PGSHIFT; + vm = get_field(env->hgatp, SATP64_MODE); + } widened = 2; } /* status.SUM will be ignored if execute on background */ @@ -618,16 +623,17 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, bool first_stage, bool two_stage) { CPUState *cs = env_cpu(env); - int page_fault_exceptions; + int page_fault_exceptions, vm; + if (first_stage) { - page_fault_exceptions = - get_field(env->satp, SATP_MODE) != VM_1_10_MBARE && - !pmp_violation; + vm = get_field(env->satp, SATP_MODE); + } else if (riscv_cpu_is_32bit(env)) { + vm = get_field(env->hgatp, SATP32_MODE); } else { - page_fault_exceptions = - get_field(env->hgatp, HGATP_MODE) != VM_1_10_MBARE && - !pmp_violation; + vm = get_field(env->hgatp, SATP64_MODE); } + page_fault_exceptions = vm != VM_1_10_MBARE && !pmp_violation; + switch (access_type) { case MMU_INST_FETCH: if (riscv_cpu_virt_enabled(env) && !first_stage) { From 4fd7455bb39910c0730db66895328cd37b5cee5a Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 24 Apr 2021 13:33:18 +1000 Subject: [PATCH 0455/3028] target/riscv: Remove the hardcoded MSTATUS_SD macro Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Message-id: fcc125d96da941b56c817c9dd6068dc36478fc53.1619234854.git.alistair.francis@wdc.com --- target/riscv/cpu_bits.h | 10 ---------- target/riscv/csr.c | 12 ++++++++++-- target/riscv/translate.c | 19 +++++++++++++++++-- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index d738e2fdbd..6e30b312f0 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -368,16 +368,6 @@ #define MXL_RV64 2 #define MXL_RV128 3 -#if defined(TARGET_RISCV32) -#define MSTATUS_SD MSTATUS32_SD -#define MISA_MXL MISA32_MXL -#define MXL_VAL MXL_RV32 -#elif defined(TARGET_RISCV64) -#define MSTATUS_SD MSTATUS64_SD -#define MISA_MXL MISA64_MXL -#define MXL_VAL MXL_RV64 -#endif - /* sstatus CSR bits */ #define SSTATUS_UIE 0x00000001 #define SSTATUS_SIE 0x00000002 diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 41951a0a84..e955753441 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -538,7 +538,11 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno, dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) | ((mstatus & MSTATUS_XS) == MSTATUS_XS); - mstatus = set_field(mstatus, MSTATUS_SD, dirty); + if (riscv_cpu_is_32bit(env)) { + mstatus = set_field(mstatus, MSTATUS32_SD, dirty); + } else { + mstatus = set_field(mstatus, MSTATUS64_SD, dirty); + } env->mstatus = mstatus; return RISCV_EXCP_NONE; @@ -614,7 +618,11 @@ static RISCVException write_misa(CPURISCVState *env, int csrno, } /* misa.MXL writes are not supported by QEMU */ - val = (env->misa & MISA_MXL) | (val & ~MISA_MXL); + if (riscv_cpu_is_32bit(env)) { + val = (env->misa & MISA32_MXL) | (val & ~MISA32_MXL); + } else { + val = (env->misa & MISA64_MXL) | (val & ~MISA64_MXL); + } /* flush translation cache */ if (val != env->misa) { diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 26eccc5eb1..a596f80f20 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -78,6 +78,17 @@ static inline bool has_ext(DisasContext *ctx, uint32_t ext) return ctx->misa & ext; } +#ifdef TARGET_RISCV32 +# define is_32bit(ctx) true +#elif defined(CONFIG_USER_ONLY) +# define is_32bit(ctx) false +#else +static inline bool is_32bit(DisasContext *ctx) +{ + return (ctx->misa & RV32) == RV32; +} +#endif + /* * RISC-V requires NaN-boxing of narrower width floating point values. * This applies when a 32-bit value is assigned to a 64-bit FP register. @@ -369,6 +380,8 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) static void mark_fs_dirty(DisasContext *ctx) { TCGv tmp; + target_ulong sd; + if (ctx->mstatus_fs == MSTATUS_FS) { return; } @@ -376,13 +389,15 @@ static void mark_fs_dirty(DisasContext *ctx) ctx->mstatus_fs = MSTATUS_FS; tmp = tcg_temp_new(); + sd = is_32bit(ctx) ? MSTATUS32_SD : MSTATUS64_SD; + tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); - tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | MSTATUS_SD); + tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | sd); tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus)); if (ctx->virt_enabled) { tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); - tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | MSTATUS_SD); + tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS | sd); tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus_hs)); } tcg_temp_free(tmp); From 419ddf00ed78c7f695a9d318cd8fbcab78b7bede Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 24 Apr 2021 13:33:31 +1000 Subject: [PATCH 0456/3028] target/riscv: Remove the hardcoded SATP_MODE macro Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Message-id: 6b701769d6621f45ba1739334198e36a64fe04df.1619234854.git.alistair.francis@wdc.com --- target/riscv/cpu_bits.h | 11 ----------- target/riscv/cpu_helper.c | 32 ++++++++++++++++++++++++-------- target/riscv/csr.c | 19 +++++++++++++++---- target/riscv/monitor.c | 22 +++++++++++++++++----- 4 files changed, 56 insertions(+), 28 deletions(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 6e30b312f0..d98f3bc8bc 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -432,17 +432,6 @@ #define SATP64_ASID 0x0FFFF00000000000ULL #define SATP64_PPN 0x00000FFFFFFFFFFFULL -#if defined(TARGET_RISCV32) -#define SATP_MODE SATP32_MODE -#define SATP_ASID SATP32_ASID -#define SATP_PPN SATP32_PPN -#endif -#if defined(TARGET_RISCV64) -#define SATP_MODE SATP64_MODE -#define SATP_ASID SATP64_ASID -#define SATP_PPN SATP64_PPN -#endif - /* VM modes (mstatus.vm) privileged ISA 1.9.1 */ #define VM_1_09_MBARE 0 #define VM_1_09_MBB 1 diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index d9defbdd34..968cb8046f 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -405,11 +405,21 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, if (first_stage == true) { if (use_background) { - base = (hwaddr)get_field(env->vsatp, SATP_PPN) << PGSHIFT; - vm = get_field(env->vsatp, SATP_MODE); + if (riscv_cpu_is_32bit(env)) { + base = (hwaddr)get_field(env->vsatp, SATP32_PPN) << PGSHIFT; + vm = get_field(env->vsatp, SATP32_MODE); + } else { + base = (hwaddr)get_field(env->vsatp, SATP64_PPN) << PGSHIFT; + vm = get_field(env->vsatp, SATP64_MODE); + } } else { - base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; - vm = get_field(env->satp, SATP_MODE); + if (riscv_cpu_is_32bit(env)) { + base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT; + vm = get_field(env->satp, SATP32_MODE); + } else { + base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT; + vm = get_field(env->satp, SATP64_MODE); + } } widened = 0; } else { @@ -624,14 +634,20 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, { CPUState *cs = env_cpu(env); int page_fault_exceptions, vm; + uint64_t stap_mode; + + if (riscv_cpu_is_32bit(env)) { + stap_mode = SATP32_MODE; + } else { + stap_mode = SATP64_MODE; + } if (first_stage) { - vm = get_field(env->satp, SATP_MODE); - } else if (riscv_cpu_is_32bit(env)) { - vm = get_field(env->hgatp, SATP32_MODE); + vm = get_field(env->satp, stap_mode); } else { - vm = get_field(env->hgatp, SATP64_MODE); + vm = get_field(env->hgatp, stap_mode); } + page_fault_exceptions = vm != VM_1_10_MBARE && !pmp_violation; switch (access_type) { diff --git a/target/riscv/csr.c b/target/riscv/csr.c index e955753441..fe5628fea6 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -997,16 +997,27 @@ static RISCVException read_satp(CPURISCVState *env, int csrno, static RISCVException write_satp(CPURISCVState *env, int csrno, target_ulong val) { + int vm, mask, asid; + if (!riscv_feature(env, RISCV_FEATURE_MMU)) { return RISCV_EXCP_NONE; } - if (validate_vm(env, get_field(val, SATP_MODE)) && - ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN))) - { + + if (riscv_cpu_is_32bit(env)) { + vm = validate_vm(env, get_field(val, SATP32_MODE)); + mask = (val ^ env->satp) & (SATP32_MODE | SATP32_ASID | SATP32_PPN); + asid = (val ^ env->satp) & SATP32_ASID; + } else { + vm = validate_vm(env, get_field(val, SATP64_MODE)); + mask = (val ^ env->satp) & (SATP64_MODE | SATP64_ASID | SATP64_PPN); + asid = (val ^ env->satp) & SATP64_ASID; + } + + if (vm && mask) { if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) { return RISCV_EXCP_ILLEGAL_INST; } else { - if ((val ^ env->satp) & SATP_ASID) { + if (asid) { tlb_flush(env_cpu(env)); } env->satp = val; diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c index e51188f919..f7e6ea72b3 100644 --- a/target/riscv/monitor.c +++ b/target/riscv/monitor.c @@ -150,9 +150,14 @@ static void mem_info_svxx(Monitor *mon, CPUArchState *env) target_ulong last_size; int last_attr; - base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT; + if (riscv_cpu_is_32bit(env)) { + base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT; + vm = get_field(env->satp, SATP32_MODE); + } else { + base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT; + vm = get_field(env->satp, SATP64_MODE); + } - vm = get_field(env->satp, SATP_MODE); switch (vm) { case VM_1_10_SV32: levels = 2; @@ -215,9 +220,16 @@ void hmp_info_mem(Monitor *mon, const QDict *qdict) return; } - if (!(env->satp & SATP_MODE)) { - monitor_printf(mon, "No translation or protection\n"); - return; + if (riscv_cpu_is_32bit(env)) { + if (!(env->satp & SATP32_MODE)) { + monitor_printf(mon, "No translation or protection\n"); + return; + } + } else { + if (!(env->satp & SATP64_MODE)) { + monitor_printf(mon, "No translation or protection\n"); + return; + } } mem_info_svxx(mon, env); From e95ea347426a94e9ff72d77aa0179b827e228cf9 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 24 Apr 2021 13:33:48 +1000 Subject: [PATCH 0457/3028] target/riscv: Remove the unused HSTATUS_WPRI macro Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Bin Meng Message-id: e095b57af0d419c8ed822958f04dfc732d7beb7e.1619234854.git.alistair.francis@wdc.com --- target/riscv/cpu_bits.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index d98f3bc8bc..52640e6856 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -396,12 +396,6 @@ #define HSTATUS32_WPRI 0xFF8FF87E #define HSTATUS64_WPRI 0xFFFFFFFFFF8FF87EULL -#if defined(TARGET_RISCV32) -#define HSTATUS_WPRI HSTATUS32_WPRI -#elif defined(TARGET_RISCV64) -#define HSTATUS_WPRI HSTATUS64_WPRI -#endif - #define HCOUNTEREN_CY (1 << 0) #define HCOUNTEREN_TM (1 << 1) #define HCOUNTEREN_IR (1 << 2) From 4bb85634afae03182f933d382b5611c3d609e9e4 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 24 Apr 2021 13:34:00 +1000 Subject: [PATCH 0458/3028] target/riscv: Remove an unused CASE_OP_32_64 macro Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Reviewed-by: Bin Meng Message-id: 4853459564af35a6690120c74ad892f60cec35ff.1619234854.git.alistair.francis@wdc.com --- target/riscv/translate.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/riscv/translate.c b/target/riscv/translate.c index a596f80f20..a1f794ffda 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -67,12 +67,6 @@ typedef struct DisasContext { CPUState *cs; } DisasContext; -#ifdef TARGET_RISCV64 -#define CASE_OP_32_64(X) case X: case glue(X, W) -#else -#define CASE_OP_32_64(X) case X -#endif - static inline bool has_ext(DisasContext *ctx, uint32_t ext) { return ctx->misa & ext; From daf866b606bdb94bb7c7ac6621353d30958521d8 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 24 Apr 2021 13:34:12 +1000 Subject: [PATCH 0459/3028] target/riscv: Consolidate RV32/64 32-bit instructions This patch removes the insn32-64.decode decode file and consolidates the instructions into the general RISC-V insn32.decode decode tree. This means that all of the instructions are avaliable in both the 32-bit and 64-bit builds. This also means that we run a check to ensure we are running a 64-bit softmmu before we execute the 64-bit only instructions. This allows us to include the 32-bit instructions in the 64-bit build, while also ensuring that 32-bit only software can not execute the instructions. Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Message-id: db709360e2be47d2f9c6483ab973fe4791aefa77.1619234854.git.alistair.francis@wdc.com --- target/riscv/fpu_helper.c | 16 ++--- target/riscv/helper.h | 18 +++-- target/riscv/insn32-64.decode | 88 ------------------------- target/riscv/insn32.decode | 67 ++++++++++++++++++- target/riscv/insn_trans/trans_rva.c.inc | 14 +++- target/riscv/insn_trans/trans_rvd.c.inc | 17 ++++- target/riscv/insn_trans/trans_rvf.c.inc | 6 +- target/riscv/insn_trans/trans_rvh.c.inc | 8 ++- target/riscv/insn_trans/trans_rvi.c.inc | 16 +++-- target/riscv/insn_trans/trans_rvm.c.inc | 12 +++- target/riscv/insn_trans/trans_rvv.c.inc | 39 +++++------ target/riscv/meson.build | 2 +- target/riscv/translate.c | 9 ++- target/riscv/vector_helper.c | 4 -- 14 files changed, 166 insertions(+), 150 deletions(-) delete mode 100644 target/riscv/insn32-64.decode diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c index 7c4ab92ecb..8700516a14 100644 --- a/target/riscv/fpu_helper.c +++ b/target/riscv/fpu_helper.c @@ -223,13 +223,13 @@ target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t rs1) return (int32_t)float32_to_uint32(frs1, &env->fp_status); } -uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1) +target_ulong helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1) { float32 frs1 = check_nanbox_s(rs1); return float32_to_int64(frs1, &env->fp_status); } -uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1) +target_ulong helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1) { float32 frs1 = check_nanbox_s(rs1); return float32_to_uint64(frs1, &env->fp_status); @@ -245,12 +245,12 @@ uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1) return nanbox_s(uint32_to_float32((uint32_t)rs1, &env->fp_status)); } -uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1) +uint64_t helper_fcvt_s_l(CPURISCVState *env, target_ulong rs1) { return nanbox_s(int64_to_float32(rs1, &env->fp_status)); } -uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1) +uint64_t helper_fcvt_s_lu(CPURISCVState *env, target_ulong rs1) { return nanbox_s(uint64_to_float32(rs1, &env->fp_status)); } @@ -332,12 +332,12 @@ target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1) return (int32_t)float64_to_uint32(frs1, &env->fp_status); } -uint64_t helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1) +target_ulong helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1) { return float64_to_int64(frs1, &env->fp_status); } -uint64_t helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1) +target_ulong helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1) { return float64_to_uint64(frs1, &env->fp_status); } @@ -352,12 +352,12 @@ uint64_t helper_fcvt_d_wu(CPURISCVState *env, target_ulong rs1) return uint32_to_float64((uint32_t)rs1, &env->fp_status); } -uint64_t helper_fcvt_d_l(CPURISCVState *env, uint64_t rs1) +uint64_t helper_fcvt_d_l(CPURISCVState *env, target_ulong rs1) { return int64_to_float64(rs1, &env->fp_status); } -uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1) +uint64_t helper_fcvt_d_lu(CPURISCVState *env, target_ulong rs1) { return uint64_to_float64(rs1, &env->fp_status); } diff --git a/target/riscv/helper.h b/target/riscv/helper.h index e3f3f41e89..c7267593c3 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -27,12 +27,12 @@ DEF_HELPER_FLAGS_3(flt_s, TCG_CALL_NO_RWG, tl, env, i64, i64) DEF_HELPER_FLAGS_3(feq_s, TCG_CALL_NO_RWG, tl, env, i64, i64) DEF_HELPER_FLAGS_2(fcvt_w_s, TCG_CALL_NO_RWG, tl, env, i64) DEF_HELPER_FLAGS_2(fcvt_wu_s, TCG_CALL_NO_RWG, tl, env, i64) -DEF_HELPER_FLAGS_2(fcvt_l_s, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(fcvt_lu_s, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_l_s, TCG_CALL_NO_RWG, tl, env, i64) +DEF_HELPER_FLAGS_2(fcvt_lu_s, TCG_CALL_NO_RWG, tl, env, i64) DEF_HELPER_FLAGS_2(fcvt_s_w, TCG_CALL_NO_RWG, i64, env, tl) DEF_HELPER_FLAGS_2(fcvt_s_wu, TCG_CALL_NO_RWG, i64, env, tl) -DEF_HELPER_FLAGS_2(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, tl) +DEF_HELPER_FLAGS_2(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, tl) DEF_HELPER_FLAGS_1(fclass_s, TCG_CALL_NO_RWG_SE, tl, i64) /* Floating Point - Double Precision */ @@ -50,12 +50,12 @@ DEF_HELPER_FLAGS_3(flt_d, TCG_CALL_NO_RWG, tl, env, i64, i64) DEF_HELPER_FLAGS_3(feq_d, TCG_CALL_NO_RWG, tl, env, i64, i64) DEF_HELPER_FLAGS_2(fcvt_w_d, TCG_CALL_NO_RWG, tl, env, i64) DEF_HELPER_FLAGS_2(fcvt_wu_d, TCG_CALL_NO_RWG, tl, env, i64) -DEF_HELPER_FLAGS_2(fcvt_l_d, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(fcvt_lu_d, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_l_d, TCG_CALL_NO_RWG, tl, env, i64) +DEF_HELPER_FLAGS_2(fcvt_lu_d, TCG_CALL_NO_RWG, tl, env, i64) DEF_HELPER_FLAGS_2(fcvt_d_w, TCG_CALL_NO_RWG, i64, env, tl) DEF_HELPER_FLAGS_2(fcvt_d_wu, TCG_CALL_NO_RWG, i64, env, tl) -DEF_HELPER_FLAGS_2(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, tl) +DEF_HELPER_FLAGS_2(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, tl) DEF_HELPER_FLAGS_1(fclass_d, TCG_CALL_NO_RWG_SE, tl, i64) /* Special functions */ @@ -241,7 +241,6 @@ DEF_HELPER_5(vlhuff_v_w, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vlhuff_v_d, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vlwuff_v_w, void, ptr, ptr, tl, env, i32) DEF_HELPER_5(vlwuff_v_d, void, ptr, ptr, tl, env, i32) -#ifdef TARGET_RISCV64 DEF_HELPER_6(vamoswapw_v_d, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamoswapd_v_d, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamoaddw_v_d, void, ptr, ptr, tl, ptr, env, i32) @@ -260,7 +259,6 @@ DEF_HELPER_6(vamominuw_v_d, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamominud_v_d, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamomaxuw_v_d, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamomaxud_v_d, void, ptr, ptr, tl, ptr, env, i32) -#endif DEF_HELPER_6(vamoswapw_v_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamoaddw_v_w, void, ptr, ptr, tl, ptr, env, i32) DEF_HELPER_6(vamoxorw_v_w, void, ptr, ptr, tl, ptr, env, i32) diff --git a/target/riscv/insn32-64.decode b/target/riscv/insn32-64.decode deleted file mode 100644 index 8157dee8b7..0000000000 --- a/target/riscv/insn32-64.decode +++ /dev/null @@ -1,88 +0,0 @@ -# -# RISC-V translation routines for the RV Instruction Set. -# -# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de -# Bastian Koppelmann, kbastian@mail.uni-paderborn.de -# -# This program is free software; you can redistribute it and/or modify it -# under the terms and conditions of the GNU General Public License, -# version 2 or later, as published by the Free Software Foundation. -# -# This program is distributed in the hope it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see . - -# This is concatenated with insn32.decode for risc64 targets. -# Most of the fields and formats are there. - -%sh5 20:5 - -@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd - -# *** RV64I Base Instruction Set (in addition to RV32I) *** -lwu ............ ..... 110 ..... 0000011 @i -ld ............ ..... 011 ..... 0000011 @i -sd ....... ..... ..... 011 ..... 0100011 @s -addiw ............ ..... 000 ..... 0011011 @i -slliw 0000000 ..... ..... 001 ..... 0011011 @sh5 -srliw 0000000 ..... ..... 101 ..... 0011011 @sh5 -sraiw 0100000 ..... ..... 101 ..... 0011011 @sh5 -addw 0000000 ..... ..... 000 ..... 0111011 @r -subw 0100000 ..... ..... 000 ..... 0111011 @r -sllw 0000000 ..... ..... 001 ..... 0111011 @r -srlw 0000000 ..... ..... 101 ..... 0111011 @r -sraw 0100000 ..... ..... 101 ..... 0111011 @r - -# *** RV64M Standard Extension (in addition to RV32M) *** -mulw 0000001 ..... ..... 000 ..... 0111011 @r -divw 0000001 ..... ..... 100 ..... 0111011 @r -divuw 0000001 ..... ..... 101 ..... 0111011 @r -remw 0000001 ..... ..... 110 ..... 0111011 @r -remuw 0000001 ..... ..... 111 ..... 0111011 @r - -# *** RV64A Standard Extension (in addition to RV32A) *** -lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld -sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st -amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st -amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st -amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st -amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st -amoor_d 01000 . . ..... ..... 011 ..... 0101111 @atom_st -amomin_d 10000 . . ..... ..... 011 ..... 0101111 @atom_st -amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st -amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st -amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st - -#*** Vector AMO operations (in addition to Zvamo) *** -vamoswapd_v 00001 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamoaddd_v 00000 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamoxord_v 00100 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamoandd_v 01100 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamoord_v 01000 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamomind_v 10000 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamomaxd_v 10100 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamominud_v 11000 . . ..... ..... 111 ..... 0101111 @r_wdvm -vamomaxud_v 11100 . . ..... ..... 111 ..... 0101111 @r_wdvm - -# *** RV64F Standard Extension (in addition to RV32F) *** -fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm -fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm -fcvt_s_l 1101000 00010 ..... ... ..... 1010011 @r2_rm -fcvt_s_lu 1101000 00011 ..... ... ..... 1010011 @r2_rm - -# *** RV64D Standard Extension (in addition to RV32D) *** -fcvt_l_d 1100001 00010 ..... ... ..... 1010011 @r2_rm -fcvt_lu_d 1100001 00011 ..... ... ..... 1010011 @r2_rm -fmv_x_d 1110001 00000 ..... 000 ..... 1010011 @r2 -fcvt_d_l 1101001 00010 ..... ... ..... 1010011 @r2_rm -fcvt_d_lu 1101001 00011 ..... ... ..... 1010011 @r2_rm -fmv_d_x 1111001 00000 ..... 000 ..... 1010011 @r2 - -# *** RV32H Base Instruction Set *** -hlv_wu 0110100 00001 ..... 100 ..... 1110011 @r2 -hlv_d 0110110 00000 ..... 100 ..... 1110011 @r2 -hsv_d 0110111 ..... ..... 100 00000 1110011 @r2_s diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 84080dd18c..fecf0f15d5 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -21,6 +21,7 @@ %rs2 20:5 %rs1 15:5 %rd 7:5 +%sh5 20:5 %sh10 20:10 %csr 20:12 @@ -86,6 +87,8 @@ @sfence_vma ....... ..... ..... ... ..... ....... %rs2 %rs1 @sfence_vm ....... ..... ..... ... ..... ....... %rs1 +# Formats 64: +@sh5 ....... ..... ..... ... ..... ....... &shift shamt=%sh5 %rs1 %rd # *** Privileged Instructions *** ecall 000000000000 00000 000 00000 1110011 @@ -144,6 +147,20 @@ csrrwi ............ ..... 101 ..... 1110011 @csr csrrsi ............ ..... 110 ..... 1110011 @csr csrrci ............ ..... 111 ..... 1110011 @csr +# *** RV64I Base Instruction Set (in addition to RV32I) *** +lwu ............ ..... 110 ..... 0000011 @i +ld ............ ..... 011 ..... 0000011 @i +sd ....... ..... ..... 011 ..... 0100011 @s +addiw ............ ..... 000 ..... 0011011 @i +slliw 0000000 ..... ..... 001 ..... 0011011 @sh5 +srliw 0000000 ..... ..... 101 ..... 0011011 @sh5 +sraiw 0100000 ..... ..... 101 ..... 0011011 @sh5 +addw 0000000 ..... ..... 000 ..... 0111011 @r +subw 0100000 ..... ..... 000 ..... 0111011 @r +sllw 0000000 ..... ..... 001 ..... 0111011 @r +srlw 0000000 ..... ..... 101 ..... 0111011 @r +sraw 0100000 ..... ..... 101 ..... 0111011 @r + # *** RV32M Standard Extension *** mul 0000001 ..... ..... 000 ..... 0110011 @r mulh 0000001 ..... ..... 001 ..... 0110011 @r @@ -154,6 +171,13 @@ divu 0000001 ..... ..... 101 ..... 0110011 @r rem 0000001 ..... ..... 110 ..... 0110011 @r remu 0000001 ..... ..... 111 ..... 0110011 @r +# *** RV64M Standard Extension (in addition to RV32M) *** +mulw 0000001 ..... ..... 000 ..... 0111011 @r +divw 0000001 ..... ..... 100 ..... 0111011 @r +divuw 0000001 ..... ..... 101 ..... 0111011 @r +remw 0000001 ..... ..... 110 ..... 0111011 @r +remuw 0000001 ..... ..... 111 ..... 0111011 @r + # *** RV32A Standard Extension *** lr_w 00010 . . 00000 ..... 010 ..... 0101111 @atom_ld sc_w 00011 . . ..... ..... 010 ..... 0101111 @atom_st @@ -167,6 +191,19 @@ amomax_w 10100 . . ..... ..... 010 ..... 0101111 @atom_st amominu_w 11000 . . ..... ..... 010 ..... 0101111 @atom_st amomaxu_w 11100 . . ..... ..... 010 ..... 0101111 @atom_st +# *** RV64A Standard Extension (in addition to RV32A) *** +lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld +sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st +amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st +amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st +amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st +amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st +amoor_d 01000 . . ..... ..... 011 ..... 0101111 @atom_st +amomin_d 10000 . . ..... ..... 011 ..... 0101111 @atom_st +amomax_d 10100 . . ..... ..... 011 ..... 0101111 @atom_st +amominu_d 11000 . . ..... ..... 011 ..... 0101111 @atom_st +amomaxu_d 11100 . . ..... ..... 011 ..... 0101111 @atom_st + # *** RV32F Standard Extension *** flw ............ ..... 010 ..... 0000111 @i fsw ....... ..... ..... 010 ..... 0100111 @s @@ -195,6 +232,12 @@ fcvt_s_w 1101000 00000 ..... ... ..... 1010011 @r2_rm fcvt_s_wu 1101000 00001 ..... ... ..... 1010011 @r2_rm fmv_w_x 1111000 00000 ..... 000 ..... 1010011 @r2 +# *** RV64F Standard Extension (in addition to RV32F) *** +fcvt_l_s 1100000 00010 ..... ... ..... 1010011 @r2_rm +fcvt_lu_s 1100000 00011 ..... ... ..... 1010011 @r2_rm +fcvt_s_l 1101000 00010 ..... ... ..... 1010011 @r2_rm +fcvt_s_lu 1101000 00011 ..... ... ..... 1010011 @r2_rm + # *** RV32D Standard Extension *** fld ............ ..... 011 ..... 0000111 @i fsd ....... ..... ..... 011 ..... 0100111 @s @@ -223,6 +266,14 @@ fcvt_wu_d 1100001 00001 ..... ... ..... 1010011 @r2_rm fcvt_d_w 1101001 00000 ..... ... ..... 1010011 @r2_rm fcvt_d_wu 1101001 00001 ..... ... ..... 1010011 @r2_rm +# *** RV64D Standard Extension (in addition to RV32D) *** +fcvt_l_d 1100001 00010 ..... ... ..... 1010011 @r2_rm +fcvt_lu_d 1100001 00011 ..... ... ..... 1010011 @r2_rm +fmv_x_d 1110001 00000 ..... 000 ..... 1010011 @r2 +fcvt_d_l 1101001 00010 ..... ... ..... 1010011 @r2_rm +fcvt_d_lu 1101001 00011 ..... ... ..... 1010011 @r2_rm +fmv_d_x 1111001 00000 ..... 000 ..... 1010011 @r2 + # *** RV32H Base Instruction Set *** hlv_b 0110000 00000 ..... 100 ..... 1110011 @r2 hlv_bu 0110000 00001 ..... 100 ..... 1110011 @r2 @@ -237,7 +288,10 @@ hsv_w 0110101 ..... ..... 100 00000 1110011 @r2_s hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma hfence_vvma 0010001 ..... ..... 000 00000 1110011 @hfence_vvma -# *** RV32V Extension *** +# *** RV32H Base Instruction Set *** +hlv_wu 0110100 00001 ..... 100 ..... 1110011 @r2 +hlv_d 0110110 00000 ..... 100 ..... 1110011 @r2 +hsv_d 0110111 ..... ..... 100 00000 1110011 @r2_s # *** Vector loads and stores are encoded within LOADFP/STORE-FP *** vlb_v ... 100 . 00000 ..... 000 ..... 0000111 @r2_nfvm @@ -592,3 +646,14 @@ vcompress_vm 010111 - ..... ..... 010 ..... 1010111 @r vsetvli 0 ........... ..... 111 ..... 1010111 @r2_zimm vsetvl 1000000 ..... ..... 111 ..... 1010111 @r + +#*** Vector AMO operations (in addition to Zvamo) *** +vamoswapd_v 00001 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoaddd_v 00000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoxord_v 00100 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoandd_v 01100 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamoord_v 01000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamomind_v 10000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamomaxd_v 10100 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamominud_v 11000 . . ..... ..... 111 ..... 0101111 @r_wdvm +vamomaxud_v 11100 . . ..... ..... 111 ..... 0101111 @r_wdvm diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc index be8a9f06dd..ab2ec4f0a5 100644 --- a/target/riscv/insn_trans/trans_rva.c.inc +++ b/target/riscv/insn_trans/trans_rva.c.inc @@ -165,60 +165,68 @@ static bool trans_amomaxu_w(DisasContext *ctx, arg_amomaxu_w *a) return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TESL)); } -#ifdef TARGET_RISCV64 - static bool trans_lr_d(DisasContext *ctx, arg_lr_d *a) { + REQUIRE_64BIT(ctx); return gen_lr(ctx, a, MO_ALIGN | MO_TEQ); } static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a) { + REQUIRE_64BIT(ctx); return gen_sc(ctx, a, (MO_ALIGN | MO_TEQ)); } static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_add_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amoxor_d(DisasContext *ctx, arg_amoxor_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_xor_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amoand_d(DisasContext *ctx, arg_amoand_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_and_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amoor_d(DisasContext *ctx, arg_amoor_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_or_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amomin_d(DisasContext *ctx, arg_amomin_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smin_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amomax_d(DisasContext *ctx, arg_amomax_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_smax_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amominu_d(DisasContext *ctx, arg_amominu_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umin_tl, (MO_ALIGN | MO_TEQ)); } static bool trans_amomaxu_d(DisasContext *ctx, arg_amomaxu_d *a) { + REQUIRE_64BIT(ctx); return gen_amo(ctx, a, &tcg_gen_atomic_fetch_umax_tl, (MO_ALIGN | MO_TEQ)); } -#endif diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc index 4f832637fa..7e45538ae0 100644 --- a/target/riscv/insn_trans/trans_rvd.c.inc +++ b/target/riscv/insn_trans/trans_rvd.c.inc @@ -358,10 +358,9 @@ static bool trans_fcvt_d_wu(DisasContext *ctx, arg_fcvt_d_wu *a) return true; } -#ifdef TARGET_RISCV64 - static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); @@ -375,6 +374,7 @@ static bool trans_fcvt_l_d(DisasContext *ctx, arg_fcvt_l_d *a) static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); @@ -388,15 +388,21 @@ static bool trans_fcvt_lu_d(DisasContext *ctx, arg_fcvt_lu_d *a) static bool trans_fmv_x_d(DisasContext *ctx, arg_fmv_x_d *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); +#ifdef TARGET_RISCV64 gen_set_gpr(a->rd, cpu_fpr[a->rs1]); return true; +#else + qemu_build_not_reached(); +#endif } static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); @@ -412,6 +418,7 @@ static bool trans_fcvt_d_l(DisasContext *ctx, arg_fcvt_d_l *a) static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); @@ -427,9 +434,11 @@ static bool trans_fcvt_d_lu(DisasContext *ctx, arg_fcvt_d_lu *a) static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVD); +#ifdef TARGET_RISCV64 TCGv t0 = tcg_temp_new(); gen_get_gpr(t0, a->rs1); @@ -437,5 +446,7 @@ static bool trans_fmv_d_x(DisasContext *ctx, arg_fmv_d_x *a) tcg_temp_free(t0); mark_fs_dirty(ctx); return true; -} +#else + qemu_build_not_reached(); #endif +} diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc index 3dfec8211d..db1c0c9974 100644 --- a/target/riscv/insn_trans/trans_rvf.c.inc +++ b/target/riscv/insn_trans/trans_rvf.c.inc @@ -415,9 +415,9 @@ static bool trans_fmv_w_x(DisasContext *ctx, arg_fmv_w_x *a) return true; } -#ifdef TARGET_RISCV64 static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); @@ -431,6 +431,7 @@ static bool trans_fcvt_l_s(DisasContext *ctx, arg_fcvt_l_s *a) static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); @@ -444,6 +445,7 @@ static bool trans_fcvt_lu_s(DisasContext *ctx, arg_fcvt_lu_s *a) static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); @@ -460,6 +462,7 @@ static bool trans_fcvt_s_l(DisasContext *ctx, arg_fcvt_s_l *a) static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a) { + REQUIRE_64BIT(ctx); REQUIRE_FPU; REQUIRE_EXT(ctx, RVF); @@ -473,4 +476,3 @@ static bool trans_fcvt_s_lu(DisasContext *ctx, arg_fcvt_s_lu *a) tcg_temp_free(t0); return true; } -#endif diff --git a/target/riscv/insn_trans/trans_rvh.c.inc b/target/riscv/insn_trans/trans_rvh.c.inc index ce7ed5affb..6b5edf82b7 100644 --- a/target/riscv/insn_trans/trans_rvh.c.inc +++ b/target/riscv/insn_trans/trans_rvh.c.inc @@ -203,10 +203,11 @@ static bool trans_hsv_w(DisasContext *ctx, arg_hsv_w *a) #endif } -#ifdef TARGET_RISCV64 static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVH); + #ifndef CONFIG_USER_ONLY TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -228,7 +229,9 @@ static bool trans_hlv_wu(DisasContext *ctx, arg_hlv_wu *a) static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVH); + #ifndef CONFIG_USER_ONLY TCGv t0 = tcg_temp_new(); TCGv t1 = tcg_temp_new(); @@ -250,7 +253,9 @@ static bool trans_hlv_d(DisasContext *ctx, arg_hlv_d *a) static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVH); + #ifndef CONFIG_USER_ONLY TCGv t0 = tcg_temp_new(); TCGv dat = tcg_temp_new(); @@ -269,7 +274,6 @@ static bool trans_hsv_d(DisasContext *ctx, arg_hsv_d *a) return false; #endif } -#endif static bool trans_hlvx_hu(DisasContext *ctx, arg_hlvx_hu *a) { diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index d04ca0394c..1340676209 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -204,22 +204,23 @@ static bool trans_sw(DisasContext *ctx, arg_sw *a) return gen_store(ctx, a, MO_TESL); } -#ifdef TARGET_RISCV64 static bool trans_lwu(DisasContext *ctx, arg_lwu *a) { + REQUIRE_64BIT(ctx); return gen_load(ctx, a, MO_TEUL); } static bool trans_ld(DisasContext *ctx, arg_ld *a) { + REQUIRE_64BIT(ctx); return gen_load(ctx, a, MO_TEQ); } static bool trans_sd(DisasContext *ctx, arg_sd *a) { + REQUIRE_64BIT(ctx); return gen_store(ctx, a, MO_TEQ); } -#endif static bool trans_addi(DisasContext *ctx, arg_addi *a) { @@ -361,14 +362,15 @@ static bool trans_and(DisasContext *ctx, arg_and *a) return gen_arith(ctx, a, &tcg_gen_and_tl); } -#ifdef TARGET_RISCV64 static bool trans_addiw(DisasContext *ctx, arg_addiw *a) { + REQUIRE_64BIT(ctx); return gen_arith_imm_tl(ctx, a, &gen_addw); } static bool trans_slliw(DisasContext *ctx, arg_slliw *a) { + REQUIRE_64BIT(ctx); TCGv source1; source1 = tcg_temp_new(); gen_get_gpr(source1, a->rs1); @@ -383,6 +385,7 @@ static bool trans_slliw(DisasContext *ctx, arg_slliw *a) static bool trans_srliw(DisasContext *ctx, arg_srliw *a) { + REQUIRE_64BIT(ctx); TCGv t = tcg_temp_new(); gen_get_gpr(t, a->rs1); tcg_gen_extract_tl(t, t, a->shamt, 32 - a->shamt); @@ -395,6 +398,7 @@ static bool trans_srliw(DisasContext *ctx, arg_srliw *a) static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a) { + REQUIRE_64BIT(ctx); TCGv t = tcg_temp_new(); gen_get_gpr(t, a->rs1); tcg_gen_sextract_tl(t, t, a->shamt, 32 - a->shamt); @@ -405,16 +409,19 @@ static bool trans_sraiw(DisasContext *ctx, arg_sraiw *a) static bool trans_addw(DisasContext *ctx, arg_addw *a) { + REQUIRE_64BIT(ctx); return gen_arith(ctx, a, &gen_addw); } static bool trans_subw(DisasContext *ctx, arg_subw *a) { + REQUIRE_64BIT(ctx); return gen_arith(ctx, a, &gen_subw); } static bool trans_sllw(DisasContext *ctx, arg_sllw *a) { + REQUIRE_64BIT(ctx); TCGv source1 = tcg_temp_new(); TCGv source2 = tcg_temp_new(); @@ -433,6 +440,7 @@ static bool trans_sllw(DisasContext *ctx, arg_sllw *a) static bool trans_srlw(DisasContext *ctx, arg_srlw *a) { + REQUIRE_64BIT(ctx); TCGv source1 = tcg_temp_new(); TCGv source2 = tcg_temp_new(); @@ -453,6 +461,7 @@ static bool trans_srlw(DisasContext *ctx, arg_srlw *a) static bool trans_sraw(DisasContext *ctx, arg_sraw *a) { + REQUIRE_64BIT(ctx); TCGv source1 = tcg_temp_new(); TCGv source2 = tcg_temp_new(); @@ -473,7 +482,6 @@ static bool trans_sraw(DisasContext *ctx, arg_sraw *a) return true; } -#endif static bool trans_fence(DisasContext *ctx, arg_fence *a) { diff --git a/target/riscv/insn_trans/trans_rvm.c.inc b/target/riscv/insn_trans/trans_rvm.c.inc index 47cd6edc72..10ecc456fc 100644 --- a/target/riscv/insn_trans/trans_rvm.c.inc +++ b/target/riscv/insn_trans/trans_rvm.c.inc @@ -87,34 +87,42 @@ static bool trans_remu(DisasContext *ctx, arg_remu *a) return gen_arith(ctx, a, &gen_remu); } -#ifdef TARGET_RISCV64 static bool trans_mulw(DisasContext *ctx, arg_mulw *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); + return gen_arith(ctx, a, &gen_mulw); } static bool trans_divw(DisasContext *ctx, arg_divw *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); + return gen_arith_div_w(ctx, a, &gen_div); } static bool trans_divuw(DisasContext *ctx, arg_divuw *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); + return gen_arith_div_uw(ctx, a, &gen_divu); } static bool trans_remw(DisasContext *ctx, arg_remw *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); + return gen_arith_div_w(ctx, a, &gen_rem); } static bool trans_remuw(DisasContext *ctx, arg_remuw *a) { + REQUIRE_64BIT(ctx); REQUIRE_EXT(ctx, RVM); + return gen_arith_div_uw(ctx, a, &gen_remu); } -#endif diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 887c6b8883..47914a3b69 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -705,7 +705,6 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq) gen_helper_vamominuw_v_w, gen_helper_vamomaxuw_v_w }; -#ifdef TARGET_RISCV64 static gen_helper_amo *const fnsd[18] = { gen_helper_vamoswapw_v_d, gen_helper_vamoaddw_v_d, @@ -726,7 +725,6 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq) gen_helper_vamominud_v_d, gen_helper_vamomaxud_v_d }; -#endif if (tb_cflags(s->base.tb) & CF_PARALLEL) { gen_helper_exit_atomic(cpu_env); @@ -734,12 +732,12 @@ static bool amo_op(DisasContext *s, arg_rwdvm *a, uint8_t seq) return true; } else { if (s->sew == 3) { -#ifdef TARGET_RISCV64 - fn = fnsd[seq]; -#else - /* Check done in amo_check(). */ - g_assert_not_reached(); -#endif + if (!is_32bit(s)) { + fn = fnsd[seq]; + } else { + /* Check done in amo_check(). */ + g_assert_not_reached(); + } } else { assert(seq < ARRAY_SIZE(fnsw)); fn = fnsw[seq]; @@ -769,6 +767,11 @@ static bool amo_check(DisasContext *s, arg_rwdvm* a) ((1 << s->sew) >= 4)); } +static bool amo_check64(DisasContext *s, arg_rwdvm* a) +{ + return !is_32bit(s) && amo_check(s, a); +} + GEN_VEXT_TRANS(vamoswapw_v, 0, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamoaddw_v, 1, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamoxorw_v, 2, rwdvm, amo_op, amo_check) @@ -778,17 +781,15 @@ GEN_VEXT_TRANS(vamominw_v, 5, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamomaxw_v, 6, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamominuw_v, 7, rwdvm, amo_op, amo_check) GEN_VEXT_TRANS(vamomaxuw_v, 8, rwdvm, amo_op, amo_check) -#ifdef TARGET_RISCV64 -GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check) -GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check) -#endif +GEN_VEXT_TRANS(vamoswapd_v, 9, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamoaddd_v, 10, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamoxord_v, 11, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamoandd_v, 12, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamoord_v, 13, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamomind_v, 14, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamomaxd_v, 15, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamominud_v, 16, rwdvm, amo_op, amo_check64) +GEN_VEXT_TRANS(vamomaxud_v, 17, rwdvm, amo_op, amo_check64) /* *** Vector Integer Arithmetic Instructions diff --git a/target/riscv/meson.build b/target/riscv/meson.build index 88ab850682..24bf049164 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -7,7 +7,7 @@ gen32 = [ gen64 = [ decodetree.process('insn16.decode', extra_args: [dir / 'insn16-64.decode', '--static-decode=decode_insn16', '--insnwidth=16']), - decodetree.process('insn32.decode', extra_args: [dir / 'insn32-64.decode', '--static-decode=decode_insn32']), + decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'), ] riscv_ss = ss.source_set() diff --git a/target/riscv/translate.c b/target/riscv/translate.c index a1f794ffda..e945352bca 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -435,6 +435,12 @@ EX_SH(12) } \ } while (0) +#define REQUIRE_64BIT(ctx) do { \ + if (is_32bit(ctx)) { \ + return false; \ + } \ +} while (0) + static int ex_rvc_register(DisasContext *ctx, int reg) { return 8 + reg; @@ -482,7 +488,6 @@ static bool gen_arith_imm_tl(DisasContext *ctx, arg_i *a, return true; } -#ifdef TARGET_RISCV64 static void gen_addw(TCGv ret, TCGv arg1, TCGv arg2) { tcg_gen_add_tl(ret, arg1, arg2); @@ -543,8 +548,6 @@ static bool gen_arith_div_uw(DisasContext *ctx, arg_r *a, return true; } -#endif - static bool gen_arith(DisasContext *ctx, arg_r *a, void(*func)(TCGv, TCGv, TCGv)) { diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 4651a1e224..12c31aa4b4 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -751,7 +751,6 @@ GEN_VEXT_AMO_NOATOMIC_OP(vamominw_v_w, 32, 32, H4, DO_MIN, l) GEN_VEXT_AMO_NOATOMIC_OP(vamomaxw_v_w, 32, 32, H4, DO_MAX, l) GEN_VEXT_AMO_NOATOMIC_OP(vamominuw_v_w, 32, 32, H4, DO_MINU, l) GEN_VEXT_AMO_NOATOMIC_OP(vamomaxuw_v_w, 32, 32, H4, DO_MAXU, l) -#ifdef TARGET_RISCV64 GEN_VEXT_AMO_NOATOMIC_OP(vamoswapw_v_d, 64, 32, H8, DO_SWAP, l) GEN_VEXT_AMO_NOATOMIC_OP(vamoswapd_v_d, 64, 64, H8, DO_SWAP, q) GEN_VEXT_AMO_NOATOMIC_OP(vamoaddw_v_d, 64, 32, H8, DO_ADD, l) @@ -770,7 +769,6 @@ GEN_VEXT_AMO_NOATOMIC_OP(vamominuw_v_d, 64, 32, H8, DO_MINU, l) GEN_VEXT_AMO_NOATOMIC_OP(vamominud_v_d, 64, 64, H8, DO_MINU, q) GEN_VEXT_AMO_NOATOMIC_OP(vamomaxuw_v_d, 64, 32, H8, DO_MAXU, l) GEN_VEXT_AMO_NOATOMIC_OP(vamomaxud_v_d, 64, 64, H8, DO_MAXU, q) -#endif static inline void vext_amo_noatomic(void *vs3, void *v0, target_ulong base, @@ -814,7 +812,6 @@ void HELPER(NAME)(void *vs3, void *v0, target_ulong base, \ GETPC()); \ } -#ifdef TARGET_RISCV64 GEN_VEXT_AMO(vamoswapw_v_d, int32_t, int64_t, idx_d, clearq) GEN_VEXT_AMO(vamoswapd_v_d, int64_t, int64_t, idx_d, clearq) GEN_VEXT_AMO(vamoaddw_v_d, int32_t, int64_t, idx_d, clearq) @@ -833,7 +830,6 @@ GEN_VEXT_AMO(vamominuw_v_d, uint32_t, uint64_t, idx_d, clearq) GEN_VEXT_AMO(vamominud_v_d, uint64_t, uint64_t, idx_d, clearq) GEN_VEXT_AMO(vamomaxuw_v_d, uint32_t, uint64_t, idx_d, clearq) GEN_VEXT_AMO(vamomaxud_v_d, uint64_t, uint64_t, idx_d, clearq) -#endif GEN_VEXT_AMO(vamoswapw_v_w, int32_t, int32_t, idx_w, clearl) GEN_VEXT_AMO(vamoaddw_v_w, int32_t, int32_t, idx_w, clearl) GEN_VEXT_AMO(vamoxorw_v_w, int32_t, int32_t, idx_w, clearl) From 6baba30ad0b7fbad035a530cc8d0a16c9cc74dc9 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 24 Apr 2021 13:34:25 +1000 Subject: [PATCH 0460/3028] target/riscv: Consolidate RV32/64 16-bit instructions This patch removes the insn16-32.decode and insn16-64.decode decode files and consolidates the instructions into the general RISC-V insn16.decode decode tree. This means that all of the instructions are avaliable in both the 32-bit and 64-bit builds. This also means that we run a check to ensure we are running a 64-bit softmmu before we execute the 64-bit only instructions. This allows us to include the 32-bit instructions in the 64-bit build, while also ensuring that 32-bit only software can not execute the instructions. Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Message-id: 01e2b0efeae311adc7ebf133c2cde6a7a37224d7.1619234854.git.alistair.francis@wdc.com --- target/riscv/insn16-32.decode | 28 ------------------- target/riscv/insn16-64.decode | 36 ------------------------- target/riscv/insn16.decode | 30 +++++++++++++++++++++ target/riscv/insn_trans/trans_rvi.c.inc | 6 +++++ target/riscv/meson.build | 11 +++----- 5 files changed, 39 insertions(+), 72 deletions(-) delete mode 100644 target/riscv/insn16-32.decode delete mode 100644 target/riscv/insn16-64.decode diff --git a/target/riscv/insn16-32.decode b/target/riscv/insn16-32.decode deleted file mode 100644 index 0819b17028..0000000000 --- a/target/riscv/insn16-32.decode +++ /dev/null @@ -1,28 +0,0 @@ -# -# RISC-V translation routines for the RVXI Base Integer Instruction Set. -# -# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de -# Bastian Koppelmann, kbastian@mail.uni-paderborn.de -# -# This program is free software; you can redistribute it and/or modify it -# under the terms and conditions of the GNU General Public License, -# version 2 or later, as published by the Free Software Foundation. -# -# This program is distributed in the hope it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see . - -# *** RV32C Standard Extension (Quadrant 0) *** -flw 011 ... ... .. ... 00 @cl_w -fsw 111 ... ... .. ... 00 @cs_w - -# *** RV32C Standard Extension (Quadrant 1) *** -jal 001 ........... 01 @cj rd=1 # C.JAL - -# *** RV32C Standard Extension (Quadrant 2) *** -flw 011 . ..... ..... 10 @c_lwsp -fsw 111 . ..... ..... 10 @c_swsp diff --git a/target/riscv/insn16-64.decode b/target/riscv/insn16-64.decode deleted file mode 100644 index 672e1e916f..0000000000 --- a/target/riscv/insn16-64.decode +++ /dev/null @@ -1,36 +0,0 @@ -# -# RISC-V translation routines for the RVXI Base Integer Instruction Set. -# -# Copyright (c) 2018 Peer Adelt, peer.adelt@hni.uni-paderborn.de -# Bastian Koppelmann, kbastian@mail.uni-paderborn.de -# -# This program is free software; you can redistribute it and/or modify it -# under the terms and conditions of the GNU General Public License, -# version 2 or later, as published by the Free Software Foundation. -# -# This program is distributed in the hope it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see . - -# *** RV64C Standard Extension (Quadrant 0) *** -ld 011 ... ... .. ... 00 @cl_d -sd 111 ... ... .. ... 00 @cs_d - -# *** RV64C Standard Extension (Quadrant 1) *** -{ - illegal 001 - 00000 ----- 01 # c.addiw, RES rd=0 - addiw 001 . ..... ..... 01 @ci -} -subw 100 1 11 ... 00 ... 01 @cs_2 -addw 100 1 11 ... 01 ... 01 @cs_2 - -# *** RV64C Standard Extension (Quadrant 2) *** -{ - illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0 - ld 011 . ..... ..... 10 @c_ldsp -} -sd 111 . ..... ..... 10 @c_sdsp diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode index 1cb93876fe..2e9212663c 100644 --- a/target/riscv/insn16.decode +++ b/target/riscv/insn16.decode @@ -92,6 +92,16 @@ lw 010 ... ... .. ... 00 @cl_w fsd 101 ... ... .. ... 00 @cs_d sw 110 ... ... .. ... 00 @cs_w +# *** RV32C and RV64C specific Standard Extension (Quadrant 0) *** +{ + ld 011 ... ... .. ... 00 @cl_d + flw 011 ... ... .. ... 00 @cl_w +} +{ + sd 111 ... ... .. ... 00 @cs_d + fsw 111 ... ... .. ... 00 @cs_w +} + # *** RV32/64C Standard Extension (Quadrant 1) *** addi 000 . ..... ..... 01 @ci addi 010 . ..... ..... 01 @c_li @@ -111,6 +121,15 @@ jal 101 ........... 01 @cj rd=0 # C.J beq 110 ... ... ..... 01 @cb_z bne 111 ... ... ..... 01 @cb_z +# *** RV64C and RV32C specific Standard Extension (Quadrant 1) *** +{ + c64_illegal 001 - 00000 ----- 01 # c.addiw, RES rd=0 + addiw 001 . ..... ..... 01 @ci + jal 001 ........... 01 @cj rd=1 # C.JAL +} +subw 100 1 11 ... 00 ... 01 @cs_2 +addw 100 1 11 ... 01 ... 01 @cs_2 + # *** RV32/64C Standard Extension (Quadrant 2) *** slli 000 . ..... ..... 10 @c_shift2 fld 001 . ..... ..... 10 @c_ldsp @@ -130,3 +149,14 @@ fld 001 . ..... ..... 10 @c_ldsp } fsd 101 ...... ..... 10 @c_sdsp sw 110 . ..... ..... 10 @c_swsp + +# *** RV32C and RV64C specific Standard Extension (Quadrant 2) *** +{ + c64_illegal 011 - 00000 ----- 10 # c.ldsp, RES rd=0 + ld 011 . ..... ..... 10 @c_ldsp + flw 011 . ..... ..... 10 @c_lwsp +} +{ + sd 111 . ..... ..... 10 @c_sdsp + fsw 111 . ..... ..... 10 @c_swsp +} diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index 1340676209..bd93f634cf 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -24,6 +24,12 @@ static bool trans_illegal(DisasContext *ctx, arg_empty *a) return true; } +static bool trans_c64_illegal(DisasContext *ctx, arg_empty *a) +{ + REQUIRE_64BIT(ctx); + return trans_illegal(ctx, a); +} + static bool trans_lui(DisasContext *ctx, arg_lui *a) { if (a->rd != 0) { diff --git a/target/riscv/meson.build b/target/riscv/meson.build index 24bf049164..af6c3416b7 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -1,18 +1,13 @@ # FIXME extra_args should accept files() dir = meson.current_source_dir() -gen32 = [ - decodetree.process('insn16.decode', extra_args: [dir / 'insn16-32.decode', '--static-decode=decode_insn16', '--insnwidth=16']), - decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'), -] -gen64 = [ - decodetree.process('insn16.decode', extra_args: [dir / 'insn16-64.decode', '--static-decode=decode_insn16', '--insnwidth=16']), +gen = [ + decodetree.process('insn16.decode', extra_args: ['--static-decode=decode_insn16', '--insnwidth=16']), decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'), ] riscv_ss = ss.source_set() -riscv_ss.add(when: 'TARGET_RISCV32', if_true: gen32) -riscv_ss.add(when: 'TARGET_RISCV64', if_true: gen64) +riscv_ss.add(gen) riscv_ss.add(files( 'cpu.c', 'cpu_helper.c', From c30a0757f094c107e491820e3d35224eb68859c7 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Sat, 24 Apr 2021 13:34:37 +1000 Subject: [PATCH 0461/3028] target/riscv: Fix the RV64H decode comment BugLink: https://gitlab.com/qemu-project/qemu/-/issues/47 Signed-off-by: Alistair Francis Reviewed-by: Richard Henderson Message-id: 024ce841221c1d15c74b253512428c4baca7e4ba.1619234854.git.alistair.francis@wdc.com --- target/riscv/insn32.decode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index fecf0f15d5..8901ba1e1b 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -288,7 +288,7 @@ hsv_w 0110101 ..... ..... 100 00000 1110011 @r2_s hfence_gvma 0110001 ..... ..... 000 00000 1110011 @hfence_gvma hfence_vvma 0010001 ..... ..... 000 00000 1110011 @hfence_vvma -# *** RV32H Base Instruction Set *** +# *** RV64H Base Instruction Set *** hlv_wu 0110100 00001 ..... 100 ..... 1110011 @r2 hlv_d 0110110 00000 ..... 100 ..... 1110011 @r2 hsv_d 0110111 ..... ..... 100 00000 1110011 @r2_s From 1d4ae5a34f45e530d2dfd2cb86fa9e86b0abec29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 25 Mar 2021 12:53:37 +0100 Subject: [PATCH 0462/3028] hw/block/pflash_cfi02: Set romd mode in pflash_cfi02_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ROMD mode isn't related to mapping setup. Ideally we'd set this mode when the state machine resets, but for now simply move it to pflash_cfi02_realize() to not introduce logical change. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210325120921.858993-2-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 25c053693c..35e30bb812 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -173,7 +173,6 @@ static void pflash_setup_mappings(PFlashCFI02 *pfl) "pflash-alias", &pfl->orig_mem, 0, size); memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]); } - pfl->rom_mode = true; } static void pflash_reset_state_machine(PFlashCFI02 *pfl) @@ -917,6 +916,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) /* Allocate memory for a bitmap for sectors being erased. */ pfl->sector_erase_map = bitmap_new(pfl->total_sectors); + pfl->rom_mode = true; pflash_setup_mappings(pfl); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); From 27545c9df24f509c6d1c1f17478281a357125554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 25 Mar 2021 12:57:28 +0100 Subject: [PATCH 0463/3028] hw/block/pflash_cfi02: Do not create aliases when not necessary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When no mapping is requested, it is pointless to create alias regions. Only create them when multiple mappings are requested to simplify the memory layout. The flatview is not changed. For example using 'qemu-system-sh4 -M r2d -S -monitor stdio', * before: (qemu) info mtree address-space: memory 0000000000000000-ffffffffffffffff (prio 0, i/o): system 0000000000000000-0000000000ffffff (prio 0, i/o): pflash 0000000000000000-0000000000ffffff (prio 0, romd): alias pflash-alias @r2d.flash 0000000000000000-0000000000ffffff 0000000004000000-000000000400003f (prio 0, i/o): r2d-fpga 000000000c000000-000000000fffffff (prio 0, ram): r2d.sdram (qemu) info mtree -f FlatView #0 AS "memory", root: system AS "cpu-memory-0", root: system Root memory region: system 0000000000000000-0000000000ffffff (prio 0, romd): r2d.flash 0000000004000000-000000000400003f (prio 0, i/o): r2d-fpga 000000000c000000-000000000fffffff (prio 0, ram): r2d.sdram * after: (qemu) info mtree address-space: memory 0000000000000000-ffffffffffffffff (prio 0, i/o): system 0000000000000000-0000000000ffffff (prio 0, romd): r2d.flash 0000000004000000-000000000400003f (prio 0, i/o): r2d-fpga 000000000c000000-000000000fffffff (prio 0, ram): r2d.sdram (qemu) info mtree -f FlatView #0 AS "memory", root: system AS "cpu-memory-0", root: system Root memory region: system 0000000000000000-0000000000ffffff (prio 0, romd): r2d.flash 0000000004000000-000000000400003f (prio 0, i/o): r2d-fpga 000000000c000000-000000000fffffff (prio 0, ram): r2d.sdram Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20210325120921.858993-3-f4bug@amsat.org> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 35e30bb812..02c514fb6e 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -917,8 +917,12 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp) pfl->sector_erase_map = bitmap_new(pfl->total_sectors); pfl->rom_mode = true; - pflash_setup_mappings(pfl); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); + if (pfl->mappings > 1) { + pflash_setup_mappings(pfl); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem); + } else { + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->orig_mem); + } timer_init_ns(&pfl->timer, QEMU_CLOCK_VIRTUAL, pflash_timer, pfl); pfl->status = 0; From d60c3b932e2fa06aba5d7aa1c451b5d287095dc8 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 09:05:57 -0600 Subject: [PATCH 0464/3028] bsd-user: whitespace changes Space after keywords, no space for function calls and spaces around operators. Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/main.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 36a889d084..079520737b 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -149,13 +149,13 @@ void cpu_loop(CPUX86State *env) abi_ulong pc; //target_siginfo_t info; - for(;;) { + for (;;) { cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); process_queued_cpu_work(cs); - switch(trapnr) { + switch (trapnr) { case 0x80: /* syscall from int $0x80 */ if (bsd_type == target_freebsd) { @@ -344,7 +344,7 @@ void cpu_loop(CPUX86State *env) { int sig; - sig = gdb_handlesig (env, TARGET_SIGTRAP); + sig = gdb_handlesig(env, TARGET_SIGTRAP); if (sig) { info.si_signo = sig; @@ -397,7 +397,7 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1) printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n", sp_ptr, cwp1); #endif - for(i = 0; i < 16; i++) { + for (i = 0; i < 16; i++) { /* FIXME - what to do if put_user() fails? */ put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); sp_ptr += sizeof(abi_ulong); @@ -447,7 +447,7 @@ static void restore_window(CPUSPARCState *env) printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n", sp_ptr, cwp1); #endif - for(i = 0; i < 16; i++) { + for (i = 0; i < 16; i++) { /* FIXME - what to do if get_user() fails? */ get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr); sp_ptr += sizeof(abi_ulong); @@ -467,7 +467,7 @@ static void flush_windows(CPUSPARCState *env) int offset, cwp1; offset = 1; - for(;;) { + for (;;) { /* if restore would invoke restore_window(), then we can stop */ cwp1 = cpu_cwp_inc(env, env->cwp + offset); #ifndef TARGET_SPARC64 @@ -647,11 +647,11 @@ void cpu_loop(CPUSPARCState *env) #ifdef TARGET_SPARC64 badtrap: #endif - printf ("Unhandled trap: 0x%x\n", trapnr); + printf("Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, 0); - exit (1); + exit(1); } - process_pending_signals (env); + process_pending_signals(env); } } @@ -824,15 +824,15 @@ int main(int argc, char **argv) } else if (!strcmp(r, "cpu")) { cpu_model = argv[optind++]; if (is_help_option(cpu_model)) { -/* XXX: implement xxx_cpu_list for targets that still miss it */ + /* XXX: implement xxx_cpu_list for targets that still miss it */ #if defined(cpu_list) - cpu_list(); + cpu_list(); #endif exit(1); } } else if (!strcmp(r, "B")) { - guest_base = strtol(argv[optind++], NULL, 0); - have_guest_base = true; + guest_base = strtol(argv[optind++], NULL, 0); + have_guest_base = true; } else if (!strcmp(r, "drop-ld-preload")) { (void) envlist_unsetenv(envlist, "LD_PRELOAD"); } else if (!strcmp(r, "bsd")) { @@ -957,7 +957,7 @@ int main(int argc, char **argv) } } - if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) { + if (loader_exec(filename, argv + optind, target_environ, regs, info) != 0) { printf("Error loading %s\n", filename); _exit(1); } @@ -1052,8 +1052,8 @@ int main(int argc, char **argv) env->idt.limit = 255; #endif env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1), - PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); idt_table = g2h_untagged(env->idt.base); set_idt(0, 0); set_idt(1, 0); @@ -1081,8 +1081,8 @@ int main(int argc, char **argv) { uint64_t *gdt_table; env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, - PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; gdt_table = g2h_untagged(env->gdt.base); #ifdef TARGET_ABI32 @@ -1122,9 +1122,9 @@ int main(int argc, char **argv) env->pc = regs->pc; env->npc = regs->npc; env->y = regs->y; - for(i = 0; i < 8; i++) + for (i = 0; i < 8; i++) env->gregs[i] = regs->u_regs[i]; - for(i = 0; i < 8; i++) + for (i = 0; i < 8; i++) env->regwptr[i] = regs->u_regs[i + 8]; } #else From 81afda4a6e62ba791e69388635b132d70dcbb5df Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 09:10:43 -0600 Subject: [PATCH 0465/3028] bsd-user: style tweak: use C not C++ comments Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/main.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 079520737b..5253ceb24b 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -147,7 +147,7 @@ void cpu_loop(CPUX86State *env) CPUState *cs = env_cpu(env); int trapnr; abi_ulong pc; - //target_siginfo_t info; + /* target_siginfo_t info; */ for (;;) { cpu_exec_start(cs); @@ -196,7 +196,7 @@ void cpu_loop(CPUX86State *env) arg6, arg7, arg8); - } else { //if (bsd_type == target_openbsd) + } else { /* if (bsd_type == target_openbsd) */ env->regs[R_EAX] = do_openbsd_syscall(env, env->regs[R_EAX], env->regs[R_EBX], @@ -225,7 +225,7 @@ void cpu_loop(CPUX86State *env) env->regs[R_ECX], env->regs[8], env->regs[9], 0, 0); - else { //if (bsd_type == target_openbsd) + else { /* if (bsd_type == target_openbsd) */ env->regs[R_EAX] = do_openbsd_syscall(env, env->regs[R_EAX], env->regs[R_EDI], @@ -369,7 +369,7 @@ void cpu_loop(CPUX86State *env) #ifdef TARGET_SPARC #define SPARC64_STACK_BIAS 2047 -//#define DEBUG_WIN +/* #define DEBUG_WIN */ /* WARNING: dealing with register windows _is_ complicated. More info can be found at http://www.sics.se/~psm/sparcstack.html */ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) @@ -496,7 +496,7 @@ void cpu_loop(CPUSPARCState *env) { CPUState *cs = env_cpu(env); int trapnr, ret, syscall_nr; - //target_siginfo_t info; + /* target_siginfo_t info; */ while (1) { cpu_exec_start(cs); @@ -526,7 +526,7 @@ void cpu_loop(CPUSPARCState *env) env->regwptr[0], env->regwptr[1], env->regwptr[2], env->regwptr[3], env->regwptr[4], env->regwptr[5]); - else { //if (bsd_type == target_openbsd) + else { /* if (bsd_type == target_openbsd) */ #if defined(TARGET_SPARC64) syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG | TARGET_OPENBSD_SYSCALL_G2RFLAG); @@ -618,7 +618,7 @@ void cpu_loop(CPUSPARCState *env) info._sifields._sigfault._addr = env->dmmuregs[4]; else info._sifields._sigfault._addr = env->tsptr->tpc; - //queue_signal(env, info.si_signo, &info); + /* queue_signal(env, info.si_signo, &info); */ } #endif break; @@ -638,7 +638,7 @@ void cpu_loop(CPUSPARCState *env) info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; - //queue_signal(env, info.si_signo, &info); + /* queue_signal(env, info.si_signo, &info); */ } #endif } From 9c039f0eddeb5b102c452aea43a2160095d5ccd5 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 09:14:55 -0600 Subject: [PATCH 0466/3028] bsd-user: style tweak: Remove #if 0'd code Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/main.c | 143 ------------------------------------------------ 1 file changed, 143 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 5253ceb24b..c342dd7829 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -243,118 +243,10 @@ void cpu_loop(CPUX86State *env) env->eflags &= ~CC_C; } break; -#endif -#if 0 - case EXCP0B_NOSEG: - case EXCP0C_STACK: - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = TARGET_SI_KERNEL; - info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); - break; - case EXCP0D_GPF: - /* XXX: potential problem if ABI32 */ -#ifndef TARGET_X86_64 - if (env->eflags & VM_MASK) { - handle_vm86_fault(env); - } else -#endif - { - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = TARGET_SI_KERNEL; - info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); - } - break; - case EXCP0E_PAGE: - info.si_signo = SIGSEGV; - info.si_errno = 0; - if (!(env->error_code & 1)) - info.si_code = TARGET_SEGV_MAPERR; - else - info.si_code = TARGET_SEGV_ACCERR; - info._sifields._sigfault._addr = env->cr[2]; - queue_signal(env, info.si_signo, &info); - break; - case EXCP00_DIVZ: -#ifndef TARGET_X86_64 - if (env->eflags & VM_MASK) { - handle_vm86_trap(env, trapnr); - } else -#endif - { - /* division by zero */ - info.si_signo = SIGFPE; - info.si_errno = 0; - info.si_code = TARGET_FPE_INTDIV; - info._sifields._sigfault._addr = env->eip; - queue_signal(env, info.si_signo, &info); - } - break; - case EXCP01_DB: - case EXCP03_INT3: -#ifndef TARGET_X86_64 - if (env->eflags & VM_MASK) { - handle_vm86_trap(env, trapnr); - } else -#endif - { - info.si_signo = SIGTRAP; - info.si_errno = 0; - if (trapnr == EXCP01_DB) { - info.si_code = TARGET_TRAP_BRKPT; - info._sifields._sigfault._addr = env->eip; - } else { - info.si_code = TARGET_SI_KERNEL; - info._sifields._sigfault._addr = 0; - } - queue_signal(env, info.si_signo, &info); - } - break; - case EXCP04_INTO: - case EXCP05_BOUND: -#ifndef TARGET_X86_64 - if (env->eflags & VM_MASK) { - handle_vm86_trap(env, trapnr); - } else -#endif - { - info.si_signo = SIGSEGV; - info.si_errno = 0; - info.si_code = TARGET_SI_KERNEL; - info._sifields._sigfault._addr = 0; - queue_signal(env, info.si_signo, &info); - } - break; - case EXCP06_ILLOP: - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPN; - info._sifields._sigfault._addr = env->eip; - queue_signal(env, info.si_signo, &info); - break; #endif case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; -#if 0 - case EXCP_DEBUG: - { - int sig; - - sig = gdb_handlesig(env, TARGET_SIGTRAP); - if (sig) - { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); - } - } - break; -#endif default: pc = env->segs[R_CS].base + env->eip; fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", @@ -588,16 +480,6 @@ void cpu_loop(CPUSPARCState *env) break; case TT_TFAULT: case TT_DFAULT: -#if 0 - { - info.si_signo = SIGSEGV; - info.si_errno = 0; - /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; - info._sifields._sigfault._addr = env->mmuregs[4]; - queue_signal(env, info.si_signo, &info); - } -#endif break; #else case TT_SPILL: /* window overflow */ @@ -608,19 +490,6 @@ void cpu_loop(CPUSPARCState *env) break; case TT_TFAULT: case TT_DFAULT: -#if 0 - { - info.si_signo = SIGSEGV; - info.si_errno = 0; - /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; - if (trapnr == TT_DFAULT) - info._sifields._sigfault._addr = env->dmmuregs[4]; - else - info._sifields._sigfault._addr = env->tsptr->tpc; - /* queue_signal(env, info.si_signo, &info); */ - } -#endif break; #endif case EXCP_INTERRUPT: @@ -628,19 +497,7 @@ void cpu_loop(CPUSPARCState *env) break; case EXCP_DEBUG: { -#if 0 - int sig = -#endif gdb_handlesig(cs, TARGET_SIGTRAP); -#if 0 - if (sig) - { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - /* queue_signal(env, info.si_signo, &info); */ - } -#endif } break; default: From 34bc8475b3778beac98c34602c8cc40ec6ef46de Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 10:38:55 -0600 Subject: [PATCH 0467/3028] bsd-user: style tweak: Use preferred block comments Use the preferred block comment style. Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/main.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index c342dd7829..cd1c26516b 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -50,9 +50,11 @@ const char *qemu_uname_release; extern char **environ; enum BSDType bsd_type; -/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so - we allocate a bigger stack. Need a better solution, for example - by remapping the process stack directly at the right place */ +/* + * XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so + * we allocate a bigger stack. Need a better solution, for example + * by remapping the process stack directly at the right place + */ unsigned long x86_stack_size = 512 * 1024; void gemu_log(const char *fmt, ...) @@ -262,13 +264,17 @@ void cpu_loop(CPUX86State *env) #define SPARC64_STACK_BIAS 2047 /* #define DEBUG_WIN */ -/* WARNING: dealing with register windows _is_ complicated. More info - can be found at http://www.sics.se/~psm/sparcstack.html */ +/* + * WARNING: dealing with register windows _is_ complicated. More info + * can be found at http://www.sics.se/~psm/sparcstack.html + */ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) { index = (index + cwp * 16) % (16 * env->nwindows); - /* wrap handling : if cwp is on the last window, then we use the - registers 'after' the end */ + /* + * wrap handling : if cwp is on the last window, then we use the + * registers 'after' the end + */ if (index < 8 && env->cwp == env->nwindows - 1) index += 16 * env->nwindows; return index; @@ -846,9 +852,11 @@ int main(int argc, char **argv) syscall_init(); signal_init(); - /* Now that we've loaded the binary, GUEST_BASE is fixed. Delay - generating the prologue until now so that the prologue can take - the real value of GUEST_BASE into account. */ + /* + * Now that we've loaded the binary, GUEST_BASE is fixed. Delay + * generating the prologue until now so that the prologue can take + * the real value of GUEST_BASE into account. + */ tcg_prologue_init(tcg_ctx); tcg_region_init(); From ac31939941932de66e7848f1ee53d404e8ab0a2f Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 09:10:43 -0600 Subject: [PATCH 0468/3028] bsd-user: Remove commented out code Remove dead code that's been commented out forever. Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/qemu.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index b836b603af..7ccc8ad397 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -71,7 +71,6 @@ struct image_info { struct sigqueue { struct sigqueue *next; - //target_siginfo_t info; }; struct emulated_sigtable { @@ -193,9 +192,6 @@ extern int do_strace; /* signal.c */ void process_pending_signals(CPUArchState *cpu_env); void signal_init(void); -//int queue_signal(CPUArchState *env, int sig, target_siginfo_t *info); -//void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info); -//void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo); long do_sigreturn(CPUArchState *env); long do_rt_sigreturn(CPUArchState *env); abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); From 4b599848a8eac9cb12151c81c8815af2c1e03691 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 10:41:11 -0600 Subject: [PATCH 0469/3028] bsd-user: style tweak: move extern to header file extern char **environ has no standard home, so move the declaration from the .c file to a handy .h file. Since this is a standard, old-school UNIX interface dating from the 5th edition, it's not quite the same issue that the rule is supposed to protect against, though. Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/main.c | 1 - bsd-user/qemu.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index cd1c26516b..71bfe17f38 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -47,7 +47,6 @@ unsigned long reserved_va; static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; -extern char **environ; enum BSDType bsd_type; /* diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 7ccc8ad397..5a82722281 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -27,6 +27,8 @@ #include "exec/user/abitypes.h" +extern char **environ; + enum BSDType { target_freebsd, target_netbsd, From 036a013f3036b9f441e0dc8bbf0237a8c789cf7a Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 19:45:20 -0600 Subject: [PATCH 0470/3028] bsd-user: style tweak: remove spacing after '*' and add after } Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/qemu.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 5a82722281..de20e8329a 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -124,19 +124,19 @@ struct linux_binprm { int argc, envc; char **argv; char **envp; - char * filename; /* Name of binary */ + char *filename; /* Name of binary */ }; void do_init_thread(struct target_pt_regs *regs, struct image_info *infop); abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, abi_ulong stringp, int push_ptr); -int loader_exec(const char * filename, char ** argv, char ** envp, - struct target_pt_regs * regs, struct image_info *infop); +int loader_exec(const char *filename, char **argv, char **envp, + struct target_pt_regs *regs, struct image_info *infop); -int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info); -int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info); +int load_elf_binary(struct linux_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info); +int load_flt_binary(struct linux_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info); abi_long memcpy_to_target(abi_ulong dest, const void *src, unsigned long len); @@ -246,7 +246,7 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) break;\ default:\ abort();\ - }\ + } \ 0;\ }) @@ -270,7 +270,7 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) /* avoid warning */\ x = 0;\ abort();\ - }\ + } \ 0;\ }) From c2bdd9a133dc9d47449c1a432df42ed38118e01c Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 19:50:53 -0600 Subject: [PATCH 0471/3028] bsd-user: style tweak: Use preferred block comments Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/qemu.h | 74 ++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index de20e8329a..7f3cfa68aa 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -47,9 +47,10 @@ extern enum BSDType bsd_type; #define THREAD #endif -/* This struct is used to hold certain information about the image. - * Basically, it replicates in user space what would be certain - * task_struct fields in the kernel +/* + * This struct is used to hold certain information about the image. Basically, + * it replicates in user space what would be certain task_struct fields in the + * kernel */ struct image_info { abi_ulong load_addr; @@ -78,12 +79,13 @@ struct sigqueue { struct emulated_sigtable { int pending; /* true if signal is pending */ struct sigqueue *first; - struct sigqueue info; /* in order to always have memory for the - first signal, we put it here */ + /* in order to always have memory for the first signal, we put it here */ + struct sigqueue info; }; -/* NOTE: we force a big alignment so that the stack stored after is - aligned too */ +/* + * NOTE: we force a big alignment so that the stack stored after is aligned too + */ typedef struct TaskState { pid_t ts_tid; /* tid (or pid) of this task */ @@ -103,7 +105,6 @@ void init_task_state(TaskState *ts); extern const char *qemu_uname_release; extern unsigned long mmap_min_addr; -/* ??? See if we can avoid exposing so much of the loader internals. */ /* * MAX_ARG_PAGES defines the number of pages allocated for arguments * and envelope for the new program. 32 should suffice, this gives @@ -224,9 +225,11 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) return page_check_range((target_ulong)addr, size, type) == 0; } -/* NOTE __get_user and __put_user use host pointers and don't check access. */ -/* These are usually used to access struct data members once the - * struct has been locked - usually with lock_user_struct(). +/* + * NOTE __get_user and __put_user use host pointers and don't check access. + * + * These are usually used to access struct data members once the struct has been + * locked - usually with lock_user_struct(). */ #define __put_user(x, hptr)\ ({\ @@ -267,17 +270,18 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) x = (typeof(*hptr))tswap64(*(uint64_t *)(hptr));\ break;\ default:\ - /* avoid warning */\ x = 0;\ abort();\ } \ 0;\ }) -/* put_user()/get_user() take a guest address and check access */ -/* These are usually used to access an atomic data type, such as an int, - * that has been passed by address. These internally perform locking - * and unlocking on the data type. +/* + * put_user()/get_user() take a guest address and check access + * + * These are usually used to access an atomic data type, such as an int, that + * has been passed by address. These internally perform locking and unlocking + * on the data type. */ #define put_user(x, gaddr, target_type) \ ({ \ @@ -301,7 +305,6 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) __ret = __get_user((x), __hptr); \ unlock_user(__hptr, __gaddr, 0); \ } else { \ - /* avoid warning */ \ (x) = 0; \ __ret = -TARGET_EFAULT; \ } \ @@ -330,22 +333,28 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) #define get_user_u8(x, gaddr) get_user((x), (gaddr), uint8_t) #define get_user_s8(x, gaddr) get_user((x), (gaddr), int8_t) -/* copy_from_user() and copy_to_user() are usually used to copy data +/* + * copy_from_user() and copy_to_user() are usually used to copy data * buffers between the target and host. These internally perform * locking/unlocking of the memory. */ abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len); abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); -/* Functions for accessing guest memory. The tget and tput functions - read/write single values, byteswapping as necessary. The lock_user function - gets a pointer to a contiguous area of guest memory, but does not perform - any byteswapping. lock_user may return either a pointer to the guest - memory, or a temporary buffer. */ +/* + * Functions for accessing guest memory. The tget and tput functions + * read/write single values, byteswapping as necessary. The lock_user function + * gets a pointer to a contiguous area of guest memory, but does not perform + * any byteswapping. lock_user may return either a pointer to the guest + * memory, or a temporary buffer. + */ -/* Lock an area of guest memory into the host. If copy is true then the - host area will have the same contents as the guest. */ -static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy) +/* + * Lock an area of guest memory into the host. If copy is true then the + * host area will have the same contents as the guest. + */ +static inline void *lock_user(int type, abi_ulong guest_addr, long len, + int copy) { if (!access_ok(type, guest_addr, len)) return NULL; @@ -364,9 +373,10 @@ static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy #endif } -/* Unlock an area of guest memory. The first LEN bytes must be - flushed back to guest memory. host_ptr = NULL is explicitly - allowed and does nothing. */ +/* + * Unlock an area of guest memory. The first LEN bytes must be flushed back to + * guest memory. host_ptr = NULL is explicitly allowed and does nothing. + */ static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, long len) { @@ -382,8 +392,10 @@ static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, #endif } -/* Return the length of a string in target memory or -TARGET_EFAULT if - access error. */ +/* + * Return the length of a string in target memory or -TARGET_EFAULT if access + * error. + */ abi_long target_strlen(abi_ulong gaddr); /* Like lock_user but for null terminated strings. */ From 3306693438c8ee770dca7ca5a365848d7bceef55 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 19:53:36 -0600 Subject: [PATCH 0472/3028] bsd-user: style tweak: don't assign in if statements Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/qemu.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 7f3cfa68aa..2494d9209d 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -288,7 +288,8 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) abi_ulong __gaddr = (gaddr); \ target_type *__hptr; \ abi_long __ret; \ - if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \ + __hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0); \ + if (__hptr) { \ __ret = __put_user((x), __hptr); \ unlock_user(__hptr, __gaddr, sizeof(target_type)); \ } else \ @@ -301,7 +302,8 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) abi_ulong __gaddr = (gaddr); \ target_type *__hptr; \ abi_long __ret; \ - if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \ + __hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1); \ + if (__hptr) { \ __ret = __get_user((x), __hptr); \ unlock_user(__hptr, __gaddr, 0); \ } else { \ From cb0ea0197f17bc6ed4a21e3c872d440501f055f0 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 19:55:03 -0600 Subject: [PATCH 0473/3028] bsd-user: style tweak: use {} for all if statements, format else correctly Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/qemu.h | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 2494d9209d..8d3767964d 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -358,16 +358,18 @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy) { - if (!access_ok(type, guest_addr, len)) + if (!access_ok(type, guest_addr, len)) { return NULL; + } #ifdef DEBUG_REMAP { void *addr; addr = g_malloc(len); - if (copy) + if (copy) { memcpy(addr, g2h_untagged(guest_addr), len); - else + } else { memset(addr, 0, len); + } return addr; } #else @@ -384,12 +386,15 @@ static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, { #ifdef DEBUG_REMAP - if (!host_ptr) + if (!host_ptr) { return; - if (host_ptr == g2h_untagged(guest_addr)) + } + if (host_ptr == g2h_untagged(guest_addr)) { return; - if (len > 0) + } + if (len > 0) { memcpy(g2h_untagged(guest_addr), host_ptr, len); + } g_free(host_ptr); #endif } @@ -405,8 +410,9 @@ static inline void *lock_user_string(abi_ulong guest_addr) { abi_long len; len = target_strlen(guest_addr); - if (len < 0) + if (len < 0) { return NULL; + } return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1); } From b23a51dc911da0a0e884b838d26aa1017ca2dd63 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 10:58:11 -0600 Subject: [PATCH 0474/3028] bsd-user: style tweak: use {} consistently in for / if / else statements Fix various issues with {} not being present on if / for statements. Minor line length tweaks Move an assignment in an if out. Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/main.c | 66 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 71bfe17f38..0f9e6bfbc0 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -217,7 +217,7 @@ void cpu_loop(CPUX86State *env) #ifndef TARGET_ABI32 case EXCP_SYSCALL: /* syscall from syscall instruction */ - if (bsd_type == target_freebsd) + if (bsd_type == target_freebsd) { env->regs[R_EAX] = do_freebsd_syscall(env, env->regs[R_EAX], env->regs[R_EDI], @@ -226,7 +226,7 @@ void cpu_loop(CPUX86State *env) env->regs[R_ECX], env->regs[8], env->regs[9], 0, 0); - else { /* if (bsd_type == target_openbsd) */ + } else { /* if (bsd_type == target_openbsd) */ env->regs[R_EAX] = do_openbsd_syscall(env, env->regs[R_EAX], env->regs[R_EDI], @@ -250,7 +250,8 @@ void cpu_loop(CPUX86State *env) break; default: pc = env->segs[R_CS].base + env->eip; - fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", + fprintf(stderr, + "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", (long)pc, trapnr); abort(); } @@ -274,8 +275,9 @@ static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) * wrap handling : if cwp is on the last window, then we use the * registers 'after' the end */ - if (index < 8 && env->cwp == env->nwindows - 1) + if (index < 8 && env->cwp == env->nwindows - 1) { index += 16 * env->nwindows; + } return index; } @@ -287,8 +289,9 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1) sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; #ifdef TARGET_SPARC64 - if (sp_ptr & 3) + if (sp_ptr & 3) { sp_ptr += SPARC64_STACK_BIAS; + } #endif #if defined(DEBUG_WIN) printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n", @@ -337,8 +340,9 @@ static void restore_window(CPUSPARCState *env) cwp1 = cpu_cwp_inc(env, env->cwp + 1); sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)]; #ifdef TARGET_SPARC64 - if (sp_ptr & 3) + if (sp_ptr & 3) { sp_ptr += SPARC64_STACK_BIAS; + } #endif #if defined(DEBUG_WIN) printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n", @@ -351,8 +355,9 @@ static void restore_window(CPUSPARCState *env) } #ifdef TARGET_SPARC64 env->canrestore++; - if (env->cleanwin < env->nwindows - 1) + if (env->cleanwin < env->nwindows - 1) { env->cleanwin++; + } env->cansave--; #else env->wim = new_wim; @@ -368,11 +373,13 @@ static void flush_windows(CPUSPARCState *env) /* if restore would invoke restore_window(), then we can stop */ cwp1 = cpu_cwp_inc(env, env->cwp + offset); #ifndef TARGET_SPARC64 - if (env->wim & (1 << cwp1)) + if (env->wim & (1 << cwp1)) { break; + } #else - if (env->canrestore == 0) + if (env->canrestore == 0) { break; + } env->cansave++; env->canrestore--; #endif @@ -407,8 +414,9 @@ void cpu_loop(CPUSPARCState *env) #else /* FreeBSD uses 0x141 for syscalls too */ case 0x141: - if (bsd_type != target_freebsd) + if (bsd_type != target_freebsd) { goto badtrap; + } /* fallthrough */ case 0x100: #endif @@ -417,7 +425,8 @@ void cpu_loop(CPUSPARCState *env) ret = do_freebsd_syscall(env, syscall_nr, env->regwptr[0], env->regwptr[1], env->regwptr[2], env->regwptr[3], - env->regwptr[4], env->regwptr[5], 0, 0); + env->regwptr[4], env->regwptr[5], + 0, 0); else if (bsd_type == target_netbsd) ret = do_netbsd_syscall(env, syscall_nr, env->regwptr[0], env->regwptr[1], @@ -610,8 +619,9 @@ int main(int argc, char **argv) envlist_t *envlist = NULL; bsd_type = target_openbsd; - if (argc <= 1) + if (argc <= 1) { usage(); + } error_init(argv[0]); module_call_init(MODULE_INIT_TRACE); @@ -631,11 +641,13 @@ int main(int argc, char **argv) optind = 1; for (;;) { - if (optind >= argc) + if (optind >= argc) { break; + } r = argv[optind]; - if (r[0] != '-') + if (r[0] != '-') { break; + } optind++; r++; if (!strcmp(r, "-")) { @@ -652,24 +664,28 @@ int main(int argc, char **argv) log_file = argv[optind++]; } else if (!strcmp(r, "E")) { r = argv[optind++]; - if (envlist_setenv(envlist, r) != 0) + if (envlist_setenv(envlist, r) != 0) { usage(); + } } else if (!strcmp(r, "ignore-environment")) { envlist_free(envlist); envlist = envlist_create(); } else if (!strcmp(r, "U")) { r = argv[optind++]; - if (envlist_unsetenv(envlist, r) != 0) + if (envlist_unsetenv(envlist, r) != 0) { usage(); + } } else if (!strcmp(r, "s")) { r = argv[optind++]; x86_stack_size = strtol(r, (char **)&r, 0); - if (x86_stack_size <= 0) + if (x86_stack_size <= 0) { usage(); - if (*r == 'M') + } + if (*r == 'M') { x86_stack_size *= MiB; - else if (*r == 'k' || *r == 'K') + } else if (*r == 'k' || *r == 'K') { x86_stack_size *= KiB; + } } else if (!strcmp(r, "L")) { interp_prefix = argv[optind++]; } else if (!strcmp(r, "p")) { @@ -809,11 +825,13 @@ int main(int argc, char **argv) if (!have_guest_base) { FILE *fp; - if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) { + fp = fopen("/proc/sys/vm/mmap_min_addr", "r"); + if (fp != NULL) { unsigned long tmp; if (fscanf(fp, "%lu", &tmp) == 1) { mmap_min_addr = tmp; - qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n", mmap_min_addr); + qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n", + mmap_min_addr); } fclose(fp); } @@ -986,10 +1004,12 @@ int main(int argc, char **argv) env->pc = regs->pc; env->npc = regs->npc; env->y = regs->y; - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { env->gregs[i] = regs->u_regs[i]; - for (i = 0; i < 8; i++) + } + for (i = 0; i < 8; i++) { env->regwptr[i] = regs->u_regs[i + 8]; + } } #else #error unsupported target CPU From 29aabb4fc3b354e8f3bbaa1b542e27d54c324271 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 11:00:34 -0600 Subject: [PATCH 0475/3028] bsd-user: use qemu_strtoul in preference to strtol Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index 0f9e6bfbc0..18f806b032 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -36,6 +36,7 @@ #include "tcg/tcg.h" #include "qemu/timer.h" #include "qemu/envlist.h" +#include "qemu/cutils.h" #include "exec/log.h" #include "trace/control.h" @@ -612,7 +613,7 @@ int main(int argc, char **argv) TaskState ts1, *ts = &ts1; CPUArchState *env; CPUState *cpu; - int optind; + int optind, rv; const char *r; const char *gdbstub = NULL; char **target_environ, **wrk; @@ -677,8 +678,8 @@ int main(int argc, char **argv) } } else if (!strcmp(r, "s")) { r = argv[optind++]; - x86_stack_size = strtol(r, (char **)&r, 0); - if (x86_stack_size <= 0) { + rv = qemu_strtoul(r, &r, 0, &x86_stack_size); + if (rv < 0 || x86_stack_size <= 0) { usage(); } if (*r == 'M') { @@ -709,7 +710,10 @@ int main(int argc, char **argv) exit(1); } } else if (!strcmp(r, "B")) { - guest_base = strtol(argv[optind++], NULL, 0); + rv = qemu_strtoul(argv[optind++], NULL, 0, &guest_base); + if (rv < 0) { + usage(); + } have_guest_base = true; } else if (!strcmp(r, "drop-ld-preload")) { (void) envlist_unsetenv(envlist, "LD_PRELOAD"); From b4bebeee1dee8d333bfa105a6c28fec5eb34b147 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 09:05:57 -0600 Subject: [PATCH 0476/3028] bsd-user: whitespace changes Fix various whitespace-only issues from checkpatch: keyword space ( no space before ( on function calls spaces around operators suspect indentations (including one functions reindented) extra spaces around unary operators Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/elfload.c | 330 ++++++++++++++++++++++----------------------- 1 file changed, 165 insertions(+), 165 deletions(-) diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index 5f4d824d78..3c9d8c2845 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -111,7 +111,7 @@ static uint32_t get_elf_hwcap(void) #ifdef TARGET_X86_64 #define ELF_START_MMAP 0x2aaaaab000ULL -#define elf_check_arch(x) ( ((x) == ELF_ARCH) ) +#define elf_check_arch(x) (((x) == ELF_ARCH)) #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2LSB @@ -134,7 +134,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i /* * This is used to ensure we don't load something for the wrong architecture. */ -#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) +#define elf_check_arch(x) (((x) == EM_386) || ((x) == EM_486)) /* * These are used to set parameters in the core dumps. @@ -168,7 +168,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_ARM ) +#define elf_check_arch(x) ((x) == EM_ARM) #define ELF_CLASS ELFCLASS32 #ifdef TARGET_WORDS_BIGENDIAN @@ -184,7 +184,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i memset(regs, 0, sizeof(*regs)); regs->ARM_cpsr = 0x10; if (infop->entry & 1) - regs->ARM_cpsr |= CPSR_T; + regs->ARM_cpsr |= CPSR_T; regs->ARM_pc = infop->entry & 0xfffffffe; regs->ARM_sp = infop->start_stack; /* FIXME - what to for failure of get_user()? */ @@ -224,9 +224,9 @@ enum #define ELF_START_MMAP 0x80000000 #ifndef TARGET_ABI32 -#define elf_check_arch(x) ( (x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS ) +#define elf_check_arch(x) ((x) == EM_SPARCV9 || (x) == EM_SPARC32PLUS) #else -#define elf_check_arch(x) ( (x) == EM_SPARC32PLUS || (x) == EM_SPARC ) +#define elf_check_arch(x) ((x) == EM_SPARC32PLUS || (x) == EM_SPARC) #endif #define ELF_CLASS ELFCLASS64 @@ -261,7 +261,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #else #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_SPARC ) +#define elf_check_arch(x) ((x) == EM_SPARC) #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB @@ -285,13 +285,13 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #if defined(TARGET_PPC64) && !defined(TARGET_ABI32) -#define elf_check_arch(x) ( (x) == EM_PPC64 ) +#define elf_check_arch(x) ((x) == EM_PPC64) #define ELF_CLASS ELFCLASS64 #else -#define elf_check_arch(x) ( (x) == EM_PPC ) +#define elf_check_arch(x) ((x) == EM_PPC) #define ELF_CLASS ELFCLASS32 @@ -376,7 +376,7 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_MIPS ) +#define elf_check_arch(x) ((x) == EM_MIPS) #ifdef TARGET_MIPS64 #define ELF_CLASS ELFCLASS64 @@ -406,7 +406,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_SH ) +#define elf_check_arch(x) ((x) == EM_SH) #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2LSB @@ -428,7 +428,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_CRIS ) +#define elf_check_arch(x) ((x) == EM_CRIS) #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2LSB @@ -448,7 +448,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP 0x80000000 -#define elf_check_arch(x) ( (x) == EM_68K ) +#define elf_check_arch(x) ((x) == EM_68K) #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB @@ -473,7 +473,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #define ELF_START_MMAP (0x30000000000ULL) -#define elf_check_arch(x) ( (x) == ELF_ARCH ) +#define elf_check_arch(x) ((x) == ELF_ARCH) #define ELF_CLASS ELFCLASS64 #define ELF_DATA ELFDATA2MSB @@ -538,8 +538,8 @@ struct exec /* Necessary parameters */ #define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE -#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1)) -#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1)) +#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE - 1)) +#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE - 1)) #define INTERPRETER_NONE 0 #define INTERPRETER_AOUT 1 @@ -547,12 +547,12 @@ struct exec #define DLINFO_ITEMS 12 -static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) +static inline void memcpy_fromfs(void *to, const void *from, unsigned long n) { memcpy(to, from, n); } -static int load_aout_interp(void * exptr, int interp_fd); +static int load_aout_interp(void *exptr, int interp_fd); #ifdef BSWAP_NEEDED static void bswap_ehdr(struct elfhdr *ehdr) @@ -613,7 +613,7 @@ static void bswap_sym(struct elf_sym *sym) * to be put directly into the top of new user memory. * */ -static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, +static abi_ulong copy_elf_strings(int argc, char **argv, void **page, abi_ulong p) { char *tmp, *tmp1, *pag = NULL; @@ -638,10 +638,10 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, --p; --tmp; --len; if (--offset < 0) { offset = p % TARGET_PAGE_SIZE; - pag = (char *)page[p/TARGET_PAGE_SIZE]; + pag = (char *)page[p / TARGET_PAGE_SIZE]; if (!pag) { pag = g_try_malloc0(TARGET_PAGE_SIZE); - page[p/TARGET_PAGE_SIZE] = pag; + page[p / TARGET_PAGE_SIZE] = pag; if (!pag) return 0; } @@ -672,8 +672,8 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, * it for args, we'll use it for something else... */ size = x86_stack_size; - if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) - size = MAX_ARG_PAGES*TARGET_PAGE_SIZE; + if (size < MAX_ARG_PAGES * TARGET_PAGE_SIZE) + size = MAX_ARG_PAGES * TARGET_PAGE_SIZE; error = target_mmap(0, size + qemu_host_page_size, PROT_READ | PROT_WRITE, @@ -686,7 +686,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, /* we reserve one extra page at the top of the stack as guard */ target_mprotect(error + size, qemu_host_page_size, PROT_NONE); - stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; + stack_base = error + size - MAX_ARG_PAGES * TARGET_PAGE_SIZE; p += stack_base; for (i = 0 ; i < MAX_ARG_PAGES ; i++) { @@ -708,7 +708,7 @@ static void set_brk(abi_ulong start, abi_ulong end) end = HOST_PAGE_ALIGN(end); if (end <= start) return; - if(target_mmap(start, end - start, + if (target_mmap(start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0) == -1) { perror("cannot mmap brk"); @@ -738,12 +738,12 @@ static void padzero(abi_ulong elf_bss, abi_ulong last_bss) end_addr = HOST_PAGE_ALIGN(elf_bss); if (end_addr1 < end_addr) { mmap((void *)g2h_untagged(end_addr1), end_addr - end_addr1, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); } } - nbyte = elf_bss & (qemu_host_page_size-1); + nbyte = elf_bss & (qemu_host_page_size - 1); if (nbyte) { nbyte = qemu_host_page_size - nbyte; do { @@ -781,10 +781,10 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, /* * Force 16 byte _final_ alignment here for generality. */ - sp = sp &~ (abi_ulong)15; + sp = sp & ~(abi_ulong)15; size = (DLINFO_ITEMS + 1) * 2; if (k_platform) - size += 2; + size += 2; #ifdef DLINFO_ARCH_ITEMS size += DLINFO_ARCH_ITEMS * 2; #endif @@ -792,7 +792,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, size += (!ibcs ? 3 : 1); /* argc itself */ size *= n; if (size & 15) - sp -= 16 - (size & 15); + sp -= 16 - (size & 15); /* This is correct because Linux defines * elf_addr_t as Elf32_Off / Elf64_Off @@ -800,13 +800,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, #define NEW_AUX_ENT(id, val) do { \ sp -= n; put_user_ual(val, sp); \ sp -= n; put_user_ual(id, sp); \ - } while(0) + } while (0) - NEW_AUX_ENT (AT_NULL, 0); + NEW_AUX_ENT(AT_NULL, 0); /* There must be exactly DLINFO_ITEMS entries here. */ NEW_AUX_ENT(AT_PHDR, (abi_ulong)(load_addr + exec->e_phoff)); - NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr))); + NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof(struct elf_phdr))); NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum)); NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE)); NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_load_addr)); @@ -834,90 +834,90 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, } -static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, +static abi_ulong load_elf_interp(struct elfhdr *interp_elf_ex, int interpreter_fd, abi_ulong *interp_load_addr) { - struct elf_phdr *elf_phdata = NULL; - struct elf_phdr *eppnt; - abi_ulong load_addr = 0; - int load_addr_set = 0; - int retval; - abi_ulong last_bss, elf_bss; - abi_ulong error; - int i; + struct elf_phdr *elf_phdata = NULL; + struct elf_phdr *eppnt; + abi_ulong load_addr = 0; + int load_addr_set = 0; + int retval; + abi_ulong last_bss, elf_bss; + abi_ulong error; + int i; - elf_bss = 0; - last_bss = 0; - error = 0; + elf_bss = 0; + last_bss = 0; + error = 0; #ifdef BSWAP_NEEDED - bswap_ehdr(interp_elf_ex); + bswap_ehdr(interp_elf_ex); #endif - /* First of all, some simple consistency checks */ - if ((interp_elf_ex->e_type != ET_EXEC && - interp_elf_ex->e_type != ET_DYN) || - !elf_check_arch(interp_elf_ex->e_machine)) { - return ~((abi_ulong)0UL); - } + /* First of all, some simple consistency checks */ + if ((interp_elf_ex->e_type != ET_EXEC && + interp_elf_ex->e_type != ET_DYN) || + !elf_check_arch(interp_elf_ex->e_machine)) { + return ~((abi_ulong)0UL); + } - /* Now read in all of the header information */ + /* Now read in all of the header information */ - if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) - return ~(abi_ulong)0UL; + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE) + return ~(abi_ulong)0UL; - elf_phdata = (struct elf_phdr *) - malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + elf_phdata = (struct elf_phdr *) + malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); - if (!elf_phdata) - return ~((abi_ulong)0UL); + if (!elf_phdata) + return ~((abi_ulong)0UL); - /* - * If the size of this structure has changed, then punt, since - * we will be doing the wrong thing. - */ - if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { - free(elf_phdata); - return ~((abi_ulong)0UL); - } + /* + * If the size of this structure has changed, then punt, since + * we will be doing the wrong thing. + */ + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { + free(elf_phdata); + return ~((abi_ulong)0UL); + } - retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); - if(retval >= 0) { - retval = read(interpreter_fd, - (char *) elf_phdata, - sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); - } - if (retval < 0) { - perror("load_elf_interp"); - exit(-1); - free (elf_phdata); - return retval; - } + retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET); + if (retval >= 0) { + retval = read(interpreter_fd, + (char *) elf_phdata, + sizeof(struct elf_phdr) * interp_elf_ex->e_phnum); + } + if (retval < 0) { + perror("load_elf_interp"); + exit(-1); + free (elf_phdata); + return retval; + } #ifdef BSWAP_NEEDED - eppnt = elf_phdata; - for (i=0; ie_phnum; i++, eppnt++) { - bswap_phdr(eppnt); - } + eppnt = elf_phdata; + for (i = 0; ie_phnum; i++, eppnt++) { + bswap_phdr(eppnt); + } #endif - if (interp_elf_ex->e_type == ET_DYN) { - /* in order to avoid hardcoding the interpreter load - address in qemu, we allocate a big enough memory zone */ - error = target_mmap(0, INTERP_MAP_SIZE, - PROT_NONE, MAP_PRIVATE | MAP_ANON, - -1, 0); - if (error == -1) { - perror("mmap"); - exit(-1); - } - load_addr = error; - load_addr_set = 1; + if (interp_elf_ex->e_type == ET_DYN) { + /* in order to avoid hardcoding the interpreter load + address in qemu, we allocate a big enough memory zone */ + error = target_mmap(0, INTERP_MAP_SIZE, + PROT_NONE, MAP_PRIVATE | MAP_ANON, + -1, 0); + if (error == -1) { + perror("mmap"); + exit(-1); } + load_addr = error; + load_addr_set = 1; + } - eppnt = elf_phdata; - for(i=0; ie_phnum; i++, eppnt++) - if (eppnt->p_type == PT_LOAD) { + eppnt = elf_phdata; + for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) + if (eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_prot = 0; abi_ulong vaddr = 0; @@ -930,23 +930,23 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, elf_type |= MAP_FIXED; vaddr = eppnt->p_vaddr; } - error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr), - eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), - elf_prot, - elf_type, - interpreter_fd, - eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); + error = target_mmap(load_addr + TARGET_ELF_PAGESTART(vaddr), + eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr), + elf_prot, + elf_type, + interpreter_fd, + eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr)); if (error == -1) { - /* Real error */ - close(interpreter_fd); - free(elf_phdata); - return ~((abi_ulong)0UL); + /* Real error */ + close(interpreter_fd); + free(elf_phdata); + return ~((abi_ulong)0UL); } if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { - load_addr = error; - load_addr_set = 1; + load_addr = error; + load_addr_set = 1; } /* @@ -962,31 +962,31 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, */ k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; if (k > last_bss) last_bss = k; - } - - /* Now use mmap to map the library into memory. */ - - close(interpreter_fd); - - /* - * Now fill out the bss section. First pad the last page up - * to the page boundary, and then perform a mmap to make sure - * that there are zeromapped pages up to and including the last - * bss page. - */ - padzero(elf_bss, last_bss); - elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ - - /* Map the last of the bss segment */ - if (last_bss > elf_bss) { - target_mmap(elf_bss, last_bss-elf_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); } - free(elf_phdata); - *interp_load_addr = load_addr; - return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; + /* Now use mmap to map the library into memory. */ + + close(interpreter_fd); + + /* + * Now fill out the bss section. First pad the last page up + * to the page boundary, and then perform a mmap to make sure + * that there are zeromapped pages up to and including the last + * bss page. + */ + padzero(elf_bss, last_bss); + elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */ + + /* Map the last of the bss segment */ + if (last_bss > elf_bss) { + target_mmap(elf_bss, last_bss - elf_bss, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0); + } + free(elf_phdata); + + *interp_load_addr = load_addr; + return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; } static int symfind(const void *s0, const void *s1) @@ -1102,7 +1102,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) } continue; } -#if defined(TARGET_ARM) || defined (TARGET_MIPS) +#if defined(TARGET_ARM) || defined(TARGET_MIPS) /* The bottom address bit marks a Thumb or MIPS16 symbol. */ syms[i].st_value &= ~(target_ulong)1; #endif @@ -1143,8 +1143,8 @@ static void load_symbols(struct elfhdr *hdr, int fd) syminfos = s; } -int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, - struct image_info * info) +int load_elf_binary(struct linux_binprm *bprm, struct target_pt_regs *regs, + struct image_info *info) { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; @@ -1178,13 +1178,13 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, /* First of all, some simple consistency checks */ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || - (! elf_check_arch(elf_ex.e_machine))) { + (!elf_check_arch(elf_ex.e_machine))) { return -ENOEXEC; } bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p); - bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p); - bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p); + bprm->p = copy_elf_strings(bprm->envc, bprm->envp, bprm->page,bprm->p); + bprm->p = copy_elf_strings(bprm->argc, bprm->argv, bprm->page,bprm->p); if (!bprm->p) { retval = -E2BIG; } @@ -1196,21 +1196,21 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, } retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET); - if(retval > 0) { - retval = read(bprm->fd, (char *) elf_phdata, + if (retval > 0) { + retval = read(bprm->fd, (char *)elf_phdata, elf_ex.e_phentsize * elf_ex.e_phnum); } if (retval < 0) { perror("load_elf_binary"); exit(-1); - free (elf_phdata); + free(elf_phdata); return -errno; } #ifdef BSWAP_NEEDED elf_ppnt = elf_phdata; - for (i=0; ip_type == PT_INTERP) { - if ( elf_interpreter != NULL ) + if (elf_interpreter != NULL) { - free (elf_phdata); + free(elf_phdata); free(elf_interpreter); close(bprm->fd); return -EINVAL; @@ -1245,16 +1245,16 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, elf_interpreter = (char *)malloc(elf_ppnt->p_filesz); if (elf_interpreter == NULL) { - free (elf_phdata); + free(elf_phdata); close(bprm->fd); return -ENOMEM; } retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET); - if(retval >= 0) { + if (retval >= 0) { retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz); } - if(retval < 0) { + if (retval < 0) { perror("load_elf_binary2"); exit(-1); } @@ -1265,8 +1265,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, /* JRP - Need to add X86 lib dir stuff here... */ - if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 || - strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) { + if (strcmp(elf_interpreter, "/usr/lib/libc.so.1") == 0 || + strcmp(elf_interpreter, "/usr/lib/ld.so.1") == 0) { ibcs2_interpreter = 1; } @@ -1275,7 +1275,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, #endif if (retval >= 0) { retval = open(path(elf_interpreter), O_RDONLY); - if(retval >= 0) { + if (retval >= 0) { interpreter_fd = retval; } else { @@ -1287,8 +1287,8 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, if (retval >= 0) { retval = lseek(interpreter_fd, 0, SEEK_SET); - if(retval >= 0) { - retval = read(interpreter_fd,bprm->buf,128); + if (retval >= 0) { + retval = read(interpreter_fd, bprm->buf, 128); } } if (retval >= 0) { @@ -1298,7 +1298,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, if (retval < 0) { perror("load_elf_binary3"); exit(-1); - free (elf_phdata); + free(elf_phdata); free(elf_interpreter); close(bprm->fd); return retval; @@ -1308,17 +1308,17 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, } /* Some simple consistency checks for the interpreter */ - if (elf_interpreter){ + if (elf_interpreter) { interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) && (N_MAGIC(interp_ex) != QMAGIC)) { - interpreter_type = INTERPRETER_ELF; + interpreter_type = INTERPRETER_ELF; } if (interp_elf_ex.e_ident[0] != 0x7f || - strncmp((char *)&interp_elf_ex.e_ident[1], "ELF",3) != 0) { + strncmp((char *)&interp_elf_ex.e_ident[1], "ELF", 3) != 0) { interpreter_type &= ~INTERPRETER_ELF; } @@ -1334,20 +1334,20 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, and then start this sucker up */ { - char * passed_p; + char *passed_p; if (interpreter_type == INTERPRETER_AOUT) { snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd); passed_p = passed_fileno; if (elf_interpreter) { - bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p); + bprm->p = copy_elf_strings(1, &passed_p, bprm->page, bprm->p); bprm->argc++; } } if (!bprm->p) { free(elf_interpreter); - free (elf_phdata); + free(elf_phdata); close(bprm->fd); return -E2BIG; } @@ -1393,7 +1393,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, * address. */ - for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { + for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0; int elf_flags = 0; abi_ulong error; @@ -1538,7 +1538,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, printf("(brk) %x\n" , info->brk); #endif - if ( info->personality == PER_SVR4 ) + if (info->personality == PER_SVR4) { /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. @@ -1553,7 +1553,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs, return 0; } -static int load_aout_interp(void * exptr, int interp_fd) +static int load_aout_interp(void *exptr, int interp_fd) { printf("a.out interpreter not yet supported\n"); return(0); From 86545e7afe3f822b8561c7ceee7540fc3b19c3f0 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 09:05:58 -0600 Subject: [PATCH 0477/3028] bsd-user: style tweak: keyword space ( Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/syscall.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c index 4abff796c7..7d986e9700 100644 --- a/bsd-user/syscall.c +++ b/bsd-user/syscall.c @@ -95,7 +95,7 @@ static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms) abi_ulong val; int idx; - switch(op) { + switch (op) { #ifdef TARGET_ABI32 case TARGET_FREEBSD_I386_SET_GSBASE: case TARGET_FREEBSD_I386_SET_FSBASE: @@ -272,7 +272,7 @@ static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); if (!target_vec) return -TARGET_EFAULT; - for(i = 0;i < count; i++) { + for (i = 0;i < count; i++) { base = tswapl(target_vec[i].iov_base); vec[i].iov_len = tswapl(target_vec[i].iov_len); if (vec[i].iov_len != 0) { @@ -298,7 +298,7 @@ static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); if (!target_vec) return -TARGET_EFAULT; - for(i = 0;i < count; i++) { + for (i = 0;i < count; i++) { if (target_vec[i].iov_base) { base = tswapl(target_vec[i].iov_base); unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); @@ -326,10 +326,10 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, #endif record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); - if(do_strace) + if (do_strace) print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - switch(num) { + switch (num) { case TARGET_FREEBSD_NR_exit: #ifdef CONFIG_GPROF _mcleanup(); @@ -428,10 +428,10 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); - if(do_strace) + if (do_strace) print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - switch(num) { + switch (num) { case TARGET_NETBSD_NR_exit: #ifdef CONFIG_GPROF _mcleanup(); @@ -507,10 +507,10 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); - if(do_strace) + if (do_strace) print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - switch(num) { + switch (num) { case TARGET_OPENBSD_NR_exit: #ifdef CONFIG_GPROF _mcleanup(); From f4a1016fb375b9a4c454002db5dabaf145086d1a Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 09:05:58 -0600 Subject: [PATCH 0478/3028] bsd-user: style tweak: keyword space ( Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/uaccess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsd-user/uaccess.c b/bsd-user/uaccess.c index 91e2067933..89163257f4 100644 --- a/bsd-user/uaccess.c +++ b/bsd-user/uaccess.c @@ -46,7 +46,7 @@ abi_long target_strlen(abi_ulong guest_addr1) int max_len, len; guest_addr = guest_addr1; - for(;;) { + for (;;) { max_len = TARGET_PAGE_SIZE - (guest_addr & ~TARGET_PAGE_MASK); ptr = lock_user(VERIFY_READ, guest_addr, max_len, 1); if (!ptr) From 5a3d8177bf0ce9f541072fc8a02a070d40445c63 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 09:14:55 -0600 Subject: [PATCH 0479/3028] bsd-user: style tweak: Remove #if 0'd code Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/strace.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/bsd-user/strace.c b/bsd-user/strace.c index 2c3b59caf0..be40b8a20c 100644 --- a/bsd-user/strace.c +++ b/bsd-user/strace.c @@ -128,14 +128,6 @@ static void print_syscall_ret_addr(const struct syscallname *name, abi_long ret) } } -#if 0 /* currently unused */ -static void -print_syscall_ret_raw(struct syscallname *name, abi_long ret) -{ - gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret); -} -#endif - /* * An array of all of the syscalls we know about */ From 5be1d0b566c6f7f37482f9cce33345ffef76b4bc Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Fri, 23 Apr 2021 09:05:57 -0600 Subject: [PATCH 0480/3028] bsd-user: style tweak: keyword space ( Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/mmap.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index 01ec808003..0ac1b92706 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -93,11 +93,11 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot) if (start > host_start) { /* handle host page containing start */ prot1 = prot; - for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { + for (addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } if (host_end == host_start + qemu_host_page_size) { - for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } end = host_end; @@ -110,7 +110,7 @@ int target_mprotect(abi_ulong start, abi_ulong len, int prot) } if (end < host_end) { prot1 = prot; - for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) { prot1 |= page_get_flags(addr); } ret = mprotect(g2h_untagged(host_end - qemu_host_page_size), @@ -148,7 +148,7 @@ static int mmap_frag(abi_ulong real_start, /* get the protection of the target pages outside the mapping */ prot1 = 0; - for(addr = real_start; addr < real_end; addr++) { + for (addr = real_start; addr < real_end; addr++) { if (addr < start || addr >= end) prot1 |= page_get_flags(addr); } @@ -225,9 +225,9 @@ static abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size) if (addr == 0) addr = mmap_next_start; addr_start = addr; - for(;;) { + for (;;) { prot = 0; - for(addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) { + for (addr1 = addr; addr1 < (addr + size); addr1 += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr1); } if (prot == 0) @@ -262,7 +262,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, printf("MAP_FIXED "); if (flags & MAP_ANON) printf("MAP_ANON "); - switch(flags & TARGET_BSD_MAP_FLAGMASK) { + switch (flags & TARGET_BSD_MAP_FLAGMASK) { case MAP_PRIVATE: printf("MAP_PRIVATE "); break; @@ -321,7 +321,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, end = start + len; real_end = HOST_PAGE_ALIGN(end); - for(addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) { + for (addr = real_start; addr < real_end; addr += TARGET_PAGE_SIZE) { flg = page_get_flags(addr); if (flg & PAGE_RESERVED) { errno = ENXIO; @@ -433,11 +433,11 @@ int target_munmap(abi_ulong start, abi_ulong len) if (start > real_start) { /* handle host page containing start */ prot = 0; - for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { + for (addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } if (real_end == real_start + qemu_host_page_size) { - for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } end = real_end; @@ -447,7 +447,7 @@ int target_munmap(abi_ulong start, abi_ulong len) } if (end < real_end) { prot = 0; - for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { + for (addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) { prot |= page_get_flags(addr); } if (prot != 0) From 37179e9ea45d6428b29ae789209c119ac18c1d39 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 10 Mar 2021 17:30:04 +0000 Subject: [PATCH 0481/3028] sockets: update SOCKET_ADDRESS_TYPE_FD listen(2) backlog socket_get_fd() fails with the error "socket_get_fd: too many connections" if the given listen backlog value is not 1. Not all callers set the backlog to 1. For example, commit 582d4210eb2f2ab5baac328fe4b479cd86da1647 ("qemu-nbd: Use SOMAXCONN for socket listen() backlog") uses SOMAXCONN. This will always fail with in socket_get_fd(). This patch calls listen(2) on the fd to update the backlog value. The socket may already be in the listen state. I have tested that this works on Linux 5.10 and macOS Catalina. As a bonus this allows us to detect when the fd cannot listen. Now we'll be able to catch unbound or connected fds in socket_listen(). Drop the num argument from socket_get_fd() since this function is also called by socket_connect() where a listen backlog value does not make sense. Fixes: e5b6353cf25c99c3f08bf51e29933352f7140e8f ("socket: Add backlog parameter to socket_listen") Reported-by: Richard W.M. Jones Cc: Juan Quintela Cc: Eric Blake Signed-off-by: Stefan Hajnoczi Message-Id: <20210310173004.420190-1-stefanha@redhat.com> Tested-by: Richard W.M. Jones Reviewed-by: Eric Blake Reviewed-by: Stefano Garzarella Signed-off-by: Eric Blake --- util/qemu-sockets.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 8af0278f15..2463c49773 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -1116,14 +1116,10 @@ fail: return NULL; } -static int socket_get_fd(const char *fdstr, int num, Error **errp) +static int socket_get_fd(const char *fdstr, Error **errp) { Monitor *cur_mon = monitor_cur(); int fd; - if (num != 1) { - error_setg_errno(errp, EINVAL, "socket_get_fd: too many connections"); - return -1; - } if (cur_mon) { fd = monitor_get_fd(cur_mon, fdstr, errp); if (fd < 0) { @@ -1159,7 +1155,7 @@ int socket_connect(SocketAddress *addr, Error **errp) break; case SOCKET_ADDRESS_TYPE_FD: - fd = socket_get_fd(addr->u.fd.str, 1, errp); + fd = socket_get_fd(addr->u.fd.str, errp); break; case SOCKET_ADDRESS_TYPE_VSOCK: @@ -1187,7 +1183,26 @@ int socket_listen(SocketAddress *addr, int num, Error **errp) break; case SOCKET_ADDRESS_TYPE_FD: - fd = socket_get_fd(addr->u.fd.str, num, errp); + fd = socket_get_fd(addr->u.fd.str, errp); + if (fd < 0) { + return -1; + } + + /* + * If the socket is not yet in the listen state, then transition it to + * the listen state now. + * + * If it's already listening then this updates the backlog value as + * requested. + * + * If this socket cannot listen because it's already in another state + * (e.g. unbound or connected) then we'll catch the error here. + */ + if (listen(fd, num) != 0) { + error_setg_errno(errp, errno, "Failed to listen on fd socket"); + closesocket(fd); + return -1; + } break; case SOCKET_ADDRESS_TYPE_VSOCK: From 65d58c91ef1a15ad945ece367983437576f8e82b Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Thu, 29 Apr 2021 08:11:04 -0600 Subject: [PATCH 0482/3028] bsd-user: remove target_signal.h, it's unused Remove the target_signal.h file. None of its contents are currently used and the bsd-user fork doesn't use them (so this reduces the diffs there). Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/i386/target_signal.h | 20 -------------------- bsd-user/qemu.h | 1 - bsd-user/signal.c | 1 - bsd-user/sparc/target_signal.h | 27 --------------------------- bsd-user/sparc64/target_signal.h | 27 --------------------------- bsd-user/x86_64/target_signal.h | 19 ------------------- 6 files changed, 95 deletions(-) delete mode 100644 bsd-user/i386/target_signal.h delete mode 100644 bsd-user/sparc/target_signal.h delete mode 100644 bsd-user/sparc64/target_signal.h delete mode 100644 bsd-user/x86_64/target_signal.h diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h deleted file mode 100644 index 2ef36d1f98..0000000000 --- a/bsd-user/i386/target_signal.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef TARGET_SIGNAL_H -#define TARGET_SIGNAL_H - -#include "cpu.h" - -/* this struct defines a stack used during syscall handling */ - -typedef struct target_sigaltstack { - abi_ulong ss_sp; - abi_long ss_flags; - abi_ulong ss_size; -} target_stack_t; - - -static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) -{ - return state->regs[R_ESP]; -} - -#endif /* TARGET_SIGNAL_H */ diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 8d3767964d..eb66d15df7 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -38,7 +38,6 @@ extern enum BSDType bsd_type; #include "syscall_defs.h" #include "target_syscall.h" -#include "target_signal.h" #include "exec/gdbstub.h" #if defined(CONFIG_USE_NPTL) diff --git a/bsd-user/signal.c b/bsd-user/signal.c index f6f7aa2427..ad6d935569 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "qemu.h" -#include "target_signal.h" void signal_init(void) { diff --git a/bsd-user/sparc/target_signal.h b/bsd-user/sparc/target_signal.h deleted file mode 100644 index 5b2abba40f..0000000000 --- a/bsd-user/sparc/target_signal.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TARGET_SIGNAL_H -#define TARGET_SIGNAL_H - -#include "cpu.h" - -/* this struct defines a stack used during syscall handling */ - -typedef struct target_sigaltstack { - abi_ulong ss_sp; - abi_long ss_flags; - abi_ulong ss_size; -} target_stack_t; - - -#ifndef UREG_I6 -#define UREG_I6 6 -#endif -#ifndef UREG_FP -#define UREG_FP UREG_I6 -#endif - -static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) -{ - return state->regwptr[UREG_FP]; -} - -#endif /* TARGET_SIGNAL_H */ diff --git a/bsd-user/sparc64/target_signal.h b/bsd-user/sparc64/target_signal.h deleted file mode 100644 index 5b2abba40f..0000000000 --- a/bsd-user/sparc64/target_signal.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef TARGET_SIGNAL_H -#define TARGET_SIGNAL_H - -#include "cpu.h" - -/* this struct defines a stack used during syscall handling */ - -typedef struct target_sigaltstack { - abi_ulong ss_sp; - abi_long ss_flags; - abi_ulong ss_size; -} target_stack_t; - - -#ifndef UREG_I6 -#define UREG_I6 6 -#endif -#ifndef UREG_FP -#define UREG_FP UREG_I6 -#endif - -static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) -{ - return state->regwptr[UREG_FP]; -} - -#endif /* TARGET_SIGNAL_H */ diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h deleted file mode 100644 index 659cd401b8..0000000000 --- a/bsd-user/x86_64/target_signal.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef TARGET_SIGNAL_H -#define TARGET_SIGNAL_H - -#include "cpu.h" - -/* this struct defines a stack used during syscall handling */ - -typedef struct target_sigaltstack { - abi_ulong ss_sp; - abi_long ss_flags; - abi_ulong ss_size; -} target_stack_t; - -static inline abi_ulong get_sp_from_cpustate(CPUX86State *state) -{ - return state->regs[R_ESP]; -} - -#endif /* TARGET_SIGNAL_H */ From f8ce39701b5be032fb3f9c05e8adb4055f70eec2 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Thu, 29 Apr 2021 08:13:57 -0600 Subject: [PATCH 0483/3028] bsd-user: Stop building the sparc targets The forked bsd-user tree doesn't really support these targets. They aren't functional at the moment anyway. Remove them from the build so that the major reorg patch series can focus on one platform (x86) before adding addition platforms once things are shuffled. This should make it easier to review and satisfy that all revisions of a patch series are buildable. Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- default-configs/targets/sparc-bsd-user.mak | 3 --- default-configs/targets/sparc64-bsd-user.mak | 4 ---- 2 files changed, 7 deletions(-) delete mode 100644 default-configs/targets/sparc-bsd-user.mak delete mode 100644 default-configs/targets/sparc64-bsd-user.mak diff --git a/default-configs/targets/sparc-bsd-user.mak b/default-configs/targets/sparc-bsd-user.mak deleted file mode 100644 index 9ba3d7b07f..0000000000 --- a/default-configs/targets/sparc-bsd-user.mak +++ /dev/null @@ -1,3 +0,0 @@ -TARGET_ARCH=sparc -TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y diff --git a/default-configs/targets/sparc64-bsd-user.mak b/default-configs/targets/sparc64-bsd-user.mak deleted file mode 100644 index 8dd3217800..0000000000 --- a/default-configs/targets/sparc64-bsd-user.mak +++ /dev/null @@ -1,4 +0,0 @@ -TARGET_ARCH=sparc64 -TARGET_BASE_ARCH=sparc -TARGET_ALIGNED_ONLY=y -TARGET_WORDS_BIGENDIAN=y From afcbcff80bf81a3399e24c7908b17776e1489df9 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Thu, 29 Apr 2021 10:04:28 -0600 Subject: [PATCH 0484/3028] bsd-user: rename linux_binprm to bsd_binprm Rename linux_binprm to bsd_binprm to reflect that we're loading BSD binaries, not ELF ones. Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- bsd-user/bsdload.c | 4 ++-- bsd-user/elfload.c | 4 ++-- bsd-user/qemu.h | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c index e1ed3b7b60..8d83f21eda 100644 --- a/bsd-user/bsdload.c +++ b/bsd-user/bsdload.c @@ -32,7 +32,7 @@ static int count(char **vec) return i; } -static int prepare_binprm(struct linux_binprm *bprm) +static int prepare_binprm(struct bsd_binprm *bprm) { struct stat st; int mode; @@ -127,7 +127,7 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, int loader_exec(const char *filename, char **argv, char **envp, struct target_pt_regs *regs, struct image_info *infop) { - struct linux_binprm bprm; + struct bsd_binprm bprm; int retval; int i; diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index 3c9d8c2845..6edceb3ea6 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -662,7 +662,7 @@ static abi_ulong copy_elf_strings(int argc, char **argv, void **page, return p; } -static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm, +static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, struct image_info *info) { abi_ulong stack_base, size, error; @@ -1143,7 +1143,7 @@ static void load_symbols(struct elfhdr *hdr, int fd) syminfos = s; } -int load_elf_binary(struct linux_binprm *bprm, struct target_pt_regs *regs, +int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, struct image_info *info) { struct elfhdr elf_ex; diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index eb66d15df7..c02e8a5ca1 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -115,7 +115,7 @@ extern unsigned long mmap_min_addr; * This structure is used to hold the arguments that are * used when loading binaries. */ -struct linux_binprm { +struct bsd_binprm { char buf[128]; void *page[MAX_ARG_PAGES]; abi_ulong p; @@ -133,9 +133,9 @@ abi_ulong loader_build_argptr(int envc, int argc, abi_ulong sp, int loader_exec(const char *filename, char **argv, char **envp, struct target_pt_regs *regs, struct image_info *infop); -int load_elf_binary(struct linux_binprm *bprm, struct target_pt_regs *regs, +int load_elf_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, struct image_info *info); -int load_flt_binary(struct linux_binprm *bprm, struct target_pt_regs *regs, +int load_flt_binary(struct bsd_binprm *bprm, struct target_pt_regs *regs, struct image_info *info); abi_long memcpy_to_target(abi_ulong dest, const void *src, From 941a4736d2b465be1d6429415f8b1f26e2167585 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 11 Nov 2020 08:42:27 -0500 Subject: [PATCH 0485/3028] qemu-option: support accept-any QemuOptsList in qemu_opts_absorb_qdict Signed-off-by: Paolo Bonzini --- util/qemu-option.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index 9678d5b682..4944015a25 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -1056,7 +1056,8 @@ bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) while (entry != NULL) { next = qdict_next(qdict, entry); - if (find_desc_by_name(opts->list->desc, entry->key)) { + if (opts_accepts_any(opts->list) || + find_desc_by_name(opts->list->desc, entry->key)) { if (!qemu_opts_from_qdict_entry(opts, entry, errp)) { return false; } From 5ecfb76ccc056eb6127e44268e475827ae73b9e0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 5 May 2021 10:15:34 -0400 Subject: [PATCH 0486/3028] configure: fix detection of gdbus-codegen "pkg-config --variable=gdbus_codegen gio-2.0" returns "gdbus-codegen", and it does not pass test -x (which does not walk the path). Meson 0.58.0 notices that something is iffy, as the dbus_vmstate1 assignment in tests/qtest/meson.build uses an empty string as the command, and fails very eloquently: ../tests/qtest/meson.build:92:2: ERROR: No program name specified. Use the "has" function instead of test -x, and fix the generation of config-host.mak since meson.build expects that GDBUS_CODEGEN is absent, rather than empty, if the tool is unavailable. Reported-by: Sebastian Mitterle Fixes: #178 Signed-off-by: Paolo Bonzini --- configure | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 54f8475444..5877a6b2bf 100755 --- a/configure +++ b/configure @@ -3341,7 +3341,7 @@ if ! test "$gio" = "no"; then gio_cflags=$($pkg_config --cflags gio-2.0) gio_libs=$($pkg_config --libs gio-2.0) gdbus_codegen=$($pkg_config --variable=gdbus_codegen gio-2.0) - if [ ! -x "$gdbus_codegen" ]; then + if ! has "$gdbus_codegen"; then gdbus_codegen= fi # Check that the libraries actually work -- Ubuntu 18.04 ships @@ -5704,6 +5704,8 @@ if test "$gio" = "yes" ; then echo "CONFIG_GIO=y" >> $config_host_mak echo "GIO_CFLAGS=$gio_cflags" >> $config_host_mak echo "GIO_LIBS=$gio_libs" >> $config_host_mak +fi +if test "$gdbus_codegen" != "" ; then echo "GDBUS_CODEGEN=$gdbus_codegen" >> $config_host_mak fi echo "CONFIG_TLS_PRIORITY=\"$tls_priority\"" >> $config_host_mak From e804f892b90e58861edd79aafa4d1f4dbdeb3819 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 30 Apr 2021 10:45:51 -0400 Subject: [PATCH 0487/3028] coverity-scan: list components, move model to scripts/coverity-scan Place all files that can be useful to rebuild the Coverity configuration in scripts/coverity-scan: the existing model file, and the components setup. The Markdown syntax was tested with Pandoc (but in any case is meant more as a human-readable reference than as a part of documentation). Suggested-by: Peter Maydell Signed-off-by: Paolo Bonzini --- scripts/coverity-scan/COMPONENTS.md | 154 ++++++++++++++++++ .../model.c} | 0 2 files changed, 154 insertions(+) create mode 100644 scripts/coverity-scan/COMPONENTS.md rename scripts/{coverity-model.c => coverity-scan/model.c} (100%) diff --git a/scripts/coverity-scan/COMPONENTS.md b/scripts/coverity-scan/COMPONENTS.md new file mode 100644 index 0000000000..02a3447dab --- /dev/null +++ b/scripts/coverity-scan/COMPONENTS.md @@ -0,0 +1,154 @@ +This is the list of currently configured Coverity components: + +alpha + ~ (/qemu)?((/include)?/hw/alpha/.*|/target/alpha/.*) + +arm + ~ (/qemu)?((/include)?/hw/arm/.*|(/include)?/hw/.*/(arm|allwinner-a10|bcm28|digic|exynos|imx|omap|stellaris|pxa2xx|versatile|zynq|cadence).*|/hw/net/xgmac.c|/hw/ssi/xilinx_spips.c|/target/arm/.*) + +avr + ~ (/qemu)?((/include)?/hw/avr/.*|/target/avr/.*) + +cris + ~ (/qemu)?((/include)?/hw/cris/.*|/target/cris/.*) + +hexagon + ~ (/qemu)?(/target/hexagon/.*) + +hppa + ~ (/qemu)?((/include)?/hw/hppa/.*|/target/hppa/.*) + +i386 + ~ (/qemu)?((/include)?/hw/i386/.*|/target/i386/.*|/hw/intc/[^/]*apic[^/]*\.c) + +lm32 + ~ (/qemu)?((/include)?/hw/lm32/.*|/target/lm32/.*|/hw/.*/(milkymist|lm32).*) + +m68k + ~ (/qemu)?((/include)?/hw/m68k/.*|/target/m68k/.*|(/include)?/hw(/.*)?/mcf.*) + +microblaze + ~ (/qemu)?((/include)?/hw/microblaze/.*|/target/microblaze/.*) + +mips + ~ (/qemu)?((/include)?/hw/mips/.*|/target/mips/.*) + +nios2 + ~ (/qemu)?((/include)?/hw/nios2/.*|/target/nios2/.*) + +ppc + ~ (/qemu)?((/include)?/hw/ppc/.*|/target/ppc/.*|/hw/pci-host/(uninorth.*|dec.*|prep.*|ppc.*)|/hw/misc/macio/.*|(/include)?/hw/.*/(xics|openpic|spapr).*) + +riscv + ~ (/qemu)?((/include)?/hw/riscv/.*|/target/riscv/.*) + +rx + ~ (/qemu)?((/include)?/hw/rx/.*|/target/rx/.*) + +s390 + ~ (/qemu)?((/include)?/hw/s390x/.*|/target/s390x/.*|/hw/.*/s390_.*) + +sh4 + ~ (/qemu)?((/include)?/hw/sh4/.*|/target/sh4/.*) + +sparc + ~ (/qemu)?((/include)?/hw/sparc(64)?.*|/target/sparc/.*|/hw/.*/grlib.*|/hw/display/cg3.c) + +tilegx + ~ (/qemu)?(/target/tilegx/.*) + +tricore + ~ (/qemu)?((/include)?/hw/tricore/.*|/target/tricore/.*) + +unicore32 + ~ (/qemu)?((/include)?/hw/unicore32/.*|/target/unicore32/.*) + +9pfs + ~ (/qemu)?(/hw/9pfs/.*|/fsdev/.*) + +audio + ~ (/qemu)?((/include)?/(audio|hw/audio)/.*) + +block + ~ (/qemu)?(/block.*|(/include?)(/hw)?/(block|storage-daemon)/.*|(/include)?/hw/ide/.*|/qemu-(img|io).*|/util/(aio|async|thread-pool).*) + +char + ~ (/qemu)?(/qemu-char\.c|/include/sysemu/char\.h|(/include)?/hw/char/.*) + +capstone + ~ (/qemu)?(/capstone/.*) + +crypto + ~ (/qemu)?((/include)?/crypto/.*|/hw/.*/crypto.*) + +disas + ~ (/qemu)?((/include)?/disas.*) + +fpu + ~ (/qemu)?((/include)?(/fpu|/libdecnumber)/.*) + +io + ~ (/qemu)?((/include)?/io/.*) + +ipmi + ~ (/qemu)?((/include)?/hw/ipmi/.*) + +libvixl + ~ (/qemu)?(/disas/libvixl/.*) + +migration + ~ (/qemu)?((/include)?/migration/.*) + +monitor + ~ (/qemu)?(/qapi.*|/qobject/.*|/monitor\..*|/[hq]mp\..*) + +nbd + ~ (/qemu)?(/nbd/.*|/include/block/nbd.*|/qemu-nbd\.c) + +net + ~ (/qemu)?((/include)?(/hw)?/(net|rdma)/.*) + +pci + ~ (/qemu)?(/hw/pci.*|/include/hw/pci.*) + +qemu-ga + ~ (/qemu)?(/qga/.*) + +scsi + ~ (/qemu)?(/scsi/.*|/hw/scsi/.*|/include/hw/scsi/.*) + +slirp + ~ (/qemu)?(/.*slirp.*) + +tcg + ~ (/qemu)?(/accel/tcg/.*|/replay/.*|/(.*/)?softmmu.*) + +trace + ~ (/qemu)?(/.*trace.*\.[ch]) + +ui + ~ (/qemu)?((/include)?(/ui|/hw/display|/hw/input)/.*) + +usb + ~ (/qemu)?(/hw/usb/.*|/include/hw/usb/.*) + +user + ~ (/qemu)?(/linux-user/.*|/bsd-user/.*|/user-exec\.c|/thunk\.c|/include/exec/user/.*) + +util + ~ (/qemu)?(/util/.*|/include/qemu/.*) + +xen + ~ (/qemu)?(.*/xen.*) + +virtiofsd + ~ (/qemu)?(/tools/virtiofsd/.*) + +(headers) + ~ (/qemu)?(/include/.*) + +testlibs + ~ (/qemu)?(/tests/qtest(/libqos/.*|/libqtest.*)) + +tests + ~ (/qemu)?(/tests/.*) diff --git a/scripts/coverity-model.c b/scripts/coverity-scan/model.c similarity index 100% rename from scripts/coverity-model.c rename to scripts/coverity-scan/model.c From a67b996e7894edfafbcd3fd007c9f58f26d25908 Mon Sep 17 00:00:00 2001 From: Stefan Reiter Date: Mon, 22 Mar 2021 16:40:24 +0100 Subject: [PATCH 0488/3028] monitor/qmp: fix race on CHR_EVENT_CLOSED without OOB The QMP dispatcher coroutine holds the qmp_queue_lock over a yield point, where it expects to be rescheduled from the main context. If a CHR_EVENT_CLOSED event is received just then, it can race and block the main thread on the mutex in monitor_qmp_cleanup_queue_and_resume. monitor_resume does not need to be called from main context, so we can call it immediately after popping a request from the queue, which allows us to drop the qmp_queue_lock mutex before yielding. Suggested-by: Wolfgang Bumiller Signed-off-by: Stefan Reiter Message-Id: <20210322154024.15011-1-s.reiter@proxmox.com> Reviewed-by: Kevin Wolf Cc: qemu-stable@nongnu.org Signed-off-by: Markus Armbruster --- monitor/qmp.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/monitor/qmp.c b/monitor/qmp.c index 2b0308f933..092c527b6f 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -257,24 +257,6 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data) trace_monitor_qmp_in_band_dequeue(req_obj, req_obj->mon->qmp_requests->length); - if (qatomic_xchg(&qmp_dispatcher_co_busy, true) == true) { - /* - * Someone rescheduled us (probably because a new requests - * came in), but we didn't actually yield. Do that now, - * only to be immediately reentered and removed from the - * list of scheduled coroutines. - */ - qemu_coroutine_yield(); - } - - /* - * Move the coroutine from iohandler_ctx to qemu_aio_context for - * executing the command handler so that it can make progress if it - * involves an AIO_WAIT_WHILE(). - */ - aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co); - qemu_coroutine_yield(); - /* * @req_obj has a request, we hold req_obj->mon->qmp_queue_lock */ @@ -298,8 +280,30 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data) monitor_resume(&mon->common); } + /* + * Drop the queue mutex now, before yielding, otherwise we might + * deadlock if the main thread tries to lock it. + */ qemu_mutex_unlock(&mon->qmp_queue_lock); + if (qatomic_xchg(&qmp_dispatcher_co_busy, true) == true) { + /* + * Someone rescheduled us (probably because a new requests + * came in), but we didn't actually yield. Do that now, + * only to be immediately reentered and removed from the + * list of scheduled coroutines. + */ + qemu_coroutine_yield(); + } + + /* + * Move the coroutine from iohandler_ctx to qemu_aio_context for + * executing the command handler so that it can make progress if it + * involves an AIO_WAIT_WHILE(). + */ + aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co); + qemu_coroutine_yield(); + /* Process request */ if (req_obj->req) { if (trace_event_get_state(TRACE_MONITOR_QMP_CMD_IN_BAND)) { From 875bb7e35b78c609252187dc7bd68d90bf742da9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 30 Apr 2021 18:03:55 +0200 Subject: [PATCH 0489/3028] Remove the deprecated moxie target There are no known users of this CPU anymore, and there are no binaries available online which could be used for regression tests, so the code has likely completely bit-rotten already. It's been marked as deprecated since two releases now and nobody spoke up that there is still a need to keep it, thus let's remove it now. Signed-off-by: Thomas Huth Message-Id: <20210430160355.698194-1-thuth@redhat.com> Reviewed-by: Peter Maydell Reviewed-by: Richard Henderson [Commit message typos fixed, trivial conflicts resolved] Signed-off-by: Markus Armbruster --- .gitlab-ci.yml | 6 +- MAINTAINERS | 8 - default-configs/devices/moxie-softmmu.mak | 5 - default-configs/targets/moxie-softmmu.mak | 2 - disas/meson.build | 1 - disas/moxie.c | 360 --------- docs/system/deprecated.rst | 8 - docs/system/removed-features.rst | 7 + fpu/softfloat-specialize.c.inc | 2 +- hw/Kconfig | 1 - hw/meson.build | 1 - hw/moxie/Kconfig | 3 - hw/moxie/meson.build | 4 - hw/moxie/moxiesim.c | 155 ---- include/disas/dis-asm.h | 1 - include/elf.h | 3 - include/exec/poison.h | 2 - include/hw/elf_ops.h | 8 - include/sysemu/arch_init.h | 1 - meson.build | 1 - qapi/machine.json | 2 +- qapi/misc-target.json | 2 +- softmmu/arch_init.c | 2 - target/meson.build | 1 - target/moxie/cpu-param.h | 17 - target/moxie/cpu.c | 161 ---- target/moxie/cpu.h | 123 --- target/moxie/helper.c | 120 --- target/moxie/helper.h | 5 - target/moxie/machine.c | 19 - target/moxie/machine.h | 1 - target/moxie/meson.build | 14 - target/moxie/mmu.c | 32 - target/moxie/mmu.h | 19 - target/moxie/translate.c | 892 ---------------------- tests/qtest/boot-serial-test.c | 8 - tests/qtest/machine-none-test.c | 1 - tests/qtest/meson.build | 2 - 38 files changed, 13 insertions(+), 1987 deletions(-) delete mode 100644 default-configs/devices/moxie-softmmu.mak delete mode 100644 default-configs/targets/moxie-softmmu.mak delete mode 100644 disas/moxie.c delete mode 100644 hw/moxie/Kconfig delete mode 100644 hw/moxie/meson.build delete mode 100644 hw/moxie/moxiesim.c delete mode 100644 target/moxie/cpu-param.h delete mode 100644 target/moxie/cpu.c delete mode 100644 target/moxie/cpu.h delete mode 100644 target/moxie/helper.c delete mode 100644 target/moxie/helper.h delete mode 100644 target/moxie/machine.c delete mode 100644 target/moxie/machine.h delete mode 100644 target/moxie/meson.build delete mode 100644 target/moxie/mmu.c delete mode 100644 target/moxie/mmu.h delete mode 100644 target/moxie/translate.c diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dcb6317aac..da6570799b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -89,7 +89,7 @@ build-system-alpine: variables: IMAGE: alpine TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu - moxie-softmmu microblazeel-softmmu mips64el-softmmu + microblazeel-softmmu mips64el-softmmu MAKE_CHECK_ARGS: check-build CONFIGURE_ARGS: --enable-docs --enable-trace-backends=log,simple,syslog artifacts: @@ -125,7 +125,7 @@ build-system-ubuntu: IMAGE: ubuntu2004 CONFIGURE_ARGS: --enable-docs --enable-fdt=system --enable-slirp=system TARGETS: aarch64-softmmu alpha-softmmu cris-softmmu hppa-softmmu - moxie-softmmu microblazeel-softmmu mips64el-softmmu + microblazeel-softmmu mips64el-softmmu MAKE_CHECK_ARGS: check-build artifacts: expire_in: 2 days @@ -684,7 +684,7 @@ build-tci: variables: IMAGE: debian-all-test-cross script: - - TARGETS="aarch64 alpha arm hppa m68k microblaze moxie ppc64 s390x x86_64" + - TARGETS="aarch64 alpha arm hppa m68k microblaze ppc64 s390x x86_64" - mkdir build - cd build - ../configure --enable-tcg-interpreter diff --git a/MAINTAINERS b/MAINTAINERS index 06642d9799..50884fef15 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -258,14 +258,6 @@ MIPS TCG CPUs (nanoMIPS ISA) S: Orphan F: disas/nanomips.* -Moxie TCG CPUs -M: Anthony Green -S: Maintained -F: target/moxie/ -F: disas/moxie.c -F: hw/moxie/ -F: default-configs/*/moxie-softmmu.mak - NiosII TCG CPUs M: Chris Wulff M: Marek Vasut diff --git a/default-configs/devices/moxie-softmmu.mak b/default-configs/devices/moxie-softmmu.mak deleted file mode 100644 index bd50da3c58..0000000000 --- a/default-configs/devices/moxie-softmmu.mak +++ /dev/null @@ -1,5 +0,0 @@ -# Default configuration for moxie-softmmu - -# Boards: -# -CONFIG_MOXIESIM=y diff --git a/default-configs/targets/moxie-softmmu.mak b/default-configs/targets/moxie-softmmu.mak deleted file mode 100644 index 183e6b0ebd..0000000000 --- a/default-configs/targets/moxie-softmmu.mak +++ /dev/null @@ -1,2 +0,0 @@ -TARGET_ARCH=moxie -TARGET_WORDS_BIGENDIAN=y diff --git a/disas/meson.build b/disas/meson.build index 4c8da01877..39a5475ff6 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -13,7 +13,6 @@ common_ss.add(when: 'CONFIG_LM32_DIS', if_true: files('lm32.c')) common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c')) common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c')) common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c')) -common_ss.add(when: 'CONFIG_MOXIE_DIS', if_true: files('moxie.c')) common_ss.add(when: 'CONFIG_NANOMIPS_DIS', if_true: files('nanomips.cpp')) common_ss.add(when: 'CONFIG_NIOS2_DIS', if_true: files('nios2.c')) common_ss.add(when: 'CONFIG_PPC_DIS', if_true: files('ppc.c')) diff --git a/disas/moxie.c b/disas/moxie.c deleted file mode 100644 index e94ab4c33d..0000000000 --- a/disas/moxie.c +++ /dev/null @@ -1,360 +0,0 @@ -/* Disassemble moxie instructions. - Copyright (c) 2009 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . */ - -#include "qemu/osdep.h" -#define STATIC_TABLE -#define DEFINE_TABLE - -#include "disas/dis-asm.h" - -static void *stream; - -/* Form 1 instructions come in different flavors: - - Some have no arguments (MOXIE_F1_NARG) - Some only use the A operand (MOXIE_F1_A) - Some use A and B registers (MOXIE_F1_AB) - Some use A and consume a 4 byte immediate value (MOXIE_F1_A4) - Some use just a 4 byte immediate value (MOXIE_F1_4) - Some use just a 4 byte memory address (MOXIE_F1_M) - Some use B and an indirect A (MOXIE_F1_AiB) - Some use A and an indirect B (MOXIE_F1_ABi) - Some consume a 4 byte immediate value and use X (MOXIE_F1_4A) - Some use B and an indirect A plus 4 bytes (MOXIE_F1_AiB4) - Some use A and an indirect B plus 4 bytes (MOXIE_F1_ABi4) - - Form 2 instructions also come in different flavors: - - Some have no arguments (MOXIE_F2_NARG) - Some use the A register and an 8-bit value (MOXIE_F2_A8V) - - Form 3 instructions also come in different flavors: - - Some have no arguments (MOXIE_F3_NARG) - Some have a 10-bit PC relative operand (MOXIE_F3_PCREL). */ - -#define MOXIE_F1_NARG 0x100 -#define MOXIE_F1_A 0x101 -#define MOXIE_F1_AB 0x102 -/* #define MOXIE_F1_ABC 0x103 */ -#define MOXIE_F1_A4 0x104 -#define MOXIE_F1_4 0x105 -#define MOXIE_F1_AiB 0x106 -#define MOXIE_F1_ABi 0x107 -#define MOXIE_F1_4A 0x108 -#define MOXIE_F1_AiB4 0x109 -#define MOXIE_F1_ABi4 0x10a -#define MOXIE_F1_M 0x10b - -#define MOXIE_F2_NARG 0x200 -#define MOXIE_F2_A8V 0x201 - -#define MOXIE_F3_NARG 0x300 -#define MOXIE_F3_PCREL 0x301 - -typedef struct moxie_opc_info_t { - short opcode; - unsigned itype; - const char * name; -} moxie_opc_info_t; - -extern const moxie_opc_info_t moxie_form1_opc_info[64]; -extern const moxie_opc_info_t moxie_form2_opc_info[4]; -extern const moxie_opc_info_t moxie_form3_opc_info[16]; - -/* The moxie processor's 16-bit instructions come in two forms: - - FORM 1 instructions start with a 0 bit... - - 0oooooooaaaabbbb - 0 F - - ooooooo - form 1 opcode number - aaaa - operand A - bbbb - operand B - - FORM 2 instructions start with bits "10"... - - 10ooaaaavvvvvvvv - 0 F - - oo - form 2 opcode number - aaaa - operand A - vvvvvvvv - 8-bit immediate value - - FORM 3 instructions start with a bits "11"... - - 11oooovvvvvvvvvv - 0 F - - oooo - form 3 opcode number - vvvvvvvvvv - 10-bit immediate value. */ - -const moxie_opc_info_t moxie_form1_opc_info[64] = - { - { 0x00, MOXIE_F1_NARG, "nop" }, - { 0x01, MOXIE_F1_A4, "ldi.l" }, - { 0x02, MOXIE_F1_AB, "mov" }, - { 0x03, MOXIE_F1_M, "jsra" }, - { 0x04, MOXIE_F1_NARG, "ret" }, - { 0x05, MOXIE_F1_AB, "add.l" }, - { 0x06, MOXIE_F1_AB, "push" }, - { 0x07, MOXIE_F1_AB, "pop" }, - { 0x08, MOXIE_F1_A4, "lda.l" }, - { 0x09, MOXIE_F1_4A, "sta.l" }, - { 0x0a, MOXIE_F1_ABi, "ld.l" }, - { 0x0b, MOXIE_F1_AiB, "st.l" }, - { 0x0c, MOXIE_F1_ABi4, "ldo.l" }, - { 0x0d, MOXIE_F1_AiB4, "sto.l" }, - { 0x0e, MOXIE_F1_AB, "cmp" }, - { 0x0f, MOXIE_F1_NARG, "bad" }, - { 0x10, MOXIE_F1_NARG, "bad" }, - { 0x11, MOXIE_F1_NARG, "bad" }, - { 0x12, MOXIE_F1_NARG, "bad" }, - { 0x13, MOXIE_F1_NARG, "bad" }, - { 0x14, MOXIE_F1_NARG, "bad" }, - { 0x15, MOXIE_F1_NARG, "bad" }, - { 0x16, MOXIE_F1_NARG, "bad" }, - { 0x17, MOXIE_F1_NARG, "bad" }, - { 0x18, MOXIE_F1_NARG, "bad" }, - { 0x19, MOXIE_F1_A, "jsr" }, - { 0x1a, MOXIE_F1_M, "jmpa" }, - { 0x1b, MOXIE_F1_A4, "ldi.b" }, - { 0x1c, MOXIE_F1_ABi, "ld.b" }, - { 0x1d, MOXIE_F1_A4, "lda.b" }, - { 0x1e, MOXIE_F1_AiB, "st.b" }, - { 0x1f, MOXIE_F1_4A, "sta.b" }, - { 0x20, MOXIE_F1_A4, "ldi.s" }, - { 0x21, MOXIE_F1_ABi, "ld.s" }, - { 0x22, MOXIE_F1_A4, "lda.s" }, - { 0x23, MOXIE_F1_AiB, "st.s" }, - { 0x24, MOXIE_F1_4A, "sta.s" }, - { 0x25, MOXIE_F1_A, "jmp" }, - { 0x26, MOXIE_F1_AB, "and" }, - { 0x27, MOXIE_F1_AB, "lshr" }, - { 0x28, MOXIE_F1_AB, "ashl" }, - { 0x29, MOXIE_F1_AB, "sub.l" }, - { 0x2a, MOXIE_F1_AB, "neg" }, - { 0x2b, MOXIE_F1_AB, "or" }, - { 0x2c, MOXIE_F1_AB, "not" }, - { 0x2d, MOXIE_F1_AB, "ashr" }, - { 0x2e, MOXIE_F1_AB, "xor" }, - { 0x2f, MOXIE_F1_AB, "mul.l" }, - { 0x30, MOXIE_F1_4, "swi" }, - { 0x31, MOXIE_F1_AB, "div.l" }, - { 0x32, MOXIE_F1_AB, "udiv.l" }, - { 0x33, MOXIE_F1_AB, "mod.l" }, - { 0x34, MOXIE_F1_AB, "umod.l" }, - { 0x35, MOXIE_F1_NARG, "brk" }, - { 0x36, MOXIE_F1_ABi4, "ldo.b" }, - { 0x37, MOXIE_F1_AiB4, "sto.b" }, - { 0x38, MOXIE_F1_ABi4, "ldo.s" }, - { 0x39, MOXIE_F1_AiB4, "sto.s" }, - { 0x3a, MOXIE_F1_NARG, "bad" }, - { 0x3b, MOXIE_F1_NARG, "bad" }, - { 0x3c, MOXIE_F1_NARG, "bad" }, - { 0x3d, MOXIE_F1_NARG, "bad" }, - { 0x3e, MOXIE_F1_NARG, "bad" }, - { 0x3f, MOXIE_F1_NARG, "bad" } - }; - -const moxie_opc_info_t moxie_form2_opc_info[4] = - { - { 0x00, MOXIE_F2_A8V, "inc" }, - { 0x01, MOXIE_F2_A8V, "dec" }, - { 0x02, MOXIE_F2_A8V, "gsr" }, - { 0x03, MOXIE_F2_A8V, "ssr" } - }; - -const moxie_opc_info_t moxie_form3_opc_info[16] = - { - { 0x00, MOXIE_F3_PCREL,"beq" }, - { 0x01, MOXIE_F3_PCREL,"bne" }, - { 0x02, MOXIE_F3_PCREL,"blt" }, - { 0x03, MOXIE_F3_PCREL,"bgt" }, - { 0x04, MOXIE_F3_PCREL,"bltu" }, - { 0x05, MOXIE_F3_PCREL,"bgtu" }, - { 0x06, MOXIE_F3_PCREL,"bge" }, - { 0x07, MOXIE_F3_PCREL,"ble" }, - { 0x08, MOXIE_F3_PCREL,"bgeu" }, - { 0x09, MOXIE_F3_PCREL,"bleu" }, - { 0x0a, MOXIE_F3_NARG, "bad" }, - { 0x0b, MOXIE_F3_NARG, "bad" }, - { 0x0c, MOXIE_F3_NARG, "bad" }, - { 0x0d, MOXIE_F3_NARG, "bad" }, - { 0x0e, MOXIE_F3_NARG, "bad" }, - { 0x0f, MOXIE_F3_NARG, "bad" } - }; - -/* Macros to extract operands from the instruction word. */ -#define OP_A(i) ((i >> 4) & 0xf) -#define OP_B(i) (i & 0xf) -#define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1) - -static const char * reg_names[16] = - { "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", - "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" }; - -int -print_insn_moxie(bfd_vma addr, struct disassemble_info * info) -{ - int length = 2; - int status; - stream = info->stream; - const moxie_opc_info_t * opcode; - bfd_byte buffer[4]; - unsigned short iword; - fprintf_function fpr = info->fprintf_func; - - if ((status = info->read_memory_func(addr, buffer, 2, info))) - goto fail; - iword = (bfd_getb16(buffer) >> 16); - - /* Form 1 instructions have the high bit set to 0. */ - if ((iword & (1<<15)) == 0) { - /* Extract the Form 1 opcode. */ - opcode = &moxie_form1_opc_info[iword >> 8]; - switch (opcode->itype) { - case MOXIE_F1_NARG: - fpr(stream, "%s", opcode->name); - break; - case MOXIE_F1_A: - fpr(stream, "%s\t%s", opcode->name, - reg_names[OP_A(iword)]); - break; - case MOXIE_F1_AB: - fpr(stream, "%s\t%s, %s", opcode->name, - reg_names[OP_A(iword)], - reg_names[OP_B(iword)]); - break; - case MOXIE_F1_A4: - { - unsigned imm; - if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) - goto fail; - imm = bfd_getb32(buffer); - fpr(stream, "%s\t%s, 0x%x", opcode->name, - reg_names[OP_A(iword)], imm); - length = 6; - } - break; - case MOXIE_F1_4: - { - unsigned imm; - if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) - goto fail; - imm = bfd_getb32(buffer); - fpr(stream, "%s\t0x%x", opcode->name, imm); - length = 6; - } - break; - case MOXIE_F1_M: - { - unsigned imm; - if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) - goto fail; - imm = bfd_getb32(buffer); - fpr(stream, "%s\t", opcode->name); - info->print_address_func((bfd_vma) imm, info); - length = 6; - } - break; - case MOXIE_F1_AiB: - fpr (stream, "%s\t(%s), %s", opcode->name, - reg_names[OP_A(iword)], reg_names[OP_B(iword)]); - break; - case MOXIE_F1_ABi: - fpr(stream, "%s\t%s, (%s)", opcode->name, - reg_names[OP_A(iword)], reg_names[OP_B(iword)]); - break; - case MOXIE_F1_4A: - { - unsigned imm; - if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) - goto fail; - imm = bfd_getb32(buffer); - fpr(stream, "%s\t0x%x, %s", - opcode->name, imm, reg_names[OP_A(iword)]); - length = 6; - } - break; - case MOXIE_F1_AiB4: - { - unsigned imm; - if ((status = info->read_memory_func(addr+2, buffer, 4, info))) - goto fail; - imm = bfd_getb32(buffer); - fpr(stream, "%s\t0x%x(%s), %s", opcode->name, - imm, - reg_names[OP_A(iword)], - reg_names[OP_B(iword)]); - length = 6; - } - break; - case MOXIE_F1_ABi4: - { - unsigned imm; - if ((status = info->read_memory_func(addr+2, buffer, 4, info))) - goto fail; - imm = bfd_getb32(buffer); - fpr(stream, "%s\t%s, 0x%x(%s)", - opcode->name, - reg_names[OP_A(iword)], - imm, - reg_names[OP_B(iword)]); - length = 6; - } - break; - default: - abort(); - } - } - else if ((iword & (1<<14)) == 0) { - /* Extract the Form 2 opcode. */ - opcode = &moxie_form2_opc_info[(iword >> 12) & 3]; - switch (opcode->itype) { - case MOXIE_F2_A8V: - fpr(stream, "%s\t%s, 0x%x", - opcode->name, - reg_names[(iword >> 8) & 0xf], - iword & ((1 << 8) - 1)); - break; - case MOXIE_F2_NARG: - fpr(stream, "%s", opcode->name); - break; - default: - abort(); - } - } else { - /* Extract the Form 3 opcode. */ - opcode = &moxie_form3_opc_info[(iword >> 10) & 15]; - switch (opcode->itype) { - case MOXIE_F3_PCREL: - fpr(stream, "%s\t", opcode->name); - info->print_address_func((bfd_vma) (addr + INST2OFFSET(iword) + 2), - info); - break; - default: - abort(); - } - } - - return length; - - fail: - info->memory_error_func(status, addr, info); - return -1; -} diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index f9169077ae..cd91c4528f 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -198,14 +198,6 @@ from Linux upstream kernel, declare it deprecated. System emulator CPUS -------------------- -``moxie`` CPU (since 5.2.0) -''''''''''''''''''''''''''' - -The ``moxie`` guest CPU support is deprecated and will be removed in -a future version of QEMU. It's unclear whether anybody is still using -CPU emulation in QEMU, and there are no test images available to make -sure that the code is still working. - ``lm32`` CPUs (since 5.2.0) ''''''''''''''''''''''''''' diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst index c21e6fa5ee..f49737c4ef 100644 --- a/docs/system/removed-features.rst +++ b/docs/system/removed-features.rst @@ -291,6 +291,13 @@ via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs. The ``max-cpu-compat`` property of the ``pseries`` machine type should be used instead. +``moxie`` CPU (removed in 6.1) +'''''''''''''''''''''''''''''' + +Nobody was using this CPU emulation in QEMU, and there were no test images +available to make sure that the code is still working, so it has been removed +without replacement. + System emulator machines ------------------------ diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 9ea318f3e2..60df67d441 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -152,7 +152,7 @@ static FloatParts parts_default_nan(float_status *status) /* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V, * S390, SH4, TriCore, and Xtensa. I cannot find documentation * for Unicore32; the choice from the original commit is unchanged. - * Our other supported targets, CRIS, LM32, Moxie, Nios2, and Tile, + * Our other supported targets, CRIS, LM32, and Nios2, * do not have floating-point. */ if (snan_bit_is_one(status)) { diff --git a/hw/Kconfig b/hw/Kconfig index ff40bd3f7b..559b7636f4 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -51,7 +51,6 @@ source lm32/Kconfig source m68k/Kconfig source microblaze/Kconfig source mips/Kconfig -source moxie/Kconfig source nios2/Kconfig source openrisc/Kconfig source ppc/Kconfig diff --git a/hw/meson.build b/hw/meson.build index 8ba79b1a52..503cbc974f 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -51,7 +51,6 @@ subdir('lm32') subdir('m68k') subdir('microblaze') subdir('mips') -subdir('moxie') subdir('nios2') subdir('openrisc') subdir('ppc') diff --git a/hw/moxie/Kconfig b/hw/moxie/Kconfig deleted file mode 100644 index 3793ef0372..0000000000 --- a/hw/moxie/Kconfig +++ /dev/null @@ -1,3 +0,0 @@ -config MOXIESIM - bool - select SERIAL diff --git a/hw/moxie/meson.build b/hw/moxie/meson.build deleted file mode 100644 index 05a7c2e00f..0000000000 --- a/hw/moxie/meson.build +++ /dev/null @@ -1,4 +0,0 @@ -moxie_ss = ss.source_set() -moxie_ss.add(when: 'CONFIG_MOXIESIM', if_true: files('moxiesim.c')) - -hw_arch += {'moxie': moxie_ss} diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c deleted file mode 100644 index 3d255d4879..0000000000 --- a/hw/moxie/moxiesim.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * QEMU/moxiesim emulation - * - * Emulates a very simple machine model similar to the one used by the - * GDB moxie simulator. - * - * Copyright (c) 2008, 2009, 2010, 2013 Anthony Green - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "qapi/error.h" -#include "cpu.h" -#include "net/net.h" -#include "sysemu/reset.h" -#include "sysemu/sysemu.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "hw/char/serial.h" -#include "elf.h" - -#define PHYS_MEM_BASE 0x80000000 -#define FIRMWARE_BASE 0x1000 -#define FIRMWARE_SIZE (128 * 0x1000) - -typedef struct { - uint64_t ram_size; - const char *kernel_filename; - const char *kernel_cmdline; - const char *initrd_filename; -} LoaderParams; - -static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params) -{ - uint64_t entry, kernel_high; - int64_t initrd_size; - long kernel_size; - ram_addr_t initrd_offset; - - kernel_size = load_elf(loader_params->kernel_filename, NULL, NULL, NULL, - &entry, NULL, &kernel_high, NULL, 1, EM_MOXIE, - 0, 0); - - if (kernel_size <= 0) { - error_report("could not load kernel '%s'", - loader_params->kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - initrd_offset = 0; - if (loader_params->initrd_filename) { - initrd_size = get_image_size(loader_params->initrd_filename); - if (initrd_size > 0) { - initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) - & TARGET_PAGE_MASK; - if (initrd_offset + initrd_size > loader_params->ram_size) { - error_report("memory too small for initial ram disk '%s'", - loader_params->initrd_filename); - exit(1); - } - initrd_size = load_image_targphys(loader_params->initrd_filename, - initrd_offset, - loader_params->ram_size); - } - if (initrd_size == (target_ulong)-1) { - error_report("could not load initial ram disk '%s'", - loader_params->initrd_filename); - exit(1); - } - } -} - -static void main_cpu_reset(void *opaque) -{ - MoxieCPU *cpu = opaque; - - cpu_reset(CPU(cpu)); -} - -static void moxiesim_init(MachineState *machine) -{ - MoxieCPU *cpu = NULL; - ram_addr_t ram_size = machine->ram_size; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - CPUMoxieState *env; - MemoryRegion *address_space_mem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - MemoryRegion *rom = g_new(MemoryRegion, 1); - hwaddr ram_base = 0x200000; - LoaderParams loader_params; - - /* Init CPUs. */ - cpu = MOXIE_CPU(cpu_create(machine->cpu_type)); - env = &cpu->env; - - qemu_register_reset(main_cpu_reset, cpu); - - /* Allocate RAM. */ - memory_region_init_ram(ram, NULL, "moxiesim.ram", ram_size, &error_fatal); - memory_region_add_subregion(address_space_mem, ram_base, ram); - - memory_region_init_ram(rom, NULL, "moxie.rom", FIRMWARE_SIZE, &error_fatal); - memory_region_add_subregion(get_system_memory(), FIRMWARE_BASE, rom); - - if (kernel_filename) { - loader_params.ram_size = ram_size; - loader_params.kernel_filename = kernel_filename; - loader_params.kernel_cmdline = kernel_cmdline; - loader_params.initrd_filename = initrd_filename; - load_kernel(cpu, &loader_params); - } - if (machine->firmware) { - if (load_image_targphys(machine->firmware, FIRMWARE_BASE, FIRMWARE_SIZE) < 0) { - error_report("Failed to load firmware '%s'", machine->firmware); - } - } - - /* A single 16450 sits at offset 0x3f8. */ - if (serial_hd(0)) { - serial_mm_init(address_space_mem, 0x3f8, 0, env->irq[4], - 8000000/16, serial_hd(0), DEVICE_LITTLE_ENDIAN); - } -} - -static void moxiesim_machine_init(MachineClass *mc) -{ - mc->desc = "Moxie simulator platform"; - mc->init = moxiesim_init; - mc->is_default = true; - mc->default_cpu_type = MOXIE_CPU_TYPE_NAME("MoxieLite"); -} - -DEFINE_MACHINE("moxiesim", moxiesim_machine_init) diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index 4701445e80..8e985e7e94 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -443,7 +443,6 @@ int print_insn_m32r (bfd_vma, disassemble_info*); int print_insn_m88k (bfd_vma, disassemble_info*); int print_insn_mn10200 (bfd_vma, disassemble_info*); int print_insn_mn10300 (bfd_vma, disassemble_info*); -int print_insn_moxie (bfd_vma, disassemble_info*); int print_insn_ns32k (bfd_vma, disassemble_info*); int print_insn_big_powerpc (bfd_vma, disassemble_info*); int print_insn_little_powerpc (bfd_vma, disassemble_info*); diff --git a/include/elf.h b/include/elf.h index 78237c9a87..33ed830ec3 100644 --- a/include/elf.h +++ b/include/elf.h @@ -206,9 +206,6 @@ typedef struct mips_elf_abiflags_v0 { #define EM_AARCH64 183 -#define EM_MOXIE 223 /* Moxie processor family */ -#define EM_MOXIE_OLD 0xFEED - #define EF_AVR_MACH 0x7F /* Mask for AVR e_flags to get core type */ /* This is the info that is needed to parse the dynamic section of the file */ diff --git a/include/exec/poison.h b/include/exec/poison.h index 4cd3f8abb4..de972bfd8e 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -20,7 +20,6 @@ #pragma GCC poison TARGET_ABI_MIPSO32 #pragma GCC poison TARGET_MIPS64 #pragma GCC poison TARGET_ABI_MIPSN64 -#pragma GCC poison TARGET_MOXIE #pragma GCC poison TARGET_NIOS2 #pragma GCC poison TARGET_OPENRISC #pragma GCC poison TARGET_PPC @@ -79,7 +78,6 @@ #pragma GCC poison CONFIG_MICROBLAZE_DIS #pragma GCC poison CONFIG_MIPS_DIS #pragma GCC poison CONFIG_NANOMIPS_DIS -#pragma GCC poison CONFIG_MOXIE_DIS #pragma GCC poison CONFIG_NIOS2_DIS #pragma GCC poison CONFIG_PPC_DIS #pragma GCC poison CONFIG_RISCV_DIS diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h index 6ee458e7bc..1c37cec4ae 100644 --- a/include/hw/elf_ops.h +++ b/include/hw/elf_ops.h @@ -368,14 +368,6 @@ static int glue(load_elf, SZ)(const char *name, int fd, } } break; - case EM_MOXIE: - if (ehdr.e_machine != EM_MOXIE) { - if (ehdr.e_machine != EM_MOXIE_OLD) { - ret = ELF_LOAD_WRONG_ARCH; - goto fail; - } - } - break; case EM_MIPS: case EM_NANOMIPS: if ((ehdr.e_machine != EM_MIPS) && diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 16da279696..44e3734d18 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -19,7 +19,6 @@ enum { QEMU_ARCH_XTENSA = (1 << 12), QEMU_ARCH_OPENRISC = (1 << 13), QEMU_ARCH_UNICORE32 = (1 << 14), - QEMU_ARCH_MOXIE = (1 << 15), QEMU_ARCH_TRICORE = (1 << 16), QEMU_ARCH_NIOS2 = (1 << 17), QEMU_ARCH_HPPA = (1 << 18), diff --git a/meson.build b/meson.build index 0b41ff4118..40e8f012ac 100644 --- a/meson.build +++ b/meson.build @@ -1214,7 +1214,6 @@ disassemblers = { 'm68k' : ['CONFIG_M68K_DIS'], 'microblaze' : ['CONFIG_MICROBLAZE_DIS'], 'mips' : ['CONFIG_MIPS_DIS'], - 'moxie' : ['CONFIG_MOXIE_DIS'], 'nios2' : ['CONFIG_NIOS2_DIS'], 'or1k' : ['CONFIG_OPENRISC_DIS'], 'ppc' : ['CONFIG_PPC_DIS'], diff --git a/qapi/machine.json b/qapi/machine.json index 6e90d463fc..f1e2ccceba 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -31,7 +31,7 @@ { 'enum' : 'SysEmuTarget', 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', 'lm32', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', - 'mips64el', 'mipsel', 'moxie', 'nios2', 'or1k', 'ppc', + 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc', 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', 'sh4eb', 'sparc', 'sparc64', 'tricore', 'unicore32', 'x86_64', 'xtensa', 'xtensaeb' ] } diff --git a/qapi/misc-target.json b/qapi/misc-target.json index 0c7491cd82..6200c671be 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -23,7 +23,7 @@ ## { 'event': 'RTC_CHANGE', 'data': { 'offset': 'int' }, - 'if': 'defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) || defined(TARGET_MIPS64) || defined(TARGET_MOXIE) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC)' } + 'if': 'defined(TARGET_ALPHA) || defined(TARGET_ARM) || defined(TARGET_HPPA) || defined(TARGET_I386) || defined(TARGET_MIPS) || defined(TARGET_MIPS64) || defined(TARGET_PPC) || defined(TARGET_PPC64) || defined(TARGET_S390X) || defined(TARGET_SH4) || defined(TARGET_SPARC)' } ## # @rtc-reset-reinjection: diff --git a/softmmu/arch_init.c b/softmmu/arch_init.c index f09bab830c..afb0904020 100644 --- a/softmmu/arch_init.c +++ b/softmmu/arch_init.c @@ -64,8 +64,6 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_MICROBLAZE #elif defined(TARGET_MIPS) #define QEMU_ARCH QEMU_ARCH_MIPS -#elif defined(TARGET_MOXIE) -#define QEMU_ARCH QEMU_ARCH_MOXIE #elif defined(TARGET_NIOS2) #define QEMU_ARCH QEMU_ARCH_NIOS2 #elif defined(TARGET_OPENRISC) diff --git a/target/meson.build b/target/meson.build index 0e2c4b69cb..289a654caf 100644 --- a/target/meson.build +++ b/target/meson.build @@ -9,7 +9,6 @@ subdir('lm32') subdir('m68k') subdir('microblaze') subdir('mips') -subdir('moxie') subdir('nios2') subdir('openrisc') subdir('ppc') diff --git a/target/moxie/cpu-param.h b/target/moxie/cpu-param.h deleted file mode 100644 index 9a40ef525c..0000000000 --- a/target/moxie/cpu-param.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Moxie cpu parameters for qemu. - * - * Copyright (c) 2008, 2010, 2013 Anthony Green - * SPDX-License-Identifier: LGPL-2.1+ - */ - -#ifndef MOXIE_CPU_PARAM_H -#define MOXIE_CPU_PARAM_H 1 - -#define TARGET_LONG_BITS 32 -#define TARGET_PAGE_BITS 12 /* 4k */ -#define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 -#define NB_MMU_MODES 1 - -#endif diff --git a/target/moxie/cpu.c b/target/moxie/cpu.c deleted file mode 100644 index 83bec34d36..0000000000 --- a/target/moxie/cpu.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * QEMU Moxie CPU - * - * Copyright (c) 2013 Anthony Green - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "cpu.h" -#include "migration/vmstate.h" -#include "machine.h" - -static void moxie_cpu_set_pc(CPUState *cs, vaddr value) -{ - MoxieCPU *cpu = MOXIE_CPU(cs); - - cpu->env.pc = value; -} - -static bool moxie_cpu_has_work(CPUState *cs) -{ - return cs->interrupt_request & CPU_INTERRUPT_HARD; -} - -static void moxie_cpu_reset(DeviceState *dev) -{ - CPUState *s = CPU(dev); - MoxieCPU *cpu = MOXIE_CPU(s); - MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(cpu); - CPUMoxieState *env = &cpu->env; - - mcc->parent_reset(dev); - - memset(env, 0, offsetof(CPUMoxieState, end_reset_fields)); - env->pc = 0x1000; -} - -static void moxie_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) -{ - info->mach = bfd_arch_moxie; - info->print_insn = print_insn_moxie; -} - -static void moxie_cpu_realizefn(DeviceState *dev, Error **errp) -{ - CPUState *cs = CPU(dev); - MoxieCPUClass *mcc = MOXIE_CPU_GET_CLASS(dev); - Error *local_err = NULL; - - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - qemu_init_vcpu(cs); - cpu_reset(cs); - - mcc->parent_realize(dev, errp); -} - -static void moxie_cpu_initfn(Object *obj) -{ - MoxieCPU *cpu = MOXIE_CPU(obj); - - cpu_set_cpustate_pointers(cpu); -} - -static ObjectClass *moxie_cpu_class_by_name(const char *cpu_model) -{ - ObjectClass *oc; - char *typename; - - typename = g_strdup_printf(MOXIE_CPU_TYPE_NAME("%s"), cpu_model); - oc = object_class_by_name(typename); - g_free(typename); - if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_MOXIE_CPU) || - object_class_is_abstract(oc))) { - return NULL; - } - return oc; -} - -#include "hw/core/tcg-cpu-ops.h" - -static struct TCGCPUOps moxie_tcg_ops = { - .initialize = moxie_translate_init, - .tlb_fill = moxie_cpu_tlb_fill, - -#ifndef CONFIG_USER_ONLY - .do_interrupt = moxie_cpu_do_interrupt, -#endif /* !CONFIG_USER_ONLY */ -}; - -static void moxie_cpu_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); - MoxieCPUClass *mcc = MOXIE_CPU_CLASS(oc); - - device_class_set_parent_realize(dc, moxie_cpu_realizefn, - &mcc->parent_realize); - device_class_set_parent_reset(dc, moxie_cpu_reset, &mcc->parent_reset); - - cc->class_by_name = moxie_cpu_class_by_name; - - cc->has_work = moxie_cpu_has_work; - cc->dump_state = moxie_cpu_dump_state; - cc->set_pc = moxie_cpu_set_pc; -#ifndef CONFIG_USER_ONLY - cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug; - cc->vmsd = &vmstate_moxie_cpu; -#endif - cc->disas_set_info = moxie_cpu_disas_set_info; - cc->tcg_ops = &moxie_tcg_ops; -} - -static void moxielite_initfn(Object *obj) -{ - /* Set cpu feature flags */ -} - -static void moxie_any_initfn(Object *obj) -{ - /* Set cpu feature flags */ -} - -#define DEFINE_MOXIE_CPU_TYPE(cpu_model, initfn) \ - { \ - .parent = TYPE_MOXIE_CPU, \ - .instance_init = initfn, \ - .name = MOXIE_CPU_TYPE_NAME(cpu_model), \ - } - -static const TypeInfo moxie_cpus_type_infos[] = { - { /* base class should be registered first */ - .name = TYPE_MOXIE_CPU, - .parent = TYPE_CPU, - .instance_size = sizeof(MoxieCPU), - .instance_init = moxie_cpu_initfn, - .class_size = sizeof(MoxieCPUClass), - .class_init = moxie_cpu_class_init, - }, - DEFINE_MOXIE_CPU_TYPE("MoxieLite", moxielite_initfn), - DEFINE_MOXIE_CPU_TYPE("any", moxie_any_initfn), -}; - -DEFINE_TYPES(moxie_cpus_type_infos) diff --git a/target/moxie/cpu.h b/target/moxie/cpu.h deleted file mode 100644 index bd6ab66084..0000000000 --- a/target/moxie/cpu.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Moxie emulation - * - * Copyright (c) 2008, 2010, 2013 Anthony Green - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef MOXIE_CPU_H -#define MOXIE_CPU_H - -#include "exec/cpu-defs.h" -#include "qom/object.h" - -#define MOXIE_EX_DIV0 0 -#define MOXIE_EX_BAD 1 -#define MOXIE_EX_IRQ 2 -#define MOXIE_EX_SWI 3 -#define MOXIE_EX_MMU_MISS 4 -#define MOXIE_EX_BREAK 16 - -typedef struct CPUMoxieState { - - uint32_t flags; /* general execution flags */ - uint32_t gregs[16]; /* general registers */ - uint32_t sregs[256]; /* special registers */ - uint32_t pc; /* program counter */ - /* Instead of saving the cc value, we save the cmp arguments - and compute cc on demand. */ - uint32_t cc_a; /* reg a for condition code calculation */ - uint32_t cc_b; /* reg b for condition code calculation */ - - void *irq[8]; - - /* Fields up to this point are cleared by a CPU reset */ - struct {} end_reset_fields; -} CPUMoxieState; - -#include "hw/core/cpu.h" - -#define TYPE_MOXIE_CPU "moxie-cpu" - -OBJECT_DECLARE_TYPE(MoxieCPU, MoxieCPUClass, - MOXIE_CPU) - -/** - * MoxieCPUClass: - * @parent_reset: The parent class' reset handler. - * - * A Moxie CPU model. - */ -struct MoxieCPUClass { - /*< private >*/ - CPUClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; - DeviceReset parent_reset; -}; - -/** - * MoxieCPU: - * @env: #CPUMoxieState - * - * A Moxie CPU. - */ -struct MoxieCPU { - /*< private >*/ - CPUState parent_obj; - /*< public >*/ - - CPUNegativeOffsetState neg; - CPUMoxieState env; -}; - - -void moxie_cpu_do_interrupt(CPUState *cs); -void moxie_cpu_dump_state(CPUState *cpu, FILE *f, int flags); -hwaddr moxie_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -void moxie_translate_init(void); -int cpu_moxie_signal_handler(int host_signum, void *pinfo, - void *puc); - -#define MOXIE_CPU_TYPE_SUFFIX "-" TYPE_MOXIE_CPU -#define MOXIE_CPU_TYPE_NAME(model) model MOXIE_CPU_TYPE_SUFFIX -#define CPU_RESOLVING_TYPE TYPE_MOXIE_CPU - -#define cpu_signal_handler cpu_moxie_signal_handler - -static inline int cpu_mmu_index(CPUMoxieState *env, bool ifetch) -{ - return 0; -} - -typedef CPUMoxieState CPUArchState; -typedef MoxieCPU ArchCPU; - -#include "exec/cpu-all.h" - -static inline void cpu_get_tb_cpu_state(CPUMoxieState *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *cs_base = 0; - *flags = 0; -} - -bool moxie_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr); - -#endif /* MOXIE_CPU_H */ diff --git a/target/moxie/helper.c b/target/moxie/helper.c deleted file mode 100644 index b1919f62b3..0000000000 --- a/target/moxie/helper.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Moxie helper routines. - * - * Copyright (c) 2008, 2009, 2010, 2013 Anthony Green - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "qemu/osdep.h" - -#include "cpu.h" -#include "mmu.h" -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" -#include "qemu/host-utils.h" -#include "exec/helper-proto.h" - -void helper_raise_exception(CPUMoxieState *env, int ex) -{ - CPUState *cs = env_cpu(env); - - cs->exception_index = ex; - /* Stash the exception type. */ - env->sregs[2] = ex; - /* Stash the address where the exception occurred. */ - cpu_restore_state(cs, GETPC(), true); - env->sregs[5] = env->pc; - /* Jump to the exception handline routine. */ - env->pc = env->sregs[1]; - cpu_loop_exit(cs); -} - -uint32_t helper_div(CPUMoxieState *env, uint32_t a, uint32_t b) -{ - if (unlikely(b == 0)) { - helper_raise_exception(env, MOXIE_EX_DIV0); - return 0; - } - if (unlikely(a == INT_MIN && b == -1)) { - return INT_MIN; - } - - return (int32_t)a / (int32_t)b; -} - -uint32_t helper_udiv(CPUMoxieState *env, uint32_t a, uint32_t b) -{ - if (unlikely(b == 0)) { - helper_raise_exception(env, MOXIE_EX_DIV0); - return 0; - } - return a / b; -} - -void helper_debug(CPUMoxieState *env) -{ - CPUState *cs = env_cpu(env); - - cs->exception_index = EXCP_DEBUG; - cpu_loop_exit(cs); -} - -bool moxie_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr) -{ - MoxieCPU *cpu = MOXIE_CPU(cs); - CPUMoxieState *env = &cpu->env; - MoxieMMUResult res; - int prot, miss; - - address &= TARGET_PAGE_MASK; - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - miss = moxie_mmu_translate(&res, env, address, access_type, mmu_idx); - if (likely(!miss)) { - tlb_set_page(cs, address, res.phy, prot, mmu_idx, TARGET_PAGE_SIZE); - return true; - } - if (probe) { - return false; - } - - cs->exception_index = MOXIE_EX_MMU_MISS; - cpu_loop_exit_restore(cs, retaddr); -} - -void moxie_cpu_do_interrupt(CPUState *cs) -{ - switch (cs->exception_index) { - case MOXIE_EX_BREAK: - break; - default: - break; - } -} - -hwaddr moxie_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -{ - MoxieCPU *cpu = MOXIE_CPU(cs); - uint32_t phy = addr; - MoxieMMUResult res; - int miss; - - miss = moxie_mmu_translate(&res, &cpu->env, addr, 0, 0); - if (!miss) { - phy = res.phy; - } - return phy; -} diff --git a/target/moxie/helper.h b/target/moxie/helper.h deleted file mode 100644 index d94ef7a17e..0000000000 --- a/target/moxie/helper.h +++ /dev/null @@ -1,5 +0,0 @@ -DEF_HELPER_2(raise_exception, void, env, int) -DEF_HELPER_1(debug, void, env) - -DEF_HELPER_FLAGS_3(div, TCG_CALL_NO_WG, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_WG, i32, env, i32, i32) diff --git a/target/moxie/machine.c b/target/moxie/machine.c deleted file mode 100644 index d0f177048c..0000000000 --- a/target/moxie/machine.c +++ /dev/null @@ -1,19 +0,0 @@ -#include "qemu/osdep.h" -#include "cpu.h" -#include "machine.h" -#include "migration/cpu.h" - -const VMStateDescription vmstate_moxie_cpu = { - .name = "cpu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(flags, CPUMoxieState), - VMSTATE_UINT32_ARRAY(gregs, CPUMoxieState, 16), - VMSTATE_UINT32_ARRAY(sregs, CPUMoxieState, 256), - VMSTATE_UINT32(pc, CPUMoxieState), - VMSTATE_UINT32(cc_a, CPUMoxieState), - VMSTATE_UINT32(cc_b, CPUMoxieState), - VMSTATE_END_OF_LIST() - } -}; diff --git a/target/moxie/machine.h b/target/moxie/machine.h deleted file mode 100644 index a1b72907ae..0000000000 --- a/target/moxie/machine.h +++ /dev/null @@ -1 +0,0 @@ -extern const VMStateDescription vmstate_moxie_cpu; diff --git a/target/moxie/meson.build b/target/moxie/meson.build deleted file mode 100644 index b4beb528cc..0000000000 --- a/target/moxie/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -moxie_ss = ss.source_set() -moxie_ss.add(files( - 'cpu.c', - 'helper.c', - 'machine.c', - 'machine.c', - 'translate.c', -)) - -moxie_softmmu_ss = ss.source_set() -moxie_softmmu_ss.add(files('mmu.c')) - -target_arch += {'moxie': moxie_ss} -target_softmmu_arch += {'moxie': moxie_softmmu_ss} diff --git a/target/moxie/mmu.c b/target/moxie/mmu.c deleted file mode 100644 index 87783a36f8..0000000000 --- a/target/moxie/mmu.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Moxie mmu emulation. - * - * Copyright (c) 2008, 2013 Anthony Green - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#include "qemu/osdep.h" - -#include "cpu.h" -#include "mmu.h" - -int moxie_mmu_translate(MoxieMMUResult *res, - CPUMoxieState *env, uint32_t vaddr, - int rw, int mmu_idx) -{ - /* Perform no translation yet. */ - res->phy = vaddr; - return 0; -} diff --git a/target/moxie/mmu.h b/target/moxie/mmu.h deleted file mode 100644 index d80690f4d2..0000000000 --- a/target/moxie/mmu.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef TARGET_MOXIE_MMU_H -#define TARGET_MOXIE_MMU_H - -#define MOXIE_MMU_ERR_EXEC 0 -#define MOXIE_MMU_ERR_READ 1 -#define MOXIE_MMU_ERR_WRITE 2 -#define MOXIE_MMU_ERR_FLUSH 3 - -typedef struct { - uint32_t phy; - uint32_t pfn; - int cause_op; -} MoxieMMUResult; - -int moxie_mmu_translate(MoxieMMUResult *res, - CPUMoxieState *env, uint32_t vaddr, - int rw, int mmu_idx); - -#endif diff --git a/target/moxie/translate.c b/target/moxie/translate.c deleted file mode 100644 index 24a742b25e..0000000000 --- a/target/moxie/translate.c +++ /dev/null @@ -1,892 +0,0 @@ -/* - * Moxie emulation for qemu: main translation routines. - * - * Copyright (c) 2009, 2013 Anthony Green - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -/* For information on the Moxie architecture, see - * http://moxielogic.org/wiki - */ - -#include "qemu/osdep.h" - -#include "cpu.h" -#include "exec/exec-all.h" -#include "disas/disas.h" -#include "tcg/tcg-op.h" -#include "exec/cpu_ldst.h" -#include "qemu/qemu-print.h" - -#include "exec/helper-proto.h" -#include "exec/helper-gen.h" -#include "exec/log.h" - -/* This is the state at translation time. */ -typedef struct DisasContext { - TranslationBlock *tb; - target_ulong pc, saved_pc; - uint32_t opcode; - uint32_t fp_status; - /* Routine used to access memory */ - int memidx; - int bstate; - target_ulong btarget; - int singlestep_enabled; -} DisasContext; - -enum { - BS_NONE = 0, /* We go out of the TB without reaching a branch or an - * exception condition */ - BS_STOP = 1, /* We want to stop translation for any reason */ - BS_BRANCH = 2, /* We reached a branch condition */ - BS_EXCP = 3, /* We reached an exception condition */ -}; - -static TCGv cpu_pc; -static TCGv cpu_gregs[16]; -static TCGv cc_a, cc_b; - -#include "exec/gen-icount.h" - -#define REG(x) (cpu_gregs[x]) - -/* Extract the signed 10-bit offset from a 16-bit branch - instruction. */ -static int extract_branch_offset(int opcode) -{ - return (((signed short)((opcode & ((1 << 10) - 1)) << 6)) >> 6) << 1; -} - -void moxie_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - MoxieCPU *cpu = MOXIE_CPU(cs); - CPUMoxieState *env = &cpu->env; - int i; - qemu_fprintf(f, "pc=0x%08x\n", env->pc); - qemu_fprintf(f, "$fp=0x%08x $sp=0x%08x $r0=0x%08x $r1=0x%08x\n", - env->gregs[0], env->gregs[1], env->gregs[2], env->gregs[3]); - for (i = 4; i < 16; i += 4) { - qemu_fprintf(f, "$r%d=0x%08x $r%d=0x%08x $r%d=0x%08x $r%d=0x%08x\n", - i - 2, env->gregs[i], i - 1, env->gregs[i + 1], - i, env->gregs[i + 2], i + 1, env->gregs[i + 3]); - } - for (i = 4; i < 16; i += 4) { - qemu_fprintf(f, "sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x sr%d=0x%08x\n", - i - 2, env->sregs[i], i - 1, env->sregs[i + 1], - i, env->sregs[i + 2], i + 1, env->sregs[i + 3]); - } -} - -void moxie_translate_init(void) -{ - int i; - static const char * const gregnames[16] = { - "$fp", "$sp", "$r0", "$r1", - "$r2", "$r3", "$r4", "$r5", - "$r6", "$r7", "$r8", "$r9", - "$r10", "$r11", "$r12", "$r13" - }; - - cpu_pc = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMoxieState, pc), "$pc"); - for (i = 0; i < 16; i++) - cpu_gregs[i] = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMoxieState, gregs[i]), - gregnames[i]); - - cc_a = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMoxieState, cc_a), "cc_a"); - cc_b = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUMoxieState, cc_b), "cc_b"); -} - -static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) -{ - if (unlikely(ctx->singlestep_enabled)) { - return false; - } - -#ifndef CONFIG_USER_ONLY - return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); -#else - return true; -#endif -} - -static inline void gen_goto_tb(CPUMoxieState *env, DisasContext *ctx, - int n, target_ulong dest) -{ - if (use_goto_tb(ctx, dest)) { - tcg_gen_goto_tb(n); - tcg_gen_movi_i32(cpu_pc, dest); - tcg_gen_exit_tb(ctx->tb, n); - } else { - tcg_gen_movi_i32(cpu_pc, dest); - if (ctx->singlestep_enabled) { - gen_helper_debug(cpu_env); - } - tcg_gen_exit_tb(NULL, 0); - } -} - -static int decode_opc(MoxieCPU *cpu, DisasContext *ctx) -{ - CPUMoxieState *env = &cpu->env; - - /* Local cache for the instruction opcode. */ - int opcode; - /* Set the default instruction length. */ - int length = 2; - - /* Examine the 16-bit opcode. */ - opcode = ctx->opcode; - - /* Decode instruction. */ - if (opcode & (1 << 15)) { - if (opcode & (1 << 14)) { - /* This is a Form 3 instruction. */ - int inst = (opcode >> 10 & 0xf); - -#define BRANCH(cond) \ - do { \ - TCGLabel *l1 = gen_new_label(); \ - tcg_gen_brcond_i32(cond, cc_a, cc_b, l1); \ - gen_goto_tb(env, ctx, 1, ctx->pc+2); \ - gen_set_label(l1); \ - gen_goto_tb(env, ctx, 0, extract_branch_offset(opcode) + ctx->pc+2); \ - ctx->bstate = BS_BRANCH; \ - } while (0) - - switch (inst) { - case 0x00: /* beq */ - BRANCH(TCG_COND_EQ); - break; - case 0x01: /* bne */ - BRANCH(TCG_COND_NE); - break; - case 0x02: /* blt */ - BRANCH(TCG_COND_LT); - break; - case 0x03: /* bgt */ - BRANCH(TCG_COND_GT); - break; - case 0x04: /* bltu */ - BRANCH(TCG_COND_LTU); - break; - case 0x05: /* bgtu */ - BRANCH(TCG_COND_GTU); - break; - case 0x06: /* bge */ - BRANCH(TCG_COND_GE); - break; - case 0x07: /* ble */ - BRANCH(TCG_COND_LE); - break; - case 0x08: /* bgeu */ - BRANCH(TCG_COND_GEU); - break; - case 0x09: /* bleu */ - BRANCH(TCG_COND_LEU); - break; - default: - { - TCGv temp = tcg_temp_new_i32(); - tcg_gen_movi_i32(cpu_pc, ctx->pc); - tcg_gen_movi_i32(temp, MOXIE_EX_BAD); - gen_helper_raise_exception(cpu_env, temp); - tcg_temp_free_i32(temp); - } - break; - } - } else { - /* This is a Form 2 instruction. */ - int inst = (opcode >> 12 & 0x3); - switch (inst) { - case 0x00: /* inc */ - { - int a = (opcode >> 8) & 0xf; - unsigned int v = (opcode & 0xff); - tcg_gen_addi_i32(REG(a), REG(a), v); - } - break; - case 0x01: /* dec */ - { - int a = (opcode >> 8) & 0xf; - unsigned int v = (opcode & 0xff); - tcg_gen_subi_i32(REG(a), REG(a), v); - } - break; - case 0x02: /* gsr */ - { - int a = (opcode >> 8) & 0xf; - unsigned v = (opcode & 0xff); - tcg_gen_ld_i32(REG(a), cpu_env, - offsetof(CPUMoxieState, sregs[v])); - } - break; - case 0x03: /* ssr */ - { - int a = (opcode >> 8) & 0xf; - unsigned v = (opcode & 0xff); - tcg_gen_st_i32(REG(a), cpu_env, - offsetof(CPUMoxieState, sregs[v])); - } - break; - default: - { - TCGv temp = tcg_temp_new_i32(); - tcg_gen_movi_i32(cpu_pc, ctx->pc); - tcg_gen_movi_i32(temp, MOXIE_EX_BAD); - gen_helper_raise_exception(cpu_env, temp); - tcg_temp_free_i32(temp); - } - break; - } - } - } else { - /* This is a Form 1 instruction. */ - int inst = opcode >> 8; - switch (inst) { - case 0x00: /* nop */ - break; - case 0x01: /* ldi.l (immediate) */ - { - int reg = (opcode >> 4) & 0xf; - int val = cpu_ldl_code(env, ctx->pc+2); - tcg_gen_movi_i32(REG(reg), val); - length = 6; - } - break; - case 0x02: /* mov (register-to-register) */ - { - int dest = (opcode >> 4) & 0xf; - int src = opcode & 0xf; - tcg_gen_mov_i32(REG(dest), REG(src)); - } - break; - case 0x03: /* jsra */ - { - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - - tcg_gen_movi_i32(t1, ctx->pc + 6); - - /* Make space for the static chain and return address. */ - tcg_gen_subi_i32(t2, REG(1), 8); - tcg_gen_mov_i32(REG(1), t2); - tcg_gen_qemu_st32(t1, REG(1), ctx->memidx); - - /* Push the current frame pointer. */ - tcg_gen_subi_i32(t2, REG(1), 4); - tcg_gen_mov_i32(REG(1), t2); - tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx); - - /* Set the pc and $fp. */ - tcg_gen_mov_i32(REG(0), REG(1)); - - gen_goto_tb(env, ctx, 0, cpu_ldl_code(env, ctx->pc+2)); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - ctx->bstate = BS_BRANCH; - length = 6; - } - break; - case 0x04: /* ret */ - { - TCGv t1 = tcg_temp_new_i32(); - - /* The new $sp is the old $fp. */ - tcg_gen_mov_i32(REG(1), REG(0)); - - /* Pop the frame pointer. */ - tcg_gen_qemu_ld32u(REG(0), REG(1), ctx->memidx); - tcg_gen_addi_i32(t1, REG(1), 4); - tcg_gen_mov_i32(REG(1), t1); - - - /* Pop the return address and skip over the static chain - slot. */ - tcg_gen_qemu_ld32u(cpu_pc, REG(1), ctx->memidx); - tcg_gen_addi_i32(t1, REG(1), 8); - tcg_gen_mov_i32(REG(1), t1); - - tcg_temp_free_i32(t1); - - /* Jump... */ - tcg_gen_exit_tb(NULL, 0); - - ctx->bstate = BS_BRANCH; - } - break; - case 0x05: /* add.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_add_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x06: /* push */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - tcg_gen_subi_i32(t1, REG(a), 4); - tcg_gen_mov_i32(REG(a), t1); - tcg_gen_qemu_st32(REG(b), REG(a), ctx->memidx); - tcg_temp_free_i32(t1); - } - break; - case 0x07: /* pop */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - TCGv t1 = tcg_temp_new_i32(); - - tcg_gen_qemu_ld32u(REG(b), REG(a), ctx->memidx); - tcg_gen_addi_i32(t1, REG(a), 4); - tcg_gen_mov_i32(REG(a), t1); - tcg_temp_free_i32(t1); - } - break; - case 0x08: /* lda.l */ - { - int reg = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld32u(REG(reg), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x09: /* sta.l */ - { - int val = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st32(REG(val), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x0a: /* ld.l (register indirect) */ - { - int src = opcode & 0xf; - int dest = (opcode >> 4) & 0xf; - - tcg_gen_qemu_ld32u(REG(dest), REG(src), ctx->memidx); - } - break; - case 0x0b: /* st.l */ - { - int dest = (opcode >> 4) & 0xf; - int val = opcode & 0xf; - - tcg_gen_qemu_st32(REG(val), REG(dest), ctx->memidx); - } - break; - case 0x0c: /* ldo.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld32u(t2, t1, ctx->memidx); - tcg_gen_mov_i32(REG(a), t2); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - case 0x0d: /* sto.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st32(REG(b), t1, ctx->memidx); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - case 0x0e: /* cmp */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_mov_i32(cc_a, REG(a)); - tcg_gen_mov_i32(cc_b, REG(b)); - } - break; - case 0x19: /* jsr */ - { - int fnreg = (opcode >> 4) & 0xf; - - /* Load the stack pointer into T0. */ - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - - tcg_gen_movi_i32(t1, ctx->pc+2); - - /* Make space for the static chain and return address. */ - tcg_gen_subi_i32(t2, REG(1), 8); - tcg_gen_mov_i32(REG(1), t2); - tcg_gen_qemu_st32(t1, REG(1), ctx->memidx); - - /* Push the current frame pointer. */ - tcg_gen_subi_i32(t2, REG(1), 4); - tcg_gen_mov_i32(REG(1), t2); - tcg_gen_qemu_st32(REG(0), REG(1), ctx->memidx); - - /* Set the pc and $fp. */ - tcg_gen_mov_i32(REG(0), REG(1)); - tcg_gen_mov_i32(cpu_pc, REG(fnreg)); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - tcg_gen_exit_tb(NULL, 0); - ctx->bstate = BS_BRANCH; - } - break; - case 0x1a: /* jmpa */ - { - tcg_gen_movi_i32(cpu_pc, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_exit_tb(NULL, 0); - ctx->bstate = BS_BRANCH; - length = 6; - } - break; - case 0x1b: /* ldi.b (immediate) */ - { - int reg = (opcode >> 4) & 0xf; - int val = cpu_ldl_code(env, ctx->pc+2); - tcg_gen_movi_i32(REG(reg), val); - length = 6; - } - break; - case 0x1c: /* ld.b (register indirect) */ - { - int src = opcode & 0xf; - int dest = (opcode >> 4) & 0xf; - - tcg_gen_qemu_ld8u(REG(dest), REG(src), ctx->memidx); - } - break; - case 0x1d: /* lda.b */ - { - int reg = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld8u(REG(reg), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x1e: /* st.b */ - { - int dest = (opcode >> 4) & 0xf; - int val = opcode & 0xf; - - tcg_gen_qemu_st8(REG(val), REG(dest), ctx->memidx); - } - break; - case 0x1f: /* sta.b */ - { - int val = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st8(REG(val), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x20: /* ldi.s (immediate) */ - { - int reg = (opcode >> 4) & 0xf; - int val = cpu_ldl_code(env, ctx->pc+2); - tcg_gen_movi_i32(REG(reg), val); - length = 6; - } - break; - case 0x21: /* ld.s (register indirect) */ - { - int src = opcode & 0xf; - int dest = (opcode >> 4) & 0xf; - - tcg_gen_qemu_ld16u(REG(dest), REG(src), ctx->memidx); - } - break; - case 0x22: /* lda.s */ - { - int reg = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld16u(REG(reg), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x23: /* st.s */ - { - int dest = (opcode >> 4) & 0xf; - int val = opcode & 0xf; - - tcg_gen_qemu_st16(REG(val), REG(dest), ctx->memidx); - } - break; - case 0x24: /* sta.s */ - { - int val = (opcode >> 4) & 0xf; - - TCGv ptr = tcg_temp_new_i32(); - tcg_gen_movi_i32(ptr, cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st16(REG(val), ptr, ctx->memidx); - tcg_temp_free_i32(ptr); - - length = 6; - } - break; - case 0x25: /* jmp */ - { - int reg = (opcode >> 4) & 0xf; - tcg_gen_mov_i32(cpu_pc, REG(reg)); - tcg_gen_exit_tb(NULL, 0); - ctx->bstate = BS_BRANCH; - } - break; - case 0x26: /* and */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_and_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x27: /* lshr */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv sv = tcg_temp_new_i32(); - tcg_gen_andi_i32(sv, REG(b), 0x1f); - tcg_gen_shr_i32(REG(a), REG(a), sv); - tcg_temp_free_i32(sv); - } - break; - case 0x28: /* ashl */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv sv = tcg_temp_new_i32(); - tcg_gen_andi_i32(sv, REG(b), 0x1f); - tcg_gen_shl_i32(REG(a), REG(a), sv); - tcg_temp_free_i32(sv); - } - break; - case 0x29: /* sub.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_sub_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x2a: /* neg */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_neg_i32(REG(a), REG(b)); - } - break; - case 0x2b: /* or */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_or_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x2c: /* not */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_not_i32(REG(a), REG(b)); - } - break; - case 0x2d: /* ashr */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv sv = tcg_temp_new_i32(); - tcg_gen_andi_i32(sv, REG(b), 0x1f); - tcg_gen_sar_i32(REG(a), REG(a), sv); - tcg_temp_free_i32(sv); - } - break; - case 0x2e: /* xor */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_xor_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x2f: /* mul.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - tcg_gen_mul_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x30: /* swi */ - { - int val = cpu_ldl_code(env, ctx->pc+2); - - TCGv temp = tcg_temp_new_i32(); - tcg_gen_movi_i32(temp, val); - tcg_gen_st_i32(temp, cpu_env, - offsetof(CPUMoxieState, sregs[3])); - tcg_gen_movi_i32(cpu_pc, ctx->pc); - tcg_gen_movi_i32(temp, MOXIE_EX_SWI); - gen_helper_raise_exception(cpu_env, temp); - tcg_temp_free_i32(temp); - - length = 6; - } - break; - case 0x31: /* div.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - tcg_gen_movi_i32(cpu_pc, ctx->pc); - gen_helper_div(REG(a), cpu_env, REG(a), REG(b)); - } - break; - case 0x32: /* udiv.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - tcg_gen_movi_i32(cpu_pc, ctx->pc); - gen_helper_udiv(REG(a), cpu_env, REG(a), REG(b)); - } - break; - case 0x33: /* mod.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - tcg_gen_rem_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x34: /* umod.l */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - tcg_gen_remu_i32(REG(a), REG(a), REG(b)); - } - break; - case 0x35: /* brk */ - { - TCGv temp = tcg_temp_new_i32(); - tcg_gen_movi_i32(cpu_pc, ctx->pc); - tcg_gen_movi_i32(temp, MOXIE_EX_BREAK); - gen_helper_raise_exception(cpu_env, temp); - tcg_temp_free_i32(temp); - } - break; - case 0x36: /* ldo.b */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld8u(t2, t1, ctx->memidx); - tcg_gen_mov_i32(REG(a), t2); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - case 0x37: /* sto.b */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st8(REG(b), t1, ctx->memidx); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - case 0x38: /* ldo.s */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(b), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_ld16u(t2, t1, ctx->memidx); - tcg_gen_mov_i32(REG(a), t2); - - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - case 0x39: /* sto.s */ - { - int a = (opcode >> 4) & 0xf; - int b = opcode & 0xf; - - TCGv t1 = tcg_temp_new_i32(); - TCGv t2 = tcg_temp_new_i32(); - tcg_gen_addi_i32(t1, REG(a), cpu_ldl_code(env, ctx->pc+2)); - tcg_gen_qemu_st16(REG(b), t1, ctx->memidx); - tcg_temp_free_i32(t1); - tcg_temp_free_i32(t2); - - length = 6; - } - break; - default: - { - TCGv temp = tcg_temp_new_i32(); - tcg_gen_movi_i32(cpu_pc, ctx->pc); - tcg_gen_movi_i32(temp, MOXIE_EX_BAD); - gen_helper_raise_exception(cpu_env, temp); - tcg_temp_free_i32(temp); - } - break; - } - } - - return length; -} - -/* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) -{ - CPUMoxieState *env = cs->env_ptr; - MoxieCPU *cpu = env_archcpu(env); - DisasContext ctx; - target_ulong pc_start; - int num_insns; - - pc_start = tb->pc; - ctx.pc = pc_start; - ctx.saved_pc = -1; - ctx.tb = tb; - ctx.memidx = 0; - ctx.singlestep_enabled = 0; - ctx.bstate = BS_NONE; - num_insns = 0; - - gen_tb_start(tb); - do { - tcg_gen_insn_start(ctx.pc); - num_insns++; - - if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) { - tcg_gen_movi_i32(cpu_pc, ctx.pc); - gen_helper_debug(cpu_env); - ctx.bstate = BS_EXCP; - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - ctx.pc += 2; - goto done_generating; - } - - ctx.opcode = cpu_lduw_code(env, ctx.pc); - ctx.pc += decode_opc(cpu, &ctx); - - if (num_insns >= max_insns) { - break; - } - if (cs->singlestep_enabled) { - break; - } - if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) { - break; - } - } while (ctx.bstate == BS_NONE && !tcg_op_buf_full()); - - if (cs->singlestep_enabled) { - tcg_gen_movi_tl(cpu_pc, ctx.pc); - gen_helper_debug(cpu_env); - } else { - switch (ctx.bstate) { - case BS_STOP: - case BS_NONE: - gen_goto_tb(env, &ctx, 0, ctx.pc); - break; - case BS_EXCP: - tcg_gen_exit_tb(NULL, 0); - break; - case BS_BRANCH: - default: - break; - } - } - done_generating: - gen_tb_end(tb, num_insns); - - tb->size = ctx.pc - pc_start; - tb->icount = num_insns; -} - -void restore_state_to_opc(CPUMoxieState *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; -} diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c index d74509b1c5..d40adddafa 100644 --- a/tests/qtest/boot-serial-test.c +++ b/tests/qtest/boot-serial-test.c @@ -61,13 +61,6 @@ static const uint8_t kernel_plml605[] = { 0xfc, 0xff, 0x00, 0xb8 /* bri -4 loop */ }; -static const uint8_t bios_moxiesim[] = { - 0x20, 0x10, 0x00, 0x00, 0x03, 0xf8, /* ldi.s r1,0x3f8 */ - 0x1b, 0x20, 0x00, 0x00, 0x00, 0x54, /* ldi.b r2,'T' */ - 0x1e, 0x12, /* st.b r1,r2 */ - 0x1a, 0x00, 0x00, 0x00, 0x10, 0x00 /* jmpa 0x1000 */ -}; - static const uint8_t bios_raspi2[] = { 0x08, 0x30, 0x9f, 0xe5, /* ldr r3,[pc,#8] Get base */ 0x54, 0x20, 0xa0, 0xe3, /* mov r2,#'T' */ @@ -145,7 +138,6 @@ static testdef_t tests[] = { sizeof(kernel_pls3adsp1800), kernel_pls3adsp1800 }, { "microblazeel", "petalogix-ml605", "", "TT", sizeof(kernel_plml605), kernel_plml605 }, - { "moxie", "moxiesim", "", "TT", sizeof(bios_moxiesim), 0, bios_moxiesim }, { "arm", "raspi2", "", "TT", sizeof(bios_raspi2), 0, bios_raspi2 }, /* For hppa, force bios to output to serial by disabling graphics. */ { "hppa", "hppa", "-vga none", "SeaBIOS wants SYSTEM HALT" }, diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c index aab06b9fc2..5feada15dc 100644 --- a/tests/qtest/machine-none-test.c +++ b/tests/qtest/machine-none-test.c @@ -40,7 +40,6 @@ static struct arch2cpu cpus_map[] = { { "mipsel", "I7200" }, { "mips64", "20Kc" }, { "mips64el", "I6500" }, - { "moxie", "MoxieLite" }, { "nios2", "FIXME" }, { "or1k", "or1200" }, { "ppc", "604" }, diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 966bc93efa..49de74ff59 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -126,8 +126,6 @@ qtests_mips64el = \ (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \ (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : []) -qtests_moxie = [ 'boot-serial-test' ] - qtests_ppc = \ (config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \ (config_all_devices.has_key('CONFIG_M48T59') ? ['m48t59-test'] : []) + \ From 09ec85176e4095be15f233ebc870d5680123f024 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sat, 1 May 2021 09:57:47 +0200 Subject: [PATCH 0490/3028] block: Drop the sheepdog block driver It was deprecated in commit e1c4269763, v5.2.0. See that commit message for rationale. Signed-off-by: Markus Armbruster Message-Id: <20210501075747.3293186-1-armbru@redhat.com> ACKed-by: Peter Krempa --- .gitlab-ci.yml | 1 - MAINTAINERS | 6 - block/meson.build | 1 - block/sheepdog.c | 3356 ------------------------ block/trace-events | 14 - configure | 10 - docs/system/deprecated.rst | 9 - docs/system/device-url-syntax.rst.inc | 18 - docs/system/qemu-block-drivers.rst.inc | 69 - docs/system/removed-features.rst | 7 + meson.build | 1 - qapi/block-core.json | 93 +- qapi/transaction.json | 8 +- tests/qemu-iotests/005 | 5 - tests/qemu-iotests/025 | 2 +- tests/qemu-iotests/check | 3 +- tests/qemu-iotests/common.rc | 4 - 17 files changed, 14 insertions(+), 3593 deletions(-) delete mode 100644 block/sheepdog.c diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index da6570799b..745fdaea92 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -342,7 +342,6 @@ build-disabled: --disable-replication --disable-sdl --disable-seccomp - --disable-sheepdog --disable-slirp --disable-smartcard --disable-snappy diff --git a/MAINTAINERS b/MAINTAINERS index 50884fef15..c765165e5c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3072,12 +3072,6 @@ L: qemu-block@nongnu.org S: Supported F: block/rbd.c -Sheepdog -M: Liu Yuan -L: qemu-block@nongnu.org -S: Odd Fixes -F: block/sheepdog.c - VHDX M: Jeff Cody L: qemu-block@nongnu.org diff --git a/block/meson.build b/block/meson.build index d21990ec95..e687c54dbc 100644 --- a/block/meson.build +++ b/block/meson.build @@ -64,7 +64,6 @@ block_ss.add(when: 'CONFIG_POSIX', if_true: [files('file-posix.c'), coref, iokit block_ss.add(when: libiscsi, if_true: files('iscsi-opts.c')) block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c')) block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c')) -block_ss.add(when: 'CONFIG_SHEEPDOG', if_true: files('sheepdog.c')) block_ss.add(when: ['CONFIG_LINUX_AIO', libaio], if_true: files('linux-aio.c')) block_ss.add(when: ['CONFIG_LINUX_IO_URING', linux_io_uring], if_true: files('io_uring.c')) diff --git a/block/sheepdog.c b/block/sheepdog.c deleted file mode 100644 index a45c73826d..0000000000 --- a/block/sheepdog.c +++ /dev/null @@ -1,3356 +0,0 @@ -/* - * Copyright (C) 2009-2010 Nippon Telegraph and Telephone Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "qapi/error.h" -#include "qapi/qapi-visit-sockets.h" -#include "qapi/qapi-visit-block-core.h" -#include "qapi/qmp/qdict.h" -#include "qapi/qobject-input-visitor.h" -#include "qapi/qobject-output-visitor.h" -#include "qemu/uri.h" -#include "qemu/error-report.h" -#include "qemu/main-loop.h" -#include "qemu/module.h" -#include "qemu/option.h" -#include "qemu/sockets.h" -#include "block/block_int.h" -#include "block/qdict.h" -#include "sysemu/block-backend.h" -#include "qemu/bitops.h" -#include "qemu/cutils.h" -#include "trace.h" - -#define SD_PROTO_VER 0x01 - -#define SD_DEFAULT_ADDR "localhost" -#define SD_DEFAULT_PORT 7000 - -#define SD_OP_CREATE_AND_WRITE_OBJ 0x01 -#define SD_OP_READ_OBJ 0x02 -#define SD_OP_WRITE_OBJ 0x03 -/* 0x04 is used internally by Sheepdog */ - -#define SD_OP_NEW_VDI 0x11 -#define SD_OP_LOCK_VDI 0x12 -#define SD_OP_RELEASE_VDI 0x13 -#define SD_OP_GET_VDI_INFO 0x14 -#define SD_OP_READ_VDIS 0x15 -#define SD_OP_FLUSH_VDI 0x16 -#define SD_OP_DEL_VDI 0x17 -#define SD_OP_GET_CLUSTER_DEFAULT 0x18 - -#define SD_FLAG_CMD_WRITE 0x01 -#define SD_FLAG_CMD_COW 0x02 -#define SD_FLAG_CMD_CACHE 0x04 /* Writeback mode for cache */ -#define SD_FLAG_CMD_DIRECT 0x08 /* Don't use cache */ - -#define SD_RES_SUCCESS 0x00 /* Success */ -#define SD_RES_UNKNOWN 0x01 /* Unknown error */ -#define SD_RES_NO_OBJ 0x02 /* No object found */ -#define SD_RES_EIO 0x03 /* I/O error */ -#define SD_RES_VDI_EXIST 0x04 /* Vdi exists already */ -#define SD_RES_INVALID_PARMS 0x05 /* Invalid parameters */ -#define SD_RES_SYSTEM_ERROR 0x06 /* System error */ -#define SD_RES_VDI_LOCKED 0x07 /* Vdi is locked */ -#define SD_RES_NO_VDI 0x08 /* No vdi found */ -#define SD_RES_NO_BASE_VDI 0x09 /* No base vdi found */ -#define SD_RES_VDI_READ 0x0A /* Cannot read requested vdi */ -#define SD_RES_VDI_WRITE 0x0B /* Cannot write requested vdi */ -#define SD_RES_BASE_VDI_READ 0x0C /* Cannot read base vdi */ -#define SD_RES_BASE_VDI_WRITE 0x0D /* Cannot write base vdi */ -#define SD_RES_NO_TAG 0x0E /* Requested tag is not found */ -#define SD_RES_STARTUP 0x0F /* Sheepdog is on starting up */ -#define SD_RES_VDI_NOT_LOCKED 0x10 /* Vdi is not locked */ -#define SD_RES_SHUTDOWN 0x11 /* Sheepdog is shutting down */ -#define SD_RES_NO_MEM 0x12 /* Cannot allocate memory */ -#define SD_RES_FULL_VDI 0x13 /* we already have the maximum vdis */ -#define SD_RES_VER_MISMATCH 0x14 /* Protocol version mismatch */ -#define SD_RES_NO_SPACE 0x15 /* Server has no room for new objects */ -#define SD_RES_WAIT_FOR_FORMAT 0x16 /* Waiting for a format operation */ -#define SD_RES_WAIT_FOR_JOIN 0x17 /* Waiting for other nodes joining */ -#define SD_RES_JOIN_FAILED 0x18 /* Target node had failed to join sheepdog */ -#define SD_RES_HALT 0x19 /* Sheepdog is stopped serving IO request */ -#define SD_RES_READONLY 0x1A /* Object is read-only */ - -/* - * Object ID rules - * - * 0 - 19 (20 bits): data object space - * 20 - 31 (12 bits): reserved data object space - * 32 - 55 (24 bits): vdi object space - * 56 - 59 ( 4 bits): reserved vdi object space - * 60 - 63 ( 4 bits): object type identifier space - */ - -#define VDI_SPACE_SHIFT 32 -#define VDI_BIT (UINT64_C(1) << 63) -#define VMSTATE_BIT (UINT64_C(1) << 62) -#define MAX_DATA_OBJS (UINT64_C(1) << 20) -#define MAX_CHILDREN 1024 -#define SD_MAX_VDI_LEN 256 -#define SD_MAX_VDI_TAG_LEN 256 -#define SD_NR_VDIS (1U << 24) -#define SD_DATA_OBJ_SIZE (UINT64_C(1) << 22) -#define SD_MAX_VDI_SIZE (SD_DATA_OBJ_SIZE * MAX_DATA_OBJS) -#define SD_DEFAULT_BLOCK_SIZE_SHIFT 22 -/* - * For erasure coding, we use at most SD_EC_MAX_STRIP for data strips and - * (SD_EC_MAX_STRIP - 1) for parity strips - * - * SD_MAX_COPIES is sum of number of data strips and parity strips. - */ -#define SD_EC_MAX_STRIP 16 -#define SD_MAX_COPIES (SD_EC_MAX_STRIP * 2 - 1) - -#define SD_INODE_SIZE (sizeof(SheepdogInode)) -#define CURRENT_VDI_ID 0 - -#define LOCK_TYPE_NORMAL 0 -#define LOCK_TYPE_SHARED 1 /* for iSCSI multipath */ - -typedef struct SheepdogReq { - uint8_t proto_ver; - uint8_t opcode; - uint16_t flags; - uint32_t epoch; - uint32_t id; - uint32_t data_length; - uint32_t opcode_specific[8]; -} SheepdogReq; - -typedef struct SheepdogRsp { - uint8_t proto_ver; - uint8_t opcode; - uint16_t flags; - uint32_t epoch; - uint32_t id; - uint32_t data_length; - uint32_t result; - uint32_t opcode_specific[7]; -} SheepdogRsp; - -typedef struct SheepdogObjReq { - uint8_t proto_ver; - uint8_t opcode; - uint16_t flags; - uint32_t epoch; - uint32_t id; - uint32_t data_length; - uint64_t oid; - uint64_t cow_oid; - uint8_t copies; - uint8_t copy_policy; - uint8_t reserved[6]; - uint64_t offset; -} SheepdogObjReq; - -typedef struct SheepdogObjRsp { - uint8_t proto_ver; - uint8_t opcode; - uint16_t flags; - uint32_t epoch; - uint32_t id; - uint32_t data_length; - uint32_t result; - uint8_t copies; - uint8_t copy_policy; - uint8_t reserved[2]; - uint32_t pad[6]; -} SheepdogObjRsp; - -typedef struct SheepdogVdiReq { - uint8_t proto_ver; - uint8_t opcode; - uint16_t flags; - uint32_t epoch; - uint32_t id; - uint32_t data_length; - uint64_t vdi_size; - uint32_t base_vdi_id; - uint8_t copies; - uint8_t copy_policy; - uint8_t store_policy; - uint8_t block_size_shift; - uint32_t snapid; - uint32_t type; - uint32_t pad[2]; -} SheepdogVdiReq; - -typedef struct SheepdogVdiRsp { - uint8_t proto_ver; - uint8_t opcode; - uint16_t flags; - uint32_t epoch; - uint32_t id; - uint32_t data_length; - uint32_t result; - uint32_t rsvd; - uint32_t vdi_id; - uint32_t pad[5]; -} SheepdogVdiRsp; - -typedef struct SheepdogClusterRsp { - uint8_t proto_ver; - uint8_t opcode; - uint16_t flags; - uint32_t epoch; - uint32_t id; - uint32_t data_length; - uint32_t result; - uint8_t nr_copies; - uint8_t copy_policy; - uint8_t block_size_shift; - uint8_t __pad1; - uint32_t __pad2[6]; -} SheepdogClusterRsp; - -typedef struct SheepdogInode { - char name[SD_MAX_VDI_LEN]; - char tag[SD_MAX_VDI_TAG_LEN]; - uint64_t ctime; - uint64_t snap_ctime; - uint64_t vm_clock_nsec; - uint64_t vdi_size; - uint64_t vm_state_size; - uint16_t copy_policy; - uint8_t nr_copies; - uint8_t block_size_shift; - uint32_t snap_id; - uint32_t vdi_id; - uint32_t parent_vdi_id; - uint32_t child_vdi_id[MAX_CHILDREN]; - uint32_t data_vdi_id[MAX_DATA_OBJS]; -} SheepdogInode; - -#define SD_INODE_HEADER_SIZE offsetof(SheepdogInode, data_vdi_id) - -/* - * 64 bit FNV-1a non-zero initial basis - */ -#define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL) - -static void deprecation_warning(void) -{ - static bool warned; - - if (!warned) { - warn_report("the sheepdog block driver is deprecated"); - warned = true; - } -} - -/* - * 64 bit Fowler/Noll/Vo FNV-1a hash code - */ -static inline uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval) -{ - unsigned char *bp = buf; - unsigned char *be = bp + len; - while (bp < be) { - hval ^= (uint64_t) *bp++; - hval += (hval << 1) + (hval << 4) + (hval << 5) + - (hval << 7) + (hval << 8) + (hval << 40); - } - return hval; -} - -static inline bool is_data_obj_writable(SheepdogInode *inode, unsigned int idx) -{ - return inode->vdi_id == inode->data_vdi_id[idx]; -} - -static inline bool is_data_obj(uint64_t oid) -{ - return !(VDI_BIT & oid); -} - -static inline uint64_t data_oid_to_idx(uint64_t oid) -{ - return oid & (MAX_DATA_OBJS - 1); -} - -static inline uint32_t oid_to_vid(uint64_t oid) -{ - return (oid & ~VDI_BIT) >> VDI_SPACE_SHIFT; -} - -static inline uint64_t vid_to_vdi_oid(uint32_t vid) -{ - return VDI_BIT | ((uint64_t)vid << VDI_SPACE_SHIFT); -} - -static inline uint64_t vid_to_vmstate_oid(uint32_t vid, uint32_t idx) -{ - return VMSTATE_BIT | ((uint64_t)vid << VDI_SPACE_SHIFT) | idx; -} - -static inline uint64_t vid_to_data_oid(uint32_t vid, uint32_t idx) -{ - return ((uint64_t)vid << VDI_SPACE_SHIFT) | idx; -} - -static inline bool is_snapshot(struct SheepdogInode *inode) -{ - return !!inode->snap_ctime; -} - -static inline size_t count_data_objs(const struct SheepdogInode *inode) -{ - return DIV_ROUND_UP(inode->vdi_size, - (1UL << inode->block_size_shift)); -} - -typedef struct SheepdogAIOCB SheepdogAIOCB; -typedef struct BDRVSheepdogState BDRVSheepdogState; - -typedef struct AIOReq { - SheepdogAIOCB *aiocb; - unsigned int iov_offset; - - uint64_t oid; - uint64_t base_oid; - uint64_t offset; - unsigned int data_len; - uint8_t flags; - uint32_t id; - bool create; - - QLIST_ENTRY(AIOReq) aio_siblings; -} AIOReq; - -enum AIOCBState { - AIOCB_WRITE_UDATA, - AIOCB_READ_UDATA, - AIOCB_FLUSH_CACHE, - AIOCB_DISCARD_OBJ, -}; - -#define AIOCBOverlapping(x, y) \ - (!(x->max_affect_data_idx < y->min_affect_data_idx \ - || y->max_affect_data_idx < x->min_affect_data_idx)) - -struct SheepdogAIOCB { - BDRVSheepdogState *s; - - QEMUIOVector *qiov; - - int64_t sector_num; - int nb_sectors; - - int ret; - enum AIOCBState aiocb_type; - - Coroutine *coroutine; - int nr_pending; - - uint32_t min_affect_data_idx; - uint32_t max_affect_data_idx; - - /* - * The difference between affect_data_idx and dirty_data_idx: - * affect_data_idx represents range of index of all request types. - * dirty_data_idx represents range of index updated by COW requests. - * dirty_data_idx is used for updating an inode object. - */ - uint32_t min_dirty_data_idx; - uint32_t max_dirty_data_idx; - - QLIST_ENTRY(SheepdogAIOCB) aiocb_siblings; -}; - -struct BDRVSheepdogState { - BlockDriverState *bs; - AioContext *aio_context; - - SheepdogInode inode; - - char name[SD_MAX_VDI_LEN]; - bool is_snapshot; - uint32_t cache_flags; - bool discard_supported; - - SocketAddress *addr; - int fd; - - CoMutex lock; - Coroutine *co_send; - Coroutine *co_recv; - - uint32_t aioreq_seq_num; - - /* Every aio request must be linked to either of these queues. */ - QLIST_HEAD(, AIOReq) inflight_aio_head; - QLIST_HEAD(, AIOReq) failed_aio_head; - - CoMutex queue_lock; - CoQueue overlapping_queue; - QLIST_HEAD(, SheepdogAIOCB) inflight_aiocb_head; -}; - -typedef struct BDRVSheepdogReopenState { - int fd; - int cache_flags; -} BDRVSheepdogReopenState; - -static const char *sd_strerror(int err) -{ - int i; - - static const struct { - int err; - const char *desc; - } errors[] = { - {SD_RES_SUCCESS, "Success"}, - {SD_RES_UNKNOWN, "Unknown error"}, - {SD_RES_NO_OBJ, "No object found"}, - {SD_RES_EIO, "I/O error"}, - {SD_RES_VDI_EXIST, "VDI exists already"}, - {SD_RES_INVALID_PARMS, "Invalid parameters"}, - {SD_RES_SYSTEM_ERROR, "System error"}, - {SD_RES_VDI_LOCKED, "VDI is already locked"}, - {SD_RES_NO_VDI, "No vdi found"}, - {SD_RES_NO_BASE_VDI, "No base VDI found"}, - {SD_RES_VDI_READ, "Failed read the requested VDI"}, - {SD_RES_VDI_WRITE, "Failed to write the requested VDI"}, - {SD_RES_BASE_VDI_READ, "Failed to read the base VDI"}, - {SD_RES_BASE_VDI_WRITE, "Failed to write the base VDI"}, - {SD_RES_NO_TAG, "Failed to find the requested tag"}, - {SD_RES_STARTUP, "The system is still booting"}, - {SD_RES_VDI_NOT_LOCKED, "VDI isn't locked"}, - {SD_RES_SHUTDOWN, "The system is shutting down"}, - {SD_RES_NO_MEM, "Out of memory on the server"}, - {SD_RES_FULL_VDI, "We already have the maximum vdis"}, - {SD_RES_VER_MISMATCH, "Protocol version mismatch"}, - {SD_RES_NO_SPACE, "Server has no space for new objects"}, - {SD_RES_WAIT_FOR_FORMAT, "Sheepdog is waiting for a format operation"}, - {SD_RES_WAIT_FOR_JOIN, "Sheepdog is waiting for other nodes joining"}, - {SD_RES_JOIN_FAILED, "Target node had failed to join sheepdog"}, - {SD_RES_HALT, "Sheepdog is stopped serving IO request"}, - {SD_RES_READONLY, "Object is read-only"}, - }; - - for (i = 0; i < ARRAY_SIZE(errors); ++i) { - if (errors[i].err == err) { - return errors[i].desc; - } - } - - return "Invalid error code"; -} - -/* - * Sheepdog I/O handling: - * - * 1. In sd_co_rw_vector, we send the I/O requests to the server and - * link the requests to the inflight_list in the - * BDRVSheepdogState. The function yields while waiting for - * receiving the response. - * - * 2. We receive the response in aio_read_response, the fd handler to - * the sheepdog connection. We switch back to sd_co_readv/sd_writev - * after all the requests belonging to the AIOCB are finished. If - * needed, sd_co_writev will send another requests for the vdi object. - */ - -static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb, - uint64_t oid, unsigned int data_len, - uint64_t offset, uint8_t flags, bool create, - uint64_t base_oid, unsigned int iov_offset) -{ - AIOReq *aio_req; - - aio_req = g_malloc(sizeof(*aio_req)); - aio_req->aiocb = acb; - aio_req->iov_offset = iov_offset; - aio_req->oid = oid; - aio_req->base_oid = base_oid; - aio_req->offset = offset; - aio_req->data_len = data_len; - aio_req->flags = flags; - aio_req->id = s->aioreq_seq_num++; - aio_req->create = create; - - acb->nr_pending++; - return aio_req; -} - -static void wait_for_overlapping_aiocb(BDRVSheepdogState *s, SheepdogAIOCB *acb) -{ - SheepdogAIOCB *cb; - -retry: - QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) { - if (AIOCBOverlapping(acb, cb)) { - qemu_co_queue_wait(&s->overlapping_queue, &s->queue_lock); - goto retry; - } - } -} - -static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s, - QEMUIOVector *qiov, int64_t sector_num, int nb_sectors, - int type) -{ - uint32_t object_size; - - object_size = (UINT32_C(1) << s->inode.block_size_shift); - - acb->s = s; - - acb->qiov = qiov; - - acb->sector_num = sector_num; - acb->nb_sectors = nb_sectors; - - acb->coroutine = qemu_coroutine_self(); - acb->ret = 0; - acb->nr_pending = 0; - - acb->min_affect_data_idx = acb->sector_num * BDRV_SECTOR_SIZE / object_size; - acb->max_affect_data_idx = (acb->sector_num * BDRV_SECTOR_SIZE + - acb->nb_sectors * BDRV_SECTOR_SIZE) / object_size; - - acb->min_dirty_data_idx = UINT32_MAX; - acb->max_dirty_data_idx = 0; - acb->aiocb_type = type; - - if (type == AIOCB_FLUSH_CACHE) { - return; - } - - qemu_co_mutex_lock(&s->queue_lock); - wait_for_overlapping_aiocb(s, acb); - QLIST_INSERT_HEAD(&s->inflight_aiocb_head, acb, aiocb_siblings); - qemu_co_mutex_unlock(&s->queue_lock); -} - -static SocketAddress *sd_server_config(QDict *options, Error **errp) -{ - QDict *server = NULL; - Visitor *iv = NULL; - SocketAddress *saddr = NULL; - - qdict_extract_subqdict(options, &server, "server."); - - iv = qobject_input_visitor_new_flat_confused(server, errp); - if (!iv) { - goto done; - } - - if (!visit_type_SocketAddress(iv, NULL, &saddr, errp)) { - goto done; - } - -done: - visit_free(iv); - qobject_unref(server); - return saddr; -} - -/* Return -EIO in case of error, file descriptor on success */ -static int connect_to_sdog(BDRVSheepdogState *s, Error **errp) -{ - int fd; - - fd = socket_connect(s->addr, errp); - - if (s->addr->type == SOCKET_ADDRESS_TYPE_INET && fd >= 0) { - int ret = socket_set_nodelay(fd); - if (ret < 0) { - warn_report("can't set TCP_NODELAY: %s", strerror(errno)); - } - } - - if (fd >= 0) { - qemu_set_nonblock(fd); - } else { - fd = -EIO; - } - - return fd; -} - -/* Return 0 on success and -errno in case of error */ -static coroutine_fn int send_co_req(int sockfd, SheepdogReq *hdr, void *data, - unsigned int *wlen) -{ - int ret; - - ret = qemu_co_send(sockfd, hdr, sizeof(*hdr)); - if (ret != sizeof(*hdr)) { - error_report("failed to send a req, %s", strerror(errno)); - return -errno; - } - - ret = qemu_co_send(sockfd, data, *wlen); - if (ret != *wlen) { - error_report("failed to send a req, %s", strerror(errno)); - return -errno; - } - - return ret; -} - -typedef struct SheepdogReqCo { - int sockfd; - BlockDriverState *bs; - AioContext *aio_context; - SheepdogReq *hdr; - void *data; - unsigned int *wlen; - unsigned int *rlen; - int ret; - bool finished; - Coroutine *co; -} SheepdogReqCo; - -static void restart_co_req(void *opaque) -{ - SheepdogReqCo *srco = opaque; - - aio_co_wake(srco->co); -} - -static coroutine_fn void do_co_req(void *opaque) -{ - int ret; - SheepdogReqCo *srco = opaque; - int sockfd = srco->sockfd; - SheepdogReq *hdr = srco->hdr; - void *data = srco->data; - unsigned int *wlen = srco->wlen; - unsigned int *rlen = srco->rlen; - - srco->co = qemu_coroutine_self(); - aio_set_fd_handler(srco->aio_context, sockfd, false, - NULL, restart_co_req, NULL, srco); - - ret = send_co_req(sockfd, hdr, data, wlen); - if (ret < 0) { - goto out; - } - - aio_set_fd_handler(srco->aio_context, sockfd, false, - restart_co_req, NULL, NULL, srco); - - ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr)); - if (ret != sizeof(*hdr)) { - error_report("failed to get a rsp, %s", strerror(errno)); - ret = -errno; - goto out; - } - - if (*rlen > hdr->data_length) { - *rlen = hdr->data_length; - } - - if (*rlen) { - ret = qemu_co_recv(sockfd, data, *rlen); - if (ret != *rlen) { - error_report("failed to get the data, %s", strerror(errno)); - ret = -errno; - goto out; - } - } - ret = 0; -out: - /* there is at most one request for this sockfd, so it is safe to - * set each handler to NULL. */ - aio_set_fd_handler(srco->aio_context, sockfd, false, - NULL, NULL, NULL, NULL); - - srco->co = NULL; - srco->ret = ret; - /* Set srco->finished before reading bs->wakeup. */ - qatomic_mb_set(&srco->finished, true); - if (srco->bs) { - bdrv_wakeup(srco->bs); - } -} - -/* - * Send the request to the sheep in a synchronous manner. - * - * Return 0 on success, -errno in case of error. - */ -static int do_req(int sockfd, BlockDriverState *bs, SheepdogReq *hdr, - void *data, unsigned int *wlen, unsigned int *rlen) -{ - Coroutine *co; - SheepdogReqCo srco = { - .sockfd = sockfd, - .aio_context = bs ? bdrv_get_aio_context(bs) : qemu_get_aio_context(), - .bs = bs, - .hdr = hdr, - .data = data, - .wlen = wlen, - .rlen = rlen, - .ret = 0, - .finished = false, - }; - - if (qemu_in_coroutine()) { - do_co_req(&srco); - } else { - co = qemu_coroutine_create(do_co_req, &srco); - if (bs) { - bdrv_coroutine_enter(bs, co); - BDRV_POLL_WHILE(bs, !srco.finished); - } else { - qemu_coroutine_enter(co); - while (!srco.finished) { - aio_poll(qemu_get_aio_context(), true); - } - } - } - - return srco.ret; -} - -static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, - struct iovec *iov, int niov, - enum AIOCBState aiocb_type); -static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req); -static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag); -static int get_sheep_fd(BDRVSheepdogState *s, Error **errp); -static void co_write_request(void *opaque); - -static coroutine_fn void reconnect_to_sdog(void *opaque) -{ - BDRVSheepdogState *s = opaque; - AIOReq *aio_req, *next; - - aio_set_fd_handler(s->aio_context, s->fd, false, NULL, - NULL, NULL, NULL); - close(s->fd); - s->fd = -1; - - /* Wait for outstanding write requests to be completed. */ - while (s->co_send != NULL) { - co_write_request(opaque); - } - - /* Try to reconnect the sheepdog server every one second. */ - while (s->fd < 0) { - Error *local_err = NULL; - s->fd = get_sheep_fd(s, &local_err); - if (s->fd < 0) { - trace_sheepdog_reconnect_to_sdog(); - error_report_err(local_err); - qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, NANOSECONDS_PER_SECOND); - } - }; - - /* - * Now we have to resend all the request in the inflight queue. However, - * resend_aioreq() can yield and newly created requests can be added to the - * inflight queue before the coroutine is resumed. To avoid mixing them, we - * have to move all the inflight requests to the failed queue before - * resend_aioreq() is called. - */ - qemu_co_mutex_lock(&s->queue_lock); - QLIST_FOREACH_SAFE(aio_req, &s->inflight_aio_head, aio_siblings, next) { - QLIST_REMOVE(aio_req, aio_siblings); - QLIST_INSERT_HEAD(&s->failed_aio_head, aio_req, aio_siblings); - } - - /* Resend all the failed aio requests. */ - while (!QLIST_EMPTY(&s->failed_aio_head)) { - aio_req = QLIST_FIRST(&s->failed_aio_head); - QLIST_REMOVE(aio_req, aio_siblings); - qemu_co_mutex_unlock(&s->queue_lock); - resend_aioreq(s, aio_req); - qemu_co_mutex_lock(&s->queue_lock); - } - qemu_co_mutex_unlock(&s->queue_lock); -} - -/* - * Receive responses of the I/O requests. - * - * This function is registered as a fd handler, and called from the - * main loop when s->fd is ready for reading responses. - */ -static void coroutine_fn aio_read_response(void *opaque) -{ - SheepdogObjRsp rsp; - BDRVSheepdogState *s = opaque; - int fd = s->fd; - int ret; - AIOReq *aio_req = NULL; - SheepdogAIOCB *acb; - uint64_t idx; - - /* read a header */ - ret = qemu_co_recv(fd, &rsp, sizeof(rsp)); - if (ret != sizeof(rsp)) { - error_report("failed to get the header, %s", strerror(errno)); - goto err; - } - - /* find the right aio_req from the inflight aio list */ - QLIST_FOREACH(aio_req, &s->inflight_aio_head, aio_siblings) { - if (aio_req->id == rsp.id) { - break; - } - } - if (!aio_req) { - error_report("cannot find aio_req %x", rsp.id); - goto err; - } - - acb = aio_req->aiocb; - - switch (acb->aiocb_type) { - case AIOCB_WRITE_UDATA: - if (!is_data_obj(aio_req->oid)) { - break; - } - idx = data_oid_to_idx(aio_req->oid); - - if (aio_req->create) { - /* - * If the object is newly created one, we need to update - * the vdi object (metadata object). min_dirty_data_idx - * and max_dirty_data_idx are changed to include updated - * index between them. - */ - if (rsp.result == SD_RES_SUCCESS) { - s->inode.data_vdi_id[idx] = s->inode.vdi_id; - acb->max_dirty_data_idx = MAX(idx, acb->max_dirty_data_idx); - acb->min_dirty_data_idx = MIN(idx, acb->min_dirty_data_idx); - } - } - break; - case AIOCB_READ_UDATA: - ret = qemu_co_recvv(fd, acb->qiov->iov, acb->qiov->niov, - aio_req->iov_offset, rsp.data_length); - if (ret != rsp.data_length) { - error_report("failed to get the data, %s", strerror(errno)); - goto err; - } - break; - case AIOCB_FLUSH_CACHE: - if (rsp.result == SD_RES_INVALID_PARMS) { - trace_sheepdog_aio_read_response(); - s->cache_flags = SD_FLAG_CMD_DIRECT; - rsp.result = SD_RES_SUCCESS; - } - break; - case AIOCB_DISCARD_OBJ: - switch (rsp.result) { - case SD_RES_INVALID_PARMS: - error_report("server doesn't support discard command"); - rsp.result = SD_RES_SUCCESS; - s->discard_supported = false; - break; - default: - break; - } - } - - /* No more data for this aio_req (reload_inode below uses its own file - * descriptor handler which doesn't use co_recv). - */ - s->co_recv = NULL; - - qemu_co_mutex_lock(&s->queue_lock); - QLIST_REMOVE(aio_req, aio_siblings); - qemu_co_mutex_unlock(&s->queue_lock); - - switch (rsp.result) { - case SD_RES_SUCCESS: - break; - case SD_RES_READONLY: - if (s->inode.vdi_id == oid_to_vid(aio_req->oid)) { - ret = reload_inode(s, 0, ""); - if (ret < 0) { - goto err; - } - } - if (is_data_obj(aio_req->oid)) { - aio_req->oid = vid_to_data_oid(s->inode.vdi_id, - data_oid_to_idx(aio_req->oid)); - } else { - aio_req->oid = vid_to_vdi_oid(s->inode.vdi_id); - } - resend_aioreq(s, aio_req); - return; - default: - acb->ret = -EIO; - error_report("%s", sd_strerror(rsp.result)); - break; - } - - g_free(aio_req); - - if (!--acb->nr_pending) { - /* - * We've finished all requests which belong to the AIOCB, so - * we can switch back to sd_co_readv/writev now. - */ - aio_co_wake(acb->coroutine); - } - - return; - -err: - reconnect_to_sdog(opaque); -} - -static void co_read_response(void *opaque) -{ - BDRVSheepdogState *s = opaque; - - if (!s->co_recv) { - s->co_recv = qemu_coroutine_create(aio_read_response, opaque); - } - - aio_co_enter(s->aio_context, s->co_recv); -} - -static void co_write_request(void *opaque) -{ - BDRVSheepdogState *s = opaque; - - aio_co_wake(s->co_send); -} - -/* - * Return a socket descriptor to read/write objects. - * - * We cannot use this descriptor for other operations because - * the block driver may be on waiting response from the server. - */ -static int get_sheep_fd(BDRVSheepdogState *s, Error **errp) -{ - int fd; - - fd = connect_to_sdog(s, errp); - if (fd < 0) { - return fd; - } - - aio_set_fd_handler(s->aio_context, fd, false, - co_read_response, NULL, NULL, s); - return fd; -} - -/* - * Parse numeric snapshot ID in @str - * If @str can't be parsed as number, return false. - * Else, if the number is zero or too large, set *@snapid to zero and - * return true. - * Else, set *@snapid to the number and return true. - */ -static bool sd_parse_snapid(const char *str, uint32_t *snapid) -{ - unsigned long ul; - int ret; - - ret = qemu_strtoul(str, NULL, 10, &ul); - if (ret == -ERANGE) { - ul = ret = 0; - } - if (ret) { - return false; - } - if (ul > UINT32_MAX) { - ul = 0; - } - - *snapid = ul; - return true; -} - -static bool sd_parse_snapid_or_tag(const char *str, - uint32_t *snapid, char tag[]) -{ - if (!sd_parse_snapid(str, snapid)) { - *snapid = 0; - if (g_strlcpy(tag, str, SD_MAX_VDI_TAG_LEN) >= SD_MAX_VDI_TAG_LEN) { - return false; - } - } else if (!*snapid) { - return false; - } else { - tag[0] = 0; - } - return true; -} - -typedef struct { - const char *path; /* non-null iff transport is tcp */ - const char *host; /* valid when transport is tcp */ - int port; /* valid when transport is tcp */ - char vdi[SD_MAX_VDI_LEN]; - char tag[SD_MAX_VDI_TAG_LEN]; - uint32_t snap_id; - /* Remainder is only for sd_config_done() */ - URI *uri; - QueryParams *qp; -} SheepdogConfig; - -static void sd_config_done(SheepdogConfig *cfg) -{ - if (cfg->qp) { - query_params_free(cfg->qp); - } - uri_free(cfg->uri); -} - -static void sd_parse_uri(SheepdogConfig *cfg, const char *filename, - Error **errp) -{ - Error *err = NULL; - QueryParams *qp = NULL; - bool is_unix; - URI *uri; - - memset(cfg, 0, sizeof(*cfg)); - - cfg->uri = uri = uri_parse(filename); - if (!uri) { - error_setg(&err, "invalid URI '%s'", filename); - goto out; - } - - /* transport */ - if (!g_strcmp0(uri->scheme, "sheepdog")) { - is_unix = false; - } else if (!g_strcmp0(uri->scheme, "sheepdog+tcp")) { - is_unix = false; - } else if (!g_strcmp0(uri->scheme, "sheepdog+unix")) { - is_unix = true; - } else { - error_setg(&err, "URI scheme must be 'sheepdog', 'sheepdog+tcp'," - " or 'sheepdog+unix'"); - goto out; - } - - if (uri->path == NULL || !strcmp(uri->path, "/")) { - error_setg(&err, "missing file path in URI"); - goto out; - } - if (g_strlcpy(cfg->vdi, uri->path + 1, SD_MAX_VDI_LEN) - >= SD_MAX_VDI_LEN) { - error_setg(&err, "VDI name is too long"); - goto out; - } - - cfg->qp = qp = query_params_parse(uri->query); - - if (is_unix) { - /* sheepdog+unix:///vdiname?socket=path */ - if (uri->server || uri->port) { - error_setg(&err, "URI scheme %s doesn't accept a server address", - uri->scheme); - goto out; - } - if (!qp->n) { - error_setg(&err, - "URI scheme %s requires query parameter 'socket'", - uri->scheme); - goto out; - } - if (qp->n != 1 || strcmp(qp->p[0].name, "socket")) { - error_setg(&err, "unexpected query parameters"); - goto out; - } - cfg->path = qp->p[0].value; - } else { - /* sheepdog[+tcp]://[host:port]/vdiname */ - if (qp->n) { - error_setg(&err, "unexpected query parameters"); - goto out; - } - cfg->host = uri->server; - cfg->port = uri->port; - } - - /* snapshot tag */ - if (uri->fragment) { - if (!sd_parse_snapid_or_tag(uri->fragment, - &cfg->snap_id, cfg->tag)) { - error_setg(&err, "'%s' is not a valid snapshot ID", - uri->fragment); - goto out; - } - } else { - cfg->snap_id = CURRENT_VDI_ID; /* search current vdi */ - } - -out: - if (err) { - error_propagate(errp, err); - sd_config_done(cfg); - } -} - -/* - * Parse a filename (old syntax) - * - * filename must be one of the following formats: - * 1. [vdiname] - * 2. [vdiname]:[snapid] - * 3. [vdiname]:[tag] - * 4. [hostname]:[port]:[vdiname] - * 5. [hostname]:[port]:[vdiname]:[snapid] - * 6. [hostname]:[port]:[vdiname]:[tag] - * - * You can boot from the snapshot images by specifying `snapid` or - * `tag'. - * - * You can run VMs outside the Sheepdog cluster by specifying - * `hostname' and `port' (experimental). - */ -static void parse_vdiname(SheepdogConfig *cfg, const char *filename, - Error **errp) -{ - Error *err = NULL; - char *p, *q, *uri; - const char *host_spec, *vdi_spec; - int nr_sep; - - strstart(filename, "sheepdog:", &filename); - p = q = g_strdup(filename); - - /* count the number of separators */ - nr_sep = 0; - while (*p) { - if (*p == ':') { - nr_sep++; - } - p++; - } - p = q; - - /* use the first two tokens as host_spec. */ - if (nr_sep >= 2) { - host_spec = p; - p = strchr(p, ':'); - p++; - p = strchr(p, ':'); - *p++ = '\0'; - } else { - host_spec = ""; - } - - vdi_spec = p; - - p = strchr(vdi_spec, ':'); - if (p) { - *p++ = '#'; - } - - uri = g_strdup_printf("sheepdog://%s/%s", host_spec, vdi_spec); - - /* - * FIXME We to escape URI meta-characters, e.g. "x?y=z" - * produces "sheepdog://x?y=z". Because of that ... - */ - sd_parse_uri(cfg, uri, &err); - if (err) { - /* - * ... this can fail, but the error message is misleading. - * Replace it by the traditional useless one until the - * escaping is fixed. - */ - error_free(err); - error_setg(errp, "Can't parse filename"); - } - - g_free(q); - g_free(uri); -} - -static void sd_parse_filename(const char *filename, QDict *options, - Error **errp) -{ - Error *err = NULL; - SheepdogConfig cfg; - char buf[32]; - - if (strstr(filename, "://")) { - sd_parse_uri(&cfg, filename, &err); - } else { - parse_vdiname(&cfg, filename, &err); - } - if (err) { - error_propagate(errp, err); - return; - } - - if (cfg.path) { - qdict_set_default_str(options, "server.path", cfg.path); - qdict_set_default_str(options, "server.type", "unix"); - } else { - qdict_set_default_str(options, "server.type", "inet"); - qdict_set_default_str(options, "server.host", - cfg.host ?: SD_DEFAULT_ADDR); - snprintf(buf, sizeof(buf), "%d", cfg.port ?: SD_DEFAULT_PORT); - qdict_set_default_str(options, "server.port", buf); - } - qdict_set_default_str(options, "vdi", cfg.vdi); - qdict_set_default_str(options, "tag", cfg.tag); - if (cfg.snap_id) { - snprintf(buf, sizeof(buf), "%d", cfg.snap_id); - qdict_set_default_str(options, "snap-id", buf); - } - - sd_config_done(&cfg); -} - -static int find_vdi_name(BDRVSheepdogState *s, const char *filename, - uint32_t snapid, const char *tag, uint32_t *vid, - bool lock, Error **errp) -{ - int ret, fd; - SheepdogVdiReq hdr; - SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; - unsigned int wlen, rlen = 0; - char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN] QEMU_NONSTRING; - - fd = connect_to_sdog(s, errp); - if (fd < 0) { - return fd; - } - - /* This pair of strncpy calls ensures that the buffer is zero-filled, - * which is desirable since we'll soon be sending those bytes, and - * don't want the send_req to read uninitialized data. - */ - strncpy(buf, filename, SD_MAX_VDI_LEN); - strncpy(buf + SD_MAX_VDI_LEN, tag, SD_MAX_VDI_TAG_LEN); - - memset(&hdr, 0, sizeof(hdr)); - if (lock) { - hdr.opcode = SD_OP_LOCK_VDI; - hdr.type = LOCK_TYPE_NORMAL; - } else { - hdr.opcode = SD_OP_GET_VDI_INFO; - } - wlen = SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN; - hdr.proto_ver = SD_PROTO_VER; - hdr.data_length = wlen; - hdr.snapid = snapid; - hdr.flags = SD_FLAG_CMD_WRITE; - - ret = do_req(fd, s->bs, (SheepdogReq *)&hdr, buf, &wlen, &rlen); - if (ret) { - error_setg_errno(errp, -ret, "cannot get vdi info"); - goto out; - } - - if (rsp->result != SD_RES_SUCCESS) { - error_setg(errp, "cannot get vdi info, %s, %s %" PRIu32 " %s", - sd_strerror(rsp->result), filename, snapid, tag); - if (rsp->result == SD_RES_NO_VDI) { - ret = -ENOENT; - } else if (rsp->result == SD_RES_VDI_LOCKED) { - ret = -EBUSY; - } else { - ret = -EIO; - } - goto out; - } - *vid = rsp->vdi_id; - - ret = 0; -out: - closesocket(fd); - return ret; -} - -static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, - struct iovec *iov, int niov, - enum AIOCBState aiocb_type) -{ - int nr_copies = s->inode.nr_copies; - SheepdogObjReq hdr; - unsigned int wlen = 0; - int ret; - uint64_t oid = aio_req->oid; - unsigned int datalen = aio_req->data_len; - uint64_t offset = aio_req->offset; - uint8_t flags = aio_req->flags; - uint64_t old_oid = aio_req->base_oid; - bool create = aio_req->create; - - qemu_co_mutex_lock(&s->queue_lock); - QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings); - qemu_co_mutex_unlock(&s->queue_lock); - - if (!nr_copies) { - error_report("bug"); - } - - memset(&hdr, 0, sizeof(hdr)); - - switch (aiocb_type) { - case AIOCB_FLUSH_CACHE: - hdr.opcode = SD_OP_FLUSH_VDI; - break; - case AIOCB_READ_UDATA: - hdr.opcode = SD_OP_READ_OBJ; - hdr.flags = flags; - break; - case AIOCB_WRITE_UDATA: - if (create) { - hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ; - } else { - hdr.opcode = SD_OP_WRITE_OBJ; - } - wlen = datalen; - hdr.flags = SD_FLAG_CMD_WRITE | flags; - break; - case AIOCB_DISCARD_OBJ: - hdr.opcode = SD_OP_WRITE_OBJ; - hdr.flags = SD_FLAG_CMD_WRITE | flags; - s->inode.data_vdi_id[data_oid_to_idx(oid)] = 0; - offset = offsetof(SheepdogInode, - data_vdi_id[data_oid_to_idx(oid)]); - oid = vid_to_vdi_oid(s->inode.vdi_id); - wlen = datalen = sizeof(uint32_t); - break; - } - - if (s->cache_flags) { - hdr.flags |= s->cache_flags; - } - - hdr.oid = oid; - hdr.cow_oid = old_oid; - hdr.copies = s->inode.nr_copies; - - hdr.data_length = datalen; - hdr.offset = offset; - - hdr.id = aio_req->id; - - qemu_co_mutex_lock(&s->lock); - s->co_send = qemu_coroutine_self(); - aio_set_fd_handler(s->aio_context, s->fd, false, - co_read_response, co_write_request, NULL, s); - socket_set_cork(s->fd, 1); - - /* send a header */ - ret = qemu_co_send(s->fd, &hdr, sizeof(hdr)); - if (ret != sizeof(hdr)) { - error_report("failed to send a req, %s", strerror(errno)); - goto out; - } - - if (wlen) { - ret = qemu_co_sendv(s->fd, iov, niov, aio_req->iov_offset, wlen); - if (ret != wlen) { - error_report("failed to send a data, %s", strerror(errno)); - } - } -out: - socket_set_cork(s->fd, 0); - aio_set_fd_handler(s->aio_context, s->fd, false, - co_read_response, NULL, NULL, s); - s->co_send = NULL; - qemu_co_mutex_unlock(&s->lock); -} - -static int read_write_object(int fd, BlockDriverState *bs, char *buf, - uint64_t oid, uint8_t copies, - unsigned int datalen, uint64_t offset, - bool write, bool create, uint32_t cache_flags) -{ - SheepdogObjReq hdr; - SheepdogObjRsp *rsp = (SheepdogObjRsp *)&hdr; - unsigned int wlen, rlen; - int ret; - - memset(&hdr, 0, sizeof(hdr)); - - if (write) { - wlen = datalen; - rlen = 0; - hdr.flags = SD_FLAG_CMD_WRITE; - if (create) { - hdr.opcode = SD_OP_CREATE_AND_WRITE_OBJ; - } else { - hdr.opcode = SD_OP_WRITE_OBJ; - } - } else { - wlen = 0; - rlen = datalen; - hdr.opcode = SD_OP_READ_OBJ; - } - - hdr.flags |= cache_flags; - - hdr.oid = oid; - hdr.data_length = datalen; - hdr.offset = offset; - hdr.copies = copies; - - ret = do_req(fd, bs, (SheepdogReq *)&hdr, buf, &wlen, &rlen); - if (ret) { - error_report("failed to send a request to the sheep"); - return ret; - } - - switch (rsp->result) { - case SD_RES_SUCCESS: - return 0; - default: - error_report("%s", sd_strerror(rsp->result)); - return -EIO; - } -} - -static int read_object(int fd, BlockDriverState *bs, char *buf, - uint64_t oid, uint8_t copies, - unsigned int datalen, uint64_t offset, - uint32_t cache_flags) -{ - return read_write_object(fd, bs, buf, oid, copies, - datalen, offset, false, - false, cache_flags); -} - -static int write_object(int fd, BlockDriverState *bs, char *buf, - uint64_t oid, uint8_t copies, - unsigned int datalen, uint64_t offset, bool create, - uint32_t cache_flags) -{ - return read_write_object(fd, bs, buf, oid, copies, - datalen, offset, true, - create, cache_flags); -} - -/* update inode with the latest state */ -static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag) -{ - Error *local_err = NULL; - SheepdogInode *inode; - int ret = 0, fd; - uint32_t vid = 0; - - fd = connect_to_sdog(s, &local_err); - if (fd < 0) { - error_report_err(local_err); - return -EIO; - } - - inode = g_malloc(SD_INODE_HEADER_SIZE); - - ret = find_vdi_name(s, s->name, snapid, tag, &vid, false, &local_err); - if (ret) { - error_report_err(local_err); - goto out; - } - - ret = read_object(fd, s->bs, (char *)inode, vid_to_vdi_oid(vid), - s->inode.nr_copies, SD_INODE_HEADER_SIZE, 0, - s->cache_flags); - if (ret < 0) { - goto out; - } - - if (inode->vdi_id != s->inode.vdi_id) { - memcpy(&s->inode, inode, SD_INODE_HEADER_SIZE); - } - -out: - g_free(inode); - closesocket(fd); - - return ret; -} - -static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req) -{ - SheepdogAIOCB *acb = aio_req->aiocb; - - aio_req->create = false; - - /* check whether this request becomes a CoW one */ - if (acb->aiocb_type == AIOCB_WRITE_UDATA && is_data_obj(aio_req->oid)) { - int idx = data_oid_to_idx(aio_req->oid); - - if (is_data_obj_writable(&s->inode, idx)) { - goto out; - } - - if (s->inode.data_vdi_id[idx]) { - aio_req->base_oid = vid_to_data_oid(s->inode.data_vdi_id[idx], idx); - aio_req->flags |= SD_FLAG_CMD_COW; - } - aio_req->create = true; - } -out: - if (is_data_obj(aio_req->oid)) { - add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, - acb->aiocb_type); - } else { - struct iovec iov; - iov.iov_base = &s->inode; - iov.iov_len = sizeof(s->inode); - add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA); - } -} - -static void sd_detach_aio_context(BlockDriverState *bs) -{ - BDRVSheepdogState *s = bs->opaque; - - aio_set_fd_handler(s->aio_context, s->fd, false, NULL, - NULL, NULL, NULL); -} - -static void sd_attach_aio_context(BlockDriverState *bs, - AioContext *new_context) -{ - BDRVSheepdogState *s = bs->opaque; - - s->aio_context = new_context; - aio_set_fd_handler(new_context, s->fd, false, - co_read_response, NULL, NULL, s); -} - -static QemuOptsList runtime_opts = { - .name = "sheepdog", - .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head), - .desc = { - { - .name = "vdi", - .type = QEMU_OPT_STRING, - }, - { - .name = "snap-id", - .type = QEMU_OPT_NUMBER, - }, - { - .name = "tag", - .type = QEMU_OPT_STRING, - }, - { /* end of list */ } - }, -}; - -static int sd_open(BlockDriverState *bs, QDict *options, int flags, - Error **errp) -{ - int ret, fd; - uint32_t vid = 0; - BDRVSheepdogState *s = bs->opaque; - const char *vdi, *snap_id_str, *tag; - uint64_t snap_id; - char *buf = NULL; - QemuOpts *opts; - - deprecation_warning(); - - s->bs = bs; - s->aio_context = bdrv_get_aio_context(bs); - - opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); - if (!qemu_opts_absorb_qdict(opts, options, errp)) { - ret = -EINVAL; - goto err_no_fd; - } - - s->addr = sd_server_config(options, errp); - if (!s->addr) { - ret = -EINVAL; - goto err_no_fd; - } - - vdi = qemu_opt_get(opts, "vdi"); - snap_id_str = qemu_opt_get(opts, "snap-id"); - snap_id = qemu_opt_get_number(opts, "snap-id", CURRENT_VDI_ID); - tag = qemu_opt_get(opts, "tag"); - - if (!vdi) { - error_setg(errp, "parameter 'vdi' is missing"); - ret = -EINVAL; - goto err_no_fd; - } - if (strlen(vdi) >= SD_MAX_VDI_LEN) { - error_setg(errp, "value of parameter 'vdi' is too long"); - ret = -EINVAL; - goto err_no_fd; - } - - if (snap_id > UINT32_MAX) { - snap_id = 0; - } - if (snap_id_str && !snap_id) { - error_setg(errp, "'snap-id=%s' is not a valid snapshot ID", - snap_id_str); - ret = -EINVAL; - goto err_no_fd; - } - - if (!tag) { - tag = ""; - } - if (strlen(tag) >= SD_MAX_VDI_TAG_LEN) { - error_setg(errp, "value of parameter 'tag' is too long"); - ret = -EINVAL; - goto err_no_fd; - } - - QLIST_INIT(&s->inflight_aio_head); - QLIST_INIT(&s->failed_aio_head); - QLIST_INIT(&s->inflight_aiocb_head); - - s->fd = get_sheep_fd(s, errp); - if (s->fd < 0) { - ret = s->fd; - goto err_no_fd; - } - - ret = find_vdi_name(s, vdi, (uint32_t)snap_id, tag, &vid, true, errp); - if (ret) { - goto err; - } - - /* - * QEMU block layer emulates writethrough cache as 'writeback + flush', so - * we always set SD_FLAG_CMD_CACHE (writeback cache) as default. - */ - s->cache_flags = SD_FLAG_CMD_CACHE; - if (flags & BDRV_O_NOCACHE) { - s->cache_flags = SD_FLAG_CMD_DIRECT; - } - s->discard_supported = true; - - if (snap_id || tag[0]) { - trace_sheepdog_open(vid); - s->is_snapshot = true; - } - - fd = connect_to_sdog(s, errp); - if (fd < 0) { - ret = fd; - goto err; - } - - buf = g_malloc(SD_INODE_SIZE); - ret = read_object(fd, s->bs, buf, vid_to_vdi_oid(vid), - 0, SD_INODE_SIZE, 0, s->cache_flags); - - closesocket(fd); - - if (ret) { - error_setg(errp, "Can't read snapshot inode"); - goto err; - } - - memcpy(&s->inode, buf, sizeof(s->inode)); - - bs->total_sectors = s->inode.vdi_size / BDRV_SECTOR_SIZE; - bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; - pstrcpy(s->name, sizeof(s->name), vdi); - qemu_co_mutex_init(&s->lock); - qemu_co_mutex_init(&s->queue_lock); - qemu_co_queue_init(&s->overlapping_queue); - qemu_opts_del(opts); - g_free(buf); - return 0; - -err: - aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd, - false, NULL, NULL, NULL, NULL); - closesocket(s->fd); -err_no_fd: - qemu_opts_del(opts); - g_free(buf); - return ret; -} - -static int sd_reopen_prepare(BDRVReopenState *state, BlockReopenQueue *queue, - Error **errp) -{ - BDRVSheepdogState *s = state->bs->opaque; - BDRVSheepdogReopenState *re_s; - int ret = 0; - - re_s = state->opaque = g_new0(BDRVSheepdogReopenState, 1); - - re_s->cache_flags = SD_FLAG_CMD_CACHE; - if (state->flags & BDRV_O_NOCACHE) { - re_s->cache_flags = SD_FLAG_CMD_DIRECT; - } - - re_s->fd = get_sheep_fd(s, errp); - if (re_s->fd < 0) { - ret = re_s->fd; - return ret; - } - - return ret; -} - -static void sd_reopen_commit(BDRVReopenState *state) -{ - BDRVSheepdogReopenState *re_s = state->opaque; - BDRVSheepdogState *s = state->bs->opaque; - - if (s->fd) { - aio_set_fd_handler(s->aio_context, s->fd, false, - NULL, NULL, NULL, NULL); - closesocket(s->fd); - } - - s->fd = re_s->fd; - s->cache_flags = re_s->cache_flags; - - g_free(state->opaque); - state->opaque = NULL; - - return; -} - -static void sd_reopen_abort(BDRVReopenState *state) -{ - BDRVSheepdogReopenState *re_s = state->opaque; - BDRVSheepdogState *s = state->bs->opaque; - - if (re_s == NULL) { - return; - } - - if (re_s->fd) { - aio_set_fd_handler(s->aio_context, re_s->fd, false, - NULL, NULL, NULL, NULL); - closesocket(re_s->fd); - } - - g_free(state->opaque); - state->opaque = NULL; - - return; -} - -static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot, - Error **errp) -{ - SheepdogVdiReq hdr; - SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; - int fd, ret; - unsigned int wlen, rlen = 0; - char buf[SD_MAX_VDI_LEN]; - - fd = connect_to_sdog(s, errp); - if (fd < 0) { - return fd; - } - - /* FIXME: would it be better to fail (e.g., return -EIO) when filename - * does not fit in buf? For now, just truncate and avoid buffer overrun. - */ - memset(buf, 0, sizeof(buf)); - pstrcpy(buf, sizeof(buf), s->name); - - memset(&hdr, 0, sizeof(hdr)); - hdr.opcode = SD_OP_NEW_VDI; - hdr.base_vdi_id = s->inode.vdi_id; - - wlen = SD_MAX_VDI_LEN; - - hdr.flags = SD_FLAG_CMD_WRITE; - hdr.snapid = snapshot; - - hdr.data_length = wlen; - hdr.vdi_size = s->inode.vdi_size; - hdr.copy_policy = s->inode.copy_policy; - hdr.copies = s->inode.nr_copies; - hdr.block_size_shift = s->inode.block_size_shift; - - ret = do_req(fd, NULL, (SheepdogReq *)&hdr, buf, &wlen, &rlen); - - closesocket(fd); - - if (ret) { - error_setg_errno(errp, -ret, "create failed"); - return ret; - } - - if (rsp->result != SD_RES_SUCCESS) { - error_setg(errp, "%s, %s", sd_strerror(rsp->result), s->inode.name); - return -EIO; - } - - if (vdi_id) { - *vdi_id = rsp->vdi_id; - } - - return 0; -} - -static int sd_prealloc(BlockDriverState *bs, int64_t old_size, int64_t new_size, - Error **errp) -{ - BlockBackend *blk = NULL; - BDRVSheepdogState *base = bs->opaque; - unsigned long buf_size; - uint32_t idx, max_idx; - uint32_t object_size; - void *buf = NULL; - int ret; - - blk = blk_new_with_bs(bs, - BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE, - BLK_PERM_ALL, errp); - - if (!blk) { - ret = -EPERM; - goto out_with_err_set; - } - - blk_set_allow_write_beyond_eof(blk, true); - - object_size = (UINT32_C(1) << base->inode.block_size_shift); - buf_size = MIN(object_size, SD_DATA_OBJ_SIZE); - buf = g_malloc0(buf_size); - - max_idx = DIV_ROUND_UP(new_size, buf_size); - - for (idx = old_size / buf_size; idx < max_idx; idx++) { - /* - * The created image can be a cloned image, so we need to read - * a data from the source image. - */ - ret = blk_pread(blk, idx * buf_size, buf, buf_size); - if (ret < 0) { - goto out; - } - ret = blk_pwrite(blk, idx * buf_size, buf, buf_size, 0); - if (ret < 0) { - goto out; - } - } - - ret = 0; -out: - if (ret < 0) { - error_setg_errno(errp, -ret, "Can't pre-allocate"); - } -out_with_err_set: - blk_unref(blk); - g_free(buf); - - return ret; -} - -static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size, - Error **errp) -{ - BlockDriverState *bs; - Visitor *v; - QObject *obj = NULL; - QDict *qdict; - int ret; - - v = qobject_output_visitor_new(&obj); - visit_type_BlockdevOptionsSheepdog(v, NULL, &location, &error_abort); - visit_free(v); - - qdict = qobject_to(QDict, obj); - qdict_flatten(qdict); - - qdict_put_str(qdict, "driver", "sheepdog"); - - bs = bdrv_open(NULL, NULL, qdict, BDRV_O_PROTOCOL | BDRV_O_RDWR, errp); - if (bs == NULL) { - ret = -EIO; - goto fail; - } - - ret = sd_prealloc(bs, 0, size, errp); -fail: - bdrv_unref(bs); - qobject_unref(qdict); - return ret; -} - -static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt) -{ - struct SheepdogInode *inode = &s->inode; - - switch (opt->type) { - case SHEEPDOG_REDUNDANCY_TYPE_FULL: - if (opt->u.full.copies > SD_MAX_COPIES || opt->u.full.copies < 1) { - return -EINVAL; - } - inode->copy_policy = 0; - inode->nr_copies = opt->u.full.copies; - return 0; - - case SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED: - { - int64_t copy = opt->u.erasure_coded.data_strips; - int64_t parity = opt->u.erasure_coded.parity_strips; - - if (copy != 2 && copy != 4 && copy != 8 && copy != 16) { - return -EINVAL; - } - - if (parity >= SD_EC_MAX_STRIP || parity < 1) { - return -EINVAL; - } - - /* - * 4 bits for parity and 4 bits for data. - * We have to compress upper data bits because it can't represent 16 - */ - inode->copy_policy = ((copy / 2) << 4) + parity; - inode->nr_copies = copy + parity; - return 0; - } - - default: - g_assert_not_reached(); - } - - return -EINVAL; -} - -/* - * Sheepdog support two kinds of redundancy, full replication and erasure - * coding. - * - * # create a fully replicated vdi with x copies - * -o redundancy=x (1 <= x <= SD_MAX_COPIES) - * - * # create a erasure coded vdi with x data strips and y parity strips - * -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP) - */ -static SheepdogRedundancy *parse_redundancy_str(const char *opt) -{ - SheepdogRedundancy *redundancy; - const char *n1, *n2; - long copy, parity; - char p[10]; - int ret; - - pstrcpy(p, sizeof(p), opt); - n1 = strtok(p, ":"); - n2 = strtok(NULL, ":"); - - if (!n1) { - return NULL; - } - - ret = qemu_strtol(n1, NULL, 10, ©); - if (ret < 0) { - return NULL; - } - - redundancy = g_new0(SheepdogRedundancy, 1); - if (!n2) { - *redundancy = (SheepdogRedundancy) { - .type = SHEEPDOG_REDUNDANCY_TYPE_FULL, - .u.full.copies = copy, - }; - } else { - ret = qemu_strtol(n2, NULL, 10, &parity); - if (ret < 0) { - g_free(redundancy); - return NULL; - } - - *redundancy = (SheepdogRedundancy) { - .type = SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED, - .u.erasure_coded = { - .data_strips = copy, - .parity_strips = parity, - }, - }; - } - - return redundancy; -} - -static int parse_block_size_shift(BDRVSheepdogState *s, - BlockdevCreateOptionsSheepdog *opts) -{ - struct SheepdogInode *inode = &s->inode; - uint64_t object_size; - int obj_order; - - if (opts->has_object_size) { - object_size = opts->object_size; - - if ((object_size - 1) & object_size) { /* not a power of 2? */ - return -EINVAL; - } - obj_order = ctz32(object_size); - if (obj_order < 20 || obj_order > 31) { - return -EINVAL; - } - inode->block_size_shift = (uint8_t)obj_order; - } - - return 0; -} - -static int sd_co_create(BlockdevCreateOptions *options, Error **errp) -{ - BlockdevCreateOptionsSheepdog *opts = &options->u.sheepdog; - int ret = 0; - uint32_t vid = 0; - char *backing_file = NULL; - char *buf = NULL; - BDRVSheepdogState *s; - uint64_t max_vdi_size; - bool prealloc = false; - - assert(options->driver == BLOCKDEV_DRIVER_SHEEPDOG); - - deprecation_warning(); - - s = g_new0(BDRVSheepdogState, 1); - - /* Steal SocketAddress from QAPI, set NULL to prevent double free */ - s->addr = opts->location->server; - opts->location->server = NULL; - - if (strlen(opts->location->vdi) >= sizeof(s->name)) { - error_setg(errp, "'vdi' string too long"); - ret = -EINVAL; - goto out; - } - pstrcpy(s->name, sizeof(s->name), opts->location->vdi); - - s->inode.vdi_size = opts->size; - backing_file = opts->backing_file; - - if (!opts->has_preallocation) { - opts->preallocation = PREALLOC_MODE_OFF; - } - switch (opts->preallocation) { - case PREALLOC_MODE_OFF: - prealloc = false; - break; - case PREALLOC_MODE_FULL: - prealloc = true; - break; - default: - error_setg(errp, "Preallocation mode not supported for Sheepdog"); - ret = -EINVAL; - goto out; - } - - if (opts->has_redundancy) { - ret = parse_redundancy(s, opts->redundancy); - if (ret < 0) { - error_setg(errp, "Invalid redundancy mode"); - goto out; - } - } - ret = parse_block_size_shift(s, opts); - if (ret < 0) { - error_setg(errp, "Invalid object_size." - " obect_size needs to be power of 2" - " and be limited from 2^20 to 2^31"); - goto out; - } - - if (opts->has_backing_file) { - BlockBackend *blk; - BDRVSheepdogState *base; - BlockDriver *drv; - - /* Currently, only Sheepdog backing image is supported. */ - drv = bdrv_find_protocol(opts->backing_file, true, NULL); - if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) { - error_setg(errp, "backing_file must be a sheepdog image"); - ret = -EINVAL; - goto out; - } - - blk = blk_new_open(opts->backing_file, NULL, NULL, - BDRV_O_PROTOCOL, errp); - if (blk == NULL) { - ret = -EIO; - goto out; - } - - base = blk_bs(blk)->opaque; - - if (!is_snapshot(&base->inode)) { - error_setg(errp, "cannot clone from a non snapshot vdi"); - blk_unref(blk); - ret = -EINVAL; - goto out; - } - s->inode.vdi_id = base->inode.vdi_id; - blk_unref(blk); - } - - s->aio_context = qemu_get_aio_context(); - - /* if block_size_shift is not specified, get cluster default value */ - if (s->inode.block_size_shift == 0) { - SheepdogVdiReq hdr; - SheepdogClusterRsp *rsp = (SheepdogClusterRsp *)&hdr; - int fd; - unsigned int wlen = 0, rlen = 0; - - fd = connect_to_sdog(s, errp); - if (fd < 0) { - ret = fd; - goto out; - } - - memset(&hdr, 0, sizeof(hdr)); - hdr.opcode = SD_OP_GET_CLUSTER_DEFAULT; - hdr.proto_ver = SD_PROTO_VER; - - ret = do_req(fd, NULL, (SheepdogReq *)&hdr, - NULL, &wlen, &rlen); - closesocket(fd); - if (ret) { - error_setg_errno(errp, -ret, "failed to get cluster default"); - goto out; - } - if (rsp->result == SD_RES_SUCCESS) { - s->inode.block_size_shift = rsp->block_size_shift; - } else { - s->inode.block_size_shift = SD_DEFAULT_BLOCK_SIZE_SHIFT; - } - } - - max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS; - - if (s->inode.vdi_size > max_vdi_size) { - error_setg(errp, "An image is too large." - " The maximum image size is %"PRIu64 "GB", - max_vdi_size / 1024 / 1024 / 1024); - ret = -EINVAL; - goto out; - } - - ret = do_sd_create(s, &vid, 0, errp); - if (ret) { - goto out; - } - - if (prealloc) { - ret = sd_create_prealloc(opts->location, opts->size, errp); - } -out: - g_free(backing_file); - g_free(buf); - g_free(s->addr); - g_free(s); - return ret; -} - -static int coroutine_fn sd_co_create_opts(BlockDriver *drv, - const char *filename, - QemuOpts *opts, - Error **errp) -{ - BlockdevCreateOptions *create_options = NULL; - QDict *qdict = NULL, *location_qdict; - Visitor *v; - char *redundancy = NULL; - Error *local_err = NULL; - int ret; - char *backing_fmt = NULL; - - redundancy = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY); - backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT); - - if (backing_fmt && strcmp(backing_fmt, "sheepdog") != 0) { - error_setg(errp, "backing_file must be a sheepdog image"); - ret = -EINVAL; - goto fail; - } - - qdict = qemu_opts_to_qdict(opts, NULL); - qdict_put_str(qdict, "driver", "sheepdog"); - - location_qdict = qdict_new(); - qdict_put(qdict, "location", location_qdict); - - sd_parse_filename(filename, location_qdict, &local_err); - if (local_err) { - error_propagate(errp, local_err); - ret = -EINVAL; - goto fail; - } - - qdict_flatten(qdict); - - /* Change legacy command line options into QMP ones */ - static const QDictRenames opt_renames[] = { - { BLOCK_OPT_BACKING_FILE, "backing-file" }, - { BLOCK_OPT_OBJECT_SIZE, "object-size" }, - { NULL, NULL }, - }; - - if (!qdict_rename_keys(qdict, opt_renames, errp)) { - ret = -EINVAL; - goto fail; - } - - /* Get the QAPI object */ - v = qobject_input_visitor_new_flat_confused(qdict, errp); - if (!v) { - ret = -EINVAL; - goto fail; - } - - visit_type_BlockdevCreateOptions(v, NULL, &create_options, errp); - visit_free(v); - if (!create_options) { - ret = -EINVAL; - goto fail; - } - - assert(create_options->driver == BLOCKDEV_DRIVER_SHEEPDOG); - create_options->u.sheepdog.size = - ROUND_UP(create_options->u.sheepdog.size, BDRV_SECTOR_SIZE); - - if (redundancy) { - create_options->u.sheepdog.has_redundancy = true; - create_options->u.sheepdog.redundancy = - parse_redundancy_str(redundancy); - if (create_options->u.sheepdog.redundancy == NULL) { - error_setg(errp, "Invalid redundancy mode"); - ret = -EINVAL; - goto fail; - } - } - - ret = sd_co_create(create_options, errp); -fail: - qapi_free_BlockdevCreateOptions(create_options); - qobject_unref(qdict); - g_free(redundancy); - g_free(backing_fmt); - return ret; -} - -static void sd_close(BlockDriverState *bs) -{ - Error *local_err = NULL; - BDRVSheepdogState *s = bs->opaque; - SheepdogVdiReq hdr; - SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; - unsigned int wlen, rlen = 0; - int fd, ret; - - trace_sheepdog_close(s->name); - - fd = connect_to_sdog(s, &local_err); - if (fd < 0) { - error_report_err(local_err); - return; - } - - memset(&hdr, 0, sizeof(hdr)); - - hdr.opcode = SD_OP_RELEASE_VDI; - hdr.type = LOCK_TYPE_NORMAL; - hdr.base_vdi_id = s->inode.vdi_id; - wlen = strlen(s->name) + 1; - hdr.data_length = wlen; - hdr.flags = SD_FLAG_CMD_WRITE; - - ret = do_req(fd, s->bs, (SheepdogReq *)&hdr, - s->name, &wlen, &rlen); - - closesocket(fd); - - if (!ret && rsp->result != SD_RES_SUCCESS && - rsp->result != SD_RES_VDI_NOT_LOCKED) { - error_report("%s, %s", sd_strerror(rsp->result), s->name); - } - - aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd, - false, NULL, NULL, NULL, NULL); - closesocket(s->fd); - qapi_free_SocketAddress(s->addr); -} - -static int64_t sd_getlength(BlockDriverState *bs) -{ - BDRVSheepdogState *s = bs->opaque; - - return s->inode.vdi_size; -} - -static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset, - bool exact, PreallocMode prealloc, - BdrvRequestFlags flags, Error **errp) -{ - BDRVSheepdogState *s = bs->opaque; - int ret, fd; - unsigned int datalen; - uint64_t max_vdi_size; - int64_t old_size = s->inode.vdi_size; - - if (prealloc != PREALLOC_MODE_OFF && prealloc != PREALLOC_MODE_FULL) { - error_setg(errp, "Unsupported preallocation mode '%s'", - PreallocMode_str(prealloc)); - return -ENOTSUP; - } - - max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS; - if (offset < old_size) { - error_setg(errp, "shrinking is not supported"); - return -EINVAL; - } else if (offset > max_vdi_size) { - error_setg(errp, "too big image size"); - return -EINVAL; - } - - fd = connect_to_sdog(s, errp); - if (fd < 0) { - return fd; - } - - /* we don't need to update entire object */ - datalen = SD_INODE_HEADER_SIZE; - s->inode.vdi_size = offset; - ret = write_object(fd, s->bs, (char *)&s->inode, - vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies, - datalen, 0, false, s->cache_flags); - close(fd); - - if (ret < 0) { - error_setg_errno(errp, -ret, "failed to update an inode"); - return ret; - } - - if (prealloc == PREALLOC_MODE_FULL) { - ret = sd_prealloc(bs, old_size, offset, errp); - if (ret < 0) { - return ret; - } - } - - return 0; -} - -/* - * This function is called after writing data objects. If we need to - * update metadata, this sends a write request to the vdi object. - */ -static void coroutine_fn sd_write_done(SheepdogAIOCB *acb) -{ - BDRVSheepdogState *s = acb->s; - struct iovec iov; - AIOReq *aio_req; - uint32_t offset, data_len, mn, mx; - - mn = acb->min_dirty_data_idx; - mx = acb->max_dirty_data_idx; - if (mn <= mx) { - /* we need to update the vdi object. */ - ++acb->nr_pending; - offset = sizeof(s->inode) - sizeof(s->inode.data_vdi_id) + - mn * sizeof(s->inode.data_vdi_id[0]); - data_len = (mx - mn + 1) * sizeof(s->inode.data_vdi_id[0]); - - acb->min_dirty_data_idx = UINT32_MAX; - acb->max_dirty_data_idx = 0; - - iov.iov_base = &s->inode; - iov.iov_len = sizeof(s->inode); - aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id), - data_len, offset, 0, false, 0, offset); - add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA); - if (--acb->nr_pending) { - qemu_coroutine_yield(); - } - } -} - -/* Delete current working VDI on the snapshot chain */ -static bool sd_delete(BDRVSheepdogState *s) -{ - Error *local_err = NULL; - unsigned int wlen = SD_MAX_VDI_LEN, rlen = 0; - SheepdogVdiReq hdr = { - .opcode = SD_OP_DEL_VDI, - .base_vdi_id = s->inode.vdi_id, - .data_length = wlen, - .flags = SD_FLAG_CMD_WRITE, - }; - SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; - int fd, ret; - - fd = connect_to_sdog(s, &local_err); - if (fd < 0) { - error_report_err(local_err); - return false; - } - - ret = do_req(fd, s->bs, (SheepdogReq *)&hdr, - s->name, &wlen, &rlen); - closesocket(fd); - if (ret) { - return false; - } - switch (rsp->result) { - case SD_RES_NO_VDI: - error_report("%s was already deleted", s->name); - /* fall through */ - case SD_RES_SUCCESS: - break; - default: - error_report("%s, %s", sd_strerror(rsp->result), s->name); - return false; - } - - return true; -} - -/* - * Create a writable VDI from a snapshot - */ -static int sd_create_branch(BDRVSheepdogState *s) -{ - Error *local_err = NULL; - int ret, fd; - uint32_t vid; - char *buf; - bool deleted; - - trace_sheepdog_create_branch_snapshot(s->inode.vdi_id); - - buf = g_malloc(SD_INODE_SIZE); - - /* - * Even If deletion fails, we will just create extra snapshot based on - * the working VDI which was supposed to be deleted. So no need to - * false bail out. - */ - deleted = sd_delete(s); - ret = do_sd_create(s, &vid, !deleted, &local_err); - if (ret) { - error_report_err(local_err); - goto out; - } - - trace_sheepdog_create_branch_created(vid); - - fd = connect_to_sdog(s, &local_err); - if (fd < 0) { - error_report_err(local_err); - ret = fd; - goto out; - } - - ret = read_object(fd, s->bs, buf, vid_to_vdi_oid(vid), - s->inode.nr_copies, SD_INODE_SIZE, 0, s->cache_flags); - - closesocket(fd); - - if (ret < 0) { - goto out; - } - - memcpy(&s->inode, buf, sizeof(s->inode)); - - s->is_snapshot = false; - ret = 0; - trace_sheepdog_create_branch_new(s->inode.vdi_id); - -out: - g_free(buf); - - return ret; -} - -/* - * Send I/O requests to the server. - * - * This function sends requests to the server, links the requests to - * the inflight_list in BDRVSheepdogState, and exits without - * waiting the response. The responses are received in the - * `aio_read_response' function which is called from the main loop as - * a fd handler. - * - * Returns 1 when we need to wait a response, 0 when there is no sent - * request and -errno in error cases. - */ -static void coroutine_fn sd_co_rw_vector(SheepdogAIOCB *acb) -{ - int ret = 0; - unsigned long len, done = 0, total = acb->nb_sectors * BDRV_SECTOR_SIZE; - unsigned long idx; - uint32_t object_size; - uint64_t oid; - uint64_t offset; - BDRVSheepdogState *s = acb->s; - SheepdogInode *inode = &s->inode; - AIOReq *aio_req; - - if (acb->aiocb_type == AIOCB_WRITE_UDATA && s->is_snapshot) { - /* - * In the case we open the snapshot VDI, Sheepdog creates the - * writable VDI when we do a write operation first. - */ - ret = sd_create_branch(s); - if (ret) { - acb->ret = -EIO; - return; - } - } - - object_size = (UINT32_C(1) << inode->block_size_shift); - idx = acb->sector_num * BDRV_SECTOR_SIZE / object_size; - offset = (acb->sector_num * BDRV_SECTOR_SIZE) % object_size; - - /* - * Make sure we don't free the aiocb before we are done with all requests. - * This additional reference is dropped at the end of this function. - */ - acb->nr_pending++; - - while (done != total) { - uint8_t flags = 0; - uint64_t old_oid = 0; - bool create = false; - - oid = vid_to_data_oid(inode->data_vdi_id[idx], idx); - - len = MIN(total - done, object_size - offset); - - switch (acb->aiocb_type) { - case AIOCB_READ_UDATA: - if (!inode->data_vdi_id[idx]) { - qemu_iovec_memset(acb->qiov, done, 0, len); - goto done; - } - break; - case AIOCB_WRITE_UDATA: - if (!inode->data_vdi_id[idx]) { - create = true; - } else if (!is_data_obj_writable(inode, idx)) { - /* Copy-On-Write */ - create = true; - old_oid = oid; - flags = SD_FLAG_CMD_COW; - } - break; - case AIOCB_DISCARD_OBJ: - /* - * We discard the object only when the whole object is - * 1) allocated 2) trimmed. Otherwise, simply skip it. - */ - if (len != object_size || inode->data_vdi_id[idx] == 0) { - goto done; - } - break; - default: - break; - } - - if (create) { - trace_sheepdog_co_rw_vector_update(inode->vdi_id, oid, - vid_to_data_oid(inode->data_vdi_id[idx], idx), - idx); - oid = vid_to_data_oid(inode->vdi_id, idx); - trace_sheepdog_co_rw_vector_new(oid); - } - - aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, create, - old_oid, - acb->aiocb_type == AIOCB_DISCARD_OBJ ? - 0 : done); - add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, - acb->aiocb_type); - done: - offset = 0; - idx++; - done += len; - } - if (--acb->nr_pending) { - qemu_coroutine_yield(); - } -} - -static void sd_aio_complete(SheepdogAIOCB *acb) -{ - BDRVSheepdogState *s; - if (acb->aiocb_type == AIOCB_FLUSH_CACHE) { - return; - } - - s = acb->s; - qemu_co_mutex_lock(&s->queue_lock); - QLIST_REMOVE(acb, aiocb_siblings); - qemu_co_queue_restart_all(&s->overlapping_queue); - qemu_co_mutex_unlock(&s->queue_lock); -} - -static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, QEMUIOVector *qiov, - int flags) -{ - SheepdogAIOCB acb; - int ret; - int64_t offset = (sector_num + nb_sectors) * BDRV_SECTOR_SIZE; - BDRVSheepdogState *s = bs->opaque; - - assert(!flags); - if (offset > s->inode.vdi_size) { - ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL); - if (ret < 0) { - return ret; - } - } - - sd_aio_setup(&acb, s, qiov, sector_num, nb_sectors, AIOCB_WRITE_UDATA); - sd_co_rw_vector(&acb); - sd_write_done(&acb); - sd_aio_complete(&acb); - - return acb.ret; -} - -static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num, - int nb_sectors, QEMUIOVector *qiov) -{ - SheepdogAIOCB acb; - BDRVSheepdogState *s = bs->opaque; - - sd_aio_setup(&acb, s, qiov, sector_num, nb_sectors, AIOCB_READ_UDATA); - sd_co_rw_vector(&acb); - sd_aio_complete(&acb); - - return acb.ret; -} - -static int coroutine_fn sd_co_flush_to_disk(BlockDriverState *bs) -{ - BDRVSheepdogState *s = bs->opaque; - SheepdogAIOCB acb; - AIOReq *aio_req; - - if (s->cache_flags != SD_FLAG_CMD_CACHE) { - return 0; - } - - sd_aio_setup(&acb, s, NULL, 0, 0, AIOCB_FLUSH_CACHE); - - acb.nr_pending++; - aio_req = alloc_aio_req(s, &acb, vid_to_vdi_oid(s->inode.vdi_id), - 0, 0, 0, false, 0, 0); - add_aio_request(s, aio_req, NULL, 0, acb.aiocb_type); - - if (--acb.nr_pending) { - qemu_coroutine_yield(); - } - - sd_aio_complete(&acb); - return acb.ret; -} - -static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) -{ - Error *local_err = NULL; - BDRVSheepdogState *s = bs->opaque; - int ret, fd; - uint32_t new_vid; - SheepdogInode *inode; - unsigned int datalen; - - trace_sheepdog_snapshot_create_info(sn_info->name, sn_info->id_str, s->name, - sn_info->vm_state_size, s->is_snapshot); - - if (s->is_snapshot) { - error_report("You can't create a snapshot of a snapshot VDI, " - "%s (%" PRIu32 ").", s->name, s->inode.vdi_id); - - return -EINVAL; - } - - trace_sheepdog_snapshot_create(sn_info->name, sn_info->id_str); - - s->inode.vm_state_size = sn_info->vm_state_size; - s->inode.vm_clock_nsec = sn_info->vm_clock_nsec; - /* It appears that inode.tag does not require a NUL terminator, - * which means this use of strncpy is ok. - */ - strncpy(s->inode.tag, sn_info->name, sizeof(s->inode.tag)); - /* we don't need to update entire object */ - datalen = SD_INODE_HEADER_SIZE; - inode = g_malloc(datalen); - - /* refresh inode. */ - fd = connect_to_sdog(s, &local_err); - if (fd < 0) { - error_report_err(local_err); - ret = fd; - goto cleanup; - } - - ret = write_object(fd, s->bs, (char *)&s->inode, - vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies, - datalen, 0, false, s->cache_flags); - if (ret < 0) { - error_report("failed to write snapshot's inode."); - goto cleanup; - } - - ret = do_sd_create(s, &new_vid, 1, &local_err); - if (ret < 0) { - error_reportf_err(local_err, - "failed to create inode for snapshot: "); - goto cleanup; - } - - ret = read_object(fd, s->bs, (char *)inode, - vid_to_vdi_oid(new_vid), s->inode.nr_copies, datalen, 0, - s->cache_flags); - - if (ret < 0) { - error_report("failed to read new inode info. %s", strerror(errno)); - goto cleanup; - } - - memcpy(&s->inode, inode, datalen); - trace_sheepdog_snapshot_create_inode(s->inode.name, s->inode.snap_id, - s->inode.vdi_id); - -cleanup: - g_free(inode); - closesocket(fd); - return ret; -} - -/* - * We implement rollback(loadvm) operation to the specified snapshot by - * 1) switch to the snapshot - * 2) rely on sd_create_branch to delete working VDI and - * 3) create a new working VDI based on the specified snapshot - */ -static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) -{ - BDRVSheepdogState *s = bs->opaque; - BDRVSheepdogState *old_s; - char tag[SD_MAX_VDI_TAG_LEN]; - uint32_t snapid = 0; - int ret; - - if (!sd_parse_snapid_or_tag(snapshot_id, &snapid, tag)) { - return -EINVAL; - } - - old_s = g_new(BDRVSheepdogState, 1); - - memcpy(old_s, s, sizeof(BDRVSheepdogState)); - - ret = reload_inode(s, snapid, tag); - if (ret) { - goto out; - } - - ret = sd_create_branch(s); - if (ret) { - goto out; - } - - g_free(old_s); - - return 0; -out: - /* recover bdrv_sd_state */ - memcpy(s, old_s, sizeof(BDRVSheepdogState)); - g_free(old_s); - - error_report("failed to open. recover old bdrv_sd_state."); - - return ret; -} - -#define NR_BATCHED_DISCARD 128 - -static int remove_objects(BDRVSheepdogState *s, Error **errp) -{ - int fd, i = 0, nr_objs = 0; - int ret; - SheepdogInode *inode = &s->inode; - - fd = connect_to_sdog(s, errp); - if (fd < 0) { - return fd; - } - - nr_objs = count_data_objs(inode); - while (i < nr_objs) { - int start_idx, nr_filled_idx; - - while (i < nr_objs && !inode->data_vdi_id[i]) { - i++; - } - start_idx = i; - - nr_filled_idx = 0; - while (i < nr_objs && nr_filled_idx < NR_BATCHED_DISCARD) { - if (inode->data_vdi_id[i]) { - inode->data_vdi_id[i] = 0; - nr_filled_idx++; - } - - i++; - } - - ret = write_object(fd, s->bs, - (char *)&inode->data_vdi_id[start_idx], - vid_to_vdi_oid(s->inode.vdi_id), inode->nr_copies, - (i - start_idx) * sizeof(uint32_t), - offsetof(struct SheepdogInode, - data_vdi_id[start_idx]), - false, s->cache_flags); - if (ret < 0) { - error_setg(errp, "Failed to discard snapshot inode"); - goto out; - } - } - - ret = 0; -out: - closesocket(fd); - return ret; -} - -static int sd_snapshot_delete(BlockDriverState *bs, - const char *snapshot_id, - const char *name, - Error **errp) -{ - /* - * FIXME should delete the snapshot matching both @snapshot_id and - * @name, but @name not used here - */ - unsigned long snap_id = 0; - char snap_tag[SD_MAX_VDI_TAG_LEN]; - int fd, ret; - char buf[SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN]; - BDRVSheepdogState *s = bs->opaque; - unsigned int wlen = SD_MAX_VDI_LEN + SD_MAX_VDI_TAG_LEN, rlen = 0; - uint32_t vid; - SheepdogVdiReq hdr = { - .opcode = SD_OP_DEL_VDI, - .data_length = wlen, - .flags = SD_FLAG_CMD_WRITE, - }; - SheepdogVdiRsp *rsp = (SheepdogVdiRsp *)&hdr; - - ret = remove_objects(s, errp); - if (ret) { - return ret; - } - - memset(buf, 0, sizeof(buf)); - memset(snap_tag, 0, sizeof(snap_tag)); - pstrcpy(buf, SD_MAX_VDI_LEN, s->name); - /* TODO Use sd_parse_snapid() once this mess is cleaned up */ - ret = qemu_strtoul(snapshot_id, NULL, 10, &snap_id); - if (ret || snap_id > UINT32_MAX) { - /* - * FIXME Since qemu_strtoul() returns -EINVAL when - * @snapshot_id is null, @snapshot_id is mandatory. Correct - * would be to require at least one of @snapshot_id and @name. - */ - error_setg(errp, "Invalid snapshot ID: %s", - snapshot_id ? snapshot_id : ""); - return -EINVAL; - } - - if (snap_id) { - hdr.snapid = (uint32_t) snap_id; - } else { - /* FIXME I suspect we should use @name here */ - /* FIXME don't truncate silently */ - pstrcpy(snap_tag, sizeof(snap_tag), snapshot_id); - pstrcpy(buf + SD_MAX_VDI_LEN, SD_MAX_VDI_TAG_LEN, snap_tag); - } - - ret = find_vdi_name(s, s->name, snap_id, snap_tag, &vid, true, errp); - if (ret) { - return ret; - } - - fd = connect_to_sdog(s, errp); - if (fd < 0) { - return fd; - } - - ret = do_req(fd, s->bs, (SheepdogReq *)&hdr, - buf, &wlen, &rlen); - closesocket(fd); - if (ret) { - error_setg_errno(errp, -ret, "Couldn't send request to server"); - return ret; - } - - switch (rsp->result) { - case SD_RES_NO_VDI: - error_setg(errp, "Can't find the snapshot"); - return -ENOENT; - case SD_RES_SUCCESS: - break; - default: - error_setg(errp, "%s", sd_strerror(rsp->result)); - return -EIO; - } - - return 0; -} - -static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) -{ - Error *local_err = NULL; - BDRVSheepdogState *s = bs->opaque; - SheepdogReq req; - int fd, nr = 1024, ret, max = BITS_TO_LONGS(SD_NR_VDIS) * sizeof(long); - QEMUSnapshotInfo *sn_tab = NULL; - unsigned wlen, rlen; - int found = 0; - SheepdogInode *inode; - unsigned long *vdi_inuse; - unsigned int start_nr; - uint64_t hval; - uint32_t vid; - - vdi_inuse = g_malloc(max); - inode = g_malloc(SD_INODE_HEADER_SIZE); - - fd = connect_to_sdog(s, &local_err); - if (fd < 0) { - error_report_err(local_err); - ret = fd; - goto out; - } - - rlen = max; - wlen = 0; - - memset(&req, 0, sizeof(req)); - - req.opcode = SD_OP_READ_VDIS; - req.data_length = max; - - ret = do_req(fd, s->bs, &req, vdi_inuse, &wlen, &rlen); - - closesocket(fd); - if (ret) { - goto out; - } - - sn_tab = g_new0(QEMUSnapshotInfo, nr); - - /* calculate a vdi id with hash function */ - hval = fnv_64a_buf(s->name, strlen(s->name), FNV1A_64_INIT); - start_nr = hval & (SD_NR_VDIS - 1); - - fd = connect_to_sdog(s, &local_err); - if (fd < 0) { - error_report_err(local_err); - ret = fd; - goto out; - } - - for (vid = start_nr; found < nr; vid = (vid + 1) % SD_NR_VDIS) { - if (!test_bit(vid, vdi_inuse)) { - break; - } - - /* we don't need to read entire object */ - ret = read_object(fd, s->bs, (char *)inode, - vid_to_vdi_oid(vid), - 0, SD_INODE_HEADER_SIZE, 0, - s->cache_flags); - - if (ret) { - continue; - } - - if (!strcmp(inode->name, s->name) && is_snapshot(inode)) { - sn_tab[found].date_sec = inode->snap_ctime >> 32; - sn_tab[found].date_nsec = inode->snap_ctime & 0xffffffff; - sn_tab[found].vm_state_size = inode->vm_state_size; - sn_tab[found].vm_clock_nsec = inode->vm_clock_nsec; - - snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str), - "%" PRIu32, inode->snap_id); - pstrcpy(sn_tab[found].name, - MIN(sizeof(sn_tab[found].name), sizeof(inode->tag)), - inode->tag); - found++; - } - } - - closesocket(fd); -out: - *psn_tab = sn_tab; - - g_free(vdi_inuse); - g_free(inode); - - if (ret < 0) { - return ret; - } - - return found; -} - -static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, - int64_t pos, int size, int load) -{ - Error *local_err = NULL; - bool create; - int fd, ret = 0, remaining = size; - unsigned int data_len; - uint64_t vmstate_oid; - uint64_t offset; - uint32_t vdi_index; - uint32_t vdi_id = load ? s->inode.parent_vdi_id : s->inode.vdi_id; - uint32_t object_size = (UINT32_C(1) << s->inode.block_size_shift); - - fd = connect_to_sdog(s, &local_err); - if (fd < 0) { - error_report_err(local_err); - return fd; - } - - while (remaining) { - vdi_index = pos / object_size; - offset = pos % object_size; - - data_len = MIN(remaining, object_size - offset); - - vmstate_oid = vid_to_vmstate_oid(vdi_id, vdi_index); - - create = (offset == 0); - if (load) { - ret = read_object(fd, s->bs, (char *)data, vmstate_oid, - s->inode.nr_copies, data_len, offset, - s->cache_flags); - } else { - ret = write_object(fd, s->bs, (char *)data, vmstate_oid, - s->inode.nr_copies, data_len, offset, create, - s->cache_flags); - } - - if (ret < 0) { - error_report("failed to save vmstate %s", strerror(errno)); - goto cleanup; - } - - pos += data_len; - data += data_len; - remaining -= data_len; - } - ret = size; -cleanup: - closesocket(fd); - return ret; -} - -static int sd_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, - int64_t pos) -{ - BDRVSheepdogState *s = bs->opaque; - void *buf; - int ret; - - buf = qemu_blockalign(bs, qiov->size); - qemu_iovec_to_buf(qiov, 0, buf, qiov->size); - ret = do_load_save_vmstate(s, (uint8_t *) buf, pos, qiov->size, 0); - qemu_vfree(buf); - - return ret; -} - -static int sd_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, - int64_t pos) -{ - BDRVSheepdogState *s = bs->opaque; - void *buf; - int ret; - - buf = qemu_blockalign(bs, qiov->size); - ret = do_load_save_vmstate(s, buf, pos, qiov->size, 1); - qemu_iovec_from_buf(qiov, 0, buf, qiov->size); - qemu_vfree(buf); - - return ret; -} - - -static coroutine_fn int sd_co_pdiscard(BlockDriverState *bs, int64_t offset, - int bytes) -{ - SheepdogAIOCB acb; - BDRVSheepdogState *s = bs->opaque; - QEMUIOVector discard_iov; - struct iovec iov; - uint32_t zero = 0; - - if (!s->discard_supported) { - return 0; - } - - memset(&discard_iov, 0, sizeof(discard_iov)); - memset(&iov, 0, sizeof(iov)); - iov.iov_base = &zero; - iov.iov_len = sizeof(zero); - discard_iov.iov = &iov; - discard_iov.niov = 1; - if (!QEMU_IS_ALIGNED(offset | bytes, BDRV_SECTOR_SIZE)) { - return -ENOTSUP; - } - sd_aio_setup(&acb, s, &discard_iov, offset >> BDRV_SECTOR_BITS, - bytes >> BDRV_SECTOR_BITS, AIOCB_DISCARD_OBJ); - sd_co_rw_vector(&acb); - sd_aio_complete(&acb); - - return acb.ret; -} - -static coroutine_fn int -sd_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, - int64_t bytes, int64_t *pnum, int64_t *map, - BlockDriverState **file) -{ - BDRVSheepdogState *s = bs->opaque; - SheepdogInode *inode = &s->inode; - uint32_t object_size = (UINT32_C(1) << inode->block_size_shift); - unsigned long start = offset / object_size, - end = DIV_ROUND_UP(offset + bytes, object_size); - unsigned long idx; - *map = offset; - int ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID; - - for (idx = start; idx < end; idx++) { - if (inode->data_vdi_id[idx] == 0) { - break; - } - } - if (idx == start) { - /* Get the longest length of unallocated sectors */ - ret = 0; - for (idx = start + 1; idx < end; idx++) { - if (inode->data_vdi_id[idx] != 0) { - break; - } - } - } - - *pnum = (idx - start) * object_size; - if (*pnum > bytes) { - *pnum = bytes; - } - if (ret > 0 && ret & BDRV_BLOCK_OFFSET_VALID) { - *file = bs; - } - return ret; -} - -static int64_t sd_get_allocated_file_size(BlockDriverState *bs) -{ - BDRVSheepdogState *s = bs->opaque; - SheepdogInode *inode = &s->inode; - uint32_t object_size = (UINT32_C(1) << inode->block_size_shift); - unsigned long i, last = DIV_ROUND_UP(inode->vdi_size, object_size); - uint64_t size = 0; - - for (i = 0; i < last; i++) { - if (inode->data_vdi_id[i] == 0) { - continue; - } - size += object_size; - } - return size; -} - -static QemuOptsList sd_create_opts = { - .name = "sheepdog-create-opts", - .head = QTAILQ_HEAD_INITIALIZER(sd_create_opts.head), - .desc = { - { - .name = BLOCK_OPT_SIZE, - .type = QEMU_OPT_SIZE, - .help = "Virtual disk size" - }, - { - .name = BLOCK_OPT_BACKING_FILE, - .type = QEMU_OPT_STRING, - .help = "File name of a base image" - }, - { - .name = BLOCK_OPT_BACKING_FMT, - .type = QEMU_OPT_STRING, - .help = "Must be 'sheepdog' if present", - }, - { - .name = BLOCK_OPT_PREALLOC, - .type = QEMU_OPT_STRING, - .help = "Preallocation mode (allowed values: off, full)" - }, - { - .name = BLOCK_OPT_REDUNDANCY, - .type = QEMU_OPT_STRING, - .help = "Redundancy of the image" - }, - { - .name = BLOCK_OPT_OBJECT_SIZE, - .type = QEMU_OPT_SIZE, - .help = "Object size of the image" - }, - { /* end of list */ } - } -}; - -static const char *const sd_strong_runtime_opts[] = { - "vdi", - "snap-id", - "tag", - "server.", - - NULL -}; - -static BlockDriver bdrv_sheepdog = { - .format_name = "sheepdog", - .protocol_name = "sheepdog", - .instance_size = sizeof(BDRVSheepdogState), - .bdrv_parse_filename = sd_parse_filename, - .bdrv_file_open = sd_open, - .bdrv_reopen_prepare = sd_reopen_prepare, - .bdrv_reopen_commit = sd_reopen_commit, - .bdrv_reopen_abort = sd_reopen_abort, - .bdrv_close = sd_close, - .bdrv_co_create = sd_co_create, - .bdrv_co_create_opts = sd_co_create_opts, - .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_getlength = sd_getlength, - .bdrv_get_allocated_file_size = sd_get_allocated_file_size, - .bdrv_co_truncate = sd_co_truncate, - - .bdrv_co_readv = sd_co_readv, - .bdrv_co_writev = sd_co_writev, - .bdrv_co_flush_to_disk = sd_co_flush_to_disk, - .bdrv_co_pdiscard = sd_co_pdiscard, - .bdrv_co_block_status = sd_co_block_status, - - .bdrv_snapshot_create = sd_snapshot_create, - .bdrv_snapshot_goto = sd_snapshot_goto, - .bdrv_snapshot_delete = sd_snapshot_delete, - .bdrv_snapshot_list = sd_snapshot_list, - - .bdrv_save_vmstate = sd_save_vmstate, - .bdrv_load_vmstate = sd_load_vmstate, - - .bdrv_detach_aio_context = sd_detach_aio_context, - .bdrv_attach_aio_context = sd_attach_aio_context, - - .create_opts = &sd_create_opts, - .strong_runtime_opts = sd_strong_runtime_opts, -}; - -static BlockDriver bdrv_sheepdog_tcp = { - .format_name = "sheepdog", - .protocol_name = "sheepdog+tcp", - .instance_size = sizeof(BDRVSheepdogState), - .bdrv_parse_filename = sd_parse_filename, - .bdrv_file_open = sd_open, - .bdrv_reopen_prepare = sd_reopen_prepare, - .bdrv_reopen_commit = sd_reopen_commit, - .bdrv_reopen_abort = sd_reopen_abort, - .bdrv_close = sd_close, - .bdrv_co_create = sd_co_create, - .bdrv_co_create_opts = sd_co_create_opts, - .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_getlength = sd_getlength, - .bdrv_get_allocated_file_size = sd_get_allocated_file_size, - .bdrv_co_truncate = sd_co_truncate, - - .bdrv_co_readv = sd_co_readv, - .bdrv_co_writev = sd_co_writev, - .bdrv_co_flush_to_disk = sd_co_flush_to_disk, - .bdrv_co_pdiscard = sd_co_pdiscard, - .bdrv_co_block_status = sd_co_block_status, - - .bdrv_snapshot_create = sd_snapshot_create, - .bdrv_snapshot_goto = sd_snapshot_goto, - .bdrv_snapshot_delete = sd_snapshot_delete, - .bdrv_snapshot_list = sd_snapshot_list, - - .bdrv_save_vmstate = sd_save_vmstate, - .bdrv_load_vmstate = sd_load_vmstate, - - .bdrv_detach_aio_context = sd_detach_aio_context, - .bdrv_attach_aio_context = sd_attach_aio_context, - - .create_opts = &sd_create_opts, - .strong_runtime_opts = sd_strong_runtime_opts, -}; - -static BlockDriver bdrv_sheepdog_unix = { - .format_name = "sheepdog", - .protocol_name = "sheepdog+unix", - .instance_size = sizeof(BDRVSheepdogState), - .bdrv_parse_filename = sd_parse_filename, - .bdrv_file_open = sd_open, - .bdrv_reopen_prepare = sd_reopen_prepare, - .bdrv_reopen_commit = sd_reopen_commit, - .bdrv_reopen_abort = sd_reopen_abort, - .bdrv_close = sd_close, - .bdrv_co_create = sd_co_create, - .bdrv_co_create_opts = sd_co_create_opts, - .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_getlength = sd_getlength, - .bdrv_get_allocated_file_size = sd_get_allocated_file_size, - .bdrv_co_truncate = sd_co_truncate, - - .bdrv_co_readv = sd_co_readv, - .bdrv_co_writev = sd_co_writev, - .bdrv_co_flush_to_disk = sd_co_flush_to_disk, - .bdrv_co_pdiscard = sd_co_pdiscard, - .bdrv_co_block_status = sd_co_block_status, - - .bdrv_snapshot_create = sd_snapshot_create, - .bdrv_snapshot_goto = sd_snapshot_goto, - .bdrv_snapshot_delete = sd_snapshot_delete, - .bdrv_snapshot_list = sd_snapshot_list, - - .bdrv_save_vmstate = sd_save_vmstate, - .bdrv_load_vmstate = sd_load_vmstate, - - .bdrv_detach_aio_context = sd_detach_aio_context, - .bdrv_attach_aio_context = sd_attach_aio_context, - - .create_opts = &sd_create_opts, - .strong_runtime_opts = sd_strong_runtime_opts, -}; - -static void bdrv_sheepdog_init(void) -{ - bdrv_register(&bdrv_sheepdog); - bdrv_register(&bdrv_sheepdog_tcp); - bdrv_register(&bdrv_sheepdog_unix); -} -block_init(bdrv_sheepdog_init); diff --git a/block/trace-events b/block/trace-events index 1a12d634e2..31062ed437 100644 --- a/block/trace-events +++ b/block/trace-events @@ -207,19 +207,5 @@ file_FindEjectableOpticalMedia(const char *media) "Matching using %s" file_setup_cdrom(const char *partition) "Using %s as optical disc" file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d" -# sheepdog.c -sheepdog_reconnect_to_sdog(void) "Wait for connection to be established" -sheepdog_aio_read_response(void) "disable cache since the server doesn't support it" -sheepdog_open(uint32_t vid) "0x%" PRIx32 " snapshot inode was open" -sheepdog_close(const char *name) "%s" -sheepdog_create_branch_snapshot(uint32_t vdi) "0x%" PRIx32 " is snapshot" -sheepdog_create_branch_created(uint32_t vdi) "0x%" PRIx32 " is created" -sheepdog_create_branch_new(uint32_t vdi) "0x%" PRIx32 " was newly created" -sheepdog_co_rw_vector_update(uint32_t vdi, uint64_t oid, uint64_t data, long idx) "update ino (%" PRIu32 ") %" PRIu64 " %" PRIu64 " %ld" -sheepdog_co_rw_vector_new(uint64_t oid) "new oid 0x%" PRIx64 -sheepdog_snapshot_create_info(const char *sn_name, const char *id, const char *name, int64_t size, int is_snapshot) "sn_info: name %s id_str %s s: name %s vm_state_size %" PRId64 " " "is_snapshot %d" -sheepdog_snapshot_create(const char *sn_name, const char *id) "%s %s" -sheepdog_snapshot_create_inode(const char *name, uint32_t snap, uint32_t vdi) "s->inode: name %s snap_id 0x%" PRIx32 " vdi 0x%" PRIx32 - # ssh.c sftp_error(const char *op, const char *ssh_err, int ssh_err_code, int sftp_err_code) "%s failed: %s (libssh error code: %d, sftp error code: %d)" diff --git a/configure b/configure index f3fe75db9d..87593045cf 100755 --- a/configure +++ b/configure @@ -447,7 +447,6 @@ vdi=${default_feature:-yes} vvfat=${default_feature:-yes} qed=${default_feature:-yes} parallels=${default_feature:-yes} -sheepdog="no" libxml2="$default_feature" debug_mutex="no" libpmem="$default_feature" @@ -1478,10 +1477,6 @@ for opt do ;; --enable-parallels) parallels="yes" ;; - --disable-sheepdog) sheepdog="no" - ;; - --enable-sheepdog) sheepdog="yes" - ;; --disable-vhost-user) vhost_user="no" ;; --enable-vhost-user) vhost_user="yes" @@ -1916,7 +1911,6 @@ disabled with --disable-FEATURE, default is enabled if available vvfat vvfat image format support qed qed image format support parallels parallels image format support - sheepdog sheepdog block driver support (deprecated) crypto-afalg Linux AF_ALG crypto backend driver capstone capstone disassembler support debug-mutex mutex debugging support @@ -6106,10 +6100,6 @@ fi if test "$parallels" = "yes" ; then echo "CONFIG_PARALLELS=y" >> $config_host_mak fi -if test "$sheepdog" = "yes" ; then - add_to deprecated_features "sheepdog" - echo "CONFIG_SHEEPDOG=y" >> $config_host_mak -fi if test "$have_mlockall" = "yes" ; then echo "HAVE_MLOCKALL=y" >> $config_host_mak fi diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index cd91c4528f..7d34da9f68 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -285,15 +285,6 @@ The above, converted to the current supported format:: json:{"file.driver":"rbd", "file.pool":"rbd", "file.image":"name"} -``sheepdog`` driver (since 5.2.0) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The ``sheepdog`` block device driver is deprecated. The corresponding upstream -server project is no longer actively maintained. Users are recommended to switch -to an alternative distributed block device driver such as RBD. The -``qemu-img convert`` command can be used to liberate existing data by moving -it out of sheepdog volumes into an alternative storage backend. - linux-user mode CPUs -------------------- diff --git a/docs/system/device-url-syntax.rst.inc b/docs/system/device-url-syntax.rst.inc index 6f6ec8366b..d15a021508 100644 --- a/docs/system/device-url-syntax.rst.inc +++ b/docs/system/device-url-syntax.rst.inc @@ -85,24 +85,6 @@ These are specified using a special URL syntax. Currently authentication must be done using ssh-agent. Other authentication methods may be supported in future. -``Sheepdog`` - Sheepdog is a distributed storage system for QEMU. QEMU supports - using either local sheepdog devices or remote networked devices. - - Syntax for specifying a sheepdog device - - :: - - sheepdog[+tcp|+unix]://[host:port]/vdiname[?socket=path][#snapid|#tag] - - Example - - .. parsed-literal:: - - |qemu_system| --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine - - See also https://sheepdog.github.io/sheepdog/. - ``GlusterFS`` GlusterFS is a user space distributed file system. QEMU supports the use of GlusterFS volumes for hosting VM disk images using TCP, Unix diff --git a/docs/system/qemu-block-drivers.rst.inc b/docs/system/qemu-block-drivers.rst.inc index 60a064b232..16225710eb 100644 --- a/docs/system/qemu-block-drivers.rst.inc +++ b/docs/system/qemu-block-drivers.rst.inc @@ -547,75 +547,6 @@ also available. Here are some example of the older syntax: |qemu_system| linux2.img -hdb nbd:unix:/tmp/my_socket |qemu_system| -cdrom nbd:localhost:10809:exportname=debian-500-ppc-netinst - - -Sheepdog disk images -~~~~~~~~~~~~~~~~~~~~ - -Sheepdog is a distributed storage system for QEMU. It provides highly -available block level storage volumes that can be attached to -QEMU-based virtual machines. - -You can create a Sheepdog disk image with the command: - -.. parsed-literal:: - - qemu-img create sheepdog:///IMAGE SIZE - -where *IMAGE* is the Sheepdog image name and *SIZE* is its -size. - -To import the existing *FILENAME* to Sheepdog, you can use a -convert command. - -.. parsed-literal:: - - qemu-img convert FILENAME sheepdog:///IMAGE - -You can boot from the Sheepdog disk image with the command: - -.. parsed-literal:: - - |qemu_system| sheepdog:///IMAGE - -You can also create a snapshot of the Sheepdog image like qcow2. - -.. parsed-literal:: - - qemu-img snapshot -c TAG sheepdog:///IMAGE - -where *TAG* is a tag name of the newly created snapshot. - -To boot from the Sheepdog snapshot, specify the tag name of the -snapshot. - -.. parsed-literal:: - - |qemu_system| sheepdog:///IMAGE#TAG - -You can create a cloned image from the existing snapshot. - -.. parsed-literal:: - - qemu-img create -b sheepdog:///BASE#TAG sheepdog:///IMAGE - -where *BASE* is an image name of the source snapshot and *TAG* -is its tag name. - -You can use an unix socket instead of an inet socket: - -.. parsed-literal:: - - |qemu_system| sheepdog+unix:///IMAGE?socket=PATH - -If the Sheepdog daemon doesn't run on the local host, you need to -specify one of the Sheepdog servers to connect to. - -.. parsed-literal:: - - qemu-img create sheepdog://HOSTNAME:PORT/IMAGE SIZE - |qemu_system| sheepdog://HOSTNAME:PORT/IMAGE - iSCSI LUNs ~~~~~~~~~~ diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst index f49737c4ef..51a79b39cb 100644 --- a/docs/system/removed-features.rst +++ b/docs/system/removed-features.rst @@ -474,3 +474,10 @@ VXHS backend (removed in 5.1) ''''''''''''''''''''''''''''' The VXHS code did not compile since v2.12.0. It was removed in 5.1. + +``sheepdog`` driver (removed in 6.0) +'''''''''''''''''''''''''''''''''''' + +The corresponding upstream server project is no longer maintained. +Users are recommended to switch to an alternative distributed block +device driver such as RBD. diff --git a/meson.build b/meson.build index 40e8f012ac..eeb82a4bc6 100644 --- a/meson.build +++ b/meson.build @@ -2634,7 +2634,6 @@ if have_block summary_info += {'vvfat support': config_host.has_key('CONFIG_VVFAT')} summary_info += {'qed support': config_host.has_key('CONFIG_QED')} summary_info += {'parallels support': config_host.has_key('CONFIG_PARALLELS')} - summary_info += {'sheepdog support': config_host.has_key('CONFIG_SHEEPDOG')} summary_info += {'FUSE exports': fuse.found()} endif summary(summary_info, bool_yn: true, section: 'Block layer support') diff --git a/qapi/block-core.json b/qapi/block-core.json index 6d227924d0..2ea294129e 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2818,7 +2818,6 @@ 'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'preallocate', 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd', { 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' }, - 'sheepdog', 'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] } ## @@ -3651,26 +3650,6 @@ '*key-secret': 'str', '*server': ['InetSocketAddressBase'] } } -## -# @BlockdevOptionsSheepdog: -# -# Driver specific block device options for sheepdog -# -# @vdi: Virtual disk image name -# @server: The Sheepdog server to connect to -# @snap-id: Snapshot ID -# @tag: Snapshot tag name -# -# Only one of @snap-id and @tag may be present. -# -# Since: 2.9 -## -{ 'struct': 'BlockdevOptionsSheepdog', - 'data': { 'server': 'SocketAddress', - 'vdi': 'str', - '*snap-id': 'uint32', - '*tag': 'str' } } - ## # @ReplicationMode: # @@ -4037,7 +4016,6 @@ 'rbd': 'BlockdevOptionsRbd', 'replication': { 'type': 'BlockdevOptionsReplication', 'if': 'defined(CONFIG_REPLICATION)' }, - 'sheepdog': 'BlockdevOptionsSheepdog', 'ssh': 'BlockdevOptionsSsh', 'throttle': 'BlockdevOptionsThrottle', 'vdi': 'BlockdevOptionsGenericFormat', @@ -4496,74 +4474,6 @@ '*zeroed-grain': 'bool' } } -## -# @SheepdogRedundancyType: -# -# @full: Create a fully replicated vdi with x copies -# @erasure-coded: Create an erasure coded vdi with x data strips and -# y parity strips -# -# Since: 2.12 -## -{ 'enum': 'SheepdogRedundancyType', - 'data': [ 'full', 'erasure-coded' ] } - -## -# @SheepdogRedundancyFull: -# -# @copies: Number of copies to use (between 1 and 31) -# -# Since: 2.12 -## -{ 'struct': 'SheepdogRedundancyFull', - 'data': { 'copies': 'int' }} - -## -# @SheepdogRedundancyErasureCoded: -# -# @data-strips: Number of data strips to use (one of {2,4,8,16}) -# @parity-strips: Number of parity strips to use (between 1 and 15) -# -# Since: 2.12 -## -{ 'struct': 'SheepdogRedundancyErasureCoded', - 'data': { 'data-strips': 'int', - 'parity-strips': 'int' }} - -## -# @SheepdogRedundancy: -# -# Since: 2.12 -## -{ 'union': 'SheepdogRedundancy', - 'base': { 'type': 'SheepdogRedundancyType' }, - 'discriminator': 'type', - 'data': { 'full': 'SheepdogRedundancyFull', - 'erasure-coded': 'SheepdogRedundancyErasureCoded' } } - -## -# @BlockdevCreateOptionsSheepdog: -# -# Driver specific image creation options for Sheepdog. -# -# @location: Where to store the new image file -# @size: Size of the virtual disk in bytes -# @backing-file: File name of a base image -# @preallocation: Preallocation mode for the new image (default: off; -# allowed values: off, full) -# @redundancy: Redundancy of the image -# @object-size: Object size of the image -# -# Since: 2.12 -## -{ 'struct': 'BlockdevCreateOptionsSheepdog', - 'data': { 'location': 'BlockdevOptionsSheepdog', - 'size': 'size', - '*backing-file': 'str', - '*preallocation': 'PreallocMode', - '*redundancy': 'SheepdogRedundancy', - '*object-size': 'size' } } - ## # @BlockdevCreateOptionsSsh: # @@ -4687,7 +4597,6 @@ 'qcow2': 'BlockdevCreateOptionsQcow2', 'qed': 'BlockdevCreateOptionsQed', 'rbd': 'BlockdevCreateOptionsRbd', - 'sheepdog': 'BlockdevCreateOptionsSheepdog', 'ssh': 'BlockdevCreateOptionsSsh', 'vdi': 'BlockdevCreateOptionsVdi', 'vhdx': 'BlockdevCreateOptionsVhdx', @@ -5322,7 +5231,7 @@ # # Notes: In transaction, if @name is empty, or any snapshot matching @name # exists, the operation will fail. Only some image formats support it, -# for example, qcow2, rbd, and sheepdog. +# for example, qcow2, and rbd. # # Since: 1.7 ## diff --git a/qapi/transaction.json b/qapi/transaction.json index 15ddebdbc3..894258d9e2 100644 --- a/qapi/transaction.json +++ b/qapi/transaction.json @@ -112,10 +112,10 @@ # # On failure, the original disks pre-snapshot attempt will be used. # -# For internal snapshots, the dictionary contains the device and the snapshot's -# name. If an internal snapshot matching name already exists, the request will -# be rejected. Only some image formats support it, for example, qcow2, rbd, -# and sheepdog. +# For internal snapshots, the dictionary contains the device and the +# snapshot's name. If an internal snapshot matching name already exists, +# the request will be rejected. Only some image formats support it, for +# example, qcow2, and rbd, # # On failure, qemu will try delete the newly created internal snapshot in the # transaction. When an I/O error occurs during deletion, the user needs to fix diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005 index 40e64a9a8f..ba377543b0 100755 --- a/tests/qemu-iotests/005 +++ b/tests/qemu-iotests/005 @@ -52,11 +52,6 @@ if [ "$IMGFMT" = "vpc" ]; then _notrun "image format $IMGFMT does not support large image sizes" fi -# sheepdog image is limited to 4TB, so we can't test it here -if [ "$IMGPROTO" = "sheepdog" ]; then - _notrun "image protocol $IMGPROTO does not support large image sizes" -fi - # Sanity check: For raw, we require a file system that permits the creation # of a HUGE (but very sparse) file. Check we can create it before continuing. if [ "$IMGFMT" = "raw" ]; then diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025 index da77ed3154..80686a30d5 100755 --- a/tests/qemu-iotests/025 +++ b/tests/qemu-iotests/025 @@ -39,7 +39,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.pattern _supported_fmt raw qcow2 qed luks -_supported_proto file sheepdog rbd nfs fuse +_supported_proto file rbd nfs fuse echo "=== Creating image" echo diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index d1c87ceaf1..08f51366f1 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -65,8 +65,7 @@ def make_argparser() -> argparse.ArgumentParser: mg.add_argument('-' + fmt, dest='imgfmt', action='store_const', const=fmt, help=f'test {fmt}') - protocol_list = ['file', 'rbd', 'sheepdog', 'nbd', 'ssh', 'nfs', - 'fuse'] + protocol_list = ['file', 'rbd', 'nbd', 'ssh', 'nfs', 'fuse'] g_prt = p.add_argument_group( ' image protocol options', 'The following options set the IMGPROTO environment variable. ' diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 7f49c9716d..cbbf6d7c7f 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -641,10 +641,6 @@ _cleanup_test_img() rbd --no-progress rm "$TEST_DIR/t.$IMGFMT" > /dev/null ;; - sheepdog) - collie vdi delete "$TEST_DIR/t.$IMGFMT" - ;; - esac } From 9d49bcf6992a2ba77f79d2512e23b8ca26d72f6a Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 3 May 2021 10:40:33 +0200 Subject: [PATCH 0491/3028] Drop the deprecated lm32 target Target lm32 was deprecated in commit d8498005122, v5.2.0. See there for rationale. Some of its code lives on in device models derived from milkymist ones: hw/char/digic-uart.c and hw/display/bcm2835_fb.c. Cc: Michael Walle Signed-off-by: Markus Armbruster Message-Id: <20210503084034.3804963-2-armbru@redhat.com> Acked-by: Michael Walle [Trivial conflicts resolved, reST markup fixed] --- .gitlab-ci.yml | 2 +- MAINTAINERS | 25 - configure | 7 +- default-configs/devices/lm32-softmmu.mak | 12 - default-configs/targets/lm32-softmmu.mak | 2 - disas/lm32.c | 361 ------- disas/meson.build | 1 - docs/system/deprecated.rst | 8 - docs/system/removed-features.rst | 7 + fpu/softfloat-specialize.c.inc | 2 +- hw/Kconfig | 1 - hw/audio/meson.build | 1 - hw/audio/milkymist-ac97.c | 360 ------- hw/audio/trace-events | 12 - hw/char/lm32_juart.c | 166 --- hw/char/lm32_uart.c | 314 ------ hw/char/meson.build | 3 - hw/char/milkymist-uart.c | 258 ----- hw/char/trace-events | 17 - hw/display/Kconfig | 4 - hw/display/meson.build | 2 - hw/display/milkymist-tmu2.c | 551 ---------- hw/display/milkymist-vgafb.c | 360 ------- hw/display/milkymist-vgafb_template.h | 74 -- hw/display/trace-events | 10 - hw/input/meson.build | 1 - hw/input/milkymist-softusb.c | 319 ------ hw/input/trace-events | 7 - hw/intc/lm32_pic.c | 195 ---- hw/intc/meson.build | 1 - hw/intc/trace-events | 9 - hw/lm32/Kconfig | 18 - hw/lm32/lm32.h | 48 - hw/lm32/lm32_boards.c | 332 ------ hw/lm32/lm32_hwsetup.h | 179 ---- hw/lm32/meson.build | 6 - hw/lm32/milkymist-hw.h | 133 --- hw/lm32/milkymist.c | 249 ----- hw/meson.build | 1 - hw/misc/meson.build | 1 - hw/misc/milkymist-hpdmc.c | 172 --- hw/misc/milkymist-pfpu.c | 548 ---------- hw/misc/trace-events | 10 - hw/net/meson.build | 1 - hw/net/milkymist-minimac2.c | 547 ---------- hw/net/trace-events | 12 - hw/sd/meson.build | 1 - hw/sd/milkymist-memcard.c | 335 ------ hw/sd/trace-events | 4 - hw/timer/lm32_timer.c | 249 ----- hw/timer/meson.build | 2 - hw/timer/milkymist-sysctl.c | 361 ------- hw/timer/trace-events | 17 - hw/usb/quirks-ftdi-ids.h | 6 - hw/usb/quirks.h | 1 - include/disas/dis-asm.h | 3 - include/exec/poison.h | 2 - include/hw/char/lm32_juart.h | 13 - include/hw/display/milkymist_tmu2.h | 42 - include/hw/lm32/lm32_pic.h | 10 - include/sysemu/arch_init.h | 1 - meson.build | 3 +- qapi/machine.json | 2 +- qemu-options.hx | 4 +- softmmu/arch_init.c | 2 - target/lm32/README | 45 - target/lm32/TODO | 1 - target/lm32/cpu-param.h | 17 - target/lm32/cpu-qom.h | 48 - target/lm32/cpu.c | 274 ----- target/lm32/cpu.h | 262 ----- target/lm32/gdbstub.c | 92 -- target/lm32/helper.c | 224 ---- target/lm32/helper.h | 14 - target/lm32/lm32-semi.c | 211 ---- target/lm32/machine.c | 33 - target/lm32/meson.build | 15 - target/lm32/op_helper.c | 148 --- target/lm32/translate.c | 1237 ---------------------- target/meson.build | 1 - tests/qtest/machine-none-test.c | 1 - tests/tcg/README | 6 - tests/tcg/configure.sh | 2 +- tests/tcg/lm32/Makefile | 106 -- tests/tcg/lm32/crt.S | 84 -- tests/tcg/lm32/helper.S | 65 -- tests/tcg/lm32/linker.ld | 55 - tests/tcg/lm32/macros.inc | 90 -- tests/tcg/lm32/test_add.S | 75 -- tests/tcg/lm32/test_addi.S | 56 - tests/tcg/lm32/test_and.S | 45 - tests/tcg/lm32/test_andhi.S | 35 - tests/tcg/lm32/test_andi.S | 35 - tests/tcg/lm32/test_b.S | 13 - tests/tcg/lm32/test_be.S | 48 - tests/tcg/lm32/test_bg.S | 78 -- tests/tcg/lm32/test_bge.S | 78 -- tests/tcg/lm32/test_bgeu.S | 78 -- tests/tcg/lm32/test_bgu.S | 78 -- tests/tcg/lm32/test_bi.S | 23 - tests/tcg/lm32/test_bne.S | 48 - tests/tcg/lm32/test_break.S | 20 - tests/tcg/lm32/test_bret.S | 38 - tests/tcg/lm32/test_call.S | 16 - tests/tcg/lm32/test_calli.S | 15 - tests/tcg/lm32/test_cmpe.S | 40 - tests/tcg/lm32/test_cmpei.S | 35 - tests/tcg/lm32/test_cmpg.S | 64 -- tests/tcg/lm32/test_cmpge.S | 64 -- tests/tcg/lm32/test_cmpgei.S | 70 -- tests/tcg/lm32/test_cmpgeu.S | 64 -- tests/tcg/lm32/test_cmpgeui.S | 70 -- tests/tcg/lm32/test_cmpgi.S | 70 -- tests/tcg/lm32/test_cmpgu.S | 64 -- tests/tcg/lm32/test_cmpgui.S | 70 -- tests/tcg/lm32/test_cmpne.S | 40 - tests/tcg/lm32/test_cmpnei.S | 35 - tests/tcg/lm32/test_divu.S | 29 - tests/tcg/lm32/test_eret.S | 38 - tests/tcg/lm32/test_lb.S | 49 - tests/tcg/lm32/test_lbu.S | 49 - tests/tcg/lm32/test_lh.S | 49 - tests/tcg/lm32/test_lhu.S | 49 - tests/tcg/lm32/test_lw.S | 32 - tests/tcg/lm32/test_modu.S | 35 - tests/tcg/lm32/test_mul.S | 70 -- tests/tcg/lm32/test_muli.S | 45 - tests/tcg/lm32/test_nor.S | 51 - tests/tcg/lm32/test_nori.S | 35 - tests/tcg/lm32/test_or.S | 51 - tests/tcg/lm32/test_orhi.S | 35 - tests/tcg/lm32/test_ori.S | 35 - tests/tcg/lm32/test_ret.S | 14 - tests/tcg/lm32/test_sb.S | 32 - tests/tcg/lm32/test_scall.S | 24 - tests/tcg/lm32/test_sextb.S | 20 - tests/tcg/lm32/test_sexth.S | 20 - tests/tcg/lm32/test_sh.S | 32 - tests/tcg/lm32/test_sl.S | 45 - tests/tcg/lm32/test_sli.S | 30 - tests/tcg/lm32/test_sr.S | 57 - tests/tcg/lm32/test_sri.S | 40 - tests/tcg/lm32/test_sru.S | 57 - tests/tcg/lm32/test_srui.S | 40 - tests/tcg/lm32/test_sub.S | 75 -- tests/tcg/lm32/test_sw.S | 38 - tests/tcg/lm32/test_xnor.S | 51 - tests/tcg/lm32/test_xnori.S | 35 - tests/tcg/lm32/test_xor.S | 51 - tests/tcg/lm32/test_xori.S | 35 - 150 files changed, 17 insertions(+), 12234 deletions(-) delete mode 100644 default-configs/devices/lm32-softmmu.mak delete mode 100644 default-configs/targets/lm32-softmmu.mak delete mode 100644 disas/lm32.c delete mode 100644 hw/audio/milkymist-ac97.c delete mode 100644 hw/char/lm32_juart.c delete mode 100644 hw/char/lm32_uart.c delete mode 100644 hw/char/milkymist-uart.c delete mode 100644 hw/display/milkymist-tmu2.c delete mode 100644 hw/display/milkymist-vgafb.c delete mode 100644 hw/display/milkymist-vgafb_template.h delete mode 100644 hw/input/milkymist-softusb.c delete mode 100644 hw/intc/lm32_pic.c delete mode 100644 hw/lm32/Kconfig delete mode 100644 hw/lm32/lm32.h delete mode 100644 hw/lm32/lm32_boards.c delete mode 100644 hw/lm32/lm32_hwsetup.h delete mode 100644 hw/lm32/meson.build delete mode 100644 hw/lm32/milkymist-hw.h delete mode 100644 hw/lm32/milkymist.c delete mode 100644 hw/misc/milkymist-hpdmc.c delete mode 100644 hw/misc/milkymist-pfpu.c delete mode 100644 hw/net/milkymist-minimac2.c delete mode 100644 hw/sd/milkymist-memcard.c delete mode 100644 hw/timer/lm32_timer.c delete mode 100644 hw/timer/milkymist-sysctl.c delete mode 100644 include/hw/char/lm32_juart.h delete mode 100644 include/hw/display/milkymist_tmu2.h delete mode 100644 include/hw/lm32/lm32_pic.h delete mode 100644 target/lm32/README delete mode 100644 target/lm32/TODO delete mode 100644 target/lm32/cpu-param.h delete mode 100644 target/lm32/cpu-qom.h delete mode 100644 target/lm32/cpu.c delete mode 100644 target/lm32/cpu.h delete mode 100644 target/lm32/gdbstub.c delete mode 100644 target/lm32/helper.c delete mode 100644 target/lm32/helper.h delete mode 100644 target/lm32/lm32-semi.c delete mode 100644 target/lm32/machine.c delete mode 100644 target/lm32/meson.build delete mode 100644 target/lm32/op_helper.c delete mode 100644 target/lm32/translate.c delete mode 100644 tests/tcg/lm32/Makefile delete mode 100644 tests/tcg/lm32/crt.S delete mode 100644 tests/tcg/lm32/helper.S delete mode 100644 tests/tcg/lm32/linker.ld delete mode 100644 tests/tcg/lm32/macros.inc delete mode 100644 tests/tcg/lm32/test_add.S delete mode 100644 tests/tcg/lm32/test_addi.S delete mode 100644 tests/tcg/lm32/test_and.S delete mode 100644 tests/tcg/lm32/test_andhi.S delete mode 100644 tests/tcg/lm32/test_andi.S delete mode 100644 tests/tcg/lm32/test_b.S delete mode 100644 tests/tcg/lm32/test_be.S delete mode 100644 tests/tcg/lm32/test_bg.S delete mode 100644 tests/tcg/lm32/test_bge.S delete mode 100644 tests/tcg/lm32/test_bgeu.S delete mode 100644 tests/tcg/lm32/test_bgu.S delete mode 100644 tests/tcg/lm32/test_bi.S delete mode 100644 tests/tcg/lm32/test_bne.S delete mode 100644 tests/tcg/lm32/test_break.S delete mode 100644 tests/tcg/lm32/test_bret.S delete mode 100644 tests/tcg/lm32/test_call.S delete mode 100644 tests/tcg/lm32/test_calli.S delete mode 100644 tests/tcg/lm32/test_cmpe.S delete mode 100644 tests/tcg/lm32/test_cmpei.S delete mode 100644 tests/tcg/lm32/test_cmpg.S delete mode 100644 tests/tcg/lm32/test_cmpge.S delete mode 100644 tests/tcg/lm32/test_cmpgei.S delete mode 100644 tests/tcg/lm32/test_cmpgeu.S delete mode 100644 tests/tcg/lm32/test_cmpgeui.S delete mode 100644 tests/tcg/lm32/test_cmpgi.S delete mode 100644 tests/tcg/lm32/test_cmpgu.S delete mode 100644 tests/tcg/lm32/test_cmpgui.S delete mode 100644 tests/tcg/lm32/test_cmpne.S delete mode 100644 tests/tcg/lm32/test_cmpnei.S delete mode 100644 tests/tcg/lm32/test_divu.S delete mode 100644 tests/tcg/lm32/test_eret.S delete mode 100644 tests/tcg/lm32/test_lb.S delete mode 100644 tests/tcg/lm32/test_lbu.S delete mode 100644 tests/tcg/lm32/test_lh.S delete mode 100644 tests/tcg/lm32/test_lhu.S delete mode 100644 tests/tcg/lm32/test_lw.S delete mode 100644 tests/tcg/lm32/test_modu.S delete mode 100644 tests/tcg/lm32/test_mul.S delete mode 100644 tests/tcg/lm32/test_muli.S delete mode 100644 tests/tcg/lm32/test_nor.S delete mode 100644 tests/tcg/lm32/test_nori.S delete mode 100644 tests/tcg/lm32/test_or.S delete mode 100644 tests/tcg/lm32/test_orhi.S delete mode 100644 tests/tcg/lm32/test_ori.S delete mode 100644 tests/tcg/lm32/test_ret.S delete mode 100644 tests/tcg/lm32/test_sb.S delete mode 100644 tests/tcg/lm32/test_scall.S delete mode 100644 tests/tcg/lm32/test_sextb.S delete mode 100644 tests/tcg/lm32/test_sexth.S delete mode 100644 tests/tcg/lm32/test_sh.S delete mode 100644 tests/tcg/lm32/test_sl.S delete mode 100644 tests/tcg/lm32/test_sli.S delete mode 100644 tests/tcg/lm32/test_sr.S delete mode 100644 tests/tcg/lm32/test_sri.S delete mode 100644 tests/tcg/lm32/test_sru.S delete mode 100644 tests/tcg/lm32/test_srui.S delete mode 100644 tests/tcg/lm32/test_sub.S delete mode 100644 tests/tcg/lm32/test_sw.S delete mode 100644 tests/tcg/lm32/test_xnor.S delete mode 100644 tests/tcg/lm32/test_xnori.S delete mode 100644 tests/tcg/lm32/test_xor.S delete mode 100644 tests/tcg/lm32/test_xori.S diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 745fdaea92..e0d941b779 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -624,7 +624,7 @@ build-deprecated: IMAGE: debian-all-test-cross CONFIGURE_ARGS: --disable-tools MAKE_CHECK_ARGS: build-tcg - TARGETS: ppc64abi32-linux-user lm32-softmmu unicore32-softmmu + TARGETS: ppc64abi32-linux-user unicore32-softmmu artifacts: expire_in: 2 days paths: diff --git a/MAINTAINERS b/MAINTAINERS index c765165e5c..96855fbc73 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -207,19 +207,6 @@ F: disas/hppa.c F: hw/net/*i82596* F: include/hw/net/lasi_82596.h -LM32 TCG CPUs -R: Michael Walle -S: Orphan -F: target/lm32/ -F: disas/lm32.c -F: hw/lm32/ -F: hw/*/lm32_* -F: hw/*/milkymist-* -F: include/hw/display/milkymist_tmu2.h -F: include/hw/char/lm32_juart.h -F: include/hw/lm32/ -F: tests/tcg/lm32/ - M68K TCG CPUs M: Laurent Vivier S: Maintained @@ -1081,18 +1068,6 @@ F: default-configs/*/hppa-softmmu.mak F: hw/hppa/ F: pc-bios/hppa-firmware.img -LM32 Machines -------------- -EVR32 and uclinux BSP -R: Michael Walle -S: Orphan -F: hw/lm32/lm32_boards.c - -milkymist -R: Michael Walle -S: Orphan -F: hw/lm32/milkymist.c - M68K Machines ------------- an5206 diff --git a/configure b/configure index 87593045cf..cae212988c 100755 --- a/configure +++ b/configure @@ -1663,7 +1663,7 @@ if [ "$ARCH" = "unknown" ]; then fi default_target_list="" -deprecated_targets_list=ppc64abi32-linux-user,lm32-softmmu,unicore32-softmmu +deprecated_targets_list=ppc64abi32-linux-user,unicore32-softmmu deprecated_features="" mak_wilds="" @@ -3617,7 +3617,7 @@ case "$fdt" in esac ########################################## -# opengl probe (for sdl2, gtk, milkymist-tmu2) +# opengl probe (for sdl2, gtk) gbm="no" if $pkg_config gbm; then @@ -6274,14 +6274,13 @@ fi # UNLINK is used to remove symlinks from older development versions # that might get into the way when doing "git update" without doing # a "make distclean" in between. -DIRS="tests tests/tcg tests/tcg/lm32 tests/qapi-schema tests/qtest/libqos" +DIRS="tests tests/tcg tests/qapi-schema tests/qtest/libqos" DIRS="$DIRS tests/qtest tests/qemu-iotests tests/vm tests/fp tests/qgraph" DIRS="$DIRS docs docs/interop fsdev scsi" DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw" DIRS="$DIRS roms/seabios" DIRS="$DIRS contrib/plugins/" LINKS="Makefile" -LINKS="$LINKS tests/tcg/lm32/Makefile" LINKS="$LINKS tests/tcg/Makefile.target" LINKS="$LINKS pc-bios/optionrom/Makefile" LINKS="$LINKS pc-bios/s390-ccw/Makefile" diff --git a/default-configs/devices/lm32-softmmu.mak b/default-configs/devices/lm32-softmmu.mak deleted file mode 100644 index 1bce3f6e8b..0000000000 --- a/default-configs/devices/lm32-softmmu.mak +++ /dev/null @@ -1,12 +0,0 @@ -# Default configuration for lm32-softmmu - -# Uncomment the following lines to disable these optional devices: -# -#CONFIG_MILKYMIST_TMU2=n # disabling it actually causes compile-time failures - -CONFIG_SEMIHOSTING=y - -# Boards: -# -CONFIG_LM32_EVR=y -CONFIG_MILKYMIST=y diff --git a/default-configs/targets/lm32-softmmu.mak b/default-configs/targets/lm32-softmmu.mak deleted file mode 100644 index 55e7184a3d..0000000000 --- a/default-configs/targets/lm32-softmmu.mak +++ /dev/null @@ -1,2 +0,0 @@ -TARGET_ARCH=lm32 -TARGET_WORDS_BIGENDIAN=y diff --git a/disas/lm32.c b/disas/lm32.c deleted file mode 100644 index 4fbb124534..0000000000 --- a/disas/lm32.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Simple LatticeMico32 disassembler. - * - * Copyright (c) 2012 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - */ - -#include "qemu/osdep.h" -#include "disas/dis-asm.h" - -typedef enum { - LM32_OP_SRUI = 0, LM32_OP_NORI, LM32_OP_MULI, LM32_OP_SH, LM32_OP_LB, - LM32_OP_SRI, LM32_OP_XORI, LM32_OP_LH, LM32_OP_ANDI, LM32_OP_XNORI, - LM32_OP_LW, LM32_OP_LHU, LM32_OP_SB, LM32_OP_ADDI, LM32_OP_ORI, - LM32_OP_SLI, LM32_OP_LBU, LM32_OP_BE, LM32_OP_BG, LM32_OP_BGE, - LM32_OP_BGEU, LM32_OP_BGU, LM32_OP_SW, LM32_OP_BNE, LM32_OP_ANDHI, - LM32_OP_CMPEI, LM32_OP_CMPGI, LM32_OP_CMPGEI, LM32_OP_CMPGEUI, - LM32_OP_CMPGUI, LM32_OP_ORHI, LM32_OP_CMPNEI, LM32_OP_SRU, LM32_OP_NOR, - LM32_OP_MUL, LM32_OP_DIVU, LM32_OP_RCSR, LM32_OP_SR, LM32_OP_XOR, - LM32_OP_ILL0, LM32_OP_AND, LM32_OP_XNOR, LM32_OP_ILL1, LM32_OP_SCALL, - LM32_OP_SEXTB, LM32_OP_ADD, LM32_OP_OR, LM32_OP_SL, LM32_OP_B, - LM32_OP_MODU, LM32_OP_SUB, LM32_OP_ILL2, LM32_OP_WCSR, LM32_OP_ILL3, - LM32_OP_CALL, LM32_OP_SEXTH, LM32_OP_BI, LM32_OP_CMPE, LM32_OP_CMPG, - LM32_OP_CMPGE, LM32_OP_CMPGEU, LM32_OP_CMPGU, LM32_OP_CALLI, LM32_OP_CMPNE, -} Lm32Opcode; - -typedef enum { - FMT_INVALID = 0, FMT_RRI5, FMT_RRI16, FMT_IMM26, FMT_LOAD, FMT_STORE, - FMT_RRR, FMT_R, FMT_RNR, FMT_CRN, FMT_CNR, FMT_BREAK, -} Lm32OpcodeFmt; - -typedef enum { - LM32_CSR_IE = 0, LM32_CSR_IM, LM32_CSR_IP, LM32_CSR_ICC, LM32_CSR_DCC, - LM32_CSR_CC, LM32_CSR_CFG, LM32_CSR_EBA, LM32_CSR_DC, LM32_CSR_DEBA, - LM32_CSR_CFG2, LM32_CSR_JTX = 0xe, LM32_CSR_JRX, LM32_CSR_BP0, - LM32_CSR_BP1, LM32_CSR_BP2, LM32_CSR_BP3, LM32_CSR_WP0 = 0x18, - LM32_CSR_WP1, LM32_CSR_WP2, LM32_CSR_WP3, -} Lm32CsrNum; - -typedef struct { - int csr; - const char *name; -} Lm32CsrInfo; - -static const Lm32CsrInfo lm32_csr_info[] = { - {LM32_CSR_IE, "ie", }, - {LM32_CSR_IM, "im", }, - {LM32_CSR_IP, "ip", }, - {LM32_CSR_ICC, "icc", }, - {LM32_CSR_DCC, "dcc", }, - {LM32_CSR_CC, "cc", }, - {LM32_CSR_CFG, "cfg", }, - {LM32_CSR_EBA, "eba", }, - {LM32_CSR_DC, "dc", }, - {LM32_CSR_DEBA, "deba", }, - {LM32_CSR_CFG2, "cfg2", }, - {LM32_CSR_JTX, "jtx", }, - {LM32_CSR_JRX, "jrx", }, - {LM32_CSR_BP0, "bp0", }, - {LM32_CSR_BP1, "bp1", }, - {LM32_CSR_BP2, "bp2", }, - {LM32_CSR_BP3, "bp3", }, - {LM32_CSR_WP0, "wp0", }, - {LM32_CSR_WP1, "wp1", }, - {LM32_CSR_WP2, "wp2", }, - {LM32_CSR_WP3, "wp3", }, -}; - -static const Lm32CsrInfo *find_csr_info(int csr) -{ - const Lm32CsrInfo *info; - int i; - - for (i = 0; i < ARRAY_SIZE(lm32_csr_info); i++) { - info = &lm32_csr_info[i]; - if (csr == info->csr) { - return info; - } - } - - return NULL; -} - -typedef struct { - int reg; - const char *name; -} Lm32RegInfo; - -typedef enum { - LM32_REG_R0 = 0, LM32_REG_R1, LM32_REG_R2, LM32_REG_R3, LM32_REG_R4, - LM32_REG_R5, LM32_REG_R6, LM32_REG_R7, LM32_REG_R8, LM32_REG_R9, - LM32_REG_R10, LM32_REG_R11, LM32_REG_R12, LM32_REG_R13, LM32_REG_R14, - LM32_REG_R15, LM32_REG_R16, LM32_REG_R17, LM32_REG_R18, LM32_REG_R19, - LM32_REG_R20, LM32_REG_R21, LM32_REG_R22, LM32_REG_R23, LM32_REG_R24, - LM32_REG_R25, LM32_REG_GP, LM32_REG_FP, LM32_REG_SP, LM32_REG_RA, - LM32_REG_EA, LM32_REG_BA, -} Lm32RegNum; - -static const Lm32RegInfo lm32_reg_info[] = { - {LM32_REG_R0, "r0", }, - {LM32_REG_R1, "r1", }, - {LM32_REG_R2, "r2", }, - {LM32_REG_R3, "r3", }, - {LM32_REG_R4, "r4", }, - {LM32_REG_R5, "r5", }, - {LM32_REG_R6, "r6", }, - {LM32_REG_R7, "r7", }, - {LM32_REG_R8, "r8", }, - {LM32_REG_R9, "r9", }, - {LM32_REG_R10, "r10", }, - {LM32_REG_R11, "r11", }, - {LM32_REG_R12, "r12", }, - {LM32_REG_R13, "r13", }, - {LM32_REG_R14, "r14", }, - {LM32_REG_R15, "r15", }, - {LM32_REG_R16, "r16", }, - {LM32_REG_R17, "r17", }, - {LM32_REG_R18, "r18", }, - {LM32_REG_R19, "r19", }, - {LM32_REG_R20, "r20", }, - {LM32_REG_R21, "r21", }, - {LM32_REG_R22, "r22", }, - {LM32_REG_R23, "r23", }, - {LM32_REG_R24, "r24", }, - {LM32_REG_R25, "r25", }, - {LM32_REG_GP, "gp", }, - {LM32_REG_FP, "fp", }, - {LM32_REG_SP, "sp", }, - {LM32_REG_RA, "ra", }, - {LM32_REG_EA, "ea", }, - {LM32_REG_BA, "ba", }, -}; - -static const Lm32RegInfo *find_reg_info(int reg) -{ - assert(ARRAY_SIZE(lm32_reg_info) == 32); - return &lm32_reg_info[reg & 0x1f]; -} - -typedef struct { - struct { - uint32_t code; - uint32_t mask; - } op; - const char *name; - const char *args_fmt; -} Lm32OpcodeInfo; - -static const Lm32OpcodeInfo lm32_opcode_info[] = { - /* pseudo instructions */ - {{0x34000000, 0xffffffff}, "nop", NULL}, - {{0xac000002, 0xffffffff}, "break", NULL}, - {{0xac000003, 0xffffffff}, "scall", NULL}, - {{0xc3e00000, 0xffffffff}, "bret", NULL}, - {{0xc3c00000, 0xffffffff}, "eret", NULL}, - {{0xc3a00000, 0xffffffff}, "ret", NULL}, - {{0xa4000000, 0xfc1f07ff}, "not", "%2, %0"}, - {{0xb8000000, 0xfc1f07ff}, "mv", "%2, %0"}, - {{0x71e00000, 0xffe00000}, "mvhi", "%1, %u"}, - {{0x34000000, 0xffe00000}, "mvi", "%1, %s"}, - -#define _O(op) {op << 26, 0x3f << 26} - /* regular opcodes */ - {_O(LM32_OP_ADD), "add", "%2, %0, %1" }, - {_O(LM32_OP_ADDI), "addi", "%1, %0, %s" }, - {_O(LM32_OP_AND), "and", "%2, %0, %1" }, - {_O(LM32_OP_ANDHI), "andhi", "%1, %0, %u" }, - {_O(LM32_OP_ANDI), "andi", "%1, %0, %u" }, - {_O(LM32_OP_B), "b", "%0", }, - {_O(LM32_OP_BE), "be", "%1, %0, %r" }, - {_O(LM32_OP_BG), "bg", "%1, %0, %r" }, - {_O(LM32_OP_BGE), "bge", "%1, %0, %r" }, - {_O(LM32_OP_BGEU), "bgeu", "%1, %0, %r" }, - {_O(LM32_OP_BGU), "bgu", "%1, %0, %r" }, - {_O(LM32_OP_BI), "bi", "%R", }, - {_O(LM32_OP_BNE), "bne", "%1, %0, %r" }, - {_O(LM32_OP_CALL), "call", "%0", }, - {_O(LM32_OP_CALLI), "calli", "%R", }, - {_O(LM32_OP_CMPE), "cmpe", "%2, %0, %1" }, - {_O(LM32_OP_CMPEI), "cmpei", "%1, %0, %s" }, - {_O(LM32_OP_CMPG), "cmpg", "%2, %0, %1" }, - {_O(LM32_OP_CMPGE), "cmpge", "%2, %0, %1" }, - {_O(LM32_OP_CMPGEI), "cmpgei", "%1, %0, %s" }, - {_O(LM32_OP_CMPGEU), "cmpgeu", "%2, %0, %1" }, - {_O(LM32_OP_CMPGEUI), "cmpgeui", "%1, %0, %s" }, - {_O(LM32_OP_CMPGI), "cmpgi", "%1, %0, %s" }, - {_O(LM32_OP_CMPGU), "cmpgu", "%2, %0, %1" }, - {_O(LM32_OP_CMPGUI), "cmpgui", "%1, %0, %s" }, - {_O(LM32_OP_CMPNE), "cmpne", "%2, %0, %1" }, - {_O(LM32_OP_CMPNEI), "cmpnei", "%1, %0, %s" }, - {_O(LM32_OP_DIVU), "divu", "%2, %0, %1" }, - {_O(LM32_OP_LB), "lb", "%1, (%0+%s)" }, - {_O(LM32_OP_LBU), "lbu", "%1, (%0+%s)" }, - {_O(LM32_OP_LH), "lh", "%1, (%0+%s)" }, - {_O(LM32_OP_LHU), "lhu", "%1, (%0+%s)" }, - {_O(LM32_OP_LW), "lw", "%1, (%0+%s)" }, - {_O(LM32_OP_MODU), "modu", "%2, %0, %1" }, - {_O(LM32_OP_MULI), "muli", "%1, %0, %s" }, - {_O(LM32_OP_MUL), "mul", "%2, %0, %1" }, - {_O(LM32_OP_NORI), "nori", "%1, %0, %u" }, - {_O(LM32_OP_NOR), "nor", "%2, %0, %1" }, - {_O(LM32_OP_ORHI), "orhi", "%1, %0, %u" }, - {_O(LM32_OP_ORI), "ori", "%1, %0, %u" }, - {_O(LM32_OP_OR), "or", "%2, %0, %1" }, - {_O(LM32_OP_RCSR), "rcsr", "%2, %c", }, - {_O(LM32_OP_SB), "sb", "(%0+%s), %1" }, - {_O(LM32_OP_SEXTB), "sextb", "%2, %0", }, - {_O(LM32_OP_SEXTH), "sexth", "%2, %0", }, - {_O(LM32_OP_SH), "sh", "(%0+%s), %1" }, - {_O(LM32_OP_SLI), "sli", "%1, %0, %h" }, - {_O(LM32_OP_SL), "sl", "%2, %0, %1" }, - {_O(LM32_OP_SRI), "sri", "%1, %0, %h" }, - {_O(LM32_OP_SR), "sr", "%2, %0, %1" }, - {_O(LM32_OP_SRUI), "srui", "%1, %0, %d" }, - {_O(LM32_OP_SRU), "sru", "%2, %0, %s" }, - {_O(LM32_OP_SUB), "sub", "%2, %0, %s" }, - {_O(LM32_OP_SW), "sw", "(%0+%s), %1" }, - {_O(LM32_OP_WCSR), "wcsr", "%c, %1", }, - {_O(LM32_OP_XNORI), "xnori", "%1, %0, %u" }, - {_O(LM32_OP_XNOR), "xnor", "%2, %0, %1" }, - {_O(LM32_OP_XORI), "xori", "%1, %0, %u" }, - {_O(LM32_OP_XOR), "xor", "%2, %0, %1" }, -#undef _O -}; - -static const Lm32OpcodeInfo *find_opcode_info(uint32_t opcode) -{ - const Lm32OpcodeInfo *info; - int i; - for (i = 0; i < ARRAY_SIZE(lm32_opcode_info); i++) { - info = &lm32_opcode_info[i]; - if ((opcode & info->op.mask) == info->op.code) { - return info; - } - } - - return NULL; -} - -int print_insn_lm32(bfd_vma memaddr, struct disassemble_info *info) -{ - fprintf_function fprintf_fn = info->fprintf_func; - void *stream = info->stream; - int rc; - uint8_t insn[4]; - const Lm32OpcodeInfo *opc_info; - uint32_t op; - const char *args_fmt; - - rc = info->read_memory_func(memaddr, insn, 4, info); - if (rc != 0) { - info->memory_error_func(rc, memaddr, info); - return -1; - } - - fprintf_fn(stream, "%02x %02x %02x %02x ", - insn[0], insn[1], insn[2], insn[3]); - - op = bfd_getb32(insn); - opc_info = find_opcode_info(op); - if (opc_info) { - fprintf_fn(stream, "%-8s ", opc_info->name); - args_fmt = opc_info->args_fmt; - while (args_fmt && *args_fmt) { - if (*args_fmt == '%') { - switch (*(++args_fmt)) { - case '0': { - uint8_t r0; - const char *r0_name; - r0 = (op >> 21) & 0x1f; - r0_name = find_reg_info(r0)->name; - fprintf_fn(stream, "%s", r0_name); - break; - } - case '1': { - uint8_t r1; - const char *r1_name; - r1 = (op >> 16) & 0x1f; - r1_name = find_reg_info(r1)->name; - fprintf_fn(stream, "%s", r1_name); - break; - } - case '2': { - uint8_t r2; - const char *r2_name; - r2 = (op >> 11) & 0x1f; - r2_name = find_reg_info(r2)->name; - fprintf_fn(stream, "%s", r2_name); - break; - } - case 'c': { - uint8_t csr; - const Lm32CsrInfo *info; - csr = (op >> 21) & 0x1f; - info = find_csr_info(csr); - if (info) { - fprintf_fn(stream, "%s", info->name); - } else { - fprintf_fn(stream, "0x%x", csr); - } - break; - } - case 'u': { - uint16_t u16; - u16 = op & 0xffff; - fprintf_fn(stream, "0x%x", u16); - break; - } - case 's': { - int16_t s16; - s16 = (int16_t)(op & 0xffff); - fprintf_fn(stream, "%d", s16); - break; - } - case 'r': { - uint32_t rela; - rela = memaddr + (((int16_t)(op & 0xffff)) << 2); - fprintf_fn(stream, "%x", rela); - break; - } - case 'R': { - uint32_t rela; - int32_t imm26; - imm26 = (int32_t)((op & 0x3ffffff) << 6) >> 4; - rela = memaddr + imm26; - fprintf_fn(stream, "%x", rela); - break; - } - case 'h': { - uint8_t u5; - u5 = (op & 0x1f); - fprintf_fn(stream, "%d", u5); - break; - } - default: - break; - } - } else { - fprintf_fn(stream, "%c", *args_fmt); - } - args_fmt++; - } - } else { - fprintf_fn(stream, ".word 0x%x", op); - } - - return 4; -} diff --git a/disas/meson.build b/disas/meson.build index 39a5475ff6..449f99e1de 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -9,7 +9,6 @@ common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c')) common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c')) common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c')) common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c')) -common_ss.add(when: 'CONFIG_LM32_DIS', if_true: files('lm32.c')) common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c')) common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c')) common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c')) diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 7d34da9f68..1199fe93c0 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -198,14 +198,6 @@ from Linux upstream kernel, declare it deprecated. System emulator CPUS -------------------- -``lm32`` CPUs (since 5.2.0) -''''''''''''''''''''''''''' - -The ``lm32`` guest CPU support is deprecated and will be removed in -a future version of QEMU. The only public user of this architecture -was the milkymist project, which has been dead for years; there was -never an upstream Linux port. - ``unicore32`` CPUs (since 5.2.0) '''''''''''''''''''''''''''''''' diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst index 51a79b39cb..4915bc3f63 100644 --- a/docs/system/removed-features.rst +++ b/docs/system/removed-features.rst @@ -298,6 +298,13 @@ Nobody was using this CPU emulation in QEMU, and there were no test images available to make sure that the code is still working, so it has been removed without replacement. +``lm32`` CPUs (removed in 6.1.0) +'''''''''''''''''''''''''''''''' + +The only public user of this architecture was the milkymist project, +which has been dead for years; there was never an upstream Linux +port. Removed without replacement. + System emulator machines ------------------------ diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 60df67d441..9b4cbf4f98 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -152,7 +152,7 @@ static FloatParts parts_default_nan(float_status *status) /* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V, * S390, SH4, TriCore, and Xtensa. I cannot find documentation * for Unicore32; the choice from the original commit is unchanged. - * Our other supported targets, CRIS, LM32, and Nios2, + * Our other supported targets, CRIS, Nios2, and Tile, * do not have floating-point. */ if (snan_bit_is_one(status)) { diff --git a/hw/Kconfig b/hw/Kconfig index 559b7636f4..10a48d1492 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -47,7 +47,6 @@ source avr/Kconfig source cris/Kconfig source hppa/Kconfig source i386/Kconfig -source lm32/Kconfig source m68k/Kconfig source microblaze/Kconfig source mips/Kconfig diff --git a/hw/audio/meson.build b/hw/audio/meson.build index 32c42bdebe..e48a9fc73d 100644 --- a/hw/audio/meson.build +++ b/hw/audio/meson.build @@ -7,7 +7,6 @@ softmmu_ss.add(when: 'CONFIG_ES1370', if_true: files('es1370.c')) softmmu_ss.add(when: 'CONFIG_GUS', if_true: files('gus.c', 'gusemu_hal.c', 'gusemu_mixer.c')) softmmu_ss.add(when: 'CONFIG_HDA', if_true: files('intel-hda.c', 'hda-codec.c')) softmmu_ss.add(when: 'CONFIG_MARVELL_88W8618', if_true: files('marvell_88w8618.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-ac97.c')) softmmu_ss.add(when: 'CONFIG_PCSPK', if_true: files('pcspk.c')) softmmu_ss.add(when: 'CONFIG_PL041', if_true: files('pl041.c', 'lm4549.c')) softmmu_ss.add(when: 'CONFIG_SB16', if_true: files('sb16.c')) diff --git a/hw/audio/milkymist-ac97.c b/hw/audio/milkymist-ac97.c deleted file mode 100644 index 7d2e057038..0000000000 --- a/hw/audio/milkymist-ac97.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * QEMU model of the Milkymist System Controller. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/ac97.pdf - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "audio/audio.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - R_AC97_CTRL = 0, - R_AC97_ADDR, - R_AC97_DATAOUT, - R_AC97_DATAIN, - R_D_CTRL, - R_D_ADDR, - R_D_REMAINING, - R_RESERVED, - R_U_CTRL, - R_U_ADDR, - R_U_REMAINING, - R_MAX -}; - -enum { - AC97_CTRL_RQEN = (1<<0), - AC97_CTRL_WRITE = (1<<1), -}; - -enum { - CTRL_EN = (1<<0), -}; - -#define TYPE_MILKYMIST_AC97 "milkymist-ac97" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistAC97State, MILKYMIST_AC97) - -struct MilkymistAC97State { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - - QEMUSoundCard card; - SWVoiceIn *voice_in; - SWVoiceOut *voice_out; - - uint32_t regs[R_MAX]; - - qemu_irq crrequest_irq; - qemu_irq crreply_irq; - qemu_irq dmar_irq; - qemu_irq dmaw_irq; -}; - -static void update_voices(MilkymistAC97State *s) -{ - if (s->regs[R_D_CTRL] & CTRL_EN) { - AUD_set_active_out(s->voice_out, 1); - } else { - AUD_set_active_out(s->voice_out, 0); - } - - if (s->regs[R_U_CTRL] & CTRL_EN) { - AUD_set_active_in(s->voice_in, 1); - } else { - AUD_set_active_in(s->voice_in, 0); - } -} - -static uint64_t ac97_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistAC97State *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_AC97_CTRL: - case R_AC97_ADDR: - case R_AC97_DATAOUT: - case R_AC97_DATAIN: - case R_D_CTRL: - case R_D_ADDR: - case R_D_REMAINING: - case R_U_CTRL: - case R_U_ADDR: - case R_U_REMAINING: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_ac97: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_ac97_memory_read(addr << 2, r); - - return r; -} - -static void ac97_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistAC97State *s = opaque; - - trace_milkymist_ac97_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_AC97_CTRL: - /* always raise an IRQ according to the direction */ - if (value & AC97_CTRL_RQEN) { - if (value & AC97_CTRL_WRITE) { - trace_milkymist_ac97_pulse_irq_crrequest(); - qemu_irq_pulse(s->crrequest_irq); - } else { - trace_milkymist_ac97_pulse_irq_crreply(); - qemu_irq_pulse(s->crreply_irq); - } - } - - /* RQEN is self clearing */ - s->regs[addr] = value & ~AC97_CTRL_RQEN; - break; - case R_D_CTRL: - case R_U_CTRL: - s->regs[addr] = value; - update_voices(s); - break; - case R_AC97_ADDR: - case R_AC97_DATAOUT: - case R_AC97_DATAIN: - case R_D_ADDR: - case R_D_REMAINING: - case R_U_ADDR: - case R_U_REMAINING: - s->regs[addr] = value; - break; - - default: - error_report("milkymist_ac97: write access to unknown register 0x" - TARGET_FMT_plx, addr); - break; - } - -} - -static const MemoryRegionOps ac97_mmio_ops = { - .read = ac97_read, - .write = ac97_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ac97_in_cb(void *opaque, int avail_b) -{ - MilkymistAC97State *s = opaque; - uint8_t buf[4096]; - uint32_t remaining = s->regs[R_U_REMAINING]; - int temp = MIN(remaining, avail_b); - uint32_t addr = s->regs[R_U_ADDR]; - int transferred = 0; - - trace_milkymist_ac97_in_cb(avail_b, remaining); - - /* prevent from raising an IRQ */ - if (temp == 0) { - return; - } - - while (temp) { - int acquired, to_copy; - - to_copy = MIN(temp, sizeof(buf)); - acquired = AUD_read(s->voice_in, buf, to_copy); - if (!acquired) { - break; - } - - cpu_physical_memory_write(addr, buf, acquired); - - temp -= acquired; - addr += acquired; - transferred += acquired; - } - - trace_milkymist_ac97_in_cb_transferred(transferred); - - s->regs[R_U_ADDR] = addr; - s->regs[R_U_REMAINING] -= transferred; - - if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) { - trace_milkymist_ac97_pulse_irq_dmaw(); - qemu_irq_pulse(s->dmaw_irq); - } -} - -static void ac97_out_cb(void *opaque, int free_b) -{ - MilkymistAC97State *s = opaque; - uint8_t buf[4096]; - uint32_t remaining = s->regs[R_D_REMAINING]; - int temp = MIN(remaining, free_b); - uint32_t addr = s->regs[R_D_ADDR]; - int transferred = 0; - - trace_milkymist_ac97_out_cb(free_b, remaining); - - /* prevent from raising an IRQ */ - if (temp == 0) { - return; - } - - while (temp) { - int copied, to_copy; - - to_copy = MIN(temp, sizeof(buf)); - cpu_physical_memory_read(addr, buf, to_copy); - copied = AUD_write(s->voice_out, buf, to_copy); - if (!copied) { - break; - } - temp -= copied; - addr += copied; - transferred += copied; - } - - trace_milkymist_ac97_out_cb_transferred(transferred); - - s->regs[R_D_ADDR] = addr; - s->regs[R_D_REMAINING] -= transferred; - - if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) { - trace_milkymist_ac97_pulse_irq_dmar(); - qemu_irq_pulse(s->dmar_irq); - } -} - -static void milkymist_ac97_reset(DeviceState *d) -{ - MilkymistAC97State *s = MILKYMIST_AC97(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - AUD_set_active_in(s->voice_in, 0); - AUD_set_active_out(s->voice_out, 0); -} - -static int ac97_post_load(void *opaque, int version_id) -{ - MilkymistAC97State *s = opaque; - - update_voices(s); - - return 0; -} - -static void milkymist_ac97_init(Object *obj) -{ - MilkymistAC97State *s = MILKYMIST_AC97(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(dev, &s->crrequest_irq); - sysbus_init_irq(dev, &s->crreply_irq); - sysbus_init_irq(dev, &s->dmar_irq); - sysbus_init_irq(dev, &s->dmaw_irq); - - memory_region_init_io(&s->regs_region, obj, &ac97_mmio_ops, s, - "milkymist-ac97", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); -} - -static void milkymist_ac97_realize(DeviceState *dev, Error **errp) -{ - MilkymistAC97State *s = MILKYMIST_AC97(dev); - struct audsettings as; - - AUD_register_card("Milkymist AC'97", &s->card); - - as.freq = 48000; - as.nchannels = 2; - as.fmt = AUDIO_FORMAT_S16; - as.endianness = 1; - - s->voice_in = AUD_open_in(&s->card, s->voice_in, - "mm_ac97.in", s, ac97_in_cb, &as); - s->voice_out = AUD_open_out(&s->card, s->voice_out, - "mm_ac97.out", s, ac97_out_cb, &as); -} - -static const VMStateDescription vmstate_milkymist_ac97 = { - .name = "milkymist-ac97", - .version_id = 1, - .minimum_version_id = 1, - .post_load = ac97_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_ac97_properties[] = { - DEFINE_AUDIO_PROPERTIES(MilkymistAC97State, card), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_ac97_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_ac97_realize; - dc->reset = milkymist_ac97_reset; - dc->vmsd = &vmstate_milkymist_ac97; - device_class_set_props(dc, milkymist_ac97_properties); -} - -static const TypeInfo milkymist_ac97_info = { - .name = TYPE_MILKYMIST_AC97, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistAC97State), - .instance_init = milkymist_ac97_init, - .class_init = milkymist_ac97_class_init, -}; - -static void milkymist_ac97_register_types(void) -{ - type_register_static(&milkymist_ac97_info); -} - -type_init(milkymist_ac97_register_types) diff --git a/hw/audio/trace-events b/hw/audio/trace-events index 60556b4a97..432e10712f 100644 --- a/hw/audio/trace-events +++ b/hw/audio/trace-events @@ -6,18 +6,6 @@ cs4231_mem_readl_reg(uint32_t reg, uint32_t ret) "read reg %d: 0x%08x" cs4231_mem_writel_reg(uint32_t reg, uint32_t old, uint32_t val) "write reg %d: 0x%08x -> 0x%08x" cs4231_mem_writel_dreg(uint32_t reg, uint32_t old, uint32_t val) "write dreg %d: 0x%02x -> 0x%02x" -# milkymist-ac97.c -milkymist_ac97_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_ac97_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_ac97_pulse_irq_crrequest(void) "Pulse IRQ CR request" -milkymist_ac97_pulse_irq_crreply(void) "Pulse IRQ CR reply" -milkymist_ac97_pulse_irq_dmaw(void) "Pulse IRQ DMA write" -milkymist_ac97_pulse_irq_dmar(void) "Pulse IRQ DMA read" -milkymist_ac97_in_cb(int avail, uint32_t remaining) "avail %d remaining %u" -milkymist_ac97_in_cb_transferred(int transferred) "transferred %d" -milkymist_ac97_out_cb(int free, uint32_t remaining) "free %d remaining %u" -milkymist_ac97_out_cb_transferred(int transferred) "transferred %d" - # hda-codec.c hda_audio_running(const char *stream, int nr, bool running) "st %s, nr %d, run %d" hda_audio_format(const char *stream, int chan, const char *fmt, int freq) "st %s, %d x %s @ %d Hz" diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c deleted file mode 100644 index ce30279650..0000000000 --- a/hw/char/lm32_juart.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * LatticeMico32 JTAG UART model. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "qemu/module.h" -#include "trace.h" -#include "chardev/char-fe.h" - -#include "hw/char/lm32_juart.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-properties-system.h" -#include "qom/object.h" - -enum { - LM32_JUART_MIN_SAVE_VERSION = 0, - LM32_JUART_CURRENT_SAVE_VERSION = 0, - LM32_JUART_MAX_SAVE_VERSION = 0, -}; - -enum { - JTX_FULL = (1<<8), -}; - -enum { - JRX_FULL = (1<<8), -}; - -OBJECT_DECLARE_SIMPLE_TYPE(LM32JuartState, LM32_JUART) - -struct LM32JuartState { - SysBusDevice parent_obj; - - CharBackend chr; - - uint32_t jtx; - uint32_t jrx; -}; - -uint32_t lm32_juart_get_jtx(DeviceState *d) -{ - LM32JuartState *s = LM32_JUART(d); - - trace_lm32_juart_get_jtx(s->jtx); - return s->jtx; -} - -uint32_t lm32_juart_get_jrx(DeviceState *d) -{ - LM32JuartState *s = LM32_JUART(d); - - trace_lm32_juart_get_jrx(s->jrx); - return s->jrx; -} - -void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx) -{ - LM32JuartState *s = LM32_JUART(d); - unsigned char ch = jtx & 0xff; - - trace_lm32_juart_set_jtx(s->jtx); - - s->jtx = jtx; - /* XXX this blocks entire thread. Rewrite to use - * qemu_chr_fe_write and background I/O callbacks */ - qemu_chr_fe_write_all(&s->chr, &ch, 1); -} - -void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx) -{ - LM32JuartState *s = LM32_JUART(d); - - trace_lm32_juart_set_jrx(s->jrx); - s->jrx &= ~JRX_FULL; -} - -static void juart_rx(void *opaque, const uint8_t *buf, int size) -{ - LM32JuartState *s = opaque; - - s->jrx = *buf | JRX_FULL; -} - -static int juart_can_rx(void *opaque) -{ - LM32JuartState *s = opaque; - - return !(s->jrx & JRX_FULL); -} - -static void juart_event(void *opaque, QEMUChrEvent event) -{ -} - -static void juart_reset(DeviceState *d) -{ - LM32JuartState *s = LM32_JUART(d); - - s->jtx = 0; - s->jrx = 0; -} - -static void lm32_juart_realize(DeviceState *dev, Error **errp) -{ - LM32JuartState *s = LM32_JUART(dev); - - qemu_chr_fe_set_handlers(&s->chr, juart_can_rx, juart_rx, - juart_event, NULL, s, NULL, true); -} - -static const VMStateDescription vmstate_lm32_juart = { - .name = "lm32-juart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(jtx, LM32JuartState), - VMSTATE_UINT32(jrx, LM32JuartState), - VMSTATE_END_OF_LIST() - } -}; - -static Property lm32_juart_properties[] = { - DEFINE_PROP_CHR("chardev", LM32JuartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void lm32_juart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = juart_reset; - dc->vmsd = &vmstate_lm32_juart; - device_class_set_props(dc, lm32_juart_properties); - dc->realize = lm32_juart_realize; -} - -static const TypeInfo lm32_juart_info = { - .name = TYPE_LM32_JUART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32JuartState), - .class_init = lm32_juart_class_init, -}; - -static void lm32_juart_register_types(void) -{ - type_register_static(&lm32_juart_info); -} - -type_init(lm32_juart_register_types) diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c deleted file mode 100644 index d8e0331311..0000000000 --- a/hw/char/lm32_uart.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * QEMU model of the LatticeMico32 UART block. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://www.latticesemi.com/documents/mico32uart.pdf - */ - - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-properties-system.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "chardev/char-fe.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - R_RXTX = 0, - R_IER, - R_IIR, - R_LCR, - R_MCR, - R_LSR, - R_MSR, - R_DIV, - R_MAX -}; - -enum { - IER_RBRI = (1<<0), - IER_THRI = (1<<1), - IER_RLSI = (1<<2), - IER_MSI = (1<<3), -}; - -enum { - IIR_STAT = (1<<0), - IIR_ID0 = (1<<1), - IIR_ID1 = (1<<2), -}; - -enum { - LCR_WLS0 = (1<<0), - LCR_WLS1 = (1<<1), - LCR_STB = (1<<2), - LCR_PEN = (1<<3), - LCR_EPS = (1<<4), - LCR_SP = (1<<5), - LCR_SB = (1<<6), -}; - -enum { - MCR_DTR = (1<<0), - MCR_RTS = (1<<1), -}; - -enum { - LSR_DR = (1<<0), - LSR_OE = (1<<1), - LSR_PE = (1<<2), - LSR_FE = (1<<3), - LSR_BI = (1<<4), - LSR_THRE = (1<<5), - LSR_TEMT = (1<<6), -}; - -enum { - MSR_DCTS = (1<<0), - MSR_DDSR = (1<<1), - MSR_TERI = (1<<2), - MSR_DDCD = (1<<3), - MSR_CTS = (1<<4), - MSR_DSR = (1<<5), - MSR_RI = (1<<6), - MSR_DCD = (1<<7), -}; - -#define TYPE_LM32_UART "lm32-uart" -OBJECT_DECLARE_SIMPLE_TYPE(LM32UartState, LM32_UART) - -struct LM32UartState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - CharBackend chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; -}; - -static void uart_update_irq(LM32UartState *s) -{ - unsigned int irq; - - if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) - && (s->regs[R_IER] & IER_RLSI)) { - irq = 1; - s->regs[R_IIR] = IIR_ID1 | IIR_ID0; - } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) { - irq = 1; - s->regs[R_IIR] = IIR_ID1; - } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) { - irq = 1; - s->regs[R_IIR] = IIR_ID0; - } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) { - irq = 1; - s->regs[R_IIR] = 0; - } else { - irq = 0; - s->regs[R_IIR] = IIR_STAT; - } - - trace_lm32_uart_irq_state(irq); - qemu_set_irq(s->irq, irq); -} - -static uint64_t uart_read(void *opaque, hwaddr addr, - unsigned size) -{ - LM32UartState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_RXTX: - r = s->regs[R_RXTX]; - s->regs[R_LSR] &= ~LSR_DR; - uart_update_irq(s); - qemu_chr_fe_accept_input(&s->chr); - break; - case R_IIR: - case R_LSR: - case R_MSR: - r = s->regs[addr]; - break; - case R_IER: - case R_LCR: - case R_MCR: - case R_DIV: - error_report("lm32_uart: read access to write only register 0x" - TARGET_FMT_plx, addr << 2); - break; - default: - error_report("lm32_uart: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_lm32_uart_memory_read(addr << 2, r); - return r; -} - -static void uart_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - LM32UartState *s = opaque; - unsigned char ch = value; - - trace_lm32_uart_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_RXTX: - /* XXX this blocks entire thread. Rewrite to use - * qemu_chr_fe_write and background I/O callbacks */ - qemu_chr_fe_write_all(&s->chr, &ch, 1); - break; - case R_IER: - case R_LCR: - case R_MCR: - case R_DIV: - s->regs[addr] = value; - break; - case R_IIR: - case R_LSR: - case R_MSR: - error_report("lm32_uart: write access to read only register 0x" - TARGET_FMT_plx, addr << 2); - break; - default: - error_report("lm32_uart: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - uart_update_irq(s); -} - -static const MemoryRegionOps uart_ops = { - .read = uart_read, - .write = uart_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static void uart_rx(void *opaque, const uint8_t *buf, int size) -{ - LM32UartState *s = opaque; - - if (s->regs[R_LSR] & LSR_DR) { - s->regs[R_LSR] |= LSR_OE; - } - - s->regs[R_LSR] |= LSR_DR; - s->regs[R_RXTX] = *buf; - - uart_update_irq(s); -} - -static int uart_can_rx(void *opaque) -{ - LM32UartState *s = opaque; - - return !(s->regs[R_LSR] & LSR_DR); -} - -static void uart_event(void *opaque, QEMUChrEvent event) -{ -} - -static void uart_reset(DeviceState *d) -{ - LM32UartState *s = LM32_UART(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* defaults */ - s->regs[R_LSR] = LSR_THRE | LSR_TEMT; -} - -static void lm32_uart_init(Object *obj) -{ - LM32UartState *s = LM32_UART(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->iomem, obj, &uart_ops, s, - "uart", R_MAX * 4); - sysbus_init_mmio(dev, &s->iomem); -} - -static void lm32_uart_realize(DeviceState *dev, Error **errp) -{ - LM32UartState *s = LM32_UART(dev); - - qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, - uart_event, NULL, s, NULL, true); -} - -static const VMStateDescription vmstate_lm32_uart = { - .name = "lm32-uart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property lm32_uart_properties[] = { - DEFINE_PROP_CHR("chardev", LM32UartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void lm32_uart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = uart_reset; - dc->vmsd = &vmstate_lm32_uart; - device_class_set_props(dc, lm32_uart_properties); - dc->realize = lm32_uart_realize; -} - -static const TypeInfo lm32_uart_info = { - .name = TYPE_LM32_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32UartState), - .instance_init = lm32_uart_init, - .class_init = lm32_uart_class_init, -}; - -static void lm32_uart_register_types(void) -{ - type_register_static(&lm32_uart_info); -} - -type_init(lm32_uart_register_types) diff --git a/hw/char/meson.build b/hw/char/meson.build index da5bb8b762..31bf506398 100644 --- a/hw/char/meson.build +++ b/hw/char/meson.build @@ -8,9 +8,6 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_serial.c')) softmmu_ss.add(when: 'CONFIG_IPACK', if_true: files('ipoctal232.c')) softmmu_ss.add(when: 'CONFIG_ISA_BUS', if_true: files('parallel-isa.c')) softmmu_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugcon.c')) -softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_juart.c')) -softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_uart.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-uart.c')) softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_uart.c')) softmmu_ss.add(when: 'CONFIG_PARALLEL', if_true: files('parallel.c')) softmmu_ss.add(when: 'CONFIG_PL011', if_true: files('pl011.c')) diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c deleted file mode 100644 index cb1b3470ad..0000000000 --- a/hw/char/milkymist-uart.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * QEMU model of the Milkymist UART block. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/uart.pdf - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-properties-system.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "chardev/char-fe.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - R_RXTX = 0, - R_DIV, - R_STAT, - R_CTRL, - R_DBG, - R_MAX -}; - -enum { - STAT_THRE = (1<<0), - STAT_RX_EVT = (1<<1), - STAT_TX_EVT = (1<<2), -}; - -enum { - CTRL_RX_IRQ_EN = (1<<0), - CTRL_TX_IRQ_EN = (1<<1), - CTRL_THRU_EN = (1<<2), -}; - -enum { - DBG_BREAK_EN = (1<<0), -}; - -#define TYPE_MILKYMIST_UART "milkymist-uart" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistUartState, MILKYMIST_UART) - -struct MilkymistUartState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - CharBackend chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; -}; - -static void uart_update_irq(MilkymistUartState *s) -{ - int rx_event = s->regs[R_STAT] & STAT_RX_EVT; - int tx_event = s->regs[R_STAT] & STAT_TX_EVT; - int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN; - int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN; - - if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) { - trace_milkymist_uart_raise_irq(); - qemu_irq_raise(s->irq); - } else { - trace_milkymist_uart_lower_irq(); - qemu_irq_lower(s->irq); - } -} - -static uint64_t uart_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistUartState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_RXTX: - r = s->regs[addr]; - break; - case R_DIV: - case R_STAT: - case R_CTRL: - case R_DBG: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_uart: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_uart_memory_read(addr << 2, r); - - return r; -} - -static void uart_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistUartState *s = opaque; - unsigned char ch = value; - - trace_milkymist_uart_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_RXTX: - qemu_chr_fe_write_all(&s->chr, &ch, 1); - s->regs[R_STAT] |= STAT_TX_EVT; - break; - case R_DIV: - case R_CTRL: - case R_DBG: - s->regs[addr] = value; - break; - - case R_STAT: - /* write one to clear bits */ - s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT)); - qemu_chr_fe_accept_input(&s->chr); - break; - - default: - error_report("milkymist_uart: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - uart_update_irq(s); -} - -static const MemoryRegionOps uart_mmio_ops = { - .read = uart_read, - .write = uart_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void uart_rx(void *opaque, const uint8_t *buf, int size) -{ - MilkymistUartState *s = opaque; - - assert(!(s->regs[R_STAT] & STAT_RX_EVT)); - - s->regs[R_STAT] |= STAT_RX_EVT; - s->regs[R_RXTX] = *buf; - - uart_update_irq(s); -} - -static int uart_can_rx(void *opaque) -{ - MilkymistUartState *s = opaque; - - return !(s->regs[R_STAT] & STAT_RX_EVT); -} - -static void uart_event(void *opaque, QEMUChrEvent event) -{ -} - -static void milkymist_uart_reset(DeviceState *d) -{ - MilkymistUartState *s = MILKYMIST_UART(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* THRE is always set */ - s->regs[R_STAT] = STAT_THRE; -} - -static void milkymist_uart_realize(DeviceState *dev, Error **errp) -{ - MilkymistUartState *s = MILKYMIST_UART(dev); - - qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, - uart_event, NULL, s, NULL, true); -} - -static void milkymist_uart_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - MilkymistUartState *s = MILKYMIST_UART(obj); - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init_io(&s->regs_region, OBJECT(s), &uart_mmio_ops, s, - "milkymist-uart", R_MAX * 4); - sysbus_init_mmio(sbd, &s->regs_region); -} - -static const VMStateDescription vmstate_milkymist_uart = { - .name = "milkymist-uart", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_uart_properties[] = { - DEFINE_PROP_CHR("chardev", MilkymistUartState, chr), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_uart_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_uart_realize; - dc->reset = milkymist_uart_reset; - dc->vmsd = &vmstate_milkymist_uart; - device_class_set_props(dc, milkymist_uart_properties); -} - -static const TypeInfo milkymist_uart_info = { - .name = TYPE_MILKYMIST_UART, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistUartState), - .instance_init = milkymist_uart_init, - .class_init = milkymist_uart_class_init, -}; - -static void milkymist_uart_register_types(void) -{ - type_register_static(&milkymist_uart_info); -} - -type_init(milkymist_uart_register_types) diff --git a/hw/char/trace-events b/hw/char/trace-events index 76d52938ea..76d303b953 100644 --- a/hw/char/trace-events +++ b/hw/char/trace-events @@ -35,23 +35,6 @@ grlib_apbuart_event(int event) "event:%d" grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x" grlib_apbuart_readl_unknown(uint64_t addr) "addr 0x%"PRIx64 -# lm32_juart.c -lm32_juart_get_jtx(uint32_t value) "jtx 0x%08x" -lm32_juart_set_jtx(uint32_t value) "jtx 0x%08x" -lm32_juart_get_jrx(uint32_t value) "jrx 0x%08x" -lm32_juart_set_jrx(uint32_t value) "jrx 0x%08x" - -# lm32_uart.c -lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_uart_irq_state(int level) "irq state %d" - -# milkymist-uart.c -milkymist_uart_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_uart_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_uart_raise_irq(void) "Raise IRQ" -milkymist_uart_lower_irq(void) "Lower IRQ" - # escc.c escc_put_queue(char channel, int b) "channel %c put: 0x%02x" escc_get_queue(char channel, int val) "channel %c get 0x%02x" diff --git a/hw/display/Kconfig b/hw/display/Kconfig index ca46b5830e..a2306b67d8 100644 --- a/hw/display/Kconfig +++ b/hw/display/Kconfig @@ -72,10 +72,6 @@ config BLIZZARD config FRAMEBUFFER bool -config MILKYMIST_TMU2 - bool - depends on OPENGL && X11 - config SM501 bool select I2C diff --git a/hw/display/meson.build b/hw/display/meson.build index 612cd6582d..aaf797c5e9 100644 --- a/hw/display/meson.build +++ b/hw/display/meson.build @@ -48,7 +48,6 @@ endif softmmu_ss.add(when: 'CONFIG_DPCD', if_true: files('dpcd.c')) softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx_dp.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-vgafb.c')) softmmu_ss.add(when: 'CONFIG_ARTIST', if_true: files('artist.c')) softmmu_ss.add(when: [pixman, 'CONFIG_ATI_VGA'], if_true: files('ati.c', 'ati_2d.c', 'ati_dbg.c')) @@ -94,7 +93,6 @@ if config_all_devices.has_key('CONFIG_VIRTIO_VGA') hw_display_modules += {'virtio-vga-gl': virtio_vga_gl_ss} endif -specific_ss.add(when: [x11, opengl, 'CONFIG_MILKYMIST_TMU2'], if_true: files('milkymist-tmu2.c')) specific_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_lcdc.c')) modules += { 'hw-display': hw_display_modules } diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c deleted file mode 100644 index 02a28c807b..0000000000 --- a/hw/display/milkymist-tmu2.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * QEMU model of the Milkymist texture mapping unit. - * - * Copyright (c) 2010 Michael Walle - * Copyright (c) 2010 Sebastien Bourdeauducq - * - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/tmu2.pdf - * - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qapi/error.h" -#include "hw/display/milkymist_tmu2.h" - -#include -#include -#include -#include "qom/object.h" - -enum { - R_CTL = 0, - R_HMESHLAST, - R_VMESHLAST, - R_BRIGHTNESS, - R_CHROMAKEY, - R_VERTICESADDR, - R_TEXFBUF, - R_TEXHRES, - R_TEXVRES, - R_TEXHMASK, - R_TEXVMASK, - R_DSTFBUF, - R_DSTHRES, - R_DSTVRES, - R_DSTHOFFSET, - R_DSTVOFFSET, - R_DSTSQUAREW, - R_DSTSQUAREH, - R_ALPHA, - R_MAX -}; - -enum { - CTL_START_BUSY = (1<<0), - CTL_CHROMAKEY = (1<<1), -}; - -enum { - MAX_BRIGHTNESS = 63, - MAX_ALPHA = 63, -}; - -enum { - MESH_MAXSIZE = 128, -}; - -struct vertex { - int x; - int y; -} QEMU_PACKED; - -#define TYPE_MILKYMIST_TMU2 "milkymist-tmu2" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistTMU2State, MILKYMIST_TMU2) - -struct MilkymistTMU2State { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - Chardev *chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; - - Display *dpy; - GLXFBConfig glx_fb_config; - GLXContext glx_context; -}; - -static const int glx_fbconfig_attr[] = { - GLX_GREEN_SIZE, 5, - GLX_GREEN_SIZE, 6, - GLX_BLUE_SIZE, 5, - None -}; - -static int tmu2_glx_init(MilkymistTMU2State *s) -{ - GLXFBConfig *configs; - int nelements; - - s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */ - if (s->dpy == NULL) { - return 1; - } - - configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements); - if (configs == NULL) { - return 1; - } - - s->glx_fb_config = *configs; - XFree(configs); - - /* FIXME: call glXDestroyContext() */ - s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config, - GLX_RGBA_TYPE, NULL, 1); - if (s->glx_context == NULL) { - return 1; - } - - return 0; -} - -static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres, - int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh) -{ - int x, y; - int x0, y0, x1, y1; - int u0, v0, u1, v1, u2, v2, u3, v3; - double xscale = 1.0 / ((double)(64 * texhres)); - double yscale = 1.0 / ((double)(64 * texvres)); - - glLoadIdentity(); - glTranslatef(ho, vo, 0); - glEnable(GL_TEXTURE_2D); - glBegin(GL_QUADS); - - for (y = 0; y < vmeshlast; y++) { - y0 = y * sh; - y1 = y0 + sh; - for (x = 0; x < hmeshlast; x++) { - x0 = x * sw; - x1 = x0 + sw; - - u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x); - v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y); - u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x); - v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y); - u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x); - v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y); - u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x); - v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y); - - glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale); - glVertex3i(x0, y0, 0); - glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale); - glVertex3i(x1, y0, 0); - glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale); - glVertex3i(x1, y1, 0); - glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale); - glVertex3i(x0, y1, 0); - } - } - - glEnd(); -} - -static void tmu2_start(MilkymistTMU2State *s) -{ - int pbuffer_attrib[6] = { - GLX_PBUFFER_WIDTH, - 0, - GLX_PBUFFER_HEIGHT, - 0, - GLX_PRESERVED_CONTENTS, - True - }; - - GLXPbuffer pbuffer; - GLuint texture; - void *fb; - hwaddr fb_len; - void *mesh; - hwaddr mesh_len; - float m; - - trace_milkymist_tmu2_start(); - - /* Create and set up a suitable OpenGL context */ - pbuffer_attrib[1] = s->regs[R_DSTHRES]; - pbuffer_attrib[3] = s->regs[R_DSTVRES]; - pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib); - glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context); - - /* Fixup endianness. TODO: would it work on BE hosts? */ - glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); - glPixelStorei(GL_PACK_SWAP_BYTES, 1); - - /* Row alignment */ - glPixelStorei(GL_UNPACK_ALIGNMENT, 2); - glPixelStorei(GL_PACK_ALIGNMENT, 2); - - /* Read the QEMU source framebuffer into an OpenGL texture */ - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - fb_len = 2ULL * s->regs[R_TEXHRES] * s->regs[R_TEXVRES]; - fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, false); - if (fb == NULL) { - glDeleteTextures(1, &texture); - glXMakeContextCurrent(s->dpy, None, None, NULL); - glXDestroyPbuffer(s->dpy, pbuffer); - return; - } - glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES], - 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb); - cpu_physical_memory_unmap(fb, fb_len, 0, fb_len); - - /* Set up texturing options */ - /* WARNING: - * Many cases of TMU2 masking are not supported by OpenGL. - * We only implement the most common ones: - * - full bilinear filtering vs. nearest texel - * - texture clamping vs. texture wrapping - */ - if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - } - if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - - /* Translucency and decay */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f; - glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f); - - /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */ - fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES]; - fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, false); - if (fb == NULL) { - glDeleteTextures(1, &texture); - glXMakeContextCurrent(s->dpy, None, None, NULL); - glXDestroyPbuffer(s->dpy, pbuffer); - return; - } - - glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB, - GL_UNSIGNED_SHORT_5_6_5, fb); - cpu_physical_memory_unmap(fb, fb_len, 0, fb_len); - glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - - /* Map the texture */ - mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex); - mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, false); - if (mesh == NULL) { - glDeleteTextures(1, &texture); - glXMakeContextCurrent(s->dpy, None, None, NULL); - glXDestroyPbuffer(s->dpy, pbuffer); - return; - } - - tmu2_gl_map((struct vertex *)mesh, - s->regs[R_TEXHRES], s->regs[R_TEXVRES], - s->regs[R_HMESHLAST], s->regs[R_VMESHLAST], - s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET], - s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]); - cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len); - - /* Write back the OpenGL framebuffer to the QEMU framebuffer */ - fb_len = 2ULL * s->regs[R_DSTHRES] * s->regs[R_DSTVRES]; - fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, true); - if (fb == NULL) { - glDeleteTextures(1, &texture); - glXMakeContextCurrent(s->dpy, None, None, NULL); - glXDestroyPbuffer(s->dpy, pbuffer); - return; - } - - glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB, - GL_UNSIGNED_SHORT_5_6_5, fb); - cpu_physical_memory_unmap(fb, fb_len, 1, fb_len); - - /* Free OpenGL allocs */ - glDeleteTextures(1, &texture); - glXMakeContextCurrent(s->dpy, None, None, NULL); - glXDestroyPbuffer(s->dpy, pbuffer); - - s->regs[R_CTL] &= ~CTL_START_BUSY; - - trace_milkymist_tmu2_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static uint64_t tmu2_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistTMU2State *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CTL: - case R_HMESHLAST: - case R_VMESHLAST: - case R_BRIGHTNESS: - case R_CHROMAKEY: - case R_VERTICESADDR: - case R_TEXFBUF: - case R_TEXHRES: - case R_TEXVRES: - case R_TEXHMASK: - case R_TEXVMASK: - case R_DSTFBUF: - case R_DSTHRES: - case R_DSTVRES: - case R_DSTHOFFSET: - case R_DSTVOFFSET: - case R_DSTSQUAREW: - case R_DSTSQUAREH: - case R_ALPHA: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_tmu2: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_tmu2_memory_read(addr << 2, r); - - return r; -} - -static void tmu2_check_registers(MilkymistTMU2State *s) -{ - if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) { - error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS); - } - - if (s->regs[R_ALPHA] > MAX_ALPHA) { - error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA); - } - - if (s->regs[R_VERTICESADDR] & 0x07) { - error_report("milkymist_tmu2: vertex mesh address has to be 64-bit " - "aligned"); - } - - if (s->regs[R_TEXFBUF] & 0x01) { - error_report("milkymist_tmu2: texture buffer address has to be " - "16-bit aligned"); - } -} - -static void tmu2_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistTMU2State *s = opaque; - - trace_milkymist_tmu2_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTL: - s->regs[addr] = value; - if (value & CTL_START_BUSY) { - tmu2_start(s); - } - break; - case R_BRIGHTNESS: - case R_HMESHLAST: - case R_VMESHLAST: - case R_CHROMAKEY: - case R_VERTICESADDR: - case R_TEXFBUF: - case R_TEXHRES: - case R_TEXVRES: - case R_TEXHMASK: - case R_TEXVMASK: - case R_DSTFBUF: - case R_DSTHRES: - case R_DSTVRES: - case R_DSTHOFFSET: - case R_DSTVOFFSET: - case R_DSTSQUAREW: - case R_DSTSQUAREH: - case R_ALPHA: - s->regs[addr] = value; - break; - - default: - error_report("milkymist_tmu2: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - tmu2_check_registers(s); -} - -static const MemoryRegionOps tmu2_mmio_ops = { - .read = tmu2_read, - .write = tmu2_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_tmu2_reset(DeviceState *d) -{ - MilkymistTMU2State *s = MILKYMIST_TMU2(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } -} - -static void milkymist_tmu2_init(Object *obj) -{ - MilkymistTMU2State *s = MILKYMIST_TMU2(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->regs_region, obj, &tmu2_mmio_ops, s, - "milkymist-tmu2", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); -} - -static void milkymist_tmu2_realize(DeviceState *dev, Error **errp) -{ - MilkymistTMU2State *s = MILKYMIST_TMU2(dev); - - if (tmu2_glx_init(s)) { - error_setg(errp, "tmu2_glx_init failed"); - } -} - -static const VMStateDescription vmstate_milkymist_tmu2 = { - .name = "milkymist-tmu2", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_tmu2_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_tmu2_realize; - dc->reset = milkymist_tmu2_reset; - dc->vmsd = &vmstate_milkymist_tmu2; -} - -static const TypeInfo milkymist_tmu2_info = { - .name = TYPE_MILKYMIST_TMU2, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistTMU2State), - .instance_init = milkymist_tmu2_init, - .class_init = milkymist_tmu2_class_init, -}; - -static void milkymist_tmu2_register_types(void) -{ - type_register_static(&milkymist_tmu2_info); -} - -type_init(milkymist_tmu2_register_types) - -DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq) -{ - DeviceState *dev; - Display *d; - GLXFBConfig *configs; - int nelements; - int ver_major, ver_minor; - - /* check that GLX will work */ - d = XOpenDisplay(NULL); - if (d == NULL) { - return NULL; - } - - if (!glXQueryVersion(d, &ver_major, &ver_minor)) { - /* - * Yeah, sometimes getting the GLX version can fail. - * Isn't X beautiful? - */ - XCloseDisplay(d); - return NULL; - } - - if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) { - printf("Your GLX version is %d.%d," - "but TMU emulation needs at least 1.3. TMU disabled.\n", - ver_major, ver_minor); - XCloseDisplay(d); - return NULL; - } - - configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements); - if (configs == NULL) { - XCloseDisplay(d); - return NULL; - } - - XFree(configs); - XCloseDisplay(d); - - dev = qdev_new(TYPE_MILKYMIST_TMU2); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); - - return dev; -} diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c deleted file mode 100644 index e2c587e2df..0000000000 --- a/hw/display/milkymist-vgafb.c +++ /dev/null @@ -1,360 +0,0 @@ - -/* - * QEMU model of the Milkymist VGA framebuffer. - * - * Copyright (c) 2010-2012 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/vgafb.pdf - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/qdev-properties.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "ui/console.h" -#include "framebuffer.h" -#include "ui/pixel_ops.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -#define BITS 8 -#include "migration/vmstate.h" -#include "milkymist-vgafb_template.h" -#define BITS 15 -#include "milkymist-vgafb_template.h" -#define BITS 16 -#include "milkymist-vgafb_template.h" -#define BITS 24 -#include "milkymist-vgafb_template.h" -#define BITS 32 -#include "milkymist-vgafb_template.h" - -enum { - R_CTRL = 0, - R_HRES, - R_HSYNC_START, - R_HSYNC_END, - R_HSCAN, - R_VRES, - R_VSYNC_START, - R_VSYNC_END, - R_VSCAN, - R_BASEADDRESS, - R_BASEADDRESS_ACT, - R_BURST_COUNT, - R_DDC, - R_SOURCE_CLOCK, - R_MAX -}; - -enum { - CTRL_RESET = (1<<0), -}; - -#define TYPE_MILKYMIST_VGAFB "milkymist-vgafb" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistVgafbState, MILKYMIST_VGAFB) - -struct MilkymistVgafbState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - MemoryRegionSection fbsection; - QemuConsole *con; - - int invalidate; - uint32_t fb_offset; - uint32_t fb_mask; - - uint32_t regs[R_MAX]; -}; - -static int vgafb_enabled(MilkymistVgafbState *s) -{ - return !(s->regs[R_CTRL] & CTRL_RESET); -} - -static void vgafb_update_display(void *opaque) -{ - MilkymistVgafbState *s = opaque; - SysBusDevice *sbd; - DisplaySurface *surface = qemu_console_surface(s->con); - int src_width; - int first = 0; - int last = 0; - drawfn fn; - - if (!vgafb_enabled(s)) { - return; - } - - sbd = SYS_BUS_DEVICE(s); - int dest_width = s->regs[R_HRES]; - - switch (surface_bits_per_pixel(surface)) { - case 0: - return; - case 8: - fn = draw_line_8; - break; - case 15: - fn = draw_line_15; - dest_width *= 2; - break; - case 16: - fn = draw_line_16; - dest_width *= 2; - break; - case 24: - fn = draw_line_24; - dest_width *= 3; - break; - case 32: - fn = draw_line_32; - dest_width *= 4; - break; - default: - hw_error("milkymist_vgafb: bad color depth\n"); - break; - } - - src_width = s->regs[R_HRES] * 2; - if (s->invalidate) { - framebuffer_update_memory_section(&s->fbsection, - sysbus_address_space(sbd), - s->regs[R_BASEADDRESS] + s->fb_offset, - s->regs[R_VRES], src_width); - } - - framebuffer_update_display(surface, &s->fbsection, - s->regs[R_HRES], - s->regs[R_VRES], - src_width, - dest_width, - 0, - s->invalidate, - fn, - NULL, - &first, &last); - - if (first >= 0) { - dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1); - } - s->invalidate = 0; -} - -static void vgafb_invalidate_display(void *opaque) -{ - MilkymistVgafbState *s = opaque; - s->invalidate = 1; -} - -static void vgafb_resize(MilkymistVgafbState *s) -{ - if (!vgafb_enabled(s)) { - return; - } - - qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]); - s->invalidate = 1; -} - -static uint64_t vgafb_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistVgafbState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CTRL: - case R_HRES: - case R_HSYNC_START: - case R_HSYNC_END: - case R_HSCAN: - case R_VRES: - case R_VSYNC_START: - case R_VSYNC_END: - case R_VSCAN: - case R_BASEADDRESS: - case R_BURST_COUNT: - case R_DDC: - case R_SOURCE_CLOCK: - r = s->regs[addr]; - break; - case R_BASEADDRESS_ACT: - r = s->regs[R_BASEADDRESS]; - break; - - default: - error_report("milkymist_vgafb: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_vgafb_memory_read(addr << 2, r); - - return r; -} - -static void vgafb_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistVgafbState *s = opaque; - - trace_milkymist_vgafb_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTRL: - s->regs[addr] = value; - vgafb_resize(s); - break; - case R_HSYNC_START: - case R_HSYNC_END: - case R_HSCAN: - case R_VSYNC_START: - case R_VSYNC_END: - case R_VSCAN: - case R_BURST_COUNT: - case R_DDC: - case R_SOURCE_CLOCK: - s->regs[addr] = value; - break; - case R_BASEADDRESS: - if (value & 0x1f) { - error_report("milkymist_vgafb: framebuffer base address have to " - "be 32 byte aligned"); - break; - } - s->regs[addr] = value & s->fb_mask; - s->invalidate = 1; - break; - case R_HRES: - case R_VRES: - s->regs[addr] = value; - vgafb_resize(s); - break; - case R_BASEADDRESS_ACT: - error_report("milkymist_vgafb: write to read-only register 0x" - TARGET_FMT_plx, addr << 2); - break; - - default: - error_report("milkymist_vgafb: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps vgafb_mmio_ops = { - .read = vgafb_read, - .write = vgafb_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_vgafb_reset(DeviceState *d) -{ - MilkymistVgafbState *s = MILKYMIST_VGAFB(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* defaults */ - s->regs[R_CTRL] = CTRL_RESET; - s->regs[R_HRES] = 640; - s->regs[R_VRES] = 480; - s->regs[R_BASEADDRESS] = 0; -} - -static const GraphicHwOps vgafb_ops = { - .invalidate = vgafb_invalidate_display, - .gfx_update = vgafb_update_display, -}; - -static void milkymist_vgafb_init(Object *obj) -{ - MilkymistVgafbState *s = MILKYMIST_VGAFB(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - memory_region_init_io(&s->regs_region, OBJECT(s), &vgafb_mmio_ops, s, - "milkymist-vgafb", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); -} - -static void milkymist_vgafb_realize(DeviceState *dev, Error **errp) -{ - MilkymistVgafbState *s = MILKYMIST_VGAFB(dev); - - s->con = graphic_console_init(dev, 0, &vgafb_ops, s); -} - -static int vgafb_post_load(void *opaque, int version_id) -{ - vgafb_invalidate_display(opaque); - return 0; -} - -static const VMStateDescription vmstate_milkymist_vgafb = { - .name = "milkymist-vgafb", - .version_id = 1, - .minimum_version_id = 1, - .post_load = vgafb_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_vgafb_properties[] = { - DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0), - DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_vgafb_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = milkymist_vgafb_reset; - dc->vmsd = &vmstate_milkymist_vgafb; - device_class_set_props(dc, milkymist_vgafb_properties); - dc->realize = milkymist_vgafb_realize; -} - -static const TypeInfo milkymist_vgafb_info = { - .name = TYPE_MILKYMIST_VGAFB, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistVgafbState), - .instance_init = milkymist_vgafb_init, - .class_init = milkymist_vgafb_class_init, -}; - -static void milkymist_vgafb_register_types(void) -{ - type_register_static(&milkymist_vgafb_info); -} - -type_init(milkymist_vgafb_register_types) diff --git a/hw/display/milkymist-vgafb_template.h b/hw/display/milkymist-vgafb_template.h deleted file mode 100644 index 96137f9709..0000000000 --- a/hw/display/milkymist-vgafb_template.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * QEMU model of the Milkymist VGA framebuffer. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - */ - -#if BITS == 8 -#define COPY_PIXEL(to, r, g, b) \ - do { \ - *to = rgb_to_pixel8(r, g, b); \ - to += 1; \ - } while (0) -#elif BITS == 15 -#define COPY_PIXEL(to, r, g, b) \ - do { \ - *(uint16_t *)to = rgb_to_pixel15(r, g, b); \ - to += 2; \ - } while (0) -#elif BITS == 16 -#define COPY_PIXEL(to, r, g, b) \ - do { \ - *(uint16_t *)to = rgb_to_pixel16(r, g, b); \ - to += 2; \ - } while (0) -#elif BITS == 24 -#define COPY_PIXEL(to, r, g, b) \ - do { \ - uint32_t tmp = rgb_to_pixel24(r, g, b); \ - *(to++) = tmp & 0xff; \ - *(to++) = (tmp >> 8) & 0xff; \ - *(to++) = (tmp >> 16) & 0xff; \ - } while (0) -#elif BITS == 32 -#define COPY_PIXEL(to, r, g, b) \ - do { \ - *(uint32_t *)to = rgb_to_pixel32(r, g, b); \ - to += 4; \ - } while (0) -#else -#error unknown bit depth -#endif - -static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s, - int width, int deststep) -{ - uint16_t rgb565; - uint8_t r, g, b; - - while (width--) { - rgb565 = lduw_be_p(s); - r = ((rgb565 >> 11) & 0x1f) << 3; - g = ((rgb565 >> 5) & 0x3f) << 2; - b = ((rgb565 >> 0) & 0x1f) << 3; - COPY_PIXEL(d, r, g, b); - s += 2; - } -} - -#undef BITS -#undef COPY_PIXEL diff --git a/hw/display/trace-events b/hw/display/trace-events index 957b8ba994..9fccca18a1 100644 --- a/hw/display/trace-events +++ b/hw/display/trace-events @@ -13,16 +13,6 @@ xenfb_input_connected(void *xendev, int abs_pointer_wanted) "%p abs %d" g364fb_read(uint64_t addr, uint32_t val) "read addr=0x%"PRIx64": 0x%x" g364fb_write(uint64_t addr, uint32_t new) "write addr=0x%"PRIx64": 0x%x" -# milkymist-tmu2.c -milkymist_tmu2_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_tmu2_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_tmu2_start(void) "Start TMU" -milkymist_tmu2_pulse_irq(void) "Pulse IRQ" - -# milkymist-vgafb.c -milkymist_vgafb_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_vgafb_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" - # vmware_vga.c vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x" vmware_value_write(uint32_t index, uint32_t value) "index %d, value 0x%x" diff --git a/hw/input/meson.build b/hw/input/meson.build index 0042c3f0dc..8deb011d4a 100644 --- a/hw/input/meson.build +++ b/hw/input/meson.build @@ -13,7 +13,6 @@ softmmu_ss.add(when: 'CONFIG_VIRTIO_INPUT', if_true: files('virtio-input-hid.c') softmmu_ss.add(when: 'CONFIG_VIRTIO_INPUT_HOST', if_true: files('virtio-input-host.c')) softmmu_ss.add(when: 'CONFIG_VHOST_USER_INPUT', if_true: files('vhost-user-input.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-softusb.c')) softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_keypad.c')) softmmu_ss.add(when: 'CONFIG_TSC210X', if_true: files('tsc210x.c')) softmmu_ss.add(when: 'CONFIG_LASIPS2', if_true: files('lasips2.c')) diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c deleted file mode 100644 index d885c708d7..0000000000 --- a/hw/input/milkymist-softusb.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * QEMU model of the Milkymist SoftUSB block. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * not available yet - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "ui/console.h" -#include "hw/input/hid.h" -#include "hw/irq.h" -#include "hw/qdev-properties.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - R_CTRL = 0, - R_MAX -}; - -enum { - CTRL_RESET = (1<<0), -}; - -#define COMLOC_DEBUG_PRODUCE 0x1000 -#define COMLOC_DEBUG_BASE 0x1001 -#define COMLOC_MEVT_PRODUCE 0x1101 -#define COMLOC_MEVT_BASE 0x1102 -#define COMLOC_KEVT_PRODUCE 0x1142 -#define COMLOC_KEVT_BASE 0x1143 - -#define TYPE_MILKYMIST_SOFTUSB "milkymist-softusb" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistSoftUsbState, MILKYMIST_SOFTUSB) - -struct MilkymistSoftUsbState { - SysBusDevice parent_obj; - - HIDState hid_kbd; - HIDState hid_mouse; - - MemoryRegion regs_region; - MemoryRegion pmem; - MemoryRegion dmem; - qemu_irq irq; - - void *pmem_ptr; - void *dmem_ptr; - - /* device properties */ - uint32_t pmem_size; - uint32_t dmem_size; - - /* device registers */ - uint32_t regs[R_MAX]; - - /* mouse state */ - uint8_t mouse_hid_buffer[4]; - - /* keyboard state */ - uint8_t kbd_hid_buffer[8]; -}; - -static uint64_t softusb_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistSoftUsbState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CTRL: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_softusb: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_softusb_memory_read(addr << 2, r); - - return r; -} - -static void -softusb_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistSoftUsbState *s = opaque; - - trace_milkymist_softusb_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTRL: - s->regs[addr] = value; - break; - - default: - error_report("milkymist_softusb: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps softusb_mmio_ops = { - .read = softusb_read, - .write = softusb_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static inline void softusb_read_dmem(MilkymistSoftUsbState *s, - uint32_t offset, uint8_t *buf, uint32_t len) -{ - if (offset + len >= s->dmem_size) { - error_report("milkymist_softusb: read dmem out of bounds " - "at offset 0x%x, len %d", offset, len); - memset(buf, 0, len); - return; - } - - memcpy(buf, s->dmem_ptr + offset, len); -} - -static inline void softusb_write_dmem(MilkymistSoftUsbState *s, - uint32_t offset, uint8_t *buf, uint32_t len) -{ - if (offset + len >= s->dmem_size) { - error_report("milkymist_softusb: write dmem out of bounds " - "at offset 0x%x, len %d", offset, len); - return; - } - - memcpy(s->dmem_ptr + offset, buf, len); -} - -static void softusb_mouse_changed(MilkymistSoftUsbState *s) -{ - uint8_t m; - - softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1); - trace_milkymist_softusb_mevt(m); - softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4); - m = (m + 1) & 0xf; - softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1); - - trace_milkymist_softusb_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static void softusb_kbd_changed(MilkymistSoftUsbState *s) -{ - uint8_t m; - - softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1); - trace_milkymist_softusb_kevt(m); - softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8); - m = (m + 1) & 0x7; - softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1); - - trace_milkymist_softusb_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static void softusb_kbd_hid_datain(HIDState *hs) -{ - MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd); - int len; - - /* if device is in reset, do nothing */ - if (s->regs[R_CTRL] & CTRL_RESET) { - return; - } - - while (hid_has_events(hs)) { - len = hid_keyboard_poll(hs, s->kbd_hid_buffer, - sizeof(s->kbd_hid_buffer)); - - if (len == 8) { - softusb_kbd_changed(s); - } - } -} - -static void softusb_mouse_hid_datain(HIDState *hs) -{ - MilkymistSoftUsbState *s = - container_of(hs, MilkymistSoftUsbState, hid_mouse); - int len; - - /* if device is in reset, do nothing */ - if (s->regs[R_CTRL] & CTRL_RESET) { - return; - } - - while (hid_has_events(hs)) { - len = hid_pointer_poll(hs, s->mouse_hid_buffer, - sizeof(s->mouse_hid_buffer)); - - if (len == 4) { - softusb_mouse_changed(s); - } - } -} - -static void milkymist_softusb_reset(DeviceState *d) -{ - MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer)); - memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer)); - - hid_reset(&s->hid_kbd); - hid_reset(&s->hid_mouse); - - /* defaults */ - s->regs[R_CTRL] = CTRL_RESET; -} - -static void milkymist_softusb_realize(DeviceState *dev, Error **errp) -{ - MilkymistSoftUsbState *s = MILKYMIST_SOFTUSB(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init_io(&s->regs_region, OBJECT(s), &softusb_mmio_ops, s, - "milkymist-softusb", R_MAX * 4); - sysbus_init_mmio(sbd, &s->regs_region); - - /* register pmem and dmem */ - memory_region_init_ram_nomigrate(&s->pmem, OBJECT(s), "milkymist-softusb.pmem", - s->pmem_size, &error_fatal); - vmstate_register_ram_global(&s->pmem); - s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem); - sysbus_init_mmio(sbd, &s->pmem); - memory_region_init_ram_nomigrate(&s->dmem, OBJECT(s), "milkymist-softusb.dmem", - s->dmem_size, &error_fatal); - vmstate_register_ram_global(&s->dmem); - s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem); - sysbus_init_mmio(sbd, &s->dmem); - - hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain); - hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain); -} - -static const VMStateDescription vmstate_milkymist_softusb = { - .name = "milkymist-softusb", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX), - VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState), - VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState), - VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState), - VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_softusb_properties[] = { - DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000), - DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_softusb_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_softusb_realize; - dc->reset = milkymist_softusb_reset; - dc->vmsd = &vmstate_milkymist_softusb; - device_class_set_props(dc, milkymist_softusb_properties); -} - -static const TypeInfo milkymist_softusb_info = { - .name = TYPE_MILKYMIST_SOFTUSB, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistSoftUsbState), - .class_init = milkymist_softusb_class_init, -}; - -static void milkymist_softusb_register_types(void) -{ - type_register_static(&milkymist_softusb_info); -} - -type_init(milkymist_softusb_register_types) diff --git a/hw/input/trace-events b/hw/input/trace-events index 1dd8ad6018..33741e74f5 100644 --- a/hw/input/trace-events +++ b/hw/input/trace-events @@ -44,13 +44,6 @@ ps2_mouse_reset(void *opaque) "%p" ps2_kbd_init(void *s) "%p" ps2_mouse_init(void *s) "%p" -# milkymist-softusb.c -milkymist_softusb_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_softusb_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_softusb_mevt(uint8_t m) "m %d" -milkymist_softusb_kevt(uint8_t m) "m %d" -milkymist_softusb_pulse_irq(void) "Pulse IRQ" - # hid.c hid_kbd_queue_full(void) "queue full" hid_kbd_queue_empty(void) "queue empty" diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c deleted file mode 100644 index 991a90bc99..0000000000 --- a/hw/intc/lm32_pic.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * LatticeMico32 CPU interrupt controller logic. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "qemu/osdep.h" - -#include "migration/vmstate.h" -#include "monitor/monitor.h" -#include "qemu/module.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "hw/lm32/lm32_pic.h" -#include "hw/intc/intc.h" -#include "hw/irq.h" -#include "qom/object.h" - -#define TYPE_LM32_PIC "lm32-pic" -OBJECT_DECLARE_SIMPLE_TYPE(LM32PicState, LM32_PIC) - -struct LM32PicState { - SysBusDevice parent_obj; - - qemu_irq parent_irq; - uint32_t im; /* interrupt mask */ - uint32_t ip; /* interrupt pending */ - uint32_t irq_state; - - /* statistics */ - uint64_t stats_irq_count[32]; -}; - -static void update_irq(LM32PicState *s) -{ - s->ip |= s->irq_state; - - if (s->ip & s->im) { - trace_lm32_pic_raise_irq(); - qemu_irq_raise(s->parent_irq); - } else { - trace_lm32_pic_lower_irq(); - qemu_irq_lower(s->parent_irq); - } -} - -static void irq_handler(void *opaque, int irq, int level) -{ - LM32PicState *s = opaque; - - assert(irq < 32); - trace_lm32_pic_interrupt(irq, level); - - if (level) { - s->irq_state |= (1 << irq); - s->stats_irq_count[irq]++; - } else { - s->irq_state &= ~(1 << irq); - } - - update_irq(s); -} - -void lm32_pic_set_im(DeviceState *d, uint32_t im) -{ - LM32PicState *s = LM32_PIC(d); - - trace_lm32_pic_set_im(im); - s->im = im; - - update_irq(s); -} - -void lm32_pic_set_ip(DeviceState *d, uint32_t ip) -{ - LM32PicState *s = LM32_PIC(d); - - trace_lm32_pic_set_ip(ip); - - /* ack interrupt */ - s->ip &= ~ip; - - update_irq(s); -} - -uint32_t lm32_pic_get_im(DeviceState *d) -{ - LM32PicState *s = LM32_PIC(d); - - trace_lm32_pic_get_im(s->im); - return s->im; -} - -uint32_t lm32_pic_get_ip(DeviceState *d) -{ - LM32PicState *s = LM32_PIC(d); - - trace_lm32_pic_get_ip(s->ip); - return s->ip; -} - -static void pic_reset(DeviceState *d) -{ - LM32PicState *s = LM32_PIC(d); - int i; - - s->im = 0; - s->ip = 0; - s->irq_state = 0; - for (i = 0; i < 32; i++) { - s->stats_irq_count[i] = 0; - } -} - -static bool lm32_get_statistics(InterruptStatsProvider *obj, - uint64_t **irq_counts, unsigned int *nb_irqs) -{ - LM32PicState *s = LM32_PIC(obj); - *irq_counts = s->stats_irq_count; - *nb_irqs = ARRAY_SIZE(s->stats_irq_count); - return true; -} - -static void lm32_print_info(InterruptStatsProvider *obj, Monitor *mon) -{ - LM32PicState *s = LM32_PIC(obj); - monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n", - s->im, s->ip, s->irq_state); -} - -static void lm32_pic_init(Object *obj) -{ - DeviceState *dev = DEVICE(obj); - LM32PicState *s = LM32_PIC(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - - qdev_init_gpio_in(dev, irq_handler, 32); - sysbus_init_irq(sbd, &s->parent_irq); -} - -static const VMStateDescription vmstate_lm32_pic = { - .name = "lm32-pic", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_UINT32(im, LM32PicState), - VMSTATE_UINT32(ip, LM32PicState), - VMSTATE_UINT32(irq_state, LM32PicState), - VMSTATE_UINT64_ARRAY(stats_irq_count, LM32PicState, 32), - VMSTATE_END_OF_LIST() - } -}; - -static void lm32_pic_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); - - dc->reset = pic_reset; - dc->vmsd = &vmstate_lm32_pic; - ic->get_statistics = lm32_get_statistics; - ic->print_info = lm32_print_info; -} - -static const TypeInfo lm32_pic_info = { - .name = TYPE_LM32_PIC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32PicState), - .instance_init = lm32_pic_init, - .class_init = lm32_pic_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_INTERRUPT_STATS_PROVIDER }, - { } - }, -}; - -static void lm32_pic_register_types(void) -{ - type_register_static(&lm32_pic_info); -} - -type_init(lm32_pic_register_types) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 1c299039f6..cc7a140f3f 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -14,7 +14,6 @@ softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c')) softmmu_ss.add(when: 'CONFIG_I8259', if_true: files('i8259_common.c', 'i8259.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_avic.c', 'imx_gpcv2.c')) softmmu_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic_common.c')) -softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_pic.c')) softmmu_ss.add(when: 'CONFIG_OPENPIC', if_true: files('openpic.c')) softmmu_ss.add(when: 'CONFIG_PL190', if_true: files('pl190.c')) softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_intc.c')) diff --git a/hw/intc/trace-events b/hw/intc/trace-events index c9ab17234b..626bb554b2 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -51,15 +51,6 @@ grlib_irqmp_set_irq(int irq) "Raise CPU IRQ %d" grlib_irqmp_readl_unknown(uint64_t addr) "addr 0x%"PRIx64 grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x" -# lm32_pic.c -lm32_pic_raise_irq(void) "Raise CPU interrupt" -lm32_pic_lower_irq(void) "Lower CPU interrupt" -lm32_pic_interrupt(int irq, int level) "Set IRQ%d %d" -lm32_pic_set_im(uint32_t im) "im 0x%08x" -lm32_pic_set_ip(uint32_t ip) "ip 0x%08x" -lm32_pic_get_im(uint32_t im) "im 0x%08x" -lm32_pic_get_ip(uint32_t ip) "ip 0x%08x" - # xics.c xics_icp_check_ipi(int server, uint8_t mfrr) "CPU %d can take IPI mfrr=0x%x" xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR 0x%"PRIx32"->0x%"PRIx32 diff --git a/hw/lm32/Kconfig b/hw/lm32/Kconfig deleted file mode 100644 index 8ac94205d7..0000000000 --- a/hw/lm32/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config LM32_DEVICES - bool - select PTIMER - -config MILKYMIST - bool - # FIXME: disabling it results in compile-time errors - select MILKYMIST_TMU2 if OPENGL && X11 - select PFLASH_CFI01 - select FRAMEBUFFER - select SD - select USB_OHCI - select LM32_DEVICES - -config LM32_EVR - bool - select LM32_DEVICES - select PFLASH_CFI02 diff --git a/hw/lm32/lm32.h b/hw/lm32/lm32.h deleted file mode 100644 index 7b4f6255b9..0000000000 --- a/hw/lm32/lm32.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef HW_LM32_H -#define HW_LM32_H - -#include "hw/char/lm32_juart.h" -#include "hw/qdev-properties.h" -#include "qapi/error.h" - -static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq) -{ - DeviceState *dev; - SysBusDevice *d; - - dev = qdev_new("lm32-pic"); - d = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(d, &error_fatal); - sysbus_connect_irq(d, 0, cpu_irq); - - return dev; -} - -static inline DeviceState *lm32_juart_init(Chardev *chr) -{ - DeviceState *dev; - - dev = qdev_new(TYPE_LM32_JUART); - qdev_prop_set_chr(dev, "chardev", chr); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - - return dev; -} - -static inline DeviceState *lm32_uart_create(hwaddr addr, - qemu_irq irq, - Chardev *chr) -{ - DeviceState *dev; - SysBusDevice *s; - - dev = qdev_new("lm32-uart"); - s = SYS_BUS_DEVICE(dev); - qdev_prop_set_chr(dev, "chardev", chr); - sysbus_realize_and_unref(s, &error_fatal); - sysbus_mmio_map(s, 0, addr); - sysbus_connect_irq(s, 0, irq); - return dev; -} - -#endif diff --git a/hw/lm32/lm32_boards.c b/hw/lm32/lm32_boards.c deleted file mode 100644 index 2961e4c2b4..0000000000 --- a/hw/lm32/lm32_boards.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * QEMU models for LatticeMico32 uclinux and evr32 boards. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "qemu/osdep.h" -#include "qemu/units.h" -#include "qemu/cutils.h" -#include "qemu/error-report.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/irq.h" -#include "hw/block/flash.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "elf.h" -#include "lm32_hwsetup.h" -#include "lm32.h" -#include "sysemu/reset.h" -#include "sysemu/sysemu.h" - -typedef struct { - LM32CPU *cpu; - hwaddr bootstrap_pc; - hwaddr flash_base; - hwaddr hwsetup_base; - hwaddr initrd_base; - size_t initrd_size; - hwaddr cmdline_base; -} ResetInfo; - -static void cpu_irq_handler(void *opaque, int irq, int level) -{ - LM32CPU *cpu = opaque; - CPUState *cs = CPU(cpu); - - if (level) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } -} - -static void main_cpu_reset(void *opaque) -{ - ResetInfo *reset_info = opaque; - CPULM32State *env = &reset_info->cpu->env; - - cpu_reset(CPU(reset_info->cpu)); - - /* init defaults */ - env->pc = (uint32_t)reset_info->bootstrap_pc; - env->regs[R_R1] = (uint32_t)reset_info->hwsetup_base; - env->regs[R_R2] = (uint32_t)reset_info->cmdline_base; - env->regs[R_R3] = (uint32_t)reset_info->initrd_base; - env->regs[R_R4] = (uint32_t)(reset_info->initrd_base + - reset_info->initrd_size); - env->eba = reset_info->flash_base; - env->deba = reset_info->flash_base; -} - -static void lm32_evr_init(MachineState *machine) -{ - MachineClass *mc = MACHINE_GET_CLASS(machine); - const char *kernel_filename = machine->kernel_filename; - LM32CPU *cpu; - CPULM32State *env; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - qemu_irq irq[32]; - ResetInfo *reset_info; - int i; - - if (machine->ram_size != mc->default_ram_size) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); - g_free(sz); - exit(EXIT_FAILURE); - } - - /* memory map */ - hwaddr flash_base = 0x04000000; - size_t flash_sector_size = 256 * KiB; - size_t flash_size = 32 * MiB; - hwaddr ram_base = 0x08000000; - hwaddr timer0_base = 0x80002000; - hwaddr uart0_base = 0x80006000; - hwaddr timer1_base = 0x8000a000; - int uart0_irq = 0; - int timer0_irq = 1; - int timer1_irq = 3; - - reset_info = g_malloc0(sizeof(ResetInfo)); - - cpu = LM32_CPU(cpu_create(machine->cpu_type)); - - env = &cpu->env; - reset_info->cpu = cpu; - - reset_info->flash_base = flash_base; - - memory_region_add_subregion(address_space_mem, ram_base, machine->ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - /* Spansion S29NS128P */ - pflash_cfi02_register(flash_base, "lm32_evr.flash", flash_size, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - flash_sector_size, - 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); - - /* create irq lines */ - env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0)); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(env->pic_state, i); - } - - lm32_uart_create(uart0_base, irq[uart0_irq], serial_hd(0)); - sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); - sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); - - /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(serial_hd(1)); - - reset_info->bootstrap_pc = flash_base; - - if (kernel_filename) { - uint64_t entry; - int kernel_size; - - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - &entry, NULL, NULL, NULL, - 1, EM_LATTICEMICO32, 0, 0); - reset_info->bootstrap_pc = entry; - - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, ram_base, - machine->ram_size); - reset_info->bootstrap_pc = ram_base; - } - - if (kernel_size < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - } - - qemu_register_reset(main_cpu_reset, reset_info); -} - -static void lm32_uclinux_init(MachineState *machine) -{ - MachineClass *mc = MACHINE_GET_CLASS(machine); - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - LM32CPU *cpu; - CPULM32State *env; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - qemu_irq irq[32]; - HWSetup *hw; - ResetInfo *reset_info; - int i; - - if (machine->ram_size != mc->default_ram_size) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); - g_free(sz); - exit(EXIT_FAILURE); - } - - /* memory map */ - hwaddr flash_base = 0x04000000; - size_t flash_sector_size = 256 * KiB; - size_t flash_size = 32 * MiB; - hwaddr ram_base = 0x08000000; - hwaddr uart0_base = 0x80000000; - hwaddr timer0_base = 0x80002000; - hwaddr timer1_base = 0x80010000; - hwaddr timer2_base = 0x80012000; - int uart0_irq = 0; - int timer0_irq = 1; - int timer1_irq = 20; - int timer2_irq = 21; - hwaddr hwsetup_base = 0x0bffe000; - hwaddr cmdline_base = 0x0bfff000; - hwaddr initrd_base = 0x08400000; - size_t initrd_max = 0x01000000; - - reset_info = g_malloc0(sizeof(ResetInfo)); - - cpu = LM32_CPU(cpu_create(machine->cpu_type)); - - env = &cpu->env; - reset_info->cpu = cpu; - - reset_info->flash_base = flash_base; - - memory_region_add_subregion(address_space_mem, ram_base, machine->ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - /* Spansion S29NS128P */ - pflash_cfi02_register(flash_base, "lm32_uclinux.flash", flash_size, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - flash_sector_size, - 1, 2, 0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1); - - /* create irq lines */ - env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, env, 0)); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(env->pic_state, i); - } - - lm32_uart_create(uart0_base, irq[uart0_irq], serial_hd(0)); - sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]); - sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]); - sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]); - - /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(serial_hd(1)); - - reset_info->bootstrap_pc = flash_base; - - if (kernel_filename) { - uint64_t entry; - int kernel_size; - - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - &entry, NULL, NULL, NULL, - 1, EM_LATTICEMICO32, 0, 0); - reset_info->bootstrap_pc = entry; - - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, ram_base, - machine->ram_size); - reset_info->bootstrap_pc = ram_base; - } - - if (kernel_size < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - } - - /* generate a rom with the hardware description */ - hw = hwsetup_init(); - hwsetup_add_cpu(hw, "LM32", 75000000); - hwsetup_add_flash(hw, "flash", flash_base, flash_size); - hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, machine->ram_size); - hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq); - hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq); - hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq); - hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq); - hwsetup_add_trailer(hw); - hwsetup_create_rom(hw, hwsetup_base); - hwsetup_free(hw); - - reset_info->hwsetup_base = hwsetup_base; - - if (kernel_cmdline && strlen(kernel_cmdline)) { - pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, - kernel_cmdline); - reset_info->cmdline_base = cmdline_base; - } - - if (initrd_filename) { - size_t initrd_size; - initrd_size = load_image_targphys(initrd_filename, initrd_base, - initrd_max); - reset_info->initrd_base = initrd_base; - reset_info->initrd_size = initrd_size; - } - - qemu_register_reset(main_cpu_reset, reset_info); -} - -static void lm32_evr_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "LatticeMico32 EVR32 eval system"; - mc->init = lm32_evr_init; - mc->is_default = true; - mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full"); - mc->default_ram_size = 64 * MiB; - mc->default_ram_id = "lm32_evr.sdram"; -} - -static const TypeInfo lm32_evr_type = { - .name = MACHINE_TYPE_NAME("lm32-evr"), - .parent = TYPE_MACHINE, - .class_init = lm32_evr_class_init, -}; - -static void lm32_uclinux_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - - mc->desc = "lm32 platform for uClinux and u-boot by Theobroma Systems"; - mc->init = lm32_uclinux_init; - mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full"); - mc->default_ram_size = 64 * MiB; - mc->default_ram_id = "lm32_uclinux.sdram"; -} - -static const TypeInfo lm32_uclinux_type = { - .name = MACHINE_TYPE_NAME("lm32-uclinux"), - .parent = TYPE_MACHINE, - .class_init = lm32_uclinux_class_init, -}; - -static void lm32_machine_init(void) -{ - type_register_static(&lm32_evr_type); - type_register_static(&lm32_uclinux_type); -} - -type_init(lm32_machine_init) diff --git a/hw/lm32/lm32_hwsetup.h b/hw/lm32/lm32_hwsetup.h deleted file mode 100644 index e6cd30ad68..0000000000 --- a/hw/lm32/lm32_hwsetup.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * LatticeMico32 hwsetup helper functions. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -/* - * These are helper functions for creating the hardware description blob used - * in the Theobroma's uClinux port. - */ - -#ifndef QEMU_HW_LM32_HWSETUP_H -#define QEMU_HW_LM32_HWSETUP_H - -#include "qemu/cutils.h" -#include "hw/loader.h" - -typedef struct { - void *data; - void *ptr; -} HWSetup; - -enum hwsetup_tag { - HWSETUP_TAG_EOL = 0, - HWSETUP_TAG_CPU = 1, - HWSETUP_TAG_ASRAM = 2, - HWSETUP_TAG_FLASH = 3, - HWSETUP_TAG_SDRAM = 4, - HWSETUP_TAG_OCM = 5, - HWSETUP_TAG_DDR_SDRAM = 6, - HWSETUP_TAG_DDR2_SDRAM = 7, - HWSETUP_TAG_TIMER = 8, - HWSETUP_TAG_UART = 9, - HWSETUP_TAG_GPIO = 10, - HWSETUP_TAG_TRISPEEDMAC = 11, - HWSETUP_TAG_I2CM = 12, - HWSETUP_TAG_LEDS = 13, - HWSETUP_TAG_7SEG = 14, - HWSETUP_TAG_SPI_S = 15, - HWSETUP_TAG_SPI_M = 16, -}; - -static inline HWSetup *hwsetup_init(void) -{ - HWSetup *hw; - - hw = g_malloc(sizeof(HWSetup)); - hw->data = g_malloc0(TARGET_PAGE_SIZE); - hw->ptr = hw->data; - - return hw; -} - -static inline void hwsetup_free(HWSetup *hw) -{ - g_free(hw->data); - g_free(hw); -} - -static inline void hwsetup_create_rom(HWSetup *hw, - hwaddr base) -{ - rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, - TARGET_PAGE_SIZE, base, NULL, NULL, NULL, NULL, true); -} - -static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u) -{ - stb_p(hw->ptr, u); - hw->ptr += 1; -} - -static inline void hwsetup_add_u32(HWSetup *hw, uint32_t u) -{ - stl_p(hw->ptr, u); - hw->ptr += 4; -} - -static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t) -{ - stl_p(hw->ptr, t); - hw->ptr += 4; -} - -static inline void hwsetup_add_str(HWSetup *hw, const char *str) -{ - pstrcpy(hw->ptr, 32, str); - hw->ptr += 32; -} - -static inline void hwsetup_add_trailer(HWSetup *hw) -{ - hwsetup_add_u32(hw, 8); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_EOL); -} - -static inline void hwsetup_add_cpu(HWSetup *hw, - const char *name, uint32_t frequency) -{ - hwsetup_add_u32(hw, 44); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_CPU); - hwsetup_add_str(hw, name); - hwsetup_add_u32(hw, frequency); -} - -static inline void hwsetup_add_flash(HWSetup *hw, - const char *name, uint32_t base, uint32_t size) -{ - hwsetup_add_u32(hw, 52); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_FLASH); - hwsetup_add_str(hw, name); - hwsetup_add_u32(hw, base); - hwsetup_add_u32(hw, size); - hwsetup_add_u8(hw, 8); /* read latency */ - hwsetup_add_u8(hw, 8); /* write latency */ - hwsetup_add_u8(hw, 25); /* address width */ - hwsetup_add_u8(hw, 32); /* data width */ -} - -static inline void hwsetup_add_ddr_sdram(HWSetup *hw, - const char *name, uint32_t base, uint32_t size) -{ - hwsetup_add_u32(hw, 48); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_DDR_SDRAM); - hwsetup_add_str(hw, name); - hwsetup_add_u32(hw, base); - hwsetup_add_u32(hw, size); -} - -static inline void hwsetup_add_timer(HWSetup *hw, - const char *name, uint32_t base, uint32_t irq) -{ - hwsetup_add_u32(hw, 56); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_TIMER); - hwsetup_add_str(hw, name); - hwsetup_add_u32(hw, base); - hwsetup_add_u8(hw, 1); /* wr_tickcount */ - hwsetup_add_u8(hw, 1); /* rd_tickcount */ - hwsetup_add_u8(hw, 1); /* start_stop_control */ - hwsetup_add_u8(hw, 32); /* counter_width */ - hwsetup_add_u32(hw, 20); /* reload_ticks */ - hwsetup_add_u8(hw, irq); - hwsetup_add_u8(hw, 0); /* padding */ - hwsetup_add_u8(hw, 0); /* padding */ - hwsetup_add_u8(hw, 0); /* padding */ -} - -static inline void hwsetup_add_uart(HWSetup *hw, - const char *name, uint32_t base, uint32_t irq) -{ - hwsetup_add_u32(hw, 56); /* size */ - hwsetup_add_tag(hw, HWSETUP_TAG_UART); - hwsetup_add_str(hw, name); - hwsetup_add_u32(hw, base); - hwsetup_add_u32(hw, 115200); /* baudrate */ - hwsetup_add_u8(hw, 8); /* databits */ - hwsetup_add_u8(hw, 1); /* stopbits */ - hwsetup_add_u8(hw, 1); /* use_interrupt */ - hwsetup_add_u8(hw, 1); /* block_on_transmit */ - hwsetup_add_u8(hw, 1); /* block_on_receive */ - hwsetup_add_u8(hw, 4); /* rx_buffer_size */ - hwsetup_add_u8(hw, 4); /* tx_buffer_size */ - hwsetup_add_u8(hw, irq); -} - -#endif /* QEMU_HW_LM32_HWSETUP_H */ diff --git a/hw/lm32/meson.build b/hw/lm32/meson.build deleted file mode 100644 index 42d6f8db3d..0000000000 --- a/hw/lm32/meson.build +++ /dev/null @@ -1,6 +0,0 @@ -lm32_ss = ss.source_set() -# LM32 boards -lm32_ss.add(when: 'CONFIG_LM32_EVR', if_true: files('lm32_boards.c')) -lm32_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist.c')) - -hw_arch += {'lm32': lm32_ss} diff --git a/hw/lm32/milkymist-hw.h b/hw/lm32/milkymist-hw.h deleted file mode 100644 index 5dca5d52f5..0000000000 --- a/hw/lm32/milkymist-hw.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef QEMU_HW_MILKYMIST_HW_H -#define QEMU_HW_MILKYMIST_HW_H - -#include "hw/qdev-core.h" -#include "net/net.h" -#include "qapi/error.h" - -static inline DeviceState *milkymist_uart_create(hwaddr base, - qemu_irq irq, - Chardev *chr) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-uart"); - qdev_prop_set_chr(dev, "chardev", chr); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); - - return dev; -} - -static inline DeviceState *milkymist_hpdmc_create(hwaddr base) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-hpdmc"); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - - return dev; -} - -static inline DeviceState *milkymist_vgafb_create(hwaddr base, - uint32_t fb_offset, uint32_t fb_mask) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-vgafb"); - qdev_prop_set_uint32(dev, "fb_offset", fb_offset); - qdev_prop_set_uint32(dev, "fb_mask", fb_mask); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - - return dev; -} - -static inline DeviceState *milkymist_sysctl_create(hwaddr base, - qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq, - uint32_t freq_hz, uint32_t system_id, uint32_t capabilities, - uint32_t gpio_strappings) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-sysctl"); - qdev_prop_set_uint32(dev, "frequency", freq_hz); - qdev_prop_set_uint32(dev, "systemid", system_id); - qdev_prop_set_uint32(dev, "capabilities", capabilities); - qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gpio_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, timer0_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, timer1_irq); - - return dev; -} - -static inline DeviceState *milkymist_pfpu_create(hwaddr base, - qemu_irq irq) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-pfpu"); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); - return dev; -} - -static inline DeviceState *milkymist_ac97_create(hwaddr base, - qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq, - qemu_irq dmaw_irq) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-ac97"); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, crrequest_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, crreply_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, dmar_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 3, dmaw_irq); - - return dev; -} - -static inline DeviceState *milkymist_minimac2_create(hwaddr base, - hwaddr buffers_base, qemu_irq rx_irq, qemu_irq tx_irq) -{ - DeviceState *dev; - - qemu_check_nic_model(&nd_table[0], "minimac2"); - dev = qdev_new("milkymist-minimac2"); - qdev_set_nic_properties(dev, &nd_table[0]); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, buffers_base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq); - - return dev; -} - -static inline DeviceState *milkymist_softusb_create(hwaddr base, - qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size, - uint32_t dmem_base, uint32_t dmem_size) -{ - DeviceState *dev; - - dev = qdev_new("milkymist-softusb"); - qdev_prop_set_uint32(dev, "pmem_size", pmem_size); - qdev_prop_set_uint32(dev, "dmem_size", dmem_size); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, pmem_base); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, dmem_base); - sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); - - return dev; -} - -#endif /* QEMU_HW_MILKYMIST_HW_H */ diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c deleted file mode 100644 index bef7855328..0000000000 --- a/hw/lm32/milkymist.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * QEMU model for the Milkymist board. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "qemu/osdep.h" -#include "qemu/units.h" -#include "qemu/error-report.h" -#include "qemu-common.h" -#include "qemu/datadir.h" -#include "cpu.h" -#include "hw/sysbus.h" -#include "hw/irq.h" -#include "hw/block/flash.h" -#include "sysemu/sysemu.h" -#include "sysemu/qtest.h" -#include "sysemu/reset.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "hw/qdev-properties.h" -#include "elf.h" -#include "milkymist-hw.h" -#include "hw/display/milkymist_tmu2.h" -#include "hw/sd/sd.h" -#include "lm32.h" -#include "qemu/cutils.h" - -#define BIOS_FILENAME "mmone-bios.bin" -#define BIOS_OFFSET 0x00860000 -#define BIOS_SIZE (512 * KiB) -#define KERNEL_LOAD_ADDR 0x40000000 - -typedef struct { - LM32CPU *cpu; - hwaddr bootstrap_pc; - hwaddr flash_base; - hwaddr initrd_base; - size_t initrd_size; - hwaddr cmdline_base; -} ResetInfo; - -static void cpu_irq_handler(void *opaque, int irq, int level) -{ - LM32CPU *cpu = opaque; - CPUState *cs = CPU(cpu); - - if (level) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } -} - -static void main_cpu_reset(void *opaque) -{ - ResetInfo *reset_info = opaque; - CPULM32State *env = &reset_info->cpu->env; - - cpu_reset(CPU(reset_info->cpu)); - - /* init defaults */ - env->pc = reset_info->bootstrap_pc; - env->regs[R_R1] = reset_info->cmdline_base; - env->regs[R_R2] = reset_info->initrd_base; - env->regs[R_R3] = reset_info->initrd_base + reset_info->initrd_size; - env->eba = reset_info->flash_base; - env->deba = reset_info->flash_base; -} - -static DeviceState *milkymist_memcard_create(hwaddr base) -{ - DeviceState *dev; - DriveInfo *dinfo; - - dev = qdev_new("milkymist-memcard"); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); - - dinfo = drive_get_next(IF_SD); - if (dinfo) { - DeviceState *card; - - card = qdev_new(TYPE_SD_CARD); - qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo), - &error_fatal); - qdev_realize_and_unref(card, qdev_get_child_bus(dev, "sd-bus"), - &error_fatal); - } - - return dev; -} - -static void -milkymist_init(MachineState *machine) -{ - MachineClass *mc = MACHINE_GET_CLASS(machine); - const char *bios_name = machine->firmware ?: BIOS_FILENAME; - const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - LM32CPU *cpu; - CPULM32State *env; - int kernel_size; - DriveInfo *dinfo; - MemoryRegion *address_space_mem = get_system_memory(); - qemu_irq irq[32]; - int i; - char *bios_filename; - ResetInfo *reset_info; - - if (machine->ram_size != mc->default_ram_size) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); - g_free(sz); - exit(EXIT_FAILURE); - } - - /* memory map */ - hwaddr flash_base = 0x00000000; - size_t flash_sector_size = 128 * KiB; - size_t flash_size = 32 * MiB; - hwaddr sdram_base = 0x40000000; - - hwaddr initrd_base = sdram_base + 0x1002000; - hwaddr cmdline_base = sdram_base + 0x1000000; - size_t initrd_max = machine->ram_size - 0x1002000; - - reset_info = g_malloc0(sizeof(ResetInfo)); - - cpu = LM32_CPU(cpu_create(machine->cpu_type)); - - env = &cpu->env; - reset_info->cpu = cpu; - - cpu_lm32_set_phys_msb_ignore(env, 1); - - memory_region_add_subregion(address_space_mem, sdram_base, machine->ram); - - dinfo = drive_get(IF_PFLASH, 0, 0); - /* Numonyx JS28F256J3F105 */ - pflash_cfi01_register(flash_base, "milkymist.flash", flash_size, - dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, - flash_sector_size, 2, 0x00, 0x89, 0x00, 0x1d, 1); - - /* create irq lines */ - env->pic_state = lm32_pic_init(qemu_allocate_irq(cpu_irq_handler, cpu, 0)); - for (i = 0; i < 32; i++) { - irq[i] = qdev_get_gpio_in(env->pic_state, i); - } - - /* load bios rom */ - bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - - if (bios_filename) { - if (load_image_targphys(bios_filename, BIOS_OFFSET, BIOS_SIZE) < 0) { - error_report("could not load bios '%s'", bios_filename); - exit(1); - } - } - - reset_info->bootstrap_pc = BIOS_OFFSET; - - /* if no kernel is given no valid bios rom is a fatal error */ - if (!kernel_filename && !dinfo && !bios_filename && !qtest_enabled()) { - error_report("could not load Milkymist One bios '%s'", bios_name); - exit(1); - } - g_free(bios_filename); - - milkymist_uart_create(0x60000000, irq[0], serial_hd(0)); - milkymist_sysctl_create(0x60001000, irq[1], irq[2], irq[3], - 80000000, 0x10014d31, 0x0000041f, 0x00000001); - milkymist_hpdmc_create(0x60002000); - milkymist_vgafb_create(0x60003000, 0x40000000, 0x0fffffff); - milkymist_memcard_create(0x60004000); - milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]); - milkymist_pfpu_create(0x60006000, irq[8]); - if (machine->enable_graphics) { - milkymist_tmu2_create(0x60007000, irq[9]); - } - milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]); - milkymist_softusb_create(0x6000f000, irq[15], - 0x20000000, 0x1000, 0x20020000, 0x2000); - - /* make sure juart isn't the first chardev */ - env->juart_state = lm32_juart_init(serial_hd(1)); - - if (kernel_filename) { - uint64_t entry; - - /* Boots a kernel elf binary. */ - kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, - &entry, NULL, NULL, NULL, - 1, EM_LATTICEMICO32, 0, 0); - reset_info->bootstrap_pc = entry; - - if (kernel_size < 0) { - kernel_size = load_image_targphys(kernel_filename, sdram_base, - machine->ram_size); - reset_info->bootstrap_pc = sdram_base; - } - - if (kernel_size < 0) { - error_report("could not load kernel '%s'", kernel_filename); - exit(1); - } - } - - if (kernel_cmdline && strlen(kernel_cmdline)) { - pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, - kernel_cmdline); - reset_info->cmdline_base = (uint32_t)cmdline_base; - } - - if (initrd_filename) { - size_t initrd_size; - initrd_size = load_image_targphys(initrd_filename, initrd_base, - initrd_max); - reset_info->initrd_base = (uint32_t)initrd_base; - reset_info->initrd_size = (uint32_t)initrd_size; - } - - qemu_register_reset(main_cpu_reset, reset_info); -} - -static void milkymist_machine_init(MachineClass *mc) -{ - mc->desc = "Milkymist One"; - mc->init = milkymist_init; - mc->default_cpu_type = LM32_CPU_TYPE_NAME("lm32-full"); - mc->default_ram_size = 128 * MiB; - mc->default_ram_id = "milkymist.sdram"; -} - -DEFINE_MACHINE("milkymist", milkymist_machine_init) diff --git a/hw/meson.build b/hw/meson.build index 503cbc974f..56ce810c4b 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -47,7 +47,6 @@ subdir('avr') subdir('cris') subdir('hppa') subdir('i386') -subdir('lm32') subdir('m68k') subdir('microblaze') subdir('mips') diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 1e7b8b064b..f934d79e29 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -63,7 +63,6 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files( 'imx_ccm.c', 'imx_rngc.c', )) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-hpdmc.c', 'milkymist-pfpu.c')) softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c')) softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files( 'npcm7xx_clk.c', diff --git a/hw/misc/milkymist-hpdmc.c b/hw/misc/milkymist-hpdmc.c deleted file mode 100644 index 09a3875f02..0000000000 --- a/hw/misc/milkymist-hpdmc.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * QEMU model of the Milkymist High Performance Dynamic Memory Controller. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/hpdmc.pdf - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - R_SYSTEM = 0, - R_BYPASS, - R_TIMING, - R_IODELAY, - R_MAX -}; - -enum { - IODELAY_DQSDELAY_RDY = (1<<5), - IODELAY_PLL1_LOCKED = (1<<6), - IODELAY_PLL2_LOCKED = (1<<7), -}; - -#define TYPE_MILKYMIST_HPDMC "milkymist-hpdmc" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistHpdmcState, MILKYMIST_HPDMC) - -struct MilkymistHpdmcState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - - uint32_t regs[R_MAX]; -}; - -static uint64_t hpdmc_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistHpdmcState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_SYSTEM: - case R_BYPASS: - case R_TIMING: - case R_IODELAY: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_hpdmc: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_hpdmc_memory_read(addr << 2, r); - - return r; -} - -static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistHpdmcState *s = opaque; - - trace_milkymist_hpdmc_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_SYSTEM: - case R_BYPASS: - case R_TIMING: - s->regs[addr] = value; - break; - case R_IODELAY: - /* ignore writes */ - break; - - default: - error_report("milkymist_hpdmc: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps hpdmc_mmio_ops = { - .read = hpdmc_read, - .write = hpdmc_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_hpdmc_reset(DeviceState *d) -{ - MilkymistHpdmcState *s = MILKYMIST_HPDMC(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - /* defaults */ - s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED - | IODELAY_PLL2_LOCKED; -} - -static void milkymist_hpdmc_realize(DeviceState *dev, Error **errp) -{ - MilkymistHpdmcState *s = MILKYMIST_HPDMC(dev); - - memory_region_init_io(&s->regs_region, OBJECT(dev), &hpdmc_mmio_ops, s, - "milkymist-hpdmc", R_MAX * 4); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->regs_region); -} - -static const VMStateDescription vmstate_milkymist_hpdmc = { - .name = "milkymist-hpdmc", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_hpdmc_realize; - dc->reset = milkymist_hpdmc_reset; - dc->vmsd = &vmstate_milkymist_hpdmc; -} - -static const TypeInfo milkymist_hpdmc_info = { - .name = TYPE_MILKYMIST_HPDMC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistHpdmcState), - .class_init = milkymist_hpdmc_class_init, -}; - -static void milkymist_hpdmc_register_types(void) -{ - type_register_static(&milkymist_hpdmc_info); -} - -type_init(milkymist_hpdmc_register_types) diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c deleted file mode 100644 index e4ee209c10..0000000000 --- a/hw/misc/milkymist-pfpu.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - * QEMU model of the Milkymist programmable FPU. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/pfpu.pdf - * - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "qemu/error-report.h" -#include -#include "qom/object.h" - -/* #define TRACE_EXEC */ - -#ifdef TRACE_EXEC -# define D_EXEC(x) x -#else -# define D_EXEC(x) -#endif - -enum { - R_CTL = 0, - R_MESHBASE, - R_HMESHLAST, - R_VMESHLAST, - R_CODEPAGE, - R_VERTICES, - R_COLLISIONS, - R_STRAYWRITES, - R_LASTDMA, - R_PC, - R_DREGBASE, - R_CODEBASE, - R_MAX -}; - -enum { - CTL_START_BUSY = (1<<0), -}; - -enum { - OP_NOP = 0, - OP_FADD, - OP_FSUB, - OP_FMUL, - OP_FABS, - OP_F2I, - OP_I2F, - OP_VECTOUT, - OP_SIN, - OP_COS, - OP_ABOVE, - OP_EQUAL, - OP_COPY, - OP_IF, - OP_TSIGN, - OP_QUAKE, -}; - -enum { - GPR_X = 0, - GPR_Y = 1, - GPR_FLAGS = 2, -}; - -enum { - LATENCY_FADD = 5, - LATENCY_FSUB = 5, - LATENCY_FMUL = 7, - LATENCY_FABS = 2, - LATENCY_F2I = 2, - LATENCY_I2F = 3, - LATENCY_VECTOUT = 0, - LATENCY_SIN = 4, - LATENCY_COS = 4, - LATENCY_ABOVE = 2, - LATENCY_EQUAL = 2, - LATENCY_COPY = 2, - LATENCY_IF = 2, - LATENCY_TSIGN = 2, - LATENCY_QUAKE = 2, - MAX_LATENCY = 7 -}; - -#define GPR_BEGIN 0x100 -#define GPR_END 0x17f -#define MICROCODE_BEGIN 0x200 -#define MICROCODE_END 0x3ff -#define MICROCODE_WORDS 2048 - -#define REINTERPRET_CAST(type, val) (*((type *)&(val))) - -#ifdef TRACE_EXEC -static const char *opcode_to_str[] = { - "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT", - "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE", -}; -#endif - -#define TYPE_MILKYMIST_PFPU "milkymist-pfpu" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistPFPUState, MILKYMIST_PFPU) - -struct MilkymistPFPUState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - Chardev *chr; - qemu_irq irq; - - uint32_t regs[R_MAX]; - uint32_t gp_regs[128]; - uint32_t microcode[MICROCODE_WORDS]; - - int output_queue_pos; - uint32_t output_queue[MAX_LATENCY]; -}; - -static inline uint32_t -get_dma_address(uint32_t base, uint32_t x, uint32_t y) -{ - return base + 8 * (128 * y + x); -} - -static inline void -output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos) -{ - s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val; -} - -static inline uint32_t -output_queue_remove(MilkymistPFPUState *s) -{ - return s->output_queue[s->output_queue_pos]; -} - -static inline void -output_queue_advance(MilkymistPFPUState *s) -{ - s->output_queue[s->output_queue_pos] = 0; - s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY; -} - -static int pfpu_decode_insn(MilkymistPFPUState *s) -{ - uint32_t pc = s->regs[R_PC]; - uint32_t insn = s->microcode[pc]; - uint32_t reg_a = (insn >> 18) & 0x7f; - uint32_t reg_b = (insn >> 11) & 0x7f; - uint32_t op = (insn >> 7) & 0xf; - uint32_t reg_d = insn & 0x7f; - uint32_t r = 0; - int latency = 0; - - switch (op) { - case OP_NOP: - break; - case OP_FADD: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = a + b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FADD; - D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_FSUB: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = a - b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FSUB; - D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_FMUL: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = a * b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FMUL; - D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_FABS: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float t = fabsf(a); - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_FABS; - D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r)); - } break; - case OP_F2I: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - int32_t t = a; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_F2I; - D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r)); - } break; - case OP_I2F: - { - int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); - float t = a; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_I2F; - D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r)); - } break; - case OP_VECTOUT: - { - uint32_t a = cpu_to_be32(s->gp_regs[reg_a]); - uint32_t b = cpu_to_be32(s->gp_regs[reg_b]); - hwaddr dma_ptr = - get_dma_address(s->regs[R_MESHBASE], - s->gp_regs[GPR_X], s->gp_regs[GPR_Y]); - cpu_physical_memory_write(dma_ptr, &a, 4); - cpu_physical_memory_write(dma_ptr + 4, &b, 4); - s->regs[R_LASTDMA] = dma_ptr + 4; - D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr)); - trace_milkymist_pfpu_vectout(a, b, dma_ptr); - } break; - case OP_SIN: - { - int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); - float t = sinf(a * (1.0f / (M_PI * 4096.0f))); - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_SIN; - D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r)); - } break; - case OP_COS: - { - int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]); - float t = cosf(a * (1.0f / (M_PI * 4096.0f))); - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_COS; - D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r)); - } break; - case OP_ABOVE: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = (a > b) ? 1.0f : 0.0f; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_ABOVE; - D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_EQUAL: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = (a == b) ? 1.0f : 0.0f; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_EQUAL; - D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_COPY: - { - r = s->gp_regs[reg_a]; - latency = LATENCY_COPY; - D_EXEC(qemu_log("COPY")); - } break; - case OP_IF: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - uint32_t f = s->gp_regs[GPR_FLAGS]; - float t = (f != 0) ? a : b; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_IF; - D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r)); - } break; - case OP_TSIGN: - { - float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]); - float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]); - float t = (b < 0) ? -a : a; - r = REINTERPRET_CAST(uint32_t, t); - latency = LATENCY_TSIGN; - D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r)); - } break; - case OP_QUAKE: - { - uint32_t a = s->gp_regs[reg_a]; - r = 0x5f3759df - (a >> 1); - latency = LATENCY_QUAKE; - D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r)); - } break; - - default: - error_report("milkymist_pfpu: unknown opcode %d", op); - break; - } - - if (!reg_d) { - D_EXEC(qemu_log("%04d %8s R%03d, R%03d \n", - s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency, - s->regs[R_PC] + latency)); - } else { - D_EXEC(qemu_log("%04d %8s R%03d, R%03d -> R%03d\n", - s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency, - s->regs[R_PC] + latency, reg_d)); - } - - if (op == OP_VECTOUT) { - return 0; - } - - /* store output for this cycle */ - if (reg_d) { - uint32_t val = output_queue_remove(s); - D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val)); - s->gp_regs[reg_d] = val; - } - - output_queue_advance(s); - - /* store op output */ - if (op != OP_NOP) { - output_queue_insert(s, r, latency-1); - } - - /* advance PC */ - s->regs[R_PC]++; - - return 1; -}; - -static void pfpu_start(MilkymistPFPUState *s) -{ - int x, y; - int i; - - for (y = 0; y <= s->regs[R_VMESHLAST]; y++) { - for (x = 0; x <= s->regs[R_HMESHLAST]; x++) { - D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y)); - - /* set current position */ - s->gp_regs[GPR_X] = x; - s->gp_regs[GPR_Y] = y; - - /* run microcode on this position */ - i = 0; - while (pfpu_decode_insn(s)) { - /* decode at most MICROCODE_WORDS instructions */ - if (++i >= MICROCODE_WORDS) { - error_report("milkymist_pfpu: too many instructions " - "executed in microcode. No VECTOUT?"); - break; - } - } - - /* reset pc for next run */ - s->regs[R_PC] = 0; - } - } - - s->regs[R_VERTICES] = x * y; - - trace_milkymist_pfpu_pulse_irq(); - qemu_irq_pulse(s->irq); -} - -static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr) -{ - return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN; -} - -static uint64_t pfpu_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistPFPUState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CTL: - case R_MESHBASE: - case R_HMESHLAST: - case R_VMESHLAST: - case R_CODEPAGE: - case R_VERTICES: - case R_COLLISIONS: - case R_STRAYWRITES: - case R_LASTDMA: - case R_PC: - case R_DREGBASE: - case R_CODEBASE: - r = s->regs[addr]; - break; - case GPR_BEGIN ... GPR_END: - r = s->gp_regs[addr - GPR_BEGIN]; - break; - case MICROCODE_BEGIN ... MICROCODE_END: - r = s->microcode[get_microcode_address(s, addr)]; - break; - - default: - error_report("milkymist_pfpu: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_pfpu_memory_read(addr << 2, r); - - return r; -} - -static void pfpu_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistPFPUState *s = opaque; - - trace_milkymist_pfpu_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_CTL: - if (value & CTL_START_BUSY) { - pfpu_start(s); - } - break; - case R_MESHBASE: - case R_HMESHLAST: - case R_VMESHLAST: - case R_CODEPAGE: - case R_VERTICES: - case R_COLLISIONS: - case R_STRAYWRITES: - case R_LASTDMA: - case R_PC: - case R_DREGBASE: - case R_CODEBASE: - s->regs[addr] = value; - break; - case GPR_BEGIN ... GPR_END: - s->gp_regs[addr - GPR_BEGIN] = value; - break; - case MICROCODE_BEGIN ... MICROCODE_END: - s->microcode[get_microcode_address(s, addr)] = value; - break; - - default: - error_report("milkymist_pfpu: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps pfpu_mmio_ops = { - .read = pfpu_read, - .write = pfpu_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_pfpu_reset(DeviceState *d) -{ - MilkymistPFPUState *s = MILKYMIST_PFPU(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - for (i = 0; i < 128; i++) { - s->gp_regs[i] = 0; - } - for (i = 0; i < MICROCODE_WORDS; i++) { - s->microcode[i] = 0; - } - s->output_queue_pos = 0; - for (i = 0; i < MAX_LATENCY; i++) { - s->output_queue[i] = 0; - } -} - -static void milkymist_pfpu_realize(DeviceState *dev, Error **errp) -{ - MilkymistPFPUState *s = MILKYMIST_PFPU(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - sysbus_init_irq(sbd, &s->irq); - - memory_region_init_io(&s->regs_region, OBJECT(dev), &pfpu_mmio_ops, s, - "milkymist-pfpu", MICROCODE_END * 4); - sysbus_init_mmio(sbd, &s->regs_region); -} - -static const VMStateDescription vmstate_milkymist_pfpu = { - .name = "milkymist-pfpu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX), - VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128), - VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS), - VMSTATE_INT32(output_queue_pos, MilkymistPFPUState), - VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_pfpu_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_pfpu_realize; - dc->reset = milkymist_pfpu_reset; - dc->vmsd = &vmstate_milkymist_pfpu; -} - -static const TypeInfo milkymist_pfpu_info = { - .name = TYPE_MILKYMIST_PFPU, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistPFPUState), - .class_init = milkymist_pfpu_class_init, -}; - -static void milkymist_pfpu_register_types(void) -{ - type_register_static(&milkymist_pfpu_info); -} - -type_init(milkymist_pfpu_register_types) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index d0a89eb059..0752217636 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -67,16 +67,6 @@ slavio_sysctrl_mem_readl(uint32_t ret) "Read system control 0x%08x" slavio_led_mem_writew(uint32_t val) "Write diagnostic LED 0x%04x" slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x" -# milkymist-hpdmc.c -milkymist_hpdmc_memory_read(uint32_t addr, uint32_t value) "addr=0x%08x value=0x%08x" -milkymist_hpdmc_memory_write(uint32_t addr, uint32_t value) "addr=0x%08x value=0x%08x" - -# milkymist-pfpu.c -milkymist_pfpu_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_pfpu_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_pfpu_vectout(uint32_t a, uint32_t b, uint32_t dma_ptr) "a 0x%08x b 0x%08x dma_ptr 0x%08x" -milkymist_pfpu_pulse_irq(void) "Pulse IRQ" - # aspeed_scu.c aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32 diff --git a/hw/net/meson.build b/hw/net/meson.build index af0749c42b..bdf71f1f40 100644 --- a/hw/net/meson.build +++ b/hw/net/meson.build @@ -39,7 +39,6 @@ softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_emc.c')) softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_eth.c')) softmmu_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_fec.c')) -specific_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-minimac2.c')) specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_llan.c')) specific_ss.add(when: 'CONFIG_XILINX_ETHLITE', if_true: files('xilinx_ethlite.c')) diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c deleted file mode 100644 index 5826944fd5..0000000000 --- a/hw/net/milkymist-minimac2.c +++ /dev/null @@ -1,547 +0,0 @@ -/* - * QEMU model of the Milkymist minimac2 block. - * - * Copyright (c) 2011 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * not available yet - * - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qom/object.h" -#include "cpu.h" /* FIXME: why does this use TARGET_PAGE_ALIGN? */ -#include "hw/irq.h" -#include "hw/qdev-properties.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "net/net.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "qemu/error-report.h" - -#include - -enum { - R_SETUP = 0, - R_MDIO, - R_STATE0, - R_COUNT0, - R_STATE1, - R_COUNT1, - R_TXCOUNT, - R_MAX -}; - -enum { - SETUP_PHY_RST = (1<<0), -}; - -enum { - MDIO_DO = (1<<0), - MDIO_DI = (1<<1), - MDIO_OE = (1<<2), - MDIO_CLK = (1<<3), -}; - -enum { - STATE_EMPTY = 0, - STATE_LOADED = 1, - STATE_PENDING = 2, -}; - -enum { - MDIO_OP_WRITE = 1, - MDIO_OP_READ = 2, -}; - -enum mdio_state { - MDIO_STATE_IDLE, - MDIO_STATE_READING, - MDIO_STATE_WRITING, -}; - -enum { - R_PHY_ID1 = 2, - R_PHY_ID2 = 3, - R_PHY_MAX = 32 -}; - -#define MINIMAC2_MTU 1530 -#define MINIMAC2_BUFFER_SIZE 2048 - -struct MilkymistMinimac2MdioState { - int last_clk; - int count; - uint32_t data; - uint16_t data_out; - int state; - - uint8_t phy_addr; - uint8_t reg_addr; -}; -typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState; - -#define TYPE_MILKYMIST_MINIMAC2 "milkymist-minimac2" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistMinimac2State, MILKYMIST_MINIMAC2) - -struct MilkymistMinimac2State { - SysBusDevice parent_obj; - - NICState *nic; - NICConf conf; - char *phy_model; - MemoryRegion buffers; - MemoryRegion regs_region; - - qemu_irq rx_irq; - qemu_irq tx_irq; - - uint32_t regs[R_MAX]; - - MilkymistMinimac2MdioState mdio; - - uint16_t phy_regs[R_PHY_MAX]; - - uint8_t *rx0_buf; - uint8_t *rx1_buf; - uint8_t *tx_buf; -}; - -static const uint8_t preamble_sfd[] = { - 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5 -}; - -static void minimac2_mdio_write_reg(MilkymistMinimac2State *s, - uint8_t phy_addr, uint8_t reg_addr, uint16_t value) -{ - trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value); - - /* nop */ -} - -static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s, - uint8_t phy_addr, uint8_t reg_addr) -{ - uint16_t r = s->phy_regs[reg_addr]; - - trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r); - - return r; -} - -static void minimac2_update_mdio(MilkymistMinimac2State *s) -{ - MilkymistMinimac2MdioState *m = &s->mdio; - - /* detect rising clk edge */ - if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) { - /* shift data in */ - int bit = ((s->regs[R_MDIO] & MDIO_DO) - && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0; - m->data = (m->data << 1) | bit; - - /* check for sync */ - if (m->data == 0xffffffff) { - m->count = 32; - } - - if (m->count == 16) { - uint8_t start = (m->data >> 14) & 0x3; - uint8_t op = (m->data >> 12) & 0x3; - uint8_t ta = (m->data) & 0x3; - - if (start == 1 && op == MDIO_OP_WRITE && ta == 2) { - m->state = MDIO_STATE_WRITING; - } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) { - m->state = MDIO_STATE_READING; - } else { - m->state = MDIO_STATE_IDLE; - } - - if (m->state != MDIO_STATE_IDLE) { - m->phy_addr = (m->data >> 7) & 0x1f; - m->reg_addr = (m->data >> 2) & 0x1f; - } - - if (m->state == MDIO_STATE_READING) { - m->data_out = minimac2_mdio_read_reg(s, m->phy_addr, - m->reg_addr); - } - } - - if (m->count < 16 && m->state == MDIO_STATE_READING) { - int bit = (m->data_out & 0x8000) ? 1 : 0; - m->data_out <<= 1; - - if (bit) { - s->regs[R_MDIO] |= MDIO_DI; - } else { - s->regs[R_MDIO] &= ~MDIO_DI; - } - } - - if (m->count == 0 && m->state) { - if (m->state == MDIO_STATE_WRITING) { - uint16_t data = m->data & 0xffff; - minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data); - } - m->state = MDIO_STATE_IDLE; - } - m->count--; - } - - m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0; -} - -static size_t assemble_frame(uint8_t *buf, size_t size, - const uint8_t *payload, size_t payload_size) -{ - uint32_t crc; - - if (size < payload_size + 12) { - qemu_log_mask(LOG_GUEST_ERROR, "milkymist_minimac2: frame too big " - "(%zd bytes)\n", payload_size); - return 0; - } - - /* prepend preamble and sfd */ - memcpy(buf, preamble_sfd, 8); - - /* now copy the payload */ - memcpy(buf + 8, payload, payload_size); - - /* pad frame if needed */ - if (payload_size < 60) { - memset(buf + payload_size + 8, 0, 60 - payload_size); - payload_size = 60; - } - - /* append fcs */ - crc = cpu_to_le32(crc32(0, buf + 8, payload_size)); - memcpy(buf + payload_size + 8, &crc, 4); - - return payload_size + 12; -} - -static void minimac2_tx(MilkymistMinimac2State *s) -{ - uint32_t txcount = s->regs[R_TXCOUNT]; - uint8_t *buf = s->tx_buf; - - if (txcount < 64) { - error_report("milkymist_minimac2: ethernet frame too small (%u < %u)", - txcount, 64); - goto err; - } - - if (txcount > MINIMAC2_MTU) { - error_report("milkymist_minimac2: MTU exceeded (%u > %u)", - txcount, MINIMAC2_MTU); - goto err; - } - - if (memcmp(buf, preamble_sfd, 8) != 0) { - error_report("milkymist_minimac2: frame doesn't contain the preamble " - "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - goto err; - } - - trace_milkymist_minimac2_tx_frame(txcount - 12); - - /* send packet, skipping preamble and sfd */ - qemu_send_packet_raw(qemu_get_queue(s->nic), buf + 8, txcount - 12); - - s->regs[R_TXCOUNT] = 0; - -err: - trace_milkymist_minimac2_pulse_irq_tx(); - qemu_irq_pulse(s->tx_irq); -} - -static void update_rx_interrupt(MilkymistMinimac2State *s) -{ - if (s->regs[R_STATE0] == STATE_PENDING - || s->regs[R_STATE1] == STATE_PENDING) { - trace_milkymist_minimac2_raise_irq_rx(); - qemu_irq_raise(s->rx_irq); - } else { - trace_milkymist_minimac2_lower_irq_rx(); - qemu_irq_lower(s->rx_irq); - } -} - -static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size) -{ - MilkymistMinimac2State *s = qemu_get_nic_opaque(nc); - - uint32_t r_count; - uint32_t r_state; - uint8_t *rx_buf; - - size_t frame_size; - - trace_milkymist_minimac2_rx_frame(buf, size); - - /* choose appropriate slot */ - if (s->regs[R_STATE0] == STATE_LOADED) { - r_count = R_COUNT0; - r_state = R_STATE0; - rx_buf = s->rx0_buf; - } else if (s->regs[R_STATE1] == STATE_LOADED) { - r_count = R_COUNT1; - r_state = R_STATE1; - rx_buf = s->rx1_buf; - } else { - return 0; - } - - /* assemble frame */ - frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size); - - if (frame_size == 0) { - return size; - } - - trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size); - - /* update slot */ - s->regs[r_count] = frame_size; - s->regs[r_state] = STATE_PENDING; - - update_rx_interrupt(s); - - return size; -} - -static uint64_t -minimac2_read(void *opaque, hwaddr addr, unsigned size) -{ - MilkymistMinimac2State *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_SETUP: - case R_MDIO: - case R_STATE0: - case R_COUNT0: - case R_STATE1: - case R_COUNT1: - case R_TXCOUNT: - r = s->regs[addr]; - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, - "milkymist_minimac2_rd%d: 0x%" HWADDR_PRIx "\n", - size, addr << 2); - break; - } - - trace_milkymist_minimac2_memory_read(addr << 2, r); - - return r; -} - -static int minimac2_can_rx(MilkymistMinimac2State *s) -{ - if (s->regs[R_STATE0] == STATE_LOADED) { - return 1; - } - if (s->regs[R_STATE1] == STATE_LOADED) { - return 1; - } - - return 0; -} - -static void -minimac2_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistMinimac2State *s = opaque; - - trace_milkymist_minimac2_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_MDIO: - { - /* MDIO_DI is read only */ - int mdio_di = (s->regs[R_MDIO] & MDIO_DI); - s->regs[R_MDIO] = value; - if (mdio_di) { - s->regs[R_MDIO] |= mdio_di; - } else { - s->regs[R_MDIO] &= ~mdio_di; - } - - minimac2_update_mdio(s); - } break; - case R_TXCOUNT: - s->regs[addr] = value; - if (value > 0) { - minimac2_tx(s); - } - break; - case R_STATE0: - case R_STATE1: - s->regs[addr] = value; - update_rx_interrupt(s); - if (minimac2_can_rx(s)) { - qemu_flush_queued_packets(qemu_get_queue(s->nic)); - } - break; - case R_SETUP: - case R_COUNT0: - case R_COUNT1: - s->regs[addr] = value; - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, - "milkymist_minimac2_wr%d: 0x%" HWADDR_PRIx - " = 0x%" PRIx64 "\n", - size, addr << 2, value); - break; - } -} - -static const MemoryRegionOps minimac2_ops = { - .read = minimac2_read, - .write = minimac2_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_minimac2_reset(DeviceState *d) -{ - MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - for (i = 0; i < R_PHY_MAX; i++) { - s->phy_regs[i] = 0; - } - - /* defaults */ - s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */ - s->phy_regs[R_PHY_ID2] = 0x161a; -} - -static NetClientInfo net_milkymist_minimac2_info = { - .type = NET_CLIENT_DRIVER_NIC, - .size = sizeof(NICState), - .receive = minimac2_rx, -}; - -static void milkymist_minimac2_realize(DeviceState *dev, Error **errp) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(dev); - size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE); - - sysbus_init_irq(sbd, &s->rx_irq); - sysbus_init_irq(sbd, &s->tx_irq); - - memory_region_init_io(&s->regs_region, OBJECT(dev), &minimac2_ops, s, - "milkymist-minimac2", R_MAX * 4); - sysbus_init_mmio(sbd, &s->regs_region); - - /* register buffers memory */ - memory_region_init_ram_nomigrate(&s->buffers, OBJECT(dev), "milkymist-minimac2.buffers", - buffers_size, &error_fatal); - vmstate_register_ram_global(&s->buffers); - s->rx0_buf = memory_region_get_ram_ptr(&s->buffers); - s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE; - s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE; - - sysbus_init_mmio(sbd, &s->buffers); - - qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf, - object_get_typename(OBJECT(dev)), dev->id, s); - qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); -} - -static const VMStateDescription vmstate_milkymist_minimac2_mdio = { - .name = "milkymist-minimac2-mdio", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState), - VMSTATE_INT32(count, MilkymistMinimac2MdioState), - VMSTATE_UINT32(data, MilkymistMinimac2MdioState), - VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState), - VMSTATE_INT32(state, MilkymistMinimac2MdioState), - VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState), - VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_milkymist_minimac2 = { - .name = "milkymist-minimac2", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX), - VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX), - VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0, - vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_minimac2_properties[] = { - DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf), - DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_minimac2_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_minimac2_realize; - dc->reset = milkymist_minimac2_reset; - dc->vmsd = &vmstate_milkymist_minimac2; - device_class_set_props(dc, milkymist_minimac2_properties); -} - -static const TypeInfo milkymist_minimac2_info = { - .name = TYPE_MILKYMIST_MINIMAC2, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistMinimac2State), - .class_init = milkymist_minimac2_class_init, -}; - -static void milkymist_minimac2_register_types(void) -{ - type_register_static(&milkymist_minimac2_info); -} - -type_init(milkymist_minimac2_register_types) diff --git a/hw/net/trace-events b/hw/net/trace-events index baf25ffa7e..314e21fa99 100644 --- a/hw/net/trace-events +++ b/hw/net/trace-events @@ -19,18 +19,6 @@ mdio_bitbang(bool mdc, bool mdio, int state, uint16_t cnt, unsigned int drive) " lance_mem_readw(uint64_t addr, uint32_t ret) "addr=0x%"PRIx64"val=0x%04x" lance_mem_writew(uint64_t addr, uint32_t val) "addr=0x%"PRIx64"val=0x%04x" -# milkymist-minimac2.c -milkymist_minimac2_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_minimac2_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_minimac2_mdio_write(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr 0x%02x addr 0x%02x value 0x%04x" -milkymist_minimac2_mdio_read(uint8_t phy_addr, uint8_t addr, uint16_t value) "phy_addr 0x%02x addr 0x%02x value 0x%04x" -milkymist_minimac2_tx_frame(uint32_t length) "length %u" -milkymist_minimac2_rx_frame(const void *buf, uint32_t length) "buf %p length %u" -milkymist_minimac2_rx_transfer(const void *buf, uint32_t length) "buf %p length %d" -milkymist_minimac2_raise_irq_rx(void) "Raise IRQ RX" -milkymist_minimac2_lower_irq_rx(void) "Lower IRQ RX" -milkymist_minimac2_pulse_irq_tx(void) "Pulse IRQ TX" - # mipsnet.c mipsnet_send(uint32_t size) "sending len=%u" mipsnet_receive(uint32_t size) "receiving len=%u" diff --git a/hw/sd/meson.build b/hw/sd/meson.build index 9c29691e13..f1ce357a3b 100644 --- a/hw/sd/meson.build +++ b/hw/sd/meson.build @@ -4,7 +4,6 @@ softmmu_ss.add(when: 'CONFIG_SDHCI', if_true: files('sdhci.c')) softmmu_ss.add(when: 'CONFIG_SDHCI_PCI', if_true: files('sdhci-pci.c')) softmmu_ss.add(when: 'CONFIG_SSI_SD', if_true: files('ssi-sd.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-memcard.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_mmc.c')) softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c')) diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c deleted file mode 100644 index a1235aa46c..0000000000 --- a/hw/sd/milkymist-memcard.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * QEMU model of the Milkymist SD Card Controller. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/memcard.pdf - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qapi/error.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "hw/qdev-properties.h" -#include "hw/sd/sd.h" -#include "qom/object.h" - -enum { - ENABLE_CMD_TX = (1<<0), - ENABLE_CMD_RX = (1<<1), - ENABLE_DAT_TX = (1<<2), - ENABLE_DAT_RX = (1<<3), -}; - -enum { - PENDING_CMD_TX = (1<<0), - PENDING_CMD_RX = (1<<1), - PENDING_DAT_TX = (1<<2), - PENDING_DAT_RX = (1<<3), -}; - -enum { - START_CMD_TX = (1<<0), - START_DAT_RX = (1<<1), -}; - -enum { - R_CLK2XDIV = 0, - R_ENABLE, - R_PENDING, - R_START, - R_CMD, - R_DAT, - R_MAX -}; - -#define TYPE_MILKYMIST_MEMCARD "milkymist-memcard" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistMemcardState, MILKYMIST_MEMCARD) - -#define TYPE_MILKYMIST_SDBUS "milkymist-sdbus" - -struct MilkymistMemcardState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - SDBus sdbus; - - int command_write_ptr; - int response_read_ptr; - int response_len; - int ignore_next_cmd; - int enabled; - uint8_t command[6]; - uint8_t response[17]; - uint32_t regs[R_MAX]; -}; - -static void update_pending_bits(MilkymistMemcardState *s) -{ - /* transmits are instantaneous, thus tx pending bits are never set */ - s->regs[R_PENDING] = 0; - /* if rx is enabled the corresponding pending bits are always set */ - if (s->regs[R_ENABLE] & ENABLE_CMD_RX) { - s->regs[R_PENDING] |= PENDING_CMD_RX; - } - if (s->regs[R_ENABLE] & ENABLE_DAT_RX) { - s->regs[R_PENDING] |= PENDING_DAT_RX; - } -} - -static void memcard_sd_command(MilkymistMemcardState *s) -{ - SDRequest req; - - req.cmd = s->command[0] & 0x3f; - req.arg = ldl_be_p(s->command + 1); - req.crc = s->command[5]; - - s->response[0] = req.cmd; - s->response_len = sdbus_do_command(&s->sdbus, &req, s->response + 1); - s->response_read_ptr = 0; - - if (s->response_len == 16) { - /* R2 response */ - s->response[0] = 0x3f; - s->response_len += 1; - } else if (s->response_len == 4) { - /* no crc calculation, insert dummy byte */ - s->response[5] = 0; - s->response_len += 2; - } - - if (req.cmd == 0) { - /* next write is a dummy byte to clock the initialization of the sd - * card */ - s->ignore_next_cmd = 1; - } -} - -static uint64_t memcard_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistMemcardState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_CMD: - if (!s->enabled) { - r = 0xff; - } else { - r = s->response[s->response_read_ptr++]; - if (s->response_read_ptr > s->response_len) { - qemu_log_mask(LOG_GUEST_ERROR, "milkymist_memcard: " - "read more cmd bytes than available: clipping\n"); - s->response_read_ptr = 0; - } - } - break; - case R_DAT: - if (!s->enabled) { - r = 0xffffffff; - } else { - sdbus_read_data(&s->sdbus, &r, sizeof(r)); - be32_to_cpus(&r); - } - break; - case R_CLK2XDIV: - case R_ENABLE: - case R_PENDING: - case R_START: - r = s->regs[addr]; - break; - - default: - qemu_log_mask(LOG_UNIMP, "milkymist_memcard: " - "read access to unknown register 0x%" HWADDR_PRIx "\n", - addr << 2); - break; - } - - trace_milkymist_memcard_memory_read(addr << 2, r); - - return r; -} - -static void memcard_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistMemcardState *s = opaque; - uint32_t val32; - - trace_milkymist_memcard_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_PENDING: - /* clear rx pending bits */ - s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX)); - update_pending_bits(s); - break; - case R_CMD: - if (!s->enabled) { - break; - } - if (s->ignore_next_cmd) { - s->ignore_next_cmd = 0; - break; - } - s->command[s->command_write_ptr] = value & 0xff; - s->command_write_ptr = (s->command_write_ptr + 1) % 6; - if (s->command_write_ptr == 0) { - memcard_sd_command(s); - } - break; - case R_DAT: - if (!s->enabled) { - break; - } - val32 = cpu_to_be32(value); - sdbus_write_data(&s->sdbus, &val32, sizeof(val32)); - break; - case R_ENABLE: - s->regs[addr] = value; - update_pending_bits(s); - break; - case R_CLK2XDIV: - case R_START: - s->regs[addr] = value; - break; - - default: - qemu_log_mask(LOG_UNIMP, "milkymist_memcard: " - "write access to unknown register 0x%" HWADDR_PRIx " " - "(value 0x%" PRIx64 ")\n", addr << 2, value); - break; - } -} - -static const MemoryRegionOps memcard_mmio_ops = { - .read = memcard_read, - .write = memcard_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void milkymist_memcard_reset(DeviceState *d) -{ - MilkymistMemcardState *s = MILKYMIST_MEMCARD(d); - int i; - - s->command_write_ptr = 0; - s->response_read_ptr = 0; - s->response_len = 0; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } -} - -static void milkymist_memcard_set_readonly(DeviceState *dev, bool level) -{ - qemu_log_mask(LOG_UNIMP, - "milkymist_memcard: read-only mode not supported\n"); -} - -static void milkymist_memcard_set_inserted(DeviceState *dev, bool level) -{ - MilkymistMemcardState *s = MILKYMIST_MEMCARD(dev); - - s->enabled = !!level; -} - -static void milkymist_memcard_init(Object *obj) -{ - MilkymistMemcardState *s = MILKYMIST_MEMCARD(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - memory_region_init_io(&s->regs_region, OBJECT(s), &memcard_mmio_ops, s, - "milkymist-memcard", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); - - qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, - DEVICE(obj), "sd-bus"); -} - -static const VMStateDescription vmstate_milkymist_memcard = { - .name = "milkymist-memcard", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_INT32(command_write_ptr, MilkymistMemcardState), - VMSTATE_INT32(response_read_ptr, MilkymistMemcardState), - VMSTATE_INT32(response_len, MilkymistMemcardState), - VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState), - VMSTATE_INT32(enabled, MilkymistMemcardState), - VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6), - VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17), - VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_memcard_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = milkymist_memcard_reset; - dc->vmsd = &vmstate_milkymist_memcard; - /* Reason: output IRQs should be wired up */ - dc->user_creatable = false; -} - -static const TypeInfo milkymist_memcard_info = { - .name = TYPE_MILKYMIST_MEMCARD, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistMemcardState), - .instance_init = milkymist_memcard_init, - .class_init = milkymist_memcard_class_init, -}; - -static void milkymist_sdbus_class_init(ObjectClass *klass, void *data) -{ - SDBusClass *sbc = SD_BUS_CLASS(klass); - - sbc->set_inserted = milkymist_memcard_set_inserted; - sbc->set_readonly = milkymist_memcard_set_readonly; -} - -static const TypeInfo milkymist_sdbus_info = { - .name = TYPE_MILKYMIST_SDBUS, - .parent = TYPE_SD_BUS, - .instance_size = sizeof(SDBus), - .class_init = milkymist_sdbus_class_init, -}; - -static void milkymist_memcard_register_types(void) -{ - type_register_static(&milkymist_memcard_info); - type_register_static(&milkymist_sdbus_info); -} - -type_init(milkymist_memcard_register_types) diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 4140e48540..e185d07a1d 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -55,10 +55,6 @@ sdcard_write_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint8_t sdcard_read_data(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t length) "%s %20s/ CMD%02d len %" PRIu32 sdcard_set_voltage(uint16_t millivolts) "%u mV" -# milkymist-memcard.c -milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" - # pxa2xx_mmci.c pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x" pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x" diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c deleted file mode 100644 index eeaf0ada5f..0000000000 --- a/hw/timer/lm32_timer.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * QEMU model of the LatticeMico32 timer block. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://www.latticesemi.com/documents/mico32timer.pdf - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qemu/timer.h" -#include "hw/ptimer.h" -#include "hw/qdev-properties.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -#define DEFAULT_FREQUENCY (50*1000000) - -enum { - R_SR = 0, - R_CR, - R_PERIOD, - R_SNAPSHOT, - R_MAX -}; - -enum { - SR_TO = (1 << 0), - SR_RUN = (1 << 1), -}; - -enum { - CR_ITO = (1 << 0), - CR_CONT = (1 << 1), - CR_START = (1 << 2), - CR_STOP = (1 << 3), -}; - -#define TYPE_LM32_TIMER "lm32-timer" -OBJECT_DECLARE_SIMPLE_TYPE(LM32TimerState, LM32_TIMER) - -struct LM32TimerState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - ptimer_state *ptimer; - - qemu_irq irq; - uint32_t freq_hz; - - uint32_t regs[R_MAX]; -}; - -static void timer_update_irq(LM32TimerState *s) -{ - int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO); - - trace_lm32_timer_irq_state(state); - qemu_set_irq(s->irq, state); -} - -static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size) -{ - LM32TimerState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_SR: - case R_CR: - case R_PERIOD: - r = s->regs[addr]; - break; - case R_SNAPSHOT: - r = (uint32_t)ptimer_get_count(s->ptimer); - break; - default: - error_report("lm32_timer: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_lm32_timer_memory_read(addr << 2, r); - return r; -} - -static void timer_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - LM32TimerState *s = opaque; - - trace_lm32_timer_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_SR: - s->regs[R_SR] &= ~SR_TO; - break; - case R_CR: - ptimer_transaction_begin(s->ptimer); - s->regs[R_CR] = value; - if (s->regs[R_CR] & CR_START) { - ptimer_run(s->ptimer, 1); - } - if (s->regs[R_CR] & CR_STOP) { - ptimer_stop(s->ptimer); - } - ptimer_transaction_commit(s->ptimer); - break; - case R_PERIOD: - s->regs[R_PERIOD] = value; - ptimer_transaction_begin(s->ptimer); - ptimer_set_count(s->ptimer, value); - ptimer_transaction_commit(s->ptimer); - break; - case R_SNAPSHOT: - error_report("lm32_timer: write access to read only register 0x" - TARGET_FMT_plx, addr << 2); - break; - default: - error_report("lm32_timer: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - timer_update_irq(s); -} - -static const MemoryRegionOps timer_ops = { - .read = timer_read, - .write = timer_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, -}; - -static void timer_hit(void *opaque) -{ - LM32TimerState *s = opaque; - - trace_lm32_timer_hit(); - - s->regs[R_SR] |= SR_TO; - - if (s->regs[R_CR] & CR_CONT) { - ptimer_set_count(s->ptimer, s->regs[R_PERIOD]); - ptimer_run(s->ptimer, 1); - } - timer_update_irq(s); -} - -static void timer_reset(DeviceState *d) -{ - LM32TimerState *s = LM32_TIMER(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - ptimer_transaction_begin(s->ptimer); - ptimer_stop(s->ptimer); - ptimer_transaction_commit(s->ptimer); -} - -static void lm32_timer_init(Object *obj) -{ - LM32TimerState *s = LM32_TIMER(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(dev, &s->irq); - - memory_region_init_io(&s->iomem, obj, &timer_ops, s, - "timer", R_MAX * 4); - sysbus_init_mmio(dev, &s->iomem); -} - -static void lm32_timer_realize(DeviceState *dev, Error **errp) -{ - LM32TimerState *s = LM32_TIMER(dev); - - s->ptimer = ptimer_init(timer_hit, s, PTIMER_POLICY_DEFAULT); - - ptimer_transaction_begin(s->ptimer); - ptimer_set_freq(s->ptimer, s->freq_hz); - ptimer_transaction_commit(s->ptimer); -} - -static const VMStateDescription vmstate_lm32_timer = { - .name = "lm32-timer", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PTIMER(ptimer, LM32TimerState), - VMSTATE_UINT32(freq_hz, LM32TimerState), - VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static Property lm32_timer_properties[] = { - DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY), - DEFINE_PROP_END_OF_LIST(), -}; - -static void lm32_timer_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = lm32_timer_realize; - dc->reset = timer_reset; - dc->vmsd = &vmstate_lm32_timer; - device_class_set_props(dc, lm32_timer_properties); -} - -static const TypeInfo lm32_timer_info = { - .name = TYPE_LM32_TIMER, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(LM32TimerState), - .instance_init = lm32_timer_init, - .class_init = lm32_timer_class_init, -}; - -static void lm32_timer_register_types(void) -{ - type_register_static(&lm32_timer_info); -} - -type_init(lm32_timer_register_types) diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 598d058506..f2081d261a 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -19,8 +19,6 @@ softmmu_ss.add(when: 'CONFIG_HPET', if_true: files('hpet.c')) softmmu_ss.add(when: 'CONFIG_I8254', if_true: files('i8254_common.c', 'i8254.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_epit.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpt.c')) -softmmu_ss.add(when: 'CONFIG_LM32_DEVICES', if_true: files('lm32_timer.c')) -softmmu_ss.add(when: 'CONFIG_MILKYMIST', if_true: files('milkymist-sysctl.c')) softmmu_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_gictimer.c')) softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-timer.c')) softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_timer.c')) diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c deleted file mode 100644 index 9ecea63861..0000000000 --- a/hw/timer/milkymist-sysctl.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * QEMU model of the Milkymist System Controller. - * - * Copyright (c) 2010-2012 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/sysctl.pdf - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "migration/vmstate.h" -#include "trace.h" -#include "qemu/timer.h" -#include "sysemu/runstate.h" -#include "hw/ptimer.h" -#include "hw/qdev-properties.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -enum { - CTRL_ENABLE = (1<<0), - CTRL_AUTORESTART = (1<<1), -}; - -enum { - ICAP_READY = (1<<0), -}; - -enum { - R_GPIO_IN = 0, - R_GPIO_OUT, - R_GPIO_INTEN, - R_TIMER0_CONTROL = 4, - R_TIMER0_COMPARE, - R_TIMER0_COUNTER, - R_TIMER1_CONTROL = 8, - R_TIMER1_COMPARE, - R_TIMER1_COUNTER, - R_ICAP = 16, - R_DBG_SCRATCHPAD = 20, - R_DBG_WRITE_LOCK, - R_CLK_FREQUENCY = 29, - R_CAPABILITIES, - R_SYSTEM_ID, - R_MAX -}; - -#define TYPE_MILKYMIST_SYSCTL "milkymist-sysctl" -OBJECT_DECLARE_SIMPLE_TYPE(MilkymistSysctlState, MILKYMIST_SYSCTL) - -struct MilkymistSysctlState { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - - ptimer_state *ptimer0; - ptimer_state *ptimer1; - - uint32_t freq_hz; - uint32_t capabilities; - uint32_t systemid; - uint32_t strappings; - - uint32_t regs[R_MAX]; - - qemu_irq gpio_irq; - qemu_irq timer0_irq; - qemu_irq timer1_irq; -}; - -static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value) -{ - trace_milkymist_sysctl_icap_write(value); - switch (value & 0xffff) { - case 0x000e: - qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); - break; - } -} - -static uint64_t sysctl_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistSysctlState *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_TIMER0_COUNTER: - r = (uint32_t)ptimer_get_count(s->ptimer0); - /* milkymist timer counts up */ - r = s->regs[R_TIMER0_COMPARE] - r; - break; - case R_TIMER1_COUNTER: - r = (uint32_t)ptimer_get_count(s->ptimer1); - /* milkymist timer counts up */ - r = s->regs[R_TIMER1_COMPARE] - r; - break; - case R_GPIO_IN: - case R_GPIO_OUT: - case R_GPIO_INTEN: - case R_TIMER0_CONTROL: - case R_TIMER0_COMPARE: - case R_TIMER1_CONTROL: - case R_TIMER1_COMPARE: - case R_ICAP: - case R_DBG_SCRATCHPAD: - case R_DBG_WRITE_LOCK: - case R_CLK_FREQUENCY: - case R_CAPABILITIES: - case R_SYSTEM_ID: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_sysctl: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_sysctl_memory_read(addr << 2, r); - - return r; -} - -static void sysctl_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistSysctlState *s = opaque; - - trace_milkymist_sysctl_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_GPIO_OUT: - case R_GPIO_INTEN: - case R_TIMER0_COUNTER: - case R_TIMER1_COUNTER: - case R_DBG_SCRATCHPAD: - s->regs[addr] = value; - break; - case R_TIMER0_COMPARE: - ptimer_transaction_begin(s->ptimer0); - ptimer_set_limit(s->ptimer0, value, 0); - s->regs[addr] = value; - ptimer_transaction_commit(s->ptimer0); - break; - case R_TIMER1_COMPARE: - ptimer_transaction_begin(s->ptimer1); - ptimer_set_limit(s->ptimer1, value, 0); - s->regs[addr] = value; - ptimer_transaction_commit(s->ptimer1); - break; - case R_TIMER0_CONTROL: - ptimer_transaction_begin(s->ptimer0); - s->regs[addr] = value; - if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) { - trace_milkymist_sysctl_start_timer0(); - ptimer_set_count(s->ptimer0, - s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]); - ptimer_run(s->ptimer0, 0); - } else { - trace_milkymist_sysctl_stop_timer0(); - ptimer_stop(s->ptimer0); - } - ptimer_transaction_commit(s->ptimer0); - break; - case R_TIMER1_CONTROL: - ptimer_transaction_begin(s->ptimer1); - s->regs[addr] = value; - if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) { - trace_milkymist_sysctl_start_timer1(); - ptimer_set_count(s->ptimer1, - s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]); - ptimer_run(s->ptimer1, 0); - } else { - trace_milkymist_sysctl_stop_timer1(); - ptimer_stop(s->ptimer1); - } - ptimer_transaction_commit(s->ptimer1); - break; - case R_ICAP: - sysctl_icap_write(s, value); - break; - case R_DBG_WRITE_LOCK: - s->regs[addr] = 1; - break; - case R_SYSTEM_ID: - qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); - break; - - case R_GPIO_IN: - case R_CLK_FREQUENCY: - case R_CAPABILITIES: - error_report("milkymist_sysctl: write to read-only register 0x" - TARGET_FMT_plx, addr << 2); - break; - - default: - error_report("milkymist_sysctl: write access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } -} - -static const MemoryRegionOps sysctl_mmio_ops = { - .read = sysctl_read, - .write = sysctl_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void timer0_hit(void *opaque) -{ - MilkymistSysctlState *s = opaque; - - if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) { - s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE; - trace_milkymist_sysctl_stop_timer0(); - ptimer_stop(s->ptimer0); - } - - trace_milkymist_sysctl_pulse_irq_timer0(); - qemu_irq_pulse(s->timer0_irq); -} - -static void timer1_hit(void *opaque) -{ - MilkymistSysctlState *s = opaque; - - if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) { - s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE; - trace_milkymist_sysctl_stop_timer1(); - ptimer_stop(s->ptimer1); - } - - trace_milkymist_sysctl_pulse_irq_timer1(); - qemu_irq_pulse(s->timer1_irq); -} - -static void milkymist_sysctl_reset(DeviceState *d) -{ - MilkymistSysctlState *s = MILKYMIST_SYSCTL(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - ptimer_transaction_begin(s->ptimer0); - ptimer_stop(s->ptimer0); - ptimer_transaction_commit(s->ptimer0); - ptimer_transaction_begin(s->ptimer1); - ptimer_stop(s->ptimer1); - ptimer_transaction_commit(s->ptimer1); - - /* defaults */ - s->regs[R_ICAP] = ICAP_READY; - s->regs[R_SYSTEM_ID] = s->systemid; - s->regs[R_CLK_FREQUENCY] = s->freq_hz; - s->regs[R_CAPABILITIES] = s->capabilities; - s->regs[R_GPIO_IN] = s->strappings; -} - -static void milkymist_sysctl_init(Object *obj) -{ - MilkymistSysctlState *s = MILKYMIST_SYSCTL(obj); - SysBusDevice *dev = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(dev, &s->gpio_irq); - sysbus_init_irq(dev, &s->timer0_irq); - sysbus_init_irq(dev, &s->timer1_irq); - - memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s, - "milkymist-sysctl", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); -} - -static void milkymist_sysctl_realize(DeviceState *dev, Error **errp) -{ - MilkymistSysctlState *s = MILKYMIST_SYSCTL(dev); - - s->ptimer0 = ptimer_init(timer0_hit, s, PTIMER_POLICY_DEFAULT); - s->ptimer1 = ptimer_init(timer1_hit, s, PTIMER_POLICY_DEFAULT); - - ptimer_transaction_begin(s->ptimer0); - ptimer_set_freq(s->ptimer0, s->freq_hz); - ptimer_transaction_commit(s->ptimer0); - ptimer_transaction_begin(s->ptimer1); - ptimer_set_freq(s->ptimer1, s->freq_hz); - ptimer_transaction_commit(s->ptimer1); -} - -static const VMStateDescription vmstate_milkymist_sysctl = { - .name = "milkymist-sysctl", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX), - VMSTATE_PTIMER(ptimer0, MilkymistSysctlState), - VMSTATE_PTIMER(ptimer1, MilkymistSysctlState), - VMSTATE_END_OF_LIST() - } -}; - -static Property milkymist_sysctl_properties[] = { - DEFINE_PROP_UINT32("frequency", MilkymistSysctlState, - freq_hz, 80000000), - DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState, - capabilities, 0x00000000), - DEFINE_PROP_UINT32("systemid", MilkymistSysctlState, - systemid, 0x10014d31), - DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState, - strappings, 0x00000001), - DEFINE_PROP_END_OF_LIST(), -}; - -static void milkymist_sysctl_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = milkymist_sysctl_realize; - dc->reset = milkymist_sysctl_reset; - dc->vmsd = &vmstate_milkymist_sysctl; - device_class_set_props(dc, milkymist_sysctl_properties); -} - -static const TypeInfo milkymist_sysctl_info = { - .name = TYPE_MILKYMIST_SYSCTL, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistSysctlState), - .instance_init = milkymist_sysctl_init, - .class_init = milkymist_sysctl_class_init, -}; - -static void milkymist_sysctl_register_types(void) -{ - type_register_static(&milkymist_sysctl_info); -} - -type_init(milkymist_sysctl_register_types) diff --git a/hw/timer/trace-events b/hw/timer/trace-events index f8b9db25c2..029fb56280 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -24,23 +24,6 @@ grlib_gptimer_hit(int id) "timer:%d HIT" grlib_gptimer_readl(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" grlib_gptimer_writel(int id, uint64_t addr, uint32_t val) "timer:%d addr 0x%"PRIx64" 0x%x" -# lm32_timer.c -lm32_timer_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_timer_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -lm32_timer_hit(void) "timer hit" -lm32_timer_irq_state(int level) "irq state %d" - -# milkymist-sysctl.c -milkymist_sysctl_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_sysctl_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" -milkymist_sysctl_icap_write(uint32_t value) "value 0x%08x" -milkymist_sysctl_start_timer0(void) "Start timer0" -milkymist_sysctl_stop_timer0(void) "Stop timer0" -milkymist_sysctl_start_timer1(void) "Start timer1" -milkymist_sysctl_stop_timer1(void) "Stop timer1" -milkymist_sysctl_pulse_irq_timer0(void) "Pulse IRQ Timer0" -milkymist_sysctl_pulse_irq_timer1(void) "Pulse IRQ Timer1" - # aspeed_timer.c aspeed_timer_ctrl_enable(uint8_t i, bool enable) "Timer %" PRIu8 ": %d" aspeed_timer_ctrl_external_clock(uint8_t i, bool enable) "Timer %" PRIu8 ": %d" diff --git a/hw/usb/quirks-ftdi-ids.h b/hw/usb/quirks-ftdi-ids.h index 57c12ef662..01aca55ca7 100644 --- a/hw/usb/quirks-ftdi-ids.h +++ b/hw/usb/quirks-ftdi-ids.h @@ -1221,12 +1221,6 @@ #define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID 0xFF1C #define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D -/* - * Milkymist One JTAG/Serial - */ -#define QIHARDWARE_VID 0x20B7 -#define MILKYMISTONE_JTAGSERIAL_PID 0x0713 - /* * CTI GmbH RS485 Converter http://www.cti-lean.com/ */ diff --git a/hw/usb/quirks.h b/hw/usb/quirks.h index 50ef2f9c2e..c3e595f40b 100644 --- a/hw/usb/quirks.h +++ b/hw/usb/quirks.h @@ -904,7 +904,6 @@ static const struct usb_device_id usbredir_ftdi_serial_ids[] = { { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, - { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID) }, { USB_DEVICE(ST_VID, ST_STMCLT1030_PID) }, { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID) }, diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index 8e985e7e94..524f29196d 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -249,8 +249,6 @@ enum bfd_architecture #define bfd_mach_nios2 0 #define bfd_mach_nios2r1 1 #define bfd_mach_nios2r2 2 - bfd_arch_lm32, /* Lattice Mico32 */ -#define bfd_mach_lm32 1 bfd_arch_rx, /* Renesas RX */ #define bfd_mach_rx 0x75 #define bfd_mach_rx_v2 0x76 @@ -457,7 +455,6 @@ int print_insn_crisv32 (bfd_vma, disassemble_info*); int print_insn_crisv10 (bfd_vma, disassemble_info*); int print_insn_microblaze (bfd_vma, disassemble_info*); int print_insn_ia64 (bfd_vma, disassemble_info*); -int print_insn_lm32 (bfd_vma, disassemble_info*); int print_insn_big_nios2 (bfd_vma, disassemble_info*); int print_insn_little_nios2 (bfd_vma, disassemble_info*); int print_insn_xtensa (bfd_vma, disassemble_info*); diff --git a/include/exec/poison.h b/include/exec/poison.h index de972bfd8e..b102e3cbf0 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -12,7 +12,6 @@ #pragma GCC poison TARGET_CRIS #pragma GCC poison TARGET_HEXAGON #pragma GCC poison TARGET_HPPA -#pragma GCC poison TARGET_LM32 #pragma GCC poison TARGET_M68K #pragma GCC poison TARGET_MICROBLAZE #pragma GCC poison TARGET_MIPS @@ -73,7 +72,6 @@ #pragma GCC poison CONFIG_HPPA_DIS #pragma GCC poison CONFIG_I386_DIS #pragma GCC poison CONFIG_HEXAGON_DIS -#pragma GCC poison CONFIG_LM32_DIS #pragma GCC poison CONFIG_M68K_DIS #pragma GCC poison CONFIG_MICROBLAZE_DIS #pragma GCC poison CONFIG_MIPS_DIS diff --git a/include/hw/char/lm32_juart.h b/include/hw/char/lm32_juart.h deleted file mode 100644 index 6fce278326..0000000000 --- a/include/hw/char/lm32_juart.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef QEMU_HW_CHAR_LM32_JUART_H -#define QEMU_HW_CHAR_LM32_JUART_H - -#include "hw/qdev-core.h" - -#define TYPE_LM32_JUART "lm32-juart" - -uint32_t lm32_juart_get_jtx(DeviceState *d); -uint32_t lm32_juart_get_jrx(DeviceState *d); -void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx); -void lm32_juart_set_jrx(DeviceState *d, uint32_t jrx); - -#endif /* QEMU_HW_CHAR_LM32_JUART_H */ diff --git a/include/hw/display/milkymist_tmu2.h b/include/hw/display/milkymist_tmu2.h deleted file mode 100644 index fdce9535a1..0000000000 --- a/include/hw/display/milkymist_tmu2.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * QEMU model of the Milkymist texture mapping unit. - * - * Copyright (c) 2010 Michael Walle - * Copyright (c) 2010 Sebastien Bourdeauducq - * - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://milkymist.walle.cc/socdoc/tmu2.pdf - * - */ - -#ifndef HW_DISPLAY_MILKYMIST_TMU2_H -#define HW_DISPLAY_MILKYMIST_TMU2_H - -#include "exec/hwaddr.h" -#include "hw/qdev-core.h" - -#if defined(CONFIG_X11) && defined(CONFIG_OPENGL) -DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq); -#else -static inline DeviceState *milkymist_tmu2_create(hwaddr base, qemu_irq irq) -{ - return NULL; -} -#endif - -#endif /* HW_DISPLAY_MILKYMIST_TMU2_H */ diff --git a/include/hw/lm32/lm32_pic.h b/include/hw/lm32/lm32_pic.h deleted file mode 100644 index 9e5e038437..0000000000 --- a/include/hw/lm32/lm32_pic.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef QEMU_HW_LM32_PIC_H -#define QEMU_HW_LM32_PIC_H - - -uint32_t lm32_pic_get_ip(DeviceState *d); -uint32_t lm32_pic_get_im(DeviceState *d); -void lm32_pic_set_ip(DeviceState *d, uint32_t ip); -void lm32_pic_set_im(DeviceState *d, uint32_t im); - -#endif /* QEMU_HW_LM32_PIC_H */ diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 44e3734d18..fc002b84de 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -9,7 +9,6 @@ enum { QEMU_ARCH_CRIS = (1 << 2), QEMU_ARCH_I386 = (1 << 3), QEMU_ARCH_M68K = (1 << 4), - QEMU_ARCH_LM32 = (1 << 5), QEMU_ARCH_MICROBLAZE = (1 << 6), QEMU_ARCH_MIPS = (1 << 7), QEMU_ARCH_PPC = (1 << 8), diff --git a/meson.build b/meson.build index eeb82a4bc6..8e16e05c2a 100644 --- a/meson.build +++ b/meson.build @@ -847,7 +847,7 @@ if 'CONFIG_VTE' in config_host link_args: config_host['VTE_LIBS'].split()) endif x11 = not_found -if gtkx11.found() or 'lm32-softmmu' in target_dirs +if gtkx11.found() x11 = dependency('x11', method: 'pkg-config', required: gtkx11.found(), kwargs: static_kwargs) endif @@ -1210,7 +1210,6 @@ disassemblers = { 'i386' : ['CONFIG_I386_DIS'], 'x86_64' : ['CONFIG_I386_DIS'], 'x32' : ['CONFIG_I386_DIS'], - 'lm32' : ['CONFIG_LM32_DIS'], 'm68k' : ['CONFIG_M68K_DIS'], 'microblaze' : ['CONFIG_MICROBLAZE_DIS'], 'mips' : ['CONFIG_MIPS_DIS'], diff --git a/qapi/machine.json b/qapi/machine.json index f1e2ccceba..37a7e34195 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -29,7 +29,7 @@ # Since: 3.0 ## { 'enum' : 'SysEmuTarget', - 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', 'lm32', + 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc', 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', diff --git a/qemu-options.hx b/qemu-options.hx index 7c825f81fc..a81ca006db 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4288,7 +4288,7 @@ SRST ERST DEF("semihosting", 0, QEMU_OPTION_semihosting, "-semihosting semihosting mode\n", - QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | + QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST ``-semihosting`` @@ -4303,7 +4303,7 @@ ERST DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, "-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \ " semihosting configuration\n", -QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | +QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST ``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]`` diff --git a/softmmu/arch_init.c b/softmmu/arch_init.c index afb0904020..2b90884e3a 100644 --- a/softmmu/arch_init.c +++ b/softmmu/arch_init.c @@ -56,8 +56,6 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_HPPA #elif defined(TARGET_I386) #define QEMU_ARCH QEMU_ARCH_I386 -#elif defined(TARGET_LM32) -#define QEMU_ARCH QEMU_ARCH_LM32 #elif defined(TARGET_M68K) #define QEMU_ARCH QEMU_ARCH_M68K #elif defined(TARGET_MICROBLAZE) diff --git a/target/lm32/README b/target/lm32/README deleted file mode 100644 index ba3508a711..0000000000 --- a/target/lm32/README +++ /dev/null @@ -1,45 +0,0 @@ -LatticeMico32 target --------------------- - -General -------- -All opcodes including the JUART CSRs are supported. - - -JTAG UART ---------- -JTAG UART is routed to a serial console device. For the current boards it -is the second one. Ie to enable it in the qemu virtual console window use -the following command line parameters: - -serial vc -serial vc -This will make serial0 (the lm32_uart) and serial1 (the JTAG UART) -available as virtual consoles. - - -Semihosting ------------ -Semihosting on this target is supported. Some system calls like read, write -and exit are executed on the host if semihosting is enabled. See -target/lm32-semi.c for all supported system calls. Emulation aware programs -can use this mechanism to shut down the virtual machine and print to the -host console. See the tcg tests for an example. - - -Special instructions --------------------- -The translation recognizes one special instruction to halt the cpu: - and r0, r0, r0 -On real hardware this instruction is a nop. It is not used by GCC and -should (hopefully) not be used within hand-crafted assembly. -Insert this instruction in your idle loop to reduce the cpu load on the -host. - - -Ignoring the MSB of the address bus ------------------------------------ -Some SoC ignores the MSB on the address bus. Thus creating a shadow memory -area. As a general rule, 0x00000000-0x7fffffff is cached, whereas -0x80000000-0xffffffff is not cached and used to access IO devices. This -behaviour can be enabled with: - cpu_lm32_set_phys_msb_ignore(env, 1); - diff --git a/target/lm32/TODO b/target/lm32/TODO deleted file mode 100644 index e163c42ebe..0000000000 --- a/target/lm32/TODO +++ /dev/null @@ -1 +0,0 @@ -* linux-user emulation diff --git a/target/lm32/cpu-param.h b/target/lm32/cpu-param.h deleted file mode 100644 index d89574ad19..0000000000 --- a/target/lm32/cpu-param.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * LatticeMico32 cpu parameters for qemu. - * - * Copyright (c) 2010 Michael Walle - * SPDX-License-Identifier: LGPL-2.0+ - */ - -#ifndef LM32_CPU_PARAM_H -#define LM32_CPU_PARAM_H 1 - -#define TARGET_LONG_BITS 32 -#define TARGET_PAGE_BITS 12 -#define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 -#define NB_MMU_MODES 1 - -#endif diff --git a/target/lm32/cpu-qom.h b/target/lm32/cpu-qom.h deleted file mode 100644 index 245b35cd1d..0000000000 --- a/target/lm32/cpu-qom.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * QEMU LatticeMico32 CPU - * - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * - */ -#ifndef QEMU_LM32_CPU_QOM_H -#define QEMU_LM32_CPU_QOM_H - -#include "hw/core/cpu.h" -#include "qom/object.h" - -#define TYPE_LM32_CPU "lm32-cpu" - -OBJECT_DECLARE_TYPE(LM32CPU, LM32CPUClass, - LM32_CPU) - -/** - * LM32CPUClass: - * @parent_realize: The parent class' realize handler. - * @parent_reset: The parent class' reset handler. - * - * A LatticeMico32 CPU model. - */ -struct LM32CPUClass { - /*< private >*/ - CPUClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; - DeviceReset parent_reset; -}; - - -#endif diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c deleted file mode 100644 index c23d72874c..0000000000 --- a/target/lm32/cpu.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * QEMU LatticeMico32 CPU - * - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu/qemu-print.h" -#include "cpu.h" - - -static void lm32_cpu_set_pc(CPUState *cs, vaddr value) -{ - LM32CPU *cpu = LM32_CPU(cs); - - cpu->env.pc = value; -} - -static void lm32_cpu_list_entry(gpointer data, gpointer user_data) -{ - ObjectClass *oc = data; - const char *typename = object_class_get_name(oc); - char *name; - - name = g_strndup(typename, strlen(typename) - strlen(LM32_CPU_TYPE_SUFFIX)); - qemu_printf(" %s\n", name); - g_free(name); -} - - -void lm32_cpu_list(void) -{ - GSList *list; - - list = object_class_get_list_sorted(TYPE_LM32_CPU, false); - qemu_printf("Available CPUs:\n"); - g_slist_foreach(list, lm32_cpu_list_entry, NULL); - g_slist_free(list); -} - -static void lm32_cpu_init_cfg_reg(LM32CPU *cpu) -{ - CPULM32State *env = &cpu->env; - uint32_t cfg = 0; - - if (cpu->features & LM32_FEATURE_MULTIPLY) { - cfg |= CFG_M; - } - - if (cpu->features & LM32_FEATURE_DIVIDE) { - cfg |= CFG_D; - } - - if (cpu->features & LM32_FEATURE_SHIFT) { - cfg |= CFG_S; - } - - if (cpu->features & LM32_FEATURE_SIGN_EXTEND) { - cfg |= CFG_X; - } - - if (cpu->features & LM32_FEATURE_I_CACHE) { - cfg |= CFG_IC; - } - - if (cpu->features & LM32_FEATURE_D_CACHE) { - cfg |= CFG_DC; - } - - if (cpu->features & LM32_FEATURE_CYCLE_COUNT) { - cfg |= CFG_CC; - } - - cfg |= (cpu->num_interrupts << CFG_INT_SHIFT); - cfg |= (cpu->num_breakpoints << CFG_BP_SHIFT); - cfg |= (cpu->num_watchpoints << CFG_WP_SHIFT); - cfg |= (cpu->revision << CFG_REV_SHIFT); - - env->cfg = cfg; -} - -static bool lm32_cpu_has_work(CPUState *cs) -{ - return cs->interrupt_request & CPU_INTERRUPT_HARD; -} - -static void lm32_cpu_reset(DeviceState *dev) -{ - CPUState *s = CPU(dev); - LM32CPU *cpu = LM32_CPU(s); - LM32CPUClass *lcc = LM32_CPU_GET_CLASS(cpu); - CPULM32State *env = &cpu->env; - - lcc->parent_reset(dev); - - /* reset cpu state */ - memset(env, 0, offsetof(CPULM32State, end_reset_fields)); - - lm32_cpu_init_cfg_reg(cpu); -} - -static void lm32_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) -{ - info->mach = bfd_mach_lm32; - info->print_insn = print_insn_lm32; -} - -static void lm32_cpu_realizefn(DeviceState *dev, Error **errp) -{ - CPUState *cs = CPU(dev); - LM32CPUClass *lcc = LM32_CPU_GET_CLASS(dev); - Error *local_err = NULL; - - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - cpu_reset(cs); - - qemu_init_vcpu(cs); - - lcc->parent_realize(dev, errp); -} - -static void lm32_cpu_initfn(Object *obj) -{ - LM32CPU *cpu = LM32_CPU(obj); - CPULM32State *env = &cpu->env; - - cpu_set_cpustate_pointers(cpu); - - env->flags = 0; -} - -static void lm32_basic_cpu_initfn(Object *obj) -{ - LM32CPU *cpu = LM32_CPU(obj); - - cpu->revision = 3; - cpu->num_interrupts = 32; - cpu->num_breakpoints = 4; - cpu->num_watchpoints = 4; - cpu->features = LM32_FEATURE_SHIFT - | LM32_FEATURE_SIGN_EXTEND - | LM32_FEATURE_CYCLE_COUNT; -} - -static void lm32_standard_cpu_initfn(Object *obj) -{ - LM32CPU *cpu = LM32_CPU(obj); - - cpu->revision = 3; - cpu->num_interrupts = 32; - cpu->num_breakpoints = 4; - cpu->num_watchpoints = 4; - cpu->features = LM32_FEATURE_MULTIPLY - | LM32_FEATURE_DIVIDE - | LM32_FEATURE_SHIFT - | LM32_FEATURE_SIGN_EXTEND - | LM32_FEATURE_I_CACHE - | LM32_FEATURE_CYCLE_COUNT; -} - -static void lm32_full_cpu_initfn(Object *obj) -{ - LM32CPU *cpu = LM32_CPU(obj); - - cpu->revision = 3; - cpu->num_interrupts = 32; - cpu->num_breakpoints = 4; - cpu->num_watchpoints = 4; - cpu->features = LM32_FEATURE_MULTIPLY - | LM32_FEATURE_DIVIDE - | LM32_FEATURE_SHIFT - | LM32_FEATURE_SIGN_EXTEND - | LM32_FEATURE_I_CACHE - | LM32_FEATURE_D_CACHE - | LM32_FEATURE_CYCLE_COUNT; -} - -static ObjectClass *lm32_cpu_class_by_name(const char *cpu_model) -{ - ObjectClass *oc; - char *typename; - - typename = g_strdup_printf(LM32_CPU_TYPE_NAME("%s"), cpu_model); - oc = object_class_by_name(typename); - g_free(typename); - if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_LM32_CPU) || - object_class_is_abstract(oc))) { - oc = NULL; - } - return oc; -} - -#include "hw/core/tcg-cpu-ops.h" - -static struct TCGCPUOps lm32_tcg_ops = { - .initialize = lm32_translate_init, - .cpu_exec_interrupt = lm32_cpu_exec_interrupt, - .tlb_fill = lm32_cpu_tlb_fill, - .debug_excp_handler = lm32_debug_excp_handler, - -#ifndef CONFIG_USER_ONLY - .do_interrupt = lm32_cpu_do_interrupt, -#endif /* !CONFIG_USER_ONLY */ -}; - -static void lm32_cpu_class_init(ObjectClass *oc, void *data) -{ - LM32CPUClass *lcc = LM32_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); - DeviceClass *dc = DEVICE_CLASS(oc); - - device_class_set_parent_realize(dc, lm32_cpu_realizefn, - &lcc->parent_realize); - device_class_set_parent_reset(dc, lm32_cpu_reset, &lcc->parent_reset); - - cc->class_by_name = lm32_cpu_class_by_name; - cc->has_work = lm32_cpu_has_work; - cc->dump_state = lm32_cpu_dump_state; - cc->set_pc = lm32_cpu_set_pc; - cc->gdb_read_register = lm32_cpu_gdb_read_register; - cc->gdb_write_register = lm32_cpu_gdb_write_register; -#ifndef CONFIG_USER_ONLY - cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug; - cc->vmsd = &vmstate_lm32_cpu; -#endif - cc->gdb_num_core_regs = 32 + 7; - cc->gdb_stop_before_watchpoint = true; - cc->disas_set_info = lm32_cpu_disas_set_info; - cc->tcg_ops = &lm32_tcg_ops; -} - -#define DEFINE_LM32_CPU_TYPE(cpu_model, initfn) \ - { \ - .parent = TYPE_LM32_CPU, \ - .name = LM32_CPU_TYPE_NAME(cpu_model), \ - .instance_init = initfn, \ - } - -static const TypeInfo lm32_cpus_type_infos[] = { - { /* base class should be registered first */ - .name = TYPE_LM32_CPU, - .parent = TYPE_CPU, - .instance_size = sizeof(LM32CPU), - .instance_init = lm32_cpu_initfn, - .abstract = true, - .class_size = sizeof(LM32CPUClass), - .class_init = lm32_cpu_class_init, - }, - DEFINE_LM32_CPU_TYPE("lm32-basic", lm32_basic_cpu_initfn), - DEFINE_LM32_CPU_TYPE("lm32-standard", lm32_standard_cpu_initfn), - DEFINE_LM32_CPU_TYPE("lm32-full", lm32_full_cpu_initfn), -}; - -DEFINE_TYPES(lm32_cpus_type_infos) diff --git a/target/lm32/cpu.h b/target/lm32/cpu.h deleted file mode 100644 index ea7c01ca8b..0000000000 --- a/target/lm32/cpu.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - * LatticeMico32 virtual CPU header. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#ifndef LM32_CPU_H -#define LM32_CPU_H - -#include "cpu-qom.h" -#include "exec/cpu-defs.h" - -typedef struct CPULM32State CPULM32State; - -static inline int cpu_mmu_index(CPULM32State *env, bool ifetch) -{ - return 0; -} - -/* Exceptions indices */ -enum { - EXCP_RESET = 0, - EXCP_BREAKPOINT, - EXCP_INSN_BUS_ERROR, - EXCP_WATCHPOINT, - EXCP_DATA_BUS_ERROR, - EXCP_DIVIDE_BY_ZERO, - EXCP_IRQ, - EXCP_SYSTEMCALL -}; - -/* Registers */ -enum { - R_R0 = 0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R10, - R_R11, R_R12, R_R13, R_R14, R_R15, R_R16, R_R17, R_R18, R_R19, R_R20, - R_R21, R_R22, R_R23, R_R24, R_R25, R_R26, R_R27, R_R28, R_R29, R_R30, - R_R31 -}; - -/* Register aliases */ -enum { - R_GP = R_R26, - R_FP = R_R27, - R_SP = R_R28, - R_RA = R_R29, - R_EA = R_R30, - R_BA = R_R31 -}; - -/* IE flags */ -enum { - IE_IE = (1<<0), - IE_EIE = (1<<1), - IE_BIE = (1<<2), -}; - -/* DC flags */ -enum { - DC_SS = (1<<0), - DC_RE = (1<<1), - DC_C0 = (1<<2), - DC_C1 = (1<<3), - DC_C2 = (1<<4), - DC_C3 = (1<<5), -}; - -/* CFG mask */ -enum { - CFG_M = (1<<0), - CFG_D = (1<<1), - CFG_S = (1<<2), - CFG_U = (1<<3), - CFG_X = (1<<4), - CFG_CC = (1<<5), - CFG_IC = (1<<6), - CFG_DC = (1<<7), - CFG_G = (1<<8), - CFG_H = (1<<9), - CFG_R = (1<<10), - CFG_J = (1<<11), - CFG_INT_SHIFT = 12, - CFG_BP_SHIFT = 18, - CFG_WP_SHIFT = 22, - CFG_REV_SHIFT = 26, -}; - -/* CSRs */ -enum { - CSR_IE = 0x00, - CSR_IM = 0x01, - CSR_IP = 0x02, - CSR_ICC = 0x03, - CSR_DCC = 0x04, - CSR_CC = 0x05, - CSR_CFG = 0x06, - CSR_EBA = 0x07, - CSR_DC = 0x08, - CSR_DEBA = 0x09, - CSR_JTX = 0x0e, - CSR_JRX = 0x0f, - CSR_BP0 = 0x10, - CSR_BP1 = 0x11, - CSR_BP2 = 0x12, - CSR_BP3 = 0x13, - CSR_WP0 = 0x18, - CSR_WP1 = 0x19, - CSR_WP2 = 0x1a, - CSR_WP3 = 0x1b, -}; - -enum { - LM32_FEATURE_MULTIPLY = 1, - LM32_FEATURE_DIVIDE = 2, - LM32_FEATURE_SHIFT = 4, - LM32_FEATURE_SIGN_EXTEND = 8, - LM32_FEATURE_I_CACHE = 16, - LM32_FEATURE_D_CACHE = 32, - LM32_FEATURE_CYCLE_COUNT = 64, -}; - -enum { - LM32_FLAG_IGNORE_MSB = 1, -}; - -struct CPULM32State { - /* general registers */ - uint32_t regs[32]; - - /* special registers */ - uint32_t pc; /* program counter */ - uint32_t ie; /* interrupt enable */ - uint32_t icc; /* instruction cache control */ - uint32_t dcc; /* data cache control */ - uint32_t cc; /* cycle counter */ - uint32_t cfg; /* configuration */ - - /* debug registers */ - uint32_t dc; /* debug control */ - uint32_t bp[4]; /* breakpoints */ - uint32_t wp[4]; /* watchpoints */ - - struct CPUBreakpoint *cpu_breakpoint[4]; - struct CPUWatchpoint *cpu_watchpoint[4]; - - /* Fields up to this point are cleared by a CPU reset */ - struct {} end_reset_fields; - - /* Fields from here on are preserved across CPU reset. */ - uint32_t eba; /* exception base address */ - uint32_t deba; /* debug exception base address */ - - /* interrupt controller handle for callbacks */ - DeviceState *pic_state; - /* JTAG UART handle for callbacks */ - DeviceState *juart_state; - - /* processor core features */ - uint32_t flags; - -}; - -/** - * LM32CPU: - * @env: #CPULM32State - * - * A LatticeMico32 CPU. - */ -struct LM32CPU { - /*< private >*/ - CPUState parent_obj; - /*< public >*/ - - CPUNegativeOffsetState neg; - CPULM32State env; - - uint32_t revision; - uint8_t num_interrupts; - uint8_t num_breakpoints; - uint8_t num_watchpoints; - uint32_t features; -}; - - -#ifndef CONFIG_USER_ONLY -extern const VMStateDescription vmstate_lm32_cpu; -#endif - -void lm32_cpu_do_interrupt(CPUState *cpu); -bool lm32_cpu_exec_interrupt(CPUState *cs, int int_req); -void lm32_cpu_dump_state(CPUState *cpu, FILE *f, int flags); -hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -int lm32_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); -int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); - -typedef enum { - LM32_WP_DISABLED = 0, - LM32_WP_READ, - LM32_WP_WRITE, - LM32_WP_READ_WRITE, -} lm32_wp_t; - -static inline lm32_wp_t lm32_wp_type(uint32_t dc, int idx) -{ - assert(idx < 4); - return (dc >> (idx+1)*2) & 0x3; -} - -/* you can call this signal handler from your SIGBUS and SIGSEGV - signal handlers to inform the virtual CPU of exceptions. non zero - is returned if the signal was handled by the virtual CPU. */ -int cpu_lm32_signal_handler(int host_signum, void *pinfo, - void *puc); -void lm32_cpu_list(void); -void lm32_translate_init(void); -void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value); -void QEMU_NORETURN raise_exception(CPULM32State *env, int index); -void lm32_debug_excp_handler(CPUState *cs); -void lm32_breakpoint_insert(CPULM32State *env, int index, target_ulong address); -void lm32_breakpoint_remove(CPULM32State *env, int index); -void lm32_watchpoint_insert(CPULM32State *env, int index, target_ulong address, - lm32_wp_t wp_type); -void lm32_watchpoint_remove(CPULM32State *env, int index); -bool lm32_cpu_do_semihosting(CPUState *cs); - -#define LM32_CPU_TYPE_SUFFIX "-" TYPE_LM32_CPU -#define LM32_CPU_TYPE_NAME(model) model LM32_CPU_TYPE_SUFFIX -#define CPU_RESOLVING_TYPE TYPE_LM32_CPU - -#define cpu_list lm32_cpu_list -#define cpu_signal_handler cpu_lm32_signal_handler - -bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr); - -typedef CPULM32State CPUArchState; -typedef LM32CPU ArchCPU; - -#include "exec/cpu-all.h" - -static inline void cpu_get_tb_cpu_state(CPULM32State *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *cs_base = 0; - *flags = 0; -} - -#endif diff --git a/target/lm32/gdbstub.c b/target/lm32/gdbstub.c deleted file mode 100644 index 56f508a5b6..0000000000 --- a/target/lm32/gdbstub.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * LM32 gdb server stub - * - * Copyright (c) 2003-2005 Fabrice Bellard - * Copyright (c) 2013 SUSE LINUX Products GmbH - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/gdbstub.h" -#include "hw/lm32/lm32_pic.h" - -int lm32_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - - if (n < 32) { - return gdb_get_reg32(mem_buf, env->regs[n]); - } else { - switch (n) { - case 32: - return gdb_get_reg32(mem_buf, env->pc); - /* FIXME: put in right exception ID */ - case 33: - return gdb_get_reg32(mem_buf, 0); - case 34: - return gdb_get_reg32(mem_buf, env->eba); - case 35: - return gdb_get_reg32(mem_buf, env->deba); - case 36: - return gdb_get_reg32(mem_buf, env->ie); - case 37: - return gdb_get_reg32(mem_buf, lm32_pic_get_im(env->pic_state)); - case 38: - return gdb_get_reg32(mem_buf, lm32_pic_get_ip(env->pic_state)); - } - } - return 0; -} - -int lm32_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPUClass *cc = CPU_GET_CLASS(cs); - CPULM32State *env = &cpu->env; - uint32_t tmp; - - if (n > cc->gdb_num_core_regs) { - return 0; - } - - tmp = ldl_p(mem_buf); - - if (n < 32) { - env->regs[n] = tmp; - } else { - switch (n) { - case 32: - env->pc = tmp; - break; - case 34: - env->eba = tmp; - break; - case 35: - env->deba = tmp; - break; - case 36: - env->ie = tmp; - break; - case 37: - lm32_pic_set_im(env->pic_state, tmp); - break; - case 38: - lm32_pic_set_ip(env->pic_state, tmp); - break; - } - } - return 4; -} diff --git a/target/lm32/helper.c b/target/lm32/helper.c deleted file mode 100644 index 01cc3c53a5..0000000000 --- a/target/lm32/helper.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * LatticeMico32 helper routines. - * - * Copyright (c) 2010-2014 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/exec-all.h" -#include "qemu/host-utils.h" -#include "semihosting/semihost.h" -#include "exec/log.h" - -bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - int prot; - - address &= TARGET_PAGE_MASK; - prot = PAGE_BITS; - if (env->flags & LM32_FLAG_IGNORE_MSB) { - tlb_set_page(cs, address, address & 0x7fffffff, prot, mmu_idx, - TARGET_PAGE_SIZE); - } else { - tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE); - } - return true; -} - -hwaddr lm32_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -{ - LM32CPU *cpu = LM32_CPU(cs); - - addr &= TARGET_PAGE_MASK; - if (cpu->env.flags & LM32_FLAG_IGNORE_MSB) { - return addr & 0x7fffffff; - } else { - return addr; - } -} - -void lm32_breakpoint_insert(CPULM32State *env, int idx, target_ulong address) -{ - cpu_breakpoint_insert(env_cpu(env), address, BP_CPU, - &env->cpu_breakpoint[idx]); -} - -void lm32_breakpoint_remove(CPULM32State *env, int idx) -{ - if (!env->cpu_breakpoint[idx]) { - return; - } - - cpu_breakpoint_remove_by_ref(env_cpu(env), env->cpu_breakpoint[idx]); - env->cpu_breakpoint[idx] = NULL; -} - -void lm32_watchpoint_insert(CPULM32State *env, int idx, target_ulong address, - lm32_wp_t wp_type) -{ - int flags = 0; - - switch (wp_type) { - case LM32_WP_DISABLED: - /* nothing to do */ - break; - case LM32_WP_READ: - flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_READ; - break; - case LM32_WP_WRITE: - flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_WRITE; - break; - case LM32_WP_READ_WRITE: - flags = BP_CPU | BP_STOP_BEFORE_ACCESS | BP_MEM_ACCESS; - break; - } - - if (flags != 0) { - cpu_watchpoint_insert(env_cpu(env), address, 1, flags, - &env->cpu_watchpoint[idx]); - } -} - -void lm32_watchpoint_remove(CPULM32State *env, int idx) -{ - if (!env->cpu_watchpoint[idx]) { - return; - } - - cpu_watchpoint_remove_by_ref(env_cpu(env), env->cpu_watchpoint[idx]); - env->cpu_watchpoint[idx] = NULL; -} - -static bool check_watchpoints(CPULM32State *env) -{ - LM32CPU *cpu = env_archcpu(env); - int i; - - for (i = 0; i < cpu->num_watchpoints; i++) { - if (env->cpu_watchpoint[i] && - env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) { - return true; - } - } - return false; -} - -void lm32_debug_excp_handler(CPUState *cs) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - CPUBreakpoint *bp; - - if (cs->watchpoint_hit) { - if (cs->watchpoint_hit->flags & BP_CPU) { - cs->watchpoint_hit = NULL; - if (check_watchpoints(env)) { - raise_exception(env, EXCP_WATCHPOINT); - } else { - cpu_loop_exit_noexc(cs); - } - } - } else { - QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { - if (bp->pc == env->pc) { - if (bp->flags & BP_CPU) { - raise_exception(env, EXCP_BREAKPOINT); - } - break; - } - } - } -} - -void lm32_cpu_do_interrupt(CPUState *cs) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - - qemu_log_mask(CPU_LOG_INT, - "exception at pc=%x type=%x\n", env->pc, cs->exception_index); - - switch (cs->exception_index) { - case EXCP_SYSTEMCALL: - if (unlikely(semihosting_enabled())) { - /* do_semicall() returns true if call was handled. Otherwise - * do the normal exception handling. */ - if (lm32_cpu_do_semihosting(cs)) { - env->pc += 4; - break; - } - } - /* fall through */ - case EXCP_INSN_BUS_ERROR: - case EXCP_DATA_BUS_ERROR: - case EXCP_DIVIDE_BY_ZERO: - case EXCP_IRQ: - /* non-debug exceptions */ - env->regs[R_EA] = env->pc; - env->ie |= (env->ie & IE_IE) ? IE_EIE : 0; - env->ie &= ~IE_IE; - if (env->dc & DC_RE) { - env->pc = env->deba + (cs->exception_index * 32); - } else { - env->pc = env->eba + (cs->exception_index * 32); - } - log_cpu_state_mask(CPU_LOG_INT, cs, 0); - break; - case EXCP_BREAKPOINT: - case EXCP_WATCHPOINT: - /* debug exceptions */ - env->regs[R_BA] = env->pc; - env->ie |= (env->ie & IE_IE) ? IE_BIE : 0; - env->ie &= ~IE_IE; - env->pc = env->deba + (cs->exception_index * 32); - log_cpu_state_mask(CPU_LOG_INT, cs, 0); - break; - default: - cpu_abort(cs, "unhandled exception type=%d\n", - cs->exception_index); - break; - } -} - -bool lm32_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - - if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->ie & IE_IE)) { - cs->exception_index = EXCP_IRQ; - lm32_cpu_do_interrupt(cs); - return true; - } - return false; -} - -/* Some soc ignores the MSB on the address bus. Thus creating a shadow memory - * area. As a general rule, 0x00000000-0x7fffffff is cached, whereas - * 0x80000000-0xffffffff is not cached and used to access IO devices. */ -void cpu_lm32_set_phys_msb_ignore(CPULM32State *env, int value) -{ - if (value) { - env->flags |= LM32_FLAG_IGNORE_MSB; - } else { - env->flags &= ~LM32_FLAG_IGNORE_MSB; - } -} diff --git a/target/lm32/helper.h b/target/lm32/helper.h deleted file mode 100644 index 445578c439..0000000000 --- a/target/lm32/helper.h +++ /dev/null @@ -1,14 +0,0 @@ -DEF_HELPER_2(raise_exception, void, env, i32) -DEF_HELPER_1(hlt, void, env) -DEF_HELPER_3(wcsr_bp, void, env, i32, i32) -DEF_HELPER_3(wcsr_wp, void, env, i32, i32) -DEF_HELPER_2(wcsr_dc, void, env, i32) -DEF_HELPER_2(wcsr_im, void, env, i32) -DEF_HELPER_2(wcsr_ip, void, env, i32) -DEF_HELPER_2(wcsr_jtx, void, env, i32) -DEF_HELPER_2(wcsr_jrx, void, env, i32) -DEF_HELPER_1(rcsr_im, i32, env) -DEF_HELPER_1(rcsr_ip, i32, env) -DEF_HELPER_1(rcsr_jtx, i32, env) -DEF_HELPER_1(rcsr_jrx, i32, env) -DEF_HELPER_1(ill, void, env) diff --git a/target/lm32/lm32-semi.c b/target/lm32/lm32-semi.c deleted file mode 100644 index 661a770249..0000000000 --- a/target/lm32/lm32-semi.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Lattice Mico32 semihosting syscall interface - * - * Copyright (c) 2014 Michael Walle - * - * Based on target/m68k/m68k-semi.c, which is - * Copyright (c) 2005-2007 CodeSourcery. - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "exec/softmmu-semi.h" - -enum { - TARGET_SYS_exit = 1, - TARGET_SYS_open = 2, - TARGET_SYS_close = 3, - TARGET_SYS_read = 4, - TARGET_SYS_write = 5, - TARGET_SYS_lseek = 6, - TARGET_SYS_fstat = 10, - TARGET_SYS_stat = 15, -}; - -enum { - NEWLIB_O_RDONLY = 0x0, - NEWLIB_O_WRONLY = 0x1, - NEWLIB_O_RDWR = 0x2, - NEWLIB_O_APPEND = 0x8, - NEWLIB_O_CREAT = 0x200, - NEWLIB_O_TRUNC = 0x400, - NEWLIB_O_EXCL = 0x800, -}; - -static int translate_openflags(int flags) -{ - int hf; - - if (flags & NEWLIB_O_WRONLY) { - hf = O_WRONLY; - } else if (flags & NEWLIB_O_RDWR) { - hf = O_RDWR; - } else { - hf = O_RDONLY; - } - - if (flags & NEWLIB_O_APPEND) { - hf |= O_APPEND; - } - - if (flags & NEWLIB_O_CREAT) { - hf |= O_CREAT; - } - - if (flags & NEWLIB_O_TRUNC) { - hf |= O_TRUNC; - } - - if (flags & NEWLIB_O_EXCL) { - hf |= O_EXCL; - } - - return hf; -} - -struct newlib_stat { - int16_t newlib_st_dev; /* device */ - uint16_t newlib_st_ino; /* inode */ - uint16_t newlib_st_mode; /* protection */ - uint16_t newlib_st_nlink; /* number of hard links */ - uint16_t newlib_st_uid; /* user ID of owner */ - uint16_t newlib_st_gid; /* group ID of owner */ - int16_t newlib_st_rdev; /* device type (if inode device) */ - int32_t newlib_st_size; /* total size, in bytes */ - int32_t newlib_st_atime; /* time of last access */ - uint32_t newlib_st_spare1; - int32_t newlib_st_mtime; /* time of last modification */ - uint32_t newlib_st_spare2; - int32_t newlib_st_ctime; /* time of last change */ - uint32_t newlib_st_spare3; -} QEMU_PACKED; - -static int translate_stat(CPULM32State *env, target_ulong addr, - struct stat *s) -{ - struct newlib_stat *p; - - p = lock_user(VERIFY_WRITE, addr, sizeof(struct newlib_stat), 0); - if (!p) { - return 0; - } - p->newlib_st_dev = cpu_to_be16(s->st_dev); - p->newlib_st_ino = cpu_to_be16(s->st_ino); - p->newlib_st_mode = cpu_to_be16(s->st_mode); - p->newlib_st_nlink = cpu_to_be16(s->st_nlink); - p->newlib_st_uid = cpu_to_be16(s->st_uid); - p->newlib_st_gid = cpu_to_be16(s->st_gid); - p->newlib_st_rdev = cpu_to_be16(s->st_rdev); - p->newlib_st_size = cpu_to_be32(s->st_size); - p->newlib_st_atime = cpu_to_be32(s->st_atime); - p->newlib_st_mtime = cpu_to_be32(s->st_mtime); - p->newlib_st_ctime = cpu_to_be32(s->st_ctime); - unlock_user(p, addr, sizeof(struct newlib_stat)); - - return 1; -} - -bool lm32_cpu_do_semihosting(CPUState *cs) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - - int ret = -1; - target_ulong nr, arg0, arg1, arg2; - void *p; - struct stat s; - - nr = env->regs[R_R8]; - arg0 = env->regs[R_R1]; - arg1 = env->regs[R_R2]; - arg2 = env->regs[R_R3]; - - switch (nr) { - case TARGET_SYS_exit: - /* void _exit(int rc) */ - exit(arg0); - - case TARGET_SYS_open: - /* int open(const char *pathname, int flags) */ - p = lock_user_string(arg0); - if (!p) { - ret = -1; - } else { - ret = open(p, translate_openflags(arg2)); - unlock_user(p, arg0, 0); - } - break; - - case TARGET_SYS_read: - /* ssize_t read(int fd, const void *buf, size_t count) */ - p = lock_user(VERIFY_WRITE, arg1, arg2, 0); - if (!p) { - ret = -1; - } else { - ret = read(arg0, p, arg2); - unlock_user(p, arg1, arg2); - } - break; - - case TARGET_SYS_write: - /* ssize_t write(int fd, const void *buf, size_t count) */ - p = lock_user(VERIFY_READ, arg1, arg2, 1); - if (!p) { - ret = -1; - } else { - ret = write(arg0, p, arg2); - unlock_user(p, arg1, 0); - } - break; - - case TARGET_SYS_close: - /* int close(int fd) */ - /* don't close stdin/stdout/stderr */ - if (arg0 > 2) { - ret = close(arg0); - } else { - ret = 0; - } - break; - - case TARGET_SYS_lseek: - /* off_t lseek(int fd, off_t offset, int whence */ - ret = lseek(arg0, arg1, arg2); - break; - - case TARGET_SYS_stat: - /* int stat(const char *path, struct stat *buf) */ - p = lock_user_string(arg0); - if (!p) { - ret = -1; - } else { - ret = stat(p, &s); - unlock_user(p, arg0, 0); - if (translate_stat(env, arg1, &s) == 0) { - ret = -1; - } - } - break; - - case TARGET_SYS_fstat: - /* int stat(int fd, struct stat *buf) */ - ret = fstat(arg0, &s); - if (ret == 0) { - if (translate_stat(env, arg1, &s) == 0) { - ret = -1; - } - } - break; - - default: - /* unhandled */ - return false; - } - - env->regs[R_R1] = ret; - return true; -} diff --git a/target/lm32/machine.c b/target/lm32/machine.c deleted file mode 100644 index 365eaa2e47..0000000000 --- a/target/lm32/machine.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "qemu/osdep.h" -#include "cpu.h" -#include "migration/cpu.h" - -static const VMStateDescription vmstate_env = { - .name = "env", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, CPULM32State, 32), - VMSTATE_UINT32(pc, CPULM32State), - VMSTATE_UINT32(ie, CPULM32State), - VMSTATE_UINT32(icc, CPULM32State), - VMSTATE_UINT32(dcc, CPULM32State), - VMSTATE_UINT32(cc, CPULM32State), - VMSTATE_UINT32(eba, CPULM32State), - VMSTATE_UINT32(dc, CPULM32State), - VMSTATE_UINT32(deba, CPULM32State), - VMSTATE_UINT32_ARRAY(bp, CPULM32State, 4), - VMSTATE_UINT32_ARRAY(wp, CPULM32State, 4), - VMSTATE_END_OF_LIST() - } -}; - -const VMStateDescription vmstate_lm32_cpu = { - .name = "cpu", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(env, LM32CPU, 1, vmstate_env, CPULM32State), - VMSTATE_END_OF_LIST() - } -}; diff --git a/target/lm32/meson.build b/target/lm32/meson.build deleted file mode 100644 index ef0eef07f1..0000000000 --- a/target/lm32/meson.build +++ /dev/null @@ -1,15 +0,0 @@ -lm32_ss = ss.source_set() -lm32_ss.add(files( - 'cpu.c', - 'gdbstub.c', - 'helper.c', - 'lm32-semi.c', - 'op_helper.c', - 'translate.c', -)) - -lm32_softmmu_ss = ss.source_set() -lm32_softmmu_ss.add(files('machine.c')) - -target_arch += {'lm32': lm32_ss} -target_softmmu_arch += {'lm32': lm32_softmmu_ss} diff --git a/target/lm32/op_helper.c b/target/lm32/op_helper.c deleted file mode 100644 index e39fcd5647..0000000000 --- a/target/lm32/op_helper.c +++ /dev/null @@ -1,148 +0,0 @@ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "qemu/host-utils.h" -#include "qemu/main-loop.h" -#include "sysemu/runstate.h" - -#include "hw/lm32/lm32_pic.h" -#include "hw/char/lm32_juart.h" - -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" - -#ifndef CONFIG_USER_ONLY -#endif - -#if !defined(CONFIG_USER_ONLY) -void raise_exception(CPULM32State *env, int index) -{ - CPUState *cs = env_cpu(env); - - cs->exception_index = index; - cpu_loop_exit(cs); -} - -void HELPER(raise_exception)(CPULM32State *env, uint32_t index) -{ - raise_exception(env, index); -} - -void HELPER(hlt)(CPULM32State *env) -{ - CPUState *cs = env_cpu(env); - - cs->halted = 1; - cs->exception_index = EXCP_HLT; - cpu_loop_exit(cs); -} - -void HELPER(ill)(CPULM32State *env) -{ -#ifndef CONFIG_USER_ONLY - CPUState *cs = env_cpu(env); - fprintf(stderr, "VM paused due to illegal instruction. " - "Connect a debugger or switch to the monitor console " - "to find out more.\n"); - vm_stop(RUN_STATE_PAUSED); - cs->halted = 1; - raise_exception(env, EXCP_HALTED); -#endif -} - -void HELPER(wcsr_bp)(CPULM32State *env, uint32_t bp, uint32_t idx) -{ - uint32_t addr = bp & ~1; - - assert(idx < 4); - - env->bp[idx] = bp; - lm32_breakpoint_remove(env, idx); - if (bp & 1) { - lm32_breakpoint_insert(env, idx, addr); - } -} - -void HELPER(wcsr_wp)(CPULM32State *env, uint32_t wp, uint32_t idx) -{ - lm32_wp_t wp_type; - - assert(idx < 4); - - env->wp[idx] = wp; - - wp_type = lm32_wp_type(env->dc, idx); - lm32_watchpoint_remove(env, idx); - if (wp_type != LM32_WP_DISABLED) { - lm32_watchpoint_insert(env, idx, wp, wp_type); - } -} - -void HELPER(wcsr_dc)(CPULM32State *env, uint32_t dc) -{ - uint32_t old_dc; - int i; - lm32_wp_t old_type; - lm32_wp_t new_type; - - old_dc = env->dc; - env->dc = dc; - - for (i = 0; i < 4; i++) { - old_type = lm32_wp_type(old_dc, i); - new_type = lm32_wp_type(dc, i); - - if (old_type != new_type) { - lm32_watchpoint_remove(env, i); - if (new_type != LM32_WP_DISABLED) { - lm32_watchpoint_insert(env, i, env->wp[i], new_type); - } - } - } -} - -void HELPER(wcsr_im)(CPULM32State *env, uint32_t im) -{ - qemu_mutex_lock_iothread(); - lm32_pic_set_im(env->pic_state, im); - qemu_mutex_unlock_iothread(); -} - -void HELPER(wcsr_ip)(CPULM32State *env, uint32_t im) -{ - qemu_mutex_lock_iothread(); - lm32_pic_set_ip(env->pic_state, im); - qemu_mutex_unlock_iothread(); -} - -void HELPER(wcsr_jtx)(CPULM32State *env, uint32_t jtx) -{ - lm32_juart_set_jtx(env->juart_state, jtx); -} - -void HELPER(wcsr_jrx)(CPULM32State *env, uint32_t jrx) -{ - lm32_juart_set_jrx(env->juart_state, jrx); -} - -uint32_t HELPER(rcsr_im)(CPULM32State *env) -{ - return lm32_pic_get_im(env->pic_state); -} - -uint32_t HELPER(rcsr_ip)(CPULM32State *env) -{ - return lm32_pic_get_ip(env->pic_state); -} - -uint32_t HELPER(rcsr_jtx)(CPULM32State *env) -{ - return lm32_juart_get_jtx(env->juart_state); -} - -uint32_t HELPER(rcsr_jrx)(CPULM32State *env) -{ - return lm32_juart_get_jrx(env->juart_state); -} -#endif - diff --git a/target/lm32/translate.c b/target/lm32/translate.c deleted file mode 100644 index 20c70d03f1..0000000000 --- a/target/lm32/translate.c +++ /dev/null @@ -1,1237 +0,0 @@ -/* - * LatticeMico32 main translation routines. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "qemu/osdep.h" -#include "cpu.h" -#include "disas/disas.h" -#include "exec/helper-proto.h" -#include "exec/exec-all.h" -#include "exec/translator.h" -#include "tcg/tcg-op.h" -#include "qemu/qemu-print.h" - -#include "exec/cpu_ldst.h" -#include "hw/lm32/lm32_pic.h" - -#include "exec/helper-gen.h" - -#include "trace-tcg.h" -#include "exec/log.h" - - -#define DISAS_LM32 0 - -#define LOG_DIS(...) \ - do { \ - if (DISAS_LM32) { \ - qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__); \ - } \ - } while (0) - -#define EXTRACT_FIELD(src, start, end) \ - (((src) >> start) & ((1 << (end - start + 1)) - 1)) - -#define MEM_INDEX 0 - -/* is_jmp field values */ -#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ -#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ -#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */ - -static TCGv cpu_R[32]; -static TCGv cpu_pc; -static TCGv cpu_ie; -static TCGv cpu_icc; -static TCGv cpu_dcc; -static TCGv cpu_cc; -static TCGv cpu_cfg; -static TCGv cpu_eba; -static TCGv cpu_dc; -static TCGv cpu_deba; -static TCGv cpu_bp[4]; -static TCGv cpu_wp[4]; - -#include "exec/gen-icount.h" - -enum { - OP_FMT_RI, - OP_FMT_RR, - OP_FMT_CR, - OP_FMT_I -}; - -/* This is the state at translation time. */ -typedef struct DisasContext { - target_ulong pc; - - /* Decoder. */ - int format; - uint32_t ir; - uint8_t opcode; - uint8_t r0, r1, r2, csr; - uint16_t imm5; - uint16_t imm16; - uint32_t imm26; - - unsigned int delayed_branch; - unsigned int tb_flags, synced_flags; /* tb dependent flags. */ - int is_jmp; - - TranslationBlock *tb; - int singlestep_enabled; - - uint32_t features; - uint8_t num_breakpoints; - uint8_t num_watchpoints; -} DisasContext; - -static const char *regnames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26/gp", "r27/fp", "r28/sp", "r29/ra", - "r30/ea", "r31/ba", "bp0", "bp1", "bp2", "bp3", "wp0", - "wp1", "wp2", "wp3" -}; - -static inline int zero_extend(unsigned int val, int width) -{ - return val & ((1 << width) - 1); -} - -static inline int sign_extend(unsigned int val, int width) -{ - int sval; - - /* LSL. */ - val <<= 32 - width; - sval = val; - /* ASR. */ - sval >>= 32 - width; - - return sval; -} - -static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index) -{ - TCGv_i32 tmp = tcg_const_i32(index); - - gen_helper_raise_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); -} - -static inline void t_gen_illegal_insn(DisasContext *dc) -{ - tcg_gen_movi_tl(cpu_pc, dc->pc); - gen_helper_ill(cpu_env); -} - -static inline bool use_goto_tb(DisasContext *dc, target_ulong dest) -{ - if (unlikely(dc->singlestep_enabled)) { - return false; - } - -#ifndef CONFIG_USER_ONLY - return (dc->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); -#else - return true; -#endif -} - -static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) -{ - if (use_goto_tb(dc, dest)) { - tcg_gen_goto_tb(n); - tcg_gen_movi_tl(cpu_pc, dest); - tcg_gen_exit_tb(dc->tb, n); - } else { - tcg_gen_movi_tl(cpu_pc, dest); - if (dc->singlestep_enabled) { - t_gen_raise_exception(dc, EXCP_DEBUG); - } - tcg_gen_exit_tb(NULL, 0); - } -} - -static void dec_add(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - if (dc->r0 == R_R0) { - if (dc->r1 == R_R0 && dc->imm16 == 0) { - LOG_DIS("nop\n"); - } else { - LOG_DIS("mvi r%d, %d\n", dc->r1, sign_extend(dc->imm16, 16)); - } - } else { - LOG_DIS("addi r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } - } else { - LOG_DIS("add r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_addi_tl(cpu_R[dc->r1], cpu_R[dc->r0], - sign_extend(dc->imm16, 16)); - } else { - tcg_gen_add_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_and(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("andi r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - LOG_DIS("and r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0], - zero_extend(dc->imm16, 16)); - } else { - if (dc->r0 == 0 && dc->r1 == 0 && dc->r2 == 0) { - tcg_gen_movi_tl(cpu_pc, dc->pc + 4); - gen_helper_hlt(cpu_env); - } else { - tcg_gen_and_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } - } -} - -static void dec_andhi(DisasContext *dc) -{ - LOG_DIS("andhi r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm16); - - tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16)); -} - -static void dec_b(DisasContext *dc) -{ - if (dc->r0 == R_RA) { - LOG_DIS("ret\n"); - } else if (dc->r0 == R_EA) { - LOG_DIS("eret\n"); - } else if (dc->r0 == R_BA) { - LOG_DIS("bret\n"); - } else { - LOG_DIS("b r%d\n", dc->r0); - } - - /* restore IE.IE in case of an eret */ - if (dc->r0 == R_EA) { - TCGv t0 = tcg_temp_new(); - TCGLabel *l1 = gen_new_label(); - tcg_gen_andi_tl(t0, cpu_ie, IE_EIE); - tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_EIE, l1); - tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE); - gen_set_label(l1); - tcg_temp_free(t0); - } else if (dc->r0 == R_BA) { - TCGv t0 = tcg_temp_new(); - TCGLabel *l1 = gen_new_label(); - tcg_gen_andi_tl(t0, cpu_ie, IE_BIE); - tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE); - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_BIE, l1); - tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE); - gen_set_label(l1); - tcg_temp_free(t0); - } - tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]); - - dc->is_jmp = DISAS_JUMP; -} - -static void dec_bi(DisasContext *dc) -{ - LOG_DIS("bi %d\n", sign_extend(dc->imm26 << 2, 26)); - - gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26))); - - dc->is_jmp = DISAS_TB_JUMP; -} - -static inline void gen_cond_branch(DisasContext *dc, int cond) -{ - TCGLabel *l1 = gen_new_label(); - tcg_gen_brcond_tl(cond, cpu_R[dc->r0], cpu_R[dc->r1], l1); - gen_goto_tb(dc, 0, dc->pc + 4); - gen_set_label(l1); - gen_goto_tb(dc, 1, dc->pc + (sign_extend(dc->imm16 << 2, 16))); - dc->is_jmp = DISAS_TB_JUMP; -} - -static void dec_be(DisasContext *dc) -{ - LOG_DIS("be r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16) * 4); - - gen_cond_branch(dc, TCG_COND_EQ); -} - -static void dec_bg(DisasContext *dc) -{ - LOG_DIS("bg r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16 * 4)); - - gen_cond_branch(dc, TCG_COND_GT); -} - -static void dec_bge(DisasContext *dc) -{ - LOG_DIS("bge r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16) * 4); - - gen_cond_branch(dc, TCG_COND_GE); -} - -static void dec_bgeu(DisasContext *dc) -{ - LOG_DIS("bgeu r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16) * 4); - - gen_cond_branch(dc, TCG_COND_GEU); -} - -static void dec_bgu(DisasContext *dc) -{ - LOG_DIS("bgu r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16) * 4); - - gen_cond_branch(dc, TCG_COND_GTU); -} - -static void dec_bne(DisasContext *dc) -{ - LOG_DIS("bne r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16) * 4); - - gen_cond_branch(dc, TCG_COND_NE); -} - -static void dec_call(DisasContext *dc) -{ - LOG_DIS("call r%d\n", dc->r0); - - tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4); - tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]); - - dc->is_jmp = DISAS_JUMP; -} - -static void dec_calli(DisasContext *dc) -{ - LOG_DIS("calli %d\n", sign_extend(dc->imm26, 26) * 4); - - tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4); - gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26))); - - dc->is_jmp = DISAS_TB_JUMP; -} - -static inline void gen_compare(DisasContext *dc, int cond) -{ - int i; - - if (dc->format == OP_FMT_RI) { - switch (cond) { - case TCG_COND_GEU: - case TCG_COND_GTU: - i = zero_extend(dc->imm16, 16); - break; - default: - i = sign_extend(dc->imm16, 16); - break; - } - - tcg_gen_setcondi_tl(cond, cpu_R[dc->r1], cpu_R[dc->r0], i); - } else { - tcg_gen_setcond_tl(cond, cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_cmpe(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpei r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpe r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_EQ); -} - -static void dec_cmpg(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpgi r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpg r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_GT); -} - -static void dec_cmpge(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpgei r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpge r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_GE); -} - -static void dec_cmpgeu(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpgeui r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpgeu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_GEU); -} - -static void dec_cmpgu(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpgui r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpgu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_GTU); -} - -static void dec_cmpne(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("cmpnei r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } else { - LOG_DIS("cmpne r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - gen_compare(dc, TCG_COND_NE); -} - -static void dec_divu(DisasContext *dc) -{ - TCGLabel *l1; - - LOG_DIS("divu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - - if (!(dc->features & LM32_FEATURE_DIVIDE)) { - qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1); - tcg_gen_movi_tl(cpu_pc, dc->pc); - t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO); - gen_set_label(l1); - tcg_gen_divu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); -} - -static void dec_lb(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("lb r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_ld8s(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_lbu(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("lbu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_ld8u(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_lh(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("lh r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_ld16s(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_lhu(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("lhu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_ld16u(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_lw(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("lw r%d, (r%d+%d)\n", dc->r1, dc->r0, sign_extend(dc->imm16, 16)); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_ld32s(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_modu(DisasContext *dc) -{ - TCGLabel *l1; - - LOG_DIS("modu r%d, r%d, %d\n", dc->r2, dc->r0, dc->r1); - - if (!(dc->features & LM32_FEATURE_DIVIDE)) { - qemu_log_mask(LOG_GUEST_ERROR, "hardware divider is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - l1 = gen_new_label(); - tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1); - tcg_gen_movi_tl(cpu_pc, dc->pc); - t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO); - gen_set_label(l1); - tcg_gen_remu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); -} - -static void dec_mul(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("muli r%d, r%d, %d\n", dc->r1, dc->r0, - sign_extend(dc->imm16, 16)); - } else { - LOG_DIS("mul r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (!(dc->features & LM32_FEATURE_MULTIPLY)) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware multiplier is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_muli_tl(cpu_R[dc->r1], cpu_R[dc->r0], - sign_extend(dc->imm16, 16)); - } else { - tcg_gen_mul_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_nor(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("nori r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - LOG_DIS("nor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (dc->format == OP_FMT_RI) { - TCGv t0 = tcg_temp_new(); - tcg_gen_movi_tl(t0, zero_extend(dc->imm16, 16)); - tcg_gen_nor_tl(cpu_R[dc->r1], cpu_R[dc->r0], t0); - tcg_temp_free(t0); - } else { - tcg_gen_nor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_or(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("ori r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - if (dc->r1 == R_R0) { - LOG_DIS("mv r%d, r%d\n", dc->r2, dc->r0); - } else { - LOG_DIS("or r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], - zero_extend(dc->imm16, 16)); - } else { - tcg_gen_or_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_orhi(DisasContext *dc) -{ - if (dc->r0 == R_R0) { - LOG_DIS("mvhi r%d, %d\n", dc->r1, dc->imm16); - } else { - LOG_DIS("orhi r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm16); - } - - tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16)); -} - -static void dec_scall(DisasContext *dc) -{ - switch (dc->imm5) { - case 2: - LOG_DIS("break\n"); - tcg_gen_movi_tl(cpu_pc, dc->pc); - t_gen_raise_exception(dc, EXCP_BREAKPOINT); - break; - case 7: - LOG_DIS("scall\n"); - tcg_gen_movi_tl(cpu_pc, dc->pc); - t_gen_raise_exception(dc, EXCP_SYSTEMCALL); - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode @0x%x", dc->pc); - t_gen_illegal_insn(dc); - break; - } -} - -static void dec_rcsr(DisasContext *dc) -{ - LOG_DIS("rcsr r%d, %d\n", dc->r2, dc->csr); - - switch (dc->csr) { - case CSR_IE: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_ie); - break; - case CSR_IM: - gen_helper_rcsr_im(cpu_R[dc->r2], cpu_env); - break; - case CSR_IP: - gen_helper_rcsr_ip(cpu_R[dc->r2], cpu_env); - break; - case CSR_CC: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cc); - break; - case CSR_CFG: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cfg); - break; - case CSR_EBA: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_eba); - break; - case CSR_DC: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_dc); - break; - case CSR_DEBA: - tcg_gen_mov_tl(cpu_R[dc->r2], cpu_deba); - break; - case CSR_JTX: - gen_helper_rcsr_jtx(cpu_R[dc->r2], cpu_env); - break; - case CSR_JRX: - gen_helper_rcsr_jrx(cpu_R[dc->r2], cpu_env); - break; - case CSR_ICC: - case CSR_DCC: - case CSR_BP0: - case CSR_BP1: - case CSR_BP2: - case CSR_BP3: - case CSR_WP0: - case CSR_WP1: - case CSR_WP2: - case CSR_WP3: - qemu_log_mask(LOG_GUEST_ERROR, "invalid read access csr=%x\n", dc->csr); - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "read_csr: unknown csr=%x\n", dc->csr); - break; - } -} - -static void dec_sb(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("sb (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_st8(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_sextb(DisasContext *dc) -{ - LOG_DIS("sextb r%d, r%d\n", dc->r2, dc->r0); - - if (!(dc->features & LM32_FEATURE_SIGN_EXTEND)) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware sign extender is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - tcg_gen_ext8s_tl(cpu_R[dc->r2], cpu_R[dc->r0]); -} - -static void dec_sexth(DisasContext *dc) -{ - LOG_DIS("sexth r%d, r%d\n", dc->r2, dc->r0); - - if (!(dc->features & LM32_FEATURE_SIGN_EXTEND)) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware sign extender is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - tcg_gen_ext16s_tl(cpu_R[dc->r2], cpu_R[dc->r0]); -} - -static void dec_sh(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("sh (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_st16(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_sl(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("sli r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5); - } else { - LOG_DIS("sl r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (!(dc->features & LM32_FEATURE_SHIFT)) { - qemu_log_mask(LOG_GUEST_ERROR, "hardware shifter is not available\n"); - t_gen_illegal_insn(dc); - return; - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_shli_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5); - } else { - TCGv t0 = tcg_temp_new(); - tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f); - tcg_gen_shl_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0); - tcg_temp_free(t0); - } -} - -static void dec_sr(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("sri r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5); - } else { - LOG_DIS("sr r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - /* The real CPU (w/o hardware shifter) only supports right shift by exactly - * one bit */ - if (dc->format == OP_FMT_RI) { - if (!(dc->features & LM32_FEATURE_SHIFT) && (dc->imm5 != 1)) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware shifter is not available\n"); - t_gen_illegal_insn(dc); - return; - } - tcg_gen_sari_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5); - } else { - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); - TCGv t0 = tcg_temp_local_new(); - tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f); - - if (!(dc->features & LM32_FEATURE_SHIFT)) { - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 1, l1); - t_gen_illegal_insn(dc); - tcg_gen_br(l2); - } - - gen_set_label(l1); - tcg_gen_sar_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0); - gen_set_label(l2); - - tcg_temp_free(t0); - } -} - -static void dec_sru(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("srui r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5); - } else { - LOG_DIS("sru r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (dc->format == OP_FMT_RI) { - if (!(dc->features & LM32_FEATURE_SHIFT) && (dc->imm5 != 1)) { - qemu_log_mask(LOG_GUEST_ERROR, - "hardware shifter is not available\n"); - t_gen_illegal_insn(dc); - return; - } - tcg_gen_shri_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5); - } else { - TCGLabel *l1 = gen_new_label(); - TCGLabel *l2 = gen_new_label(); - TCGv t0 = tcg_temp_local_new(); - tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f); - - if (!(dc->features & LM32_FEATURE_SHIFT)) { - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 1, l1); - t_gen_illegal_insn(dc); - tcg_gen_br(l2); - } - - gen_set_label(l1); - tcg_gen_shr_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0); - gen_set_label(l2); - - tcg_temp_free(t0); - } -} - -static void dec_sub(DisasContext *dc) -{ - LOG_DIS("sub r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - - tcg_gen_sub_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); -} - -static void dec_sw(DisasContext *dc) -{ - TCGv t0; - - LOG_DIS("sw (r%d+%d), r%d\n", dc->r0, sign_extend(dc->imm16, 16), dc->r1); - - t0 = tcg_temp_new(); - tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16)); - tcg_gen_qemu_st32(cpu_R[dc->r1], t0, MEM_INDEX); - tcg_temp_free(t0); -} - -static void dec_user(DisasContext *dc) -{ - LOG_DIS("user"); - - qemu_log_mask(LOG_GUEST_ERROR, "user instruction undefined\n"); - t_gen_illegal_insn(dc); -} - -static void dec_wcsr(DisasContext *dc) -{ - int no; - - LOG_DIS("wcsr %d, r%d\n", dc->csr, dc->r1); - - switch (dc->csr) { - case CSR_IE: - tcg_gen_mov_tl(cpu_ie, cpu_R[dc->r1]); - tcg_gen_movi_tl(cpu_pc, dc->pc + 4); - dc->is_jmp = DISAS_UPDATE; - break; - case CSR_IM: - /* mark as an io operation because it could cause an interrupt */ - if (tb_cflags(dc->tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_wcsr_im(cpu_env, cpu_R[dc->r1]); - tcg_gen_movi_tl(cpu_pc, dc->pc + 4); - dc->is_jmp = DISAS_UPDATE; - break; - case CSR_IP: - /* mark as an io operation because it could cause an interrupt */ - if (tb_cflags(dc->tb) & CF_USE_ICOUNT) { - gen_io_start(); - } - gen_helper_wcsr_ip(cpu_env, cpu_R[dc->r1]); - tcg_gen_movi_tl(cpu_pc, dc->pc + 4); - dc->is_jmp = DISAS_UPDATE; - break; - case CSR_ICC: - /* TODO */ - break; - case CSR_DCC: - /* TODO */ - break; - case CSR_EBA: - tcg_gen_mov_tl(cpu_eba, cpu_R[dc->r1]); - break; - case CSR_DEBA: - tcg_gen_mov_tl(cpu_deba, cpu_R[dc->r1]); - break; - case CSR_JTX: - gen_helper_wcsr_jtx(cpu_env, cpu_R[dc->r1]); - break; - case CSR_JRX: - gen_helper_wcsr_jrx(cpu_env, cpu_R[dc->r1]); - break; - case CSR_DC: - gen_helper_wcsr_dc(cpu_env, cpu_R[dc->r1]); - break; - case CSR_BP0: - case CSR_BP1: - case CSR_BP2: - case CSR_BP3: - no = dc->csr - CSR_BP0; - if (dc->num_breakpoints <= no) { - qemu_log_mask(LOG_GUEST_ERROR, - "breakpoint #%i is not available\n", no); - t_gen_illegal_insn(dc); - break; - } - gen_helper_wcsr_bp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no)); - break; - case CSR_WP0: - case CSR_WP1: - case CSR_WP2: - case CSR_WP3: - no = dc->csr - CSR_WP0; - if (dc->num_watchpoints <= no) { - qemu_log_mask(LOG_GUEST_ERROR, - "watchpoint #%i is not available\n", no); - t_gen_illegal_insn(dc); - break; - } - gen_helper_wcsr_wp(cpu_env, cpu_R[dc->r1], tcg_const_i32(no)); - break; - case CSR_CC: - case CSR_CFG: - qemu_log_mask(LOG_GUEST_ERROR, "invalid write access csr=%x\n", - dc->csr); - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "write_csr: unknown csr=%x\n", - dc->csr); - break; - } -} - -static void dec_xnor(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("xnori r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - if (dc->r1 == R_R0) { - LOG_DIS("not r%d, r%d\n", dc->r2, dc->r0); - } else { - LOG_DIS("xnor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0], - zero_extend(dc->imm16, 16)); - tcg_gen_not_tl(cpu_R[dc->r1], cpu_R[dc->r1]); - } else { - tcg_gen_eqv_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_xor(DisasContext *dc) -{ - if (dc->format == OP_FMT_RI) { - LOG_DIS("xori r%d, r%d, %d\n", dc->r1, dc->r0, - zero_extend(dc->imm16, 16)); - } else { - LOG_DIS("xor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1); - } - - if (dc->format == OP_FMT_RI) { - tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0], - zero_extend(dc->imm16, 16)); - } else { - tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); - } -} - -static void dec_ill(DisasContext *dc) -{ - qemu_log_mask(LOG_GUEST_ERROR, "invalid opcode 0x%02x\n", dc->opcode); - t_gen_illegal_insn(dc); -} - -typedef void (*DecoderInfo)(DisasContext *dc); -static const DecoderInfo decinfo[] = { - dec_sru, dec_nor, dec_mul, dec_sh, dec_lb, dec_sr, dec_xor, dec_lh, - dec_and, dec_xnor, dec_lw, dec_lhu, dec_sb, dec_add, dec_or, dec_sl, - dec_lbu, dec_be, dec_bg, dec_bge, dec_bgeu, dec_bgu, dec_sw, dec_bne, - dec_andhi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_orhi, - dec_cmpne, - dec_sru, dec_nor, dec_mul, dec_divu, dec_rcsr, dec_sr, dec_xor, dec_ill, - dec_and, dec_xnor, dec_ill, dec_scall, dec_sextb, dec_add, dec_or, dec_sl, - dec_b, dec_modu, dec_sub, dec_user, dec_wcsr, dec_ill, dec_call, dec_sexth, - dec_bi, dec_cmpe, dec_cmpg, dec_cmpge, dec_cmpgeu, dec_cmpgu, dec_calli, - dec_cmpne -}; - -static inline void decode(DisasContext *dc, uint32_t ir) -{ - dc->ir = ir; - LOG_DIS("%8.8x\t", dc->ir); - - dc->opcode = EXTRACT_FIELD(ir, 26, 31); - - dc->imm5 = EXTRACT_FIELD(ir, 0, 4); - dc->imm16 = EXTRACT_FIELD(ir, 0, 15); - dc->imm26 = EXTRACT_FIELD(ir, 0, 25); - - dc->csr = EXTRACT_FIELD(ir, 21, 25); - dc->r0 = EXTRACT_FIELD(ir, 21, 25); - dc->r1 = EXTRACT_FIELD(ir, 16, 20); - dc->r2 = EXTRACT_FIELD(ir, 11, 15); - - /* bit 31 seems to indicate insn type. */ - if (ir & (1 << 31)) { - dc->format = OP_FMT_RR; - } else { - dc->format = OP_FMT_RI; - } - - assert(ARRAY_SIZE(decinfo) == 64); - assert(dc->opcode < 64); - - decinfo[dc->opcode](dc); -} - -/* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) -{ - CPULM32State *env = cs->env_ptr; - LM32CPU *cpu = env_archcpu(env); - struct DisasContext ctx, *dc = &ctx; - uint32_t pc_start; - uint32_t page_start; - int num_insns; - - pc_start = tb->pc; - dc->features = cpu->features; - dc->num_breakpoints = cpu->num_breakpoints; - dc->num_watchpoints = cpu->num_watchpoints; - dc->tb = tb; - - dc->is_jmp = DISAS_NEXT; - dc->pc = pc_start; - dc->singlestep_enabled = cs->singlestep_enabled; - - if (pc_start & 3) { - qemu_log_mask(LOG_GUEST_ERROR, - "unaligned PC=%x. Ignoring lowest bits.\n", pc_start); - pc_start &= ~3; - } - - page_start = pc_start & TARGET_PAGE_MASK; - num_insns = 0; - - gen_tb_start(tb); - do { - tcg_gen_insn_start(dc->pc); - num_insns++; - - if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { - tcg_gen_movi_tl(cpu_pc, dc->pc); - t_gen_raise_exception(dc, EXCP_DEBUG); - dc->is_jmp = DISAS_UPDATE; - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - dc->pc += 4; - break; - } - - /* Pretty disas. */ - LOG_DIS("%8.8x:\t", dc->pc); - - if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) { - gen_io_start(); - } - - decode(dc, cpu_ldl_code(env, dc->pc)); - dc->pc += 4; - } while (!dc->is_jmp - && !tcg_op_buf_full() - && !cs->singlestep_enabled - && !singlestep - && (dc->pc - page_start < TARGET_PAGE_SIZE) - && num_insns < max_insns); - - - if (unlikely(cs->singlestep_enabled)) { - if (dc->is_jmp == DISAS_NEXT) { - tcg_gen_movi_tl(cpu_pc, dc->pc); - } - t_gen_raise_exception(dc, EXCP_DEBUG); - } else { - switch (dc->is_jmp) { - case DISAS_NEXT: - gen_goto_tb(dc, 1, dc->pc); - break; - default: - case DISAS_JUMP: - case DISAS_UPDATE: - /* indicate that the hash table must be used - to find the next TB */ - tcg_gen_exit_tb(NULL, 0); - break; - case DISAS_TB_JUMP: - /* nothing more to generate */ - break; - } - } - - gen_tb_end(tb, num_insns); - - tb->size = dc->pc - pc_start; - tb->icount = num_insns; - -#ifdef DEBUG_DISAS - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) - && qemu_log_in_addr_range(pc_start)) { - FILE *logfile = qemu_log_lock(); - qemu_log("\n"); - log_target_disas(cs, pc_start, dc->pc - pc_start); - qemu_log_unlock(logfile); - } -#endif -} - -void lm32_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - LM32CPU *cpu = LM32_CPU(cs); - CPULM32State *env = &cpu->env; - int i; - - if (!env) { - return; - } - - qemu_fprintf(f, "IN: PC=%x %s\n", - env->pc, lookup_symbol(env->pc)); - - qemu_fprintf(f, "ie=%8.8x (IE=%x EIE=%x BIE=%x) im=%8.8x ip=%8.8x\n", - env->ie, - (env->ie & IE_IE) ? 1 : 0, - (env->ie & IE_EIE) ? 1 : 0, - (env->ie & IE_BIE) ? 1 : 0, - lm32_pic_get_im(env->pic_state), - lm32_pic_get_ip(env->pic_state)); - qemu_fprintf(f, "eba=%8.8x deba=%8.8x\n", - env->eba, - env->deba); - - for (i = 0; i < 32; i++) { - qemu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); - if ((i + 1) % 4 == 0) { - qemu_fprintf(f, "\n"); - } - } - qemu_fprintf(f, "\n\n"); -} - -void restore_state_to_opc(CPULM32State *env, TranslationBlock *tb, - target_ulong *data) -{ - env->pc = data[0]; -} - -void lm32_translate_init(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cpu_R); i++) { - cpu_R[i] = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, regs[i]), - regnames[i]); - } - - for (i = 0; i < ARRAY_SIZE(cpu_bp); i++) { - cpu_bp[i] = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, bp[i]), - regnames[32+i]); - } - - for (i = 0; i < ARRAY_SIZE(cpu_wp); i++) { - cpu_wp[i] = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, wp[i]), - regnames[36+i]); - } - - cpu_pc = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, pc), - "pc"); - cpu_ie = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, ie), - "ie"); - cpu_icc = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, icc), - "icc"); - cpu_dcc = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, dcc), - "dcc"); - cpu_cc = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, cc), - "cc"); - cpu_cfg = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, cfg), - "cfg"); - cpu_eba = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, eba), - "eba"); - cpu_dc = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, dc), - "dc"); - cpu_deba = tcg_global_mem_new(cpu_env, - offsetof(CPULM32State, deba), - "deba"); -} - diff --git a/target/meson.build b/target/meson.build index 289a654caf..ccc87f30f3 100644 --- a/target/meson.build +++ b/target/meson.build @@ -5,7 +5,6 @@ subdir('cris') subdir('hexagon') subdir('hppa') subdir('i386') -subdir('lm32') subdir('m68k') subdir('microblaze') subdir('mips') diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c index 5feada15dc..0ec1549648 100644 --- a/tests/qtest/machine-none-test.c +++ b/tests/qtest/machine-none-test.c @@ -32,7 +32,6 @@ static struct arch2cpu cpus_map[] = { { "i386", "qemu32,apic-id=0" }, { "alpha", "ev67" }, { "cris", "crisv32" }, - { "lm32", "lm32-full" }, { "m68k", "m5206" }, { "microblaze", "any" }, { "microblazeel", "any" }, diff --git a/tests/tcg/README b/tests/tcg/README index 2a58f9a058..706bb185b4 100644 --- a/tests/tcg/README +++ b/tests/tcg/README @@ -7,9 +7,3 @@ CRIS ==== The testsuite for CRIS is in tests/tcg/cris. You can run it with "make test-cris". - -LM32 -==== -The testsuite for LM32 is in tests/tcg/lm32. You can run it -with "make test-lm32". - diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh index fa1a4261a4..8f20ce065d 100755 --- a/tests/tcg/configure.sh +++ b/tests/tcg/configure.sh @@ -96,7 +96,7 @@ for target in $target_list; do xtensa|xtensaeb) arches=xtensa ;; - alpha|cris|hexagon|hppa|i386|lm32|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64) + alpha|cris|hexagon|hppa|i386|microblaze|microblazeel|m68k|openrisc|riscv64|s390x|sh4|sparc64) arches=$target ;; *) diff --git a/tests/tcg/lm32/Makefile b/tests/tcg/lm32/Makefile deleted file mode 100644 index 57e7363b2c..0000000000 --- a/tests/tcg/lm32/Makefile +++ /dev/null @@ -1,106 +0,0 @@ --include ../../../config-host.mak - -CROSS=lm32-elf- - -SIM = qemu-system-lm32 -SIMFLAGS = -M lm32-evr -nographic -semihosting -net none -kernel - -CC = $(CROSS)gcc -AS = $(CROSS)as -AS = $(CC) -x assembler -SIZE = $(CROSS)size -LD = $(CC) -OBJCOPY = $(CROSS)objcopy - -TSRC_PATH = $(SRC_PATH)/tests/tcg/lm32 - -LDFLAGS = -T$(TSRC_PATH)/linker.ld -ASFLAGS += -Wa,-I,$(TSRC_PATH)/ - -CRT = crt.o -HELPER = helper.o -TESTCASES += test_add.tst -TESTCASES += test_addi.tst -TESTCASES += test_and.tst -TESTCASES += test_andhi.tst -TESTCASES += test_andi.tst -TESTCASES += test_b.tst -TESTCASES += test_be.tst -TESTCASES += test_bg.tst -TESTCASES += test_bge.tst -TESTCASES += test_bgeu.tst -TESTCASES += test_bgu.tst -TESTCASES += test_bi.tst -TESTCASES += test_bne.tst -TESTCASES += test_break.tst -TESTCASES += test_bret.tst -TESTCASES += test_call.tst -TESTCASES += test_calli.tst -TESTCASES += test_cmpe.tst -TESTCASES += test_cmpei.tst -TESTCASES += test_cmpg.tst -TESTCASES += test_cmpgi.tst -TESTCASES += test_cmpge.tst -TESTCASES += test_cmpgei.tst -TESTCASES += test_cmpgeu.tst -TESTCASES += test_cmpgeui.tst -TESTCASES += test_cmpgu.tst -TESTCASES += test_cmpgui.tst -TESTCASES += test_cmpne.tst -TESTCASES += test_cmpnei.tst -TESTCASES += test_divu.tst -TESTCASES += test_eret.tst -TESTCASES += test_lb.tst -TESTCASES += test_lbu.tst -TESTCASES += test_lh.tst -TESTCASES += test_lhu.tst -TESTCASES += test_lw.tst -TESTCASES += test_modu.tst -TESTCASES += test_mul.tst -TESTCASES += test_muli.tst -TESTCASES += test_nor.tst -TESTCASES += test_nori.tst -TESTCASES += test_or.tst -TESTCASES += test_ori.tst -TESTCASES += test_orhi.tst -#TESTCASES += test_rcsr.tst -TESTCASES += test_ret.tst -TESTCASES += test_sb.tst -TESTCASES += test_scall.tst -TESTCASES += test_sextb.tst -TESTCASES += test_sexth.tst -TESTCASES += test_sh.tst -TESTCASES += test_sl.tst -TESTCASES += test_sli.tst -TESTCASES += test_sr.tst -TESTCASES += test_sri.tst -TESTCASES += test_sru.tst -TESTCASES += test_srui.tst -TESTCASES += test_sub.tst -TESTCASES += test_sw.tst -#TESTCASES += test_wcsr.tst -TESTCASES += test_xnor.tst -TESTCASES += test_xnori.tst -TESTCASES += test_xor.tst -TESTCASES += test_xori.tst - -all: build - -%.o: $(TSRC_PATH)/%.c - $(CC) $(CFLAGS) -c $< -o $@ - -%.o: $(TSRC_PATH)/%.S - $(AS) $(ASFLAGS) -c $< -o $@ - -%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT) $(HELPER) - $(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $(HELPER) $< -o $@ - -build: $(TESTCASES) - -check: $(TESTCASES:test_%.tst=check_%) - -check_%: test_%.tst - @$(SIM) $(SIMFLAGS) $< - -clean: - $(RM) -fr $(TESTCASES) $(CRT) $(HELPER) diff --git a/tests/tcg/lm32/crt.S b/tests/tcg/lm32/crt.S deleted file mode 100644 index fc437a3de1..0000000000 --- a/tests/tcg/lm32/crt.S +++ /dev/null @@ -1,84 +0,0 @@ -.text -.global _start - -_start: -_reset_handler: - xor r0, r0, r0 - mvhi r1, hi(_start) - ori r1, r1, lo(_start) - wcsr eba, r1 - wcsr deba, r1 - mvhi sp, hi(_fstack) - ori sp, sp, lo(_fstack) - bi _main - -_breakpoint_handler: - ori r25, r25, 1 - addi ra, ba, 4 - ret - nop - nop - nop - nop - nop - -_instruction_bus_error_handler: - ori r25, r25, 2 - addi ra, ea, 4 - ret - nop - nop - nop - nop - nop - -_watchpoint_handler: - ori r25, r25, 4 - addi ra, ba, 4 - ret - nop - nop - nop - nop - nop - -_data_bus_error_handler: - ori r25, r25, 8 - addi ra, ea, 4 - ret - nop - nop - nop - nop - nop - -_divide_by_zero_handler: - ori r25, r25, 16 - addi ra, ea, 4 - ret - nop - nop - nop - nop - nop - -_interrupt_handler: - ori r25, r25, 32 - addi ra, ea, 4 - ret - nop - nop - nop - nop - nop - -_system_call_handler: - ori r25, r25, 64 - addi ra, ea, 4 - ret - nop - nop - nop - nop - nop - diff --git a/tests/tcg/lm32/helper.S b/tests/tcg/lm32/helper.S deleted file mode 100644 index 3351d41e84..0000000000 --- a/tests/tcg/lm32/helper.S +++ /dev/null @@ -1,65 +0,0 @@ -.text -.global _start, _write, _exit -.global _tc_fail, _tc_pass - -_write: - addi sp, sp, -4 - sw (sp+4), r8 - mvi r8, 5 - scall - lw r8, (sp+4) - addi sp, sp, 4 - ret - -_exit: - mvi r8, 1 - scall -1: - bi 1b - -_tc_pass: -.data -1: - .ascii "OK\n" -2: -.text - addi sp, sp, -16 - sw (sp+4), ra - sw (sp+8), r1 - sw (sp+12), r2 - sw (sp+16), r3 - mvi r1, 1 - mvhi r2, hi(1b) - ori r2, r2, lo(1b) - mvi r3, (2b - 1b) - calli _write - lw r3, (sp+16) - lw r2, (sp+12) - lw r1, (sp+8) - lw ra, (sp+4) - addi sp, sp, 16 - ret - -_tc_fail: -.data -1: - .ascii "FAILED\n" -2: -.text - addi sp, sp, -16 - sw (sp+4), ra - sw (sp+8), r1 - sw (sp+12), r2 - sw (sp+16), r3 - sw (sp+4), ra - mvi r1, 1 - mvhi r2, hi(1b) - ori r2, r2, lo(1b) - mvi r3, (2b - 1b) - calli _write - lw r3, (sp+16) - lw r2, (sp+12) - lw r1, (sp+8) - lw ra, (sp+4) - addi sp, sp, 16 - ret diff --git a/tests/tcg/lm32/linker.ld b/tests/tcg/lm32/linker.ld deleted file mode 100644 index 52d43a4c74..0000000000 --- a/tests/tcg/lm32/linker.ld +++ /dev/null @@ -1,55 +0,0 @@ -OUTPUT_FORMAT("elf32-lm32") -ENTRY(_start) - -__DYNAMIC = 0; - -MEMORY { - ram : ORIGIN = 0x08000000, LENGTH = 0x04000000 /* 64M */ -} - -SECTIONS -{ - .text : - { - _ftext = .; - *(.text .stub .text.* .gnu.linkonce.t.*) - _etext = .; - } > ram - - .rodata : - { - . = ALIGN(4); - _frodata = .; - *(.rodata .rodata.* .gnu.linkonce.r.*) - *(.rodata1) - _erodata = .; - } > ram - - .data : - { - . = ALIGN(4); - _fdata = .; - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - _gp = ALIGN(16); - *(.sdata .sdata.* .gnu.linkonce.s.*) - _edata = .; - } > ram - - .bss : - { - . = ALIGN(4); - _fbss = .; - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - _ebss = .; - _end = .; - } > ram -} - -PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4); - diff --git a/tests/tcg/lm32/macros.inc b/tests/tcg/lm32/macros.inc deleted file mode 100644 index 360ad53c9f..0000000000 --- a/tests/tcg/lm32/macros.inc +++ /dev/null @@ -1,90 +0,0 @@ - -.equ MAX_TESTNAME_LEN, 32 -.macro test_name name - .data -tn_\name: - .ascii "\name" - .space MAX_TESTNAME_LEN - (. - tn_\name), ' ' - .text - .global \name -\name: - addi sp, sp, -12 - sw (sp+4), r1 - sw (sp+8), r2 - sw (sp+12), r3 - mvi r1, 1 - mvhi r2, hi(tn_\name) - ori r2, r2, lo(tn_\name) - mvi r3, MAX_TESTNAME_LEN - calli _write - lw r3, (sp+12) - lw r2, (sp+8) - lw r1, (sp+4) - addi sp, sp, 12 -.endm - -.macro load reg val - mvhi \reg, hi(\val) - ori \reg, \reg, lo(\val) -.endm - -.macro tc_pass - calli _tc_pass -.endm - -.macro tc_fail - addi r12, r12, 1 - calli _tc_fail -.endm - -.macro check_r3 val - mvhi r13, hi(\val) - ori r13, r13, lo(\val) - be r3, r13, 1f - tc_fail - bi 2f -1: - tc_pass -2: -.endm - -.macro check_mem adr val - mvhi r13, hi(\adr) - ori r13, r13, lo(\adr) - mvhi r14, hi(\val) - ori r14, r14, lo(\val) - lw r13, (r13+0) - be r13, r14, 1f - tc_fail - bi 2f -1: - tc_pass -2: -.endm - -.macro check_excp excp - andi r13, r25, \excp - bne r13, r0, 1f - tc_fail - bi 2f -1: - tc_pass -2: -.endm - -.macro start - .global _main - .text -_main: - mvi r12, 0 -.endm - -.macro end - mv r1, r12 - calli _exit -.endm - -# base + -# 0 ctrl -# 4 pass/fail -# 8 ptr to test name diff --git a/tests/tcg/lm32/test_add.S b/tests/tcg/lm32/test_add.S deleted file mode 100644 index 030ad197bb..0000000000 --- a/tests/tcg/lm32/test_add.S +++ /dev/null @@ -1,75 +0,0 @@ -.include "macros.inc" - -start - -test_name ADD_1 -mvi r1, 0 -mvi r2, 0 -add r3, r1, r2 -check_r3 0 - -test_name ADD_2 -mvi r1, 0 -mvi r2, 1 -add r3, r1, r2 -check_r3 1 - -test_name ADD_3 -mvi r1, 1 -mvi r2, 0 -add r3, r1, r2 -check_r3 1 - -test_name ADD_4 -mvi r1, 1 -mvi r2, -1 -add r3, r1, r2 -check_r3 0 - -test_name ADD_5 -mvi r1, -1 -mvi r2, 1 -add r3, r1, r2 -check_r3 0 - -test_name ADD_6 -mvi r1, -1 -mvi r2, 0 -add r3, r1, r2 -check_r3 -1 - -test_name ADD_7 -mvi r1, 0 -mvi r2, -1 -add r3, r1, r2 -check_r3 -1 - -test_name ADD_8 -mvi r3, 2 -add r3, r3, r3 -check_r3 4 - -test_name ADD_9 -mvi r1, 4 -mvi r3, 2 -add r3, r1, r3 -check_r3 6 - -test_name ADD_10 -mvi r1, 4 -mvi r3, 2 -add r3, r3, r1 -check_r3 6 - -test_name ADD_11 -mvi r1, 4 -add r3, r1, r1 -check_r3 8 - -test_name ADD_12 -load r1 0x12345678 -load r2 0xabcdef97 -add r3, r1, r2 -check_r3 0xbe02460f - -end diff --git a/tests/tcg/lm32/test_addi.S b/tests/tcg/lm32/test_addi.S deleted file mode 100644 index 68e766d1e5..0000000000 --- a/tests/tcg/lm32/test_addi.S +++ /dev/null @@ -1,56 +0,0 @@ -.include "macros.inc" - -start - -test_name ADDI_1 -mvi r1, 0 -addi r3, r1, 0 -check_r3 0 - -test_name ADDI_2 -mvi r1, 0 -addi r3, r1, 1 -check_r3 1 - -test_name ADDI_3 -mvi r1, 1 -addi r3, r1, 0 -check_r3 1 - -test_name ADDI_4 -mvi r1, 1 -addi r3, r1, -1 -check_r3 0 - -test_name ADDI_5 -mvi r1, -1 -addi r3, r1, 1 -check_r3 0 - -test_name ADDI_6 -mvi r1, -1 -addi r3, r1, 0 -check_r3 -1 - -test_name ADDI_7 -mvi r1, 0 -addi r3, r1, -1 -check_r3 -1 - -test_name ADDI_8 -mvi r3, 4 -addi r3, r3, 4 -check_r3 8 - -test_name ADDI_9 -mvi r3, 4 -addi r3, r3, -4 -check_r3 0 - -test_name ADDI_10 -mvi r3, 4 -addi r3, r3, -5 -check_r3 -1 - -end - diff --git a/tests/tcg/lm32/test_and.S b/tests/tcg/lm32/test_and.S deleted file mode 100644 index 80962ce7a2..0000000000 --- a/tests/tcg/lm32/test_and.S +++ /dev/null @@ -1,45 +0,0 @@ -.include "macros.inc" - -start - -test_name AND_1 -mvi r1, 0 -mvi r2, 0 -and r3, r1, r2 -check_r3 0 - -test_name AND_2 -mvi r1, 0 -mvi r2, 1 -and r3, r1, r2 -check_r3 0 - -test_name AND_3 -mvi r1, 1 -mvi r2, 1 -and r3, r1, r2 -check_r3 1 - -test_name AND_4 -mvi r3, 7 -and r3, r3, r3 -check_r3 7 - -test_name AND_5 -mvi r1, 7 -and r3, r1, r1 -check_r3 7 - -test_name AND_6 -mvi r1, 7 -mvi r3, 0 -and r3, r1, r3 -check_r3 0 - -test_name AND_7 -load r1 0xaa55aa55 -load r2 0x55aa55aa -and r3, r1, r2 -check_r3 0 - -end diff --git a/tests/tcg/lm32/test_andhi.S b/tests/tcg/lm32/test_andhi.S deleted file mode 100644 index 4f73af550b..0000000000 --- a/tests/tcg/lm32/test_andhi.S +++ /dev/null @@ -1,35 +0,0 @@ -.include "macros.inc" - -start - -test_name ANDHI_1 -mvi r1, 0 -andhi r3, r1, 0 -check_r3 0 - -test_name ANDHI_2 -mvi r1, 1 -andhi r3, r1, 1 -check_r3 0 - -test_name ANDHI_3 -load r1 0x000f0000 -andhi r3, r1, 1 -check_r3 0x00010000 - -test_name ANDHI_4 -load r1 0xffffffff -andhi r3, r1, 0xffff -check_r3 0xffff0000 - -test_name ANDHI_5 -load r1 0xffffffff -andhi r3, r1, 0 -check_r3 0 - -test_name ANDHI_6 -load r3 0x55aaffff -andhi r3, r3, 0xaaaa -check_r3 0x00aa0000 - -end diff --git a/tests/tcg/lm32/test_andi.S b/tests/tcg/lm32/test_andi.S deleted file mode 100644 index da1b0a32f7..0000000000 --- a/tests/tcg/lm32/test_andi.S +++ /dev/null @@ -1,35 +0,0 @@ -.include "macros.inc" - -start - -test_name ANDI_1 -mvi r1, 0 -andi r3, r1, 0 -check_r3 0 - -test_name ANDI_2 -mvi r1, 1 -andi r3, r1, 1 -check_r3 1 - -test_name ANDI_3 -load r1 0x000f0000 -andi r3, r1, 1 -check_r3 0 - -test_name ANDI_4 -load r1 0xffffffff -andi r3, r1, 0xffff -check_r3 0xffff - -test_name ANDI_5 -load r1 0xffffffff -andi r3, r1, 0 -check_r3 0 - -test_name ANDI_6 -load r3 0xffff55aa -andi r3, r3, 0xaaaa -check_r3 0x000000aa - -end diff --git a/tests/tcg/lm32/test_b.S b/tests/tcg/lm32/test_b.S deleted file mode 100644 index 98172d8a95..0000000000 --- a/tests/tcg/lm32/test_b.S +++ /dev/null @@ -1,13 +0,0 @@ -.include "macros.inc" - -start - -test_name B_1 -load r1 jump -b r1 -tc_fail -end - -jump: -tc_pass -end diff --git a/tests/tcg/lm32/test_be.S b/tests/tcg/lm32/test_be.S deleted file mode 100644 index 635cabacad..0000000000 --- a/tests/tcg/lm32/test_be.S +++ /dev/null @@ -1,48 +0,0 @@ -.include "macros.inc" - -start - -test_name BE_1 -mvi r1, 0 -mvi r2, 0 -be r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BE_2 -mvi r1, 1 -mvi r2, 0 -be r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BE_3 -mvi r1, 0 -mvi r2, 1 -be r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -bi 2f -1: -tc_pass -bi 3f -2: -test_name BE_4 -mvi r1, 1 -mvi r2, 1 -be r1, r2, 1b -tc_fail -3: - -end - diff --git a/tests/tcg/lm32/test_bg.S b/tests/tcg/lm32/test_bg.S deleted file mode 100644 index 81823c2304..0000000000 --- a/tests/tcg/lm32/test_bg.S +++ /dev/null @@ -1,78 +0,0 @@ -.include "macros.inc" - -start - -test_name BG_1 -mvi r1, 0 -mvi r2, 0 -bg r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BG_2 -mvi r1, 1 -mvi r2, 0 -bg r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BG_3 -mvi r1, 0 -mvi r2, 1 -bg r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BG_4 -mvi r1, 0 -mvi r2, -1 -bg r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BG_5 -mvi r1, -1 -mvi r2, 0 -bg r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BG_6 -mvi r1, -1 -mvi r2, -1 -bg r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -bi 2f -1: -tc_pass -bi 3f -2: -test_name BG_7 -mvi r1, 1 -mvi r2, 0 -bg r1, r2, 1b -tc_fail -3: - -end - diff --git a/tests/tcg/lm32/test_bge.S b/tests/tcg/lm32/test_bge.S deleted file mode 100644 index 6684d15a55..0000000000 --- a/tests/tcg/lm32/test_bge.S +++ /dev/null @@ -1,78 +0,0 @@ -.include "macros.inc" - -start - -test_name BGE_1 -mvi r1, 0 -mvi r2, 0 -bge r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BGE_2 -mvi r1, 1 -mvi r2, 0 -bge r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BGE_3 -mvi r1, 0 -mvi r2, 1 -bge r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BGE_4 -mvi r1, 0 -mvi r2, -1 -bge r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BGE_5 -mvi r1, -1 -mvi r2, 0 -bge r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BGE_6 -mvi r1, -1 -mvi r2, -1 -bge r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -bi 2f -1: -tc_pass -bi 3f -2: -test_name BGE_7 -mvi r1, 1 -mvi r2, 0 -bge r1, r2, 1b -tc_fail -3: - -end - diff --git a/tests/tcg/lm32/test_bgeu.S b/tests/tcg/lm32/test_bgeu.S deleted file mode 100644 index be440308fd..0000000000 --- a/tests/tcg/lm32/test_bgeu.S +++ /dev/null @@ -1,78 +0,0 @@ -.include "macros.inc" - -start - -test_name BGEU_1 -mvi r1, 0 -mvi r2, 0 -bgeu r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BGEU_2 -mvi r1, 1 -mvi r2, 0 -bgeu r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BGEU_3 -mvi r1, 0 -mvi r2, 1 -bgeu r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BGEU_4 -mvi r1, 0 -mvi r2, -1 -bgeu r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BGEU_5 -mvi r1, -1 -mvi r2, 0 -bgeu r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BGEU_6 -mvi r1, -1 -mvi r2, -1 -bgeu r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -bi 2f -1: -tc_pass -bi 3f -2: -test_name BGEU_7 -mvi r1, 1 -mvi r2, 0 -bgeu r1, r2, 1b -tc_fail -3: - -end - diff --git a/tests/tcg/lm32/test_bgu.S b/tests/tcg/lm32/test_bgu.S deleted file mode 100644 index 8cc695b310..0000000000 --- a/tests/tcg/lm32/test_bgu.S +++ /dev/null @@ -1,78 +0,0 @@ -.include "macros.inc" - -start - -test_name BGU_1 -mvi r1, 0 -mvi r2, 0 -bgu r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BGU_2 -mvi r1, 1 -mvi r2, 0 -bgu r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BGU_3 -mvi r1, 0 -mvi r2, 1 -bgu r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BGU_4 -mvi r1, 0 -mvi r2, -1 -bgu r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BGU_5 -mvi r1, -1 -mvi r2, 0 -bgu r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BGU_6 -mvi r1, -1 -mvi r2, -1 -bgu r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -bi 2f -1: -tc_pass -bi 3f -2: -test_name BGU_7 -mvi r1, 1 -mvi r2, 0 -bgu r1, r2, 1b -tc_fail -3: - -end - diff --git a/tests/tcg/lm32/test_bi.S b/tests/tcg/lm32/test_bi.S deleted file mode 100644 index a1fbd6fc07..0000000000 --- a/tests/tcg/lm32/test_bi.S +++ /dev/null @@ -1,23 +0,0 @@ -.include "macros.inc" - -start - -test_name BI_1 -bi jump -tc_fail -end - -jump_back: -tc_pass -end - -jump: -tc_pass - -test_name BI_2 -bi jump_back -tc_fail - -end - - diff --git a/tests/tcg/lm32/test_bne.S b/tests/tcg/lm32/test_bne.S deleted file mode 100644 index 871a006755..0000000000 --- a/tests/tcg/lm32/test_bne.S +++ /dev/null @@ -1,48 +0,0 @@ -.include "macros.inc" - -start - -test_name BNE_1 -mvi r1, 0 -mvi r2, 0 -bne r1, r2, 1f -tc_pass -bi 2f -1: -tc_fail -2: - -test_name BNE_2 -mvi r1, 1 -mvi r2, 0 -bne r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -test_name BNE_3 -mvi r1, 0 -mvi r2, 1 -bne r1, r2, 1f -tc_fail -bi 2f -1: -tc_pass -2: - -bi 2f -1: -tc_fail -bi 3f -2: -test_name BNE_4 -mvi r1, 1 -mvi r2, 1 -bne r1, r2, 1b -tc_pass -3: - -end - diff --git a/tests/tcg/lm32/test_break.S b/tests/tcg/lm32/test_break.S deleted file mode 100644 index 0384fc6128..0000000000 --- a/tests/tcg/lm32/test_break.S +++ /dev/null @@ -1,20 +0,0 @@ -.include "macros.inc" - -start - -test_name BREAK_1 -mvi r1, 1 -wcsr IE, r1 -insn: -break -check_excp 1 - -test_name BREAK_2 -mv r3, ba -check_r3 insn - -test_name BREAK_3 -rcsr r3, IE -check_r3 4 - -end diff --git a/tests/tcg/lm32/test_bret.S b/tests/tcg/lm32/test_bret.S deleted file mode 100644 index 645210e434..0000000000 --- a/tests/tcg/lm32/test_bret.S +++ /dev/null @@ -1,38 +0,0 @@ -.include "macros.inc" - -start - -test_name BRET_1 -mvi r1, 4 -wcsr IE, r1 -load ba mark -bret -tc_fail -bi 1f - -mark: -tc_pass - -1: -test_name BRET_2 -rcsr r3, IE -check_r3 5 - -test_name BRET_3 -mvi r1, 0 -wcsr IE, r1 -load ba mark2 -bret -tc_fail -bi 1f - -mark2: -tc_pass - -1: -test_name BRET_4 -rcsr r3, IE -check_r3 0 - -end - diff --git a/tests/tcg/lm32/test_call.S b/tests/tcg/lm32/test_call.S deleted file mode 100644 index 1b91a5f2be..0000000000 --- a/tests/tcg/lm32/test_call.S +++ /dev/null @@ -1,16 +0,0 @@ -.include "macros.inc" - -start - -test_name CALL_1 -load r1 mark -call r1 -return: - -tc_fail -end - -mark: -mv r3, ra -check_r3 return -end diff --git a/tests/tcg/lm32/test_calli.S b/tests/tcg/lm32/test_calli.S deleted file mode 100644 index 1d87ae6e21..0000000000 --- a/tests/tcg/lm32/test_calli.S +++ /dev/null @@ -1,15 +0,0 @@ -.include "macros.inc" - -start - -test_name CALLI_1 -calli mark -return: - -tc_fail -end - -mark: -mv r3, ra -check_r3 return -end diff --git a/tests/tcg/lm32/test_cmpe.S b/tests/tcg/lm32/test_cmpe.S deleted file mode 100644 index 60a885500b..0000000000 --- a/tests/tcg/lm32/test_cmpe.S +++ /dev/null @@ -1,40 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPE_1 -mvi r1, 0 -mvi r2, 0 -cmpe r3, r1, r2 -check_r3 1 - -test_name CMPE_2 -mvi r1, 0 -mvi r2, 1 -cmpe r3, r1, r2 -check_r3 0 - -test_name CMPE_3 -mvi r1, 1 -mvi r2, 0 -cmpe r3, r1, r2 -check_r3 0 - -test_name CMPE_4 -mvi r3, 0 -mvi r2, 1 -cmpe r3, r3, r2 -check_r3 0 - -test_name CMPE_5 -mvi r3, 0 -mvi r2, 0 -cmpe r3, r3, r2 -check_r3 1 - -test_name CMPE_6 -mvi r3, 0 -cmpe r3, r3, r3 -check_r3 1 - -end diff --git a/tests/tcg/lm32/test_cmpei.S b/tests/tcg/lm32/test_cmpei.S deleted file mode 100644 index c3d3566ad3..0000000000 --- a/tests/tcg/lm32/test_cmpei.S +++ /dev/null @@ -1,35 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPEI_1 -mvi r1, 0 -cmpei r3, r1, 0 -check_r3 1 - -test_name CMPEI_2 -mvi r1, 0 -cmpei r3, r1, 1 -check_r3 0 - -test_name CMPEI_3 -mvi r1, 1 -cmpei r3, r1, 0 -check_r3 0 - -test_name CMPEI_4 -load r1 0xffffffff -cmpei r3, r1, -1 -check_r3 1 - -test_name CMPEI_5 -mvi r3, 0 -cmpei r3, r3, 0 -check_r3 1 - -test_name CMPEI_6 -mvi r3, 0 -cmpei r3, r3, 1 -check_r3 0 - -end diff --git a/tests/tcg/lm32/test_cmpg.S b/tests/tcg/lm32/test_cmpg.S deleted file mode 100644 index 012407874c..0000000000 --- a/tests/tcg/lm32/test_cmpg.S +++ /dev/null @@ -1,64 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPG_1 -mvi r1, 0 -mvi r2, 0 -cmpg r3, r1, r2 -check_r3 0 - -test_name CMPG_2 -mvi r1, 0 -mvi r2, 1 -cmpg r3, r1, r2 -check_r3 0 - -test_name CMPG_3 -mvi r1, 1 -mvi r2, 0 -cmpg r3, r1, r2 -check_r3 1 - -test_name CMPG_4 -mvi r1, 1 -mvi r2, 1 -cmpg r3, r1, r2 -check_r3 0 - -test_name CMPG_5 -mvi r1, 0 -mvi r2, -1 -cmpg r3, r1, r2 -check_r3 1 - -test_name CMPG_6 -mvi r1, -1 -mvi r2, 0 -cmpg r3, r1, r2 -check_r3 0 - -test_name CMPG_7 -mvi r1, -1 -mvi r2, -1 -cmpg r3, r1, r2 -check_r3 0 - -test_name CMPG_8 -mvi r3, 0 -mvi r2, 1 -cmpg r3, r3, r2 -check_r3 0 - -test_name CMPG_9 -mvi r3, 1 -mvi r2, 0 -cmpg r3, r3, r2 -check_r3 1 - -test_name CMPG_10 -mvi r3, 0 -cmpg r3, r3, r3 -check_r3 0 - -end diff --git a/tests/tcg/lm32/test_cmpge.S b/tests/tcg/lm32/test_cmpge.S deleted file mode 100644 index 84620a00e3..0000000000 --- a/tests/tcg/lm32/test_cmpge.S +++ /dev/null @@ -1,64 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPGE_1 -mvi r1, 0 -mvi r2, 0 -cmpge r3, r1, r2 -check_r3 1 - -test_name CMPGE_2 -mvi r1, 0 -mvi r2, 1 -cmpge r3, r1, r2 -check_r3 0 - -test_name CMPGE_3 -mvi r1, 1 -mvi r2, 0 -cmpge r3, r1, r2 -check_r3 1 - -test_name CMPGE_4 -mvi r1, 1 -mvi r2, 1 -cmpge r3, r1, r2 -check_r3 1 - -test_name CMPGE_5 -mvi r1, 0 -mvi r2, -1 -cmpge r3, r1, r2 -check_r3 1 - -test_name CMPGE_6 -mvi r1, -1 -mvi r2, 0 -cmpge r3, r1, r2 -check_r3 0 - -test_name CMPGE_7 -mvi r1, -1 -mvi r2, -1 -cmpge r3, r1, r2 -check_r3 1 - -test_name CMPGE_8 -mvi r3, 0 -mvi r2, 1 -cmpge r3, r3, r2 -check_r3 0 - -test_name CMPGE_9 -mvi r3, 1 -mvi r2, 0 -cmpge r3, r3, r2 -check_r3 1 - -test_name CMPGE_10 -mvi r3, 0 -cmpge r3, r3, r3 -check_r3 1 - -end diff --git a/tests/tcg/lm32/test_cmpgei.S b/tests/tcg/lm32/test_cmpgei.S deleted file mode 100644 index 6e388a2a35..0000000000 --- a/tests/tcg/lm32/test_cmpgei.S +++ /dev/null @@ -1,70 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPGEI_1 -mvi r1, 0 -cmpgei r3, r1, 0 -check_r3 1 - -test_name CMPGEI_2 -mvi r1, 0 -cmpgei r3, r1, 1 -check_r3 0 - -test_name CMPGEI_3 -mvi r1, 1 -cmpgei r3, r1, 0 -check_r3 1 - -test_name CMPGEI_4 -mvi r1, 1 -cmpgei r3, r1, 1 -check_r3 1 - -test_name CMPGEI_5 -mvi r1, 0 -cmpgei r3, r1, -1 -check_r3 1 - -test_name CMPGEI_6 -mvi r1, -1 -cmpgei r3, r1, 0 -check_r3 0 - -test_name CMPGEI_7 -mvi r1, -1 -cmpgei r3, r1, -1 -check_r3 1 - -test_name CMPGEI_8 -mvi r3, 0 -cmpgei r3, r3, 1 -check_r3 0 - -test_name CMPGEI_9 -mvi r3, 1 -cmpgei r3, r3, 0 -check_r3 1 - -test_name CMPGEI_10 -mvi r3, 0 -cmpgei r3, r3, 0 -check_r3 1 - -test_name CMPGEI_11 -mvi r1, 0 -cmpgei r3, r1, -32768 -check_r3 1 - -test_name CMPGEI_12 -mvi r1, -1 -cmpgei r3, r1, -32768 -check_r3 1 - -test_name CMPGEI_13 -mvi r1, -32768 -cmpgei r3, r1, -32768 -check_r3 1 - -end diff --git a/tests/tcg/lm32/test_cmpgeu.S b/tests/tcg/lm32/test_cmpgeu.S deleted file mode 100644 index 2110ccb6b7..0000000000 --- a/tests/tcg/lm32/test_cmpgeu.S +++ /dev/null @@ -1,64 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPGEU_1 -mvi r1, 0 -mvi r2, 0 -cmpgeu r3, r1, r2 -check_r3 1 - -test_name CMPGEU_2 -mvi r1, 0 -mvi r2, 1 -cmpgeu r3, r1, r2 -check_r3 0 - -test_name CMPGEU_3 -mvi r1, 1 -mvi r2, 0 -cmpgeu r3, r1, r2 -check_r3 1 - -test_name CMPGEU_4 -mvi r1, 1 -mvi r2, 1 -cmpgeu r3, r1, r2 -check_r3 1 - -test_name CMPGEU_5 -mvi r1, 0 -mvi r2, -1 -cmpgeu r3, r1, r2 -check_r3 0 - -test_name CMPGEU_6 -mvi r1, -1 -mvi r2, 0 -cmpgeu r3, r1, r2 -check_r3 1 - -test_name CMPGEU_7 -mvi r1, -1 -mvi r2, -1 -cmpgeu r3, r1, r2 -check_r3 1 - -test_name CMPGEU_8 -mvi r3, 0 -mvi r2, 1 -cmpgeu r3, r3, r2 -check_r3 0 - -test_name CMPGEU_9 -mvi r3, 1 -mvi r2, 0 -cmpgeu r3, r3, r2 -check_r3 1 - -test_name CMPGEU_10 -mvi r3, 0 -cmpgeu r3, r3, r3 -check_r3 1 - -end diff --git a/tests/tcg/lm32/test_cmpgeui.S b/tests/tcg/lm32/test_cmpgeui.S deleted file mode 100644 index 3866d96cb7..0000000000 --- a/tests/tcg/lm32/test_cmpgeui.S +++ /dev/null @@ -1,70 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPGEUI_1 -mvi r1, 0 -cmpgeui r3, r1, 0 -check_r3 1 - -test_name CMPGEUI_2 -mvi r1, 0 -cmpgeui r3, r1, 1 -check_r3 0 - -test_name CMPGEUI_3 -mvi r1, 1 -cmpgeui r3, r1, 0 -check_r3 1 - -test_name CMPGEUI_4 -mvi r1, 1 -cmpgeui r3, r1, 1 -check_r3 1 - -test_name CMPGEUI_5 -mvi r1, 0 -cmpgeui r3, r1, 0xffff -check_r3 0 - -test_name CMPGEUI_6 -mvi r1, -1 -cmpgeui r3, r1, 0 -check_r3 1 - -test_name CMPGEUI_7 -mvi r1, -1 -cmpgeui r3, r1, 0xffff -check_r3 1 - -test_name CMPGEUI_8 -mvi r3, 0 -cmpgeui r3, r3, 1 -check_r3 0 - -test_name CMPGEUI_9 -mvi r3, 1 -cmpgeui r3, r3, 0 -check_r3 1 - -test_name CMPGEUI_10 -mvi r3, 0 -cmpgeui r3, r3, 0 -check_r3 1 - -test_name CMPGEUI_11 -mvi r1, 0 -cmpgeui r3, r1, 0x8000 -check_r3 0 - -test_name CMPGEUI_12 -mvi r1, -1 -cmpgeui r3, r1, 0x8000 -check_r3 1 - -test_name CMPGEUI_13 -ori r1, r0, 0x8000 -cmpgeui r3, r1, 0x8000 -check_r3 1 - -end diff --git a/tests/tcg/lm32/test_cmpgi.S b/tests/tcg/lm32/test_cmpgi.S deleted file mode 100644 index 21695f97ab..0000000000 --- a/tests/tcg/lm32/test_cmpgi.S +++ /dev/null @@ -1,70 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPGI_1 -mvi r1, 0 -cmpgi r3, r1, 0 -check_r3 0 - -test_name CMPGI_2 -mvi r1, 0 -cmpgi r3, r1, 1 -check_r3 0 - -test_name CMPGI_3 -mvi r1, 1 -cmpgi r3, r1, 0 -check_r3 1 - -test_name CMPGI_4 -mvi r1, 1 -cmpgi r3, r1, 1 -check_r3 0 - -test_name CMPGI_5 -mvi r1, 0 -cmpgi r3, r1, -1 -check_r3 1 - -test_name CMPGI_6 -mvi r1, -1 -cmpgi r3, r1, 0 -check_r3 0 - -test_name CMPGI_7 -mvi r1, -1 -cmpgi r3, r1, -1 -check_r3 0 - -test_name CMPGI_8 -mvi r3, 0 -cmpgi r3, r3, 1 -check_r3 0 - -test_name CMPGI_9 -mvi r3, 1 -cmpgi r3, r3, 0 -check_r3 1 - -test_name CMPGI_10 -mvi r3, 0 -cmpgi r3, r3, 0 -check_r3 0 - -test_name CMPGI_11 -mvi r1, 0 -cmpgi r3, r1, -32768 -check_r3 1 - -test_name CMPGI_12 -mvi r1, -1 -cmpgi r3, r1, -32768 -check_r3 1 - -test_name CMPGI_13 -mvi r1, -32768 -cmpgi r3, r1, -32768 -check_r3 0 - -end diff --git a/tests/tcg/lm32/test_cmpgu.S b/tests/tcg/lm32/test_cmpgu.S deleted file mode 100644 index dd465471ea..0000000000 --- a/tests/tcg/lm32/test_cmpgu.S +++ /dev/null @@ -1,64 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPGU_1 -mvi r1, 0 -mvi r2, 0 -cmpgu r3, r1, r2 -check_r3 0 - -test_name CMPGU_2 -mvi r1, 0 -mvi r2, 1 -cmpgu r3, r1, r2 -check_r3 0 - -test_name CMPGU_3 -mvi r1, 1 -mvi r2, 0 -cmpgu r3, r1, r2 -check_r3 1 - -test_name CMPGU_4 -mvi r1, 1 -mvi r2, 1 -cmpgu r3, r1, r2 -check_r3 0 - -test_name CMPGU_5 -mvi r1, 0 -mvi r2, -1 -cmpgu r3, r1, r2 -check_r3 0 - -test_name CMPGU_6 -mvi r1, -1 -mvi r2, 0 -cmpgu r3, r1, r2 -check_r3 1 - -test_name CMPGU_7 -mvi r1, -1 -mvi r2, -1 -cmpgu r3, r1, r2 -check_r3 0 - -test_name CMPGU_8 -mvi r3, 0 -mvi r2, 1 -cmpgu r3, r3, r2 -check_r3 0 - -test_name CMPGU_9 -mvi r3, 1 -mvi r2, 0 -cmpgu r3, r3, r2 -check_r3 1 - -test_name CMPGU_10 -mvi r3, 0 -cmpgu r3, r3, r3 -check_r3 0 - -end diff --git a/tests/tcg/lm32/test_cmpgui.S b/tests/tcg/lm32/test_cmpgui.S deleted file mode 100644 index dd94001492..0000000000 --- a/tests/tcg/lm32/test_cmpgui.S +++ /dev/null @@ -1,70 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPGUI_1 -mvi r1, 0 -cmpgui r3, r1, 0 -check_r3 0 - -test_name CMPGUI_2 -mvi r1, 0 -cmpgui r3, r1, 1 -check_r3 0 - -test_name CMPGUI_3 -mvi r1, 1 -cmpgui r3, r1, 0 -check_r3 1 - -test_name CMPGUI_4 -mvi r1, 1 -cmpgui r3, r1, 1 -check_r3 0 - -test_name CMPGUI_5 -mvi r1, 0 -cmpgui r3, r1, 0xffff -check_r3 0 - -test_name CMPGUI_6 -mvi r1, -1 -cmpgui r3, r1, 0 -check_r3 1 - -test_name CMPGUI_7 -mvi r1, -1 -cmpgui r3, r1, 0xffff -check_r3 1 - -test_name CMPGUI_8 -mvi r3, 0 -cmpgui r3, r3, 1 -check_r3 0 - -test_name CMPGUI_9 -mvi r3, 1 -cmpgui r3, r3, 0 -check_r3 1 - -test_name CMPGUI_10 -mvi r3, 0 -cmpgui r3, r3, 0 -check_r3 0 - -test_name CMPGUI_11 -mvi r1, 0 -cmpgui r3, r1, 0x8000 -check_r3 0 - -test_name CMPGUI_12 -mvi r1, -1 -cmpgui r3, r1, 0x8000 -check_r3 1 - -test_name CMPGUI_13 -ori r1, r0, 0x8000 -cmpgui r3, r1, 0x8000 -check_r3 0 - -end diff --git a/tests/tcg/lm32/test_cmpne.S b/tests/tcg/lm32/test_cmpne.S deleted file mode 100644 index 0f1078114c..0000000000 --- a/tests/tcg/lm32/test_cmpne.S +++ /dev/null @@ -1,40 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPNE_1 -mvi r1, 0 -mvi r2, 0 -cmpne r3, r1, r2 -check_r3 0 - -test_name CMPNE_2 -mvi r1, 0 -mvi r2, 1 -cmpne r3, r1, r2 -check_r3 1 - -test_name CMPNE_3 -mvi r1, 1 -mvi r2, 0 -cmpne r3, r1, r2 -check_r3 1 - -test_name CMPNE_4 -mvi r3, 0 -mvi r2, 1 -cmpne r3, r3, r2 -check_r3 1 - -test_name CMPNE_5 -mvi r3, 0 -mvi r2, 0 -cmpne r3, r3, r2 -check_r3 0 - -test_name CMPNE_6 -mvi r3, 0 -cmpne r3, r3, r3 -check_r3 0 - -end diff --git a/tests/tcg/lm32/test_cmpnei.S b/tests/tcg/lm32/test_cmpnei.S deleted file mode 100644 index 060dd9d394..0000000000 --- a/tests/tcg/lm32/test_cmpnei.S +++ /dev/null @@ -1,35 +0,0 @@ -.include "macros.inc" - -start - -test_name CMPNEI_1 -mvi r1, 0 -cmpnei r3, r1, 0 -check_r3 0 - -test_name CMPNEI_2 -mvi r1, 0 -cmpnei r3, r1, 1 -check_r3 1 - -test_name CMPNEI_3 -mvi r1, 1 -cmpnei r3, r1, 0 -check_r3 1 - -test_name CMPNEI_4 -load r1 0xffffffff -cmpnei r3, r1, -1 -check_r3 0 - -test_name CMPNEI_5 -mvi r3, 0 -cmpnei r3, r3, 0 -check_r3 0 - -test_name CMPNEI_6 -mvi r3, 0 -cmpnei r3, r3, 1 -check_r3 1 - -end diff --git a/tests/tcg/lm32/test_divu.S b/tests/tcg/lm32/test_divu.S deleted file mode 100644 index f381d095c5..0000000000 --- a/tests/tcg/lm32/test_divu.S +++ /dev/null @@ -1,29 +0,0 @@ -.include "macros.inc" - -start - -test_name DIVU_1 -mvi r1, 0 -mvi r2, 1 -divu r3, r1, r2 -check_r3 0 - -test_name DIVU_2 -mvi r1, 1 -mvi r2, 1 -divu r3, r1, r2 -check_r3 1 - -test_name DIVU_3 -mvi r1, 0 -mvi r2, 0 -divu r3, r1, r2 -check_excp 16 - -test_name DIVU_4 -load r1 0xabcdef12 -load r2 0x12345 -divu r3, r1, r2 -check_r3 0x9700 - -end diff --git a/tests/tcg/lm32/test_eret.S b/tests/tcg/lm32/test_eret.S deleted file mode 100644 index 6830bd1abf..0000000000 --- a/tests/tcg/lm32/test_eret.S +++ /dev/null @@ -1,38 +0,0 @@ -.include "macros.inc" - -start - -test_name ERET_1 -mvi r1, 2 -wcsr IE, r1 -load ea mark -eret -tc_fail -bi 1f - -mark: -tc_pass - -1: -test_name ERET_2 -rcsr r3, IE -check_r3 3 - -test_name ERET_3 -mvi r1, 0 -wcsr IE, r1 -load ea mark2 -eret -tc_fail -bi 1f - -mark2: -tc_pass - -1: -test_name ERET_4 -rcsr r3, IE -check_r3 0 - -end - diff --git a/tests/tcg/lm32/test_lb.S b/tests/tcg/lm32/test_lb.S deleted file mode 100644 index d677eea4c4..0000000000 --- a/tests/tcg/lm32/test_lb.S +++ /dev/null @@ -1,49 +0,0 @@ -.include "macros.inc" - -start - -test_name LB_1 -load r1 data -lb r3, (r1+0) -check_r3 0x7e - -test_name LB_2 -load r1 data -lb r3, (r1+1) -check_r3 0x7f - -test_name LB_3 -load r1 data -lb r3, (r1+-1) -check_r3 0x7d - -test_name LB_4 -load r1 data_msb -lb r3, (r1+0) -check_r3 0xfffffffe - -test_name LB_5 -load r1 data_msb -lb r3, (r1+1) -check_r3 0xffffffff - -test_name LB_6 -load r1 data_msb -lb r3, (r1+-1) -check_r3 0xfffffffd - -test_name LB_7 -load r3 data -lb r3, (r3+0) -check_r3 0x7e - -end - -.data - .align 4 - .byte 0x7a, 0x7b, 0x7c, 0x7d -data: - .byte 0x7e, 0x7f, 0x70, 0x71 - .byte 0xfa, 0xfb, 0xfc, 0xfd -data_msb: - .byte 0xfe, 0xff, 0xf0, 0xf1 diff --git a/tests/tcg/lm32/test_lbu.S b/tests/tcg/lm32/test_lbu.S deleted file mode 100644 index dc5d5f67d3..0000000000 --- a/tests/tcg/lm32/test_lbu.S +++ /dev/null @@ -1,49 +0,0 @@ -.include "macros.inc" - -start - -test_name LBU_1 -load r1 data -lbu r3, (r1+0) -check_r3 0x7e - -test_name LBU_2 -load r1 data -lbu r3, (r1+1) -check_r3 0x7f - -test_name LBU_3 -load r1 data -lbu r3, (r1+-1) -check_r3 0x7d - -test_name LBU_4 -load r1 data_msb -lbu r3, (r1+0) -check_r3 0xfe - -test_name LBU_5 -load r1 data_msb -lbu r3, (r1+1) -check_r3 0xff - -test_name LBU_6 -load r1 data_msb -lbu r3, (r1+-1) -check_r3 0xfd - -test_name LBU_7 -load r3 data -lbu r3, (r3+0) -check_r3 0x7e - -end - -.data - .align 4 - .byte 0x7a, 0x7b, 0x7c, 0x7d -data: - .byte 0x7e, 0x7f, 0x70, 0x71 - .byte 0xfa, 0xfb, 0xfc, 0xfd -data_msb: - .byte 0xfe, 0xff, 0xf0, 0xf1 diff --git a/tests/tcg/lm32/test_lh.S b/tests/tcg/lm32/test_lh.S deleted file mode 100644 index 397996bddd..0000000000 --- a/tests/tcg/lm32/test_lh.S +++ /dev/null @@ -1,49 +0,0 @@ -.include "macros.inc" - -start - -test_name LH_1 -load r1 data -lh r3, (r1+0) -check_r3 0x7e7f - -test_name LH_2 -load r1 data -lh r3, (r1+2) -check_r3 0x7071 - -test_name LH_3 -load r1 data -lh r3, (r1+-2) -check_r3 0x7c7d - -test_name LH_4 -load r1 data_msb -lh r3, (r1+0) -check_r3 0xfffffeff - -test_name LH_5 -load r1 data_msb -lh r3, (r1+2) -check_r3 0xfffff0f1 - -test_name LH_6 -load r1 data_msb -lh r3, (r1+-2) -check_r3 0xfffffcfd - -test_name LH_7 -load r3 data -lh r3, (r3+0) -check_r3 0x7e7f - -end - -.data - .align 4 - .byte 0x7a, 0x7b, 0x7c, 0x7d -data: - .byte 0x7e, 0x7f, 0x70, 0x71 - .byte 0xfa, 0xfb, 0xfc, 0xfd -data_msb: - .byte 0xfe, 0xff, 0xf0, 0xf1 diff --git a/tests/tcg/lm32/test_lhu.S b/tests/tcg/lm32/test_lhu.S deleted file mode 100644 index 8de7c52560..0000000000 --- a/tests/tcg/lm32/test_lhu.S +++ /dev/null @@ -1,49 +0,0 @@ -.include "macros.inc" - -start - -test_name LHU_1 -load r1 data -lhu r3, (r1+0) -check_r3 0x7e7f - -test_name LHU_2 -load r1 data -lhu r3, (r1+2) -check_r3 0x7071 - -test_name LHU_3 -load r1 data -lhu r3, (r1+-2) -check_r3 0x7c7d - -test_name LHU_4 -load r1 data_msb -lhu r3, (r1+0) -check_r3 0xfeff - -test_name LHU_5 -load r1 data_msb -lhu r3, (r1+2) -check_r3 0xf0f1 - -test_name LHU_6 -load r1 data_msb -lhu r3, (r1+-2) -check_r3 0xfcfd - -test_name LHU_7 -load r3 data -lhu r3, (r3+0) -check_r3 0x7e7f - -end - -.data - .align 4 - .byte 0x7a, 0x7b, 0x7c, 0x7d -data: - .byte 0x7e, 0x7f, 0x70, 0x71 - .byte 0xfa, 0xfb, 0xfc, 0xfd -data_msb: - .byte 0xfe, 0xff, 0xf0, 0xf1 diff --git a/tests/tcg/lm32/test_lw.S b/tests/tcg/lm32/test_lw.S deleted file mode 100644 index 996e5f8c88..0000000000 --- a/tests/tcg/lm32/test_lw.S +++ /dev/null @@ -1,32 +0,0 @@ -.include "macros.inc" - -start - -test_name LW_1 -load r1 data -lw r3, (r1+0) -check_r3 0x7e7f7071 - -test_name LW_2 -load r1 data -lw r3, (r1+4) -check_r3 0x72737475 - -test_name LW_3 -load r1 data -lw r3, (r1+-4) -check_r3 0x7a7b7c7d - -test_name LW_4 -load r3 data -lw r3, (r3+0) -check_r3 0x7e7f7071 - -end - -.data - .align 4 - .byte 0x7a, 0x7b, 0x7c, 0x7d -data: - .byte 0x7e, 0x7f, 0x70, 0x71 - .byte 0x72, 0x73, 0x74, 0x75 diff --git a/tests/tcg/lm32/test_modu.S b/tests/tcg/lm32/test_modu.S deleted file mode 100644 index 42486900b4..0000000000 --- a/tests/tcg/lm32/test_modu.S +++ /dev/null @@ -1,35 +0,0 @@ -.include "macros.inc" - -start - -test_name MODU_1 -mvi r1, 0 -mvi r2, 1 -modu r3, r1, r2 -check_r3 0 - -test_name MODU_2 -mvi r1, 1 -mvi r2, 1 -modu r3, r1, r2 -check_r3 0 - -test_name MODU_3 -mvi r1, 3 -mvi r2, 2 -modu r3, r1, r2 -check_r3 1 - -test_name MODU_4 -mvi r1, 0 -mvi r2, 0 -modu r3, r1, r2 -check_excp 16 - -test_name MODU_5 -load r1 0xabcdef12 -load r2 0x12345 -modu r3, r1, r2 -check_r3 0x3c12 - -end diff --git a/tests/tcg/lm32/test_mul.S b/tests/tcg/lm32/test_mul.S deleted file mode 100644 index e9b937e648..0000000000 --- a/tests/tcg/lm32/test_mul.S +++ /dev/null @@ -1,70 +0,0 @@ -.include "macros.inc" - -start - -test_name MUL_1 -mvi r1, 0 -mvi r2, 0 -mul r3, r1, r2 -check_r3 0 - -test_name MUL_2 -mvi r1, 1 -mvi r2, 0 -mul r3, r1, r2 -check_r3 0 - -test_name MUL_3 -mvi r1, 0 -mvi r2, 1 -mul r3, r1, r2 -check_r3 0 - -test_name MUL_4 -mvi r1, 1 -mvi r2, 1 -mul r3, r1, r2 -check_r3 1 - -test_name MUL_5 -mvi r1, 2 -mvi r2, -1 -mul r3, r1, r2 -check_r3 -2 - -test_name MUL_6 -mvi r1, -2 -mvi r2, -1 -mul r3, r1, r2 -check_r3 2 - -test_name MUL_7 -mvi r1, 0x1234 -mvi r2, 0x789 -mul r3, r1, r2 -check_r3 0x8929d4 - -test_name MUL_8 -mvi r3, 4 -mul r3, r3, r3 -check_r3 16 - -test_name MUL_9 -mvi r2, 2 -mvi r3, 4 -mul r3, r3, r2 -check_r3 8 - -test_name MUL_10 -load r1 0x12345678 -load r2 0x7bcdef12 -mul r3, r1, r2 -check_r3 0xa801c70 - -test_name MUL_11 -load r1 0x12345678 -load r2 0xabcdef12 -mul r3, r1, r2 -check_r3 0x8a801c70 - -end diff --git a/tests/tcg/lm32/test_muli.S b/tests/tcg/lm32/test_muli.S deleted file mode 100644 index d6dd4a0f7e..0000000000 --- a/tests/tcg/lm32/test_muli.S +++ /dev/null @@ -1,45 +0,0 @@ -.include "macros.inc" - -start - -test_name MULI_1 -mvi r1, 0 -muli r3, r1, 0 -check_r3 0 - -test_name MULI_2 -mvi r1, 1 -muli r3, r1, 0 -check_r3 0 - -test_name MULI_3 -mvi r1, 0 -muli r3, r1, 1 -check_r3 0 - -test_name MULI_4 -mvi r1, 1 -muli r3, r1, 1 -check_r3 1 - -test_name MULI_5 -mvi r1, 2 -muli r3, r1, -1 -check_r3 -2 - -test_name MULI_6 -mvi r1, -2 -muli r3, r1, -1 -check_r3 2 - -test_name MULI_7 -mvi r1, 0x1234 -muli r3, r1, 0x789 -check_r3 0x8929d4 - -test_name MULI_8 -mvi r3, 4 -muli r3, r3, 4 -check_r3 16 - -end diff --git a/tests/tcg/lm32/test_nor.S b/tests/tcg/lm32/test_nor.S deleted file mode 100644 index 74d7592565..0000000000 --- a/tests/tcg/lm32/test_nor.S +++ /dev/null @@ -1,51 +0,0 @@ -.include "macros.inc" - -start - -test_name NOR_1 -mvi r1, 0 -mvi r2, 0 -nor r3, r1, r2 -check_r3 0xffffffff - -test_name NOR_2 -mvi r1, 0 -mvi r2, 1 -nor r3, r1, r2 -check_r3 0xfffffffe - -test_name NOR_3 -mvi r1, 1 -mvi r2, 1 -nor r3, r1, r2 -check_r3 0xfffffffe - -test_name NOR_4 -mvi r1, 1 -mvi r2, 0 -nor r3, r1, r2 -check_r3 0xfffffffe - -test_name NOR_5 -load r1 0xaa55aa55 -load r2 0x55aa55aa -nor r3, r1, r2 -check_r3 0 - -test_name NOR_6 -load r1 0xaa550000 -load r2 0x0000aa55 -nor r3, r1, r2 -check_r3 0x55aa55aa - -test_name NOR_7 -load r1 0xaa55aa55 -nor r3, r1, r1 -check_r3 0x55aa55aa - -test_name NOR_8 -load r3 0xaa55aa55 -nor r3, r3, r3 -check_r3 0x55aa55aa - -end diff --git a/tests/tcg/lm32/test_nori.S b/tests/tcg/lm32/test_nori.S deleted file mode 100644 index d00309c73e..0000000000 --- a/tests/tcg/lm32/test_nori.S +++ /dev/null @@ -1,35 +0,0 @@ -.include "macros.inc" - -start - -test_name NORI_1 -mvi r1, 0 -nori r3, r1, 0 -check_r3 0xffffffff - -test_name NORI_2 -mvi r1, 0 -nori r3, r1, 1 -check_r3 0xfffffffe - -test_name NORI_3 -mvi r1, 1 -nori r3, r1, 1 -check_r3 0xfffffffe - -test_name NORI_4 -mvi r1, 1 -nori r3, r1, 0 -check_r3 0xfffffffe - -test_name NORI_5 -load r1 0xaa55aa55 -nori r3, r1, 0x55aa -check_r3 0x55aa0000 - -test_name NORI_6 -load r3 0xaa55aa55 -nori r3, r3, 0x55aa -check_r3 0x55aa0000 - -end diff --git a/tests/tcg/lm32/test_or.S b/tests/tcg/lm32/test_or.S deleted file mode 100644 index 4ed292330e..0000000000 --- a/tests/tcg/lm32/test_or.S +++ /dev/null @@ -1,51 +0,0 @@ -.include "macros.inc" - -start - -test_name OR_1 -mvi r1, 0 -mvi r2, 0 -or r3, r1, r2 -check_r3 0 - -test_name OR_2 -mvi r1, 0 -mvi r2, 1 -or r3, r1, r2 -check_r3 1 - -test_name OR_3 -mvi r1, 1 -mvi r2, 1 -or r3, r1, r2 -check_r3 1 - -test_name OR_4 -mvi r1, 1 -mvi r2, 0 -or r3, r1, r2 -check_r3 1 - -test_name OR_5 -load r1 0xaa55aa55 -load r2 0x55aa55aa -or r3, r1, r2 -check_r3 0xffffffff - -test_name OR_6 -load r1 0xaa550000 -load r2 0x0000aa55 -or r3, r1, r2 -check_r3 0xaa55aa55 - -test_name OR_7 -load r1 0xaa55aa55 -or r3, r1, r1 -check_r3 0xaa55aa55 - -test_name OR_8 -load r3 0xaa55aa55 -or r3, r3, r3 -check_r3 0xaa55aa55 - -end diff --git a/tests/tcg/lm32/test_orhi.S b/tests/tcg/lm32/test_orhi.S deleted file mode 100644 index 78b7600e03..0000000000 --- a/tests/tcg/lm32/test_orhi.S +++ /dev/null @@ -1,35 +0,0 @@ -.include "macros.inc" - -start - -test_name ORHI_1 -mvi r1, 0 -orhi r3, r1, 0 -check_r3 0 - -test_name ORHI_2 -mvi r1, 0 -orhi r3, r1, 1 -check_r3 0x00010000 - -test_name ORHI_3 -load r1 0x00010000 -orhi r3, r1, 1 -check_r3 0x00010000 - -test_name ORHI_4 -mvi r1, 1 -orhi r3, r1, 0 -check_r3 1 - -test_name ORHI_5 -load r1 0xaa55aa55 -orhi r3, r1, 0x55aa -check_r3 0xffffaa55 - -test_name ORHI_6 -load r3 0xaa55aa55 -orhi r3, r3, 0x55aa -check_r3 0xffffaa55 - -end diff --git a/tests/tcg/lm32/test_ori.S b/tests/tcg/lm32/test_ori.S deleted file mode 100644 index 3d576cdb8b..0000000000 --- a/tests/tcg/lm32/test_ori.S +++ /dev/null @@ -1,35 +0,0 @@ -.include "macros.inc" - -start - -test_name ORI_1 -mvi r1, 0 -ori r3, r1, 0 -check_r3 0 - -test_name ORI_2 -mvi r1, 0 -ori r3, r1, 1 -check_r3 1 - -test_name ORI_3 -mvi r1, 1 -ori r3, r1, 1 -check_r3 1 - -test_name ORI_4 -mvi r1, 1 -ori r3, r1, 0 -check_r3 1 - -test_name ORI_5 -load r1 0xaa55aa55 -ori r3, r1, 0x55aa -check_r3 0xaa55ffff - -test_name ORI_6 -load r3 0xaa55aa55 -ori r3, r3, 0x55aa -check_r3 0xaa55ffff - -end diff --git a/tests/tcg/lm32/test_ret.S b/tests/tcg/lm32/test_ret.S deleted file mode 100644 index 320264f148..0000000000 --- a/tests/tcg/lm32/test_ret.S +++ /dev/null @@ -1,14 +0,0 @@ -.include "macros.inc" - -start - -test_name RET_1 -load ra mark -ret - -tc_fail -end - -mark: -tc_pass -end diff --git a/tests/tcg/lm32/test_sb.S b/tests/tcg/lm32/test_sb.S deleted file mode 100644 index b15a89d342..0000000000 --- a/tests/tcg/lm32/test_sb.S +++ /dev/null @@ -1,32 +0,0 @@ -.include "macros.inc" - -start - -test_name SB_1 -load r1 data -load r2 0xf0f1f2aa -sb (r1+0), r2 -check_mem data 0xaa000000 - -test_name SB_2 -load r1 data -load r2 0xf0f1f2bb -sb (r1+1), r2 -check_mem data 0xaabb0000 - -test_name SB_3 -load r1 data -load r2 0xf0f1f2cc -sb (r1+-1), r2 -check_mem data0 0x000000cc - -end - -.data - .align 4 -data0: - .byte 0, 0, 0, 0 -data: - .byte 0, 0, 0, 0 -data1: - .byte 0, 0, 0, 0 diff --git a/tests/tcg/lm32/test_scall.S b/tests/tcg/lm32/test_scall.S deleted file mode 100644 index 46032f841d..0000000000 --- a/tests/tcg/lm32/test_scall.S +++ /dev/null @@ -1,24 +0,0 @@ -.include "macros.inc" - -start - -test_name SCALL_1 -mvi r1, 1 -wcsr IE, r1 -# we are running in a semi hosted environment -# therefore we have to set r8 to some unused system -# call -mvi r8, 0 -insn: -scall -check_excp 64 - -test_name SCALL_2 -mv r3, ea -check_r3 insn - -test_name SCALL_3 -rcsr r3, IE -check_r3 2 - -end diff --git a/tests/tcg/lm32/test_sextb.S b/tests/tcg/lm32/test_sextb.S deleted file mode 100644 index 58db8ee8b9..0000000000 --- a/tests/tcg/lm32/test_sextb.S +++ /dev/null @@ -1,20 +0,0 @@ -.include "macros.inc" - -start - -test_name SEXTB_1 -mvi r1, 0 -sextb r3, r1 -check_r3 0 - -test_name SEXTB_2 -mvi r1, 0x7f -sextb r3, r1 -check_r3 0x0000007f - -test_name SEXTB_3 -mvi r1, 0x80 -sextb r3, r1 -check_r3 0xffffff80 - -end diff --git a/tests/tcg/lm32/test_sexth.S b/tests/tcg/lm32/test_sexth.S deleted file mode 100644 index a059ec3ee6..0000000000 --- a/tests/tcg/lm32/test_sexth.S +++ /dev/null @@ -1,20 +0,0 @@ -.include "macros.inc" - -start - -test_name SEXTH_1 -mvi r1, 0 -sexth r3, r1 -check_r3 0 - -test_name SEXTH_2 -load r1 0x7fff -sexth r3, r1 -check_r3 0x00007fff - -test_name SEXTH_3 -load r1 0x8000 -sexth r3, r1 -check_r3 0xffff8000 - -end diff --git a/tests/tcg/lm32/test_sh.S b/tests/tcg/lm32/test_sh.S deleted file mode 100644 index bba10224f6..0000000000 --- a/tests/tcg/lm32/test_sh.S +++ /dev/null @@ -1,32 +0,0 @@ -.include "macros.inc" - -start - -test_name SH_1 -load r1 data -load r2 0xf0f1aaaa -sh (r1+0), r2 -check_mem data 0xaaaa0000 - -test_name SH_2 -load r1 data -load r2 0xf0f1bbbb -sh (r1+2), r2 -check_mem data 0xaaaabbbb - -test_name SH_3 -load r1 data -load r2 0xf0f1cccc -sh (r1+-2), r2 -check_mem data0 0x0000cccc - -end - -.data - .align 4 -data0: - .byte 0, 0, 0, 0 -data: - .byte 0, 0, 0, 0 -data1: - .byte 0, 0, 0, 0 diff --git a/tests/tcg/lm32/test_sl.S b/tests/tcg/lm32/test_sl.S deleted file mode 100644 index 0aee17fdb8..0000000000 --- a/tests/tcg/lm32/test_sl.S +++ /dev/null @@ -1,45 +0,0 @@ -.include "macros.inc" - -start - -test_name SL_1 -mvi r1, 1 -mvi r2, 0 -sl r3, r1, r2 -check_r3 1 - -test_name SL_2 -mvi r1, 0 -mvi r2, 1 -sl r3, r1, r2 -check_r3 0 - -test_name SL_3 -mvi r1, 1 -mvi r2, 31 -sl r3, r1, r2 -check_r3 0x80000000 - -test_name SL_4 -mvi r1, 16 -mvi r2, 31 -sl r3, r1, r2 -check_r3 0 - -test_name SL_5 -mvi r1, 1 -mvi r2, 34 -sl r3, r1, r2 -check_r3 4 - -test_name SL_6 -mvi r1, 2 -sl r3, r1, r1 -check_r3 8 - -test_name SL_7 -mvi r3, 2 -sl r3, r3, r3 -check_r3 8 - -end diff --git a/tests/tcg/lm32/test_sli.S b/tests/tcg/lm32/test_sli.S deleted file mode 100644 index a421de9014..0000000000 --- a/tests/tcg/lm32/test_sli.S +++ /dev/null @@ -1,30 +0,0 @@ -.include "macros.inc" - -start - -test_name SLI_1 -mvi r1, 1 -sli r3, r1, 0 -check_r3 1 - -test_name SLI_2 -mvi r1, 0 -sli r3, r1, 1 -check_r3 0 - -test_name SLI_3 -mvi r1, 1 -sli r3, r1, 31 -check_r3 0x80000000 - -test_name SLI_4 -mvi r1, 16 -sli r3, r1, 31 -check_r3 0 - -test_name SLI_7 -mvi r3, 2 -sli r3, r3, 2 -check_r3 8 - -end diff --git a/tests/tcg/lm32/test_sr.S b/tests/tcg/lm32/test_sr.S deleted file mode 100644 index 62431a9864..0000000000 --- a/tests/tcg/lm32/test_sr.S +++ /dev/null @@ -1,57 +0,0 @@ -.include "macros.inc" - -start - -test_name SR_1 -mvi r1, 1 -mvi r2, 0 -sr r3, r1, r2 -check_r3 1 - -test_name SR_2 -mvi r1, 0 -mvi r2, 1 -sr r3, r1, r2 -check_r3 0 - -test_name SR_3 -load r1 0x40000000 -mvi r2, 30 -sr r3, r1, r2 -check_r3 1 - -test_name SR_4 -load r1 0x40000000 -mvi r2, 31 -sr r3, r1, r2 -check_r3 0 - -test_name SR_5 -mvi r1, 16 -mvi r2, 34 -sr r3, r1, r2 -check_r3 4 - -test_name SR_6 -mvi r1, 2 -sr r3, r1, r1 -check_r3 0 - -test_name SR_7 -mvi r3, 2 -sr r3, r3, r3 -check_r3 0 - -test_name SR_8 -mvi r1, 0xfffffff0 -mvi r2, 2 -sr r3, r1, r2 -check_r3 0xfffffffc - -test_name SR_9 -mvi r1, 0xfffffff0 -mvi r2, 4 -sr r3, r1, r2 -check_r3 0xffffffff - -end diff --git a/tests/tcg/lm32/test_sri.S b/tests/tcg/lm32/test_sri.S deleted file mode 100644 index c1be907b5b..0000000000 --- a/tests/tcg/lm32/test_sri.S +++ /dev/null @@ -1,40 +0,0 @@ -.include "macros.inc" - -start - -test_name SRI_1 -mvi r1, 1 -sri r3, r1, 0 -check_r3 1 - -test_name SRI_2 -mvi r1, 0 -sri r3, r1, 1 -check_r3 0 - -test_name SRI_3 -load r1 0x40000000 -sri r3, r1, 30 -check_r3 1 - -test_name SRI_4 -load r1 0x40000000 -sri r3, r1, 31 -check_r3 0 - -test_name SRI_5 -mvi r3, 2 -sri r3, r3, 2 -check_r3 0 - -test_name SRI_6 -mvi r1, 0xfffffff0 -sri r3, r1, 2 -check_r3 0xfffffffc - -test_name SRI_7 -mvi r1, 0xfffffff0 -sri r3, r1, 4 -check_r3 0xffffffff - -end diff --git a/tests/tcg/lm32/test_sru.S b/tests/tcg/lm32/test_sru.S deleted file mode 100644 index 2ab0b54c77..0000000000 --- a/tests/tcg/lm32/test_sru.S +++ /dev/null @@ -1,57 +0,0 @@ -.include "macros.inc" - -start - -test_name SRU_1 -mvi r1, 1 -mvi r2, 0 -sru r3, r1, r2 -check_r3 1 - -test_name SRU_2 -mvi r1, 0 -mvi r2, 1 -sru r3, r1, r2 -check_r3 0 - -test_name SRU_3 -load r1 0x40000000 -mvi r2, 30 -sru r3, r1, r2 -check_r3 1 - -test_name SRU_4 -load r1 0x40000000 -mvi r2, 31 -sru r3, r1, r2 -check_r3 0 - -test_name SRU_5 -mvi r1, 16 -mvi r2, 34 -sru r3, r1, r2 -check_r3 4 - -test_name SRU_6 -mvi r1, 2 -sru r3, r1, r1 -check_r3 0 - -test_name SRU_7 -mvi r3, 2 -sru r3, r3, r3 -check_r3 0 - -test_name SRU_8 -mvi r1, 0xfffffff0 -mvi r2, 2 -sru r3, r1, r2 -check_r3 0x3ffffffc - -test_name SRU_9 -mvi r1, 0xfffffff0 -mvi r2, 4 -sru r3, r1, r2 -check_r3 0x0fffffff - -end diff --git a/tests/tcg/lm32/test_srui.S b/tests/tcg/lm32/test_srui.S deleted file mode 100644 index 872c374121..0000000000 --- a/tests/tcg/lm32/test_srui.S +++ /dev/null @@ -1,40 +0,0 @@ -.include "macros.inc" - -start - -test_name SRUI_1 -mvi r1, 1 -srui r3, r1, 0 -check_r3 1 - -test_name SRUI_2 -mvi r1, 0 -srui r3, r1, 1 -check_r3 0 - -test_name SRUI_3 -load r1 0x40000000 -srui r3, r1, 30 -check_r3 1 - -test_name SRUI_4 -load r1 0x40000000 -srui r3, r1, 31 -check_r3 0 - -test_name SRUI_5 -mvi r3, 2 -srui r3, r3, 2 -check_r3 0 - -test_name SRUI_6 -mvi r1, 0xfffffff0 -srui r3, r1, 2 -check_r3 0x3ffffffc - -test_name SRUI_7 -mvi r1, 0xfffffff0 -srui r3, r1, 4 -check_r3 0x0fffffff - -end diff --git a/tests/tcg/lm32/test_sub.S b/tests/tcg/lm32/test_sub.S deleted file mode 100644 index 44b74a9e10..0000000000 --- a/tests/tcg/lm32/test_sub.S +++ /dev/null @@ -1,75 +0,0 @@ -.include "macros.inc" - -start - -test_name SUB_1 -mvi r1, 0 -mvi r2, 0 -sub r3, r1, r2 -check_r3 0 - -test_name SUB_2 -mvi r1, 0 -mvi r2, 1 -sub r3, r1, r2 -check_r3 -1 - -test_name SUB_3 -mvi r1, 1 -mvi r2, 0 -sub r3, r1, r2 -check_r3 1 - -test_name SUB_4 -mvi r1, 1 -mvi r2, -1 -sub r3, r1, r2 -check_r3 2 - -test_name SUB_5 -mvi r1, -1 -mvi r2, 1 -sub r3, r1, r2 -check_r3 -2 - -test_name SUB_6 -mvi r1, -1 -mvi r2, 0 -sub r3, r1, r2 -check_r3 -1 - -test_name SUB_7 -mvi r1, 0 -mvi r2, -1 -sub r3, r1, r2 -check_r3 1 - -test_name SUB_8 -mvi r3, 2 -sub r3, r3, r3 -check_r3 0 - -test_name SUB_9 -mvi r1, 4 -mvi r3, 2 -sub r3, r1, r3 -check_r3 2 - -test_name SUB_10 -mvi r1, 4 -mvi r3, 2 -sub r3, r3, r1 -check_r3 -2 - -test_name SUB_11 -mvi r1, 4 -sub r3, r1, r1 -check_r3 0 - -test_name SUB_12 -load r1 0x12345678 -load r2 0xabcdef97 -sub r3, r1, r2 -check_r3 0x666666e1 - -end diff --git a/tests/tcg/lm32/test_sw.S b/tests/tcg/lm32/test_sw.S deleted file mode 100644 index 2b1c017e7b..0000000000 --- a/tests/tcg/lm32/test_sw.S +++ /dev/null @@ -1,38 +0,0 @@ -.include "macros.inc" - -start - -test_name SW_1 -load r1 data -load r2 0xaabbccdd -sw (r1+0), r2 -check_mem data 0xaabbccdd - -test_name SW_2 -load r1 data -load r2 0x00112233 -sw (r1+4), r2 -check_mem data1 0x00112233 - -test_name SW_3 -load r1 data -load r2 0x44556677 -sw (r1+-4), r2 -check_mem data0 0x44556677 - -test_name SW_4 -load r1 data -sw (r1+0), r1 -lw r3, (r1+0) -check_r3 data - -end - -.data - .align 4 -data0: - .byte 0, 0, 0, 0 -data: - .byte 0, 0, 0, 0 -data1: - .byte 0, 0, 0, 0 diff --git a/tests/tcg/lm32/test_xnor.S b/tests/tcg/lm32/test_xnor.S deleted file mode 100644 index 14a62075f6..0000000000 --- a/tests/tcg/lm32/test_xnor.S +++ /dev/null @@ -1,51 +0,0 @@ -.include "macros.inc" - -start - -test_name XNOR_1 -mvi r1, 0 -mvi r2, 0 -xnor r3, r1, r2 -check_r3 0xffffffff - -test_name XNOR_2 -mvi r1, 0 -mvi r2, 1 -xnor r3, r1, r2 -check_r3 0xfffffffe - -test_name XNOR_3 -mvi r1, 1 -mvi r2, 1 -xnor r3, r1, r2 -check_r3 0xffffffff - -test_name XNOR_4 -mvi r1, 1 -mvi r2, 0 -xnor r3, r1, r2 -check_r3 0xfffffffe - -test_name XNOR_5 -load r1 0xaa55aa55 -load r2 0x55aa55aa -xnor r3, r1, r2 -check_r3 0 - -test_name XNOR_6 -load r1 0xaa550000 -load r2 0x0000aa55 -xnor r3, r1, r2 -check_r3 0x55aa55aa - -test_name XNOR_7 -load r1 0xaa55aa55 -xnor r3, r1, r1 -check_r3 0xffffffff - -test_name XNOR_8 -load r3 0xaa55aa55 -xnor r3, r3, r3 -check_r3 0xffffffff - -end diff --git a/tests/tcg/lm32/test_xnori.S b/tests/tcg/lm32/test_xnori.S deleted file mode 100644 index 9d9c3c6780..0000000000 --- a/tests/tcg/lm32/test_xnori.S +++ /dev/null @@ -1,35 +0,0 @@ -.include "macros.inc" - -start - -test_name XNORI_1 -mvi r1, 0 -xnori r3, r1, 0 -check_r3 0xffffffff - -test_name XNORI_2 -mvi r1, 0 -xnori r3, r1, 1 -check_r3 0xfffffffe - -test_name XNORI_3 -mvi r1, 1 -xnori r3, r1, 1 -check_r3 0xffffffff - -test_name XNORI_4 -mvi r1, 1 -xnori r3, r1, 0 -check_r3 0xfffffffe - -test_name XNORI_5 -load r1 0xaa55aa55 -xnori r3, r1, 0x5555 -check_r3 0x55aa00ff - -test_name XNORI_6 -load r3 0xaa55aa55 -xnori r3, r3, 0x5555 -check_r3 0x55aa00ff - -end diff --git a/tests/tcg/lm32/test_xor.S b/tests/tcg/lm32/test_xor.S deleted file mode 100644 index 6c6e712bae..0000000000 --- a/tests/tcg/lm32/test_xor.S +++ /dev/null @@ -1,51 +0,0 @@ -.include "macros.inc" - -start - -test_name XOR_1 -mvi r1, 0 -mvi r2, 0 -xor r3, r1, r2 -check_r3 0 - -test_name XOR_2 -mvi r1, 0 -mvi r2, 1 -xor r3, r1, r2 -check_r3 1 - -test_name XOR_3 -mvi r1, 1 -mvi r2, 1 -xor r3, r1, r2 -check_r3 0 - -test_name XOR_4 -mvi r1, 1 -mvi r2, 0 -xor r3, r1, r2 -check_r3 1 - -test_name XOR_5 -load r1 0xaa55aa55 -load r2 0x55aa55aa -xor r3, r1, r2 -check_r3 0xffffffff - -test_name XOR_6 -load r1 0xaa550000 -load r2 0x0000aa55 -xor r3, r1, r2 -check_r3 0xaa55aa55 - -test_name XOR_7 -load r1 0xaa55aa55 -xor r3, r1, r1 -check_r3 0 - -test_name XOR_8 -load r3 0xaa55aa55 -xor r3, r3, r3 -check_r3 0 - -end diff --git a/tests/tcg/lm32/test_xori.S b/tests/tcg/lm32/test_xori.S deleted file mode 100644 index 2051699f12..0000000000 --- a/tests/tcg/lm32/test_xori.S +++ /dev/null @@ -1,35 +0,0 @@ -.include "macros.inc" - -start - -test_name XORI_1 -mvi r1, 0 -xori r3, r1, 0 -check_r3 0 - -test_name XORI_2 -mvi r1, 0 -xori r3, r1, 1 -check_r3 1 - -test_name XORI_3 -mvi r1, 1 -xori r3, r1, 1 -check_r3 0 - -test_name XORI_4 -mvi r1, 1 -xori r3, r1, 0 -check_r3 1 - -test_name XORI_5 -load r1 0xaa55aa55 -xori r3, r1, 0x5555 -check_r3 0xaa55ff00 - -test_name XORI_6 -load r3 0xaa55aa55 -xori r3, r3, 0x5555 -check_r3 0xaa55ff00 - -end From 4369223902a79b7fc56ca076d99b88ff14964ddd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 3 May 2021 10:40:34 +0200 Subject: [PATCH 0492/3028] Drop the deprecated unicore32 target Target unicore32 was deprecated in commit 8e4ff4a8d2b, v5.2.0. See there for rationale. Cc: Guan Xuetao Signed-off-by: Markus Armbruster Message-Id: <20210503084034.3804963-3-armbru@redhat.com> Acked-by: Thomas Huth --- .gitlab-ci.yml | 2 +- MAINTAINERS | 15 - configure | 2 +- default-configs/devices/unicore32-softmmu.mak | 6 - default-configs/targets/unicore32-softmmu.mak | 1 - docs/system/deprecated.rst | 8 - docs/system/removed-features.rst | 7 + fpu/softfloat-specialize.c.inc | 11 +- hw/Kconfig | 1 - hw/dma/meson.build | 1 - hw/dma/puv3_dma.c | 119 - hw/gpio/meson.build | 1 - hw/gpio/puv3_gpio.c | 154 -- hw/intc/meson.build | 1 - hw/intc/puv3_intc.c | 147 -- hw/meson.build | 1 - hw/misc/meson.build | 3 - hw/misc/puv3_pm.c | 159 -- hw/timer/meson.build | 1 - hw/timer/puv3_ost.c | 166 -- hw/unicore32/Kconfig | 5 - hw/unicore32/meson.build | 5 - hw/unicore32/puv3.c | 145 -- include/elf.h | 3 +- include/exec/poison.h | 1 - include/hw/unicore32/puv3.h | 40 - include/sysemu/arch_init.h | 1 - qapi/machine.json | 2 +- softmmu/arch_init.c | 2 - target/meson.build | 1 - target/unicore32/cpu-param.h | 17 - target/unicore32/cpu-qom.h | 37 - target/unicore32/cpu.c | 174 -- target/unicore32/cpu.h | 168 -- target/unicore32/helper.c | 183 -- target/unicore32/helper.h | 62 - target/unicore32/meson.build | 14 - target/unicore32/op_helper.c | 244 -- target/unicore32/softmmu.c | 280 --- target/unicore32/translate.c | 2083 ----------------- target/unicore32/ucf64_helper.c | 324 --- tests/qtest/machine-none-test.c | 1 - 42 files changed, 16 insertions(+), 4582 deletions(-) delete mode 100644 default-configs/devices/unicore32-softmmu.mak delete mode 100644 default-configs/targets/unicore32-softmmu.mak delete mode 100644 hw/dma/puv3_dma.c delete mode 100644 hw/gpio/puv3_gpio.c delete mode 100644 hw/intc/puv3_intc.c delete mode 100644 hw/misc/puv3_pm.c delete mode 100644 hw/timer/puv3_ost.c delete mode 100644 hw/unicore32/Kconfig delete mode 100644 hw/unicore32/meson.build delete mode 100644 hw/unicore32/puv3.c delete mode 100644 include/hw/unicore32/puv3.h delete mode 100644 target/unicore32/cpu-param.h delete mode 100644 target/unicore32/cpu-qom.h delete mode 100644 target/unicore32/cpu.c delete mode 100644 target/unicore32/cpu.h delete mode 100644 target/unicore32/helper.c delete mode 100644 target/unicore32/helper.h delete mode 100644 target/unicore32/meson.build delete mode 100644 target/unicore32/op_helper.c delete mode 100644 target/unicore32/softmmu.c delete mode 100644 target/unicore32/translate.c delete mode 100644 target/unicore32/ucf64_helper.c diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e0d941b779..9876f73040 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -624,7 +624,7 @@ build-deprecated: IMAGE: debian-all-test-cross CONFIGURE_ARGS: --disable-tools MAKE_CHECK_ARGS: build-tcg - TARGETS: ppc64abi32-linux-user unicore32-softmmu + TARGETS: ppc64abi32-linux-user artifacts: expire_in: 2 days paths: diff --git a/MAINTAINERS b/MAINTAINERS index 96855fbc73..607648b56c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -318,13 +318,6 @@ F: hw/sparc64/ F: include/hw/sparc/sparc64.h F: disas/sparc.c -UniCore32 TCG CPUs -M: Guan Xuetao -S: Maintained -F: target/unicore32/ -F: hw/unicore32/ -F: include/hw/unicore32/ - X86 TCG CPUs M: Paolo Bonzini M: Richard Henderson @@ -1508,14 +1501,6 @@ F: hw/s390x/s390-pci* F: include/hw/s390x/s390-pci* L: qemu-s390x@nongnu.org -UniCore32 Machines ------------------- -PKUnity-3 SoC initramfs-with-busybox -M: Guan Xuetao -S: Maintained -F: hw/*/puv3* -F: hw/unicore32/ - X86 Machines ------------ PC diff --git a/configure b/configure index cae212988c..cc703b3e8d 100755 --- a/configure +++ b/configure @@ -1663,7 +1663,7 @@ if [ "$ARCH" = "unknown" ]; then fi default_target_list="" -deprecated_targets_list=ppc64abi32-linux-user,unicore32-softmmu +deprecated_targets_list=ppc64abi32-linux-user deprecated_features="" mak_wilds="" diff --git a/default-configs/devices/unicore32-softmmu.mak b/default-configs/devices/unicore32-softmmu.mak deleted file mode 100644 index 899288e3d7..0000000000 --- a/default-configs/devices/unicore32-softmmu.mak +++ /dev/null @@ -1,6 +0,0 @@ -# Default configuration for unicore32-softmmu - -# Boards: -# -CONFIG_PUV3=y -CONFIG_SEMIHOSTING=y diff --git a/default-configs/targets/unicore32-softmmu.mak b/default-configs/targets/unicore32-softmmu.mak deleted file mode 100644 index 57331e94fe..0000000000 --- a/default-configs/targets/unicore32-softmmu.mak +++ /dev/null @@ -1 +0,0 @@ -TARGET_ARCH=unicore32 diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst index 1199fe93c0..abbf8243a3 100644 --- a/docs/system/deprecated.rst +++ b/docs/system/deprecated.rst @@ -198,14 +198,6 @@ from Linux upstream kernel, declare it deprecated. System emulator CPUS -------------------- -``unicore32`` CPUs (since 5.2.0) -'''''''''''''''''''''''''''''''' - -The ``unicore32`` guest CPU support is deprecated and will be removed in -a future version of QEMU. Support for this CPU was removed from the -upstream Linux kernel, and there is no available upstream toolchain -to build binaries for it. - ``Icelake-Client`` CPU Model (since 5.2.0) '''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst index 4915bc3f63..5a462ac568 100644 --- a/docs/system/removed-features.rst +++ b/docs/system/removed-features.rst @@ -305,6 +305,13 @@ The only public user of this architecture was the milkymist project, which has been dead for years; there was never an upstream Linux port. Removed without replacement. +``unicore32`` CPUs (since 6.1.0) +'''''''''''''''''''''''''''''''' + +Support for this CPU was removed from the upstream Linux kernel, and +there is no available upstream toolchain to build binaries for it. +Removed without replacement. + System emulator machines ------------------------ diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 9b4cbf4f98..3f01e1b8c5 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -103,7 +103,7 @@ static inline bool snan_bit_is_one(float_status *status) { #if defined(TARGET_MIPS) return status->snan_bit_is_one; -#elif defined(TARGET_HPPA) || defined(TARGET_UNICORE32) || defined(TARGET_SH4) +#elif defined(TARGET_HPPA) || defined(TARGET_SH4) return 1; #else return 0; @@ -149,11 +149,10 @@ static FloatParts parts_default_nan(float_status *status) sign = 1; frac = ~0ULL; #else - /* This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V, - * S390, SH4, TriCore, and Xtensa. I cannot find documentation - * for Unicore32; the choice from the original commit is unchanged. - * Our other supported targets, CRIS, Nios2, and Tile, - * do not have floating-point. + /* + * This case is true for Alpha, ARM, MIPS, OpenRISC, PPC, RISC-V, + * S390, SH4, TriCore, and Xtensa. Our other supported targets, + * CRIS, Nios2, and Tile, do not have floating-point. */ if (snan_bit_is_one(status)) { /* set all bits other than msb */ diff --git a/hw/Kconfig b/hw/Kconfig index 10a48d1492..aa10357adf 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -60,7 +60,6 @@ source sh4/Kconfig source sparc/Kconfig source sparc64/Kconfig source tricore/Kconfig -source unicore32/Kconfig source xtensa/Kconfig # Symbols used by multiple targets diff --git a/hw/dma/meson.build b/hw/dma/meson.build index 5c78a4e05f..f3f0661bc3 100644 --- a/hw/dma/meson.build +++ b/hw/dma/meson.build @@ -1,4 +1,3 @@ -softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_dma.c')) softmmu_ss.add(when: 'CONFIG_RC4030', if_true: files('rc4030.c')) softmmu_ss.add(when: 'CONFIG_PL080', if_true: files('pl080.c')) softmmu_ss.add(when: 'CONFIG_PL330', if_true: files('pl330.c')) diff --git a/hw/dma/puv3_dma.c b/hw/dma/puv3_dma.c deleted file mode 100644 index cca1e9ec21..0000000000 --- a/hw/dma/puv3_dma.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * DMA device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qom/object.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" -#include "qemu/module.h" -#include "qemu/log.h" - -#define PUV3_DMA_CH_NR (6) -#define PUV3_DMA_CH_MASK (0xff) -#define PUV3_DMA_CH(offset) ((offset) >> 8) - -#define TYPE_PUV3_DMA "puv3_dma" -OBJECT_DECLARE_SIMPLE_TYPE(PUV3DMAState, PUV3_DMA) - -struct PUV3DMAState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t reg_CFG[PUV3_DMA_CH_NR]; -}; - -static uint64_t puv3_dma_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3DMAState *s = opaque; - uint32_t ret = 0; - - assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR); - - switch (offset & PUV3_DMA_CH_MASK) { - case 0x10: - ret = s->reg_CFG[PUV3_DMA_CH(offset)]; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad read offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - - return ret; -} - -static void puv3_dma_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PUV3DMAState *s = opaque; - - assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR); - - switch (offset & PUV3_DMA_CH_MASK) { - case 0x10: - s->reg_CFG[PUV3_DMA_CH(offset)] = value; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad write offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, value); -} - -static const MemoryRegionOps puv3_dma_ops = { - .read = puv3_dma_read, - .write = puv3_dma_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_dma_realize(DeviceState *dev, Error **errp) -{ - PUV3DMAState *s = PUV3_DMA(dev); - int i; - - for (i = 0; i < PUV3_DMA_CH_NR; i++) { - s->reg_CFG[i] = 0x0; - } - - memory_region_init_io(&s->iomem, OBJECT(s), &puv3_dma_ops, s, "puv3_dma", - PUV3_REGS_OFFSET); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); -} - -static void puv3_dma_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = puv3_dma_realize; -} - -static const TypeInfo puv3_dma_info = { - .name = TYPE_PUV3_DMA, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3DMAState), - .class_init = puv3_dma_class_init, -}; - -static void puv3_dma_register_type(void) -{ - type_register_static(&puv3_dma_info); -} - -type_init(puv3_dma_register_type) diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build index 79568f00ce..7bd6a57264 100644 --- a/hw/gpio/meson.build +++ b/hw/gpio/meson.build @@ -3,7 +3,6 @@ softmmu_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c')) softmmu_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c')) softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c')) softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c')) -softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_gpio.c')) softmmu_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c')) softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c')) diff --git a/hw/gpio/puv3_gpio.c b/hw/gpio/puv3_gpio.c deleted file mode 100644 index e003ae505c..0000000000 --- a/hw/gpio/puv3_gpio.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * GPIO device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qom/object.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" -#include "qemu/module.h" -#include "qemu/log.h" - -#define TYPE_PUV3_GPIO "puv3_gpio" -OBJECT_DECLARE_SIMPLE_TYPE(PUV3GPIOState, PUV3_GPIO) - -struct PUV3GPIOState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq[9]; - - uint32_t reg_GPLR; - uint32_t reg_GPDR; - uint32_t reg_GPIR; -}; - -static uint64_t puv3_gpio_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3GPIOState *s = opaque; - uint32_t ret = 0; - - switch (offset) { - case 0x00: - ret = s->reg_GPLR; - break; - case 0x04: - ret = s->reg_GPDR; - break; - case 0x20: - ret = s->reg_GPIR; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad read offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - - return ret; -} - -static void puv3_gpio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PUV3GPIOState *s = opaque; - - DPRINTF("offset 0x%x, value 0x%x\n", offset, value); - switch (offset) { - case 0x04: - s->reg_GPDR = value; - break; - case 0x08: - if (s->reg_GPDR & value) { - s->reg_GPLR |= value; - } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Write gpio input port\n", - __func__); - } - break; - case 0x0c: - if (s->reg_GPDR & value) { - s->reg_GPLR &= ~value; - } else { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Write gpio input port\n", - __func__); - } - break; - case 0x10: /* GRER */ - case 0x14: /* GFER */ - case 0x18: /* GEDR */ - break; - case 0x20: /* GPIR */ - s->reg_GPIR = value; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad write offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } -} - -static const MemoryRegionOps puv3_gpio_ops = { - .read = puv3_gpio_read, - .write = puv3_gpio_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_gpio_realize(DeviceState *dev, Error **errp) -{ - PUV3GPIOState *s = PUV3_GPIO(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - s->reg_GPLR = 0; - s->reg_GPDR = 0; - - /* FIXME: these irqs not handled yet */ - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW0]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW1]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW2]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW3]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW4]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW5]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW6]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOLOW7]); - sysbus_init_irq(sbd, &s->irq[PUV3_IRQS_GPIOHIGH]); - - memory_region_init_io(&s->iomem, OBJECT(s), &puv3_gpio_ops, s, "puv3_gpio", - PUV3_REGS_OFFSET); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void puv3_gpio_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = puv3_gpio_realize; -} - -static const TypeInfo puv3_gpio_info = { - .name = TYPE_PUV3_GPIO, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3GPIOState), - .class_init = puv3_gpio_class_init, -}; - -static void puv3_gpio_register_type(void) -{ - type_register_static(&puv3_gpio_info); -} - -type_init(puv3_gpio_register_type) diff --git a/hw/intc/meson.build b/hw/intc/meson.build index cc7a140f3f..6e52a166e3 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -16,7 +16,6 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_avic.c', 'imx_gpcv2.c')) softmmu_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic_common.c')) softmmu_ss.add(when: 'CONFIG_OPENPIC', if_true: files('openpic.c')) softmmu_ss.add(when: 'CONFIG_PL190', if_true: files('pl190.c')) -softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_intc.c')) softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview_gic.c')) softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_intctl.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_intc.c')) diff --git a/hw/intc/puv3_intc.c b/hw/intc/puv3_intc.c deleted file mode 100644 index 65226f5e7c..0000000000 --- a/hw/intc/puv3_intc.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * INTC device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/irq.h" -#include "hw/sysbus.h" -#include "qom/object.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" -#include "qemu/module.h" -#include "qemu/log.h" - -#define TYPE_PUV3_INTC "puv3_intc" -OBJECT_DECLARE_SIMPLE_TYPE(PUV3INTCState, PUV3_INTC) - -struct PUV3INTCState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq parent_irq; - - uint32_t reg_ICMR; - uint32_t reg_ICPR; -}; - -/* Update interrupt status after enabled or pending bits have been changed. */ -static void puv3_intc_update(PUV3INTCState *s) -{ - if (s->reg_ICMR & s->reg_ICPR) { - qemu_irq_raise(s->parent_irq); - } else { - qemu_irq_lower(s->parent_irq); - } -} - -/* Process a change in an external INTC input. */ -static void puv3_intc_handler(void *opaque, int irq, int level) -{ - PUV3INTCState *s = opaque; - - DPRINTF("irq 0x%x, level 0x%x\n", irq, level); - if (level) { - s->reg_ICPR |= (1 << irq); - } else { - s->reg_ICPR &= ~(1 << irq); - } - puv3_intc_update(s); -} - -static uint64_t puv3_intc_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3INTCState *s = opaque; - uint32_t ret = 0; - - switch (offset) { - case 0x04: /* INTC_ICMR */ - ret = s->reg_ICMR; - break; - case 0x0c: /* INTC_ICIP */ - ret = s->reg_ICPR; /* the same value with ICPR */ - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad read offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - return ret; -} - -static void puv3_intc_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PUV3INTCState *s = opaque; - - DPRINTF("offset 0x%x, value 0x%x\n", offset, value); - switch (offset) { - case 0x00: /* INTC_ICLR */ - case 0x14: /* INTC_ICCR */ - break; - case 0x04: /* INTC_ICMR */ - s->reg_ICMR = value; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad write offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - return; - } - puv3_intc_update(s); -} - -static const MemoryRegionOps puv3_intc_ops = { - .read = puv3_intc_read, - .write = puv3_intc_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_intc_realize(DeviceState *dev, Error **errp) -{ - PUV3INTCState *s = PUV3_INTC(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - qdev_init_gpio_in(dev, puv3_intc_handler, PUV3_IRQS_NR); - sysbus_init_irq(sbd, &s->parent_irq); - - s->reg_ICMR = 0; - s->reg_ICPR = 0; - - memory_region_init_io(&s->iomem, OBJECT(s), &puv3_intc_ops, s, "puv3_intc", - PUV3_REGS_OFFSET); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void puv3_intc_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - dc->realize = puv3_intc_realize; -} - -static const TypeInfo puv3_intc_info = { - .name = TYPE_PUV3_INTC, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3INTCState), - .class_init = puv3_intc_class_init, -}; - -static void puv3_intc_register_type(void) -{ - type_register_static(&puv3_intc_info); -} - -type_init(puv3_intc_register_type) diff --git a/hw/meson.build b/hw/meson.build index 56ce810c4b..6bdbae0e81 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -61,5 +61,4 @@ subdir('sh4') subdir('sparc') subdir('sparc64') subdir('tricore') -subdir('unicore32') subdir('xtensa') diff --git a/hw/misc/meson.build b/hw/misc/meson.build index f934d79e29..66e1648533 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -36,9 +36,6 @@ softmmu_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c')) softmmu_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c')) -# PKUnity SoC devices -softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_pm.c')) - subdir('macio') softmmu_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c')) diff --git a/hw/misc/puv3_pm.c b/hw/misc/puv3_pm.c deleted file mode 100644 index 676c23f7db..0000000000 --- a/hw/misc/puv3_pm.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Power Management device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qom/object.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" -#include "qemu/module.h" -#include "qemu/log.h" - -#define TYPE_PUV3_PM "puv3_pm" -OBJECT_DECLARE_SIMPLE_TYPE(PUV3PMState, PUV3_PM) - -struct PUV3PMState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - uint32_t reg_PMCR; - uint32_t reg_PCGR; - uint32_t reg_PLL_SYS_CFG; - uint32_t reg_PLL_DDR_CFG; - uint32_t reg_PLL_VGA_CFG; - uint32_t reg_DIVCFG; -}; - -static uint64_t puv3_pm_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3PMState *s = opaque; - uint32_t ret = 0; - - switch (offset) { - case 0x14: - ret = s->reg_PCGR; - break; - case 0x18: - ret = s->reg_PLL_SYS_CFG; - break; - case 0x1c: - ret = s->reg_PLL_DDR_CFG; - break; - case 0x20: - ret = s->reg_PLL_VGA_CFG; - break; - case 0x24: - ret = s->reg_DIVCFG; - break; - case 0x28: /* PLL SYS STATUS */ - ret = 0x00002401; - break; - case 0x2c: /* PLL DDR STATUS */ - ret = 0x00100c00; - break; - case 0x30: /* PLL VGA STATUS */ - ret = 0x00003801; - break; - case 0x34: /* DIV STATUS */ - ret = 0x22f52015; - break; - case 0x38: /* SW RESET */ - ret = 0x0; - break; - case 0x44: /* PLL DFC DONE */ - ret = 0x7; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad read offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - - return ret; -} - -static void puv3_pm_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PUV3PMState *s = opaque; - - switch (offset) { - case 0x0: - s->reg_PMCR = value; - break; - case 0x14: - s->reg_PCGR = value; - break; - case 0x18: - s->reg_PLL_SYS_CFG = value; - break; - case 0x1c: - s->reg_PLL_DDR_CFG = value; - break; - case 0x20: - s->reg_PLL_VGA_CFG = value; - break; - case 0x24: - case 0x38: - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad write offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, value); -} - -static const MemoryRegionOps puv3_pm_ops = { - .read = puv3_pm_read, - .write = puv3_pm_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_pm_realize(DeviceState *dev, Error **errp) -{ - PUV3PMState *s = PUV3_PM(dev); - - s->reg_PCGR = 0x0; - - memory_region_init_io(&s->iomem, OBJECT(s), &puv3_pm_ops, s, "puv3_pm", - PUV3_REGS_OFFSET); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); -} - -static void puv3_pm_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = puv3_pm_realize; -} - -static const TypeInfo puv3_pm_info = { - .name = TYPE_PUV3_PM, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3PMState), - .class_init = puv3_pm_class_init, -}; - -static void puv3_pm_register_type(void) -{ - type_register_static(&puv3_pm_info); -} - -type_init(puv3_pm_register_type) diff --git a/hw/timer/meson.build b/hw/timer/meson.build index f2081d261a..157f540ecd 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -25,7 +25,6 @@ softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_timer.c')) softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_timer.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gptimer.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_synctimer.c')) -softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_ost.c')) softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_timer.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_systmr.c')) softmmu_ss.add(when: 'CONFIG_SH_TIMER', if_true: files('sh_timer.c')) diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c deleted file mode 100644 index d5bf26b56b..0000000000 --- a/hw/timer/puv3_ost.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * OSTimer device simulation in PKUnity SoC - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "hw/irq.h" -#include "hw/ptimer.h" -#include "qemu/module.h" -#include "qemu/log.h" -#include "qom/object.h" - -#undef DEBUG_PUV3 -#include "hw/unicore32/puv3.h" - -#define TYPE_PUV3_OST "puv3_ost" -OBJECT_DECLARE_SIMPLE_TYPE(PUV3OSTState, PUV3_OST) - -/* puv3 ostimer implementation. */ -struct PUV3OSTState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq; - ptimer_state *ptimer; - - uint32_t reg_OSMR0; - uint32_t reg_OSCR; - uint32_t reg_OSSR; - uint32_t reg_OIER; -}; - -static uint64_t puv3_ost_read(void *opaque, hwaddr offset, - unsigned size) -{ - PUV3OSTState *s = opaque; - uint32_t ret = 0; - - switch (offset) { - case 0x10: /* Counter Register */ - ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer); - break; - case 0x14: /* Status Register */ - ret = s->reg_OSSR; - break; - case 0x1c: /* Interrupt Enable Register */ - ret = s->reg_OIER; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad read offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } - DPRINTF("offset 0x%x, value 0x%x\n", offset, ret); - return ret; -} - -static void puv3_ost_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PUV3OSTState *s = opaque; - - DPRINTF("offset 0x%x, value 0x%x\n", offset, value); - switch (offset) { - case 0x00: /* Match Register 0 */ - ptimer_transaction_begin(s->ptimer); - s->reg_OSMR0 = value; - if (s->reg_OSMR0 > s->reg_OSCR) { - ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR); - } else { - ptimer_set_count(s->ptimer, s->reg_OSMR0 + - (0xffffffff - s->reg_OSCR)); - } - ptimer_run(s->ptimer, 2); - ptimer_transaction_commit(s->ptimer); - break; - case 0x14: /* Status Register */ - assert(value == 0); - if (s->reg_OSSR) { - s->reg_OSSR = value; - qemu_irq_lower(s->irq); - } - break; - case 0x1c: /* Interrupt Enable Register */ - s->reg_OIER = value; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad write offset 0x%"HWADDR_PRIx"\n", - __func__, offset); - } -} - -static const MemoryRegionOps puv3_ost_ops = { - .read = puv3_ost_read, - .write = puv3_ost_write, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void puv3_ost_tick(void *opaque) -{ - PUV3OSTState *s = opaque; - - DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n", - s->reg_OSCR, s->reg_OSMR0); - - s->reg_OSCR = s->reg_OSMR0; - if (s->reg_OIER) { - s->reg_OSSR = 1; - qemu_irq_raise(s->irq); - } -} - -static void puv3_ost_realize(DeviceState *dev, Error **errp) -{ - PUV3OSTState *s = PUV3_OST(dev); - SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - - s->reg_OIER = 0; - s->reg_OSSR = 0; - s->reg_OSMR0 = 0; - s->reg_OSCR = 0; - - sysbus_init_irq(sbd, &s->irq); - - s->ptimer = ptimer_init(puv3_ost_tick, s, PTIMER_POLICY_DEFAULT); - ptimer_transaction_begin(s->ptimer); - ptimer_set_freq(s->ptimer, 50 * 1000 * 1000); - ptimer_transaction_commit(s->ptimer); - - memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost", - PUV3_REGS_OFFSET); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void puv3_ost_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = puv3_ost_realize; -} - -static const TypeInfo puv3_ost_info = { - .name = TYPE_PUV3_OST, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PUV3OSTState), - .class_init = puv3_ost_class_init, -}; - -static void puv3_ost_register_type(void) -{ - type_register_static(&puv3_ost_info); -} - -type_init(puv3_ost_register_type) diff --git a/hw/unicore32/Kconfig b/hw/unicore32/Kconfig deleted file mode 100644 index 4443a29dd2..0000000000 --- a/hw/unicore32/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config PUV3 - bool - select ISA_BUS - select PCKBD - select PTIMER diff --git a/hw/unicore32/meson.build b/hw/unicore32/meson.build deleted file mode 100644 index fc26d6bcab..0000000000 --- a/hw/unicore32/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -unicore32_ss = ss.source_set() -# PKUnity-v3 SoC and board information -unicore32_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3.c')) - -hw_arch += {'unicore32': unicore32_ss} diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c deleted file mode 100644 index eacacb4249..0000000000 --- a/hw/unicore32/puv3.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Generic PKUnity SoC machine and board descriptor - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "cpu.h" -#include "ui/console.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "sysemu/qtest.h" -#include "hw/unicore32/puv3.h" -#include "hw/input/i8042.h" -#include "hw/irq.h" - -#define KERNEL_LOAD_ADDR 0x03000000 -#define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */ - -/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */ -#define PUV3_DMA_BASE (0xc0200000) /* AHB-4 */ - -/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */ -#define PUV3_GPIO_BASE (0xee500000) /* APB-5 */ -#define PUV3_INTC_BASE (0xee600000) /* APB-6 */ -#define PUV3_OST_BASE (0xee800000) /* APB-8 */ -#define PUV3_PM_BASE (0xeea00000) /* APB-10 */ -#define PUV3_PS2_BASE (0xeeb00000) /* APB-11 */ - -static void puv3_intc_cpu_handler(void *opaque, int irq, int level) -{ - UniCore32CPU *cpu = opaque; - CPUState *cs = CPU(cpu); - - assert(irq == 0); - if (level) { - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); - } -} - -static void puv3_soc_init(CPUUniCore32State *env) -{ - qemu_irq cpu_intc, irqs[PUV3_IRQS_NR]; - DeviceState *dev; - MemoryRegion *i8042 = g_new(MemoryRegion, 1); - int i; - - /* Initialize interrupt controller */ - cpu_intc = qemu_allocate_irq(puv3_intc_cpu_handler, - env_archcpu(env), 0); - dev = sysbus_create_simple("puv3_intc", PUV3_INTC_BASE, cpu_intc); - for (i = 0; i < PUV3_IRQS_NR; i++) { - irqs[i] = qdev_get_gpio_in(dev, i); - } - - /* Initialize minimal necessary devices for kernel booting */ - sysbus_create_simple("puv3_pm", PUV3_PM_BASE, NULL); - sysbus_create_simple("puv3_dma", PUV3_DMA_BASE, NULL); - sysbus_create_simple("puv3_ost", PUV3_OST_BASE, irqs[PUV3_IRQS_OST0]); - sysbus_create_varargs("puv3_gpio", PUV3_GPIO_BASE, - irqs[PUV3_IRQS_GPIOLOW0], irqs[PUV3_IRQS_GPIOLOW1], - irqs[PUV3_IRQS_GPIOLOW2], irqs[PUV3_IRQS_GPIOLOW3], - irqs[PUV3_IRQS_GPIOLOW4], irqs[PUV3_IRQS_GPIOLOW5], - irqs[PUV3_IRQS_GPIOLOW6], irqs[PUV3_IRQS_GPIOLOW7], - irqs[PUV3_IRQS_GPIOHIGH], NULL); - - /* Keyboard (i8042), mouse disabled for nographic */ - i8042_mm_init(irqs[PUV3_IRQS_PS2_KBD], NULL, i8042, PUV3_REGS_OFFSET, 4); - memory_region_add_subregion(get_system_memory(), PUV3_PS2_BASE, i8042); -} - -static void puv3_board_init(CPUUniCore32State *env, ram_addr_t ram_size) -{ - MemoryRegion *ram_memory = g_new(MemoryRegion, 1); - - /* SDRAM at address zero. */ - memory_region_init_ram(ram_memory, NULL, "puv3.ram", ram_size, - &error_fatal); - memory_region_add_subregion(get_system_memory(), 0, ram_memory); -} - -static const GraphicHwOps no_ops; - -static void puv3_load_kernel(const char *kernel_filename) -{ - int size; - - if (kernel_filename == NULL && qtest_enabled()) { - return; - } - if (kernel_filename == NULL) { - error_report("kernel parameter cannot be empty"); - exit(1); - } - - /* only zImage format supported */ - size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, - KERNEL_MAX_SIZE); - if (size < 0) { - error_report("Load kernel error: '%s'", kernel_filename); - exit(1); - } - - /* cheat curses that we have a graphic console, only under ocd console */ - graphic_console_init(NULL, 0, &no_ops, NULL); -} - -static void puv3_init(MachineState *machine) -{ - ram_addr_t ram_size = machine->ram_size; - const char *kernel_filename = machine->kernel_filename; - const char *initrd_filename = machine->initrd_filename; - CPUUniCore32State *env; - UniCore32CPU *cpu; - - if (initrd_filename) { - error_report("Please use kernel built-in initramdisk"); - exit(1); - } - - cpu = UNICORE32_CPU(cpu_create(machine->cpu_type)); - env = &cpu->env; - - puv3_soc_init(env); - puv3_board_init(env, ram_size); - puv3_load_kernel(kernel_filename); -} - -static void puv3_machine_init(MachineClass *mc) -{ - mc->desc = "PKUnity Version-3 based on UniCore32"; - mc->init = puv3_init; - mc->is_default = true; - mc->default_cpu_type = UNICORE32_CPU_TYPE_NAME("UniCore-II"); -} - -DEFINE_MACHINE("puv3", puv3_machine_init) diff --git a/include/elf.h b/include/elf.h index 33ed830ec3..033bcc9576 100644 --- a/include/elf.h +++ b/include/elf.h @@ -174,9 +174,8 @@ typedef struct mips_elf_abiflags_v0 { #define EM_OPENRISC 92 /* OpenCores OpenRISC */ -#define EM_UNICORE32 110 /* UniCore32 */ - #define EM_HEXAGON 164 /* Qualcomm Hexagon */ + #define EM_RX 173 /* Renesas RX family */ #define EM_RISCV 243 /* RISC-V */ diff --git a/include/exec/poison.h b/include/exec/poison.h index b102e3cbf0..8fc7530b6e 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -30,7 +30,6 @@ #pragma GCC poison TARGET_SPARC #pragma GCC poison TARGET_SPARC64 #pragma GCC poison TARGET_TRICORE -#pragma GCC poison TARGET_UNICORE32 #pragma GCC poison TARGET_XTENSA #pragma GCC poison TARGET_ALIGNED_ONLY diff --git a/include/hw/unicore32/puv3.h b/include/hw/unicore32/puv3.h deleted file mode 100644 index f587a1f622..0000000000 --- a/include/hw/unicore32/puv3.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Misc PKUnity SoC declarations - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ - -#ifndef QEMU_HW_PUV3_H -#define QEMU_HW_PUV3_H - -#define PUV3_REGS_OFFSET (0x1000) /* 4K is reasonable */ - -/* Hardware interrupts */ -#define PUV3_IRQS_NR (32) - -#define PUV3_IRQS_GPIOLOW0 (0) -#define PUV3_IRQS_GPIOLOW1 (1) -#define PUV3_IRQS_GPIOLOW2 (2) -#define PUV3_IRQS_GPIOLOW3 (3) -#define PUV3_IRQS_GPIOLOW4 (4) -#define PUV3_IRQS_GPIOLOW5 (5) -#define PUV3_IRQS_GPIOLOW6 (6) -#define PUV3_IRQS_GPIOLOW7 (7) -#define PUV3_IRQS_GPIOHIGH (8) -#define PUV3_IRQS_PS2_KBD (22) -#define PUV3_IRQS_PS2_AUX (23) -#define PUV3_IRQS_OST0 (26) - -/* All puv3_*.c use DPRINTF for debug. */ -#ifdef DEBUG_PUV3 -#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#endif /* QEMU_HW_PUV3_H */ diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index fc002b84de..e723c467eb 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -17,7 +17,6 @@ enum { QEMU_ARCH_SPARC = (1 << 11), QEMU_ARCH_XTENSA = (1 << 12), QEMU_ARCH_OPENRISC = (1 << 13), - QEMU_ARCH_UNICORE32 = (1 << 14), QEMU_ARCH_TRICORE = (1 << 16), QEMU_ARCH_NIOS2 = (1 << 17), QEMU_ARCH_HPPA = (1 << 18), diff --git a/qapi/machine.json b/qapi/machine.json index 37a7e34195..58a9c86b36 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -33,7 +33,7 @@ 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', 'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc', 'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4', - 'sh4eb', 'sparc', 'sparc64', 'tricore', 'unicore32', + 'sh4eb', 'sparc', 'sparc64', 'tricore', 'x86_64', 'xtensa', 'xtensaeb' ] } ## diff --git a/softmmu/arch_init.c b/softmmu/arch_init.c index 2b90884e3a..6ff9f30bad 100644 --- a/softmmu/arch_init.c +++ b/softmmu/arch_init.c @@ -80,8 +80,6 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_SPARC #elif defined(TARGET_TRICORE) #define QEMU_ARCH QEMU_ARCH_TRICORE -#elif defined(TARGET_UNICORE32) -#define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_XTENSA) #define QEMU_ARCH QEMU_ARCH_XTENSA #elif defined(TARGET_AVR) diff --git a/target/meson.build b/target/meson.build index ccc87f30f3..2f6940255e 100644 --- a/target/meson.build +++ b/target/meson.build @@ -17,5 +17,4 @@ subdir('s390x') subdir('sh4') subdir('sparc') subdir('tricore') -subdir('unicore32') subdir('xtensa') diff --git a/target/unicore32/cpu-param.h b/target/unicore32/cpu-param.h deleted file mode 100644 index 94d8a5daa1..0000000000 --- a/target/unicore32/cpu-param.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * UniCore32 cpu parameters for qemu. - * - * Copyright (C) 2010-2012 Guan Xuetao - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef UNICORE32_CPU_PARAM_H -#define UNICORE32_CPU_PARAM_H 1 - -#define TARGET_LONG_BITS 32 -#define TARGET_PAGE_BITS 12 -#define TARGET_PHYS_ADDR_SPACE_BITS 32 -#define TARGET_VIRT_ADDR_SPACE_BITS 32 -#define NB_MMU_MODES 2 - -#endif diff --git a/target/unicore32/cpu-qom.h b/target/unicore32/cpu-qom.h deleted file mode 100644 index 43621e7479..0000000000 --- a/target/unicore32/cpu-qom.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * QEMU UniCore32 CPU - * - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ -#ifndef QEMU_UC32_CPU_QOM_H -#define QEMU_UC32_CPU_QOM_H - -#include "hw/core/cpu.h" -#include "qom/object.h" - -#define TYPE_UNICORE32_CPU "unicore32-cpu" - -OBJECT_DECLARE_TYPE(UniCore32CPU, UniCore32CPUClass, - UNICORE32_CPU) - -/** - * UniCore32CPUClass: - * @parent_realize: The parent class' realize handler. - * - * A UniCore32 CPU model. - */ -struct UniCore32CPUClass { - /*< private >*/ - CPUClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; -}; - - -#endif diff --git a/target/unicore32/cpu.c b/target/unicore32/cpu.c deleted file mode 100644 index 0258884f84..0000000000 --- a/target/unicore32/cpu.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * QEMU UniCore32 CPU - * - * Copyright (c) 2010-2012 Guan Xuetao - * Copyright (c) 2012 SUSE LINUX Products GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Contributions from 2012-04-01 on are considered under GPL version 2, - * or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "cpu.h" -#include "migration/vmstate.h" -#include "exec/exec-all.h" - -static void uc32_cpu_set_pc(CPUState *cs, vaddr value) -{ - UniCore32CPU *cpu = UNICORE32_CPU(cs); - - cpu->env.regs[31] = value; -} - -static bool uc32_cpu_has_work(CPUState *cs) -{ - return cs->interrupt_request & - (CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB); -} - -static inline void set_feature(CPUUniCore32State *env, int feature) -{ - env->features |= feature; -} - -/* CPU models */ - -static ObjectClass *uc32_cpu_class_by_name(const char *cpu_model) -{ - ObjectClass *oc; - char *typename; - - typename = g_strdup_printf(UNICORE32_CPU_TYPE_NAME("%s"), cpu_model); - oc = object_class_by_name(typename); - g_free(typename); - if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_UNICORE32_CPU) || - object_class_is_abstract(oc))) { - oc = NULL; - } - return oc; -} - -static void unicore_ii_cpu_initfn(Object *obj) -{ - UniCore32CPU *cpu = UNICORE32_CPU(obj); - CPUUniCore32State *env = &cpu->env; - - env->cp0.c0_cpuid = 0x4d000863; - env->cp0.c0_cachetype = 0x0d152152; - env->cp0.c1_sys = 0x2000; - env->cp0.c2_base = 0x0; - env->cp0.c3_faultstatus = 0x0; - env->cp0.c4_faultaddr = 0x0; - env->ucf64.xregs[UC32_UCF64_FPSCR] = 0; - - set_feature(env, UC32_HWCAP_CMOV); - set_feature(env, UC32_HWCAP_UCF64); -} - -static void uc32_any_cpu_initfn(Object *obj) -{ - UniCore32CPU *cpu = UNICORE32_CPU(obj); - CPUUniCore32State *env = &cpu->env; - - env->cp0.c0_cpuid = 0xffffffff; - env->ucf64.xregs[UC32_UCF64_FPSCR] = 0; - - set_feature(env, UC32_HWCAP_CMOV); - set_feature(env, UC32_HWCAP_UCF64); -} - -static void uc32_cpu_realizefn(DeviceState *dev, Error **errp) -{ - CPUState *cs = CPU(dev); - UniCore32CPUClass *ucc = UNICORE32_CPU_GET_CLASS(dev); - Error *local_err = NULL; - - cpu_exec_realizefn(cs, &local_err); - if (local_err != NULL) { - error_propagate(errp, local_err); - return; - } - - qemu_init_vcpu(cs); - - ucc->parent_realize(dev, errp); -} - -static void uc32_cpu_initfn(Object *obj) -{ - UniCore32CPU *cpu = UNICORE32_CPU(obj); - CPUUniCore32State *env = &cpu->env; - - cpu_set_cpustate_pointers(cpu); - -#ifdef CONFIG_USER_ONLY - env->uncached_asr = ASR_MODE_USER; - env->regs[31] = 0; -#else - env->uncached_asr = ASR_MODE_PRIV; - env->regs[31] = 0x03000000; -#endif -} - -static const VMStateDescription vmstate_uc32_cpu = { - .name = "cpu", - .unmigratable = 1, -}; - -#include "hw/core/tcg-cpu-ops.h" - -static struct TCGCPUOps uc32_tcg_ops = { - .initialize = uc32_translate_init, - .cpu_exec_interrupt = uc32_cpu_exec_interrupt, - .tlb_fill = uc32_cpu_tlb_fill, - -#ifndef CONFIG_USER_ONLY - .do_interrupt = uc32_cpu_do_interrupt, -#endif /* !CONFIG_USER_ONLY */ -}; - -static void uc32_cpu_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); - UniCore32CPUClass *ucc = UNICORE32_CPU_CLASS(oc); - - device_class_set_parent_realize(dc, uc32_cpu_realizefn, - &ucc->parent_realize); - - cc->class_by_name = uc32_cpu_class_by_name; - cc->has_work = uc32_cpu_has_work; - cc->dump_state = uc32_cpu_dump_state; - cc->set_pc = uc32_cpu_set_pc; - cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug; - dc->vmsd = &vmstate_uc32_cpu; - cc->tcg_ops = &uc32_tcg_ops; -} - -#define DEFINE_UNICORE32_CPU_TYPE(cpu_model, initfn) \ - { \ - .parent = TYPE_UNICORE32_CPU, \ - .instance_init = initfn, \ - .name = UNICORE32_CPU_TYPE_NAME(cpu_model), \ - } - -static const TypeInfo uc32_cpu_type_infos[] = { - { - .name = TYPE_UNICORE32_CPU, - .parent = TYPE_CPU, - .instance_size = sizeof(UniCore32CPU), - .instance_init = uc32_cpu_initfn, - .abstract = true, - .class_size = sizeof(UniCore32CPUClass), - .class_init = uc32_cpu_class_init, - }, - DEFINE_UNICORE32_CPU_TYPE("UniCore-II", unicore_ii_cpu_initfn), - DEFINE_UNICORE32_CPU_TYPE("any", uc32_any_cpu_initfn), -}; - -DEFINE_TYPES(uc32_cpu_type_infos) diff --git a/target/unicore32/cpu.h b/target/unicore32/cpu.h deleted file mode 100644 index 7a32e086ed..0000000000 --- a/target/unicore32/cpu.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * UniCore32 virtual CPU header - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ - -#ifndef UNICORE32_CPU_H -#define UNICORE32_CPU_H - -#include "cpu-qom.h" -#include "exec/cpu-defs.h" - -typedef struct CPUUniCore32State { - /* Regs for current mode. */ - uint32_t regs[32]; - /* Frequently accessed ASR bits are stored separately for efficiently. - This contains all the other bits. Use asr_{read,write} to access - the whole ASR. */ - uint32_t uncached_asr; - uint32_t bsr; - - /* Banked registers. */ - uint32_t banked_bsr[6]; - uint32_t banked_r29[6]; - uint32_t banked_r30[6]; - - /* asr flag cache for faster execution */ - uint32_t CF; /* 0 or 1 */ - uint32_t VF; /* V is the bit 31. All other bits are undefined */ - uint32_t NF; /* N is bit 31. All other bits are undefined. */ - uint32_t ZF; /* Z set if zero. */ - - /* System control coprocessor (cp0) */ - struct { - uint32_t c0_cpuid; - uint32_t c0_cachetype; - uint32_t c1_sys; /* System control register. */ - uint32_t c2_base; /* MMU translation table base. */ - uint32_t c3_faultstatus; /* Fault status registers. */ - uint32_t c4_faultaddr; /* Fault address registers. */ - uint32_t c5_cacheop; /* Cache operation registers. */ - uint32_t c6_tlbop; /* TLB operation registers. */ - } cp0; - - /* UniCore-F64 coprocessor state. */ - struct { - float64 regs[16]; - uint32_t xregs[32]; - float_status fp_status; - } ucf64; - - /* Internal CPU feature flags. */ - uint32_t features; - -} CPUUniCore32State; - -/** - * UniCore32CPU: - * @env: #CPUUniCore32State - * - * A UniCore32 CPU. - */ -struct UniCore32CPU { - /*< private >*/ - CPUState parent_obj; - /*< public >*/ - - CPUNegativeOffsetState neg; - CPUUniCore32State env; -}; - - -void uc32_cpu_do_interrupt(CPUState *cpu); -bool uc32_cpu_exec_interrupt(CPUState *cpu, int int_req); -void uc32_cpu_dump_state(CPUState *cpu, FILE *f, int flags); -hwaddr uc32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); - -#define ASR_M (0x1f) -#define ASR_MODE_USER (0x10) -#define ASR_MODE_INTR (0x12) -#define ASR_MODE_PRIV (0x13) -#define ASR_MODE_TRAP (0x17) -#define ASR_MODE_EXTN (0x1b) -#define ASR_MODE_SUSR (0x1f) -#define ASR_I (1 << 7) -#define ASR_V (1 << 28) -#define ASR_C (1 << 29) -#define ASR_Z (1 << 30) -#define ASR_N (1 << 31) -#define ASR_NZCV (ASR_N | ASR_Z | ASR_C | ASR_V) -#define ASR_RESERVED (~(ASR_M | ASR_I | ASR_NZCV)) - -#define UC32_EXCP_PRIV (1) -#define UC32_EXCP_ITRAP (2) -#define UC32_EXCP_DTRAP (3) -#define UC32_EXCP_INTR (4) - -/* Return the current ASR value. */ -target_ulong cpu_asr_read(CPUUniCore32State *env1); -/* Set the ASR. Note that some bits of mask must be all-set or all-clear. */ -void cpu_asr_write(CPUUniCore32State *env1, target_ulong val, target_ulong mask); - -/* UniCore-F64 system registers. */ -#define UC32_UCF64_FPSCR (31) -#define UCF64_FPSCR_MASK (0x27ffffff) -#define UCF64_FPSCR_RND_MASK (0x7) -#define UCF64_FPSCR_RND(r) (((r) >> 0) & UCF64_FPSCR_RND_MASK) -#define UCF64_FPSCR_TRAPEN_MASK (0x7f) -#define UCF64_FPSCR_TRAPEN(r) (((r) >> 10) & UCF64_FPSCR_TRAPEN_MASK) -#define UCF64_FPSCR_FLAG_MASK (0x3ff) -#define UCF64_FPSCR_FLAG(r) (((r) >> 17) & UCF64_FPSCR_FLAG_MASK) -#define UCF64_FPSCR_FLAG_ZERO (1 << 17) -#define UCF64_FPSCR_FLAG_INFINITY (1 << 18) -#define UCF64_FPSCR_FLAG_INVALID (1 << 19) -#define UCF64_FPSCR_FLAG_UNDERFLOW (1 << 20) -#define UCF64_FPSCR_FLAG_OVERFLOW (1 << 21) -#define UCF64_FPSCR_FLAG_INEXACT (1 << 22) -#define UCF64_FPSCR_FLAG_HUGEINT (1 << 23) -#define UCF64_FPSCR_FLAG_DENORMAL (1 << 24) -#define UCF64_FPSCR_FLAG_UNIMP (1 << 25) -#define UCF64_FPSCR_FLAG_DIVZERO (1 << 26) - -#define UC32_HWCAP_CMOV 4 /* 1 << 2 */ -#define UC32_HWCAP_UCF64 8 /* 1 << 3 */ - -#define cpu_signal_handler uc32_cpu_signal_handler - -int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc); - -/* MMU modes definitions */ -#define MMU_USER_IDX 1 -static inline int cpu_mmu_index(CPUUniCore32State *env, bool ifetch) -{ - return (env->uncached_asr & ASR_M) == ASR_MODE_USER ? 1 : 0; -} - -typedef CPUUniCore32State CPUArchState; -typedef UniCore32CPU ArchCPU; - -#include "exec/cpu-all.h" - -#define UNICORE32_CPU_TYPE_SUFFIX "-" TYPE_UNICORE32_CPU -#define UNICORE32_CPU_TYPE_NAME(model) model UNICORE32_CPU_TYPE_SUFFIX -#define CPU_RESOLVING_TYPE TYPE_UNICORE32_CPU - -static inline void cpu_get_tb_cpu_state(CPUUniCore32State *env, target_ulong *pc, - target_ulong *cs_base, uint32_t *flags) -{ - *pc = env->regs[31]; - *cs_base = 0; - *flags = 0; - if ((env->uncached_asr & ASR_M) != ASR_MODE_USER) { - *flags |= (1 << 6); - } -} - -bool uc32_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr); -void uc32_translate_init(void); -void switch_mode(CPUUniCore32State *, int); - -#endif /* UNICORE32_CPU_H */ diff --git a/target/unicore32/helper.c b/target/unicore32/helper.c deleted file mode 100644 index 704393c27f..0000000000 --- a/target/unicore32/helper.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Contributions from 2012-04-01 on are considered under GPL version 2, - * or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "cpu.h" -#include "exec/exec-all.h" -#include "exec/helper-proto.h" -#include "semihosting/console.h" - -#undef DEBUG_UC32 - -#ifdef DEBUG_UC32 -#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#ifndef CONFIG_USER_ONLY -void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg, - uint32_t cop) -{ - /* - * movc pp.nn, rn, #imm9 - * rn: UCOP_REG_D - * nn: UCOP_REG_N - * 1: sys control reg. - * 2: page table base reg. - * 3: data fault status reg. - * 4: insn fault status reg. - * 5: cache op. reg. - * 6: tlb op. reg. - * imm9: split UCOP_IMM10 with bit5 is 0 - */ - switch (creg) { - case 1: - if (cop != 0) { - goto unrecognized; - } - env->cp0.c1_sys = val; - break; - case 2: - if (cop != 0) { - goto unrecognized; - } - env->cp0.c2_base = val; - break; - case 3: - if (cop != 0) { - goto unrecognized; - } - env->cp0.c3_faultstatus = val; - break; - case 4: - if (cop != 0) { - goto unrecognized; - } - env->cp0.c4_faultaddr = val; - break; - case 5: - switch (cop) { - case 28: - DPRINTF("Invalidate Entire I&D cache\n"); - return; - case 20: - DPRINTF("Invalidate Entire Icache\n"); - return; - case 12: - DPRINTF("Invalidate Entire Dcache\n"); - return; - case 10: - DPRINTF("Clean Entire Dcache\n"); - return; - case 14: - DPRINTF("Flush Entire Dcache\n"); - return; - case 13: - DPRINTF("Invalidate Dcache line\n"); - return; - case 11: - DPRINTF("Clean Dcache line\n"); - return; - case 15: - DPRINTF("Flush Dcache line\n"); - return; - } - break; - case 6: - if ((cop <= 6) && (cop >= 2)) { - /* invalid all tlb */ - tlb_flush(env_cpu(env)); - return; - } - break; - default: - goto unrecognized; - } - return; -unrecognized: - qemu_log_mask(LOG_GUEST_ERROR, - "Wrong register (%d) or wrong operation (%d) in cp0_set!\n", - creg, cop); -} - -uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop) -{ - /* - * movc rd, pp.nn, #imm9 - * rd: UCOP_REG_D - * nn: UCOP_REG_N - * 0: cpuid and cachetype - * 1: sys control reg. - * 2: page table base reg. - * 3: data fault status reg. - * 4: insn fault status reg. - * imm9: split UCOP_IMM10 with bit5 is 0 - */ - switch (creg) { - case 0: - switch (cop) { - case 0: - return env->cp0.c0_cpuid; - case 1: - return env->cp0.c0_cachetype; - } - break; - case 1: - if (cop == 0) { - return env->cp0.c1_sys; - } - break; - case 2: - if (cop == 0) { - return env->cp0.c2_base; - } - break; - case 3: - if (cop == 0) { - return env->cp0.c3_faultstatus; - } - break; - case 4: - if (cop == 0) { - return env->cp0.c4_faultaddr; - } - break; - } - qemu_log_mask(LOG_GUEST_ERROR, - "Wrong register (%d) or wrong operation (%d) in cp0_set!\n", - creg, cop); - return 0; -} - -void helper_cp1_putc(target_ulong regval) -{ - const char c = regval; - - qemu_semihosting_log_out(&c, sizeof(c)); -} -#endif /* !CONFIG_USER_ONLY */ - -bool uc32_cpu_exec_interrupt(CPUState *cs, int interrupt_request) -{ - if (interrupt_request & CPU_INTERRUPT_HARD) { - UniCore32CPU *cpu = UNICORE32_CPU(cs); - CPUUniCore32State *env = &cpu->env; - - if (!(env->uncached_asr & ASR_I)) { - cs->exception_index = UC32_EXCP_INTR; - uc32_cpu_do_interrupt(cs); - return true; - } - } - return false; -} diff --git a/target/unicore32/helper.h b/target/unicore32/helper.h deleted file mode 100644 index a4a5d45d1d..0000000000 --- a/target/unicore32/helper.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ - -#ifndef CONFIG_USER_ONLY -DEF_HELPER_4(cp0_set, void, env, i32, i32, i32) -DEF_HELPER_3(cp0_get, i32, env, i32, i32) -DEF_HELPER_1(cp1_putc, void, i32) -#endif - -DEF_HELPER_2(exception, void, env, i32) - -DEF_HELPER_3(asr_write, void, env, i32, i32) -DEF_HELPER_1(asr_read, i32, env) - -DEF_HELPER_2(get_user_reg, i32, env, i32) -DEF_HELPER_3(set_user_reg, void, env, i32, i32) - -DEF_HELPER_3(add_cc, i32, env, i32, i32) -DEF_HELPER_3(adc_cc, i32, env, i32, i32) -DEF_HELPER_3(sub_cc, i32, env, i32, i32) -DEF_HELPER_3(sbc_cc, i32, env, i32, i32) - -DEF_HELPER_2(shl, i32, i32, i32) -DEF_HELPER_2(shr, i32, i32, i32) -DEF_HELPER_2(sar, i32, i32, i32) -DEF_HELPER_3(shl_cc, i32, env, i32, i32) -DEF_HELPER_3(shr_cc, i32, env, i32, i32) -DEF_HELPER_3(sar_cc, i32, env, i32, i32) -DEF_HELPER_3(ror_cc, i32, env, i32, i32) - -DEF_HELPER_1(ucf64_get_fpscr, i32, env) -DEF_HELPER_2(ucf64_set_fpscr, void, env, i32) - -DEF_HELPER_3(ucf64_adds, f32, f32, f32, env) -DEF_HELPER_3(ucf64_addd, f64, f64, f64, env) -DEF_HELPER_3(ucf64_subs, f32, f32, f32, env) -DEF_HELPER_3(ucf64_subd, f64, f64, f64, env) -DEF_HELPER_3(ucf64_muls, f32, f32, f32, env) -DEF_HELPER_3(ucf64_muld, f64, f64, f64, env) -DEF_HELPER_3(ucf64_divs, f32, f32, f32, env) -DEF_HELPER_3(ucf64_divd, f64, f64, f64, env) -DEF_HELPER_1(ucf64_negs, f32, f32) -DEF_HELPER_1(ucf64_negd, f64, f64) -DEF_HELPER_1(ucf64_abss, f32, f32) -DEF_HELPER_1(ucf64_absd, f64, f64) -DEF_HELPER_4(ucf64_cmps, void, f32, f32, i32, env) -DEF_HELPER_4(ucf64_cmpd, void, f64, f64, i32, env) - -DEF_HELPER_2(ucf64_sf2df, f64, f32, env) -DEF_HELPER_2(ucf64_df2sf, f32, f64, env) - -DEF_HELPER_2(ucf64_si2sf, f32, f32, env) -DEF_HELPER_2(ucf64_si2df, f64, f32, env) - -DEF_HELPER_2(ucf64_sf2si, f32, f32, env) -DEF_HELPER_2(ucf64_df2si, f32, f64, env) diff --git a/target/unicore32/meson.build b/target/unicore32/meson.build deleted file mode 100644 index 0fa78772eb..0000000000 --- a/target/unicore32/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -unicore32_ss = ss.source_set() -unicore32_ss.add(files( - 'cpu.c', - 'helper.c', - 'op_helper.c', - 'translate.c', - 'ucf64_helper.c', -), curses) - -unicore32_softmmu_ss = ss.source_set() -unicore32_softmmu_ss.add(files('softmmu.c')) - -target_arch += {'unicore32': unicore32_ss} -target_softmmu_arch += {'unicore32': unicore32_softmmu_ss} diff --git a/target/unicore32/op_helper.c b/target/unicore32/op_helper.c deleted file mode 100644 index eeaa78601a..0000000000 --- a/target/unicore32/op_helper.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * UniCore32 helper routines - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "exec/exec-all.h" -#include "exec/cpu_ldst.h" - -#define SIGNBIT (uint32_t)0x80000000 -#define SIGNBIT64 ((uint64_t)1 << 63) - -void HELPER(exception)(CPUUniCore32State *env, uint32_t excp) -{ - CPUState *cs = env_cpu(env); - - cs->exception_index = excp; - cpu_loop_exit(cs); -} - -static target_ulong asr_read(CPUUniCore32State *env) -{ - int ZF; - ZF = (env->ZF == 0); - return env->uncached_asr | (env->NF & 0x80000000) | (ZF << 30) | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3); -} - -target_ulong cpu_asr_read(CPUUniCore32State *env) -{ - return asr_read(env); -} - -target_ulong HELPER(asr_read)(CPUUniCore32State *env) -{ - return asr_read(env); -} - -static void asr_write(CPUUniCore32State *env, target_ulong val, - target_ulong mask) -{ - if (mask & ASR_NZCV) { - env->ZF = (~val) & ASR_Z; - env->NF = val; - env->CF = (val >> 29) & 1; - env->VF = (val << 3) & 0x80000000; - } - - if ((env->uncached_asr ^ val) & mask & ASR_M) { - switch_mode(env, val & ASR_M); - } - mask &= ~ASR_NZCV; - env->uncached_asr = (env->uncached_asr & ~mask) | (val & mask); -} - -void cpu_asr_write(CPUUniCore32State *env, target_ulong val, target_ulong mask) -{ - asr_write(env, val, mask); -} - -void HELPER(asr_write)(CPUUniCore32State *env, target_ulong val, - target_ulong mask) -{ - asr_write(env, val, mask); -} - -/* Access to user mode registers from privileged modes. */ -uint32_t HELPER(get_user_reg)(CPUUniCore32State *env, uint32_t regno) -{ - uint32_t val; - - if (regno == 29) { - val = env->banked_r29[0]; - } else if (regno == 30) { - val = env->banked_r30[0]; - } else { - val = env->regs[regno]; - } - return val; -} - -void HELPER(set_user_reg)(CPUUniCore32State *env, uint32_t regno, uint32_t val) -{ - if (regno == 29) { - env->banked_r29[0] = val; - } else if (regno == 30) { - env->banked_r30[0] = val; - } else { - env->regs[regno] = val; - } -} - -/* ??? Flag setting arithmetic is awkward because we need to do comparisons. - The only way to do that in TCG is a conditional branch, which clobbers - all our temporaries. For now implement these as helper functions. */ - -uint32_t HELPER(add_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) -{ - uint32_t result; - result = a + b; - env->NF = env->ZF = result; - env->CF = result < a; - env->VF = (a ^ b ^ -1) & (a ^ result); - return result; -} - -uint32_t HELPER(adc_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) -{ - uint32_t result; - if (!env->CF) { - result = a + b; - env->CF = result < a; - } else { - result = a + b + 1; - env->CF = result <= a; - } - env->VF = (a ^ b ^ -1) & (a ^ result); - env->NF = env->ZF = result; - return result; -} - -uint32_t HELPER(sub_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) -{ - uint32_t result; - result = a - b; - env->NF = env->ZF = result; - env->CF = a >= b; - env->VF = (a ^ b) & (a ^ result); - return result; -} - -uint32_t HELPER(sbc_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) -{ - uint32_t result; - if (!env->CF) { - result = a - b - 1; - env->CF = a > b; - } else { - result = a - b; - env->CF = a >= b; - } - env->VF = (a ^ b) & (a ^ result); - env->NF = env->ZF = result; - return result; -} - -/* Similarly for variable shift instructions. */ - -uint32_t HELPER(shl)(uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - return 0; - } - return x << shift; -} - -uint32_t HELPER(shr)(uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - return 0; - } - return (uint32_t)x >> shift; -} - -uint32_t HELPER(sar)(uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - shift = 31; - } - return (int32_t)x >> shift; -} - -uint32_t HELPER(shl_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - if (shift == 32) { - env->CF = x & 1; - } else { - env->CF = 0; - } - return 0; - } else if (shift != 0) { - env->CF = (x >> (32 - shift)) & 1; - return x << shift; - } - return x; -} - -uint32_t HELPER(shr_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - if (shift == 32) { - env->CF = (x >> 31) & 1; - } else { - env->CF = 0; - } - return 0; - } else if (shift != 0) { - env->CF = (x >> (shift - 1)) & 1; - return x >> shift; - } - return x; -} - -uint32_t HELPER(sar_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) -{ - int shift = i & 0xff; - if (shift >= 32) { - env->CF = (x >> 31) & 1; - return (int32_t)x >> 31; - } else if (shift != 0) { - env->CF = (x >> (shift - 1)) & 1; - return (int32_t)x >> shift; - } - return x; -} - -uint32_t HELPER(ror_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) -{ - int shift1, shift; - shift1 = i & 0xff; - shift = shift1 & 0x1f; - if (shift == 0) { - if (shift1 != 0) { - env->CF = (x >> 31) & 1; - } - return x; - } else { - env->CF = (x >> (shift - 1)) & 1; - return ((uint32_t)x >> shift) | (x << (32 - shift)); - } -} diff --git a/target/unicore32/softmmu.c b/target/unicore32/softmmu.c deleted file mode 100644 index cbdaa500b7..0000000000 --- a/target/unicore32/softmmu.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Softmmu related functions - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ -#ifdef CONFIG_USER_ONLY -#error This file only exist under softmmu circumstance -#endif - -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/exec-all.h" -#include "qemu/error-report.h" - -#undef DEBUG_UC32 - -#ifdef DEBUG_UC32 -#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#define SUPERPAGE_SIZE (1 << 22) -#define UC32_PAGETABLE_READ (1 << 8) -#define UC32_PAGETABLE_WRITE (1 << 7) -#define UC32_PAGETABLE_EXEC (1 << 6) -#define UC32_PAGETABLE_EXIST (1 << 2) -#define PAGETABLE_TYPE(x) ((x) & 3) - - -/* Map CPU modes onto saved register banks. */ -static inline int bank_number(CPUUniCore32State *env, int mode) -{ - switch (mode) { - case ASR_MODE_USER: - case ASR_MODE_SUSR: - return 0; - case ASR_MODE_PRIV: - return 1; - case ASR_MODE_TRAP: - return 2; - case ASR_MODE_EXTN: - return 3; - case ASR_MODE_INTR: - return 4; - } - cpu_abort(env_cpu(env), "Bad mode %x\n", mode); - return -1; -} - -void switch_mode(CPUUniCore32State *env, int mode) -{ - int old_mode; - int i; - - old_mode = env->uncached_asr & ASR_M; - if (mode == old_mode) { - return; - } - - i = bank_number(env, old_mode); - env->banked_r29[i] = env->regs[29]; - env->banked_r30[i] = env->regs[30]; - env->banked_bsr[i] = env->bsr; - - i = bank_number(env, mode); - env->regs[29] = env->banked_r29[i]; - env->regs[30] = env->banked_r30[i]; - env->bsr = env->banked_bsr[i]; -} - -/* Handle a CPU exception. */ -void uc32_cpu_do_interrupt(CPUState *cs) -{ - UniCore32CPU *cpu = UNICORE32_CPU(cs); - CPUUniCore32State *env = &cpu->env; - uint32_t addr; - int new_mode; - - switch (cs->exception_index) { - case UC32_EXCP_PRIV: - new_mode = ASR_MODE_PRIV; - addr = 0x08; - break; - case UC32_EXCP_ITRAP: - DPRINTF("itrap happened at %x\n", env->regs[31]); - new_mode = ASR_MODE_TRAP; - addr = 0x0c; - break; - case UC32_EXCP_DTRAP: - DPRINTF("dtrap happened at %x\n", env->regs[31]); - new_mode = ASR_MODE_TRAP; - addr = 0x10; - break; - case UC32_EXCP_INTR: - new_mode = ASR_MODE_INTR; - addr = 0x18; - break; - default: - cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); - return; - } - /* High vectors. */ - if (env->cp0.c1_sys & (1 << 13)) { - addr += 0xffff0000; - } - - switch_mode(env, new_mode); - env->bsr = cpu_asr_read(env); - env->uncached_asr = (env->uncached_asr & ~ASR_M) | new_mode; - env->uncached_asr |= ASR_I; - /* The PC already points to the proper instruction. */ - env->regs[30] = env->regs[31]; - env->regs[31] = addr; - cs->interrupt_request |= CPU_INTERRUPT_EXITTB; -} - -static int get_phys_addr_ucv2(CPUUniCore32State *env, uint32_t address, - int access_type, int is_user, uint32_t *phys_ptr, int *prot, - target_ulong *page_size) -{ - CPUState *cs = env_cpu(env); - int code; - uint32_t table; - uint32_t desc; - uint32_t phys_addr; - - /* Pagetable walk. */ - /* Lookup l1 descriptor. */ - table = env->cp0.c2_base & 0xfffff000; - table |= (address >> 20) & 0xffc; - desc = ldl_phys(cs->as, table); - code = 0; - switch (PAGETABLE_TYPE(desc)) { - case 3: - /* Superpage */ - if (!(desc & UC32_PAGETABLE_EXIST)) { - code = 0x0b; /* superpage miss */ - goto do_fault; - } - phys_addr = (desc & 0xffc00000) | (address & 0x003fffff); - *page_size = SUPERPAGE_SIZE; - break; - case 0: - /* Lookup l2 entry. */ - if (is_user) { - DPRINTF("PGD address %x, desc %x\n", table, desc); - } - if (!(desc & UC32_PAGETABLE_EXIST)) { - code = 0x05; /* second pagetable miss */ - goto do_fault; - } - table = (desc & 0xfffff000) | ((address >> 10) & 0xffc); - desc = ldl_phys(cs->as, table); - /* 4k page. */ - if (is_user) { - DPRINTF("PTE address %x, desc %x\n", table, desc); - } - if (!(desc & UC32_PAGETABLE_EXIST)) { - code = 0x08; /* page miss */ - goto do_fault; - } - switch (PAGETABLE_TYPE(desc)) { - case 0: - phys_addr = (desc & 0xfffff000) | (address & 0xfff); - *page_size = TARGET_PAGE_SIZE; - break; - default: - cpu_abort(cs, "wrong page type!"); - } - break; - default: - cpu_abort(cs, "wrong page type!"); - } - - *phys_ptr = phys_addr; - *prot = 0; - /* Check access permissions. */ - if (desc & UC32_PAGETABLE_READ) { - *prot |= PAGE_READ; - } else { - if (is_user && (access_type == 0)) { - code = 0x11; /* access unreadable area */ - goto do_fault; - } - } - - if (desc & UC32_PAGETABLE_WRITE) { - *prot |= PAGE_WRITE; - } else { - if (is_user && (access_type == 1)) { - code = 0x12; /* access unwritable area */ - goto do_fault; - } - } - - if (desc & UC32_PAGETABLE_EXEC) { - *prot |= PAGE_EXEC; - } else { - if (is_user && (access_type == 2)) { - code = 0x13; /* access unexecutable area */ - goto do_fault; - } - } - -do_fault: - return code; -} - -bool uc32_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr) -{ - UniCore32CPU *cpu = UNICORE32_CPU(cs); - CPUUniCore32State *env = &cpu->env; - uint32_t phys_addr; - target_ulong page_size; - int prot; - int ret, is_user; - - ret = 1; - is_user = mmu_idx == MMU_USER_IDX; - - if ((env->cp0.c1_sys & 1) == 0) { - /* MMU disabled. */ - phys_addr = address; - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - page_size = TARGET_PAGE_SIZE; - ret = 0; - } else { - if ((address & (1 << 31)) || (is_user)) { - ret = get_phys_addr_ucv2(env, address, access_type, is_user, - &phys_addr, &prot, &page_size); - if (is_user) { - DPRINTF("user space access: ret %x, address %" VADDR_PRIx ", " - "access_type %x, phys_addr %x, prot %x\n", - ret, address, access_type, phys_addr, prot); - } - } else { - /*IO memory */ - phys_addr = address | (1 << 31); - prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; - page_size = TARGET_PAGE_SIZE; - ret = 0; - } - } - - if (ret == 0) { - /* Map a single page. */ - phys_addr &= TARGET_PAGE_MASK; - address &= TARGET_PAGE_MASK; - tlb_set_page(cs, address, phys_addr, prot, mmu_idx, page_size); - return true; - } - - if (probe) { - return false; - } - - env->cp0.c3_faultstatus = ret; - env->cp0.c4_faultaddr = address; - if (access_type == 2) { - cs->exception_index = UC32_EXCP_ITRAP; - } else { - cs->exception_index = UC32_EXCP_DTRAP; - } - cpu_loop_exit_restore(cs, retaddr); -} - -hwaddr uc32_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) -{ - error_report("function uc32_cpu_get_phys_page_debug not " - "implemented, aborting"); - return -1; -} diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c deleted file mode 100644 index 370709c9ea..0000000000 --- a/target/unicore32/translate.c +++ /dev/null @@ -1,2083 +0,0 @@ -/* - * UniCore32 translation - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ -#include "qemu/osdep.h" - -#include "cpu.h" -#include "disas/disas.h" -#include "exec/exec-all.h" -#include "tcg/tcg-op.h" -#include "qemu/log.h" -#include "exec/cpu_ldst.h" -#include "exec/translator.h" -#include "qemu/qemu-print.h" - -#include "exec/helper-proto.h" -#include "exec/helper-gen.h" - -#include "trace-tcg.h" -#include "exec/log.h" - - -/* internal defines */ -typedef struct DisasContext { - target_ulong pc; - int is_jmp; - /* Nonzero if this instruction has been conditionally skipped. */ - int condjmp; - /* The label that will be jumped to when the instruction is skipped. */ - TCGLabel *condlabel; - TranslationBlock *tb; - int singlestep_enabled; -#ifndef CONFIG_USER_ONLY - int user; -#endif -} DisasContext; - -#ifndef CONFIG_USER_ONLY -#define IS_USER(s) (s->user) -#else -#define IS_USER(s) 1 -#endif - -/* is_jmp field values */ -#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */ -#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */ -#define DISAS_TB_JUMP DISAS_TARGET_2 /* only pc was modified statically */ -/* These instructions trap after executing, so defer them until after the - conditional executions state has been updated. */ -#define DISAS_SYSCALL DISAS_TARGET_3 - -static TCGv_i32 cpu_R[32]; - -/* FIXME: These should be removed. */ -static TCGv cpu_F0s, cpu_F1s; -static TCGv_i64 cpu_F0d, cpu_F1d; - -#include "exec/gen-icount.h" - -static const char *regnames[] = { - "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07", - "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "r30", "pc" }; - -/* initialize TCG globals. */ -void uc32_translate_init(void) -{ - int i; - - for (i = 0; i < 32; i++) { - cpu_R[i] = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUUniCore32State, regs[i]), regnames[i]); - } -} - -static int num_temps; - -/* Allocate a temporary variable. */ -static TCGv_i32 new_tmp(void) -{ - num_temps++; - return tcg_temp_new_i32(); -} - -/* Release a temporary variable. */ -static void dead_tmp(TCGv tmp) -{ - tcg_temp_free(tmp); - num_temps--; -} - -static inline TCGv load_cpu_offset(int offset) -{ - TCGv tmp = new_tmp(); - tcg_gen_ld_i32(tmp, cpu_env, offset); - return tmp; -} - -#define load_cpu_field(name) load_cpu_offset(offsetof(CPUUniCore32State, name)) - -static inline void store_cpu_offset(TCGv var, int offset) -{ - tcg_gen_st_i32(var, cpu_env, offset); - dead_tmp(var); -} - -#define store_cpu_field(var, name) \ - store_cpu_offset(var, offsetof(CPUUniCore32State, name)) - -/* Set a variable to the value of a CPU register. */ -static void load_reg_var(DisasContext *s, TCGv var, int reg) -{ - if (reg == 31) { - uint32_t addr; - /* normaly, since we updated PC */ - addr = (long)s->pc; - tcg_gen_movi_i32(var, addr); - } else { - tcg_gen_mov_i32(var, cpu_R[reg]); - } -} - -/* Create a new temporary and set it to the value of a CPU register. */ -static inline TCGv load_reg(DisasContext *s, int reg) -{ - TCGv tmp = new_tmp(); - load_reg_var(s, tmp, reg); - return tmp; -} - -/* Set a CPU register. The source must be a temporary and will be - marked as dead. */ -static void store_reg(DisasContext *s, int reg, TCGv var) -{ - if (reg == 31) { - tcg_gen_andi_i32(var, var, ~3); - s->is_jmp = DISAS_JUMP; - } - tcg_gen_mov_i32(cpu_R[reg], var); - dead_tmp(var); -} - -/* Value extensions. */ -#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var) -#define gen_uxth(var) tcg_gen_ext16u_i32(var, var) -#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var) -#define gen_sxth(var) tcg_gen_ext16s_i32(var, var) - -#define UCOP_REG_M (((insn) >> 0) & 0x1f) -#define UCOP_REG_N (((insn) >> 19) & 0x1f) -#define UCOP_REG_D (((insn) >> 14) & 0x1f) -#define UCOP_REG_S (((insn) >> 9) & 0x1f) -#define UCOP_REG_LO (((insn) >> 14) & 0x1f) -#define UCOP_REG_HI (((insn) >> 9) & 0x1f) -#define UCOP_SH_OP (((insn) >> 6) & 0x03) -#define UCOP_SH_IM (((insn) >> 9) & 0x1f) -#define UCOP_OPCODES (((insn) >> 25) & 0x0f) -#define UCOP_IMM_9 (((insn) >> 0) & 0x1ff) -#define UCOP_IMM10 (((insn) >> 0) & 0x3ff) -#define UCOP_IMM14 (((insn) >> 0) & 0x3fff) -#define UCOP_COND (((insn) >> 25) & 0x0f) -#define UCOP_CMOV_COND (((insn) >> 19) & 0x0f) -#define UCOP_CPNUM (((insn) >> 10) & 0x0f) -#define UCOP_UCF64_FMT (((insn) >> 24) & 0x03) -#define UCOP_UCF64_FUNC (((insn) >> 6) & 0x0f) -#define UCOP_UCF64_COND (((insn) >> 6) & 0x0f) - -#define UCOP_SET(i) ((insn) & (1 << (i))) -#define UCOP_SET_P UCOP_SET(28) -#define UCOP_SET_U UCOP_SET(27) -#define UCOP_SET_B UCOP_SET(26) -#define UCOP_SET_W UCOP_SET(25) -#define UCOP_SET_L UCOP_SET(24) -#define UCOP_SET_S UCOP_SET(24) - -#define ILLEGAL cpu_abort(env_cpu(env), \ - "Illegal UniCore32 instruction %x at line %d!", \ - insn, __LINE__) - -#ifndef CONFIG_USER_ONLY -static void disas_cp0_insn(CPUUniCore32State *env, DisasContext *s, - uint32_t insn) -{ - TCGv tmp, tmp2, tmp3; - if ((insn & 0xfe000000) == 0xe0000000) { - tmp2 = new_tmp(); - tmp3 = new_tmp(); - tcg_gen_movi_i32(tmp2, UCOP_REG_N); - tcg_gen_movi_i32(tmp3, UCOP_IMM10); - if (UCOP_SET_L) { - tmp = new_tmp(); - gen_helper_cp0_get(tmp, cpu_env, tmp2, tmp3); - store_reg(s, UCOP_REG_D, tmp); - } else { - tmp = load_reg(s, UCOP_REG_D); - gen_helper_cp0_set(cpu_env, tmp, tmp2, tmp3); - dead_tmp(tmp); - } - dead_tmp(tmp2); - dead_tmp(tmp3); - return; - } - ILLEGAL; -} - -static void disas_ocd_insn(CPUUniCore32State *env, DisasContext *s, - uint32_t insn) -{ - TCGv tmp; - - if ((insn & 0xff003fff) == 0xe1000400) { - /* - * movc rd, pp.nn, #imm9 - * rd: UCOP_REG_D - * nn: UCOP_REG_N (must be 0) - * imm9: 0 - */ - if (UCOP_REG_N == 0) { - tmp = new_tmp(); - tcg_gen_movi_i32(tmp, 0); - store_reg(s, UCOP_REG_D, tmp); - return; - } else { - ILLEGAL; - } - } - if ((insn & 0xff003fff) == 0xe0000401) { - /* - * movc pp.nn, rn, #imm9 - * rn: UCOP_REG_D - * nn: UCOP_REG_N (must be 1) - * imm9: 1 - */ - if (UCOP_REG_N == 1) { - tmp = load_reg(s, UCOP_REG_D); - gen_helper_cp1_putc(tmp); - dead_tmp(tmp); - return; - } else { - ILLEGAL; - } - } - ILLEGAL; -} -#endif - -static inline void gen_set_asr(TCGv var, uint32_t mask) -{ - TCGv tmp_mask = tcg_const_i32(mask); - gen_helper_asr_write(cpu_env, var, tmp_mask); - tcg_temp_free_i32(tmp_mask); -} -/* Set NZCV flags from the high 4 bits of var. */ -#define gen_set_nzcv(var) gen_set_asr(var, ASR_NZCV) - -static void gen_exception(int excp) -{ - TCGv tmp = new_tmp(); - tcg_gen_movi_i32(tmp, excp); - gen_helper_exception(cpu_env, tmp); - dead_tmp(tmp); -} - -#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, CF)) - -/* Set CF to the top bit of var. */ -static void gen_set_CF_bit31(TCGv var) -{ - TCGv tmp = new_tmp(); - tcg_gen_shri_i32(tmp, var, 31); - gen_set_CF(tmp); - dead_tmp(tmp); -} - -/* Set N and Z flags from var. */ -static inline void gen_logic_CC(TCGv var) -{ - tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, NF)); - tcg_gen_st_i32(var, cpu_env, offsetof(CPUUniCore32State, ZF)); -} - -/* dest = T0 + T1 + CF. */ -static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1) -{ - TCGv tmp; - tcg_gen_add_i32(dest, t0, t1); - tmp = load_cpu_field(CF); - tcg_gen_add_i32(dest, dest, tmp); - dead_tmp(tmp); -} - -/* dest = T0 - T1 + CF - 1. */ -static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1) -{ - TCGv tmp; - tcg_gen_sub_i32(dest, t0, t1); - tmp = load_cpu_field(CF); - tcg_gen_add_i32(dest, dest, tmp); - tcg_gen_subi_i32(dest, dest, 1); - dead_tmp(tmp); -} - -static void shifter_out_im(TCGv var, int shift) -{ - TCGv tmp = new_tmp(); - if (shift == 0) { - tcg_gen_andi_i32(tmp, var, 1); - } else { - tcg_gen_shri_i32(tmp, var, shift); - if (shift != 31) { - tcg_gen_andi_i32(tmp, tmp, 1); - } - } - gen_set_CF(tmp); - dead_tmp(tmp); -} - -/* Shift by immediate. Includes special handling for shift == 0. */ -static inline void gen_uc32_shift_im(TCGv var, int shiftop, int shift, - int flags) -{ - switch (shiftop) { - case 0: /* LSL */ - if (shift != 0) { - if (flags) { - shifter_out_im(var, 32 - shift); - } - tcg_gen_shli_i32(var, var, shift); - } - break; - case 1: /* LSR */ - if (shift == 0) { - if (flags) { - tcg_gen_shri_i32(var, var, 31); - gen_set_CF(var); - } - tcg_gen_movi_i32(var, 0); - } else { - if (flags) { - shifter_out_im(var, shift - 1); - } - tcg_gen_shri_i32(var, var, shift); - } - break; - case 2: /* ASR */ - if (shift == 0) { - shift = 32; - } - if (flags) { - shifter_out_im(var, shift - 1); - } - if (shift == 32) { - shift = 31; - } - tcg_gen_sari_i32(var, var, shift); - break; - case 3: /* ROR/RRX */ - if (shift != 0) { - if (flags) { - shifter_out_im(var, shift - 1); - } - tcg_gen_rotri_i32(var, var, shift); break; - } else { - TCGv tmp = load_cpu_field(CF); - if (flags) { - shifter_out_im(var, 0); - } - tcg_gen_shri_i32(var, var, 1); - tcg_gen_shli_i32(tmp, tmp, 31); - tcg_gen_or_i32(var, var, tmp); - dead_tmp(tmp); - } - } -}; - -static inline void gen_uc32_shift_reg(TCGv var, int shiftop, - TCGv shift, int flags) -{ - if (flags) { - switch (shiftop) { - case 0: - gen_helper_shl_cc(var, cpu_env, var, shift); - break; - case 1: - gen_helper_shr_cc(var, cpu_env, var, shift); - break; - case 2: - gen_helper_sar_cc(var, cpu_env, var, shift); - break; - case 3: - gen_helper_ror_cc(var, cpu_env, var, shift); - break; - } - } else { - switch (shiftop) { - case 0: - gen_helper_shl(var, var, shift); - break; - case 1: - gen_helper_shr(var, var, shift); - break; - case 2: - gen_helper_sar(var, var, shift); - break; - case 3: - tcg_gen_andi_i32(shift, shift, 0x1f); - tcg_gen_rotr_i32(var, var, shift); - break; - } - } - dead_tmp(shift); -} - -static void gen_test_cc(int cc, TCGLabel *label) -{ - TCGv tmp; - TCGv tmp2; - TCGLabel *inv; - - switch (cc) { - case 0: /* eq: Z */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - break; - case 1: /* ne: !Z */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); - break; - case 2: /* cs: C */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); - break; - case 3: /* cc: !C */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - break; - case 4: /* mi: N */ - tmp = load_cpu_field(NF); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); - break; - case 5: /* pl: !N */ - tmp = load_cpu_field(NF); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); - break; - case 6: /* vs: V */ - tmp = load_cpu_field(VF); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); - break; - case 7: /* vc: !V */ - tmp = load_cpu_field(VF); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); - break; - case 8: /* hi: C && !Z */ - inv = gen_new_label(); - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); - dead_tmp(tmp); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label); - gen_set_label(inv); - break; - case 9: /* ls: !C || Z */ - tmp = load_cpu_field(CF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - dead_tmp(tmp); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - break; - case 10: /* ge: N == V -> N ^ V == 0 */ - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); - break; - case 11: /* lt: N != V -> N ^ V != 0 */ - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); - break; - case 12: /* gt: !Z && N == V */ - inv = gen_new_label(); - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv); - dead_tmp(tmp); - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label); - gen_set_label(inv); - break; - case 13: /* le: Z || N != V */ - tmp = load_cpu_field(ZF); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); - dead_tmp(tmp); - tmp = load_cpu_field(VF); - tmp2 = load_cpu_field(NF); - tcg_gen_xor_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label); - break; - default: - fprintf(stderr, "Bad condition code 0x%x\n", cc); - abort(); - } - dead_tmp(tmp); -} - -static const uint8_t table_logic_cc[16] = { - 1, /* and */ 1, /* xor */ 0, /* sub */ 0, /* rsb */ - 0, /* add */ 0, /* adc */ 0, /* sbc */ 0, /* rsc */ - 1, /* andl */ 1, /* xorl */ 0, /* cmp */ 0, /* cmn */ - 1, /* orr */ 1, /* mov */ 1, /* bic */ 1, /* mvn */ -}; - -/* Set PC state from an immediate address. */ -static inline void gen_bx_im(DisasContext *s, uint32_t addr) -{ - s->is_jmp = DISAS_UPDATE; - tcg_gen_movi_i32(cpu_R[31], addr & ~3); -} - -/* Set PC state from var. var is marked as dead. */ -static inline void gen_bx(DisasContext *s, TCGv var) -{ - s->is_jmp = DISAS_UPDATE; - tcg_gen_andi_i32(cpu_R[31], var, ~3); - dead_tmp(var); -} - -static inline void store_reg_bx(DisasContext *s, int reg, TCGv var) -{ - store_reg(s, reg, var); -} - -static inline TCGv gen_ld8s(TCGv addr, int index) -{ - TCGv tmp = new_tmp(); - tcg_gen_qemu_ld8s(tmp, addr, index); - return tmp; -} - -static inline TCGv gen_ld8u(TCGv addr, int index) -{ - TCGv tmp = new_tmp(); - tcg_gen_qemu_ld8u(tmp, addr, index); - return tmp; -} - -static inline TCGv gen_ld16s(TCGv addr, int index) -{ - TCGv tmp = new_tmp(); - tcg_gen_qemu_ld16s(tmp, addr, index); - return tmp; -} - -static inline TCGv gen_ld16u(TCGv addr, int index) -{ - TCGv tmp = new_tmp(); - tcg_gen_qemu_ld16u(tmp, addr, index); - return tmp; -} - -static inline TCGv gen_ld32(TCGv addr, int index) -{ - TCGv tmp = new_tmp(); - tcg_gen_qemu_ld32u(tmp, addr, index); - return tmp; -} - -static inline void gen_st8(TCGv val, TCGv addr, int index) -{ - tcg_gen_qemu_st8(val, addr, index); - dead_tmp(val); -} - -static inline void gen_st16(TCGv val, TCGv addr, int index) -{ - tcg_gen_qemu_st16(val, addr, index); - dead_tmp(val); -} - -static inline void gen_st32(TCGv val, TCGv addr, int index) -{ - tcg_gen_qemu_st32(val, addr, index); - dead_tmp(val); -} - -static inline void gen_set_pc_im(uint32_t val) -{ - tcg_gen_movi_i32(cpu_R[31], val); -} - -/* Force a TB lookup after an instruction that changes the CPU state. */ -static inline void gen_lookup_tb(DisasContext *s) -{ - tcg_gen_movi_i32(cpu_R[31], s->pc & ~1); - s->is_jmp = DISAS_UPDATE; -} - -static inline void gen_add_data_offset(DisasContext *s, unsigned int insn, - TCGv var) -{ - int val; - TCGv offset; - - if (UCOP_SET(29)) { - /* immediate */ - val = UCOP_IMM14; - if (!UCOP_SET_U) { - val = -val; - } - if (val != 0) { - tcg_gen_addi_i32(var, var, val); - } - } else { - /* shift/register */ - offset = load_reg(s, UCOP_REG_M); - gen_uc32_shift_im(offset, UCOP_SH_OP, UCOP_SH_IM, 0); - if (!UCOP_SET_U) { - tcg_gen_sub_i32(var, var, offset); - } else { - tcg_gen_add_i32(var, var, offset); - } - dead_tmp(offset); - } -} - -static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn, - TCGv var) -{ - int val; - TCGv offset; - - if (UCOP_SET(26)) { - /* immediate */ - val = (insn & 0x1f) | ((insn >> 4) & 0x3e0); - if (!UCOP_SET_U) { - val = -val; - } - if (val != 0) { - tcg_gen_addi_i32(var, var, val); - } - } else { - /* register */ - offset = load_reg(s, UCOP_REG_M); - if (!UCOP_SET_U) { - tcg_gen_sub_i32(var, var, offset); - } else { - tcg_gen_add_i32(var, var, offset); - } - dead_tmp(offset); - } -} - -static inline long ucf64_reg_offset(int reg) -{ - if (reg & 1) { - return offsetof(CPUUniCore32State, ucf64.regs[reg >> 1]) - + offsetof(CPU_DoubleU, l.upper); - } else { - return offsetof(CPUUniCore32State, ucf64.regs[reg >> 1]) - + offsetof(CPU_DoubleU, l.lower); - } -} - -#define ucf64_gen_ld32(reg) load_cpu_offset(ucf64_reg_offset(reg)) -#define ucf64_gen_st32(var, reg) store_cpu_offset(var, ucf64_reg_offset(reg)) - -/* UniCore-F64 single load/store I_offset */ -static void do_ucf64_ldst_i(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - int offset; - TCGv tmp; - TCGv addr; - - addr = load_reg(s, UCOP_REG_N); - if (!UCOP_SET_P && !UCOP_SET_W) { - ILLEGAL; - } - - if (UCOP_SET_P) { - offset = UCOP_IMM10 << 2; - if (!UCOP_SET_U) { - offset = -offset; - } - if (offset != 0) { - tcg_gen_addi_i32(addr, addr, offset); - } - } - - if (UCOP_SET_L) { /* load */ - tmp = gen_ld32(addr, IS_USER(s)); - ucf64_gen_st32(tmp, UCOP_REG_D); - } else { /* store */ - tmp = ucf64_gen_ld32(UCOP_REG_D); - gen_st32(tmp, addr, IS_USER(s)); - } - - if (!UCOP_SET_P) { - offset = UCOP_IMM10 << 2; - if (!UCOP_SET_U) { - offset = -offset; - } - if (offset != 0) { - tcg_gen_addi_i32(addr, addr, offset); - } - } - if (UCOP_SET_W) { - store_reg(s, UCOP_REG_N, addr); - } else { - dead_tmp(addr); - } -} - -/* UniCore-F64 load/store multiple words */ -static void do_ucf64_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - unsigned int i; - int j, n, freg; - TCGv tmp; - TCGv addr; - - if (UCOP_REG_D != 0) { - ILLEGAL; - } - if (UCOP_REG_N == 31) { - ILLEGAL; - } - if ((insn << 24) == 0) { - ILLEGAL; - } - - addr = load_reg(s, UCOP_REG_N); - - n = 0; - for (i = 0; i < 8; i++) { - if (UCOP_SET(i)) { - n++; - } - } - - if (UCOP_SET_U) { - if (UCOP_SET_P) { /* pre increment */ - tcg_gen_addi_i32(addr, addr, 4); - } /* unnecessary to do anything when post increment */ - } else { - if (UCOP_SET_P) { /* pre decrement */ - tcg_gen_addi_i32(addr, addr, -(n * 4)); - } else { /* post decrement */ - if (n != 1) { - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); - } - } - } - - freg = ((insn >> 8) & 3) << 3; /* freg should be 0, 8, 16, 24 */ - - for (i = 0, j = 0; i < 8; i++, freg++) { - if (!UCOP_SET(i)) { - continue; - } - - if (UCOP_SET_L) { /* load */ - tmp = gen_ld32(addr, IS_USER(s)); - ucf64_gen_st32(tmp, freg); - } else { /* store */ - tmp = ucf64_gen_ld32(freg); - gen_st32(tmp, addr, IS_USER(s)); - } - - j++; - /* unnecessary to add after the last transfer */ - if (j != n) { - tcg_gen_addi_i32(addr, addr, 4); - } - } - - if (UCOP_SET_W) { /* write back */ - if (UCOP_SET_U) { - if (!UCOP_SET_P) { /* post increment */ - tcg_gen_addi_i32(addr, addr, 4); - } /* unnecessary to do anything when pre increment */ - } else { - if (UCOP_SET_P) { - /* pre decrement */ - if (n != 1) { - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); - } - } else { - /* post decrement */ - tcg_gen_addi_i32(addr, addr, -(n * 4)); - } - } - store_reg(s, UCOP_REG_N, addr); - } else { - dead_tmp(addr); - } -} - -/* UniCore-F64 mrc/mcr */ -static void do_ucf64_trans(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - TCGv tmp; - - if ((insn & 0xfe0003ff) == 0xe2000000) { - /* control register */ - if ((UCOP_REG_N != UC32_UCF64_FPSCR) || (UCOP_REG_D == 31)) { - ILLEGAL; - } - if (UCOP_SET(24)) { - /* CFF */ - tmp = new_tmp(); - gen_helper_ucf64_get_fpscr(tmp, cpu_env); - store_reg(s, UCOP_REG_D, tmp); - } else { - /* CTF */ - tmp = load_reg(s, UCOP_REG_D); - gen_helper_ucf64_set_fpscr(cpu_env, tmp); - dead_tmp(tmp); - gen_lookup_tb(s); - } - return; - } - if ((insn & 0xfe0003ff) == 0xe0000000) { - /* general register */ - if (UCOP_REG_D == 31) { - ILLEGAL; - } - if (UCOP_SET(24)) { /* MFF */ - tmp = ucf64_gen_ld32(UCOP_REG_N); - store_reg(s, UCOP_REG_D, tmp); - } else { /* MTF */ - tmp = load_reg(s, UCOP_REG_D); - ucf64_gen_st32(tmp, UCOP_REG_N); - } - return; - } - if ((insn & 0xfb000000) == 0xe9000000) { - /* MFFC */ - if (UCOP_REG_D != 31) { - ILLEGAL; - } - if (UCOP_UCF64_COND & 0x8) { - ILLEGAL; - } - - tmp = new_tmp(); - tcg_gen_movi_i32(tmp, UCOP_UCF64_COND); - if (UCOP_SET(26)) { - tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N)); - tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, tmp, cpu_env); - } else { - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N)); - tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, tmp, cpu_env); - } - dead_tmp(tmp); - return; - } - ILLEGAL; -} - -/* UniCore-F64 convert instructions */ -static void do_ucf64_fcvt(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - if (UCOP_UCF64_FMT == 3) { - ILLEGAL; - } - if (UCOP_REG_N != 0) { - ILLEGAL; - } - switch (UCOP_UCF64_FUNC) { - case 0: /* cvt.s */ - switch (UCOP_UCF64_FMT) { - case 1 /* d */: - tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_df2sf(cpu_F0s, cpu_F0d, cpu_env); - tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - case 2 /* w */: - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_si2sf(cpu_F0s, cpu_F0s, cpu_env); - tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - default /* s */: - ILLEGAL; - break; - } - break; - case 1: /* cvt.d */ - switch (UCOP_UCF64_FMT) { - case 0 /* s */: - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_sf2df(cpu_F0d, cpu_F0s, cpu_env); - tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - case 2 /* w */: - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_si2df(cpu_F0d, cpu_F0s, cpu_env); - tcg_gen_st_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - default /* d */: - ILLEGAL; - break; - } - break; - case 4: /* cvt.w */ - switch (UCOP_UCF64_FMT) { - case 0 /* s */: - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_sf2si(cpu_F0s, cpu_F0s, cpu_env); - tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - case 1 /* d */: - tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - gen_helper_ucf64_df2si(cpu_F0s, cpu_F0d, cpu_env); - tcg_gen_st_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_D)); - break; - default /* w */: - ILLEGAL; - break; - } - break; - default: - ILLEGAL; - } -} - -/* UniCore-F64 compare instructions */ -static void do_ucf64_fcmp(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - if (UCOP_SET(25)) { - ILLEGAL; - } - if (UCOP_REG_D != 0) { - ILLEGAL; - } - - ILLEGAL; /* TODO */ - if (UCOP_SET(24)) { - tcg_gen_ld_i64(cpu_F0d, cpu_env, ucf64_reg_offset(UCOP_REG_N)); - tcg_gen_ld_i64(cpu_F1d, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - /* gen_helper_ucf64_cmpd(cpu_F0d, cpu_F1d, cpu_env); */ - } else { - tcg_gen_ld_i32(cpu_F0s, cpu_env, ucf64_reg_offset(UCOP_REG_N)); - tcg_gen_ld_i32(cpu_F1s, cpu_env, ucf64_reg_offset(UCOP_REG_M)); - /* gen_helper_ucf64_cmps(cpu_F0s, cpu_F1s, cpu_env); */ - } -} - -#define gen_helper_ucf64_movs(x, y) do { } while (0) -#define gen_helper_ucf64_movd(x, y) do { } while (0) - -#define UCF64_OP1(name) do { \ - if (UCOP_REG_N != 0) { \ - ILLEGAL; \ - } \ - switch (UCOP_UCF64_FMT) { \ - case 0 /* s */: \ - tcg_gen_ld_i32(cpu_F0s, cpu_env, \ - ucf64_reg_offset(UCOP_REG_M)); \ - gen_helper_ucf64_##name##s(cpu_F0s, cpu_F0s); \ - tcg_gen_st_i32(cpu_F0s, cpu_env, \ - ucf64_reg_offset(UCOP_REG_D)); \ - break; \ - case 1 /* d */: \ - tcg_gen_ld_i64(cpu_F0d, cpu_env, \ - ucf64_reg_offset(UCOP_REG_M)); \ - gen_helper_ucf64_##name##d(cpu_F0d, cpu_F0d); \ - tcg_gen_st_i64(cpu_F0d, cpu_env, \ - ucf64_reg_offset(UCOP_REG_D)); \ - break; \ - case 2 /* w */: \ - ILLEGAL; \ - break; \ - } \ - } while (0) - -#define UCF64_OP2(name) do { \ - switch (UCOP_UCF64_FMT) { \ - case 0 /* s */: \ - tcg_gen_ld_i32(cpu_F0s, cpu_env, \ - ucf64_reg_offset(UCOP_REG_N)); \ - tcg_gen_ld_i32(cpu_F1s, cpu_env, \ - ucf64_reg_offset(UCOP_REG_M)); \ - gen_helper_ucf64_##name##s(cpu_F0s, \ - cpu_F0s, cpu_F1s, cpu_env); \ - tcg_gen_st_i32(cpu_F0s, cpu_env, \ - ucf64_reg_offset(UCOP_REG_D)); \ - break; \ - case 1 /* d */: \ - tcg_gen_ld_i64(cpu_F0d, cpu_env, \ - ucf64_reg_offset(UCOP_REG_N)); \ - tcg_gen_ld_i64(cpu_F1d, cpu_env, \ - ucf64_reg_offset(UCOP_REG_M)); \ - gen_helper_ucf64_##name##d(cpu_F0d, \ - cpu_F0d, cpu_F1d, cpu_env); \ - tcg_gen_st_i64(cpu_F0d, cpu_env, \ - ucf64_reg_offset(UCOP_REG_D)); \ - break; \ - case 2 /* w */: \ - ILLEGAL; \ - break; \ - } \ - } while (0) - -/* UniCore-F64 data processing */ -static void do_ucf64_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - if (UCOP_UCF64_FMT == 3) { - ILLEGAL; - } - switch (UCOP_UCF64_FUNC) { - case 0: /* add */ - UCF64_OP2(add); - break; - case 1: /* sub */ - UCF64_OP2(sub); - break; - case 2: /* mul */ - UCF64_OP2(mul); - break; - case 4: /* div */ - UCF64_OP2(div); - break; - case 5: /* abs */ - UCF64_OP1(abs); - break; - case 6: /* mov */ - UCF64_OP1(mov); - break; - case 7: /* neg */ - UCF64_OP1(neg); - break; - default: - ILLEGAL; - } -} - -/* Disassemble an F64 instruction */ -static void disas_ucf64_insn(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - if (!UCOP_SET(29)) { - if (UCOP_SET(26)) { - do_ucf64_ldst_m(env, s, insn); - } else { - do_ucf64_ldst_i(env, s, insn); - } - } else { - if (UCOP_SET(5)) { - switch ((insn >> 26) & 0x3) { - case 0: - do_ucf64_datap(env, s, insn); - break; - case 1: - ILLEGAL; - break; - case 2: - do_ucf64_fcvt(env, s, insn); - break; - case 3: - do_ucf64_fcmp(env, s, insn); - break; - } - } else { - do_ucf64_trans(env, s, insn); - } - } -} - -static inline bool use_goto_tb(DisasContext *s, uint32_t dest) -{ -#ifndef CONFIG_USER_ONLY - return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); -#else - return true; -#endif -} - -static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest) -{ - if (use_goto_tb(s, dest)) { - tcg_gen_goto_tb(n); - gen_set_pc_im(dest); - tcg_gen_exit_tb(s->tb, n); - } else { - gen_set_pc_im(dest); - tcg_gen_exit_tb(NULL, 0); - } -} - -static inline void gen_jmp(DisasContext *s, uint32_t dest) -{ - if (unlikely(s->singlestep_enabled)) { - /* An indirect jump so that we still trigger the debug exception. */ - gen_bx_im(s, dest); - } else { - gen_goto_tb(s, 0, dest); - s->is_jmp = DISAS_TB_JUMP; - } -} - -/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */ -static int gen_set_psr(DisasContext *s, uint32_t mask, int bsr, TCGv t0) -{ - TCGv tmp; - if (bsr) { - /* ??? This is also undefined in system mode. */ - if (IS_USER(s)) { - return 1; - } - - tmp = load_cpu_field(bsr); - tcg_gen_andi_i32(tmp, tmp, ~mask); - tcg_gen_andi_i32(t0, t0, mask); - tcg_gen_or_i32(tmp, tmp, t0); - store_cpu_field(tmp, bsr); - } else { - gen_set_asr(t0, mask); - } - dead_tmp(t0); - gen_lookup_tb(s); - return 0; -} - -/* Generate an old-style exception return. Marks pc as dead. */ -static void gen_exception_return(DisasContext *s, TCGv pc) -{ - TCGv tmp; - store_reg(s, 31, pc); - tmp = load_cpu_field(bsr); - gen_set_asr(tmp, 0xffffffff); - dead_tmp(tmp); - s->is_jmp = DISAS_UPDATE; -} - -static void disas_coproc_insn(CPUUniCore32State *env, DisasContext *s, - uint32_t insn) -{ - switch (UCOP_CPNUM) { -#ifndef CONFIG_USER_ONLY - case 0: - disas_cp0_insn(env, s, insn); - break; - case 1: - disas_ocd_insn(env, s, insn); - break; -#endif - case 2: - disas_ucf64_insn(env, s, insn); - break; - default: - /* Unknown coprocessor. */ - cpu_abort(env_cpu(env), "Unknown coprocessor!"); - } -} - -/* data processing instructions */ -static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - TCGv tmp; - TCGv tmp2; - int logic_cc; - - if (UCOP_OPCODES == 0x0f || UCOP_OPCODES == 0x0d) { - if (UCOP_SET(23)) { /* CMOV instructions */ - if ((UCOP_CMOV_COND == 0xe) || (UCOP_CMOV_COND == 0xf)) { - ILLEGAL; - } - /* if not always execute, we generate a conditional jump to - next instruction */ - s->condlabel = gen_new_label(); - gen_test_cc(UCOP_CMOV_COND ^ 1, s->condlabel); - s->condjmp = 1; - } - } - - logic_cc = table_logic_cc[UCOP_OPCODES] & (UCOP_SET_S >> 24); - - if (UCOP_SET(29)) { - unsigned int val; - /* immediate operand */ - val = UCOP_IMM_9; - if (UCOP_SH_IM) { - val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM)); - } - tmp2 = new_tmp(); - tcg_gen_movi_i32(tmp2, val); - if (logic_cc && UCOP_SH_IM) { - gen_set_CF_bit31(tmp2); - } - } else { - /* register */ - tmp2 = load_reg(s, UCOP_REG_M); - if (UCOP_SET(5)) { - tmp = load_reg(s, UCOP_REG_S); - gen_uc32_shift_reg(tmp2, UCOP_SH_OP, tmp, logic_cc); - } else { - gen_uc32_shift_im(tmp2, UCOP_SH_OP, UCOP_SH_IM, logic_cc); - } - } - - if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) { - tmp = load_reg(s, UCOP_REG_N); - } else { - tmp = NULL; - } - - switch (UCOP_OPCODES) { - case 0x00: - tcg_gen_and_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x01: - tcg_gen_xor_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x02: - if (UCOP_SET_S && UCOP_REG_D == 31) { - /* SUBS r31, ... is used for exception return. */ - if (IS_USER(s)) { - ILLEGAL; - } - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); - gen_exception_return(s, tmp); - } else { - if (UCOP_SET_S) { - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); - } else { - tcg_gen_sub_i32(tmp, tmp, tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp); - } - break; - case 0x03: - if (UCOP_SET_S) { - gen_helper_sub_cc(tmp, cpu_env, tmp2, tmp); - } else { - tcg_gen_sub_i32(tmp, tmp2, tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x04: - if (UCOP_SET_S) { - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); - } else { - tcg_gen_add_i32(tmp, tmp, tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x05: - if (UCOP_SET_S) { - gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2); - } else { - gen_add_carry(tmp, tmp, tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x06: - if (UCOP_SET_S) { - gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2); - } else { - gen_sub_carry(tmp, tmp, tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x07: - if (UCOP_SET_S) { - gen_helper_sbc_cc(tmp, cpu_env, tmp2, tmp); - } else { - gen_sub_carry(tmp, tmp2, tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x08: - if (UCOP_SET_S) { - tcg_gen_and_i32(tmp, tmp, tmp2); - gen_logic_CC(tmp); - } - dead_tmp(tmp); - break; - case 0x09: - if (UCOP_SET_S) { - tcg_gen_xor_i32(tmp, tmp, tmp2); - gen_logic_CC(tmp); - } - dead_tmp(tmp); - break; - case 0x0a: - if (UCOP_SET_S) { - gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); - } - dead_tmp(tmp); - break; - case 0x0b: - if (UCOP_SET_S) { - gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); - } - dead_tmp(tmp); - break; - case 0x0c: - tcg_gen_or_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - case 0x0d: - if (logic_cc && UCOP_REG_D == 31) { - /* MOVS r31, ... is used for exception return. */ - if (IS_USER(s)) { - ILLEGAL; - } - gen_exception_return(s, tmp2); - } else { - if (logic_cc) { - gen_logic_CC(tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp2); - } - break; - case 0x0e: - tcg_gen_andc_i32(tmp, tmp, tmp2); - if (logic_cc) { - gen_logic_CC(tmp); - } - store_reg_bx(s, UCOP_REG_D, tmp); - break; - default: - case 0x0f: - tcg_gen_not_i32(tmp2, tmp2); - if (logic_cc) { - gen_logic_CC(tmp2); - } - store_reg_bx(s, UCOP_REG_D, tmp2); - break; - } - if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) { - dead_tmp(tmp2); - } -} - -/* multiply */ -static void do_mult(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - TCGv tmp, tmp2, tmp3, tmp4; - - if (UCOP_SET(27)) { - /* 64 bit mul */ - tmp = load_reg(s, UCOP_REG_M); - tmp2 = load_reg(s, UCOP_REG_N); - if (UCOP_SET(26)) { - tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2); - } else { - tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2); - } - if (UCOP_SET(25)) { /* mult accumulate */ - tmp3 = load_reg(s, UCOP_REG_LO); - tmp4 = load_reg(s, UCOP_REG_HI); - tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, tmp3, tmp4); - dead_tmp(tmp3); - dead_tmp(tmp4); - } - store_reg(s, UCOP_REG_LO, tmp); - store_reg(s, UCOP_REG_HI, tmp2); - } else { - /* 32 bit mul */ - tmp = load_reg(s, UCOP_REG_M); - tmp2 = load_reg(s, UCOP_REG_N); - tcg_gen_mul_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - if (UCOP_SET(25)) { - /* Add */ - tmp2 = load_reg(s, UCOP_REG_S); - tcg_gen_add_i32(tmp, tmp, tmp2); - dead_tmp(tmp2); - } - if (UCOP_SET_S) { - gen_logic_CC(tmp); - } - store_reg(s, UCOP_REG_D, tmp); - } -} - -/* miscellaneous instructions */ -static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - unsigned int val; - TCGv tmp; - - if ((insn & 0xffffffe0) == 0x10ffc120) { - /* Trivial implementation equivalent to bx. */ - tmp = load_reg(s, UCOP_REG_M); - gen_bx(s, tmp); - return; - } - - if ((insn & 0xfbffc000) == 0x30ffc000) { - /* PSR = immediate */ - val = UCOP_IMM_9; - if (UCOP_SH_IM) { - val = (val >> UCOP_SH_IM) | (val << (32 - UCOP_SH_IM)); - } - tmp = new_tmp(); - tcg_gen_movi_i32(tmp, val); - if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) { - ILLEGAL; - } - return; - } - - if ((insn & 0xfbffffe0) == 0x12ffc020) { - /* PSR.flag = reg */ - tmp = load_reg(s, UCOP_REG_M); - if (gen_set_psr(s, ASR_NZCV, UCOP_SET_B, tmp)) { - ILLEGAL; - } - return; - } - - if ((insn & 0xfbffffe0) == 0x10ffc020) { - /* PSR = reg */ - tmp = load_reg(s, UCOP_REG_M); - if (gen_set_psr(s, ~ASR_RESERVED, UCOP_SET_B, tmp)) { - ILLEGAL; - } - return; - } - - if ((insn & 0xfbf83fff) == 0x10f80000) { - /* reg = PSR */ - if (UCOP_SET_B) { - if (IS_USER(s)) { - ILLEGAL; - } - tmp = load_cpu_field(bsr); - } else { - tmp = new_tmp(); - gen_helper_asr_read(tmp, cpu_env); - } - store_reg(s, UCOP_REG_D, tmp); - return; - } - - if ((insn & 0xfbf83fe0) == 0x12f80120) { - /* clz */ - tmp = load_reg(s, UCOP_REG_M); - if (UCOP_SET(26)) { - /* clo */ - tcg_gen_not_i32(tmp, tmp); - } - tcg_gen_clzi_i32(tmp, tmp, 32); - store_reg(s, UCOP_REG_D, tmp); - return; - } - - /* otherwise */ - ILLEGAL; -} - -/* load/store I_offset and R_offset */ -static void do_ldst_ir(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - unsigned int mmu_idx; - TCGv tmp; - TCGv tmp2; - - tmp2 = load_reg(s, UCOP_REG_N); - mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W)); - - /* immediate */ - if (UCOP_SET_P) { - gen_add_data_offset(s, insn, tmp2); - } - - if (UCOP_SET_L) { - /* load */ - if (UCOP_SET_B) { - tmp = gen_ld8u(tmp2, mmu_idx); - } else { - tmp = gen_ld32(tmp2, mmu_idx); - } - } else { - /* store */ - tmp = load_reg(s, UCOP_REG_D); - if (UCOP_SET_B) { - gen_st8(tmp, tmp2, mmu_idx); - } else { - gen_st32(tmp, tmp2, mmu_idx); - } - } - if (!UCOP_SET_P) { - gen_add_data_offset(s, insn, tmp2); - store_reg(s, UCOP_REG_N, tmp2); - } else if (UCOP_SET_W) { - store_reg(s, UCOP_REG_N, tmp2); - } else { - dead_tmp(tmp2); - } - if (UCOP_SET_L) { - /* Complete the load. */ - if (UCOP_REG_D == 31) { - gen_bx(s, tmp); - } else { - store_reg(s, UCOP_REG_D, tmp); - } - } -} - -/* SWP instruction */ -static void do_swap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - TCGv addr; - TCGv tmp; - TCGv tmp2; - - if ((insn & 0xff003fe0) != 0x40000120) { - ILLEGAL; - } - - /* ??? This is not really atomic. However we know - we never have multiple CPUs running in parallel, - so it is good enough. */ - addr = load_reg(s, UCOP_REG_N); - tmp = load_reg(s, UCOP_REG_M); - if (UCOP_SET_B) { - tmp2 = gen_ld8u(addr, IS_USER(s)); - gen_st8(tmp, addr, IS_USER(s)); - } else { - tmp2 = gen_ld32(addr, IS_USER(s)); - gen_st32(tmp, addr, IS_USER(s)); - } - dead_tmp(addr); - store_reg(s, UCOP_REG_D, tmp2); -} - -/* load/store hw/sb */ -static void do_ldst_hwsb(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - TCGv addr; - TCGv tmp; - - if (UCOP_SH_OP == 0) { - do_swap(env, s, insn); - return; - } - - addr = load_reg(s, UCOP_REG_N); - if (UCOP_SET_P) { - gen_add_datah_offset(s, insn, addr); - } - - if (UCOP_SET_L) { /* load */ - switch (UCOP_SH_OP) { - case 1: - tmp = gen_ld16u(addr, IS_USER(s)); - break; - case 2: - tmp = gen_ld8s(addr, IS_USER(s)); - break; - default: /* see do_swap */ - case 3: - tmp = gen_ld16s(addr, IS_USER(s)); - break; - } - } else { /* store */ - if (UCOP_SH_OP != 1) { - ILLEGAL; - } - tmp = load_reg(s, UCOP_REG_D); - gen_st16(tmp, addr, IS_USER(s)); - } - /* Perform base writeback before the loaded value to - ensure correct behavior with overlapping index registers. */ - if (!UCOP_SET_P) { - gen_add_datah_offset(s, insn, addr); - store_reg(s, UCOP_REG_N, addr); - } else if (UCOP_SET_W) { - store_reg(s, UCOP_REG_N, addr); - } else { - dead_tmp(addr); - } - if (UCOP_SET_L) { - /* Complete the load. */ - store_reg(s, UCOP_REG_D, tmp); - } -} - -/* load/store multiple words */ -static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - unsigned int val, i, mmu_idx; - int j, n, reg, user, loaded_base; - TCGv tmp; - TCGv tmp2; - TCGv addr; - TCGv loaded_var; - - if (UCOP_SET(7)) { - ILLEGAL; - } - /* XXX: store correct base if write back */ - user = 0; - if (UCOP_SET_B) { /* S bit in instruction table */ - if (IS_USER(s)) { - ILLEGAL; /* only usable in supervisor mode */ - } - if (UCOP_SET(18) == 0) { /* pc reg */ - user = 1; - } - } - - mmu_idx = (IS_USER(s) || (!UCOP_SET_P && UCOP_SET_W)); - addr = load_reg(s, UCOP_REG_N); - - /* compute total size */ - loaded_base = 0; - loaded_var = NULL; - n = 0; - for (i = 0; i < 6; i++) { - if (UCOP_SET(i)) { - n++; - } - } - for (i = 9; i < 19; i++) { - if (UCOP_SET(i)) { - n++; - } - } - /* XXX: test invalid n == 0 case ? */ - if (UCOP_SET_U) { - if (UCOP_SET_P) { - /* pre increment */ - tcg_gen_addi_i32(addr, addr, 4); - } else { - /* post increment */ - } - } else { - if (UCOP_SET_P) { - /* pre decrement */ - tcg_gen_addi_i32(addr, addr, -(n * 4)); - } else { - /* post decrement */ - if (n != 1) { - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); - } - } - } - - j = 0; - reg = UCOP_SET(6) ? 16 : 0; - for (i = 0; i < 19; i++, reg++) { - if (i == 6) { - i = i + 3; - } - if (UCOP_SET(i)) { - if (UCOP_SET_L) { /* load */ - tmp = gen_ld32(addr, mmu_idx); - if (reg == 31) { - gen_bx(s, tmp); - } else if (user) { - tmp2 = tcg_const_i32(reg); - gen_helper_set_user_reg(cpu_env, tmp2, tmp); - tcg_temp_free_i32(tmp2); - dead_tmp(tmp); - } else if (reg == UCOP_REG_N) { - loaded_var = tmp; - loaded_base = 1; - } else { - store_reg(s, reg, tmp); - } - } else { /* store */ - if (reg == 31) { - /* special case: r31 = PC + 4 */ - val = (long)s->pc; - tmp = new_tmp(); - tcg_gen_movi_i32(tmp, val); - } else if (user) { - tmp = new_tmp(); - tmp2 = tcg_const_i32(reg); - gen_helper_get_user_reg(tmp, cpu_env, tmp2); - tcg_temp_free_i32(tmp2); - } else { - tmp = load_reg(s, reg); - } - gen_st32(tmp, addr, mmu_idx); - } - j++; - /* no need to add after the last transfer */ - if (j != n) { - tcg_gen_addi_i32(addr, addr, 4); - } - } - } - if (UCOP_SET_W) { /* write back */ - if (UCOP_SET_U) { - if (UCOP_SET_P) { - /* pre increment */ - } else { - /* post increment */ - tcg_gen_addi_i32(addr, addr, 4); - } - } else { - if (UCOP_SET_P) { - /* pre decrement */ - if (n != 1) { - tcg_gen_addi_i32(addr, addr, -((n - 1) * 4)); - } - } else { - /* post decrement */ - tcg_gen_addi_i32(addr, addr, -(n * 4)); - } - } - store_reg(s, UCOP_REG_N, addr); - } else { - dead_tmp(addr); - } - if (loaded_base) { - store_reg(s, UCOP_REG_N, loaded_var); - } - if (UCOP_SET_B && !user) { - /* Restore ASR from BSR. */ - tmp = load_cpu_field(bsr); - gen_set_asr(tmp, 0xffffffff); - dead_tmp(tmp); - s->is_jmp = DISAS_UPDATE; - } -} - -/* branch (and link) */ -static void do_branch(CPUUniCore32State *env, DisasContext *s, uint32_t insn) -{ - unsigned int val; - int32_t offset; - TCGv tmp; - - if (UCOP_COND == 0xf) { - ILLEGAL; - } - - if (UCOP_COND != 0xe) { - /* if not always execute, we generate a conditional jump to - next instruction */ - s->condlabel = gen_new_label(); - gen_test_cc(UCOP_COND ^ 1, s->condlabel); - s->condjmp = 1; - } - - val = (int32_t)s->pc; - if (UCOP_SET_L) { - tmp = new_tmp(); - tcg_gen_movi_i32(tmp, val); - store_reg(s, 30, tmp); - } - offset = (((int32_t)insn << 8) >> 8); - val += (offset << 2); /* unicore is pc+4 */ - gen_jmp(s, val); -} - -static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s) -{ - unsigned int insn; - - insn = cpu_ldl_code(env, s->pc); - s->pc += 4; - - /* UniCore instructions class: - * AAAB BBBC xxxx xxxx xxxx xxxD xxEx xxxx - * AAA : see switch case - * BBBB : opcodes or cond or PUBW - * C : S OR L - * D : 8 - * E : 5 - */ - switch (insn >> 29) { - case 0x0: - if (UCOP_SET(5) && UCOP_SET(8) && !UCOP_SET(28)) { - do_mult(env, s, insn); - break; - } - - if (UCOP_SET(8)) { - do_misc(env, s, insn); - break; - } - /* fallthrough */ - case 0x1: - if (((UCOP_OPCODES >> 2) == 2) && !UCOP_SET_S) { - do_misc(env, s, insn); - break; - } - do_datap(env, s, insn); - break; - - case 0x2: - if (UCOP_SET(8) && UCOP_SET(5)) { - do_ldst_hwsb(env, s, insn); - break; - } - if (UCOP_SET(8) || UCOP_SET(5)) { - ILLEGAL; - } - /* fallthrough */ - case 0x3: - do_ldst_ir(env, s, insn); - break; - - case 0x4: - if (UCOP_SET(8)) { - ILLEGAL; /* extended instructions */ - } - do_ldst_m(env, s, insn); - break; - case 0x5: - do_branch(env, s, insn); - break; - case 0x6: - /* Coprocessor. */ - disas_coproc_insn(env, s, insn); - break; - case 0x7: - if (!UCOP_SET(28)) { - disas_coproc_insn(env, s, insn); - break; - } - if ((insn & 0xff000000) == 0xff000000) { /* syscall */ - gen_set_pc_im(s->pc); - s->is_jmp = DISAS_SYSCALL; - break; - } - ILLEGAL; - } -} - -/* generate intermediate code for basic block 'tb'. */ -void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) -{ - CPUUniCore32State *env = cs->env_ptr; - DisasContext dc1, *dc = &dc1; - target_ulong pc_start; - uint32_t page_start; - int num_insns; - - /* generate intermediate code */ - num_temps = 0; - - pc_start = tb->pc; - - dc->tb = tb; - - dc->is_jmp = DISAS_NEXT; - dc->pc = pc_start; - dc->singlestep_enabled = cs->singlestep_enabled; - dc->condjmp = 0; - cpu_F0s = tcg_temp_new_i32(); - cpu_F1s = tcg_temp_new_i32(); - cpu_F0d = tcg_temp_new_i64(); - cpu_F1d = tcg_temp_new_i64(); - page_start = pc_start & TARGET_PAGE_MASK; - num_insns = 0; - -#ifndef CONFIG_USER_ONLY - if ((env->uncached_asr & ASR_M) == ASR_MODE_USER) { - dc->user = 1; - } else { - dc->user = 0; - } -#endif - - gen_tb_start(tb); - do { - tcg_gen_insn_start(dc->pc); - num_insns++; - - if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { - gen_set_pc_im(dc->pc); - gen_exception(EXCP_DEBUG); - dc->is_jmp = DISAS_JUMP; - /* The address covered by the breakpoint must be included in - [tb->pc, tb->pc + tb->size) in order to for it to be - properly cleared -- thus we increment the PC here so that - the logic setting tb->size below does the right thing. */ - dc->pc += 4; - goto done_generating; - } - - if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) { - gen_io_start(); - } - - disas_uc32_insn(env, dc); - - if (num_temps) { - fprintf(stderr, "Internal resource leak before %08x\n", dc->pc); - num_temps = 0; - } - - if (dc->condjmp && !dc->is_jmp) { - gen_set_label(dc->condlabel); - dc->condjmp = 0; - } - /* Translation stops when a conditional branch is encountered. - * Otherwise the subsequent code could get translated several times. - * Also stop translation when a page boundary is reached. This - * ensures prefetch aborts occur at the right place. */ - } while (!dc->is_jmp && !tcg_op_buf_full() && - !cs->singlestep_enabled && - !singlestep && - dc->pc - page_start < TARGET_PAGE_SIZE && - num_insns < max_insns); - - if (tb_cflags(tb) & CF_LAST_IO) { - if (dc->condjmp) { - /* FIXME: This can theoretically happen with self-modifying - code. */ - cpu_abort(cs, "IO on conditional branch instruction"); - } - } - - /* At this stage dc->condjmp will only be set when the skipped - instruction was a conditional branch or trap, and the PC has - already been written. */ - if (unlikely(cs->singlestep_enabled)) { - /* Make sure the pc is updated, and raise a debug exception. */ - if (dc->condjmp) { - if (dc->is_jmp == DISAS_SYSCALL) { - gen_exception(UC32_EXCP_PRIV); - } else { - gen_exception(EXCP_DEBUG); - } - gen_set_label(dc->condlabel); - } - if (dc->condjmp || !dc->is_jmp) { - gen_set_pc_im(dc->pc); - dc->condjmp = 0; - } - if (dc->is_jmp == DISAS_SYSCALL && !dc->condjmp) { - gen_exception(UC32_EXCP_PRIV); - } else { - gen_exception(EXCP_DEBUG); - } - } else { - /* While branches must always occur at the end of an IT block, - there are a few other things that can cause us to terminate - the TB in the middel of an IT block: - - Exception generating instructions (bkpt, swi, undefined). - - Page boundaries. - - Hardware watchpoints. - Hardware breakpoints have already been handled and skip this code. - */ - switch (dc->is_jmp) { - case DISAS_NEXT: - gen_goto_tb(dc, 1, dc->pc); - break; - default: - case DISAS_JUMP: - case DISAS_UPDATE: - /* indicate that the hash table must be used to find the next TB */ - tcg_gen_exit_tb(NULL, 0); - break; - case DISAS_TB_JUMP: - /* nothing more to generate */ - break; - case DISAS_SYSCALL: - gen_exception(UC32_EXCP_PRIV); - break; - } - if (dc->condjmp) { - gen_set_label(dc->condlabel); - gen_goto_tb(dc, 1, dc->pc); - dc->condjmp = 0; - } - } - -done_generating: - gen_tb_end(tb, num_insns); - -#ifdef DEBUG_DISAS - if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) - && qemu_log_in_addr_range(pc_start)) { - FILE *logfile = qemu_log_lock(); - qemu_log("----------------\n"); - qemu_log("IN: %s\n", lookup_symbol(pc_start)); - log_target_disas(cs, pc_start, dc->pc - pc_start); - qemu_log("\n"); - qemu_log_unlock(logfile); - } -#endif - tb->size = dc->pc - pc_start; - tb->icount = num_insns; -} - -static const char *cpu_mode_names[16] = { - "USER", "REAL", "INTR", "PRIV", "UM14", "UM15", "UM16", "TRAP", - "UM18", "UM19", "UM1A", "EXTN", "UM1C", "UM1D", "UM1E", "SUSR" -}; - -#undef UCF64_DUMP_STATE -#ifdef UCF64_DUMP_STATE -static void cpu_dump_state_ucf64(CPUUniCore32State *env, int flags) -{ - int i; - union { - uint32_t i; - float s; - } s0, s1; - CPU_DoubleU d; - /* ??? This assumes float64 and double have the same layout. - Oh well, it's only debug dumps. */ - union { - float64 f64; - double d; - } d0; - - for (i = 0; i < 16; i++) { - d.d = env->ucf64.regs[i]; - s0.i = d.l.lower; - s1.i = d.l.upper; - d0.f64 = d.d; - qemu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g)", - i * 2, (int)s0.i, s0.s, - i * 2 + 1, (int)s1.i, s1.s); - qemu_fprintf(f, " d%02d=%" PRIx64 "(%8g)\n", - i, (uint64_t)d0.f64, d0.d); - } - qemu_fprintf(f, "FPSCR: %08x\n", (int)env->ucf64.xregs[UC32_UCF64_FPSCR]); -} -#else -#define cpu_dump_state_ucf64(env, file, pr, flags) do { } while (0) -#endif - -void uc32_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - UniCore32CPU *cpu = UNICORE32_CPU(cs); - CPUUniCore32State *env = &cpu->env; - int i; - uint32_t psr; - - for (i = 0; i < 32; i++) { - qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]); - if ((i % 4) == 3) { - qemu_fprintf(f, "\n"); - } else { - qemu_fprintf(f, " "); - } - } - psr = cpu_asr_read(env); - qemu_fprintf(f, "PSR=%08x %c%c%c%c %s\n", - psr, - psr & (1 << 31) ? 'N' : '-', - psr & (1 << 30) ? 'Z' : '-', - psr & (1 << 29) ? 'C' : '-', - psr & (1 << 28) ? 'V' : '-', - cpu_mode_names[psr & 0xf]); - - if (flags & CPU_DUMP_FPU) { - cpu_dump_state_ucf64(env, f, cpu_fprintf, flags); - } -} - -void restore_state_to_opc(CPUUniCore32State *env, TranslationBlock *tb, - target_ulong *data) -{ - env->regs[31] = data[0]; -} diff --git a/target/unicore32/ucf64_helper.c b/target/unicore32/ucf64_helper.c deleted file mode 100644 index 12a91900f6..0000000000 --- a/target/unicore32/ucf64_helper.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * UniCore-F64 simulation helpers for QEMU. - * - * Copyright (C) 2010-2012 Guan Xuetao - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or any later version. - * See the COPYING file in the top-level directory. - */ -#include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" -#include "fpu/softfloat.h" - -/* - * The convention used for UniCore-F64 instructions: - * Single precition routines have a "s" suffix - * Double precision routines have a "d" suffix. - */ - -/* Convert host exception flags to f64 form. */ -static inline int ucf64_exceptbits_from_host(int host_bits) -{ - int target_bits = 0; - - if (host_bits & float_flag_invalid) { - target_bits |= UCF64_FPSCR_FLAG_INVALID; - } - if (host_bits & float_flag_divbyzero) { - target_bits |= UCF64_FPSCR_FLAG_DIVZERO; - } - if (host_bits & float_flag_overflow) { - target_bits |= UCF64_FPSCR_FLAG_OVERFLOW; - } - if (host_bits & float_flag_underflow) { - target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW; - } - if (host_bits & float_flag_inexact) { - target_bits |= UCF64_FPSCR_FLAG_INEXACT; - } - return target_bits; -} - -uint32_t HELPER(ucf64_get_fpscr)(CPUUniCore32State *env) -{ - int i; - uint32_t fpscr; - - fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK); - i = get_float_exception_flags(&env->ucf64.fp_status); - fpscr |= ucf64_exceptbits_from_host(i); - return fpscr; -} - -/* Convert ucf64 exception flags to target form. */ -static inline int ucf64_exceptbits_to_host(int target_bits) -{ - int host_bits = 0; - - if (target_bits & UCF64_FPSCR_FLAG_INVALID) { - host_bits |= float_flag_invalid; - } - if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) { - host_bits |= float_flag_divbyzero; - } - if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) { - host_bits |= float_flag_overflow; - } - if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) { - host_bits |= float_flag_underflow; - } - if (target_bits & UCF64_FPSCR_FLAG_INEXACT) { - host_bits |= float_flag_inexact; - } - return host_bits; -} - -void HELPER(ucf64_set_fpscr)(CPUUniCore32State *env, uint32_t val) -{ - UniCore32CPU *cpu = env_archcpu(env); - int i; - uint32_t changed; - - changed = env->ucf64.xregs[UC32_UCF64_FPSCR]; - env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK); - - changed ^= val; - if (changed & (UCF64_FPSCR_RND_MASK)) { - i = UCF64_FPSCR_RND(val); - switch (i) { - case 0: - i = float_round_nearest_even; - break; - case 1: - i = float_round_to_zero; - break; - case 2: - i = float_round_up; - break; - case 3: - i = float_round_down; - break; - default: /* 100 and 101 not implement */ - cpu_abort(CPU(cpu), "Unsupported UniCore-F64 round mode"); - } - set_float_rounding_mode(i, &env->ucf64.fp_status); - } - - i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val)); - set_float_exception_flags(i, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUUniCore32State *env) -{ - return float32_add(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUUniCore32State *env) -{ - return float64_add(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUUniCore32State *env) -{ - return float32_sub(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUUniCore32State *env) -{ - return float64_sub(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUUniCore32State *env) -{ - return float32_mul(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUUniCore32State *env) -{ - return float64_mul(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUUniCore32State *env) -{ - return float32_div(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUUniCore32State *env) -{ - return float64_div(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_negs)(float32 a) -{ - return float32_chs(a); -} - -float64 HELPER(ucf64_negd)(float64 a) -{ - return float64_chs(a); -} - -float32 HELPER(ucf64_abss)(float32 a) -{ - return float32_abs(a); -} - -float64 HELPER(ucf64_absd)(float64 a) -{ - return float64_abs(a); -} - -void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, - CPUUniCore32State *env) -{ - FloatRelation flag = float32_compare_quiet(a, b, &env->ucf64.fp_status); - env->CF = 0; - switch (c & 0x7) { - case 0: /* F */ - break; - case 1: /* UN */ - if (flag == 2) { - env->CF = 1; - } - break; - case 2: /* EQ */ - if (flag == 0) { - env->CF = 1; - } - break; - case 3: /* UEQ */ - if ((flag == 0) || (flag == 2)) { - env->CF = 1; - } - break; - case 4: /* OLT */ - if (flag == -1) { - env->CF = 1; - } - break; - case 5: /* ULT */ - if ((flag == -1) || (flag == 2)) { - env->CF = 1; - } - break; - case 6: /* OLE */ - if ((flag == -1) || (flag == 0)) { - env->CF = 1; - } - break; - case 7: /* ULE */ - if (flag != 1) { - env->CF = 1; - } - break; - } - env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29) - | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff); -} - -void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, - CPUUniCore32State *env) -{ - FloatRelation flag = float64_compare_quiet(a, b, &env->ucf64.fp_status); - env->CF = 0; - switch (c & 0x7) { - case 0: /* F */ - break; - case 1: /* UN */ - if (flag == 2) { - env->CF = 1; - } - break; - case 2: /* EQ */ - if (flag == 0) { - env->CF = 1; - } - break; - case 3: /* UEQ */ - if ((flag == 0) || (flag == 2)) { - env->CF = 1; - } - break; - case 4: /* OLT */ - if (flag == -1) { - env->CF = 1; - } - break; - case 5: /* ULT */ - if ((flag == -1) || (flag == 2)) { - env->CF = 1; - } - break; - case 6: /* OLE */ - if ((flag == -1) || (flag == 0)) { - env->CF = 1; - } - break; - case 7: /* ULE */ - if (flag != 1) { - env->CF = 1; - } - break; - } - env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29) - | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff); -} - -/* Helper routines to perform bitwise copies between float and int. */ -static inline float32 ucf64_itos(uint32_t i) -{ - union { - uint32_t i; - float32 s; - } v; - - v.i = i; - return v.s; -} - -static inline uint32_t ucf64_stoi(float32 s) -{ - union { - uint32_t i; - float32 s; - } v; - - v.s = s; - return v.i; -} - -/* Integer to float conversion. */ -float32 HELPER(ucf64_si2sf)(float32 x, CPUUniCore32State *env) -{ - return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_si2df)(float32 x, CPUUniCore32State *env) -{ - return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status); -} - -/* Float to integer conversion. */ -float32 HELPER(ucf64_sf2si)(float32 x, CPUUniCore32State *env) -{ - return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status)); -} - -float32 HELPER(ucf64_df2si)(float64 x, CPUUniCore32State *env) -{ - return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status)); -} - -/* floating point conversion */ -float64 HELPER(ucf64_sf2df)(float32 x, CPUUniCore32State *env) -{ - return float32_to_float64(x, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_df2sf)(float64 x, CPUUniCore32State *env) -{ - return float64_to_float32(x, &env->ucf64.fp_status); -} diff --git a/tests/qtest/machine-none-test.c b/tests/qtest/machine-none-test.c index 0ec1549648..138101b46a 100644 --- a/tests/qtest/machine-none-test.c +++ b/tests/qtest/machine-none-test.c @@ -49,7 +49,6 @@ static struct arch2cpu cpus_map[] = { { "sparc", "LEON2" }, { "sparc64", "Fujitsu Sparc64" }, { "tricore", "tc1796" }, - { "unicore32", "UniCore-II" }, { "xtensa", "dc233c" }, { "xtensaeb", "fsf" }, { "hppa", "hppa" }, From bf5dcf8f2cf61283a46aea14867adbec1a20fe3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 May 2021 09:07:13 +0200 Subject: [PATCH 0493/3028] backends/tpm: Replace qemu_mutex_lock calls with QEMU_LOCK_GUARD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the tpm_emulator_ctrlcmd() handler by replacing a pair of qemu_mutex_lock/qemu_mutex_unlock calls by the WITH_QEMU_LOCK_GUARD macro. Reviewed-by: Stefan Berger Reviewed-by: Christophe de Dinechin Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210512070713.3286188-1-philmd@redhat.com> Signed-off-by: Laurent Vivier --- backends/tpm/tpm_emulator.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c index a012adc193..e5f1063ab6 100644 --- a/backends/tpm/tpm_emulator.c +++ b/backends/tpm/tpm_emulator.c @@ -30,6 +30,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qemu/sockets.h" +#include "qemu/lockable.h" #include "io/channel-socket.h" #include "sysemu/tpm_backend.h" #include "sysemu/tpm_util.h" @@ -124,31 +125,26 @@ static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg, uint32_t cmd_no = cpu_to_be32(cmd); ssize_t n = sizeof(uint32_t) + msg_len_in; uint8_t *buf = NULL; - int ret = -1; - qemu_mutex_lock(&tpm->mutex); + WITH_QEMU_LOCK_GUARD(&tpm->mutex) { + buf = g_alloca(n); + memcpy(buf, &cmd_no, sizeof(cmd_no)); + memcpy(buf + sizeof(cmd_no), msg, msg_len_in); - buf = g_alloca(n); - memcpy(buf, &cmd_no, sizeof(cmd_no)); - memcpy(buf + sizeof(cmd_no), msg, msg_len_in); - - n = qemu_chr_fe_write_all(dev, buf, n); - if (n <= 0) { - goto end; - } - - if (msg_len_out != 0) { - n = qemu_chr_fe_read_all(dev, msg, msg_len_out); + n = qemu_chr_fe_write_all(dev, buf, n); if (n <= 0) { - goto end; + return -1; + } + + if (msg_len_out != 0) { + n = qemu_chr_fe_read_all(dev, msg, msg_len_out); + if (n <= 0) { + return -1; + } } } - ret = 0; - -end: - qemu_mutex_unlock(&tpm->mutex); - return ret; + return 0; } static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, From 989f622d418a81051ee8a2cb3942d18fcf5e3937 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 May 2021 12:41:55 +0200 Subject: [PATCH 0494/3028] hw/virtio: Pass virtio_feature_get_config_size() a const argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VirtIOFeature structure isn't modified, mark it const. Signed-off-by: Philippe Mathieu-Daudé Acked-by: Jason Wang Reviewed-by: Richard Henderson Reviewed-by: Stefan Hajnoczi Reviewed-by: Stefano Garzarella Message-Id: <20210511104157.2880306-2-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/virtio/virtio.c | 2 +- include/hw/virtio/virtio.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 9e13cb9e3a..e02544b2df 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2981,7 +2981,7 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val) return ret; } -size_t virtio_feature_get_config_size(VirtIOFeature *feature_sizes, +size_t virtio_feature_get_config_size(const VirtIOFeature *feature_sizes, uint64_t host_features) { size_t config_size = 0; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index b7ece7a6a8..8bab9cfb75 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -43,7 +43,7 @@ typedef struct VirtIOFeature { size_t end; } VirtIOFeature; -size_t virtio_feature_get_config_size(VirtIOFeature *features, +size_t virtio_feature_get_config_size(const VirtIOFeature *features, uint64_t host_features); typedef struct VirtQueue VirtQueue; From f212f3e7f868cb0e82fdf2d68e83adcad4e33730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 May 2021 12:41:56 +0200 Subject: [PATCH 0495/3028] virtio-blk: Constify VirtIOFeature feature_sizes[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Acked-by: Jason Wang Reviewed-by: Richard Henderson Reviewed-by: Stefan Hajnoczi Reviewed-by: Stefano Garzarella Message-Id: <20210511104157.2880306-3-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/block/virtio-blk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index d28979efb8..f139cd7cc9 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -40,7 +40,7 @@ * Starting from the discard feature, we can use this array to properly * set the config size depending on the features enabled. */ -static VirtIOFeature feature_sizes[] = { +static const VirtIOFeature feature_sizes[] = { {.flags = 1ULL << VIRTIO_BLK_F_DISCARD, .end = endof(struct virtio_blk_config, discard_sector_alignment)}, {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES, From 28cbc87be58b490a31f5c2697c79cf0534cd3fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 May 2021 12:41:57 +0200 Subject: [PATCH 0496/3028] virtio-net: Constify VirtIOFeature feature_sizes[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Acked-by: Jason Wang Reviewed-by: Richard Henderson Reviewed-by: Stefan Hajnoczi Reviewed-by: Stefano Garzarella Message-Id: <20210511104157.2880306-4-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/net/virtio-net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 66b9ff4511..6b7e8dd04e 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -89,7 +89,7 @@ VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \ VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) -static VirtIOFeature feature_sizes[] = { +static const VirtIOFeature feature_sizes[] = { {.flags = 1ULL << VIRTIO_NET_F_MAC, .end = endof(struct virtio_net_config, mac)}, {.flags = 1ULL << VIRTIO_NET_F_STATUS, From 4962b312cd2a09902efdf34d91f529164e321b8d Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Fri, 7 May 2021 18:12:28 +0200 Subject: [PATCH 0497/3028] virtiofsd: Fix check of chown()'s return value Otherwise you always get this warning when using --socket-group=users vhost socket failed to set group to users (100) While here, print out the error if chown() fails. Fixes: f6698f2b03b0 ("tools/virtiofsd: add support for --socket-group") Signed-off-by: Greg Kurz Reviewed-by: Dr. David Alan Gilbert Message-Id: <162040394890.714971.15502455176528384778.stgit@bahia.lan> Signed-off-by: Laurent Vivier --- tools/virtiofsd/fuse_virtio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c index 1170f375a5..9efdbd8ffd 100644 --- a/tools/virtiofsd/fuse_virtio.c +++ b/tools/virtiofsd/fuse_virtio.c @@ -1024,9 +1024,9 @@ static int fv_create_listen_socket(struct fuse_session *se) if (se->vu_socket_group) { struct group *g = getgrnam(se->vu_socket_group); if (g) { - if (!chown(se->vu_socket_path, -1, g->gr_gid)) { + if (chown(se->vu_socket_path, -1, g->gr_gid) == -1) { fuse_log(FUSE_LOG_WARNING, - "vhost socket failed to set group to %s (%d)\n", + "vhost socket failed to set group to %s (%d): %m\n", se->vu_socket_group, g->gr_gid); } } From 09ceb33091ab50ea632727d105057f2bd6324672 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sat, 8 May 2021 12:33:15 +0300 Subject: [PATCH 0498/3028] qapi: spelling fix (addtional) Fixes: 3d0d3c30ae3a259bff176f85a3efa2d0816695af Signed-off-by: Michael Tokarev Reviewed-by: Kevin Wolf Message-Id: <20210508093315.393274-1-mjt@msgid.tls.msk.ru> Signed-off-by: Laurent Vivier --- qapi/qom.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qapi/qom.json b/qapi/qom.json index cd0e76d564..40d70c434a 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -251,8 +251,8 @@ # # @max_queue_size: the maximum number of packets to keep in the queue for # comparing with incoming packets from @secondary_in. If the -# queue is full and addtional packets are received, the -# addtional packets are dropped. (default: 1024) +# queue is full and additional packets are received, the +# additional packets are dropped. (default: 1024) # # @vnet_hdr_support: if true, vnet header support is enabled (default: false) # From bcfec3763e44b6996384272bf43fbcfce7f45c57 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Sat, 8 May 2021 12:36:15 +0300 Subject: [PATCH 0499/3028] hw/gpio/aspeed: spelling fix (addtional) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 36d737ee82b2972167e97901c5271ba3f904ba71 Signed-off-by: Michael Tokarev Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210508093615.411920-1-mjt@msgid.tls.msk.ru> Signed-off-by: Laurent Vivier --- hw/gpio/aspeed_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index 985a259e05..34d8acb0e3 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -170,7 +170,7 @@ /* AST2600 only - 1.8V gpios */ /* * The AST2600 has same 3.6V gpios as the AST2400 (memory offsets 0x0-0x198) - * and addtional 1.8V gpios (memory offsets 0x800-0x9D4). + * and additional 1.8V gpios (memory offsets 0x800-0x9D4). */ #define GPIO_1_8V_REG_OFFSET 0x800 #define GPIO_1_8V_ABCD_DATA_VALUE ((0x800 - GPIO_1_8V_REG_OFFSET) >> 2) From 72fe4742c6e7fa3d237b5cb5866dfaf7733141e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 2 May 2021 18:39:30 +0200 Subject: [PATCH 0500/3028] hw/timer/etraxfs_timer: Convert to 3-phase reset (Resettable interface) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TYPE_ETRAX_FS_TIMER is a sysbus device, so its DeviceClass::reset() handler is called automatically when its qbus parent is reset (we don't need to register it manually). Convert the generic reset to a enter/hold resettable ones, and remove the qemu_register_reset() call. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Message-Id: <20210502163931.552675-2-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/timer/etraxfs_timer.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index 5379006086..4ba662190d 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -309,9 +309,9 @@ static const MemoryRegionOps timer_ops = { } }; -static void etraxfs_timer_reset(void *opaque) +static void etraxfs_timer_reset_enter(Object *obj, ResetType type) { - ETRAXTimerState *t = opaque; + ETRAXTimerState *t = ETRAX_TIMER(obj); ptimer_transaction_begin(t->ptimer_t0); ptimer_stop(t->ptimer_t0); @@ -325,6 +325,12 @@ static void etraxfs_timer_reset(void *opaque) t->rw_wd_ctrl = 0; t->r_intr = 0; t->rw_intr_mask = 0; +} + +static void etraxfs_timer_reset_hold(Object *obj) +{ + ETRAXTimerState *t = ETRAX_TIMER(obj); + qemu_irq_lower(t->irq); } @@ -343,14 +349,16 @@ static void etraxfs_timer_realize(DeviceState *dev, Error **errp) memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, "etraxfs-timer", 0x5c); sysbus_init_mmio(sbd, &t->mmio); - qemu_register_reset(etraxfs_timer_reset, t); } static void etraxfs_timer_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); dc->realize = etraxfs_timer_realize; + rc->phases.enter = etraxfs_timer_reset_enter; + rc->phases.hold = etraxfs_timer_reset_hold; } static const TypeInfo etraxfs_timer_info = { From fae5a0420754453beca3407250899254fb6745a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 2 May 2021 18:39:31 +0200 Subject: [PATCH 0501/3028] hw/rtc/mc146818rtc: Convert to 3-phase reset (Resettable interface) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TYPE_MC146818_RTC is an ISA device, so its DeviceClass::reset() handler is called automatically when its qbus parent is reset (we don't need to register it manually). We have 2 reset() methods: a generic one and the qdev one. Merge them into a reset_enter handler (keeping the IRQ lowering to a reset_hold one), and remove the qemu_register_reset() call. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Message-Id: <20210502163931.552675-3-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/rtc/mc146818rtc.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 3d2d3854e7..4fbafddb22 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -871,22 +871,6 @@ static void rtc_notify_suspend(Notifier *notifier, void *data) rtc_set_memory(ISA_DEVICE(s), 0xF, 0xFE); } -static void rtc_reset(void *opaque) -{ - RTCState *s = opaque; - - s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE); - s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF); - check_update_timer(s); - - qemu_irq_lower(s->irq); - - if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { - s->irq_coalesced = 0; - s->irq_reinject_on_ack_count = 0; - } -} - static const MemoryRegionOps cmos_ops = { .read = cmos_ioport_read, .write = cmos_ioport_write, @@ -961,7 +945,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) memory_region_add_coalescing(&s->coalesced_io, 0, 1); qdev_set_legacy_instance_id(dev, RTC_ISA_BASE, 3); - qemu_register_reset(rtc_reset, s); object_property_add_tm(OBJECT(s), "date", rtc_get_date); @@ -997,15 +980,32 @@ static Property mc146818rtc_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void rtc_resetdev(DeviceState *d) +static void rtc_reset_enter(Object *obj, ResetType type) { - RTCState *s = MC146818_RTC(d); + RTCState *s = MC146818_RTC(obj); /* Reason: VM do suspend self will set 0xfe * Reset any values other than 0xfe(Guest suspend case) */ if (s->cmos_data[0x0f] != 0xfe) { s->cmos_data[0x0f] = 0x00; } + + s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE); + s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF); + check_update_timer(s); + + + if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) { + s->irq_coalesced = 0; + s->irq_reinject_on_ack_count = 0; + } +} + +static void rtc_reset_hold(Object *obj) +{ + RTCState *s = MC146818_RTC(obj); + + qemu_irq_lower(s->irq); } static void rtc_build_aml(ISADevice *isadev, Aml *scope) @@ -1032,11 +1032,13 @@ static void rtc_build_aml(ISADevice *isadev, Aml *scope) static void rtc_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); ISADeviceClass *isa = ISA_DEVICE_CLASS(klass); dc->realize = rtc_realizefn; - dc->reset = rtc_resetdev; dc->vmsd = &vmstate_rtc; + rc->phases.enter = rtc_reset_enter; + rc->phases.hold = rtc_reset_hold; isa->build_aml = rtc_build_aml; device_class_set_props(dc, mc146818rtc_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); From b6d003dbee81f1bf419c7cceec0c4c358184a601 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Mon, 12 Apr 2021 19:02:55 +0200 Subject: [PATCH 0502/3028] cutils: fix memory leak in get_relocated_path() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_relocated_path() allocates a GString object and returns the character data (C string) to the caller without freeing the memory allocated for that object as reported by valgrind: 24 bytes in 1 blocks are definitely lost in loss record 2,805 of 6,532 at 0x4839809: malloc (vg_replace_malloc.c:307) by 0x55AABB8: g_malloc (in /usr/lib64/libglib-2.0.so.0.6600.8) by 0x55C2481: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.6600.8) by 0x55C4827: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.6600.8) by 0x55C4CEA: g_string_new (in /usr/lib64/libglib-2.0.so.0.6600.8) by 0x906314: get_relocated_path (cutils.c:1036) by 0x6E1F77: qemu_read_default_config_file (vl.c:2122) by 0x6E1F77: qemu_init (vl.c:2687) by 0x3E3AF8: main (main.c:49) Let's use g_string_free(gstring, false) to free only the GString object and transfer the ownership of the character data to the caller. Fixes: f4f5ed2cbd ("cutils: introduce get_relocated_path") Signed-off-by: Stefano Garzarella Reviewed-by: Marc-André Lureau Reviewed-by: Markus Armbruster Message-Id: <20210412170255.231406-1-sgarzare@redhat.com> Signed-off-by: Laurent Vivier --- util/cutils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/cutils.c b/util/cutils.c index ee908486da..c9b91e7535 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -1055,5 +1055,5 @@ char *get_relocated_path(const char *dir) assert(G_IS_DIR_SEPARATOR(dir[-1])); g_string_append(result, dir - 1); } - return result->str; + return g_string_free(result, false); } From b51d44677193002926a7519df89153df847f5f6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 6 Apr 2021 15:39:44 +0200 Subject: [PATCH 0503/3028] hw/mem/meson: Fix linking sparse-mem device with fuzzer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sparse-mem.c is added to the 'mem_ss' source set, which itself is conditionally added to softmmu_ss if CONFIG_MEM_DEVICE is selected. But if CONFIG_MEM_DEVICE isn't selected, we get a link failure even if CONFIG_FUZZ is selected: /usr/bin/ld: tests_qtest_fuzz_generic_fuzz.c.o: in function `generic_pre_fuzz': tests/qtest/fuzz/generic_fuzz.c:826: undefined reference to `sparse_mem_init' clang-10: error: linker command failed with exit code 1 (use -v to see invocation) Fix by adding sparse-mem.c directly to the softmmu_ss set. Fixes: 230376d285b ("memory: add a sparse memory device for fuzzing") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alexander Bulekov Message-Id: <20210406133944.4193691-1-philmd@redhat.com> Signed-off-by: Laurent Vivier --- hw/mem/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/mem/meson.build b/hw/mem/meson.build index ef79e04678..3c8fdef9f9 100644 --- a/hw/mem/meson.build +++ b/hw/mem/meson.build @@ -1,8 +1,9 @@ mem_ss = ss.source_set() mem_ss.add(files('memory-device.c')) -mem_ss.add(when: 'CONFIG_FUZZ', if_true: files('sparse-mem.c')) mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c')) mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c')) mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c')) softmmu_ss.add_all(when: 'CONFIG_MEM_DEVICE', if_true: mem_ss) + +softmmu_ss.add(when: 'CONFIG_FUZZ', if_true: files('sparse-mem.c')) From 4872fdf71b52288105ae5513f892f39633bec28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 25 Apr 2021 20:21:24 +0200 Subject: [PATCH 0504/3028] hw/pci-host: Do not build gpex-acpi.c if GPEX is not selected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since its introduction in commit 5b85eabe68f ("acpi: add acpi_dsdt_add_gpex") we build gpex-acpi.c if ACPI is selected, even if the GPEX_HOST device isn't build. Add the missing Kconfig dependency. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Reviewed-by: Gerd Hoffmann Message-Id: <20210425182124.3735214-1-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- hw/pci-host/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index 34b3538beb..1698d3a192 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -3,7 +3,7 @@ pci_ss.add(when: 'CONFIG_PAM', if_true: files('pam.c')) pci_ss.add(when: 'CONFIG_PCI_BONITO', if_true: files('bonito.c')) pci_ss.add(when: 'CONFIG_PCI_EXPRESS_DESIGNWARE', if_true: files('designware.c')) pci_ss.add(when: 'CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', if_true: files('gpex.c')) -pci_ss.add(when: 'CONFIG_ACPI', if_true: files('gpex-acpi.c')) +pci_ss.add(when: ['CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', 'CONFIG_ACPI'], if_true: files('gpex-acpi.c')) pci_ss.add(when: 'CONFIG_PCI_EXPRESS_Q35', if_true: files('q35.c')) pci_ss.add(when: 'CONFIG_PCI_EXPRESS_XILINX', if_true: files('xilinx-pcie.c')) pci_ss.add(when: 'CONFIG_PCI_I440FX', if_true: files('i440fx.c')) From dcf20655ffca2b0219d2914db4aadcce4b61fa0a Mon Sep 17 00:00:00 2001 From: Jagannathan Raman Date: Fri, 7 May 2021 11:53:23 -0400 Subject: [PATCH 0505/3028] multi-process: Avoid logical AND of mutually exclusive tests Fixes an if statement that performs a logical AND of mutually exclusive tests Buglink: https://bugs.launchpad.net/qemu/+bug/1926995 Reviewed-by: Thomas Huth Signed-off-by: Jagannathan Raman Reviewed-by: Thomas Huth Reviewed-by: Stefan Hajnoczi Message-Id: <1620402803-9237-1-git-send-email-jag.raman@oracle.com> Signed-off-by: Laurent Vivier --- hw/remote/mpqemu-link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c index 9ce31526e8..e67a5de72c 100644 --- a/hw/remote/mpqemu-link.c +++ b/hw/remote/mpqemu-link.c @@ -218,7 +218,7 @@ uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev, bool mpqemu_msg_valid(MPQemuMsg *msg) { - if (msg->cmd >= MPQEMU_CMD_MAX && msg->cmd < 0) { + if (msg->cmd >= MPQEMU_CMD_MAX || msg->cmd < 0) { return false; } From 52a1c621f9d56d18212273c64b4119513a2db1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 5 May 2021 18:10:46 +0200 Subject: [PATCH 0506/3028] target/sh4: Return error if CPUClass::get_phys_page_debug() fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the get_physical_address() call fails, the SH4 get_phys_page_debug() handler returns an uninitialized address. Instead return -1, which correspond to "no page found" (see cpu_get_phys_page_debug() doc string). This fixes a warning emitted when building with CFLAGS=-O3 (using GCC 10.2.1 20201125): target/sh4/helper.c: In function ‘superh_cpu_get_phys_page_debug’: target/sh4/helper.c:446:12: warning: ‘physical’ may be used uninitialized in this function [-Wmaybe-uninitialized] 446 | return physical; | ^~~~~~~~ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Yoshinori Sato Message-Id: <20210505161046.1397608-1-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- target/sh4/helper.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target/sh4/helper.c b/target/sh4/helper.c index bd8e034f17..2d622081e8 100644 --- a/target/sh4/helper.c +++ b/target/sh4/helper.c @@ -441,9 +441,12 @@ hwaddr superh_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) target_ulong physical; int prot; - get_physical_address(&cpu->env, &physical, &prot, addr, MMU_DATA_LOAD); + if (get_physical_address(&cpu->env, &physical, &prot, addr, MMU_DATA_LOAD) + == MMU_OK) { + return physical; + } - return physical; + return -1; } void cpu_load_tlb(CPUSH4State * env) From 6cd04a88fa3fc5941fcd3677355e1b75efe9c7a8 Mon Sep 17 00:00:00 2001 From: Frederic Konrad Date: Wed, 28 Apr 2021 21:15:19 +0200 Subject: [PATCH 0507/3028] hw/avr/atmega.c: use the avr51 cpu for atmega1280 According to the as documentation: (https://sourceware.org/binutils/docs-2.36/as/AVR-Options.html) "Instruction set avr51 is for the enhanced AVR core with exactly 128K program memory space (MCU types: atmega128, atmega128a, atmega1280, atmega1281, atmega1284, atmega1284p, atmega128rfa1, atmega128rfr2, atmega1284rfr2, at90can128, at90usb1286, at90usb1287, m3000)." But when compiling a program for atmega1280 or avr51 and trying to execute it: $ cat > test.S << EOF > loop: > rjmp loop > EOF $ avr-gcc -nostdlib -nostartfiles -mmcu=atmega1280 test.S -o test.elf $ qemu-system-avr -serial mon:stdio -nographic -no-reboot -M mega \ -bios test.elf qemu-system-avr: Current machine: Arduino Mega (ATmega1280) with 'avr6' CPU qemu-system-avr: ELF image 'test.elf' is for 'avr51' CPU So this fixes the atmega1280 class to use an avr51 CPU. Signed-off-by: Frederic Konrad Reviewed-by: Joaquin de Andres Message-Id: <1619637319-22299-1-git-send-email-frederic.konrad@adacore.com> Signed-off-by: Laurent Vivier --- hw/avr/atmega.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c index 80b8a41cb5..0608e2d475 100644 --- a/hw/avr/atmega.c +++ b/hw/avr/atmega.c @@ -401,7 +401,7 @@ static void atmega1280_class_init(ObjectClass *oc, void *data) { AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc); - amc->cpu_type = AVR_CPU_TYPE_NAME("avr6"); + amc->cpu_type = AVR_CPU_TYPE_NAME("avr51"); amc->flash_size = 128 * KiB; amc->eeprom_size = 4 * KiB; amc->sram_size = 8 * KiB; From 29f9c636894c462fa54fad08049e51877905e93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 2 May 2021 21:09:00 +0200 Subject: [PATCH 0508/3028] target/avr: Ignore unimplemented WDR opcode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running the WDR opcode triggers a segfault: $ cat > foo.S << EOF > __start: > wdr > EOF $ avr-gcc -nostdlib -nostartfiles -mmcu=avr6 foo.S -o foo.elf $ qemu-system-avr -serial mon:stdio -nographic -no-reboot \ -M mega -bios foo.elf -d in_asm --singlestep IN: 0x00000000: WDR Segmentation fault (core dumped) (gdb) bt #0 0x00005555add0b23a in gdb_get_cpu_pid (cpu=0x5555af5a4af0) at ../gdbstub.c:718 #1 0x00005555add0b2dd in gdb_get_cpu_process (cpu=0x5555af5a4af0) at ../gdbstub.c:743 #2 0x00005555add0e477 in gdb_set_stop_cpu (cpu=0x5555af5a4af0) at ../gdbstub.c:2742 #3 0x00005555adc99b96 in cpu_handle_guest_debug (cpu=0x5555af5a4af0) at ../softmmu/cpus.c:306 #4 0x00005555adcc66ab in rr_cpu_thread_fn (arg=0x5555af5a4af0) at ../accel/tcg/tcg-accel-ops-rr.c:224 #5 0x00005555adefaf12 in qemu_thread_start (args=0x5555af5d9870) at ../util/qemu-thread-posix.c:521 #6 0x00007f692d940ea5 in start_thread () from /lib64/libpthread.so.0 #7 0x00007f692d6699fd in clone () from /lib64/libc.so.6 Since the watchdog peripheral is not implemented, simply log the opcode as unimplemented and keep going. Reported-by: Fred Konrad Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: KONRAD Frederic Message-Id: <20210502190900.604292-1-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- target/avr/helper.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/target/avr/helper.c b/target/avr/helper.c index 35e1019594..981c29da45 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -188,11 +188,7 @@ void helper_break(CPUAVRState *env) void helper_wdr(CPUAVRState *env) { - CPUState *cs = env_cpu(env); - - /* WD is not implemented yet, placeholder */ - cs->exception_index = EXCP_DEBUG; - cpu_loop_exit(cs); + qemu_log_mask(LOG_UNIMP, "WDG reset (not implemented)\n"); } /* From 1a37352277763220739290c689867540ec193d06 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 16 Feb 2021 11:50:39 +0100 Subject: [PATCH 0509/3028] migrate/ram: remove "ram_bulk_stage" and "fpo_enabled" The bulk stage is kind of weird: migration_bitmap_find_dirty() will indicate a dirty page, however, ram_save_host_page() will never save it, as migration_bitmap_clear_dirty() detects that it is not dirty. We already fill the bitmap in ram_list_init_bitmaps() with ones, marking everything dirty - it didn't used to be that way, which is why we needed an explicit first bulk stage. Let's simplify: make the bitmap the single source of thuth. Explicitly handle the "xbzrle_enabled after first round" case. Regarding XBZRLE (implicitly handled via "ram_bulk_stage = false" right now), there is now a slight change in behavior: - Colo: When starting, it will be disabled (was implicitly enabled) until the first round actually finishes. - Free page hinting: When starting, XBZRLE will be disabled (was implicitly enabled) until the first round actually finished. - Snapshots: When starting, XBZRLE will be disabled. We essentially only do a single run, so I guess it will never actually get disabled. Postcopy seems to indirectly disable it in ram_save_page(), so there shouldn't be really any change. Cc: "Michael S. Tsirkin" Cc: Juan Quintela Cc: "Dr. David Alan Gilbert" Cc: Andrey Gruzdev Cc: Peter Xu Signed-off-by: David Hildenbrand Message-Id: <20210216105039.40680-1-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- hw/virtio/virtio-balloon.c | 4 +- hw/virtio/virtio-mem.c | 3 -- include/migration/misc.h | 1 - migration/ram.c | 78 +++++++++----------------------------- 4 files changed, 18 insertions(+), 68 deletions(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index d120bf8f43..4b5d9e5e50 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -663,9 +663,6 @@ virtio_balloon_free_page_hint_notify(NotifierWithReturn *n, void *data) } switch (pnd->reason) { - case PRECOPY_NOTIFY_SETUP: - precopy_enable_free_page_optimization(); - break; case PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC: virtio_balloon_free_page_stop(dev); break; @@ -685,6 +682,7 @@ virtio_balloon_free_page_hint_notify(NotifierWithReturn *n, void *data) */ virtio_balloon_free_page_done(dev); break; + case PRECOPY_NOTIFY_SETUP: case PRECOPY_NOTIFY_COMPLETE: break; default: diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 655824ff81..75aa7d6f1b 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -902,9 +902,6 @@ static int virtio_mem_precopy_notify(NotifierWithReturn *n, void *data) PrecopyNotifyData *pnd = data; switch (pnd->reason) { - case PRECOPY_NOTIFY_SETUP: - precopy_enable_free_page_optimization(); - break; case PRECOPY_NOTIFY_AFTER_BITMAP_SYNC: virtio_mem_precopy_exclude_unplugged(vmem); break; diff --git a/include/migration/misc.h b/include/migration/misc.h index 738675ef52..465906710d 100644 --- a/include/migration/misc.h +++ b/include/migration/misc.h @@ -37,7 +37,6 @@ void precopy_infrastructure_init(void); void precopy_add_notifier(NotifierWithReturn *n); void precopy_remove_notifier(NotifierWithReturn *n); int precopy_notify(PrecopyNotifyReason reason, Error **errp); -void precopy_enable_free_page_optimization(void); void ram_mig_init(void); void qemu_guest_free_page_hint(void *addr, size_t len); diff --git a/migration/ram.c b/migration/ram.c index ace8ad431c..bee2756cd3 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -311,10 +311,6 @@ struct RAMState { ram_addr_t last_page; /* last ram version we have seen */ uint32_t last_version; - /* We are in the first round */ - bool ram_bulk_stage; - /* The free page optimization is enabled */ - bool fpo_enabled; /* How many times we have dirty too many pages */ int dirty_rate_high_cnt; /* these variables are used for bitmap sync */ @@ -330,6 +326,8 @@ struct RAMState { uint64_t xbzrle_pages_prev; /* Amount of xbzrle encoded bytes since the beginning of the period */ uint64_t xbzrle_bytes_prev; + /* Start using XBZRLE (e.g., after the first round). */ + bool xbzrle_enabled; /* compression statistics since the beginning of the period */ /* amount of count that no free thread to compress data */ @@ -383,15 +381,6 @@ int precopy_notify(PrecopyNotifyReason reason, Error **errp) return notifier_with_return_list_notify(&precopy_notifier_list, &pnd); } -void precopy_enable_free_page_optimization(void) -{ - if (!ram_state) { - return; - } - - ram_state->fpo_enabled = true; -} - uint64_t ram_bytes_remaining(void) { return ram_state ? (ram_state->migration_dirty_pages * TARGET_PAGE_SIZE) : @@ -664,7 +653,7 @@ static void mig_throttle_guest_down(uint64_t bytes_dirty_period, */ static void xbzrle_cache_zero_page(RAMState *rs, ram_addr_t current_addr) { - if (rs->ram_bulk_stage || !migrate_use_xbzrle()) { + if (!rs->xbzrle_enabled) { return; } @@ -792,23 +781,12 @@ unsigned long migration_bitmap_find_dirty(RAMState *rs, RAMBlock *rb, { unsigned long size = rb->used_length >> TARGET_PAGE_BITS; unsigned long *bitmap = rb->bmap; - unsigned long next; if (ramblock_is_ignored(rb)) { return size; } - /* - * When the free page optimization is enabled, we need to check the bitmap - * to send the non-free pages rather than all the pages in the bulk stage. - */ - if (!rs->fpo_enabled && rs->ram_bulk_stage && start > 0) { - next = start + 1; - } else { - next = find_next_bit(bitmap, size, start); - } - - return next; + return find_next_bit(bitmap, size, start); } static inline bool migration_bitmap_clear_dirty(RAMState *rs, @@ -1185,8 +1163,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) trace_ram_save_page(block->idstr, (uint64_t)offset, p); XBZRLE_cache_lock(); - if (!rs->ram_bulk_stage && !migration_in_postcopy() && - migrate_use_xbzrle()) { + if (rs->xbzrle_enabled && !migration_in_postcopy()) { pages = save_xbzrle_page(rs, &p, current_addr, block, offset, last_stage); if (!last_stage) { @@ -1386,7 +1363,10 @@ static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again) pss->block = QLIST_FIRST_RCU(&ram_list.blocks); /* Flag that we've looped */ pss->complete_round = true; - rs->ram_bulk_stage = false; + /* After the first round, enable XBZRLE. */ + if (migrate_use_xbzrle()) { + rs->xbzrle_enabled = true; + } } /* Didn't find anything this time, but try again on the new block */ *again = true; @@ -1800,14 +1780,6 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss) } if (block) { - /* - * As soon as we start servicing pages out of order, then we have - * to kill the bulk stage, since the bulk stage assumes - * in (migration_bitmap_find_and_reset_dirty) that every page is - * dirty, that's no longer true. - */ - rs->ram_bulk_stage = false; - /* * We want the background search to continue from the queued page * since the guest is likely to want other pages near to the page @@ -1920,15 +1892,15 @@ static bool save_page_use_compression(RAMState *rs) } /* - * If xbzrle is on, stop using the data compression after first - * round of migration even if compression is enabled. In theory, - * xbzrle can do better than compression. + * If xbzrle is enabled (e.g., after first round of migration), stop + * using the data compression. In theory, xbzrle can do better than + * compression. */ - if (rs->ram_bulk_stage || !migrate_use_xbzrle()) { - return true; + if (rs->xbzrle_enabled) { + return false; } - return false; + return true; } /* @@ -2235,8 +2207,7 @@ static void ram_state_reset(RAMState *rs) rs->last_sent_block = NULL; rs->last_page = 0; rs->last_version = ram_list.version; - rs->ram_bulk_stage = true; - rs->fpo_enabled = false; + rs->xbzrle_enabled = false; } #define MAX_WAIT 50 /* ms, half buffered_file limit */ @@ -2720,15 +2691,7 @@ static void ram_state_resume_prepare(RAMState *rs, QEMUFile *out) /* This may not be aligned with current bitmaps. Recalculate. */ rs->migration_dirty_pages = pages; - rs->last_seen_block = NULL; - rs->last_sent_block = NULL; - rs->last_page = 0; - rs->last_version = ram_list.version; - /* - * Disable the bulk stage, otherwise we'll resend the whole RAM no - * matter what we have sent. - */ - rs->ram_bulk_stage = false; + ram_state_reset(rs); /* Update RAMState cache of output QEMUFile */ rs->f = out; @@ -3345,16 +3308,9 @@ static void decompress_data_with_multi_threads(QEMUFile *f, } } - /* - * we must set ram_bulk_stage to false, otherwise in - * migation_bitmap_find_dirty the bitmap will be unused and - * all the pages in ram cache wil be flushed to the ram of - * secondary VM. - */ static void colo_init_ram_state(void) { ram_state_init(&ram_state); - ram_state->ram_bulk_stage = false; } /* From 23feba906e42747463aa233fb54c58d7f02430c9 Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Tue, 16 Mar 2021 20:57:15 +0800 Subject: [PATCH 0510/3028] migration/ram: Reduce unnecessary rate limiting When the host page is a huge page and something is sent in the current iteration, migration_rate_limit() should be executed. If not, it can be omitted. Signed-off-by: Keqian Zhu Signed-off-by: Kunkun Jiang Reviewed-by: David Edmondson Reviewed-by: Dr. David Alan Gilbert Message-Id: <20210316125716.1243-2-jiangkunkun@huawei.com> Signed-off-by: Dr. David Alan Gilbert --- migration/ram.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index bee2756cd3..00b579b981 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2035,8 +2035,13 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, pages += tmppages; pss->page++; - /* Allow rate limiting to happen in the middle of huge pages */ - migration_rate_limit(); + /* + * Allow rate limiting to happen in the middle of huge pages if + * something is sent in the current iteration. + */ + if (pagesize_bits > 1 && tmppages > 0) { + migration_rate_limit(); + } } while ((pss->page & (pagesize_bits - 1)) && offset_in_ramblock(pss->block, ((ram_addr_t)pss->page) << TARGET_PAGE_BITS)); From ba1b7c812c1efa49f9c297b6a22c598ff0eb5a4b Mon Sep 17 00:00:00 2001 From: Kunkun Jiang Date: Tue, 16 Mar 2021 20:57:16 +0800 Subject: [PATCH 0511/3028] migration/ram: Optimize ram_save_host_page() Starting from pss->page, ram_save_host_page() will check every page and send the dirty pages up to the end of the current host page or the boundary of used_length of the block. If the host page size is a huge page, the step "check" will take a lot of time. It will improve performance to use migration_bitmap_find_dirty(). Tested on Kunpeng 920; VM parameters: 1U 4G (page size 1G) The time of ram_save_host_page() in the last round of ram saving: before optimize: 9250us after optimize: 34us Signed-off-by: Keqian Zhu Signed-off-by: Kunkun Jiang Reviewed-by: Peter Xu Message-Id: <20210316125716.1243-3-jiangkunkun@huawei.com> Signed-off-by: Dr. David Alan Gilbert --- migration/ram.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 00b579b981..bb52bd97db 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -2013,6 +2013,8 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, int tmppages, pages = 0; size_t pagesize_bits = qemu_ram_pagesize(pss->block) >> TARGET_PAGE_BITS; + unsigned long hostpage_boundary = + QEMU_ALIGN_UP(pss->page + 1, pagesize_bits); unsigned long start_page = pss->page; int res; @@ -2023,30 +2025,27 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss, do { /* Check the pages is dirty and if it is send it */ - if (!migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { - pss->page++; - continue; - } + if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) { + tmppages = ram_save_target_page(rs, pss, last_stage); + if (tmppages < 0) { + return tmppages; + } - tmppages = ram_save_target_page(rs, pss, last_stage); - if (tmppages < 0) { - return tmppages; + pages += tmppages; + /* + * Allow rate limiting to happen in the middle of huge pages if + * something is sent in the current iteration. + */ + if (pagesize_bits > 1 && tmppages > 0) { + migration_rate_limit(); + } } - - pages += tmppages; - pss->page++; - /* - * Allow rate limiting to happen in the middle of huge pages if - * something is sent in the current iteration. - */ - if (pagesize_bits > 1 && tmppages > 0) { - migration_rate_limit(); - } - } while ((pss->page & (pagesize_bits - 1)) && + pss->page = migration_bitmap_find_dirty(rs, pss->block, pss->page); + } while ((pss->page < hostpage_boundary) && offset_in_ramblock(pss->block, ((ram_addr_t)pss->page) << TARGET_PAGE_BITS)); - /* The offset we leave with is the last one we looked at */ - pss->page--; + /* The offset we leave with is the min boundary of host page and block */ + pss->page = MIN(pss->page, hostpage_boundary) - 1; res = ram_save_release_protection(rs, pss, start_page); return (res < 0 ? res : pages); From 372043f389126bf6bb4ba88b970f3dfcaf86b722 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 29 Apr 2021 16:04:24 +0200 Subject: [PATCH 0512/3028] migration: Drop redundant query-migrate result @blocked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Result @blocked is redundant. Unfortunately, we realized this too close to the release to risk dropping it, so we deprecated it instead, in commit e11ce6c06. Since it was deprecated from the start, we can delete it without the customary grace period. Do so. Signed-off-by: Markus Armbruster Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Daniel P. Berrangé Message-Id: <20210429140424.2802929-1-armbru@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- migration/migration.c | 29 +++++++++++++---------------- monitor/hmp-cmds.c | 2 +- qapi/migration.json | 6 ------ 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 8ca034136b..fdadee290e 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1073,27 +1073,24 @@ static void populate_vfio_info(MigrationInfo *info) static void fill_source_migration_info(MigrationInfo *info) { MigrationState *s = migrate_get_current(); + GSList *cur_blocker = migration_blockers; - info->blocked = migration_is_blocked(NULL); - info->has_blocked_reasons = info->blocked; info->blocked_reasons = NULL; - if (info->blocked) { - GSList *cur_blocker = migration_blockers; - /* - * There are two types of reasons a migration might be blocked; - * a) devices marked in VMState as non-migratable, and - * b) Explicit migration blockers - * We need to add both of them here. - */ - qemu_savevm_non_migratable_list(&info->blocked_reasons); + /* + * There are two types of reasons a migration might be blocked; + * a) devices marked in VMState as non-migratable, and + * b) Explicit migration blockers + * We need to add both of them here. + */ + qemu_savevm_non_migratable_list(&info->blocked_reasons); - while (cur_blocker) { - QAPI_LIST_PREPEND(info->blocked_reasons, - g_strdup(error_get_pretty(cur_blocker->data))); - cur_blocker = g_slist_next(cur_blocker); - } + while (cur_blocker) { + QAPI_LIST_PREPEND(info->blocked_reasons, + g_strdup(error_get_pretty(cur_blocker->data))); + cur_blocker = g_slist_next(cur_blocker); } + info->has_blocked_reasons = info->blocked_reasons != NULL; switch (s->state) { case MIGRATION_STATUS_NONE: diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 0ad5b77477..d9bef63373 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -224,7 +224,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) migration_global_dump(mon); - if (info->blocked) { + if (info->blocked_reasons) { strList *reasons = info->blocked_reasons; monitor_printf(mon, "Outgoing migration blocked:\n"); while (reasons) { diff --git a/qapi/migration.json b/qapi/migration.json index 0b17cce46b..7a5bdf9a0d 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -228,11 +228,6 @@ # Present and non-empty when migration is blocked. # (since 6.0) # -# @blocked: True if outgoing migration is blocked (since 6.0) -# -# Features: -# @deprecated: Member @blocked is deprecated. Use @blocked-reasons instead. -# # Since: 0.14 ## { 'struct': 'MigrationInfo', @@ -246,7 +241,6 @@ '*setup-time': 'int', '*cpu-throttle-percentage': 'int', '*error-desc': 'str', - 'blocked': { 'type': 'bool', 'features': [ 'deprecated' ] }, '*blocked-reasons': ['str'], '*postcopy-blocktime' : 'uint32', '*postcopy-vcpu-blocktime': ['uint32'], From 082851a3af1450fa714e9a0a3ca7cb4b9dbd8855 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 29 Apr 2021 13:26:59 +0200 Subject: [PATCH 0513/3028] util: vfio-helpers: Factor out and fix processing of existing ram blocks Factor it out into common code when a new notifier is registered, just as done with the memory region notifier. This keeps logic about how to process existing ram blocks at a central place. Just like when adding a new ram block, we have to register the max_length. Ram blocks are only "fake resized". All memory (max_length) is mapped. Print the warning from inside qemu_vfio_ram_block_added(). Reviewed-by: Peter Xu Signed-off-by: David Hildenbrand Message-Id: <20210429112708.12291-2-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- hw/core/numa.c | 14 ++++++++++++++ include/exec/cpu-common.h | 1 + softmmu/physmem.c | 5 +++++ util/vfio-helpers.c | 29 ++++++++--------------------- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/hw/core/numa.c b/hw/core/numa.c index ac6bed5817..134ebc2b72 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -802,9 +802,23 @@ void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms) } } +static int ram_block_notify_add_single(RAMBlock *rb, void *opaque) +{ + const ram_addr_t max_size = qemu_ram_get_max_length(rb); + void *host = qemu_ram_get_host_addr(rb); + RAMBlockNotifier *notifier = opaque; + + if (host) { + notifier->ram_block_added(notifier, host, max_size); + } + return 0; +} + void ram_block_notifier_add(RAMBlockNotifier *n) { QLIST_INSERT_HEAD(&ram_list.ramblock_notifiers, n, next); + /* Notify about all existing ram blocks. */ + qemu_ram_foreach_block(ram_block_notify_add_single, n); } void ram_block_notifier_remove(RAMBlockNotifier *n) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 5a0a2d93e0..ccabed4003 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -57,6 +57,7 @@ const char *qemu_ram_get_idstr(RAMBlock *rb); void *qemu_ram_get_host_addr(RAMBlock *rb); ram_addr_t qemu_ram_get_offset(RAMBlock *rb); ram_addr_t qemu_ram_get_used_length(RAMBlock *rb); +ram_addr_t qemu_ram_get_max_length(RAMBlock *rb); bool qemu_ram_is_shared(RAMBlock *rb); bool qemu_ram_is_uf_zeroable(RAMBlock *rb); void qemu_ram_set_uf_zeroable(RAMBlock *rb); diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 5232696571..0a05533ed0 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -1694,6 +1694,11 @@ ram_addr_t qemu_ram_get_used_length(RAMBlock *rb) return rb->used_length; } +ram_addr_t qemu_ram_get_max_length(RAMBlock *rb) +{ + return rb->max_length; +} + bool qemu_ram_is_shared(RAMBlock *rb) { return rb->flags & RAM_SHARED; diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c index 97dfa3fd57..92b9565797 100644 --- a/util/vfio-helpers.c +++ b/util/vfio-helpers.c @@ -463,8 +463,14 @@ static void qemu_vfio_ram_block_added(RAMBlockNotifier *n, void *host, size_t size) { QEMUVFIOState *s = container_of(n, QEMUVFIOState, ram_notifier); + int ret; + trace_qemu_vfio_ram_block_added(s, host, size); - qemu_vfio_dma_map(s, host, size, false, NULL); + ret = qemu_vfio_dma_map(s, host, size, false, NULL); + if (ret) { + error_report("qemu_vfio_dma_map(%p, %zu) failed: %s", host, size, + strerror(-ret)); + } } static void qemu_vfio_ram_block_removed(RAMBlockNotifier *n, @@ -477,33 +483,14 @@ static void qemu_vfio_ram_block_removed(RAMBlockNotifier *n, } } -static int qemu_vfio_init_ramblock(RAMBlock *rb, void *opaque) -{ - void *host_addr = qemu_ram_get_host_addr(rb); - ram_addr_t length = qemu_ram_get_used_length(rb); - int ret; - QEMUVFIOState *s = opaque; - - if (!host_addr) { - return 0; - } - ret = qemu_vfio_dma_map(s, host_addr, length, false, NULL); - if (ret) { - fprintf(stderr, "qemu_vfio_init_ramblock: failed %p %" PRId64 "\n", - host_addr, (uint64_t)length); - } - return 0; -} - static void qemu_vfio_open_common(QEMUVFIOState *s) { qemu_mutex_init(&s->lock); s->ram_notifier.ram_block_added = qemu_vfio_ram_block_added; s->ram_notifier.ram_block_removed = qemu_vfio_ram_block_removed; - ram_block_notifier_add(&s->ram_notifier); s->low_water_mark = QEMU_VFIO_IOVA_MIN; s->high_water_mark = QEMU_VFIO_IOVA_MAX; - qemu_ram_foreach_block(qemu_vfio_init_ramblock, s); + ram_block_notifier_add(&s->ram_notifier); } /** From 8f44304c76036ac8544468c9306c5b30d1fdd201 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 29 Apr 2021 13:27:00 +0200 Subject: [PATCH 0514/3028] numa: Teach ram block notifiers about resizeable ram blocks Ram block notifiers are currently not aware of resizes. To properly handle resizes during migration, we want to teach ram block notifiers about resizeable ram. Introduce the basic infrastructure but keep using max_size in the existing notifiers. Supply the max_size when adding and removing ram blocks. Also, notify on resizes. Acked-by: Paul Durrant Reviewed-by: Peter Xu Cc: xen-devel@lists.xenproject.org Cc: haxm-team@intel.com Cc: Paul Durrant Cc: Stefano Stabellini Cc: Anthony Perard Cc: Wenchao Wang Cc: Colin Xu Signed-off-by: David Hildenbrand Message-Id: <20210429112708.12291-3-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- hw/core/numa.c | 22 +++++++++++++++++----- hw/i386/xen/xen-mapcache.c | 7 ++++--- include/exec/ramlist.h | 13 +++++++++---- softmmu/physmem.c | 12 ++++++++++-- target/i386/hax/hax-mem.c | 5 +++-- target/i386/sev.c | 18 ++++++++++-------- util/vfio-helpers.c | 16 ++++++++-------- 7 files changed, 61 insertions(+), 32 deletions(-) diff --git a/hw/core/numa.c b/hw/core/numa.c index 134ebc2b72..4c58b2348d 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -805,11 +805,12 @@ void query_numa_node_mem(NumaNodeMem node_mem[], MachineState *ms) static int ram_block_notify_add_single(RAMBlock *rb, void *opaque) { const ram_addr_t max_size = qemu_ram_get_max_length(rb); + const ram_addr_t size = qemu_ram_get_used_length(rb); void *host = qemu_ram_get_host_addr(rb); RAMBlockNotifier *notifier = opaque; if (host) { - notifier->ram_block_added(notifier, host, max_size); + notifier->ram_block_added(notifier, host, size, max_size); } return 0; } @@ -826,20 +827,31 @@ void ram_block_notifier_remove(RAMBlockNotifier *n) QLIST_REMOVE(n, next); } -void ram_block_notify_add(void *host, size_t size) +void ram_block_notify_add(void *host, size_t size, size_t max_size) { RAMBlockNotifier *notifier; QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { - notifier->ram_block_added(notifier, host, size); + notifier->ram_block_added(notifier, host, size, max_size); } } -void ram_block_notify_remove(void *host, size_t size) +void ram_block_notify_remove(void *host, size_t size, size_t max_size) { RAMBlockNotifier *notifier; QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { - notifier->ram_block_removed(notifier, host, size); + notifier->ram_block_removed(notifier, host, size, max_size); + } +} + +void ram_block_notify_resize(void *host, size_t old_size, size_t new_size) +{ + RAMBlockNotifier *notifier; + + QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { + if (notifier->ram_block_resized) { + notifier->ram_block_resized(notifier, host, old_size, new_size); + } } } diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c index e82b7dcdd2..bd47c3d672 100644 --- a/hw/i386/xen/xen-mapcache.c +++ b/hw/i386/xen/xen-mapcache.c @@ -169,7 +169,8 @@ static void xen_remap_bucket(MapCacheEntry *entry, if (entry->vaddr_base != NULL) { if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) { - ram_block_notify_remove(entry->vaddr_base, entry->size); + ram_block_notify_remove(entry->vaddr_base, entry->size, + entry->size); } /* @@ -224,7 +225,7 @@ static void xen_remap_bucket(MapCacheEntry *entry, } if (!(entry->flags & XEN_MAPCACHE_ENTRY_DUMMY)) { - ram_block_notify_add(vaddr_base, size); + ram_block_notify_add(vaddr_base, size, size); } entry->vaddr_base = vaddr_base; @@ -465,7 +466,7 @@ static void xen_invalidate_map_cache_entry_unlocked(uint8_t *buffer) } pentry->next = entry->next; - ram_block_notify_remove(entry->vaddr_base, entry->size); + ram_block_notify_remove(entry->vaddr_base, entry->size, entry->size); if (munmap(entry->vaddr_base, entry->size) != 0) { perror("unmap fails"); exit(-1); diff --git a/include/exec/ramlist.h b/include/exec/ramlist.h index 26704aa3b0..ece6497ee2 100644 --- a/include/exec/ramlist.h +++ b/include/exec/ramlist.h @@ -65,15 +65,20 @@ void qemu_mutex_lock_ramlist(void); void qemu_mutex_unlock_ramlist(void); struct RAMBlockNotifier { - void (*ram_block_added)(RAMBlockNotifier *n, void *host, size_t size); - void (*ram_block_removed)(RAMBlockNotifier *n, void *host, size_t size); + void (*ram_block_added)(RAMBlockNotifier *n, void *host, size_t size, + size_t max_size); + void (*ram_block_removed)(RAMBlockNotifier *n, void *host, size_t size, + size_t max_size); + void (*ram_block_resized)(RAMBlockNotifier *n, void *host, size_t old_size, + size_t new_size); QLIST_ENTRY(RAMBlockNotifier) next; }; void ram_block_notifier_add(RAMBlockNotifier *n); void ram_block_notifier_remove(RAMBlockNotifier *n); -void ram_block_notify_add(void *host, size_t size); -void ram_block_notify_remove(void *host, size_t size); +void ram_block_notify_add(void *host, size_t size, size_t max_size); +void ram_block_notify_remove(void *host, size_t size, size_t max_size); +void ram_block_notify_resize(void *host, size_t old_size, size_t new_size); void ram_block_dump(Monitor *mon); diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 0a05533ed0..81ec3b85b9 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -1807,6 +1807,7 @@ static int memory_try_enable_merging(void *addr, size_t len) */ int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp) { + const ram_addr_t oldsize = block->used_length; const ram_addr_t unaligned_size = newsize; assert(block); @@ -1843,6 +1844,11 @@ int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp) return -EINVAL; } + /* Notify before modifying the ram block and touching the bitmaps. */ + if (block->host) { + ram_block_notify_resize(block->host, oldsize, newsize); + } + cpu_physical_memory_clear_dirty_range(block->offset, block->used_length); block->used_length = newsize; cpu_physical_memory_set_dirty_range(block->offset, block->used_length, @@ -2010,7 +2016,8 @@ static void ram_block_add(RAMBlock *new_block, Error **errp, bool shared) qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK); } - ram_block_notify_add(new_block->host, new_block->max_length); + ram_block_notify_add(new_block->host, new_block->used_length, + new_block->max_length); } } @@ -2189,7 +2196,8 @@ void qemu_ram_free(RAMBlock *block) } if (block->host) { - ram_block_notify_remove(block->host, block->max_length); + ram_block_notify_remove(block->host, block->used_length, + block->max_length); } qemu_mutex_lock_ramlist(); diff --git a/target/i386/hax/hax-mem.c b/target/i386/hax/hax-mem.c index 35495f5e82..8d44edbffd 100644 --- a/target/i386/hax/hax-mem.c +++ b/target/i386/hax/hax-mem.c @@ -293,7 +293,8 @@ static MemoryListener hax_memory_listener = { .priority = 10, }; -static void hax_ram_block_added(RAMBlockNotifier *n, void *host, size_t size) +static void hax_ram_block_added(RAMBlockNotifier *n, void *host, size_t size, + size_t max_size) { /* * We must register each RAM block with the HAXM kernel module, or @@ -304,7 +305,7 @@ static void hax_ram_block_added(RAMBlockNotifier *n, void *host, size_t size) * host physical pages for the RAM block as part of this registration * process, hence the name hax_populate_ram(). */ - if (hax_populate_ram((uint64_t)(uintptr_t)host, size) < 0) { + if (hax_populate_ram((uint64_t)(uintptr_t)host, max_size) < 0) { fprintf(stderr, "HAX failed to populate RAM\n"); abort(); } diff --git a/target/i386/sev.c b/target/i386/sev.c index 9a43be11cb..41f7800b5f 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -180,7 +180,8 @@ sev_set_guest_state(SevGuestState *sev, SevState new_state) } static void -sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size) +sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size, + size_t max_size) { int r; struct kvm_enc_region range; @@ -197,19 +198,20 @@ sev_ram_block_added(RAMBlockNotifier *n, void *host, size_t size) } range.addr = (__u64)(unsigned long)host; - range.size = size; + range.size = max_size; - trace_kvm_memcrypt_register_region(host, size); + trace_kvm_memcrypt_register_region(host, max_size); r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_REG_REGION, &range); if (r) { error_report("%s: failed to register region (%p+%#zx) error '%s'", - __func__, host, size, strerror(errno)); + __func__, host, max_size, strerror(errno)); exit(1); } } static void -sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size) +sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size, + size_t max_size) { int r; struct kvm_enc_region range; @@ -226,13 +228,13 @@ sev_ram_block_removed(RAMBlockNotifier *n, void *host, size_t size) } range.addr = (__u64)(unsigned long)host; - range.size = size; + range.size = max_size; - trace_kvm_memcrypt_unregister_region(host, size); + trace_kvm_memcrypt_unregister_region(host, max_size); r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_UNREG_REGION, &range); if (r) { error_report("%s: failed to unregister region (%p+%#zx)", - __func__, host, size); + __func__, host, max_size); } } diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c index 92b9565797..911115b86e 100644 --- a/util/vfio-helpers.c +++ b/util/vfio-helpers.c @@ -459,26 +459,26 @@ fail_container: return ret; } -static void qemu_vfio_ram_block_added(RAMBlockNotifier *n, - void *host, size_t size) +static void qemu_vfio_ram_block_added(RAMBlockNotifier *n, void *host, + size_t size, size_t max_size) { QEMUVFIOState *s = container_of(n, QEMUVFIOState, ram_notifier); int ret; - trace_qemu_vfio_ram_block_added(s, host, size); - ret = qemu_vfio_dma_map(s, host, size, false, NULL); + trace_qemu_vfio_ram_block_added(s, host, max_size); + ret = qemu_vfio_dma_map(s, host, max_size, false, NULL); if (ret) { - error_report("qemu_vfio_dma_map(%p, %zu) failed: %s", host, size, + error_report("qemu_vfio_dma_map(%p, %zu) failed: %s", host, max_size, strerror(-ret)); } } -static void qemu_vfio_ram_block_removed(RAMBlockNotifier *n, - void *host, size_t size) +static void qemu_vfio_ram_block_removed(RAMBlockNotifier *n, void *host, + size_t size, size_t max_size) { QEMUVFIOState *s = container_of(n, QEMUVFIOState, ram_notifier); if (host) { - trace_qemu_vfio_ram_block_removed(s, host, size); + trace_qemu_vfio_ram_block_removed(s, host, max_size); qemu_vfio_dma_unmap(s, host); } } From e15c7d1e8c34bbffec2aa88f8fe7cd9812b1c71f Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 29 Apr 2021 13:27:01 +0200 Subject: [PATCH 0515/3028] numa: Make all callbacks of ram block notifiers optional Let's make add/remove optional. We want to introduce a RAM block notifier for RAM migration that is only interested in resize events. Reviewed-by: Peter Xu Signed-off-by: David Hildenbrand Message-Id: <20210429112708.12291-4-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- hw/core/numa.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/core/numa.c b/hw/core/numa.c index 4c58b2348d..1058d3697b 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -818,8 +818,11 @@ static int ram_block_notify_add_single(RAMBlock *rb, void *opaque) void ram_block_notifier_add(RAMBlockNotifier *n) { QLIST_INSERT_HEAD(&ram_list.ramblock_notifiers, n, next); + /* Notify about all existing ram blocks. */ - qemu_ram_foreach_block(ram_block_notify_add_single, n); + if (n->ram_block_added) { + qemu_ram_foreach_block(ram_block_notify_add_single, n); + } } void ram_block_notifier_remove(RAMBlockNotifier *n) @@ -832,7 +835,9 @@ void ram_block_notify_add(void *host, size_t size, size_t max_size) RAMBlockNotifier *notifier; QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { - notifier->ram_block_added(notifier, host, size, max_size); + if (notifier->ram_block_added) { + notifier->ram_block_added(notifier, host, size, max_size); + } } } @@ -841,7 +846,9 @@ void ram_block_notify_remove(void *host, size_t size, size_t max_size) RAMBlockNotifier *notifier; QLIST_FOREACH(notifier, &ram_list.ramblock_notifiers, next) { - notifier->ram_block_removed(notifier, host, size, max_size); + if (notifier->ram_block_removed) { + notifier->ram_block_removed(notifier, host, size, max_size); + } } } From c7c0e72408df5e7821c0e995122fb2fe0ac001f1 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 29 Apr 2021 13:27:02 +0200 Subject: [PATCH 0516/3028] migration/ram: Handle RAM block resizes during precopy Resizing while migrating is dangerous and does not work as expected. The whole migration code works on the usable_length of ram blocks and does not expect this to change at random points in time. In the case of precopy, the ram block size must not change on the source, after syncing the RAM block list in ram_save_setup(), so as long as the guest is still running on the source. Resizing can be trigger *after* (but not during) a reset in ACPI code by the guest - hw/arm/virt-acpi-build.c:acpi_ram_update() - hw/i386/acpi-build.c:acpi_ram_update() Use the ram block notifier to get notified about resizes. Let's simply cancel migration and indicate the reason. We'll continue running on the source. No harm done. Update the documentation. Postcopy will be handled separately. Reviewed-by: Peter Xu Signed-off-by: David Hildenbrand Message-Id: <20210429112708.12291-5-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert Manual merge --- include/exec/memory.h | 10 ++++++---- migration/migration.c | 9 +++++++-- migration/migration.h | 1 + migration/ram.c | 30 ++++++++++++++++++++++++++++++ softmmu/physmem.c | 5 +++-- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 5728a681b2..c8b9088924 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -131,7 +131,7 @@ typedef struct IOMMUTLBEvent { #define RAM_SHARED (1 << 1) /* Only a portion of RAM (used_length) is actually used, and migrated. - * This used_length size can change across reboots. + * Resizing RAM while migrating can result in the migration being canceled. */ #define RAM_RESIZEABLE (1 << 2) @@ -955,7 +955,9 @@ void memory_region_init_ram_shared_nomigrate(MemoryRegion *mr, * RAM. Accesses into the region will * modify memory directly. Only an initial * portion of this RAM is actually used. - * The used size can change across reboots. + * Changing the size while migrating + * can result in the migration being + * canceled. * * @mr: the #MemoryRegion to be initialized. * @owner: the object that tracks the region's reference count @@ -1586,8 +1588,8 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr); /* memory_region_ram_resize: Resize a RAM region. * - * Only legal before guest might have detected the memory size: e.g. on - * incoming migration, or right after reset. + * Resizing RAM while migrating can result in the migration being canceled. + * Care has to be taken if the guest might have already detected the memory. * * @mr: a memory region created with @memory_region_init_resizeable_ram. * @newsize: the new size the region diff --git a/migration/migration.c b/migration/migration.c index fdadee290e..4698b47442 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -223,13 +223,18 @@ void migration_object_init(void) dirty_bitmap_mig_init(); } +void migration_cancel(void) +{ + migrate_fd_cancel(current_migration); +} + void migration_shutdown(void) { /* * Cancel the current migration - that will (eventually) * stop the migration using this structure */ - migrate_fd_cancel(current_migration); + migration_cancel(); object_unref(OBJECT(current_migration)); /* @@ -2307,7 +2312,7 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, void qmp_migrate_cancel(Error **errp) { - migrate_fd_cancel(migrate_get_current()); + migration_cancel(); } void qmp_migrate_continue(MigrationStatus state, Error **errp) diff --git a/migration/migration.h b/migration/migration.h index db6708326b..f7b388d718 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -375,5 +375,6 @@ int foreach_not_ignored_block(RAMBlockIterFunc func, void *opaque); void migration_make_urgent_request(void); void migration_consume_urgent_request(void); bool migration_rate_limit(void); +void migration_cancel(void); #endif diff --git a/migration/ram.c b/migration/ram.c index bb52bd97db..77922c445e 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4096,8 +4096,38 @@ static SaveVMHandlers savevm_ram_handlers = { .resume_prepare = ram_resume_prepare, }; +static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host, + size_t old_size, size_t new_size) +{ + ram_addr_t offset; + RAMBlock *rb = qemu_ram_block_from_host(host, false, &offset); + Error *err = NULL; + + if (ramblock_is_ignored(rb)) { + return; + } + + if (!migration_is_idle()) { + /* + * Precopy code on the source cannot deal with the size of RAM blocks + * changing at random points in time - especially after sending the + * RAM block sizes in the migration stream, they must no longer change. + * Abort and indicate a proper reason. + */ + error_setg(&err, "RAM block '%s' resized during precopy.", rb->idstr); + migrate_set_error(migrate_get_current(), err); + error_free(err); + migration_cancel(); + } +} + +static RAMBlockNotifier ram_mig_ram_notifier = { + .ram_block_resized = ram_mig_ram_block_resized, +}; + void ram_mig_init(void) { qemu_mutex_init(&XBZRLE.lock); register_savevm_live("ram", 0, 4, &savevm_ram_handlers, &ram_state); + ram_block_notifier_add(&ram_mig_ram_notifier); } diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 81ec3b85b9..813a3efe8e 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -1798,8 +1798,9 @@ static int memory_try_enable_merging(void *addr, size_t len) return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE); } -/* Only legal before guest might have detected the memory size: e.g. on - * incoming migration, or right after reset. +/* + * Resizing RAM while migrating can result in the migration being canceled. + * Care has to be taken if the guest might have already detected the memory. * * As memory core doesn't know how is memory accessed, it is up to * resize callback to update device state and/or add assertions to detect From dcdc460767ed0a650e06ff256fa2a52ff1b57047 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 29 Apr 2021 13:27:03 +0200 Subject: [PATCH 0517/3028] exec: Relax range check in ram_block_discard_range() We want to make use of ram_block_discard_range() in the RAM block resize callback when growing a RAM block, *before* used_length is changed. Let's relax the check. As RAM blocks always mmap the whole max_length area, we cannot corrupt unrelated data. Reviewed-by: Peter Xu Signed-off-by: David Hildenbrand Message-Id: <20210429112708.12291-6-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- softmmu/physmem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/softmmu/physmem.c b/softmmu/physmem.c index 813a3efe8e..e1da81ed2f 100644 --- a/softmmu/physmem.c +++ b/softmmu/physmem.c @@ -3500,7 +3500,7 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) goto err; } - if ((start + length) <= rb->used_length) { + if ((start + length) <= rb->max_length) { bool need_madvise, need_fallocate; if (!QEMU_IS_ALIGNED(length, rb->page_size)) { error_report("ram_block_discard_range: Unaligned length: %zx", @@ -3567,7 +3567,7 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length) } else { error_report("ram_block_discard_range: Overrun block '%s' (%" PRIu64 "/%zx/" RAM_ADDR_FMT")", - rb->idstr, start, length, rb->used_length); + rb->idstr, start, length, rb->max_length); } err: From cc61c703b6a8b9dfdfb92d5f3fa1961f6d232926 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 29 Apr 2021 13:27:04 +0200 Subject: [PATCH 0518/3028] migration/ram: Discard RAM when growing RAM blocks after ram_postcopy_incoming_init() In case we grow our RAM after ram_postcopy_incoming_init() (e.g., when synchronizing the RAM block state with the migration source), the resized part would not get discarded. Let's perform that when being notified about a resize while postcopy has been advised, but is not listening yet. With precopy, the process is as following: 1. VM created - RAM blocks are created 2. Incomming migration started - Postcopy is advised - All pages in RAM blocks are discarded 3. Precopy starts - RAM blocks are resized to match the size on the migration source. - RAM pages from precopy stream are loaded - Uffd handler is registered, postcopy starts listening 4. Guest started, postcopy running - Pagefaults get resolved, pages get placed Reviewed-by: Peter Xu Signed-off-by: David Hildenbrand Message-Id: <20210429112708.12291-7-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- migration/ram.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/migration/ram.c b/migration/ram.c index 77922c445e..e1d081d334 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4099,6 +4099,7 @@ static SaveVMHandlers savevm_ram_handlers = { static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host, size_t old_size, size_t new_size) { + PostcopyState ps = postcopy_state_get(); ram_addr_t offset; RAMBlock *rb = qemu_ram_block_from_host(host, false, &offset); Error *err = NULL; @@ -4119,6 +4120,35 @@ static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host, error_free(err); migration_cancel(); } + + switch (ps) { + case POSTCOPY_INCOMING_ADVISE: + /* + * Update what ram_postcopy_incoming_init()->init_range() does at the + * time postcopy was advised. Syncing RAM blocks with the source will + * result in RAM resizes. + */ + if (old_size < new_size) { + if (ram_discard_range(rb->idstr, old_size, new_size - old_size)) { + error_report("RAM block '%s' discard of resized RAM failed", + rb->idstr); + } + } + break; + case POSTCOPY_INCOMING_NONE: + case POSTCOPY_INCOMING_RUNNING: + case POSTCOPY_INCOMING_END: + /* + * Once our guest is running, postcopy does no longer care about + * resizes. When growing, the new memory was not available on the + * source, no handler needed. + */ + break; + default: + error_report("RAM block '%s' resized during postcopy state: %d", + rb->idstr, ps); + exit(-1); + } } static RAMBlockNotifier ram_mig_ram_notifier = { From 6a23f6399a1f8807447f8680f80e4d536522683e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 29 Apr 2021 13:27:05 +0200 Subject: [PATCH 0519/3028] migration/ram: Simplify host page handling in ram_load_postcopy() Add two new helper functions. This will come in come handy once we want to handle ram block resizes while postcopy is active. Note that ram_block_from_stream() will already print proper errors. Reviewed-by: Dr. David Alan Gilbert Signed-off-by: David Hildenbrand Message-Id: <20210429112708.12291-8-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert dgilbert: Added brackets in host_page_from_ram_block_offset to cause uintptr_t to cast the sum, to fix armhf-cross build --- migration/ram.c | 55 ++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index e1d081d334..26ed42b87d 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3085,6 +3085,20 @@ static inline void *host_from_ram_block_offset(RAMBlock *block, return block->host + offset; } +static void *host_page_from_ram_block_offset(RAMBlock *block, + ram_addr_t offset) +{ + /* Note: Explicitly no check against offset_in_ramblock(). */ + return (void *)QEMU_ALIGN_DOWN((uintptr_t)(block->host + offset), + block->page_size); +} + +static ram_addr_t host_page_offset_from_ram_block_offset(RAMBlock *block, + ram_addr_t offset) +{ + return ((uintptr_t)block->host + offset) & (block->page_size - 1); +} + static inline void *colo_cache_from_block_offset(RAMBlock *block, ram_addr_t offset, bool record_bitmap) { @@ -3481,13 +3495,12 @@ static int ram_load_postcopy(QEMUFile *f) MigrationIncomingState *mis = migration_incoming_get_current(); /* Temporary page that is later 'placed' */ void *postcopy_host_page = mis->postcopy_tmp_page; - void *this_host = NULL; + void *host_page = NULL; bool all_zero = true; int target_pages = 0; while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) { ram_addr_t addr; - void *host = NULL; void *page_buffer = NULL; void *place_source = NULL; RAMBlock *block = NULL; @@ -3512,9 +3525,12 @@ static int ram_load_postcopy(QEMUFile *f) if (flags & (RAM_SAVE_FLAG_ZERO | RAM_SAVE_FLAG_PAGE | RAM_SAVE_FLAG_COMPRESS_PAGE)) { block = ram_block_from_stream(f, flags); + if (!block) { + ret = -EINVAL; + break; + } - host = host_from_ram_block_offset(block, addr); - if (!host) { + if (!offset_in_ramblock(block, addr)) { error_report("Illegal RAM offset " RAM_ADDR_FMT, addr); ret = -EINVAL; break; @@ -3532,19 +3548,17 @@ static int ram_load_postcopy(QEMUFile *f) * of a host page in one chunk. */ page_buffer = postcopy_host_page + - ((uintptr_t)host & (block->page_size - 1)); + host_page_offset_from_ram_block_offset(block, addr); + /* If all TP are zero then we can optimise the place */ if (target_pages == 1) { - this_host = (void *)QEMU_ALIGN_DOWN((uintptr_t)host, - block->page_size); - } else { + host_page = host_page_from_ram_block_offset(block, addr); + } else if (host_page != host_page_from_ram_block_offset(block, + addr)) { /* not the 1st TP within the HP */ - if (QEMU_ALIGN_DOWN((uintptr_t)host, block->page_size) != - (uintptr_t)this_host) { - error_report("Non-same host page %p/%p", - host, this_host); - ret = -EINVAL; - break; - } + error_report("Non-same host page %p/%p", host_page, + host_page_from_ram_block_offset(block, addr)); + ret = -EINVAL; + break; } /* @@ -3623,16 +3637,11 @@ static int ram_load_postcopy(QEMUFile *f) } if (!ret && place_needed) { - /* This gets called at the last target page in the host page */ - void *place_dest = (void *)QEMU_ALIGN_DOWN((uintptr_t)host, - block->page_size); - if (all_zero) { - ret = postcopy_place_page_zero(mis, place_dest, - block); + ret = postcopy_place_page_zero(mis, host_page, block); } else { - ret = postcopy_place_page(mis, place_dest, - place_source, block); + ret = postcopy_place_page(mis, host_page, place_source, + block); } place_needed = false; target_pages = 0; From 898ba906ccb85ba17d65e64a31cc13128803ef86 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 29 Apr 2021 13:27:06 +0200 Subject: [PATCH 0520/3028] migration/ram: Handle RAM block resizes during postcopy Resizing while migrating is dangerous and does not work as expected. The whole migration code works with the usable_length of a ram block and does not expect this value to change at random points in time. In the case of postcopy, relying on used_length is racy as soon as the guest is running. Also, when used_length changes we might leave the uffd handler registered for some memory regions, reject valid pages when migrating and fail when sending the recv bitmap to the source. Resizing can be trigger *after* (but not during) a reset in ACPI code by the guest - hw/arm/virt-acpi-build.c:acpi_ram_update() - hw/i386/acpi-build.c:acpi_ram_update() Let's remember the original used_length in a separate variable and use it in relevant postcopy code. Make sure to update it when we resize during precopy, when synchronizing the RAM block sizes with the source. Reviewed-by: Peter Xu Reviewed-by: Dr. David Alan Gilbert Signed-off-by: David Hildenbrand Message-Id: <20210429112708.12291-9-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- include/exec/ramblock.h | 10 ++++++++++ migration/postcopy-ram.c | 15 ++++++++++++--- migration/ram.c | 11 +++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/include/exec/ramblock.h b/include/exec/ramblock.h index 07d50864d8..664701b759 100644 --- a/include/exec/ramblock.h +++ b/include/exec/ramblock.h @@ -59,6 +59,16 @@ struct RAMBlock { */ unsigned long *clear_bmap; uint8_t clear_bmap_shift; + + /* + * RAM block length that corresponds to the used_length on the migration + * source (after RAM block sizes were synchronized). Especially, after + * starting to run the guest, used_length and postcopy_length can differ. + * Used to register/unregister uffd handlers and as the size of the received + * bitmap. Receiving any page beyond this length will bail out, as it + * could not have been valid on the source. + */ + ram_addr_t postcopy_length; }; #endif #endif diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index ab482adef1..2e9697bdd2 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -17,6 +17,7 @@ */ #include "qemu/osdep.h" +#include "qemu/rcu.h" #include "exec/target_page.h" #include "migration.h" #include "qemu-file.h" @@ -30,6 +31,7 @@ #include "qemu/error-report.h" #include "trace.h" #include "hw/boards.h" +#include "exec/ramblock.h" /* Arbitrary limit on size of each discard command, * keeps them around ~200 bytes @@ -452,6 +454,13 @@ static int init_range(RAMBlock *rb, void *opaque) ram_addr_t length = qemu_ram_get_used_length(rb); trace_postcopy_init_range(block_name, host_addr, offset, length); + /* + * Save the used_length before running the guest. In case we have to + * resize RAM blocks when syncing RAM block sizes from the source during + * precopy, we'll update it manually via the ram block notifier. + */ + rb->postcopy_length = length; + /* * We need the whole of RAM to be truly empty for postcopy, so things * like ROMs and any data tables built during init must be zero'd @@ -474,7 +483,7 @@ static int cleanup_range(RAMBlock *rb, void *opaque) const char *block_name = qemu_ram_get_idstr(rb); void *host_addr = qemu_ram_get_host_addr(rb); ram_addr_t offset = qemu_ram_get_offset(rb); - ram_addr_t length = qemu_ram_get_used_length(rb); + ram_addr_t length = rb->postcopy_length; MigrationIncomingState *mis = opaque; struct uffdio_range range_struct; trace_postcopy_cleanup_range(block_name, host_addr, offset, length); @@ -580,7 +589,7 @@ static int nhp_range(RAMBlock *rb, void *opaque) const char *block_name = qemu_ram_get_idstr(rb); void *host_addr = qemu_ram_get_host_addr(rb); ram_addr_t offset = qemu_ram_get_offset(rb); - ram_addr_t length = qemu_ram_get_used_length(rb); + ram_addr_t length = rb->postcopy_length; trace_postcopy_nhp_range(block_name, host_addr, offset, length); /* @@ -624,7 +633,7 @@ static int ram_block_enable_notify(RAMBlock *rb, void *opaque) struct uffdio_register reg_struct; reg_struct.range.start = (uintptr_t)qemu_ram_get_host_addr(rb); - reg_struct.range.len = qemu_ram_get_used_length(rb); + reg_struct.range.len = rb->postcopy_length; reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING; /* Now tell our userfault_fd that it's responsible for this area */ diff --git a/migration/ram.c b/migration/ram.c index 26ed42b87d..6d09ca78bc 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -240,7 +240,7 @@ int64_t ramblock_recv_bitmap_send(QEMUFile *file, return -1; } - nbits = block->used_length >> TARGET_PAGE_BITS; + nbits = block->postcopy_length >> TARGET_PAGE_BITS; /* * Make sure the tmp bitmap buffer is big enough, e.g., on 32bit @@ -3530,7 +3530,13 @@ static int ram_load_postcopy(QEMUFile *f) break; } - if (!offset_in_ramblock(block, addr)) { + /* + * Relying on used_length is racy and can result in false positives. + * We might place pages beyond used_length in case RAM was shrunk + * while in postcopy, which is fine - trying to place via + * UFFDIO_COPY/UFFDIO_ZEROPAGE will never segfault. + */ + if (!block->host || addr >= block->postcopy_length) { error_report("Illegal RAM offset " RAM_ADDR_FMT, addr); ret = -EINVAL; break; @@ -4143,6 +4149,7 @@ static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host, rb->idstr); } } + rb->postcopy_length = new_size; break; case POSTCOPY_INCOMING_NONE: case POSTCOPY_INCOMING_RUNNING: From c1668bde5cce6c1b4dbe4b2981266cedbd111504 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 29 Apr 2021 13:27:07 +0200 Subject: [PATCH 0521/3028] migration/multifd: Print used_length of memory block We actually want to print the used_length, against which we check. Reviewed-by: Dr. David Alan Gilbert Signed-off-by: David Hildenbrand Message-Id: <20210429112708.12291-10-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- migration/multifd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/multifd.c b/migration/multifd.c index a6677c45c8..0a4803cfcc 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -361,7 +361,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) if (offset > (block->used_length - qemu_target_page_size())) { error_setg(errp, "multifd: offset too long %" PRIu64 " (max " RAM_ADDR_FMT ")", - offset, block->max_length); + offset, block->used_length); return -1; } p->pages->iov[i].iov_base = block->host + offset; From 542147f4e5701fbb5b41c13d64ce90200f4ca766 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 29 Apr 2021 13:27:08 +0200 Subject: [PATCH 0522/3028] migration/ram: Use offset_in_ramblock() in range checks We never read or write beyond the used_length of memory blocks when migrating. Make this clearer by using offset_in_ramblock() consistently. Reviewed-by: Dr. David Alan Gilbert Signed-off-by: David Hildenbrand Message-Id: <20210429112708.12291-11-david@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- migration/ram.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 6d09ca78bc..60ea913c54 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1342,8 +1342,8 @@ static bool find_dirty_block(RAMState *rs, PageSearchStatus *pss, bool *again) *again = false; return false; } - if ((((ram_addr_t)pss->page) << TARGET_PAGE_BITS) - >= pss->block->used_length) { + if (!offset_in_ramblock(pss->block, + ((ram_addr_t)pss->page) << TARGET_PAGE_BITS)) { /* Didn't find anything in this RAM Block */ pss->page = 0; pss->block = QLIST_NEXT_RCU(pss->block, next); @@ -1863,7 +1863,7 @@ int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len) rs->last_req_rb = ramblock; } trace_ram_save_queue_pages(ramblock->idstr, start, len); - if (start + len > ramblock->used_length) { + if (!offset_in_ramblock(ramblock, start + len - 1)) { error_report("%s request overrun start=" RAM_ADDR_FMT " len=" RAM_ADDR_FMT " blocklen=" RAM_ADDR_FMT, __func__, start, len, ramblock->used_length); @@ -3696,8 +3696,8 @@ void colo_flush_ram_cache(void) while (block) { offset = migration_bitmap_find_dirty(ram_state, block, offset); - if (((ram_addr_t)offset) << TARGET_PAGE_BITS - >= block->used_length) { + if (!offset_in_ramblock(block, + ((ram_addr_t)offset) << TARGET_PAGE_BITS)) { offset = 0; block = QLIST_NEXT_RCU(block, next); } else { From a1209bb7107c850be2909393a8304ea7ae747137 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Tue, 4 May 2021 11:05:45 +0100 Subject: [PATCH 0523/3028] tests/migration-test: Fix "true" vs true MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accidental use of "true" as a boolean; spotted by coverity and Peter. Fixes: b99784ef6c3 Fixes: d795f47466e Reported-by: Peter Maydell Reported-by: Coverity (CID 1432373, 1432292, 1432288) Signed-off-by: Dr. David Alan Gilbert Message-Id: <20210504100545.112213-1-dgilbert@redhat.com> Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Dr. David Alan Gilbert --- tests/qtest/migration-test.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 3a711bb492..4d989f191b 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -898,8 +898,8 @@ static void test_xbzrle(const char *uri) migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432); - migrate_set_capability(from, "xbzrle", "true"); - migrate_set_capability(to, "xbzrle", "true"); + migrate_set_capability(from, "xbzrle", true); + migrate_set_capability(to, "xbzrle", true); /* Wait for the first serial output from the source */ wait_for_serial("src_serial"); @@ -1246,8 +1246,8 @@ static void test_multifd_tcp(const char *method) migrate_set_parameter_str(from, "multifd-compression", method); migrate_set_parameter_str(to, "multifd-compression", method); - migrate_set_capability(from, "multifd", "true"); - migrate_set_capability(to, "multifd", "true"); + migrate_set_capability(from, "multifd", true); + migrate_set_capability(to, "multifd", true); /* Start incoming migration from the 1st socket */ rsp = wait_command(to, "{ 'execute': 'migrate-incoming'," @@ -1330,8 +1330,8 @@ static void test_multifd_tcp_cancel(void) migrate_set_parameter_int(from, "multifd-channels", 16); migrate_set_parameter_int(to, "multifd-channels", 16); - migrate_set_capability(from, "multifd", "true"); - migrate_set_capability(to, "multifd", "true"); + migrate_set_capability(from, "multifd", true); + migrate_set_capability(to, "multifd", true); /* Start incoming migration from the 1st socket */ rsp = wait_command(to, "{ 'execute': 'migrate-incoming'," @@ -1358,7 +1358,7 @@ static void test_multifd_tcp_cancel(void) migrate_set_parameter_int(to2, "multifd-channels", 16); - migrate_set_capability(to2, "multifd", "true"); + migrate_set_capability(to2, "multifd", true); /* Start incoming migration from the 1st socket */ rsp = wait_command(to2, "{ 'execute': 'migrate-incoming'," From ff7b9b56cd7053eef0aaf40c32c2be475fd37df8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 May 2021 19:58:19 +0100 Subject: [PATCH 0524/3028] tests/qtest/migration-test: Use g_autofree to avoid leaks on error paths Coverity notices that several places in the migration-test code fail to free memory in error-exit paths. This is pretty unimportant in test case code, but we can avoid having to manually free the memory entirely by using g_autofree. The places where Coverity spotted a leak were relating to early exits not freeing 'uri' in test_precopy_unix(), do_test_validate_uuid(), migrate_postcopy_prepare() and test_migrate_auto_converge(). This patch converts all the string-allocation in the test code to g_autofree for consistency. Fixes: Coverity CID 1432313, 1432315, 1432352, 1432364 Signed-off-by: Peter Maydell Message-Id: <20210506185819.9010-1-peter.maydell@linaro.org> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- tests/qtest/migration-test.c | 61 ++++++++++++------------------------ 1 file changed, 20 insertions(+), 41 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 4d989f191b..2b028df687 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -110,13 +110,12 @@ static void init_bootfile(const char *bootpath, void *content, size_t len) */ static void wait_for_serial(const char *side) { - char *serialpath = g_strdup_printf("%s/%s", tmpfs, side); + g_autofree char *serialpath = g_strdup_printf("%s/%s", tmpfs, side); FILE *serialfile = fopen(serialpath, "r"); const char *arch = qtest_get_arch(); int started = (strcmp(side, "src_serial") == 0 && strcmp(arch, "ppc64") == 0) ? 0 : 1; - g_free(serialpath); do { int readvalue = fgetc(serialfile); @@ -274,10 +273,9 @@ static void check_guests_ram(QTestState *who) static void cleanup(const char *filename) { - char *path = g_strdup_printf("%s/%s", tmpfs, filename); + g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, filename); unlink(path); - g_free(path); } static char *SocketAddress_to_str(SocketAddress *addr) @@ -374,11 +372,8 @@ static char *migrate_get_parameter_str(QTestState *who, static void migrate_check_parameter_str(QTestState *who, const char *parameter, const char *value) { - char *result; - - result = migrate_get_parameter_str(who, parameter); + g_autofree char *result = migrate_get_parameter_str(who, parameter); g_assert_cmpstr(result, ==, value); - g_free(result); } static void migrate_set_parameter_str(QTestState *who, const char *parameter, @@ -495,12 +490,14 @@ static void migrate_start_destroy(MigrateStart *args) static int test_migrate_start(QTestState **from, QTestState **to, const char *uri, MigrateStart *args) { - gchar *arch_source, *arch_target; - gchar *cmd_source, *cmd_target; + g_autofree gchar *arch_source = NULL; + g_autofree gchar *arch_target = NULL; + g_autofree gchar *cmd_source = NULL; + g_autofree gchar *cmd_target = NULL; const gchar *ignore_stderr; - char *bootpath = NULL; - char *shmem_opts; - char *shmem_path; + g_autofree char *bootpath = NULL; + g_autofree char *shmem_opts = NULL; + g_autofree char *shmem_path = NULL; const char *arch = qtest_get_arch(); const char *machine_opts = NULL; const char *memory_size; @@ -559,8 +556,6 @@ static int test_migrate_start(QTestState **from, QTestState **to, g_assert_not_reached(); } - g_free(bootpath); - if (!getenv("QTEST_LOG") && args->hide_stderr) { ignore_stderr = "2>/dev/null"; } else { @@ -588,11 +583,9 @@ static int test_migrate_start(QTestState **from, QTestState **to, memory_size, tmpfs, arch_source, shmem_opts, args->opts_source, ignore_stderr); - g_free(arch_source); if (!args->only_target) { *from = qtest_init(cmd_source); } - g_free(cmd_source); cmd_target = g_strdup_printf("-accel kvm -accel tcg%s%s " "-name target,debug-threads=on " @@ -605,18 +598,14 @@ static int test_migrate_start(QTestState **from, QTestState **to, memory_size, tmpfs, uri, arch_target, shmem_opts, args->opts_target, ignore_stderr); - g_free(arch_target); *to = qtest_init(cmd_target); - g_free(cmd_target); - g_free(shmem_opts); /* * Remove shmem file immediately to avoid memory leak in test failed case. * It's valid becase QEMU has already opened this file */ if (args->use_shmem) { unlink(shmem_path); - g_free(shmem_path); } out: @@ -662,7 +651,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr, QTestState **to_ptr, MigrateStart *args) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); QTestState *from, *to; if (test_migrate_start(&from, &to, uri, args)) { @@ -684,7 +673,6 @@ static int migrate_postcopy_prepare(QTestState **from_ptr, wait_for_serial("src_serial"); migrate_qmp(from, uri, "{}"); - g_free(uri); wait_for_migration_pass(from); @@ -724,7 +712,7 @@ static void test_postcopy_recovery(void) { MigrateStart *args = migrate_start_new(); QTestState *from, *to; - char *uri; + g_autofree char *uri = NULL; args->hide_stderr = true; @@ -775,7 +763,6 @@ static void test_postcopy_recovery(void) (const char * []) { "failed", "active", "completed", NULL }); migrate_qmp(from, uri, "{'resume': true}"); - g_free(uri); /* Restore the postcopy bandwidth to unlimited */ migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0); @@ -800,7 +787,7 @@ static void test_baddest(void) static void test_precopy_unix(void) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); MigrateStart *args = migrate_start_new(); QTestState *from, *to; @@ -836,14 +823,13 @@ static void test_precopy_unix(void) wait_for_migration_complete(from); test_migrate_end(from, to, true); - g_free(uri); } #if 0 /* Currently upset on aarch64 TCG */ static void test_ignore_shared(void) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); QTestState *from, *to; if (test_migrate_start(&from, &to, uri, false, true, NULL, NULL)) { @@ -873,7 +859,6 @@ static void test_ignore_shared(void) g_assert_cmpint(read_ram_property_int(from, "transferred"), <, 1024 * 1024); test_migrate_end(from, to, true); - g_free(uri); } #endif @@ -925,16 +910,15 @@ static void test_xbzrle(const char *uri) static void test_xbzrle_unix(void) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); test_xbzrle(uri); - g_free(uri); } static void test_precopy_tcp(void) { MigrateStart *args = migrate_start_new(); - char *uri; + g_autofree char *uri = NULL; QTestState *from, *to; if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", args)) { @@ -971,7 +955,6 @@ static void test_precopy_tcp(void) wait_for_migration_complete(from); test_migrate_end(from, to, true); - g_free(uri); } static void test_migrate_fd_proto(void) @@ -1060,7 +1043,7 @@ static void test_migrate_fd_proto(void) static void do_test_validate_uuid(MigrateStart *args, bool should_fail) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); QTestState *from, *to; if (test_migrate_start(&from, &to, uri, args)) { @@ -1088,7 +1071,6 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail) } test_migrate_end(from, to, false); - g_free(uri); } static void test_validate_uuid(void) @@ -1136,7 +1118,7 @@ static void test_validate_uuid_dst_not_set(void) static void test_migrate_auto_converge(void) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); MigrateStart *args = migrate_start_new(); QTestState *from, *to; int64_t remaining, percentage; @@ -1214,7 +1196,6 @@ static void test_migrate_auto_converge(void) wait_for_serial("dest_serial"); wait_for_migration_complete(from); - g_free(uri); test_migrate_end(from, to, true); } @@ -1224,7 +1205,7 @@ static void test_multifd_tcp(const char *method) MigrateStart *args = migrate_start_new(); QTestState *from, *to; QDict *rsp; - char *uri; + g_autofree char *uri = NULL; if (test_migrate_start(&from, &to, "defer", args)) { return; @@ -1273,7 +1254,6 @@ static void test_multifd_tcp(const char *method) wait_for_serial("dest_serial"); wait_for_migration_complete(from); test_migrate_end(from, to, true); - g_free(uri); } static void test_multifd_tcp_none(void) @@ -1309,7 +1289,7 @@ static void test_multifd_tcp_cancel(void) MigrateStart *args = migrate_start_new(); QTestState *from, *to, *to2; QDict *rsp; - char *uri; + g_autofree char *uri = NULL; args->hide_stderr = true; @@ -1387,7 +1367,6 @@ static void test_multifd_tcp_cancel(void) wait_for_serial("dest_serial"); wait_for_migration_complete(from); test_migrate_end(from, to2, true); - g_free(uri); } int main(int argc, char **argv) From 1c3baa1ac4dee2b52837fda89d1d9deeb5da512e Mon Sep 17 00:00:00 2001 From: Hyman Date: Sat, 20 Mar 2021 01:04:56 +0800 Subject: [PATCH 0525/3028] tests/migration: introduce multifd into guestperf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guestperf tool does not cover the multifd-enabled migration currently, it is worth supporting so that developers can analysis the migration performance with all kinds of migration. To request that multifd is enabled, with 4 channels: $ ./tests/migration/guestperf.py \ --multifd --multifd-channels 4 --output output.json To run the entire standardized set of multifd-enabled comparisons, with unix migration: $ ./tests/migration/guestperf-batch.py \ --dst-host localhost --transport unix \ --filter compr-multifd* --output outputdir Signed-off-by: Hyman Huang(黄勇) Message-Id: Reviewed-by: Daniel P. Berrangé Signed-off-by: Dr. David Alan Gilbert --- tests/migration/guestperf/comparison.py | 14 ++++++++++++++ tests/migration/guestperf/engine.py | 16 ++++++++++++++++ tests/migration/guestperf/scenario.py | 12 ++++++++++-- tests/migration/guestperf/shell.py | 10 +++++++++- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/tests/migration/guestperf/comparison.py b/tests/migration/guestperf/comparison.py index ba2edbe546..c03b3f6d7e 100644 --- a/tests/migration/guestperf/comparison.py +++ b/tests/migration/guestperf/comparison.py @@ -121,4 +121,18 @@ COMPARISONS = [ Scenario("compr-xbzrle-cache-50", compression_xbzrle=True, compression_xbzrle_cache=50), ]), + + + # Looking at effect of multifd with + # varying numbers of channels + Comparison("compr-multifd", scenarios = [ + Scenario("compr-multifd-channels-4", + multifd=True, multifd_channels=2), + Scenario("compr-multifd-channels-8", + multifd=True, multifd_channels=8), + Scenario("compr-multifd-channels-32", + multifd=True, multifd_channels=32), + Scenario("compr-multifd-channels-64", + multifd=True, multifd_channels=64), + ]), ] diff --git a/tests/migration/guestperf/engine.py b/tests/migration/guestperf/engine.py index 6b49aed579..208e095794 100644 --- a/tests/migration/guestperf/engine.py +++ b/tests/migration/guestperf/engine.py @@ -188,6 +188,22 @@ class Engine(object): 1024 * 1024 * 1024 / 100 * scenario._compression_xbzrle_cache)) + if scenario._multifd: + resp = src.command("migrate-set-capabilities", + capabilities = [ + { "capability": "multifd", + "state": True } + ]) + resp = src.command("migrate-set-parameters", + multifd_channels=scenario._multifd_channels) + resp = dst.command("migrate-set-capabilities", + capabilities = [ + { "capability": "multifd", + "state": True } + ]) + resp = dst.command("migrate-set-parameters", + multifd_channels=scenario._multifd_channels) + resp = src.command("migrate", uri=connect_uri) post_copy = False diff --git a/tests/migration/guestperf/scenario.py b/tests/migration/guestperf/scenario.py index 28ef36c26d..de70d9b2f5 100644 --- a/tests/migration/guestperf/scenario.py +++ b/tests/migration/guestperf/scenario.py @@ -29,7 +29,8 @@ class Scenario(object): post_copy=False, post_copy_iters=5, auto_converge=False, auto_converge_step=10, compression_mt=False, compression_mt_threads=1, - compression_xbzrle=False, compression_xbzrle_cache=10): + compression_xbzrle=False, compression_xbzrle_cache=10, + multifd=False, multifd_channels=2): self._name = name @@ -56,6 +57,9 @@ class Scenario(object): self._compression_xbzrle = compression_xbzrle self._compression_xbzrle_cache = compression_xbzrle_cache # percentage of guest RAM + self._multifd = multifd + self._multifd_channels = multifd_channels + def serialize(self): return { "name": self._name, @@ -73,6 +77,8 @@ class Scenario(object): "compression_mt_threads": self._compression_mt_threads, "compression_xbzrle": self._compression_xbzrle, "compression_xbzrle_cache": self._compression_xbzrle_cache, + "multifd": self._multifd, + "multifd_channels": self._multifd_channels, } @classmethod @@ -92,4 +98,6 @@ class Scenario(object): data["compression_mt"], data["compression_mt_threads"], data["compression_xbzrle"], - data["compression_xbzrle_cache"]) + data["compression_xbzrle_cache"], + data["multifd"], + data["multifd_channels"]) diff --git a/tests/migration/guestperf/shell.py b/tests/migration/guestperf/shell.py index f838888809..8a809e3dda 100644 --- a/tests/migration/guestperf/shell.py +++ b/tests/migration/guestperf/shell.py @@ -122,6 +122,11 @@ class Shell(BaseShell): parser.add_argument("--compression-xbzrle", dest="compression_xbzrle", default=False, action="store_true") parser.add_argument("--compression-xbzrle-cache", dest="compression_xbzrle_cache", default=10, type=int) + parser.add_argument("--multifd", dest="multifd", default=False, + action="store_true") + parser.add_argument("--multifd-channels", dest="multifd_channels", + default=2, type=int) + def get_scenario(self, args): return Scenario(name="perfreport", downtime=args.downtime, @@ -142,7 +147,10 @@ class Shell(BaseShell): compression_mt_threads=args.compression_mt_threads, compression_xbzrle=args.compression_xbzrle, - compression_xbzrle_cache=args.compression_xbzrle_cache) + compression_xbzrle_cache=args.compression_xbzrle_cache, + + multifd=args.multifd, + multifd_channels=args.multifd_channels) def run(self, argv): args = self._parser.parse_args(argv) From 5a487950f9bc92114b30eeef34d7ca8db11d1b7c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 14 Apr 2021 10:19:03 +0200 Subject: [PATCH 0526/3028] tests/docker/dockerfiles: Add ccache to containers where it was missing Make sure that ccache is available in all containers. Message-Id: <20210414081907.871437-2-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/docker/dockerfiles/alpine.docker | 1 + tests/docker/dockerfiles/fedora-i386-cross.docker | 1 + tests/docker/dockerfiles/fedora-win32-cross.docker | 1 + tests/docker/dockerfiles/fedora-win64-cross.docker | 1 + tests/docker/dockerfiles/opensuse-leap.docker | 1 + 5 files changed, 5 insertions(+) diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index d63a269aef..a1ef408a6a 100644 --- a/tests/docker/dockerfiles/alpine.docker +++ b/tests/docker/dockerfiles/alpine.docker @@ -9,6 +9,7 @@ ENV PACKAGES \ alsa-lib-dev \ bash \ binutils \ + ccache \ coreutils \ curl-dev \ g++ \ diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker index 966072c08e..66cdb06c19 100644 --- a/tests/docker/dockerfiles/fedora-i386-cross.docker +++ b/tests/docker/dockerfiles/fedora-i386-cross.docker @@ -1,6 +1,7 @@ FROM fedora:33 ENV PACKAGES \ bzip2 \ + ccache \ diffutils \ findutils \ gcc \ diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker index 81b5659e9c..3733df63e9 100644 --- a/tests/docker/dockerfiles/fedora-win32-cross.docker +++ b/tests/docker/dockerfiles/fedora-win32-cross.docker @@ -4,6 +4,7 @@ FROM fedora:33 ENV PACKAGES \ bc \ bzip2 \ + ccache \ diffutils \ findutils \ gcc \ diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker index bcb428e724..2564ce4979 100644 --- a/tests/docker/dockerfiles/fedora-win64-cross.docker +++ b/tests/docker/dockerfiles/fedora-win64-cross.docker @@ -4,6 +4,7 @@ FROM fedora:33 ENV PACKAGES \ bc \ bzip2 \ + ccache \ diffutils \ findutils \ gcc \ diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker index 0e64893e4a..f7e1cbfbe6 100644 --- a/tests/docker/dockerfiles/opensuse-leap.docker +++ b/tests/docker/dockerfiles/opensuse-leap.docker @@ -5,6 +5,7 @@ ENV PACKAGES \ bc \ brlapi-devel \ bzip2 \ + ccache \ cyrus-sasl-devel \ gcc \ gcc-c++ \ From 1d8b96126e76178d6a44f435ddd55727e23fd00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 19 Apr 2021 01:34:34 +0200 Subject: [PATCH 0527/3028] gitlab-ci: Replace YAML anchors by extends (container_job) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'extends' is an alternative to using YAML anchors and is a little more flexible and readable. See: https://docs.gitlab.com/ee/ci/yaml/#extends Reviewed-by: Wainer dos Santos Moschetta Reviewed-by: Thomas Huth Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210418233448.1267991-2-f4bug@amsat.org> Signed-off-by: Thomas Huth --- .gitlab-ci.d/containers.yml | 76 ++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/.gitlab-ci.d/containers.yml b/.gitlab-ci.d/containers.yml index 33e4046e23..4ef76d1f54 100644 --- a/.gitlab-ci.d/containers.yml +++ b/.gitlab-ci.d/containers.yml @@ -1,4 +1,4 @@ -.container_job_template: &container_job_definition +.container_job_template: image: docker:stable stage: containers services: @@ -22,230 +22,230 @@ - docker logout amd64-alpine-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: alpine amd64-centos7-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: centos7 amd64-centos8-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: centos8 amd64-debian10-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: debian10 amd64-debian11-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: debian11 alpha-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-alpha-cross amd64-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-amd64-cross amd64-debian-user-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-all-test-cross amd64-debian-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-amd64 arm64-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-arm64-cross arm64-test-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian11-container'] variables: NAME: debian-arm64-test-cross armel-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-armel-cross armhf-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-armhf-cross hppa-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-hppa-cross m68k-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-m68k-cross mips64-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-mips64-cross mips64el-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-mips64el-cross mips-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-mips-cross mipsel-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-mipsel-cross powerpc-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-powerpc-cross ppc64-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-ppc64-cross ppc64el-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-ppc64el-cross riscv64-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-riscv64-cross s390x-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-s390x-cross sh4-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-sh4-cross sparc64-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-sparc64-cross tricore-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template stage: containers-layer2 needs: ['amd64-debian10-container'] variables: NAME: debian-tricore-cross xtensa-debian-cross-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: debian-xtensa-cross cris-fedora-cross-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: fedora-cris-cross amd64-fedora-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: fedora i386-fedora-cross-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: fedora-i386-cross win32-fedora-cross-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: fedora-win32-cross win64-fedora-cross-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: fedora-win64-cross amd64-ubuntu1804-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: ubuntu1804 amd64-ubuntu2004-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: ubuntu2004 amd64-ubuntu-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: ubuntu amd64-opensuse-leap-container: - <<: *container_job_definition + extends: .container_job_template variables: NAME: opensuse-leap From 6683da0951ec0b508ae3e1b8758b0dd7cc7d4020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 19 Apr 2021 01:34:35 +0200 Subject: [PATCH 0528/3028] gitlab-ci: Replace YAML anchors by extends (native_build_job) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'extends' is an alternative to using YAML anchors and is a little more flexible and readable. See: https://docs.gitlab.com/ee/ci/yaml/#extends Reviewed-by: Wainer dos Santos Moschetta Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210418233448.1267991-3-f4bug@amsat.org> Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 64 +++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9876f73040..1e6caa5aff 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,7 +13,7 @@ include: - local: '/.gitlab-ci.d/containers.yml' - local: '/.gitlab-ci.d/crossbuilds.yml' -.native_build_job_template: &native_build_job_definition +.native_build_job_template: stage: build image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest before_script: @@ -83,7 +83,7 @@ include: - du -chs ${CI_PROJECT_DIR}/avocado-cache build-system-alpine: - <<: *native_build_job_definition + extends: .native_build_job_template needs: - job: amd64-alpine-container variables: @@ -118,7 +118,7 @@ acceptance-system-alpine: <<: *acceptance_definition build-system-ubuntu: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-ubuntu2004-container variables: @@ -152,7 +152,7 @@ acceptance-system-ubuntu: <<: *acceptance_definition build-system-debian: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-container variables: @@ -186,7 +186,7 @@ acceptance-system-debian: <<: *acceptance_definition build-system-fedora: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-fedora-container variables: @@ -221,7 +221,7 @@ acceptance-system-fedora: <<: *acceptance_definition build-system-centos: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-centos8-container variables: @@ -256,7 +256,7 @@ acceptance-system-centos: <<: *acceptance_definition build-system-opensuse: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-opensuse-leap-container variables: @@ -290,7 +290,7 @@ acceptance-system-opensuse: build-disabled: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-fedora-container variables: @@ -376,7 +376,7 @@ build-disabled: # Also use a different coroutine implementation (which is only really of # interest to KVM users, i.e. with TCG disabled) build-tcg-disabled: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-centos8-container variables: @@ -399,7 +399,7 @@ build-tcg-disabled: 260 261 262 263 264 270 272 273 277 279 build-user: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-user-cross-container variables: @@ -408,7 +408,7 @@ build-user: MAKE_CHECK_ARGS: check-tcg build-user-static: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-user-cross-container variables: @@ -418,7 +418,7 @@ build-user-static: # Only build the softmmu targets we have check-tcg tests for build-some-softmmu: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-user-cross-container variables: @@ -431,7 +431,7 @@ build-some-softmmu: # we skip sparc64-linux-user until it has been fixed somewhat # we skip cris-linux-user as it doesn't use the common run loop build-user-plugins: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-user-cross-container variables: @@ -441,7 +441,7 @@ build-user-plugins: timeout: 1h 30m build-user-centos7: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-centos7-container variables: @@ -450,7 +450,7 @@ build-user-centos7: MAKE_CHECK_ARGS: check-tcg build-some-softmmu-plugins: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-user-cross-container variables: @@ -460,7 +460,7 @@ build-some-softmmu-plugins: MAKE_CHECK_ARGS: check-tcg clang-system: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-fedora-container variables: @@ -472,7 +472,7 @@ clang-system: MAKE_CHECK_ARGS: check-qtest check-tcg clang-user: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-user-cross-container variables: @@ -494,7 +494,7 @@ clang-user: # Split in three sets of build/check/acceptance to limit the execution time of each # job build-cfi-aarch64: - <<: *native_build_job_definition + extends: .native_build_job_template needs: - job: amd64-fedora-container variables: @@ -531,7 +531,7 @@ acceptance-cfi-aarch64: <<: *acceptance_definition build-cfi-ppc64-s390x: - <<: *native_build_job_definition + extends: .native_build_job_template needs: - job: amd64-fedora-container variables: @@ -568,7 +568,7 @@ acceptance-cfi-ppc64-s390x: <<: *acceptance_definition build-cfi-x86_64: - <<: *native_build_job_definition + extends: .native_build_job_template needs: - job: amd64-fedora-container variables: @@ -605,7 +605,7 @@ acceptance-cfi-x86_64: <<: *acceptance_definition tsan-build: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-ubuntu2004-container variables: @@ -617,7 +617,7 @@ tsan-build: # These targets are on the way out build-deprecated: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-user-cross-container variables: @@ -644,7 +644,7 @@ check-deprecated: # gprof/gcov are GCC features gprof-gcov: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-ubuntu2004-container variables: @@ -657,7 +657,7 @@ gprof-gcov: - ${CI_PROJECT_DIR}/scripts/ci/coverage-summary.sh build-oss-fuzz: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-fedora-container variables: @@ -677,7 +677,7 @@ build-oss-fuzz: - cd build-oss-fuzz && make check-qtest-i386 check-unit build-tci: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-user-cross-container variables: @@ -702,7 +702,7 @@ build-tci: # Alternate coroutines implementations are only really of interest to KVM users # However we can't test against KVM on Gitlab-CI so we can only run unit tests build-coroutine-sigaltstack: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-ubuntu2004-container variables: @@ -716,7 +716,7 @@ build-coroutine-sigaltstack: # These jobs test old gcrypt and nettle from RHEL7 # which had some API differences. crypto-old-nettle: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-centos7-container variables: @@ -726,7 +726,7 @@ crypto-old-nettle: MAKE_CHECK_ARGS: check crypto-old-gcrypt: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-centos7-container variables: @@ -736,7 +736,7 @@ crypto-old-gcrypt: MAKE_CHECK_ARGS: check crypto-only-gnutls: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-centos7-container variables: @@ -748,7 +748,7 @@ crypto-only-gnutls: # Check our reduced build configurations build-without-default-devices: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-centos8-container variables: @@ -756,7 +756,7 @@ build-without-default-devices: CONFIGURE_ARGS: --without-default-devices --disable-user build-without-default-features: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-container variables: @@ -806,7 +806,7 @@ build-libvhost-user: # No targets are built here, just tools, docs, and unit tests. This # also feeds into the eventual documentation deployment steps later build-tools-and-docs-debian: - <<: *native_build_job_definition + extends: .native_build_job_template needs: job: amd64-debian-container variables: From e267ce590071e687b178c61dd68ba4868a134bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 19 Apr 2021 01:34:36 +0200 Subject: [PATCH 0529/3028] gitlab-ci: Replace YAML anchors by extends (native_test_job) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'extends' is an alternative to using YAML anchors and is a little more flexible and readable. See: https://docs.gitlab.com/ee/ci/yaml/#extends Reviewed-by: Wainer dos Santos Moschetta Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210418233448.1267991-4-f4bug@amsat.org> Signed-off-by: Thomas Huth --- .gitlab-ci.yml | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1e6caa5aff..24f300aace 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,7 +41,7 @@ include: make -j"$JOBS" $MAKE_CHECK_ARGS ; fi -.native_test_job_template: &native_test_job_definition +.native_test_job_template: stage: test image: $CI_REGISTRY_IMAGE/qemu/$IMAGE:latest script: @@ -99,7 +99,7 @@ build-system-alpine: - build check-system-alpine: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-alpine artifacts: true @@ -108,7 +108,7 @@ check-system-alpine: MAKE_CHECK_ARGS: check acceptance-system-alpine: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-alpine artifacts: true @@ -133,7 +133,7 @@ build-system-ubuntu: - build check-system-ubuntu: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-ubuntu artifacts: true @@ -142,7 +142,7 @@ check-system-ubuntu: MAKE_CHECK_ARGS: check acceptance-system-ubuntu: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-ubuntu artifacts: true @@ -167,7 +167,7 @@ build-system-debian: - build check-system-debian: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-debian artifacts: true @@ -176,7 +176,7 @@ check-system-debian: MAKE_CHECK_ARGS: check acceptance-system-debian: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-debian artifacts: true @@ -202,7 +202,7 @@ build-system-fedora: - build check-system-fedora: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-fedora artifacts: true @@ -211,7 +211,7 @@ check-system-fedora: MAKE_CHECK_ARGS: check acceptance-system-fedora: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-fedora artifacts: true @@ -237,7 +237,7 @@ build-system-centos: - build check-system-centos: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-centos artifacts: true @@ -246,7 +246,7 @@ check-system-centos: MAKE_CHECK_ARGS: check acceptance-system-centos: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-centos artifacts: true @@ -270,7 +270,7 @@ build-system-opensuse: - build check-system-opensuse: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-opensuse artifacts: true @@ -279,7 +279,7 @@ check-system-opensuse: MAKE_CHECK_ARGS: check acceptance-system-opensuse: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-system-opensuse artifacts: true @@ -512,7 +512,7 @@ build-cfi-aarch64: - build check-cfi-aarch64: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-cfi-aarch64 artifacts: true @@ -521,7 +521,7 @@ check-cfi-aarch64: MAKE_CHECK_ARGS: check acceptance-cfi-aarch64: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-cfi-aarch64 artifacts: true @@ -549,7 +549,7 @@ build-cfi-ppc64-s390x: - build check-cfi-ppc64-s390x: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-cfi-ppc64-s390x artifacts: true @@ -558,7 +558,7 @@ check-cfi-ppc64-s390x: MAKE_CHECK_ARGS: check acceptance-cfi-ppc64-s390x: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-cfi-ppc64-s390x artifacts: true @@ -586,7 +586,7 @@ build-cfi-x86_64: - build check-cfi-x86_64: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-cfi-x86_64 artifacts: true @@ -595,7 +595,7 @@ check-cfi-x86_64: MAKE_CHECK_ARGS: check acceptance-cfi-x86_64: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-cfi-x86_64 artifacts: true @@ -633,7 +633,7 @@ build-deprecated: # We split the check-tcg step as test failures are expected but we still # want to catch the build breaking. check-deprecated: - <<: *native_test_job_definition + extends: .native_test_job_template needs: - job: build-deprecated artifacts: true From f62215298a3c38b3b64271f9c6a93ca2f28115a3 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 12 Apr 2021 15:34:36 +0100 Subject: [PATCH 0530/3028] libqos/qgraph: fix "UNAVAILBLE" typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Hajnoczi Message-Id: <20210412143437.727560-2-stefanha@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Acked-by: Paolo Bonzini Signed-off-by: Thomas Huth --- tests/qtest/libqos/qgraph.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/libqos/qgraph.c b/tests/qtest/libqos/qgraph.c index b3b1a31f81..d1dc491930 100644 --- a/tests/qtest/libqos/qgraph.c +++ b/tests/qtest/libqos/qgraph.c @@ -844,7 +844,7 @@ void qos_dump_graph(void) } qos_printf_literal("type=%d cmd_line='%s' [%s]\n", node->type, node->command_line, - node->available ? "available" : "UNAVAILBLE" + node->available ? "available" : "UNAVAILABLE" ); } g_list_free(keys); From ce508a3c29c2fdaeea785a00abcf35cf90da7c2d Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 12 Apr 2021 15:34:37 +0100 Subject: [PATCH 0531/3028] docs/devel/qgraph: add troubleshooting information It can be tricky to troubleshoot qos-test when a test won't execute. Add an explanation of how to trace qgraph node connectivity and find which node has the problem. Signed-off-by: Stefan Hajnoczi Message-Id: <20210412143437.727560-3-stefanha@redhat.com> Acked-by: Paolo Bonzini Signed-off-by: Thomas Huth --- docs/devel/qgraph.rst | 58 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/docs/devel/qgraph.rst b/docs/devel/qgraph.rst index a9aff167ad..318534d4b0 100644 --- a/docs/devel/qgraph.rst +++ b/docs/devel/qgraph.rst @@ -92,6 +92,64 @@ The basic framework steps are the following: Depending on the QEMU binary used, only some drivers/machines will be available and only test that are reached by them will be executed. +Troubleshooting unavailable tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +If there is no path from an available machine to a test then that test will be +unavailable and won't execute. This can happen if a test or driver did not set +up its qgraph node correctly. It can also happen if the necessary machine type +or device is missing from the QEMU binary because it was compiled out or +otherwise. + +It is possible to troubleshoot unavailable tests by running:: + + $ QTEST_QEMU_BINARY=build/qemu-system-x86_64 build/tests/qtest/qos-test --verbose + # ALL QGRAPH EDGES: { + # src='virtio-net' + # |-> dest='virtio-net-tests/vhost-user/multiqueue' type=2 (node=0x559142109e30) + # |-> dest='virtio-net-tests/vhost-user/migrate' type=2 (node=0x559142109d00) + # src='virtio-net-pci' + # |-> dest='virtio-net' type=1 (node=0x55914210d740) + # src='pci-bus' + # |-> dest='virtio-net-pci' type=2 (node=0x55914210d880) + # src='pci-bus-pc' + # |-> dest='pci-bus' type=1 (node=0x559142103f40) + # src='i440FX-pcihost' + # |-> dest='pci-bus-pc' type=0 (node=0x55914210ac70) + # src='x86_64/pc' + # |-> dest='i440FX-pcihost' type=0 (node=0x5591421117f0) + # src='' + # |-> dest='x86_64/pc' type=0 (node=0x559142111600) + # |-> dest='arm/raspi2' type=0 (node=0x559142110740) + ... + # } + # ALL QGRAPH NODES: { + # name='virtio-net-tests/announce-self' type=3 cmd_line='(null)' [available] + # name='arm/raspi2' type=0 cmd_line='-M raspi2 ' [UNAVAILABLE] + ... + # } + +The ``virtio-net-tests/announce-self`` test is listed as "available" in the +"ALL QGRAPH NODES" output. This means the test will execute. We can follow the +qgraph path in the "ALL QGRAPH EDGES" output as follows: '' -> 'x86_64/pc' -> +'i440FX-pcihost' -> 'pci-bus-pc' -> 'pci-bus' -> 'virtio-net-pci' -> +'virtio-net'. The root of the qgraph is '' and the depth first search begins +there. + +The ``arm/raspi`` machine node is listed as "UNAVAILABLE". Although it is +reachable from the root via '' -> 'arm/raspi2' the node is unavailable because +the QEMU binary did not list it when queried by the framework. This is expected +because we used the ``qemu-system-x86_64`` binary which does not support ARM +machine types. + +If a test is unexpectedly listed as "UNAVAILABLE", first check that the "ALL +QGRAPH EDGES" output reports edge connectivity from the root ('') to the test. +If there is no connectivity then the qgraph nodes were not set up correctly and +the driver or test code is incorrect. If there is connectivity, check the +availability of each node in the path in the "ALL QGRAPH NODES" output. The +first unavailable node in the path is the reason why the test is unavailable. +Typically this is because the QEMU binary lacks support for the necessary +machine type or device. + Creating a new driver and its interface """"""""""""""""""""""""""""""""""""""""" From 20868330a9d13228e59d0818d77f271cf1141280 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 12 Apr 2021 15:30:50 +0100 Subject: [PATCH 0532/3028] libqtest: refuse QTEST_QEMU_BINARY=qemu-kvm Some downstreams rename the QEMU binary to "qemu-kvm". This breaks qtest_get_arch(), which attempts to parse the target architecture from the QTEST_QEMU_BINARY environment variable. Print an error instead of returning the architecture "kvm". Things fail in weird ways when the architecture string is bogus. Arguably qtests should always be run in a build directory instead of against an installed QEMU. In any case, printing a clear error when this happens is helpful. Since this is an error that is triggered by the user and not a test failure, use exit(1) instead of abort(). Change the existing abort() call in qtest_get_arch() to exit(1) too for the same reason and to be consistent. Reported-by: Qin Wang Signed-off-by: Stefan Hajnoczi Reviewed-by: Emanuele Giuseppe Esposito Reviewed-by: Thomas Huth Cc: Emanuele Giuseppe Esposito Message-Id: <20210412143050.725918-1-stefanha@redhat.com> Signed-off-by: Thomas Huth --- tests/qtest/libqtest.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 71e359efcd..825b13a44c 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -907,7 +907,14 @@ const char *qtest_get_arch(void) if (!end) { fprintf(stderr, "Can't determine architecture from binary name.\n"); - abort(); + exit(1); + } + + if (!strstr(qemu, "-system-")) { + fprintf(stderr, "QTEST_QEMU_BINARY must end with *-system- " + "where 'arch' is the target\narchitecture (x86_64, aarch64, " + "etc).\n"); + exit(1); } return end + 1; From e0c5a18efc56fcb3b480507d8f04fb4eb9cda92f Mon Sep 17 00:00:00 2001 From: Mahmoud Mandour Date: Mon, 15 Mar 2021 12:58:14 +0200 Subject: [PATCH 0533/3028] util/compatfd.c: Replaced a malloc call with g_malloc. Replaced a call to malloc() and its respective call to free() with g_malloc() and g_free(). g_malloc() is preferred more than g_try_* functions, which return NULL on error, when the size of the requested allocation is small. This is because allocating few bytes should not be a problem in a healthy system. Otherwise, the system is already in a critical state. Subsequently, removed NULL-checking after g_malloc(). Signed-off-by: Mahmoud Mandour Message-Id: <20210315105814.5188-3-ma.mandourr@gmail.com> Signed-off-by: Thomas Huth --- util/compatfd.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/util/compatfd.c b/util/compatfd.c index 174f394533..a8ec525c6c 100644 --- a/util/compatfd.c +++ b/util/compatfd.c @@ -72,14 +72,10 @@ static int qemu_signalfd_compat(const sigset_t *mask) QemuThread thread; int fds[2]; - info = malloc(sizeof(*info)); - if (info == NULL) { - errno = ENOMEM; - return -1; - } + info = g_malloc(sizeof(*info)); if (pipe(fds) == -1) { - free(info); + g_free(info); return -1; } From 423dbce5a2bf392bf9f6ab655a672d3d6654c325 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 May 2021 20:43:58 +0100 Subject: [PATCH 0534/3028] tests/qtest/ahci-test.c: Calculate iso_size with 64-bit arithmetic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coverity notes that when calculating the 64-bit iso_size value in ahci_test_cdrom() we actually only do it with 32-bit arithmetic. This doesn't matter for the current test code because nsectors is always small; but adding the cast avoids the coverity complaints. Fixes: Coverity CID 1432343 Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: John Snow Message-Id: <20210506194358.3925-1-peter.maydell@linaro.org> Signed-off-by: Thomas Huth --- tests/qtest/ahci-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c index 5e1954852e..8073ccc205 100644 --- a/tests/qtest/ahci-test.c +++ b/tests/qtest/ahci-test.c @@ -1491,14 +1491,14 @@ static void ahci_test_cdrom(int nsectors, bool dma, uint8_t cmd, char *iso; int fd; AHCIOpts opts = { - .size = (ATAPI_SECTOR_SIZE * nsectors), + .size = ((uint64_t)ATAPI_SECTOR_SIZE * nsectors), .atapi = true, .atapi_dma = dma, .post_cb = ahci_cb_cmp_buff, .set_bcl = override_bcl, .bcl = bcl, }; - uint64_t iso_size = ATAPI_SECTOR_SIZE * (nsectors + 1); + uint64_t iso_size = (uint64_t)ATAPI_SECTOR_SIZE * (nsectors + 1); /* Prepare ISO and fill 'tx' buffer */ fd = prepare_iso(iso_size, &tx, &iso); From 302585450c667cac06371a80446eedf670d2d510 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 5 May 2021 14:55:16 +0100 Subject: [PATCH 0535/3028] tests/qtest/npcm7xx_pwm-test.c: Avoid g_assert_true() for non-test assertions In the glib API, the distinction between g_assert() and g_assert_true() is that the former is for "bug, terminate the application" and the latter is for "test check, on failure either terminate or just mark the testcase as failed". For QEMU, g_assert() is always fatal, so code can assume that if the assertion fails execution does not proceed, but this is not true of g_assert_true(). In npcm7xx_pwm-test, the pwm_index() and pwm_module_index() functions include some assertions that are just guarding against possible bugs in the test code that might lead us to out-of-bounds array accesses. These should use g_assert() because they aren't part of what the test is testing and the code does not correctly handle the case where the condition was false. This fixes some Coverity issues where Coverity knows that g_assert_true() can continue when the condition is false and complains about the possible array overrun at various callsites. Fixes: Coverity CID 1442340, 1442341, 1442343, 1442344, 1442345, 1442346 Signed-off-by: Peter Maydell Reviewed-by: Thomas Huth Reviewed-by: Hao Wu Reviewed-by: Havard Skinnemoen Message-Id: <20210505135516.21097-1-peter.maydell@linaro.org> Signed-off-by: Thomas Huth --- tests/qtest/npcm7xx_pwm-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c index bd15a1c294..a54fd70d27 100644 --- a/tests/qtest/npcm7xx_pwm-test.c +++ b/tests/qtest/npcm7xx_pwm-test.c @@ -201,7 +201,7 @@ static int pwm_module_index(const PWMModule *module) { ptrdiff_t diff = module - pwm_module_list; - g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list)); + g_assert(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list)); return diff; } @@ -211,7 +211,7 @@ static int pwm_index(const PWM *pwm) { ptrdiff_t diff = pwm - pwm_list; - g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_list)); + g_assert(diff >= 0 && diff < ARRAY_SIZE(pwm_list)); return diff; } From 3a46f81676c717876213e27950d153a3ccd85f2f Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Tue, 4 May 2021 11:05:45 +0100 Subject: [PATCH 0536/3028] tests/migration-test: Fix "true" vs true MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accidental use of "true" as a boolean; spotted by coverity and Peter. Fixes: b99784ef6c3 Fixes: d795f47466e Reported-by: Peter Maydell Reported-by: Coverity (CID 1432373, 1432292, 1432288) Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20210504100545.112213-1-dgilbert@redhat.com> Signed-off-by: Thomas Huth --- tests/qtest/migration-test.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 3a711bb492..4d989f191b 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -898,8 +898,8 @@ static void test_xbzrle(const char *uri) migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432); - migrate_set_capability(from, "xbzrle", "true"); - migrate_set_capability(to, "xbzrle", "true"); + migrate_set_capability(from, "xbzrle", true); + migrate_set_capability(to, "xbzrle", true); /* Wait for the first serial output from the source */ wait_for_serial("src_serial"); @@ -1246,8 +1246,8 @@ static void test_multifd_tcp(const char *method) migrate_set_parameter_str(from, "multifd-compression", method); migrate_set_parameter_str(to, "multifd-compression", method); - migrate_set_capability(from, "multifd", "true"); - migrate_set_capability(to, "multifd", "true"); + migrate_set_capability(from, "multifd", true); + migrate_set_capability(to, "multifd", true); /* Start incoming migration from the 1st socket */ rsp = wait_command(to, "{ 'execute': 'migrate-incoming'," @@ -1330,8 +1330,8 @@ static void test_multifd_tcp_cancel(void) migrate_set_parameter_int(from, "multifd-channels", 16); migrate_set_parameter_int(to, "multifd-channels", 16); - migrate_set_capability(from, "multifd", "true"); - migrate_set_capability(to, "multifd", "true"); + migrate_set_capability(from, "multifd", true); + migrate_set_capability(to, "multifd", true); /* Start incoming migration from the 1st socket */ rsp = wait_command(to, "{ 'execute': 'migrate-incoming'," @@ -1358,7 +1358,7 @@ static void test_multifd_tcp_cancel(void) migrate_set_parameter_int(to2, "multifd-channels", 16); - migrate_set_capability(to2, "multifd", "true"); + migrate_set_capability(to2, "multifd", true); /* Start incoming migration from the 1st socket */ rsp = wait_command(to2, "{ 'execute': 'migrate-incoming'," From e7b13acdf2bc6f05bbad46f76c7cb63f63426918 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 May 2021 17:55:23 +0100 Subject: [PATCH 0537/3028] tests/qtest/tpm-util.c: Free memory with correct free function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tpm_util_migration_start_qemu() allocates memory with g_strdup_printf() but frees it with free() rather than g_free(), which provokes Coverity complaints (CID 1432379, 1432350). Use the correct free function. Fixes: Coverity CID 1432379, CID 1432350 Signed-off-by: Peter Maydell Reviewed-by: Stefan Berger Reviewed-by: Alex Bennée Message-Id: <20210503165525.26221-2-peter.maydell@linaro.org> Signed-off-by: Thomas Huth --- tests/qtest/tpm-util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c index b70cc32d60..3a40ff3f96 100644 --- a/tests/qtest/tpm-util.c +++ b/tests/qtest/tpm-util.c @@ -289,6 +289,6 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, *dst_qemu = qtest_init(dst_qemu_args); - free(src_qemu_args); - free(dst_qemu_args); + g_free(src_qemu_args); + g_free(dst_qemu_args); } From 6c054176dba1c3669f7dbf0f3b6bf9e7245a0dfe Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 May 2021 17:55:24 +0100 Subject: [PATCH 0538/3028] tests/qtest/rtc-test: Remove pointless NULL check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In rtc-test.c we know that s is non-NULL because qtest_start() will return a non-NULL value, and we assume this when we pass s to qtest_irq_intercept_in(). So we can drop the initial assignment of NULL and the "if (s)" condition at the end of the function. Fixes: Coverity CID 1432353 Signed-off-by: Peter Maydell Reviewed-by: Thomas Huth Reviewed-by: Alex Bennée Message-Id: <20210503165525.26221-3-peter.maydell@linaro.org> Signed-off-by: Thomas Huth --- tests/qtest/rtc-test.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/qtest/rtc-test.c b/tests/qtest/rtc-test.c index 402ce2c609..8126ab1bdb 100644 --- a/tests/qtest/rtc-test.c +++ b/tests/qtest/rtc-test.c @@ -686,7 +686,7 @@ static void periodic_timer(void) int main(int argc, char **argv) { - QTestState *s = NULL; + QTestState *s; int ret; g_test_init(&argc, &argv, NULL); @@ -712,9 +712,7 @@ int main(int argc, char **argv) ret = g_test_run(); - if (s) { - qtest_quit(s); - } + qtest_quit(s); return ret; } From bfaa3b05a9af6acd011e772fa42eff5d05424a35 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 3 May 2021 17:55:25 +0100 Subject: [PATCH 0539/3028] tests: Avoid side effects inside g_assert() arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For us, assertions are always enabled, but side-effect expressions inside the argument to g_assert() are bad style anyway. Fix three occurrences in IPMI related tests, which will silence some Coverity nits. Fixes: CID 1432322, CID 1432287, CID 1432291 Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Message-Id: <20210503165525.26221-4-peter.maydell@linaro.org> Signed-off-by: Thomas Huth --- tests/qtest/ipmi-bt-test.c | 6 ++++-- tests/qtest/ipmi-kcs-test.c | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/qtest/ipmi-bt-test.c b/tests/qtest/ipmi-bt-test.c index a42207d416..8492f02a9c 100644 --- a/tests/qtest/ipmi-bt-test.c +++ b/tests/qtest/ipmi-bt-test.c @@ -98,7 +98,8 @@ static void bt_wait_b_busy(void) { unsigned int count = 1000; while (IPMI_BT_CTLREG_GET_B_BUSY() != 0) { - g_assert(--count != 0); + --count; + g_assert(count != 0); usleep(100); } } @@ -107,7 +108,8 @@ static void bt_wait_b2h_atn(void) { unsigned int count = 1000; while (IPMI_BT_CTLREG_GET_B2H_ATN() == 0) { - g_assert(--count != 0); + --count; + g_assert(count != 0); usleep(100); } } diff --git a/tests/qtest/ipmi-kcs-test.c b/tests/qtest/ipmi-kcs-test.c index fc0a918c8d..afc24dd3e4 100644 --- a/tests/qtest/ipmi-kcs-test.c +++ b/tests/qtest/ipmi-kcs-test.c @@ -73,7 +73,8 @@ static void kcs_wait_ibf(void) { unsigned int count = 1000; while (IPMI_KCS_CMDREG_GET_IBF() != 0) { - g_assert(--count != 0); + --count; + g_assert(count != 0); } } From 13b48fb00e61dc7662da27c020c3263b74374acc Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 14 Apr 2021 13:20:01 +0200 Subject: [PATCH 0540/3028] include/sysemu: Poison all accelerator CONFIG switches in common code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are already poisoning CONFIG_KVM since this switch is not working in common code. Do the same with the other accelerator switches, too (except for CONFIG_TCG, which is special, since it is also defined in config-host.h). Message-Id: <20210414112004.943383-2-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- include/exec/poison.h | 4 ++++ include/sysemu/hax.h | 4 ++++ include/sysemu/hvf.h | 4 ++++ include/sysemu/whpx.h | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/include/exec/poison.h b/include/exec/poison.h index 8fc7530b6e..a527def5f0 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -83,8 +83,12 @@ #pragma GCC poison CONFIG_SPARC_DIS #pragma GCC poison CONFIG_XTENSA_DIS +#pragma GCC poison CONFIG_HAX +#pragma GCC poison CONFIG_HVF #pragma GCC poison CONFIG_LINUX_USER #pragma GCC poison CONFIG_KVM #pragma GCC poison CONFIG_SOFTMMU +#pragma GCC poison CONFIG_WHPX +#pragma GCC poison CONFIG_XEN #endif diff --git a/include/sysemu/hax.h b/include/sysemu/hax.h index 12fb54f990..247f0661d1 100644 --- a/include/sysemu/hax.h +++ b/include/sysemu/hax.h @@ -24,6 +24,8 @@ int hax_sync_vcpus(void); +#ifdef NEED_CPU_H + #ifdef CONFIG_HAX int hax_enabled(void); @@ -34,4 +36,6 @@ int hax_enabled(void); #endif /* CONFIG_HAX */ +#endif /* NEED_CPU_H */ + #endif /* QEMU_HAX_H */ diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index c98636bc81..bb70082e45 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -16,6 +16,8 @@ #include "qemu/accel.h" #include "qom/object.h" +#ifdef NEED_CPU_H + #ifdef CONFIG_HVF uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, int reg); @@ -26,6 +28,8 @@ extern bool hvf_allowed; #define hvf_get_supported_cpuid(func, idx, reg) 0 #endif /* !CONFIG_HVF */ +#endif /* NEED_CPU_H */ + #define TYPE_HVF_ACCEL ACCEL_CLASS_NAME("hvf") typedef struct HVFState HVFState; diff --git a/include/sysemu/whpx.h b/include/sysemu/whpx.h index 8ca1c1c4ac..2889fa2278 100644 --- a/include/sysemu/whpx.h +++ b/include/sysemu/whpx.h @@ -13,6 +13,8 @@ #ifndef QEMU_WHPX_H #define QEMU_WHPX_H +#ifdef NEED_CPU_H + #ifdef CONFIG_WHPX int whpx_enabled(void); @@ -25,4 +27,6 @@ bool whpx_apic_in_platform(void); #endif /* CONFIG_WHPX */ +#endif /* NEED_CPU_H */ + #endif /* QEMU_WHPX_H */ From 43bd0bf30fcee4170e137ecd0929053454f7d295 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 14 Apr 2021 13:20:02 +0200 Subject: [PATCH 0541/3028] migration: Move populate_vfio_info() into a separate file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CONFIG_VFIO switch only works in target specific code. Since migration/migration.c is common code, the #ifdef does not have the intended behavior here. Move the related code to a separate file now which gets compiled via specific_ss instead. Fixes: 3710586caa ("qapi: Add VFIO devices migration stats in Migration stats") Message-Id: <20210414112004.943383-3-thuth@redhat.com> Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- migration/meson.build | 3 ++- migration/migration.c | 15 --------------- migration/migration.h | 2 ++ migration/target.c | 25 +++++++++++++++++++++++++ 4 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 migration/target.c diff --git a/migration/meson.build b/migration/meson.build index 3ecedce94d..f8714dcb15 100644 --- a/migration/meson.build +++ b/migration/meson.build @@ -31,4 +31,5 @@ softmmu_ss.add(when: ['CONFIG_RDMA', rdma], if_true: files('rdma.c')) softmmu_ss.add(when: 'CONFIG_LIVE_BLOCK_MIGRATION', if_true: files('block.c')) softmmu_ss.add(when: zstd, if_true: files('multifd-zstd.c')) -specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: files('dirtyrate.c', 'ram.c')) +specific_ss.add(when: 'CONFIG_SOFTMMU', + if_true: files('dirtyrate.c', 'ram.c', 'target.c')) diff --git a/migration/migration.c b/migration/migration.c index 8ca034136b..db8c378079 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -60,10 +60,6 @@ #include "qemu/yank.h" #include "sysemu/cpus.h" -#ifdef CONFIG_VFIO -#include "hw/vfio/vfio-common.h" -#endif - #define MAX_THROTTLE (128 << 20) /* Migration transfer speed throttling */ /* Amount of time to allocate to each "chunk" of bandwidth-throttled @@ -1059,17 +1055,6 @@ static void populate_disk_info(MigrationInfo *info) } } -static void populate_vfio_info(MigrationInfo *info) -{ -#ifdef CONFIG_VFIO - if (vfio_mig_active()) { - info->has_vfio = true; - info->vfio = g_malloc0(sizeof(*info->vfio)); - info->vfio->transferred = vfio_mig_bytes_transferred(); - } -#endif -} - static void fill_source_migration_info(MigrationInfo *info) { MigrationState *s = migrate_get_current(); diff --git a/migration/migration.h b/migration/migration.h index db6708326b..2730fa05c0 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -376,4 +376,6 @@ void migration_make_urgent_request(void); void migration_consume_urgent_request(void); bool migration_rate_limit(void); +void populate_vfio_info(MigrationInfo *info); + #endif diff --git a/migration/target.c b/migration/target.c new file mode 100644 index 0000000000..907ebf0a0a --- /dev/null +++ b/migration/target.c @@ -0,0 +1,25 @@ +/* + * QEMU live migration - functions that need to be compiled target-specific + * + * This work is licensed under the terms of the GNU GPL, version 2 + * or (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qapi/qapi-types-migration.h" +#include "migration.h" + +#ifdef CONFIG_VFIO +#include "hw/vfio/vfio-common.h" +#endif + +void populate_vfio_info(MigrationInfo *info) +{ +#ifdef CONFIG_VFIO + if (vfio_mig_active()) { + info->has_vfio = true; + info->vfio = g_malloc0(sizeof(*info->vfio)); + info->vfio->transferred = vfio_mig_bytes_transferred(); + } +#endif +} From e0447a834d6170485ad925344223896d0d1d3810 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 14 Apr 2021 13:20:04 +0200 Subject: [PATCH 0542/3028] configure: Poison all current target-specific #defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are generating a lot of target-specific defines in the *-config-devices.h and *-config-target.h files. Using them in common code is wrong and leads to very subtle bugs since a "#ifdef CONFIG_SOMETHING" is not working there as expected. To avoid these issues, we are already poisoning many of the macros in include/exec/poison.h - but it's cumbersome to maintain this list manually. Thus let's generate an additional list of poisoned macros automatically from the current config switches - this should give us a much better test coverage via the different CI configurations. Note that CONFIG_TCG (which is also defined in config-host.h) and CONFIG_USER_ONLY are special, so we have to filter these out. Message-Id: <20210414112004.943383-5-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- Makefile | 2 +- configure | 7 +++++++ include/exec/poison.h | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bcbbec71a1..4cab10a2a4 100644 --- a/Makefile +++ b/Makefile @@ -213,7 +213,7 @@ qemu-%.tar.bz2: distclean: clean -$(quiet-@)test -f build.ninja && $(NINJA) $(NINJAFLAGS) -t clean -g || : - rm -f config-host.mak config-host.h* + rm -f config-host.mak config-host.h* config-poison.h rm -f tests/tcg/config-*.mak rm -f config-all-disas.mak config.status rm -f roms/seabios/config.mak roms/vgabios/config.mak diff --git a/configure b/configure index f05ca143b3..0e4233fd8a 100755 --- a/configure +++ b/configure @@ -6473,6 +6473,13 @@ if test -n "${deprecated_features}"; then echo " features: ${deprecated_features}" fi +# Create list of config switches that should be poisoned in common code... +# but filter out CONFIG_TCG and CONFIG_USER_ONLY which are special. +sed -n -e '/CONFIG_TCG/d' -e '/CONFIG_USER_ONLY/d' \ + -e '/^#define / { s///; s/ .*//; s/^/#pragma GCC poison /p; }' \ + *-config-devices.h *-config-target.h | \ + sort -u > config-poison.h + # Save the configure command line for later reuse. cat <config.status #!/bin/sh diff --git a/include/exec/poison.h b/include/exec/poison.h index a527def5f0..7ad4ad18e8 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -4,6 +4,8 @@ #ifndef HW_POISON_H #define HW_POISON_H +#include "config-poison.h" + #pragma GCC poison TARGET_I386 #pragma GCC poison TARGET_X86_64 #pragma GCC poison TARGET_AARCH64 From 2ed765fdeed88cb5434148f0d6ef27ece3dc063c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 6 May 2021 19:58:19 +0100 Subject: [PATCH 0543/3028] tests/qtest/migration-test: Use g_autofree to avoid leaks on error paths Coverity notices that several places in the migration-test code fail to free memory in error-exit paths. This is pretty unimportant in test case code, but we can avoid having to manually free the memory entirely by using g_autofree. The places where Coverity spotted a leak were relating to early exits not freeing 'uri' in test_precopy_unix(), do_test_validate_uuid(), migrate_postcopy_prepare() and test_migrate_auto_converge(). This patch converts all the string-allocation in the test code to g_autofree for consistency. Fixes: Coverity CID 1432313, 1432315, 1432352, 1432364 Signed-off-by: Peter Maydell Reviewed-by: Dr. David Alan Gilbert Message-Id: <20210506185819.9010-1-peter.maydell@linaro.org> Signed-off-by: Thomas Huth --- tests/qtest/migration-test.c | 61 ++++++++++++------------------------ 1 file changed, 20 insertions(+), 41 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index 4d989f191b..2b028df687 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -110,13 +110,12 @@ static void init_bootfile(const char *bootpath, void *content, size_t len) */ static void wait_for_serial(const char *side) { - char *serialpath = g_strdup_printf("%s/%s", tmpfs, side); + g_autofree char *serialpath = g_strdup_printf("%s/%s", tmpfs, side); FILE *serialfile = fopen(serialpath, "r"); const char *arch = qtest_get_arch(); int started = (strcmp(side, "src_serial") == 0 && strcmp(arch, "ppc64") == 0) ? 0 : 1; - g_free(serialpath); do { int readvalue = fgetc(serialfile); @@ -274,10 +273,9 @@ static void check_guests_ram(QTestState *who) static void cleanup(const char *filename) { - char *path = g_strdup_printf("%s/%s", tmpfs, filename); + g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, filename); unlink(path); - g_free(path); } static char *SocketAddress_to_str(SocketAddress *addr) @@ -374,11 +372,8 @@ static char *migrate_get_parameter_str(QTestState *who, static void migrate_check_parameter_str(QTestState *who, const char *parameter, const char *value) { - char *result; - - result = migrate_get_parameter_str(who, parameter); + g_autofree char *result = migrate_get_parameter_str(who, parameter); g_assert_cmpstr(result, ==, value); - g_free(result); } static void migrate_set_parameter_str(QTestState *who, const char *parameter, @@ -495,12 +490,14 @@ static void migrate_start_destroy(MigrateStart *args) static int test_migrate_start(QTestState **from, QTestState **to, const char *uri, MigrateStart *args) { - gchar *arch_source, *arch_target; - gchar *cmd_source, *cmd_target; + g_autofree gchar *arch_source = NULL; + g_autofree gchar *arch_target = NULL; + g_autofree gchar *cmd_source = NULL; + g_autofree gchar *cmd_target = NULL; const gchar *ignore_stderr; - char *bootpath = NULL; - char *shmem_opts; - char *shmem_path; + g_autofree char *bootpath = NULL; + g_autofree char *shmem_opts = NULL; + g_autofree char *shmem_path = NULL; const char *arch = qtest_get_arch(); const char *machine_opts = NULL; const char *memory_size; @@ -559,8 +556,6 @@ static int test_migrate_start(QTestState **from, QTestState **to, g_assert_not_reached(); } - g_free(bootpath); - if (!getenv("QTEST_LOG") && args->hide_stderr) { ignore_stderr = "2>/dev/null"; } else { @@ -588,11 +583,9 @@ static int test_migrate_start(QTestState **from, QTestState **to, memory_size, tmpfs, arch_source, shmem_opts, args->opts_source, ignore_stderr); - g_free(arch_source); if (!args->only_target) { *from = qtest_init(cmd_source); } - g_free(cmd_source); cmd_target = g_strdup_printf("-accel kvm -accel tcg%s%s " "-name target,debug-threads=on " @@ -605,18 +598,14 @@ static int test_migrate_start(QTestState **from, QTestState **to, memory_size, tmpfs, uri, arch_target, shmem_opts, args->opts_target, ignore_stderr); - g_free(arch_target); *to = qtest_init(cmd_target); - g_free(cmd_target); - g_free(shmem_opts); /* * Remove shmem file immediately to avoid memory leak in test failed case. * It's valid becase QEMU has already opened this file */ if (args->use_shmem) { unlink(shmem_path); - g_free(shmem_path); } out: @@ -662,7 +651,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr, QTestState **to_ptr, MigrateStart *args) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); QTestState *from, *to; if (test_migrate_start(&from, &to, uri, args)) { @@ -684,7 +673,6 @@ static int migrate_postcopy_prepare(QTestState **from_ptr, wait_for_serial("src_serial"); migrate_qmp(from, uri, "{}"); - g_free(uri); wait_for_migration_pass(from); @@ -724,7 +712,7 @@ static void test_postcopy_recovery(void) { MigrateStart *args = migrate_start_new(); QTestState *from, *to; - char *uri; + g_autofree char *uri = NULL; args->hide_stderr = true; @@ -775,7 +763,6 @@ static void test_postcopy_recovery(void) (const char * []) { "failed", "active", "completed", NULL }); migrate_qmp(from, uri, "{'resume': true}"); - g_free(uri); /* Restore the postcopy bandwidth to unlimited */ migrate_set_parameter_int(from, "max-postcopy-bandwidth", 0); @@ -800,7 +787,7 @@ static void test_baddest(void) static void test_precopy_unix(void) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); MigrateStart *args = migrate_start_new(); QTestState *from, *to; @@ -836,14 +823,13 @@ static void test_precopy_unix(void) wait_for_migration_complete(from); test_migrate_end(from, to, true); - g_free(uri); } #if 0 /* Currently upset on aarch64 TCG */ static void test_ignore_shared(void) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); QTestState *from, *to; if (test_migrate_start(&from, &to, uri, false, true, NULL, NULL)) { @@ -873,7 +859,6 @@ static void test_ignore_shared(void) g_assert_cmpint(read_ram_property_int(from, "transferred"), <, 1024 * 1024); test_migrate_end(from, to, true); - g_free(uri); } #endif @@ -925,16 +910,15 @@ static void test_xbzrle(const char *uri) static void test_xbzrle_unix(void) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); test_xbzrle(uri); - g_free(uri); } static void test_precopy_tcp(void) { MigrateStart *args = migrate_start_new(); - char *uri; + g_autofree char *uri = NULL; QTestState *from, *to; if (test_migrate_start(&from, &to, "tcp:127.0.0.1:0", args)) { @@ -971,7 +955,6 @@ static void test_precopy_tcp(void) wait_for_migration_complete(from); test_migrate_end(from, to, true); - g_free(uri); } static void test_migrate_fd_proto(void) @@ -1060,7 +1043,7 @@ static void test_migrate_fd_proto(void) static void do_test_validate_uuid(MigrateStart *args, bool should_fail) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); QTestState *from, *to; if (test_migrate_start(&from, &to, uri, args)) { @@ -1088,7 +1071,6 @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail) } test_migrate_end(from, to, false); - g_free(uri); } static void test_validate_uuid(void) @@ -1136,7 +1118,7 @@ static void test_validate_uuid_dst_not_set(void) static void test_migrate_auto_converge(void) { - char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); MigrateStart *args = migrate_start_new(); QTestState *from, *to; int64_t remaining, percentage; @@ -1214,7 +1196,6 @@ static void test_migrate_auto_converge(void) wait_for_serial("dest_serial"); wait_for_migration_complete(from); - g_free(uri); test_migrate_end(from, to, true); } @@ -1224,7 +1205,7 @@ static void test_multifd_tcp(const char *method) MigrateStart *args = migrate_start_new(); QTestState *from, *to; QDict *rsp; - char *uri; + g_autofree char *uri = NULL; if (test_migrate_start(&from, &to, "defer", args)) { return; @@ -1273,7 +1254,6 @@ static void test_multifd_tcp(const char *method) wait_for_serial("dest_serial"); wait_for_migration_complete(from); test_migrate_end(from, to, true); - g_free(uri); } static void test_multifd_tcp_none(void) @@ -1309,7 +1289,7 @@ static void test_multifd_tcp_cancel(void) MigrateStart *args = migrate_start_new(); QTestState *from, *to, *to2; QDict *rsp; - char *uri; + g_autofree char *uri = NULL; args->hide_stderr = true; @@ -1387,7 +1367,6 @@ static void test_multifd_tcp_cancel(void) wait_for_serial("dest_serial"); wait_for_migration_complete(from); test_migrate_end(from, to2, true); - g_free(uri); } int main(int argc, char **argv) From 052b66e7211af64964e005126eaa3c944b296b0e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 12 May 2021 19:15:48 +0200 Subject: [PATCH 0544/3028] pc-bios/s390-ccw: Fix inline assembly for older versions of Clang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang versions before v11.0 insist on having the %rX or %cX register names instead of just a number. Since our Travis-CI is currently still using Clang v6.0, we have to fix this to avoid failing jobs. Message-Id: <20210512171550.476130-2-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/helper.h | 2 +- pc-bios/s390-ccw/jump2ipl.c | 4 ++-- pc-bios/s390-ccw/menu.c | 8 ++++---- pc-bios/s390-ccw/virtio.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pc-bios/s390-ccw/helper.h b/pc-bios/s390-ccw/helper.h index dfcfea0ff0..3d0731c4c6 100644 --- a/pc-bios/s390-ccw/helper.h +++ b/pc-bios/s390-ccw/helper.h @@ -31,7 +31,7 @@ static inline void *u32toptr(uint32_t n) static inline void yield(void) { - asm volatile ("diag 0,0,0x44" + asm volatile ("diag %%r0,%%r0,0x44" : : : "memory", "cc"); } diff --git a/pc-bios/s390-ccw/jump2ipl.c b/pc-bios/s390-ccw/jump2ipl.c index 73e4367e09..78f5f46533 100644 --- a/pc-bios/s390-ccw/jump2ipl.c +++ b/pc-bios/s390-ccw/jump2ipl.c @@ -64,8 +64,8 @@ void jump_to_IPL_code(uint64_t address) * We use the load normal reset to keep r15 unchanged. jump_to_IPL_2 * can then use r15 as its stack pointer. */ - asm volatile("lghi 1,1\n\t" - "diag 1,1,0x308\n\t" + asm volatile("lghi %%r1,1\n\t" + "diag %%r1,%%r1,0x308\n\t" : : : "1", "memory"); panic("\n! IPL returns !\n"); } diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c index de8260a5d6..d601952d3e 100644 --- a/pc-bios/s390-ccw/menu.c +++ b/pc-bios/s390-ccw/menu.c @@ -36,9 +36,9 @@ static inline void enable_clock_int(void) uint64_t tmp = 0; asm volatile( - "stctg 0,0,%0\n" + "stctg %%c0,%%c0,%0\n" "oi 6+%0, 0x8\n" - "lctlg 0,0,%0" + "lctlg %%c0,%%c0,%0" : : "Q" (tmp) : "memory" ); } @@ -48,9 +48,9 @@ static inline void disable_clock_int(void) uint64_t tmp = 0; asm volatile( - "stctg 0,0,%0\n" + "stctg %%c0,%%c0,%0\n" "ni 6+%0, 0xf7\n" - "lctlg 0,0,%0" + "lctlg %%c0,%%c0,%0" : : "Q" (tmp) : "memory" ); } diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c index ab49840db8..5d2c6e3381 100644 --- a/pc-bios/s390-ccw/virtio.c +++ b/pc-bios/s390-ccw/virtio.c @@ -54,7 +54,7 @@ static long kvm_hypercall(unsigned long nr, unsigned long param1, register ulong r_param3 asm("4") = param3; register long retval asm("2"); - asm volatile ("diag 2,4,0x500" + asm volatile ("diag %%r2,%%r4,0x500" : "=d" (retval) : "d" (r_nr), "0" (r_param1), "r"(r_param2), "d"(r_param3) : "memory", "cc"); From 73e6aec6522e1edd63f631c52577b49a39bc234f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 23 Mar 2021 15:53:28 +0400 Subject: [PATCH 0545/3028] sphinx: adopt kernel readthedoc theme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default "alabaster" sphinx theme has a couple shortcomings: - the navbar moves along the page - the search bar is not always at the same place - it lacks some contrast and colours The "rtd" theme from readthedocs.org is a popular third party theme used notably by the kernel, with a custom style sheet. I like it better, perhaps others do too. It also simplifies the "Edit on Gitlab" links. Tweak a bit the custom theme to match qemu.org style, use the QEMU logo, and favicon etc. Signed-off-by: Marc-André Lureau Tested-by: Bin Meng Message-Id: <20210323115328.4146052-1-marcandre.lureau@redhat.com> Reviewed-by: John Snow --- docs/_templates/editpage.html | 5 - docs/conf.py | 52 ++++--- docs/devel/_templates/editpage.html | 5 - docs/interop/_templates/editpage.html | 5 - docs/meson.build | 5 +- docs/specs/_templates/editpage.html | 5 - docs/sphinx-static/theme_overrides.css | 161 +++++++++++++++++++++ docs/system/_templates/editpage.html | 5 - docs/tools/_templates/editpage.html | 5 - docs/user/_templates/editpage.html | 5 - tests/docker/dockerfiles/alpine.docker | 1 + tests/docker/dockerfiles/debian10.docker | 1 + tests/docker/dockerfiles/fedora.docker | 1 + tests/docker/dockerfiles/ubuntu.docker | 1 + tests/docker/dockerfiles/ubuntu1804.docker | 1 + tests/docker/dockerfiles/ubuntu2004.docker | 1 + 16 files changed, 200 insertions(+), 59 deletions(-) delete mode 100644 docs/_templates/editpage.html delete mode 100644 docs/devel/_templates/editpage.html delete mode 100644 docs/interop/_templates/editpage.html delete mode 100644 docs/specs/_templates/editpage.html create mode 100644 docs/sphinx-static/theme_overrides.css delete mode 100644 docs/system/_templates/editpage.html delete mode 100644 docs/tools/_templates/editpage.html delete mode 100644 docs/user/_templates/editpage.html diff --git a/docs/_templates/editpage.html b/docs/_templates/editpage.html deleted file mode 100644 index 4319b0f5ac..0000000000 --- a/docs/_templates/editpage.html +++ /dev/null @@ -1,5 +0,0 @@ -

diff --git a/docs/conf.py b/docs/conf.py index 2ee6111872..00cf66ab54 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -29,6 +29,7 @@ import os import sys import sphinx +from distutils.version import LooseVersion from sphinx.errors import ConfigError # Make Sphinx fail cleanly if using an old Python, rather than obscurely @@ -150,38 +151,47 @@ with open(os.path.join(qemu_docdir, 'defs.rst.inc')) as f: # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +try: + import sphinx_rtd_theme +except ImportError: + raise ConfigError( + 'The Sphinx \'sphinx_rtd_theme\' HTML theme was not found.\n' + ) + +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -# We initialize this to empty here, so the per-manual conf.py can just -# add individual key/value entries. -html_theme_options = { -} +if LooseVersion(sphinx_rtd_theme.__version__) >= LooseVersion("0.4.3"): + html_theme_options = { + "style_nav_header_background": "#802400", + } + +html_logo = os.path.join(qemu_docdir, "../ui/icons/qemu_128x128.png") + +html_favicon = os.path.join(qemu_docdir, "../ui/icons/qemu_32x32.png") # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -# QEMU doesn't yet have any static files, so comment this out so we don't -# get a warning about a missing directory. -# If we do ever add this then it would probably be better to call the -# subdirectory sphinx_static, as the Linux kernel does. -# html_static_path = ['_static'] +html_static_path = [os.path.join(qemu_docdir, "sphinx-static")] + +html_css_files = [ + 'theme_overrides.css', +] + +html_context = { + "display_gitlab": True, + "gitlab_user": "qemu-project", + "gitlab_repo": "qemu", + "gitlab_version": "master", + "conf_py_path": "/docs/", # Path in the checkout to the docs root +} # Custom sidebar templates, must be a dictionary that maps document names # to template names. -# -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'about.html', - 'editpage.html', - 'navigation.html', - 'searchbox.html', - ] -} +#html_sidebars = {} # Don't copy the rST source files to the HTML output directory, # and don't put links to the sources into the output HTML. diff --git a/docs/devel/_templates/editpage.html b/docs/devel/_templates/editpage.html deleted file mode 100644 index a86d22bca8..0000000000 --- a/docs/devel/_templates/editpage.html +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/docs/interop/_templates/editpage.html b/docs/interop/_templates/editpage.html deleted file mode 100644 index 215e562681..0000000000 --- a/docs/interop/_templates/editpage.html +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/docs/meson.build b/docs/meson.build index f84306ba7e..855e3916e9 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -27,10 +27,9 @@ if sphinx_build.found() build_docs = (sphinx_build_test_out.returncode() == 0) if not build_docs - warning('@0@ is either too old or uses too old a Python version' - .format(sphinx_build.full_path())) + warning('@0@: @1@'.format(sphinx_build.full_path(), sphinx_build_test_out.stderr())) if get_option('docs').enabled() - error('Install a Python 3 version of python-sphinx') + error('Install a Python 3 version of python-sphinx and the readthedoc theme') endif endif endif diff --git a/docs/specs/_templates/editpage.html b/docs/specs/_templates/editpage.html deleted file mode 100644 index aaa468aa98..0000000000 --- a/docs/specs/_templates/editpage.html +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/docs/sphinx-static/theme_overrides.css b/docs/sphinx-static/theme_overrides.css new file mode 100644 index 0000000000..c70ef95128 --- /dev/null +++ b/docs/sphinx-static/theme_overrides.css @@ -0,0 +1,161 @@ +/* -*- coding: utf-8; mode: css -*- + * + * Sphinx HTML theme customization: read the doc + * Based on Linux Documentation/sphinx-static/theme_overrides.css + */ + +/* Improve contrast and increase size for easier reading. */ + +body { + font-family: serif; + color: black; + font-size: 100%; +} + +h1, h2, .rst-content .toctree-wrapper p.caption, h3, h4, h5, h6, legend { + font-family: sans-serif; +} + +.rst-content dl:not(.docutils) dt { + border-top: none; + border-left: solid 3px #ccc; + background-color: #f0f0f0; + color: black; +} + +.wy-nav-top { + background: #802400; +} + +.wy-side-nav-search input[type="text"] { + border-color: #f60; +} + +.wy-menu-vertical p.caption { + color: white; +} + +.wy-menu-vertical li.current a { + color: #505050; +} + +.wy-menu-vertical li.on a, .wy-menu-vertical li.current > a { + color: #303030; +} + +.fa-gitlab { + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2), 0 3px 10px 0 rgba(0,0,0,0.19); + border-radius: 5px; +} + +div[class^="highlight"] pre { + font-family: monospace; + color: black; + font-size: 100%; +} + +.wy-menu-vertical { + font-family: sans-serif; +} + +.c { + font-style: normal; +} + +p { + font-size: 100%; +} + +/* Interim: Code-blocks with line nos - lines and line numbers don't line up. + * see: https://github.com/rtfd/sphinx_rtd_theme/issues/419 + */ + +div[class^="highlight"] pre { + line-height: normal; +} +.rst-content .highlight > pre { + line-height: normal; +} + +/* Keep fields from being strangely far apart due to inheirited table CSS. */ +.rst-content table.field-list th.field-name { + padding-top: 1px; + padding-bottom: 1px; +} +.rst-content table.field-list td.field-body { + padding-top: 1px; + padding-bottom: 1px; +} + +@media screen { + + /* content column + * + * RTD theme's default is 800px as max width for the content, but we have + * tables with tons of columns, which need the full width of the view-port. + */ + + .wy-nav-content{max-width: none; } + + /* table: + * + * - Sequences of whitespace should collapse into a single whitespace. + * - make the overflow auto (scrollbar if needed) + * - align caption "left" ("center" is unsuitable on vast tables) + */ + + .wy-table-responsive table td { white-space: normal; } + .wy-table-responsive { overflow: auto; } + .rst-content table.docutils caption { text-align: left; font-size: 100%; } + + /* captions: + * + * - captions should have 100% (not 85%) font size + * - hide the permalink symbol as long as link is not hovered + */ + + .toc-title { + font-size: 150%; + font-weight: bold; + } + + caption, .wy-table caption, .rst-content table.field-list caption { + font-size: 100%; + } + caption a.headerlink { opacity: 0; } + caption a.headerlink:hover { opacity: 1; } + + /* Menu selection and keystrokes */ + + span.menuselection { + color: blue; + font-family: "Courier New", Courier, monospace + } + + code.kbd, code.kbd span { + color: white; + background-color: darkblue; + font-weight: bold; + font-family: "Courier New", Courier, monospace + } + + /* fix bottom margin of lists items */ + + .rst-content .section ul li:last-child, .rst-content .section ul li p:last-child { + margin-bottom: 12px; + } + + /* inline literal: drop the borderbox, padding and red color */ + + code, .rst-content tt, .rst-content code { + color: inherit; + border: none; + padding: unset; + background: inherit; + font-size: 85%; + } + + .rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal { + color: inherit; + } +} diff --git a/docs/system/_templates/editpage.html b/docs/system/_templates/editpage.html deleted file mode 100644 index 6586b2e257..0000000000 --- a/docs/system/_templates/editpage.html +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/docs/tools/_templates/editpage.html b/docs/tools/_templates/editpage.html deleted file mode 100644 index 2a9c8fc92b..0000000000 --- a/docs/tools/_templates/editpage.html +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/docs/user/_templates/editpage.html b/docs/user/_templates/editpage.html deleted file mode 100644 index 1f5ee01e60..0000000000 --- a/docs/user/_templates/editpage.html +++ /dev/null @@ -1,5 +0,0 @@ -
- -
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker index d63a269aef..88d3bbe5f2 100644 --- a/tests/docker/dockerfiles/alpine.docker +++ b/tests/docker/dockerfiles/alpine.docker @@ -39,6 +39,7 @@ ENV PACKAGES \ pulseaudio-dev \ python3 \ py3-sphinx \ + py3-sphinx_rtd_theme \ shadow \ snappy-dev \ spice-dev \ diff --git a/tests/docker/dockerfiles/debian10.docker b/tests/docker/dockerfiles/debian10.docker index d034acbd25..63cf835ec5 100644 --- a/tests/docker/dockerfiles/debian10.docker +++ b/tests/docker/dockerfiles/debian10.docker @@ -32,6 +32,7 @@ RUN apt update && \ psmisc \ python3 \ python3-sphinx \ + python3-sphinx-rtd-theme \ $(apt-get -s build-dep --arch-only qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2) ENV FEATURES docs diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index 915fdc1845..d8fa16372d 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -92,6 +92,7 @@ ENV PACKAGES \ python3-pillow \ python3-pip \ python3-sphinx \ + python3-sphinx_rtd_theme \ python3-virtualenv \ rdma-core-devel \ SDL2-devel \ diff --git a/tests/docker/dockerfiles/ubuntu.docker b/tests/docker/dockerfiles/ubuntu.docker index b5ef7a8198..98a527361c 100644 --- a/tests/docker/dockerfiles/ubuntu.docker +++ b/tests/docker/dockerfiles/ubuntu.docker @@ -63,6 +63,7 @@ ENV PACKAGES \ ninja-build \ python3-yaml \ python3-sphinx \ + python3-sphinx-rtd-theme \ sparse \ xfslibs-dev RUN apt-get update && \ diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker index 9b0a19ba5e..c0d3642507 100644 --- a/tests/docker/dockerfiles/ubuntu1804.docker +++ b/tests/docker/dockerfiles/ubuntu1804.docker @@ -48,6 +48,7 @@ ENV PACKAGES \ make \ python3-yaml \ python3-sphinx \ + python3-sphinx-rtd-theme \ ninja-build \ sparse \ xfslibs-dev diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker index 9750016e51..f1e0ebad49 100644 --- a/tests/docker/dockerfiles/ubuntu2004.docker +++ b/tests/docker/dockerfiles/ubuntu2004.docker @@ -58,6 +58,7 @@ ENV PACKAGES flex bison \ python3-pil \ python3-pip \ python3-sphinx \ + python3-sphinx-rtd-theme \ python3-venv \ python3-yaml \ rpm2cpio \ From 568740bedf22cc8d0ec9ab1ce522a97baab5961c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 27 Apr 2021 20:55:24 +0200 Subject: [PATCH 0546/3028] cirrus.yml: Fix the MSYS2 task The MSYS2 task in the Cirrus-CI is currently failing with error messages like this: warning: database file for 'ucrt64' does not exist (use '-Sy' to download) :: Starting core system upgrade... there is nothing to do :: Starting full system upgrade... error: failed to prepare transaction (could not find database) Seems like it can be fixed by switching to a newer release and by refreshing the database one more time after changing the /etc/pacman.conf file. Message-Id: <20210504100223.25427-30-alex.bennee@linaro.org> Reviewed-by: Yonggang Luo Signed-off-by: Thomas Huth --- .cirrus.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index f53c519447..f4bf49b704 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -67,7 +67,7 @@ windows_msys2_task: CIRRUS_SHELL: powershell MSYS: winsymlinks:nativestrict MSYSTEM: MINGW64 - MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2021-01-05/msys2-base-x86_64-20210105.sfx.exe + MSYS2_URL: https://github.com/msys2/msys2-installer/releases/download/2021-04-19/msys2-base-x86_64-20210419.sfx.exe MSYS2_FINGERPRINT: 0 MSYS2_PACKAGES: " diffutils git grep make pkg-config sed @@ -130,7 +130,7 @@ windows_msys2_task: taskkill /F /FI "MODULES eq msys-2.0.dll" tasklist C:\tools\msys64\usr\bin\bash.exe -lc "mv -f /etc/pacman.conf.pacnew /etc/pacman.conf || true" - C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -Suu --overwrite=*" + C:\tools\msys64\usr\bin\bash.exe -lc "pacman --noconfirm -Syuu --overwrite=*" Write-Output "Core install time taken: $((Get-Date).Subtract($start_time))" $start_time = Get-Date From 4c21e3534a0b0373258d559f50a65d0e5385b7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 May 2021 12:41:55 +0200 Subject: [PATCH 0547/3028] hw/virtio: Pass virtio_feature_get_config_size() a const argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VirtIOFeature structure isn't modified, mark it const. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210511104157.2880306-2-philmd@redhat.com> --- hw/virtio/virtio.c | 2 +- include/hw/virtio/virtio.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 07f4e60b30..564ca63246 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2982,7 +2982,7 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val) return ret; } -size_t virtio_feature_get_config_size(VirtIOFeature *feature_sizes, +size_t virtio_feature_get_config_size(const VirtIOFeature *feature_sizes, uint64_t host_features) { size_t config_size = 0; diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index b7ece7a6a8..8bab9cfb75 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -43,7 +43,7 @@ typedef struct VirtIOFeature { size_t end; } VirtIOFeature; -size_t virtio_feature_get_config_size(VirtIOFeature *features, +size_t virtio_feature_get_config_size(const VirtIOFeature *features, uint64_t host_features); typedef struct VirtQueue VirtQueue; From 01ce7724a17521083d70114e9f24fb9d2d51e29c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 May 2021 12:41:56 +0200 Subject: [PATCH 0548/3028] virtio-blk: Constify VirtIOFeature feature_sizes[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210511104157.2880306-3-philmd@redhat.com> --- hw/block/virtio-blk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index d28979efb8..f139cd7cc9 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -40,7 +40,7 @@ * Starting from the discard feature, we can use this array to properly * set the config size depending on the features enabled. */ -static VirtIOFeature feature_sizes[] = { +static const VirtIOFeature feature_sizes[] = { {.flags = 1ULL << VIRTIO_BLK_F_DISCARD, .end = endof(struct virtio_blk_config, discard_sector_alignment)}, {.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES, From ad6461ad6eb3cf36c5d535da5f036f75dd145bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 11 May 2021 12:41:57 +0200 Subject: [PATCH 0549/3028] virtio-net: Constify VirtIOFeature feature_sizes[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210511104157.2880306-4-philmd@redhat.com> --- hw/net/virtio-net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 66b9ff4511..6b7e8dd04e 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -89,7 +89,7 @@ VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \ VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) -static VirtIOFeature feature_sizes[] = { +static const VirtIOFeature feature_sizes[] = { {.flags = 1ULL << VIRTIO_NET_F_MAC, .end = endof(struct virtio_net_config, mac)}, {.flags = 1ULL << VIRTIO_NET_F_STATUS, From 48e824e06b4fd331a384c99ff633d5bdc9584a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 22 Apr 2021 08:41:27 +0200 Subject: [PATCH 0550/3028] MAINTAINERS: Add include/exec/gen-icount.h to 'Main Loop' section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the 'Main Loop' section covers softmmu/icount.c, add "exec/gen-icount.h" there too. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210422064128.2318616-2-f4bug@amsat.org> Signed-off-by: Richard Henderson --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index f73354fc8a..6f73315dcc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2429,6 +2429,7 @@ F: ui/cocoa.m Main loop M: Paolo Bonzini S: Maintained +F: include/exec/gen-icount.h F: include/qemu/main-loop.h F: include/sysemu/runstate.h F: include/sysemu/runstate-action.h From 91150447be25a12b59c8168996471af33ab10277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 22 Apr 2021 08:41:28 +0200 Subject: [PATCH 0551/3028] exec/gen-icount.h: Add missing "exec/exec-all.h" include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When including "exec/gen-icount.h" we get: include/exec/gen-icount.h: In function ‘gen_tb_start’: include/exec/gen-icount.h:40:9: error: implicit declaration of function ‘tb_cflags’ [-Werror=implicit-function-declaration] 40 | if (tb_cflags(tb) & CF_USE_ICOUNT) { | ^~~~~~~~~ include/exec/gen-icount.h:40:9: error: nested extern declaration of ‘tb_cflags’ [-Werror=nested-externs] include/exec/gen-icount.h:40:25: error: ‘CF_USE_ICOUNT’ undeclared (first use in this function); did you mean ‘CPU_COUNT’? 40 | if (tb_cflags(tb) & CF_USE_ICOUNT) { | ^~~~~~~~~~~~~ | CPU_COUNT Since tb_cflags() is declared in "exec/exec-all.h", include this header in "exec/gen-icount.h". Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210422064128.2318616-3-f4bug@amsat.org> Signed-off-by: Richard Henderson --- include/exec/gen-icount.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index 298e01eef4..467529d84c 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -1,6 +1,7 @@ #ifndef GEN_ICOUNT_H #define GEN_ICOUNT_H +#include "exec/exec-all.h" #include "qemu/timer.h" /* Helpers for instruction counting code generation. */ From 4d87fcddb54d801c7c1c9d83d17ab0a7d10b637f Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Wed, 12 May 2021 15:54:33 -0300 Subject: [PATCH 0552/3028] tcg: Add tcg_constant_tl Used in ppc D/DS/X-form load/store implementation. Signed-off-by: Matheus Ferst Message-Id: <20210512185441.3619828-24-matheus.ferst@eldorado.org.br> Signed-off-by: Richard Henderson --- include/tcg/tcg-op.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 2cd1faf9c4..ef8a008ea7 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -1096,6 +1096,7 @@ void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t); #define tcg_gen_sextract_tl tcg_gen_sextract_i64 #define tcg_gen_extract2_tl tcg_gen_extract2_i64 #define tcg_const_tl tcg_const_i64 +#define tcg_constant_tl tcg_constant_i64 #define tcg_const_local_tl tcg_const_local_i64 #define tcg_gen_movcond_tl tcg_gen_movcond_i64 #define tcg_gen_add2_tl tcg_gen_add2_i64 @@ -1209,6 +1210,7 @@ void tcg_gen_stl_vec(TCGv_vec r, TCGv_ptr base, TCGArg offset, TCGType t); #define tcg_gen_sextract_tl tcg_gen_sextract_i32 #define tcg_gen_extract2_tl tcg_gen_extract2_i32 #define tcg_const_tl tcg_const_i32 +#define tcg_constant_tl tcg_constant_i32 #define tcg_const_local_tl tcg_const_local_i32 #define tcg_gen_movcond_tl tcg_gen_movcond_i32 #define tcg_gen_add2_tl tcg_gen_add2_i32 From f7afa7daa08c09d7c8435a95a13f6bd9dd11255e Mon Sep 17 00:00:00 2001 From: Connor Kuehl Date: Wed, 21 Apr 2021 16:23:42 -0500 Subject: [PATCH 0553/3028] iotests/231: Update expected deprecation message The deprecation message in the expected output has technically been wrong since the wrong version of a patch was applied to it. Because of this, the test fails. Correct the expected output so that it passes. Signed-off-by: Connor Kuehl Reviewed-by: Max Reitz Reviewed-by: Stefano Garzarella Message-Id: <20210421212343.85524-2-ckuehl@redhat.com> Signed-off-by: Max Reitz --- tests/qemu-iotests/231.out | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/qemu-iotests/231.out b/tests/qemu-iotests/231.out index 579ba11c16..747dd221bb 100644 --- a/tests/qemu-iotests/231.out +++ b/tests/qemu-iotests/231.out @@ -1,9 +1,7 @@ QA output created by 231 -qemu-img: RBD options encoded in the filename as keyvalue pairs is deprecated. Future versions may cease to parse these options in the future. +qemu-img: warning: RBD options encoded in the filename as keyvalue pairs is deprecated unable to get monitor info from DNS SRV with service name: ceph-mon -no monitors specified to connect to. qemu-img: Could not open 'json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=BOGUS_CONF'}': error connecting: No such file or directory unable to get monitor info from DNS SRV with service name: ceph-mon -no monitors specified to connect to. qemu-img: Could not open 'json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'BOGUS_CONF'}': error connecting: No such file or directory *** done From 2b99cfce08da53a07e86271747fe465556ac7eb4 Mon Sep 17 00:00:00 2001 From: Connor Kuehl Date: Wed, 21 Apr 2021 16:23:43 -0500 Subject: [PATCH 0554/3028] block/rbd: Add an escape-aware strchr helper Sometimes the parser needs to further split a token it has collected from the token input stream. Right now, it does a cursory check to see if the relevant characters appear in the token to determine if it should break it down further. However, qemu_rbd_next_tok() will escape characters as it removes tokens from the token stream and plain strchr() won't. This can make the initial strchr() check slightly misleading since it implies qemu_rbd_next_tok() will find the token and split on it, except the reality is that qemu_rbd_next_tok() will pass over it if it is escaped. Use a custom strchr to avoid mixing escaped and unescaped string operations. Furthermore, this code is identical to how qemu_rbd_next_tok() seeks its next token, so incorporate this custom strchr into the body of that function to reduce duplication. Reported-by: Han Han Fixes: https://bugzilla.redhat.com/1873913 Signed-off-by: Connor Kuehl Message-Id: <20210421212343.85524-3-ckuehl@redhat.com> Reviewed-by: Stefano Garzarella Signed-off-by: Max Reitz --- block/rbd.c | 32 +++++++++++++++++++++----------- tests/qemu-iotests/231 | 4 ++++ tests/qemu-iotests/231.out | 3 +++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/block/rbd.c b/block/rbd.c index f098a89c7b..26f64cce7c 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -113,21 +113,31 @@ static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, const char *keypairs, const char *secretid, Error **errp); +static char *qemu_rbd_strchr(char *src, char delim) +{ + char *p; + + for (p = src; *p; ++p) { + if (*p == delim) { + return p; + } + if (*p == '\\' && p[1] != '\0') { + ++p; + } + } + + return NULL; +} + + static char *qemu_rbd_next_tok(char *src, char delim, char **p) { char *end; *p = NULL; - for (end = src; *end; ++end) { - if (*end == delim) { - break; - } - if (*end == '\\' && end[1] != '\0') { - end++; - } - } - if (*end == delim) { + end = qemu_rbd_strchr(src, delim); + if (end) { *p = end + 1; *end = '\0'; } @@ -171,7 +181,7 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options, qemu_rbd_unescape(found_str); qdict_put_str(options, "pool", found_str); - if (strchr(p, '@')) { + if (qemu_rbd_strchr(p, '@')) { image_name = qemu_rbd_next_tok(p, '@', &p); found_str = qemu_rbd_next_tok(p, ':', &p); @@ -181,7 +191,7 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options, image_name = qemu_rbd_next_tok(p, ':', &p); } /* Check for namespace in the image_name */ - if (strchr(image_name, '/')) { + if (qemu_rbd_strchr(image_name, '/')) { found_str = qemu_rbd_next_tok(image_name, '/', &image_name); qemu_rbd_unescape(found_str); qdict_put_str(options, "namespace", found_str); diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231 index 0f66d0ca36..8e6c6447c1 100755 --- a/tests/qemu-iotests/231 +++ b/tests/qemu-iotests/231 @@ -55,6 +55,10 @@ _filter_conf() $QEMU_IMG info "json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=${BOGUS_CONF}'}" 2>&1 | _filter_conf $QEMU_IMG info "json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'${BOGUS_CONF}'}" 2>&1 | _filter_conf +# Regression test: the qemu-img invocation is expected to fail, but it should +# not seg fault the parser. +$QEMU_IMG create "rbd:rbd/aa\/bb:conf=${BOGUS_CONF}" 1M 2>&1 | _filter_conf + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/231.out b/tests/qemu-iotests/231.out index 747dd221bb..a785a6e859 100644 --- a/tests/qemu-iotests/231.out +++ b/tests/qemu-iotests/231.out @@ -4,4 +4,7 @@ unable to get monitor info from DNS SRV with service name: ceph-mon qemu-img: Could not open 'json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=BOGUS_CONF'}': error connecting: No such file or directory unable to get monitor info from DNS SRV with service name: ceph-mon qemu-img: Could not open 'json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'BOGUS_CONF'}': error connecting: No such file or directory +Formatting 'rbd:rbd/aa\/bb:conf=BOGUS_CONF', fmt=raw size=1048576 +unable to get monitor info from DNS SRV with service name: ceph-mon +qemu-img: rbd:rbd/aa\/bb:conf=BOGUS_CONF: error connecting: No such file or directory *** done From 78632a3d1685454fec83f83586c675e7f2a1a84a Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 23 Apr 2021 16:42:33 +0300 Subject: [PATCH 0555/3028] monitor: hmp_qemu_io: acquire aio contex, fix crash Max reported the following bug: $ ./qemu-img create -f raw src.img 1G $ ./qemu-img create -f raw dst.img 1G $ (echo ' {"execute":"qmp_capabilities"} {"execute":"blockdev-mirror", "arguments":{"job-id":"mirror", "device":"source", "target":"target", "sync":"full", "filter-node-name":"mirror-top"}} '; sleep 3; echo ' {"execute":"human-monitor-command", "arguments":{"command-line": "qemu-io mirror-top \"write 0 1G\""}}') \ | x86_64-softmmu/qemu-system-x86_64 \ -qmp stdio \ -blockdev file,node-name=source,filename=src.img \ -blockdev file,node-name=target,filename=dst.img \ -object iothread,id=iothr0 \ -device virtio-blk,drive=source,iothread=iothr0 crashes: 0 raise () at /usr/lib/libc.so.6 1 abort () at /usr/lib/libc.so.6 2 error_exit (err=, msg=msg@entry=0x55fbb1634790 <__func__.27> "qemu_mutex_unlock_impl") at ../util/qemu-thread-posix.c:37 3 qemu_mutex_unlock_impl (mutex=mutex@entry=0x55fbb25ab6e0, file=file@entry=0x55fbb1636957 "../util/async.c", line=line@entry=650) at ../util/qemu-thread-posix.c:109 4 aio_context_release (ctx=ctx@entry=0x55fbb25ab680) at ../util/async.c:650 5 bdrv_do_drained_begin (bs=bs@entry=0x55fbb3a87000, recursive=recursive@entry=false, parent=parent@entry=0x0, ignore_bds_parents=ignore_bds_parents@entry=false, poll=poll@entry=true) at ../block/io.c:441 6 bdrv_do_drained_begin (poll=true, ignore_bds_parents=false, parent=0x0, recursive=false, bs=0x55fbb3a87000) at ../block/io.c:448 7 blk_drain (blk=0x55fbb26c5a00) at ../block/block-backend.c:1718 8 blk_unref (blk=0x55fbb26c5a00) at ../block/block-backend.c:498 9 blk_unref (blk=0x55fbb26c5a00) at ../block/block-backend.c:491 10 hmp_qemu_io (mon=0x7fffaf3fc7d0, qdict=) at ../block/monitor/block-hmp-cmds.c:628 man pthread_mutex_unlock ... EPERM The mutex type is PTHREAD_MUTEX_ERRORCHECK or PTHREAD_MUTEX_RECURSIVE, or the mutex is a robust mutex, and the current thread does not own the mutex. So, thread doesn't own the mutex. And we have iothread here. Next, note that AIO_WAIT_WHILE() documents that ctx must be acquired exactly once by caller. But where is it acquired in the call stack? Seems nowhere. qemuio_command do acquire aio context.. But we need context acquired around blk_unref() as well and actually around blk_insert_bs() too. Let's refactor qemuio_command so that it doesn't acquire aio context but callers do that instead. This way we can cleanly acquire aio context in hmp_qemu_io() around all three calls. Reported-by: Max Reitz Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210423134233.51495-1-vsementsov@virtuozzo.com> [mreitz: Fixed comment] Signed-off-by: Max Reitz --- block/monitor/block-hmp-cmds.c | 31 +++++++++++++++++++++---------- qemu-io-cmds.c | 8 ++++---- qemu-io.c | 17 +++++++++++++++-- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/block/monitor/block-hmp-cmds.c b/block/monitor/block-hmp-cmds.c index ebf1033f31..3e6670c963 100644 --- a/block/monitor/block-hmp-cmds.c +++ b/block/monitor/block-hmp-cmds.c @@ -557,8 +557,10 @@ void hmp_eject(Monitor *mon, const QDict *qdict) void hmp_qemu_io(Monitor *mon, const QDict *qdict) { - BlockBackend *blk; + BlockBackend *blk = NULL; + BlockDriverState *bs = NULL; BlockBackend *local_blk = NULL; + AioContext *ctx = NULL; bool qdev = qdict_get_try_bool(qdict, "qdev", false); const char *device = qdict_get_str(qdict, "device"); const char *command = qdict_get_str(qdict, "command"); @@ -573,20 +575,24 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) } else { blk = blk_by_name(device); if (!blk) { - BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err); - if (bs) { - blk = local_blk = blk_new(bdrv_get_aio_context(bs), - 0, BLK_PERM_ALL); - ret = blk_insert_bs(blk, bs, &err); - if (ret < 0) { - goto fail; - } - } else { + bs = bdrv_lookup_bs(NULL, device, &err); + if (!bs) { goto fail; } } } + ctx = blk ? blk_get_aio_context(blk) : bdrv_get_aio_context(bs); + aio_context_acquire(ctx); + + if (bs) { + blk = local_blk = blk_new(bdrv_get_aio_context(bs), 0, BLK_PERM_ALL); + ret = blk_insert_bs(blk, bs, &err); + if (ret < 0) { + goto fail; + } + } + /* * Notably absent: Proper permission management. This is sad, but it seems * almost impossible to achieve without changing the semantics and thereby @@ -616,6 +622,11 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) fail: blk_unref(local_blk); + + if (ctx) { + aio_context_release(ctx); + } + hmp_handle_error(mon, err); } diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 97611969cb..998b67186d 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -2457,9 +2457,12 @@ static const cmdinfo_t help_cmd = { .oneline = "help for one or all commands", }; +/* + * Called with aio context of blk acquired. Or with qemu_get_aio_context() + * context acquired if blk is NULL. + */ int qemuio_command(BlockBackend *blk, const char *cmd) { - AioContext *ctx; char *input; const cmdinfo_t *ct; char **v; @@ -2471,10 +2474,7 @@ int qemuio_command(BlockBackend *blk, const char *cmd) if (c) { ct = find_command(v[0]); if (ct) { - ctx = blk ? blk_get_aio_context(blk) : qemu_get_aio_context(); - aio_context_acquire(ctx); ret = command(blk, ct, c, v); - aio_context_release(ctx); } else { fprintf(stderr, "command \"%s\" not found\n", v[0]); ret = -EINVAL; diff --git a/qemu-io.c b/qemu-io.c index bf902302e9..57f07501df 100644 --- a/qemu-io.c +++ b/qemu-io.c @@ -411,6 +411,19 @@ static void prep_fetchline(void *opaque) *fetchable= 1; } +static int do_qemuio_command(const char *cmd) +{ + int ret; + AioContext *ctx = + qemuio_blk ? blk_get_aio_context(qemuio_blk) : qemu_get_aio_context(); + + aio_context_acquire(ctx); + ret = qemuio_command(qemuio_blk, cmd); + aio_context_release(ctx); + + return ret; +} + static int command_loop(void) { int i, fetchable = 0, prompted = 0; @@ -418,7 +431,7 @@ static int command_loop(void) char *input; for (i = 0; !quit_qemu_io && i < ncmdline; i++) { - ret = qemuio_command(qemuio_blk, cmdline[i]); + ret = do_qemuio_command(cmdline[i]); if (ret < 0) { last_error = ret; } @@ -446,7 +459,7 @@ static int command_loop(void) if (input == NULL) { break; } - ret = qemuio_command(qemuio_blk, input); + ret = do_qemuio_command(input); g_free(input); if (ret < 0) { From 9c785cd714b3c368503ba3aed4266a77056cae29 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 21 Apr 2021 10:58:58 +0300 Subject: [PATCH 0556/3028] mirror: stop cancelling in-flight requests on non-force cancel in READY If mirror is READY than cancel operation is not discarding the whole result of the operation, but instead it's a documented way get a point-in-time snapshot of source disk. So, we should not cancel any requests if mirror is READ and force=false. Let's fix that case. Note, that bug that we have before this commit is not critical, as the only .bdrv_cancel_in_flight implementation is nbd_cancel_in_flight() and it cancels only requests waiting for reconnection, so it should be rare case. Fixes: 521ff8b779b11c394dbdc43f02e158dd99df308a Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210421075858.40197-1-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/backup.c | 2 +- block/mirror.c | 6 ++++-- include/block/block_int.h | 2 +- include/qemu/job.h | 2 +- job.c | 2 +- tests/qemu-iotests/264 | 2 +- 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/block/backup.c b/block/backup.c index 6cf2f974aa..bd3614ce70 100644 --- a/block/backup.c +++ b/block/backup.c @@ -331,7 +331,7 @@ static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed) } } -static void backup_cancel(Job *job) +static void backup_cancel(Job *job, bool force) { BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); diff --git a/block/mirror.c b/block/mirror.c index 840b8e8c15..019f6deaa5 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1178,12 +1178,14 @@ static bool mirror_drained_poll(BlockJob *job) return !!s->in_flight; } -static void mirror_cancel(Job *job) +static void mirror_cancel(Job *job, bool force) { MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); BlockDriverState *target = blk_bs(s->target); - bdrv_cancel_in_flight(target); + if (force || !job_is_ready(job)) { + bdrv_cancel_in_flight(target); + } } static const BlockJobDriver mirror_job_driver = { diff --git a/include/block/block_int.h b/include/block/block_int.h index c823f5b1b3..731ffedb27 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -357,7 +357,7 @@ struct BlockDriver { * of in-flight requests, so don't waste the time if possible. * * One example usage is to avoid waiting for an nbd target node reconnect - * timeout during job-cancel. + * timeout during job-cancel with force=true. */ void (*bdrv_cancel_in_flight)(BlockDriverState *bs); diff --git a/include/qemu/job.h b/include/qemu/job.h index efc6fa7544..41162ed494 100644 --- a/include/qemu/job.h +++ b/include/qemu/job.h @@ -254,7 +254,7 @@ struct JobDriver { /** * If the callback is not NULL, it will be invoked in job_cancel_async */ - void (*cancel)(Job *job); + void (*cancel)(Job *job, bool force); /** Called when the job is freed */ diff --git a/job.c b/job.c index 4aff13d95a..8775c1803b 100644 --- a/job.c +++ b/job.c @@ -716,7 +716,7 @@ static int job_finalize_single(Job *job) static void job_cancel_async(Job *job, bool force) { if (job->driver->cancel) { - job->driver->cancel(job); + job->driver->cancel(job, force); } if (job->user_paused) { /* Do not call job_enter here, the caller will handle it. */ diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264 index 4f96825a22..bc431d1a19 100755 --- a/tests/qemu-iotests/264 +++ b/tests/qemu-iotests/264 @@ -95,7 +95,7 @@ class TestNbdReconnect(iotests.QMPTestCase): self.assert_qmp(result, 'return', {}) def cancel_job(self): - result = self.vm.qmp('block-job-cancel', device='drive0') + result = self.vm.qmp('block-job-cancel', device='drive0', force=True) self.assert_qmp(result, 'return', {}) start_t = time.time() From f29f4c25eb9f11d78d62185b69456681f9c703b2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 3 May 2021 13:01:06 +0200 Subject: [PATCH 0557/3028] qemu-iotests: do not buffer the test output Instead of buffering the test output into a StringIO, patch it on the fly by wrapping sys.stdout's write method. This can be done unconditionally, even if using -d, which makes execute_unittest a bit simpler. Signed-off-by: Paolo Bonzini Reviewed-by: Vladimir Sementsov-Ogievskiy Tested-by: Emanuele Giuseppe Esposito Message-Id: <20210323181928.311862-2-pbonzini@redhat.com> Message-Id: <20210503110110.476887-2-pbonzini@redhat.com> Signed-off-by: Max Reitz --- tests/qemu-iotests/240.out | 8 ++-- tests/qemu-iotests/245.out | 8 ++-- tests/qemu-iotests/295.out | 6 +-- tests/qemu-iotests/296.out | 8 ++-- tests/qemu-iotests/iotests.py | 70 ++++++++++++++++++++--------------- 5 files changed, 56 insertions(+), 44 deletions(-) diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out index e0982831ae..89ed25e506 100644 --- a/tests/qemu-iotests/240.out +++ b/tests/qemu-iotests/240.out @@ -15,7 +15,7 @@ {"return": {}} {"execute": "blockdev-del", "arguments": {"node-name": "hd0"}} {"return": {}} -==Attach two SCSI disks using the same block device and the same iothread== +.==Attach two SCSI disks using the same block device and the same iothread== {"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}} {"return": {}} {"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}} @@ -32,7 +32,7 @@ {"return": {}} {"execute": "blockdev-del", "arguments": {"node-name": "hd0"}} {"return": {}} -==Attach two SCSI disks using the same block device but different iothreads== +.==Attach two SCSI disks using the same block device but different iothreads== {"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}} {"return": {}} {"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}} @@ -55,7 +55,7 @@ {"return": {}} {"execute": "blockdev-del", "arguments": {"node-name": "hd0"}} {"return": {}} -==Attach a SCSI disks using the same block device as a NBD server== +.==Attach a SCSI disks using the same block device as a NBD server== {"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}} {"return": {}} {"execute": "nbd-server-start", "arguments": {"addr": {"data": {"path": "SOCK_DIR/PID-nbd.sock"}, "type": "unix"}}} @@ -68,7 +68,7 @@ {"return": {}} {"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}} {"return": {}} -.... +. ---------------------------------------------------------------------- Ran 4 tests diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out index 4b33dcaf5c..99c12f4f98 100644 --- a/tests/qemu-iotests/245.out +++ b/tests/qemu-iotests/245.out @@ -1,16 +1,16 @@ -{"execute": "job-finalize", "arguments": {"id": "commit0"}} +..{"execute": "job-finalize", "arguments": {"id": "commit0"}} {"return": {}} {"data": {"id": "commit0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"device": "commit0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} -{"execute": "job-finalize", "arguments": {"id": "stream0"}} +...{"execute": "job-finalize", "arguments": {"id": "stream0"}} {"return": {}} {"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} -{"execute": "job-finalize", "arguments": {"id": "stream0"}} +.{"execute": "job-finalize", "arguments": {"id": "stream0"}} {"return": {}} {"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} -..................... +............... ---------------------------------------------------------------------- Ran 21 tests diff --git a/tests/qemu-iotests/295.out b/tests/qemu-iotests/295.out index ad34b2ca2c..5ff91f116c 100644 --- a/tests/qemu-iotests/295.out +++ b/tests/qemu-iotests/295.out @@ -4,7 +4,7 @@ {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}} {"return": {}} -{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +.{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}} {"return": {}} @@ -13,7 +13,7 @@ Job failed: Invalid password, cannot unlock any keyslot {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} {"return": {}} -{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} +.{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job_add_key"}} {"return": {}} @@ -33,7 +33,7 @@ Job failed: All the active keyslots match the (old) password that was given and {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}} {"return": {}} -... +. ---------------------------------------------------------------------- Ran 3 tests diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out index cb2859a15c..6c69735604 100644 --- a/tests/qemu-iotests/296.out +++ b/tests/qemu-iotests/296.out @@ -13,7 +13,7 @@ Job failed: Failed to get shared "consistent read" lock qemu-img: Failed to get shared "consistent read" lock Is another process using the image [TEST_DIR/test.img]? -Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10 +.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10 Job failed: Block node is read-only {"execute": "job-dismiss", "arguments": {"id": "job0"}} @@ -26,15 +26,15 @@ Job failed: Failed to get shared "consistent read" lock {"return": {}} {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10 +.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10 {"return": {}} {"error": {"class": "GenericError", "desc": "Failed to get \"write\" lock"}} -Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10 +.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10 {"return": {}} {"return": {}} -.... +. ---------------------------------------------------------------------- Ran 4 tests diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 5af0182895..55a017577f 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -20,7 +20,6 @@ import atexit import bz2 from collections import OrderedDict import faulthandler -import io import json import logging import os @@ -32,7 +31,7 @@ import subprocess import sys import time from typing import (Any, Callable, Dict, Iterable, - List, Optional, Sequence, Tuple, TypeVar) + List, Optional, Sequence, TextIO, Tuple, Type, TypeVar) import unittest from contextlib import contextmanager @@ -1271,37 +1270,50 @@ def skip_if_user_is_root(func): return func(*args, **kwargs) return func_wrapper +# We need to filter out the time taken from the output so that +# qemu-iotest can reliably diff the results against master output, +# and hide skipped tests from the reference output. + +class ReproducibleTestResult(unittest.TextTestResult): + def addSkip(self, test, reason): + # Same as TextTestResult, but print dot instead of "s" + unittest.TestResult.addSkip(self, test, reason) + if self.showAll: + self.stream.writeln("skipped {0!r}".format(reason)) + elif self.dots: + self.stream.write(".") + self.stream.flush() + +class ReproducibleStreamWrapper: + def __init__(self, stream: TextIO): + self.stream = stream + + def __getattr__(self, attr): + if attr in ('stream', '__getstate__'): + raise AttributeError(attr) + return getattr(self.stream, attr) + + def write(self, arg=None): + arg = re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', arg) + arg = re.sub(r' \(skipped=\d+\)', r'', arg) + self.stream.write(arg) + +class ReproducibleTestRunner(unittest.TextTestRunner): + def __init__(self, stream: Optional[TextIO] = None, + resultclass: Type[unittest.TestResult] = ReproducibleTestResult, + **kwargs: Any) -> None: + rstream = ReproducibleStreamWrapper(stream or sys.stdout) + super().__init__(stream=rstream, # type: ignore + descriptions=True, + resultclass=resultclass, + **kwargs) + def execute_unittest(debug=False): """Executes unittests within the calling module.""" verbosity = 2 if debug else 1 - - if debug: - output = sys.stdout - else: - # We need to filter out the time taken from the output so that - # qemu-iotest can reliably diff the results against master output. - output = io.StringIO() - - runner = unittest.TextTestRunner(stream=output, descriptions=True, - verbosity=verbosity) - try: - # unittest.main() will use sys.exit(); so expect a SystemExit - # exception - unittest.main(testRunner=runner) - finally: - # We need to filter out the time taken from the output so that - # qemu-iotest can reliably diff the results against master output. - if not debug: - out = output.getvalue() - out = re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', out) - - # Hide skipped tests from the reference output - out = re.sub(r'OK \(skipped=\d+\)', 'OK', out) - out_first_line, out_rest = out.split('\n', 1) - out = out_first_line.replace('s', '.') + '\n' + out_rest - - sys.stderr.write(out) + runner = ReproducibleTestRunner(verbosity=verbosity) + unittest.main(testRunner=runner) def execute_setup_common(supported_fmts: Sequence[str] = (), supported_platforms: Sequence[str] = (), From 00dbc85e0efd863498d52408b248039816c10532 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 3 May 2021 13:01:07 +0200 Subject: [PATCH 0558/3028] qemu-iotests: allow passing unittest.main arguments to the test scripts Python test scripts that use unittest consist of multiple tests. unittest.main allows selecting which tests to run, but currently this is not possible because the iotests wrapper ignores sys.argv. unittest.main command line options also allow the user to pick the desired options for verbosity, failfast mode, etc. While "-d" is currently translated to "-v", it also enables extra debug output, and other options are not available at all. These command line options only work if the unittest.main testRunner argument is a type, rather than a TestRunner instance. Therefore, pass the class name and "verbosity" argument to unittest.main, and adjust for the different default warnings between TextTestRunner and unittest.main. Signed-off-by: Paolo Bonzini Reviewed-by: Vladimir Sementsov-Ogievskiy Tested-by: Emanuele Giuseppe Esposito Message-Id: <20210323181928.311862-3-pbonzini@redhat.com> Message-Id: <20210503110110.476887-3-pbonzini@redhat.com> Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 55a017577f..5ead94229f 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -1308,12 +1308,16 @@ class ReproducibleTestRunner(unittest.TextTestRunner): resultclass=resultclass, **kwargs) -def execute_unittest(debug=False): +def execute_unittest(argv: List[str], debug: bool = False) -> None: """Executes unittests within the calling module.""" - verbosity = 2 if debug else 1 - runner = ReproducibleTestRunner(verbosity=verbosity) - unittest.main(testRunner=runner) + # Some tests have warnings, especially ResourceWarnings for unclosed + # files and sockets. Ignore them for now to ensure reproducibility of + # the test output. + unittest.main(argv=argv, + testRunner=ReproducibleTestRunner, + verbosity=2 if debug else 1, + warnings=None if sys.warnoptions else 'ignore') def execute_setup_common(supported_fmts: Sequence[str] = (), supported_platforms: Sequence[str] = (), @@ -1350,7 +1354,7 @@ def execute_test(*args, test_function=None, **kwargs): debug = execute_setup_common(*args, **kwargs) if not test_function: - execute_unittest(debug) + execute_unittest(sys.argv, debug) else: test_function() From c64430d2386d9968342a8e1ae00ed34ff0b98bbb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 3 May 2021 13:01:08 +0200 Subject: [PATCH 0559/3028] qemu-iotests: move command line and environment handling from TestRunner to TestEnv In the next patch, "check" will learn how to execute a test script without going through TestRunner. To enable this, keep only the text output and subprocess handling in the TestRunner; move into TestEnv the logic to prepare for running a subprocess. Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Paolo Bonzini Tested-by: Emanuele Giuseppe Esposito Message-Id: <20210323181928.311862-4-pbonzini@redhat.com> Message-Id: <20210503110110.476887-4-pbonzini@redhat.com> Signed-off-by: Max Reitz --- tests/qemu-iotests/testenv.py | 17 ++++++++++++++++- tests/qemu-iotests/testrunner.py | 14 +------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py index 6d27712617..fca3a609e0 100644 --- a/tests/qemu-iotests/testenv.py +++ b/tests/qemu-iotests/testenv.py @@ -25,7 +25,7 @@ import collections import random import subprocess import glob -from typing import Dict, Any, Optional, ContextManager +from typing import List, Dict, Any, Optional, ContextManager def isxfile(path: str) -> bool: @@ -74,6 +74,21 @@ class TestEnv(ContextManager['TestEnv']): 'CACHEMODE_IS_DEFAULT', 'IMGFMT_GENERIC', 'IMGOPTSSYNTAX', 'IMGKEYSECRET', 'QEMU_DEFAULT_MACHINE', 'MALLOC_PERTURB_'] + def prepare_subprocess(self, args: List[str]) -> Dict[str, str]: + if self.debug: + args.append('-d') + + with open(args[0], encoding="utf-8") as f: + try: + if f.readline().rstrip() == '#!/usr/bin/env python3': + args.insert(0, self.python) + except UnicodeDecodeError: # binary test? for future. + pass + + os_env = os.environ.copy() + os_env.update(self.get_env()) + return os_env + def get_env(self) -> Dict[str, str]: env = {} for v in self.env_variables: diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py index 1fc61fcaa3..519924dc81 100644 --- a/tests/qemu-iotests/testrunner.py +++ b/tests/qemu-iotests/testrunner.py @@ -129,7 +129,6 @@ class TestRunner(ContextManager['TestRunner']): def __init__(self, env: TestEnv, makecheck: bool = False, color: str = 'auto') -> None: self.env = env - self.test_run_env = self.env.get_env() self.makecheck = makecheck self.last_elapsed = LastElapsedTime('.last-elapsed-cache', env) @@ -243,18 +242,7 @@ class TestRunner(ContextManager['TestRunner']): silent_unlink(p) args = [str(f_test.resolve())] - if self.env.debug: - args.append('-d') - - with f_test.open(encoding="utf-8") as f: - try: - if f.readline().rstrip() == '#!/usr/bin/env python3': - args.insert(0, self.env.python) - except UnicodeDecodeError: # binary test? for future. - pass - - env = os.environ.copy() - env.update(self.test_run_env) + env = self.env.prepare_subprocess(args) t0 = time.time() with f_bad.open('w', encoding="utf-8") as f: From 480b75ee1423ee6d8aba59cb8090d60eb97676ff Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 3 May 2021 13:01:09 +0200 Subject: [PATCH 0560/3028] qemu-iotests: let "check" spawn an arbitrary test command Right now there is no easy way for "check" to print a reproducer command. Because such a reproducer command line would be huge, we can instead teach check to start a command of our choice. This can be for example a Python unit test with arguments to only run a specific subtest. Move the trailing empty line to print_env(), since it always looks better and one caller was not adding it. Signed-off-by: Paolo Bonzini Reviewed-by: Vladimir Sementsov-Ogievskiy Tested-by: Emanuele Giuseppe Esposito Message-Id: <20210323181928.311862-5-pbonzini@redhat.com> Message-Id: <20210503110110.476887-5-pbonzini@redhat.com> Signed-off-by: Max Reitz --- tests/qemu-iotests/check | 19 ++++++++++++++++++- tests/qemu-iotests/testenv.py | 3 ++- tests/qemu-iotests/testrunner.py | 1 - 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 08f51366f1..2dd529eb75 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -19,6 +19,9 @@ import os import sys import argparse +import shutil +from pathlib import Path + from findtests import TestFinder from testenv import TestEnv from testrunner import TestRunner @@ -100,7 +103,7 @@ def make_argparser() -> argparse.ArgumentParser: 'rerun failed ./check command, starting from the ' 'middle of the process.') g_sel.add_argument('tests', metavar='TEST_FILES', nargs='*', - help='tests to run') + help='tests to run, or "--" followed by a command') return p @@ -113,6 +116,20 @@ if __name__ == '__main__': imgopts=args.imgopts, misalign=args.misalign, debug=args.debug, valgrind=args.valgrind) + if len(sys.argv) > 1 and sys.argv[-len(args.tests)-1] == '--': + if not args.tests: + sys.exit("missing command after '--'") + cmd = args.tests + env.print_env() + exec_pathstr = shutil.which(cmd[0]) + if exec_pathstr is None: + sys.exit('command not found: ' + cmd[0]) + exec_path = Path(exec_pathstr).resolve() + cmd[0] = str(exec_path) + full_env = env.prepare_subprocess(cmd) + os.chdir(exec_path.parent) + os.execve(cmd[0], cmd, full_env) + testfinder = TestFinder(test_dir=env.source_iotests) groups = args.groups.split(',') if args.groups else None diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py index fca3a609e0..cd0e39b789 100644 --- a/tests/qemu-iotests/testenv.py +++ b/tests/qemu-iotests/testenv.py @@ -284,7 +284,8 @@ IMGPROTO -- {IMGPROTO} PLATFORM -- {platform} TEST_DIR -- {TEST_DIR} SOCK_DIR -- {SOCK_DIR} -SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER}""" +SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER} +""" args = collections.defaultdict(str, self.get_env()) diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py index 519924dc81..2f56ac545d 100644 --- a/tests/qemu-iotests/testrunner.py +++ b/tests/qemu-iotests/testrunner.py @@ -316,7 +316,6 @@ class TestRunner(ContextManager['TestRunner']): if not self.makecheck: self.env.print_env() - print() test_field_width = max(len(os.path.basename(t)) for t in tests) + 2 From c3d479aab9d72fa0d6a3aafdaf0729140e6eae51 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 3 May 2021 13:01:10 +0200 Subject: [PATCH 0561/3028] qemu-iotests: fix case of SOCK_DIR already in the environment Due to a typo, in this case the SOCK_DIR was not being created. Reviewed-by: Vladimir Sementsov-Ogievskiy Signed-off-by: Paolo Bonzini Tested-by: Emanuele Giuseppe Esposito Message-Id: <20210323181928.311862-6-pbonzini@redhat.com> Message-Id: <20210503110110.476887-6-pbonzini@redhat.com> Signed-off-by: Max Reitz --- tests/qemu-iotests/testenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py index cd0e39b789..0c3fe75636 100644 --- a/tests/qemu-iotests/testenv.py +++ b/tests/qemu-iotests/testenv.py @@ -120,7 +120,7 @@ class TestEnv(ContextManager['TestEnv']): try: self.sock_dir = os.environ['SOCK_DIR'] self.tmp_sock_dir = False - Path(self.test_dir).mkdir(parents=True, exist_ok=True) + Path(self.sock_dir).mkdir(parents=True, exist_ok=True) except KeyError: self.sock_dir = tempfile.mkdtemp() self.tmp_sock_dir = True From d65173f924ef0a170693fc59692a542d38f31879 Mon Sep 17 00:00:00 2001 From: Connor Kuehl Date: Wed, 5 May 2021 14:55:12 -0500 Subject: [PATCH 0562/3028] Document qemu-img options data_file and data_file_raw The contents of this patch were initially developed and posted by Han Han[1], however, it appears the original patch was not applied. Since then, the relevant documentation has been moved and adapted to a new format. I've taken most of the original wording and tweaked it according to some of the feedback from the original patch submission. I've also adapted it to restructured text, which is the format the documentation currently uses. [1] https://lists.nongnu.org/archive/html/qemu-block/2019-10/msg01253.html Fixes: https://bugzilla.redhat.com/1763105 Signed-off-by: Han Han Suggested-by: Max Reitz [ Max: provided description of data_file_raw behavior ] Signed-off-by: Connor Kuehl Message-Id: <20210505195512.391128-1-ckuehl@redhat.com> Signed-off-by: Max Reitz --- docs/tools/qemu-img.rst | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst index c9efcfaefc..cfe1147879 100644 --- a/docs/tools/qemu-img.rst +++ b/docs/tools/qemu-img.rst @@ -866,6 +866,37 @@ Supported image file formats: issue ``lsattr filename`` to check if the NOCOW flag is set or not (Capital 'C' is NOCOW flag). + ``data_file`` + Filename where all guest data will be stored. If this option is used, + the qcow2 file will only contain the image's metadata. + + Note: Data loss will occur if the given filename already exists when + using this option with ``qemu-img create`` since ``qemu-img`` will create + the data file anew, overwriting the file's original contents. To simply + update the reference to point to the given pre-existing file, use + ``qemu-img amend``. + + ``data_file_raw`` + If this option is set to ``on``, QEMU will always keep the external data + file consistent as a standalone read-only raw image. + + It does this by forwarding all write accesses to the qcow2 file through to + the raw data file, including their offsets. Therefore, data that is visible + on the qcow2 node (i.e., to the guest) at some offset is visible at the same + offset in the raw data file. This results in a read-only raw image. Writes + that bypass the qcow2 metadata may corrupt the qcow2 metadata because the + out-of-band writes may result in the metadata falling out of sync with the + raw image. + + If this option is ``off``, QEMU will use the data file to store data in an + arbitrary manner. The file’s content will not make sense without the + accompanying qcow2 metadata. Where data is written will have no relation to + its offset as seen by the guest, and some writes (specifically zero writes) + may not be forwarded to the data file at all, but will only be handled by + modifying qcow2 metadata. + + This option can only be enabled if ``data_file`` is set. + ``Other`` QEMU also supports various other image file formats for From bcc8584c832f7a52fd8c64483dd452c1baf01db7 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 6 May 2021 22:41:43 +0300 Subject: [PATCH 0563/3028] block/copy-on-read: use bdrv_drop_filter() and drop s->active Now, after huge update of block graph permission update algorithm, we don't need this workaround with active state of the filter. Drop it and use new smart bdrv_drop_filter() function. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210506194143.394141-1-vsementsov@virtuozzo.com> Signed-off-by: Max Reitz --- block/copy-on-read.c | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/block/copy-on-read.c b/block/copy-on-read.c index 9cad9e1b8c..c428682272 100644 --- a/block/copy-on-read.c +++ b/block/copy-on-read.c @@ -29,7 +29,6 @@ typedef struct BDRVStateCOR { - bool active; BlockDriverState *bottom_bs; bool chain_frozen; } BDRVStateCOR; @@ -89,7 +88,6 @@ static int cor_open(BlockDriverState *bs, QDict *options, int flags, */ bdrv_ref(bottom_bs); } - state->active = true; state->bottom_bs = bottom_bs; /* @@ -112,17 +110,6 @@ static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - BDRVStateCOR *s = bs->opaque; - - if (!s->active) { - /* - * While the filter is being removed - */ - *nperm = 0; - *nshared = BLK_PERM_ALL; - return; - } - *nperm = perm & PERM_PASSTHROUGH; *nshared = (shared & PERM_PASSTHROUGH) | PERM_UNCHANGED; @@ -280,32 +267,14 @@ static BlockDriver bdrv_copy_on_read = { void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs) { - BdrvChild *child; - BlockDriverState *bs; BDRVStateCOR *s = cor_filter_bs->opaque; - child = bdrv_filter_child(cor_filter_bs); - if (!child) { - return; - } - bs = child->bs; - - /* Retain the BDS until we complete the graph change. */ - bdrv_ref(bs); - /* Hold a guest back from writing while permissions are being reset. */ - bdrv_drained_begin(bs); - /* Drop permissions before the graph change. */ - s->active = false; /* unfreeze, as otherwise bdrv_replace_node() will fail */ if (s->chain_frozen) { s->chain_frozen = false; bdrv_unfreeze_backing_chain(cor_filter_bs, s->bottom_bs); } - bdrv_child_refresh_perms(cor_filter_bs, child, &error_abort); - bdrv_replace_node(cor_filter_bs, bs, &error_abort); - - bdrv_drained_end(bs); - bdrv_unref(bs); + bdrv_drop_filter(cor_filter_bs, &error_abort); bdrv_unref(cor_filter_bs); } From ac4e14f5dc93d6b4bc5d4849bb61810023330380 Mon Sep 17 00:00:00 2001 From: Emanuele Giuseppe Esposito Date: Mon, 10 May 2021 21:04:49 +0200 Subject: [PATCH 0564/3028] qemu-iotests: fix pylint 2.8 consider-using-with error pylint 2.8 introduces consider-using-with error, suggesting to use the 'with' block statement when possible. Modify all subprocess.Popen call to use the 'with' statement, except the one in __init__ of QemuIoInteractive class, since it is assigned to a class field and used in other methods. Signed-off-by: Emanuele Giuseppe Esposito Message-Id: <20210510190449.65948-1-eesposit@redhat.com> [mreitz: Disable bad-option-value warning in the iotests' pylintrc, so that disabling consider-using-with in QemuIoInteractive will not produce a warning in pre-2.8 pylint versions] Signed-off-by: Max Reitz --- tests/qemu-iotests/iotests.py | 63 ++++++++++++++++---------------- tests/qemu-iotests/pylintrc | 3 ++ tests/qemu-iotests/testrunner.py | 22 +++++------ 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 5ead94229f..777fa2ec0e 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -112,15 +112,14 @@ def qemu_tool_pipe_and_status(tool: str, args: Sequence[str], Run a tool and return both its output and its exit code """ stderr = subprocess.STDOUT if connect_stderr else None - subp = subprocess.Popen(args, - stdout=subprocess.PIPE, - stderr=stderr, - universal_newlines=True) - output = subp.communicate()[0] - if subp.returncode < 0: - cmd = ' '.join(args) - sys.stderr.write(f'{tool} received signal {-subp.returncode}: {cmd}\n') - return (output, subp.returncode) + with subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=stderr, universal_newlines=True) as subp: + output = subp.communicate()[0] + if subp.returncode < 0: + cmd = ' '.join(args) + sys.stderr.write(f'{tool} received signal \ + {-subp.returncode}: {cmd}\n') + return (output, subp.returncode) def qemu_img_pipe_and_status(*args: str) -> Tuple[str, int]: """ @@ -236,6 +235,9 @@ def qemu_io_silent_check(*args): class QemuIoInteractive: def __init__(self, *args): self.args = qemu_io_args_no_fmt + list(args) + # We need to keep the Popen objext around, and not + # close it immediately. Therefore, disable the pylint check: + # pylint: disable=consider-using-with self._p = subprocess.Popen(self.args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, @@ -309,22 +311,22 @@ def qemu_nbd_popen(*args): cmd.extend(args) log('Start NBD server') - p = subprocess.Popen(cmd) - try: - while not os.path.exists(pid_file): - if p.poll() is not None: - raise RuntimeError( - "qemu-nbd terminated with exit code {}: {}" - .format(p.returncode, ' '.join(cmd))) + with subprocess.Popen(cmd) as p: + try: + while not os.path.exists(pid_file): + if p.poll() is not None: + raise RuntimeError( + "qemu-nbd terminated with exit code {}: {}" + .format(p.returncode, ' '.join(cmd))) - time.sleep(0.01) - yield - finally: - if os.path.exists(pid_file): - os.remove(pid_file) - log('Kill NBD server') - p.kill() - p.wait() + time.sleep(0.01) + yield + finally: + if os.path.exists(pid_file): + os.remove(pid_file) + log('Kill NBD server') + p.kill() + p.wait() def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt): '''Return True if two image files are identical''' @@ -333,13 +335,12 @@ def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt): def create_image(name, size): '''Create a fully-allocated raw image with sector markers''' - file = open(name, 'wb') - i = 0 - while i < size: - sector = struct.pack('>l504xl', i // 512, i // 512) - file.write(sector) - i = i + 512 - file.close() + with open(name, 'wb') as file: + i = 0 + while i < size: + sector = struct.pack('>l504xl', i // 512, i // 512) + file.write(sector) + i = i + 512 def image_size(img): '''Return image's virtual size''' diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc index 7a6c0a9474..f2c0b522ac 100644 --- a/tests/qemu-iotests/pylintrc +++ b/tests/qemu-iotests/pylintrc @@ -19,6 +19,9 @@ disable=invalid-name, too-many-public-methods, # pylint warns about Optional[] etc. as unsubscriptable in 3.9 unsubscriptable-object, + # Sometimes we need to disable a newly introduced pylint warning. + # Doing so should not produce a warning in older versions of pylint. + bad-option-value, # These are temporary, and should be removed: missing-docstring, too-many-return-statements, diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py index 2f56ac545d..4a6ec421ed 100644 --- a/tests/qemu-iotests/testrunner.py +++ b/tests/qemu-iotests/testrunner.py @@ -246,17 +246,17 @@ class TestRunner(ContextManager['TestRunner']): t0 = time.time() with f_bad.open('w', encoding="utf-8") as f: - proc = subprocess.Popen(args, cwd=str(f_test.parent), env=env, - stdout=f, stderr=subprocess.STDOUT) - try: - proc.wait() - except KeyboardInterrupt: - proc.terminate() - proc.wait() - return TestResult(status='not run', - description='Interrupted by user', - interrupted=True) - ret = proc.returncode + with subprocess.Popen(args, cwd=str(f_test.parent), env=env, + stdout=f, stderr=subprocess.STDOUT) as proc: + try: + proc.wait() + except KeyboardInterrupt: + proc.terminate() + proc.wait() + return TestResult(status='not run', + description='Interrupted by user', + interrupted=True) + ret = proc.returncode elapsed = round(time.time() - t0, 1) From 94783301b8cb3f2b4fd871badd923fb3b9d2e7bf Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 6 May 2021 12:06:14 +0300 Subject: [PATCH 0565/3028] block/write-threshold: don't use write notifiers write-notifiers are used only for write-threshold. New code for such purpose should create filters. Let's better special-case write-threshold and drop write notifiers at all. (Actually, write-threshold is special-cased anyway, as the only user of write-notifiers) So, create a new direct interface for bdrv_co_write_req_prepare() and drop all write-notifier related logic from write-threshold.c. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-Id: <20210506090621.11848-2-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi [mreitz: Adjusted comment as per Eric's suggestion] Signed-off-by: Max Reitz --- block/io.c | 5 ++- block/write-threshold.c | 70 +++++++-------------------------- include/block/block_int.h | 1 - include/block/write-threshold.h | 9 +++++ 4 files changed, 27 insertions(+), 58 deletions(-) diff --git a/block/io.c b/block/io.c index 35b6c56efc..3520de51bb 100644 --- a/block/io.c +++ b/block/io.c @@ -30,6 +30,7 @@ #include "block/blockjob_int.h" #include "block/block_int.h" #include "block/coroutines.h" +#include "block/write-threshold.h" #include "qemu/cutils.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -2008,8 +2009,8 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, int64_t bytes, } else { assert(child->perm & BLK_PERM_WRITE); } - return notifier_with_return_list_notify(&bs->before_write_notifiers, - req); + bdrv_write_threshold_check_write(bs, offset, bytes); + return 0; case BDRV_TRACKED_TRUNCATE: assert(child->perm & BLK_PERM_RESIZE); return 0; diff --git a/block/write-threshold.c b/block/write-threshold.c index 85b78dc2a9..71df3c434f 100644 --- a/block/write-threshold.c +++ b/block/write-threshold.c @@ -29,14 +29,6 @@ bool bdrv_write_threshold_is_set(const BlockDriverState *bs) return bs->write_threshold_offset > 0; } -static void write_threshold_disable(BlockDriverState *bs) -{ - if (bdrv_write_threshold_is_set(bs)) { - notifier_with_return_remove(&bs->write_threshold_notifier); - bs->write_threshold_offset = 0; - } -} - uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs, const BdrvTrackedRequest *req) { @@ -51,55 +43,9 @@ uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs, return 0; } -static int coroutine_fn before_write_notify(NotifierWithReturn *notifier, - void *opaque) -{ - BdrvTrackedRequest *req = opaque; - BlockDriverState *bs = req->bs; - uint64_t amount = 0; - - amount = bdrv_write_threshold_exceeded(bs, req); - if (amount > 0) { - qapi_event_send_block_write_threshold( - bs->node_name, - amount, - bs->write_threshold_offset); - - /* autodisable to avoid flooding the monitor */ - write_threshold_disable(bs); - } - - return 0; /* should always let other notifiers run */ -} - -static void write_threshold_register_notifier(BlockDriverState *bs) -{ - bs->write_threshold_notifier.notify = before_write_notify; - bdrv_add_before_write_notifier(bs, &bs->write_threshold_notifier); -} - -static void write_threshold_update(BlockDriverState *bs, - int64_t threshold_bytes) -{ - bs->write_threshold_offset = threshold_bytes; -} - void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes) { - if (bdrv_write_threshold_is_set(bs)) { - if (threshold_bytes > 0) { - write_threshold_update(bs, threshold_bytes); - } else { - write_threshold_disable(bs); - } - } else { - if (threshold_bytes > 0) { - /* avoid multiple registration */ - write_threshold_register_notifier(bs); - write_threshold_update(bs, threshold_bytes); - } - /* discard bogus disable request */ - } + bs->write_threshold_offset = threshold_bytes; } void qmp_block_set_write_threshold(const char *node_name, @@ -122,3 +68,17 @@ void qmp_block_set_write_threshold(const char *node_name, aio_context_release(aio_context); } + +void bdrv_write_threshold_check_write(BlockDriverState *bs, int64_t offset, + int64_t bytes) +{ + int64_t end = offset + bytes; + uint64_t wtr = bs->write_threshold_offset; + + if (wtr > 0 && end > wtr) { + qapi_event_send_block_write_threshold(bs->node_name, end - wtr, wtr); + + /* autodisable to avoid flooding the monitor */ + bdrv_write_threshold_set(bs, 0); + } +} diff --git a/include/block/block_int.h b/include/block/block_int.h index 731ffedb27..aff948fb63 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -959,7 +959,6 @@ struct BlockDriverState { /* threshold limit for writes, in bytes. "High water mark". */ uint64_t write_threshold_offset; - NotifierWithReturn write_threshold_notifier; /* Writing to the list requires the BQL _and_ the dirty_bitmap_mutex. * Reading from the list can be done with either the BQL or the diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h index c646f267a4..848a5dde85 100644 --- a/include/block/write-threshold.h +++ b/include/block/write-threshold.h @@ -59,4 +59,13 @@ bool bdrv_write_threshold_is_set(const BlockDriverState *bs); uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs, const BdrvTrackedRequest *req); +/* + * bdrv_write_threshold_check_write + * + * Check whether the specified request exceeds the write threshold. + * If so, send a corresponding event and disable write threshold checking. + */ +void bdrv_write_threshold_check_write(BlockDriverState *bs, int64_t offset, + int64_t bytes); + #endif From ad578c56d596a3250a62ae8687005ca6909d2688 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 6 May 2021 12:06:15 +0300 Subject: [PATCH 0566/3028] block: drop write notifiers They are unused now. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-Id: <20210506090621.11848-3-vsementsov@virtuozzo.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- block.c | 1 - block/io.c | 6 ------ include/block/block_int.h | 12 ------------ 3 files changed, 19 deletions(-) diff --git a/block.c b/block.c index 9ad725d205..75a82af641 100644 --- a/block.c +++ b/block.c @@ -400,7 +400,6 @@ BlockDriverState *bdrv_new(void) for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) { QLIST_INIT(&bs->op_blockers[i]); } - notifier_with_return_list_init(&bs->before_write_notifiers); qemu_co_mutex_init(&bs->reqs_lock); qemu_mutex_init(&bs->dirty_bitmap_mutex); bs->refcnt = 1; diff --git a/block/io.c b/block/io.c index 3520de51bb..1e826ba9e8 100644 --- a/block/io.c +++ b/block/io.c @@ -3165,12 +3165,6 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov) return true; } -void bdrv_add_before_write_notifier(BlockDriverState *bs, - NotifierWithReturn *notifier) -{ - notifier_with_return_list_add(&bs->before_write_notifiers, notifier); -} - void bdrv_io_plug(BlockDriverState *bs) { BdrvChild *child; diff --git a/include/block/block_int.h b/include/block/block_int.h index aff948fb63..b2c8b09d0f 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -954,9 +954,6 @@ struct BlockDriverState { */ int64_t total_sectors; - /* Callback before write request is processed */ - NotifierWithReturnList before_write_notifiers; - /* threshold limit for writes, in bytes. "High water mark". */ uint64_t write_threshold_offset; @@ -1083,15 +1080,6 @@ void bdrv_parse_filename_strip_prefix(const char *filename, const char *prefix, bool bdrv_backing_overridden(BlockDriverState *bs); -/** - * bdrv_add_before_write_notifier: - * - * Register a callback that is invoked before write requests are processed but - * after any throttling or waiting for overlapping requests. - */ -void bdrv_add_before_write_notifier(BlockDriverState *bs, - NotifierWithReturn *notifier); - /** * bdrv_add_aio_context_notifier: * From e46354a8aeefe4637c689de27532bc00712f9c60 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 6 May 2021 12:06:16 +0300 Subject: [PATCH 0567/3028] test-write-threshold: rewrite test_threshold_(not_)trigger tests These tests use bdrv_write_threshold_exceeded() API, which is used only for test (since pre-previous commit). Better is testing real API, which is used in block.c as well. So, let's call bdrv_write_threshold_check_write(), and check is bs->write_threshold_offset cleared or not (it's cleared iff threshold triggered). Also we get rid of BdrvTrackedRequest use here. Note, that paranoiac bdrv_check_request() calls were added in 8b1170012b1 to protect BdrvTrackedRequest. Drop them now. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-Id: <20210506090621.11848-4-vsementsov@virtuozzo.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- tests/unit/test-write-threshold.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c index fc1c45a2eb..fd40a815b8 100644 --- a/tests/unit/test-write-threshold.c +++ b/tests/unit/test-write-threshold.c @@ -55,41 +55,27 @@ static void test_threshold_multi_set_get(void) static void test_threshold_not_trigger(void) { - uint64_t amount = 0; uint64_t threshold = 4 * 1024 * 1024; BlockDriverState bs; - BdrvTrackedRequest req; memset(&bs, 0, sizeof(bs)); - memset(&req, 0, sizeof(req)); - req.offset = 1024; - req.bytes = 1024; - - bdrv_check_request(req.offset, req.bytes, &error_abort); bdrv_write_threshold_set(&bs, threshold); - amount = bdrv_write_threshold_exceeded(&bs, &req); - g_assert_cmpuint(amount, ==, 0); + bdrv_write_threshold_check_write(&bs, 1024, 1024); + g_assert_cmpuint(bdrv_write_threshold_get(&bs), ==, threshold); } static void test_threshold_trigger(void) { - uint64_t amount = 0; uint64_t threshold = 4 * 1024 * 1024; BlockDriverState bs; - BdrvTrackedRequest req; memset(&bs, 0, sizeof(bs)); - memset(&req, 0, sizeof(req)); - req.offset = (4 * 1024 * 1024) - 1024; - req.bytes = 2 * 1024; - - bdrv_check_request(req.offset, req.bytes, &error_abort); bdrv_write_threshold_set(&bs, threshold); - amount = bdrv_write_threshold_exceeded(&bs, &req); - g_assert_cmpuint(amount, >=, 1024); + bdrv_write_threshold_check_write(&bs, threshold - 1024, 2 * 1024); + g_assert_cmpuint(bdrv_write_threshold_get(&bs), ==, 0); } typedef struct TestStruct { From 2e0e9cbd897078fea2ad3772106e0cbd1f0c239a Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 6 May 2021 12:06:17 +0300 Subject: [PATCH 0568/3028] block/write-threshold: drop extra APIs bdrv_write_threshold_exceeded() is unused. bdrv_write_threshold_is_set() is used only to double check the value of bs->write_threshold_offset in tests. No real sense in it (both tests do check real value with help of bdrv_write_threshold_get()) Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-Id: <20210506090621.11848-5-vsementsov@virtuozzo.com> Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi [mreitz: Adjusted commit message as per Eric's suggestion] Signed-off-by: Max Reitz --- block/write-threshold.c | 19 ------------------- include/block/write-threshold.h | 24 ------------------------ tests/unit/test-write-threshold.c | 4 ---- 3 files changed, 47 deletions(-) diff --git a/block/write-threshold.c b/block/write-threshold.c index 71df3c434f..65a6acd142 100644 --- a/block/write-threshold.c +++ b/block/write-threshold.c @@ -24,25 +24,6 @@ uint64_t bdrv_write_threshold_get(const BlockDriverState *bs) return bs->write_threshold_offset; } -bool bdrv_write_threshold_is_set(const BlockDriverState *bs) -{ - return bs->write_threshold_offset > 0; -} - -uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs, - const BdrvTrackedRequest *req) -{ - if (bdrv_write_threshold_is_set(bs)) { - if (req->offset > bs->write_threshold_offset) { - return (req->offset - bs->write_threshold_offset) + req->bytes; - } - if ((req->offset + req->bytes) > bs->write_threshold_offset) { - return (req->offset + req->bytes) - bs->write_threshold_offset; - } - } - return 0; -} - void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes) { bs->write_threshold_offset = threshold_bytes; diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h index 848a5dde85..a03ee1cacd 100644 --- a/include/block/write-threshold.h +++ b/include/block/write-threshold.h @@ -35,30 +35,6 @@ void bdrv_write_threshold_set(BlockDriverState *bs, uint64_t threshold_bytes); */ uint64_t bdrv_write_threshold_get(const BlockDriverState *bs); -/* - * bdrv_write_threshold_is_set - * - * Tell if a write threshold is set for a given BDS. - */ -bool bdrv_write_threshold_is_set(const BlockDriverState *bs); - -/* - * bdrv_write_threshold_exceeded - * - * Return the extent of a write request that exceeded the threshold, - * or zero if the request is below the threshold. - * Return zero also if the threshold was not set. - * - * NOTE: here we assume the following holds for each request this code - * deals with: - * - * assert((req->offset + req->bytes) <= UINT64_MAX) - * - * Please not there is *not* an actual C assert(). - */ -uint64_t bdrv_write_threshold_exceeded(const BlockDriverState *bs, - const BdrvTrackedRequest *req); - /* * bdrv_write_threshold_check_write * diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c index fd40a815b8..bb5c1a5217 100644 --- a/tests/unit/test-write-threshold.c +++ b/tests/unit/test-write-threshold.c @@ -18,8 +18,6 @@ static void test_threshold_not_set_on_init(void) BlockDriverState bs; memset(&bs, 0, sizeof(bs)); - g_assert(!bdrv_write_threshold_is_set(&bs)); - res = bdrv_write_threshold_get(&bs); g_assert_cmpint(res, ==, 0); } @@ -33,8 +31,6 @@ static void test_threshold_set_get(void) bdrv_write_threshold_set(&bs, threshold); - g_assert(bdrv_write_threshold_is_set(&bs)); - res = bdrv_write_threshold_get(&bs); g_assert_cmpint(res, ==, threshold); } From 935129223ce2a2eb61c59b585869724570d3a349 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 6 May 2021 12:06:19 +0300 Subject: [PATCH 0569/3028] test-write-threshold: drop extra tests Testing set/get of one 64bit variable doesn't seem necessary. We have a lot of such variables. Also remaining tests do test set/get anyway. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-Id: <20210506090621.11848-7-vsementsov@virtuozzo.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- tests/unit/test-write-threshold.c | 43 ------------------------------- 1 file changed, 43 deletions(-) diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c index bb5c1a5217..9e9986aefc 100644 --- a/tests/unit/test-write-threshold.c +++ b/tests/unit/test-write-threshold.c @@ -12,43 +12,6 @@ #include "block/write-threshold.h" -static void test_threshold_not_set_on_init(void) -{ - uint64_t res; - BlockDriverState bs; - memset(&bs, 0, sizeof(bs)); - - res = bdrv_write_threshold_get(&bs); - g_assert_cmpint(res, ==, 0); -} - -static void test_threshold_set_get(void) -{ - uint64_t threshold = 4 * 1024 * 1024; - uint64_t res; - BlockDriverState bs; - memset(&bs, 0, sizeof(bs)); - - bdrv_write_threshold_set(&bs, threshold); - - res = bdrv_write_threshold_get(&bs); - g_assert_cmpint(res, ==, threshold); -} - -static void test_threshold_multi_set_get(void) -{ - uint64_t threshold1 = 4 * 1024 * 1024; - uint64_t threshold2 = 15 * 1024 * 1024; - uint64_t res; - BlockDriverState bs; - memset(&bs, 0, sizeof(bs)); - - bdrv_write_threshold_set(&bs, threshold1); - bdrv_write_threshold_set(&bs, threshold2); - res = bdrv_write_threshold_get(&bs); - g_assert_cmpint(res, ==, threshold2); -} - static void test_threshold_not_trigger(void) { uint64_t threshold = 4 * 1024 * 1024; @@ -84,12 +47,6 @@ int main(int argc, char **argv) { size_t i; TestStruct tests[] = { - { "/write-threshold/not-set-on-init", - test_threshold_not_set_on_init }, - { "/write-threshold/set-get", - test_threshold_set_get }, - { "/write-threshold/multi-set-get", - test_threshold_multi_set_get }, { "/write-threshold/not-trigger", test_threshold_not_trigger }, { "/write-threshold/trigger", From 23357b93c7bbeec65aef75f798cacbcda0ca5f4d Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 6 May 2021 12:06:20 +0300 Subject: [PATCH 0570/3028] test-write-threshold: drop extra TestStruct structure We don't need this extra logic: it doesn't make code simpler. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Max Reitz Message-Id: <20210506090621.11848-8-vsementsov@virtuozzo.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- tests/unit/test-write-threshold.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c index 9e9986aefc..49b1ef7a20 100644 --- a/tests/unit/test-write-threshold.c +++ b/tests/unit/test-write-threshold.c @@ -37,26 +37,12 @@ static void test_threshold_trigger(void) g_assert_cmpuint(bdrv_write_threshold_get(&bs), ==, 0); } -typedef struct TestStruct { - const char *name; - void (*func)(void); -} TestStruct; - int main(int argc, char **argv) { - size_t i; - TestStruct tests[] = { - { "/write-threshold/not-trigger", - test_threshold_not_trigger }, - { "/write-threshold/trigger", - test_threshold_trigger }, - { NULL, NULL } - }; - g_test_init(&argc, &argv, NULL); - for (i = 0; tests[i].name != NULL; i++) { - g_test_add_func(tests[i].name, tests[i].func); - } + g_test_add_func("/write-threshold/not-trigger", test_threshold_not_trigger); + g_test_add_func("/write-threshold/trigger", test_threshold_trigger); + return g_test_run(); } From c61ebf362d0abf288ce266845519d5a550a1d89f Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 6 May 2021 12:06:21 +0300 Subject: [PATCH 0571/3028] write-threshold: deal with includes "qemu/typedefs.h" is enough for include/block/write-threshold.h header with forward declaration of BlockDriverState. Also drop extra includes from block/write-threshold.c and tests/unit/test-write-threshold.c Signed-off-by: Vladimir Sementsov-Ogievskiy Message-Id: <20210506090621.11848-9-vsementsov@virtuozzo.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Max Reitz --- block/write-threshold.c | 2 -- include/block/write-threshold.h | 2 +- tests/unit/test-write-threshold.c | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/block/write-threshold.c b/block/write-threshold.c index 65a6acd142..35cafbc22d 100644 --- a/block/write-threshold.c +++ b/block/write-threshold.c @@ -12,9 +12,7 @@ #include "qemu/osdep.h" #include "block/block_int.h" -#include "qemu/coroutine.h" #include "block/write-threshold.h" -#include "qemu/notify.h" #include "qapi/error.h" #include "qapi/qapi-commands-block-core.h" #include "qapi/qapi-events-block-core.h" diff --git a/include/block/write-threshold.h b/include/block/write-threshold.h index a03ee1cacd..f50f923e7e 100644 --- a/include/block/write-threshold.h +++ b/include/block/write-threshold.h @@ -13,7 +13,7 @@ #ifndef BLOCK_WRITE_THRESHOLD_H #define BLOCK_WRITE_THRESHOLD_H -#include "block/block_int.h" +#include "qemu/typedefs.h" /* * bdrv_write_threshold_set: diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c index 49b1ef7a20..0158e4637a 100644 --- a/tests/unit/test-write-threshold.c +++ b/tests/unit/test-write-threshold.c @@ -7,7 +7,6 @@ */ #include "qemu/osdep.h" -#include "qapi/error.h" #include "block/block_int.h" #include "block/write-threshold.h" From e526ab61e95059e4eaec636bfdedbf6695347cb2 Mon Sep 17 00:00:00 2001 From: Roman Kapl Date: Tue, 27 Apr 2021 13:05:04 +0200 Subject: [PATCH 0572/3028] amd_iommu: fix wrong MMIO operations Address was swapped with value when writing MMIO registers, so the user saw garbage in lot of cases. The interrupt status was not correctly set. Signed-off-by: Roman Kapl Message-Id: <20210427110504.10878-1-rka@sysgo.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 43b6e9bf51..2801dff97c 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -99,7 +99,7 @@ static uint64_t amdvi_readq(AMDVIState *s, hwaddr addr) } /* internal write */ -static void amdvi_writeq_raw(AMDVIState *s, uint64_t val, hwaddr addr) +static void amdvi_writeq_raw(AMDVIState *s, hwaddr addr, uint64_t val) { stq_le_p(&s->mmior[addr], val); } @@ -382,7 +382,7 @@ static void amdvi_completion_wait(AMDVIState *s, uint64_t *cmd) } /* set completion interrupt */ if (extract64(cmd[0], 1, 1)) { - amdvi_test_mask(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_COMP_INT); + amdvi_assign_orq(s, AMDVI_MMIO_STATUS, AMDVI_MMIO_STATUS_COMP_INT); /* generate interrupt */ amdvi_generate_msi_interrupt(s); } @@ -553,7 +553,7 @@ static void amdvi_cmdbuf_run(AMDVIState *s) trace_amdvi_command_exec(s->cmdbuf_head, s->cmdbuf_tail, s->cmdbuf); amdvi_cmdbuf_exec(s); s->cmdbuf_head += AMDVI_COMMAND_SIZE; - amdvi_writeq_raw(s, s->cmdbuf_head, AMDVI_MMIO_COMMAND_HEAD); + amdvi_writeq_raw(s, AMDVI_MMIO_COMMAND_HEAD, s->cmdbuf_head); /* wrap head pointer */ if (s->cmdbuf_head >= s->cmdbuf_len * AMDVI_COMMAND_SIZE) { From 8a49487c654a6150615d758e0816314b00cb481e Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sun, 25 Apr 2021 14:11:36 +0200 Subject: [PATCH 0573/3028] pc-dimm: remove unnecessary get_vmstate_memory_region() method The get_vmstate_memory_region() method from PCDIMMDeviceClass is only ever called from this class and is never overridden, so it can be converted into an ordinary function. This saves us from having to do an indirect call in order to reach it. Signed-off-by: Maciej S. Szmigiero Message-Id: Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/mem/pc-dimm.c | 33 ++++++++++++++------------------- include/hw/mem/pc-dimm.h | 5 ----- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 12b655eda8..a3a2560301 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -34,6 +34,16 @@ static int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp); +static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm, Error **errp) +{ + if (!dimm->hostmem) { + error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property must be set"); + return NULL; + } + + return host_memory_backend_get_memory(dimm->hostmem); +} + void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine, const uint64_t *legacy_align, Error **errp) { @@ -66,9 +76,8 @@ void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine, void pc_dimm_plug(PCDIMMDevice *dimm, MachineState *machine) { - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm, - &error_abort); + MemoryRegion *vmstate_mr = pc_dimm_get_memory_region(dimm, + &error_abort); memory_device_plug(MEMORY_DEVICE(dimm), machine); vmstate_register_ram(vmstate_mr, DEVICE(dimm)); @@ -76,9 +85,8 @@ void pc_dimm_plug(PCDIMMDevice *dimm, MachineState *machine) void pc_dimm_unplug(PCDIMMDevice *dimm, MachineState *machine) { - PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); - MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm, - &error_abort); + MemoryRegion *vmstate_mr = pc_dimm_get_memory_region(dimm, + &error_abort); memory_device_unplug(MEMORY_DEVICE(dimm), machine); vmstate_unregister_ram(vmstate_mr, DEVICE(dimm)); @@ -205,16 +213,6 @@ static void pc_dimm_unrealize(DeviceState *dev) host_memory_backend_set_mapped(dimm->hostmem, false); } -static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm, Error **errp) -{ - if (!dimm->hostmem) { - error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property must be set"); - return NULL; - } - - return host_memory_backend_get_memory(dimm->hostmem); -} - static uint64_t pc_dimm_md_get_addr(const MemoryDeviceState *md) { return object_property_get_uint(OBJECT(md), PC_DIMM_ADDR_PROP, @@ -266,7 +264,6 @@ static void pc_dimm_md_fill_device_info(const MemoryDeviceState *md, static void pc_dimm_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc); MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); dc->realize = pc_dimm_realize; @@ -274,8 +271,6 @@ static void pc_dimm_class_init(ObjectClass *oc, void *data) device_class_set_props(dc, pc_dimm_properties); dc->desc = "DIMM memory module"; - ddc->get_vmstate_memory_region = pc_dimm_get_memory_region; - mdc->get_addr = pc_dimm_md_get_addr; mdc->set_addr = pc_dimm_md_set_addr; /* for a dimm plugged_size == region_size */ diff --git a/include/hw/mem/pc-dimm.h b/include/hw/mem/pc-dimm.h index 3d3db82641..1473e6db62 100644 --- a/include/hw/mem/pc-dimm.h +++ b/include/hw/mem/pc-dimm.h @@ -56,9 +56,6 @@ struct PCDIMMDevice { * PCDIMMDeviceClass: * @realize: called after common dimm is realized so that the dimm based * devices get the chance to do specified operations. - * @get_vmstate_memory_region: returns #MemoryRegion which indicates the - * memory of @dimm should be kept during live migration. Will not fail - * after the device was realized. */ struct PCDIMMDeviceClass { /* private */ @@ -66,8 +63,6 @@ struct PCDIMMDeviceClass { /* public */ void (*realize)(PCDIMMDevice *dimm, Error **errp); - MemoryRegion *(*get_vmstate_memory_region)(PCDIMMDevice *dimm, - Error **errp); }; void pc_dimm_pre_plug(PCDIMMDevice *dimm, MachineState *machine, From 570fe439e5d1b8626cf344c6bc97d90cfcaf0c79 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 7 Apr 2021 16:34:58 +0200 Subject: [PATCH 0574/3028] virtio-blk: Fix rollback path in virtio_blk_data_plane_start() When dataplane multiqueue support was added in QEMU 2.7, the path that would rollback guest notifiers assignment in case of error simply got dropped. Later on, when Error was added to blk_set_aio_context() in QEMU 4.1, another error path was introduced, but it ommits to rollback both host and guest notifiers. It seems cleaner to fix the rollback path in one go. The patch is simple enough that it can be adjusted if backported to a pre-4.1 QEMU. Fixes: 51b04ac5c6a6 ("virtio-blk: dataplane multiqueue support") Cc: stefanha@redhat.com Fixes: 97896a4887a0 ("block: Add Error to blk_set_aio_context()") Cc: kwolf@redhat.com Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi Message-Id: <20210407143501.244343-2-groug@kaod.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/dataplane/virtio-blk.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index e9050c8987..d7b5c95d26 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -207,7 +207,7 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } - goto fail_guest_notifiers; + goto fail_host_notifiers; } } @@ -221,7 +221,7 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) aio_context_release(old_context); if (r < 0) { error_report_err(local_err); - goto fail_guest_notifiers; + goto fail_aio_context; } /* Process queued requests before the ones in vring */ @@ -245,6 +245,13 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) aio_context_release(s->ctx); return 0; + fail_aio_context: + for (i = 0; i < nvqs; i++) { + virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); + } + fail_host_notifiers: + k->set_guest_notifiers(qbus->parent, nvqs, false); fail_guest_notifiers: /* * If we failed to set up the guest notifiers queued requests will be From d0267da614890b8f817364ae25850cdbb580a569 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 7 Apr 2021 16:34:59 +0200 Subject: [PATCH 0575/3028] virtio-blk: Configure all host notifiers in a single MR transaction This allows the virtio-blk-pci device to batch the setup of all its host notifiers. This significantly improves boot time of VMs with a high number of vCPUs, e.g. from 3m26.186s down to 0m58.023s for a pseries machine with 384 vCPUs. Note that memory_region_transaction_commit() must be called before virtio_bus_cleanup_host_notifier() because the latter might close ioeventfds that the transaction still assumes to be around when it commits. Signed-off-by: Greg Kurz Message-Id: <20210407143501.244343-3-groug@kaod.org> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/dataplane/virtio-blk.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index d7b5c95d26..cd81893d1d 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -198,19 +198,30 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) goto fail_guest_notifiers; } + memory_region_transaction_begin(); + /* Set up virtqueue notify */ for (i = 0; i < nvqs; i++) { r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, true); if (r != 0) { + int j = i; + fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r); while (i--) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + + memory_region_transaction_commit(); + + while (j--) { virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } goto fail_host_notifiers; } } + memory_region_transaction_commit(); + s->starting = false; vblk->dataplane_started = true; trace_virtio_blk_data_plane_start(s); @@ -246,8 +257,15 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) return 0; fail_aio_context: + memory_region_transaction_begin(); + for (i = 0; i < nvqs; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + + memory_region_transaction_commit(); + + for (i = 0; i < nvqs; i++) { virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } fail_host_notifiers: @@ -312,8 +330,15 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev) aio_context_release(s->ctx); + memory_region_transaction_begin(); + for (i = 0; i < nvqs; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + + memory_region_transaction_commit(); + + for (i = 0; i < nvqs; i++) { virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } From 61fc57bfc464c3584bd7ab810c86833661f0188c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 7 Apr 2021 16:35:00 +0200 Subject: [PATCH 0576/3028] virtio-scsi: Set host notifiers and callbacks separately Host notifiers are guaranteed to be idle until the callbacks are hooked up with virtio_queue_aio_set_host_notifier_handler(). They thus don't need to be set or unset with the AioContext lock held. Do this outside the critical section, like virtio-blk already does : basically downgrading virtio_scsi_vring_init() to only setup the host notifier and set the callback in the caller. This will allow to batch addition/deletion of ioeventds in a single memory transaction, which is expected to greatly improve initialization time. Signed-off-by: Greg Kurz Message-Id: <20210407143501.244343-4-groug@kaod.org> Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/virtio-scsi-dataplane.c | 40 ++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index 4ad8793406..b2cb3d9dcc 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -94,8 +94,7 @@ static bool virtio_scsi_data_plane_handle_event(VirtIODevice *vdev, return progress; } -static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n, - VirtIOHandleAIOOutput fn) +static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); int rc; @@ -109,7 +108,6 @@ static int virtio_scsi_vring_init(VirtIOSCSI *s, VirtQueue *vq, int n, return rc; } - virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, fn); return 0; } @@ -154,38 +152,44 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) goto fail_guest_notifiers; } - aio_context_acquire(s->ctx); - rc = virtio_scsi_vring_init(s, vs->ctrl_vq, 0, - virtio_scsi_data_plane_handle_ctrl); - if (rc) { - goto fail_vrings; + rc = virtio_scsi_set_host_notifier(s, vs->ctrl_vq, 0); + if (rc != 0) { + goto fail_host_notifiers; } vq_init_count++; - rc = virtio_scsi_vring_init(s, vs->event_vq, 1, - virtio_scsi_data_plane_handle_event); - if (rc) { - goto fail_vrings; + rc = virtio_scsi_set_host_notifier(s, vs->event_vq, 1); + if (rc != 0) { + goto fail_host_notifiers; } vq_init_count++; + for (i = 0; i < vs->conf.num_queues; i++) { - rc = virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2, - virtio_scsi_data_plane_handle_cmd); + rc = virtio_scsi_set_host_notifier(s, vs->cmd_vqs[i], i + 2); if (rc) { - goto fail_vrings; + goto fail_host_notifiers; } vq_init_count++; } + aio_context_acquire(s->ctx); + virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, + virtio_scsi_data_plane_handle_ctrl); + virtio_queue_aio_set_host_notifier_handler(vs->event_vq, s->ctx, + virtio_scsi_data_plane_handle_event); + + for (i = 0; i < vs->conf.num_queues; i++) { + virtio_queue_aio_set_host_notifier_handler(vs->cmd_vqs[i], s->ctx, + virtio_scsi_data_plane_handle_cmd); + } + s->dataplane_starting = false; s->dataplane_started = true; aio_context_release(s->ctx); return 0; -fail_vrings: - aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s); - aio_context_release(s->ctx); +fail_host_notifiers: for (i = 0; i < vq_init_count; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); From c4f5dcc4360a02085a633fd7a90b7ac395ca1ba4 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 7 Apr 2021 16:35:01 +0200 Subject: [PATCH 0577/3028] virtio-scsi: Configure all host notifiers in a single MR transaction This allows the virtio-scsi-pci device to batch the setup of all its host notifiers. This significantly improves boot time of VMs with a high number of vCPUs, e.g. from 6m5.563s down to 1m2.884s for a pseries machine with 384 vCPUs. Note that memory_region_transaction_commit() must be called before virtio_bus_cleanup_host_notifier() because the latter might close ioeventfds that the transaction still assumes to be around when it commits. Signed-off-by: Greg Kurz Message-Id: <20210407143501.244343-5-groug@kaod.org> Reviewed-by: Stefan Hajnoczi Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/scsi/virtio-scsi-dataplane.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c index b2cb3d9dcc..28e003250a 100644 --- a/hw/scsi/virtio-scsi-dataplane.c +++ b/hw/scsi/virtio-scsi-dataplane.c @@ -152,6 +152,8 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) goto fail_guest_notifiers; } + memory_region_transaction_begin(); + rc = virtio_scsi_set_host_notifier(s, vs->ctrl_vq, 0); if (rc != 0) { goto fail_host_notifiers; @@ -173,6 +175,8 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) vq_init_count++; } + memory_region_transaction_commit(); + aio_context_acquire(s->ctx); virtio_queue_aio_set_host_notifier_handler(vs->ctrl_vq, s->ctx, virtio_scsi_data_plane_handle_ctrl); @@ -192,6 +196,11 @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev) fail_host_notifiers: for (i = 0; i < vq_init_count; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + + memory_region_transaction_commit(); + + for (i = 0; i < vq_init_count; i++) { virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false); @@ -229,8 +238,15 @@ void virtio_scsi_dataplane_stop(VirtIODevice *vdev) blk_drain_all(); /* ensure there are no in-flight requests */ + memory_region_transaction_begin(); + for (i = 0; i < vs->conf.num_queues + 2; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + + memory_region_transaction_commit(); + + for (i = 0; i < vs->conf.num_queues + 2; i++) { virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i); } From 43bea443575772bdabd13781be043468c205d6cf Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 8 Apr 2021 08:51:19 +0200 Subject: [PATCH 0578/3028] checkpatch: Fix use of uninitialized value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit checkfilename() doesn't always set $acpi_testexpected. Fix the following warning: Use of uninitialized value $acpi_testexpected in string eq at ./scripts/checkpatch.pl line 1529. Fixes: d2f1af0e4120 ("checkpatch: don't emit warning on newly created acpi data files") Cc: isaku.yamahata@intel.com Signed-off-by: Greg Kurz Message-Id: <161786467973.295167.5612704777283969903.stgit@bahia.lan> Reviewed-by: Alex Bennée Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- scripts/checkpatch.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 8f7053ec9b..3d185cceac 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1532,6 +1532,7 @@ sub process { ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ && (defined($1) || defined($2)))) && !(($realfile ne '') && + defined($acpi_testexpected) && ($realfile eq $acpi_testexpected))) { $reported_maintainer_file = 1; WARN("added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); From 05dfb447a4e11b32d4ed94f73629c497235fc3dc Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Thu, 1 Apr 2021 19:11:38 +0200 Subject: [PATCH 0579/3028] hw/smbios: support for type 41 (onboard devices extended information) Type 41 defines the attributes of devices that are onboard. The original intent was to imply the BIOS had some level of control over the enablement of the associated devices. If network devices are present in this table, by default, udev will name the corresponding interfaces enoX, X being the instance number. Without such information, udev will fallback to using the PCI ID and this usually gives ens3 or ens4. This can be a bit annoying as the name of the network card may depend on the order of options and may change if a new PCI device is added earlier on the commande line. Being able to provide SMBIOS type 41 entry ensure the name of the interface won't change and helps the user guess the right name without booting a first time. This can be invoked with: $QEMU -netdev user,id=internet -device virtio-net-pci,mac=50:54:00:00:00:42,netdev=internet,id=internet-dev \ -smbios type=41,designation='Onboard LAN',instance=1,kind=ethernet,pcidev=internet-dev The PCI segment is assumed to be 0. This should hold true for most cases. $ dmidecode -t 41 # dmidecode 3.3 Getting SMBIOS data from sysfs. SMBIOS 2.8 present. Handle 0x2900, DMI type 41, 11 bytes Onboard Device Reference Designation: Onboard LAN Type: Ethernet Status: Enabled Type Instance: 1 Bus Address: 0000:00:09.0 $ ip -brief a lo UNKNOWN 127.0.0.1/8 ::1/128 eno1 UP 10.0.2.14/24 fec0::5254:ff:fe00:42/64 fe80::5254:ff:fe00:42/64 Signed-off-by: Vincent Bernat Message-Id: <20210401171138.62970-1-vincent@bernat.ch> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/arm/virt.c | 7 +- hw/i386/fw_cfg.c | 4 +- hw/smbios/smbios.c | 124 ++++++++++++++++++++++++++++++++++- include/hw/firmware/smbios.h | 14 +++- qemu-options.hx | 30 ++++++++- 5 files changed, 173 insertions(+), 6 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 9f01d9041b..26a1e252fe 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -53,6 +53,7 @@ #include "sysemu/kvm.h" #include "hw/loader.h" #include "exec/address-spaces.h" +#include "qapi/error.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "qemu/module.h" @@ -1524,8 +1525,10 @@ static void virt_build_smbios(VirtMachineState *vms) vmc->smbios_old_sys_ver ? "1.0" : mc->name, false, true, SMBIOS_ENTRY_POINT_30); - smbios_get_tables(MACHINE(vms), NULL, 0, &smbios_tables, &smbios_tables_len, - &smbios_anchor, &smbios_anchor_len); + smbios_get_tables(MACHINE(vms), NULL, 0, + &smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len, + &error_fatal); if (smbios_anchor) { fw_cfg_add_file(vms->fw_cfg, "etc/smbios/smbios-tables", diff --git a/hw/i386/fw_cfg.c b/hw/i386/fw_cfg.c index e48a54fa36..4e68d5dea4 100644 --- a/hw/i386/fw_cfg.c +++ b/hw/i386/fw_cfg.c @@ -22,6 +22,7 @@ #include "hw/nvram/fw_cfg.h" #include "e820_memory_layout.h" #include "kvm/kvm_i386.h" +#include "qapi/error.h" #include CONFIG_DEVICES struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX}; @@ -78,7 +79,8 @@ void fw_cfg_build_smbios(MachineState *ms, FWCfgState *fw_cfg) } smbios_get_tables(ms, mem_array, array_count, &smbios_tables, &smbios_tables_len, - &smbios_anchor, &smbios_anchor_len); + &smbios_anchor, &smbios_anchor_len, + &error_fatal); g_free(mem_array); if (smbios_anchor) { diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c index f22c4f5b73..7397e56737 100644 --- a/hw/smbios/smbios.c +++ b/hw/smbios/smbios.c @@ -27,6 +27,7 @@ #include "hw/firmware/smbios.h" #include "hw/loader.h" #include "hw/boards.h" +#include "hw/pci/pci_bus.h" #include "smbios_build.h" /* legacy structures and constants for <= 2.0 machines */ @@ -118,6 +119,28 @@ static struct { uint16_t speed; } type17; +static QEnumLookup type41_kind_lookup = { + .array = (const char *const[]) { + "other", + "unknown", + "video", + "scsi", + "ethernet", + "tokenring", + "sound", + "pata", + "sata", + "sas", + }, + .size = 10 +}; +struct type41_instance { + const char *designation, *pcidev; + uint8_t instance, kind; + QTAILQ_ENTRY(type41_instance) next; +}; +static QTAILQ_HEAD(, type41_instance) type41 = QTAILQ_HEAD_INITIALIZER(type41); + static QemuOptsList qemu_smbios_opts = { .name = "smbios", .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head), @@ -358,6 +381,32 @@ static const QemuOptDesc qemu_smbios_type17_opts[] = { { /* end of list */ } }; +static const QemuOptDesc qemu_smbios_type41_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "designation", + .type = QEMU_OPT_STRING, + .help = "reference designation string", + },{ + .name = "kind", + .type = QEMU_OPT_STRING, + .help = "device type", + .def_value_str = "other", + },{ + .name = "instance", + .type = QEMU_OPT_NUMBER, + .help = "device type instance", + },{ + .name = "pcidev", + .type = QEMU_OPT_STRING, + .help = "PCI device", + }, + { /* end of list */ } +}; + static void smbios_register_config(void) { qemu_add_opts(&qemu_smbios_opts); @@ -773,6 +822,53 @@ static void smbios_build_type_32_table(void) SMBIOS_BUILD_TABLE_POST; } +static void smbios_build_type_41_table(Error **errp) +{ + unsigned instance = 0; + struct type41_instance *t41; + + QTAILQ_FOREACH(t41, &type41, next) { + SMBIOS_BUILD_TABLE_PRE(41, 0x2900 + instance, true); + + SMBIOS_TABLE_SET_STR(41, reference_designation_str, t41->designation); + t->device_type = t41->kind; + t->device_type_instance = t41->instance; + t->segment_group_number = cpu_to_le16(0); + t->bus_number = 0; + t->device_number = 0; + + if (t41->pcidev) { + PCIDevice *pdev = NULL; + int rc = pci_qdev_find_device(t41->pcidev, &pdev); + if (rc != 0) { + error_setg(errp, + "No PCI device %s for SMBIOS type 41 entry %s", + t41->pcidev, t41->designation); + return; + } + /* + * We only handle the case were the device is attached to + * the PCI root bus. The general case is more complex as + * bridges are enumerated later and the table would need + * to be updated at this moment. + */ + if (!pci_bus_is_root(pci_get_bus(pdev))) { + error_setg(errp, + "Cannot create type 41 entry for PCI device %s: " + "not attached to the root bus", + t41->pcidev); + return; + } + t->segment_group_number = cpu_to_le16(0); + t->bus_number = pci_dev_bus_num(pdev); + t->device_number = pdev->devfn; + } + + SMBIOS_BUILD_TABLE_POST; + instance++; + } +} + static void smbios_build_type_127_table(void) { SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */ @@ -883,7 +979,8 @@ void smbios_get_tables(MachineState *ms, const struct smbios_phys_mem_area *mem_array, const unsigned int mem_array_size, uint8_t **tables, size_t *tables_len, - uint8_t **anchor, size_t *anchor_len) + uint8_t **anchor, size_t *anchor_len, + Error **errp) { unsigned i, dimm_cnt; @@ -928,6 +1025,7 @@ void smbios_get_tables(MachineState *ms, smbios_build_type_32_table(); smbios_build_type_38_table(); + smbios_build_type_41_table(errp); smbios_build_type_127_table(); smbios_validate_table(ms); @@ -1224,6 +1322,30 @@ void smbios_entry_add(QemuOpts *opts, Error **errp) save_opt(&type17.part, opts, "part"); type17.speed = qemu_opt_get_number(opts, "speed", 0); return; + case 41: { + struct type41_instance *t; + Error *local_err = NULL; + + if (!qemu_opts_validate(opts, qemu_smbios_type41_opts, errp)) { + return; + } + t = g_new0(struct type41_instance, 1); + save_opt(&t->designation, opts, "designation"); + t->kind = qapi_enum_parse(&type41_kind_lookup, + qemu_opt_get(opts, "kind"), + 0, &local_err) + 1; + t->kind |= 0x80; /* enabled */ + if (local_err != NULL) { + error_propagate(errp, local_err); + g_free(t); + return; + } + t->instance = qemu_opt_get_number(opts, "instance", 1); + save_opt(&t->pcidev, opts, "pcidev"); + + QTAILQ_INSERT_TAIL(&type41, t, next); + return; + } default: error_setg(errp, "Don't know how to build fields for SMBIOS type %ld", diff --git a/include/hw/firmware/smbios.h b/include/hw/firmware/smbios.h index 02a0ced0a0..5a0dd0c8cf 100644 --- a/include/hw/firmware/smbios.h +++ b/include/hw/firmware/smbios.h @@ -258,6 +258,17 @@ struct smbios_type_32 { uint8_t boot_status; } QEMU_PACKED; +/* SMBIOS type 41 - Onboard Devices Extended Information */ +struct smbios_type_41 { + struct smbios_structure_header header; + uint8_t reference_designation_str; + uint8_t device_type; + uint8_t device_type_instance; + uint16_t segment_group_number; + uint8_t bus_number; + uint8_t device_number; +} QEMU_PACKED; + /* SMBIOS type 127 -- End-of-table */ struct smbios_type_127 { struct smbios_structure_header header; @@ -273,5 +284,6 @@ void smbios_get_tables(MachineState *ms, const struct smbios_phys_mem_area *mem_array, const unsigned int mem_array_size, uint8_t **tables, size_t *tables_len, - uint8_t **anchor, size_t *anchor_len); + uint8_t **anchor, size_t *anchor_len, + Error **errp); #endif /* QEMU_SMBIOS_H */ diff --git a/qemu-options.hx b/qemu-options.hx index fd21002bd6..f71f716aa0 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2370,7 +2370,9 @@ DEF("smbios", HAS_ARG, QEMU_OPTION_smbios, " specify SMBIOS type 11 fields\n" "-smbios type=17[,loc_pfx=str][,bank=str][,manufacturer=str][,serial=str]\n" " [,asset=str][,part=str][,speed=%d]\n" - " specify SMBIOS type 17 fields\n", + " specify SMBIOS type 17 fields\n" + "-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]\n" + " specify SMBIOS type 41 fields\n", QEMU_ARCH_I386 | QEMU_ARCH_ARM) SRST ``-smbios file=binary`` @@ -2432,6 +2434,32 @@ SRST ``-smbios type=17[,loc_pfx=str][,bank=str][,manufacturer=str][,serial=str][,asset=str][,part=str][,speed=%d]`` Specify SMBIOS type 17 fields + +``-smbios type=41[,designation=str][,kind=str][,instance=%d][,pcidev=str]`` + Specify SMBIOS type 41 fields + + This argument can be repeated multiple times. Its main use is to allow network interfaces be created + as ``enoX`` on Linux, with X being the instance number, instead of the name depending on the interface + position on the PCI bus. + + Here is an example of use: + + .. parsed-literal:: + + -netdev user,id=internet \\ + -device virtio-net-pci,mac=50:54:00:00:00:42,netdev=internet,id=internet-dev \\ + -smbios type=41,designation='Onboard LAN',instance=1,kind=ethernet,pcidev=internet-dev + + In the guest OS, the device should then appear as ``eno1``: + + ..parsed-literal:: + + $ ip -brief l + lo UNKNOWN 00:00:00:00:00:00 + eno1 UP 50:54:00:00:00:42 + + Currently, the PCI device has to be attached to the root bus. + ERST DEFHEADING() From b8893a3c862111fa1c530c4be6f7426e7f07bf1e Mon Sep 17 00:00:00 2001 From: Pavel Dovgalyuk Date: Mon, 29 Mar 2021 10:43:12 +0300 Subject: [PATCH 0580/3028] hw/virtio: enable ioeventfd configuring for mmio This patch adds ioeventfd flag for virtio-mmio configuration. It allows switching ioeventfd on and off. Signed-off-by: Pavel Dovgalyuk Message-Id: <161700379211.1135943.8859209566937991305.stgit@pasha-ThinkPad-X280> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-mmio.c | 11 ++++++++++- include/hw/virtio/virtio-mmio.h | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 342c918ea7..5952471b38 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -36,7 +36,9 @@ static bool virtio_mmio_ioeventfd_enabled(DeviceState *d) { - return kvm_eventfds_enabled(); + VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); + + return (proxy->flags & VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD) != 0; } static int virtio_mmio_ioeventfd_assign(DeviceState *d, @@ -720,6 +722,8 @@ static Property virtio_mmio_properties[] = { DEFINE_PROP_BOOL("format_transport_address", VirtIOMMIOProxy, format_transport_address, true), DEFINE_PROP_BOOL("force-legacy", VirtIOMMIOProxy, legacy, true), + DEFINE_PROP_BIT("ioeventfd", VirtIOMMIOProxy, flags, + VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_END_OF_LIST(), }; @@ -731,6 +735,11 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp) qbus_create_inplace(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS, d, NULL); sysbus_init_irq(sbd, &proxy->irq); + + if (!kvm_eventfds_enabled()) { + proxy->flags &= ~VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD; + } + if (proxy->legacy) { memory_region_init_io(&proxy->iomem, OBJECT(d), &virtio_legacy_mem_ops, proxy, diff --git a/include/hw/virtio/virtio-mmio.h b/include/hw/virtio/virtio-mmio.h index d4c4c386ab..090f7730e7 100644 --- a/include/hw/virtio/virtio-mmio.h +++ b/include/hw/virtio/virtio-mmio.h @@ -49,12 +49,17 @@ typedef struct VirtIOMMIOQueue { uint32_t used[2]; } VirtIOMMIOQueue; +#define VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT 1 +#define VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD \ + (1 << VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT) + struct VirtIOMMIOProxy { /* Generic */ SysBusDevice parent_obj; MemoryRegion iomem; qemu_irq irq; bool legacy; + uint32_t flags; /* Guest accessible state needing migration and reset */ uint32_t host_features_sel; uint32_t guest_features_sel; From c232b8f45375bbffe7c6941968309400a59a893c Mon Sep 17 00:00:00 2001 From: Zenghui Yu Date: Tue, 13 Apr 2021 21:37:37 +0800 Subject: [PATCH 0581/3028] vhost-vdpa: Make vhost_vdpa_get_device_id() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As it's only used inside hw/virtio/vhost-vdpa.c. Signed-off-by: Zenghui Yu Message-Id: <20210413133737.1574-1-yuzenghui@huawei.com> Reviewed-by: Stefano Garzarella Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 4 ++-- include/hw/virtio/vhost-vdpa.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 01d2101d09..8f2fb9f10b 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -371,8 +371,8 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) return 0; } -int vhost_vdpa_get_device_id(struct vhost_dev *dev, - uint32_t *device_id) +static int vhost_vdpa_get_device_id(struct vhost_dev *dev, + uint32_t *device_id) { int ret; ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_DEVICE_ID, device_id); diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h index 9b81a409da..28ca65018e 100644 --- a/include/hw/virtio/vhost-vdpa.h +++ b/include/hw/virtio/vhost-vdpa.h @@ -22,6 +22,4 @@ typedef struct vhost_vdpa { } VhostVDPA; extern AddressSpace address_space_memory; -extern int vhost_vdpa_get_device_id(struct vhost_dev *dev, - uint32_t *device_id); #endif From f7a6df5f5bf3acc219352a1b25573ae2082d7e42 Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Thu, 3 Dec 2020 20:58:19 +0100 Subject: [PATCH 0582/3028] Fix build with 64 bits time_t time element is deprecated on new input_event structure in kernel's input.h [1] This will avoid the following build failure: hw/input/virtio-input-host.c: In function 'virtio_input_host_handle_status': hw/input/virtio-input-host.c:198:28: error: 'struct input_event' has no member named 'time' 198 | if (gettimeofday(&evdev.time, NULL)) { | ^ Fixes: - http://autobuild.buildroot.org/results/a538167e288c14208d557cd45446df86d3d599d5 - http://autobuild.buildroot.org/results/efd4474fb4b6c0ce0ab3838ce130429c51e43bbb [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=152194fe9c3f Signed-off-by: Fabrice Fontaine Message-Id: <20201203195819.583626-1-fontaine.fabrice@gmail.com> Fixes: https://gitlab.com/qemu-project/qemu/-/issues/246 Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- contrib/vhost-user-input/main.c | 8 ++++++-- hw/input/virtio-input-host.c | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/contrib/vhost-user-input/main.c b/contrib/vhost-user-input/main.c index c15d18c33f..081230da54 100644 --- a/contrib/vhost-user-input/main.c +++ b/contrib/vhost-user-input/main.c @@ -6,12 +6,13 @@ #include "qemu/osdep.h" -#include +#include #include "qemu/iov.h" #include "qemu/bswap.h" #include "qemu/sockets.h" #include "libvhost-user-glib.h" +#include "standard-headers/linux/input.h" #include "standard-headers/linux/virtio_input.h" #include "qapi/error.h" @@ -113,13 +114,16 @@ vi_evdev_watch(VuDev *dev, int condition, void *data) static void vi_handle_status(VuInput *vi, virtio_input_event *event) { struct input_event evdev; + struct timeval tval; int rc; - if (gettimeofday(&evdev.time, NULL)) { + if (gettimeofday(&tval, NULL)) { perror("vi_handle_status: gettimeofday"); return; } + evdev.input_event_sec = tval.tv_sec; + evdev.input_event_usec = tval.tv_usec; evdev.type = le16toh(event->type); evdev.code = le16toh(event->code); evdev.value = le32toh(event->value); diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c index 85daf73f1a..137efba57b 100644 --- a/hw/input/virtio-input-host.c +++ b/hw/input/virtio-input-host.c @@ -193,13 +193,16 @@ static void virtio_input_host_handle_status(VirtIOInput *vinput, { VirtIOInputHost *vih = VIRTIO_INPUT_HOST(vinput); struct input_event evdev; + struct timeval tval; int rc; - if (gettimeofday(&evdev.time, NULL)) { + if (gettimeofday(&tval, NULL)) { perror("virtio_input_host_handle_status: gettimeofday"); return; } + evdev.input_event_sec = tval.tv_sec; + evdev.input_event_usec = tval.tv_usec; evdev.type = le16_to_cpu(event->type); evdev.code = le16_to_cpu(event->code); evdev.value = le32_to_cpu(event->value); From 48c8c5e8862431235ec5ab553977ee5fe6ffbba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 3 Mar 2021 22:46:57 +0100 Subject: [PATCH 0583/3028] linux-user: Remove dead code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can not use watchpoints in user-mode emulation because we need the softmmu slow path to detect accesses to watchpointed memory. This code is expanded as empty stub in "hw/core/cpu.h" anyway, so we can drop it. Reviewed-by: Laurent Vivier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210303214708.1727801-18-f4bug@amsat.org> Signed-off-by: Laurent Vivier --- linux-user/main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 7995b6e7a6..4dfc47ad3b 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -205,7 +205,6 @@ CPUArchState *cpu_copy(CPUArchState *env) CPUState *new_cpu = cpu_create(cpu_type); CPUArchState *new_env = new_cpu->env_ptr; CPUBreakpoint *bp; - CPUWatchpoint *wp; /* Reset non arch specific state */ cpu_reset(new_cpu); @@ -217,13 +216,9 @@ CPUArchState *cpu_copy(CPUArchState *env) Note: Once we support ptrace with hw-debug register access, make sure BP_CPU break/watchpoints are handled correctly on clone. */ QTAILQ_INIT(&new_cpu->breakpoints); - QTAILQ_INIT(&new_cpu->watchpoints); QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) { cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL); } - QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) { - cpu_watchpoint_insert(new_cpu, wp->vaddr, wp->len, wp->flags, NULL); - } return new_env; } From 5847d3098d92851015e0f0c868e1305103feae02 Mon Sep 17 00:00:00 2001 From: Matus Kysel Date: Tue, 6 Apr 2021 14:42:03 +0000 Subject: [PATCH 0584/3028] linux-user: strace now handles unshare syscall args correctly Syscall unshare did not have custom print function for strace, but it's argument is same as flags in clone syscall, so it can be easily implemented. Also updated missing flags from clone_flags. Signed-off-by: Matus Kysel Reviewed-by: Laurent Vivier Message-Id: <20210406144203.1020598-1-mkysel@tachyum.com> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 18 ++++++++++++++++++ linux-user/strace.list | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index e969121b6c..1cadb6d50f 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1109,6 +1109,12 @@ UNUSED static struct flags clone_flags[] = { #if defined(CLONE_NEWNET) FLAG_GENERIC(CLONE_NEWNET), #endif +#if defined(CLONE_NEWCGROUP) + FLAG_GENERIC(CLONE_NEWCGROUP), +#endif +#if defined(CLONE_NEWTIME) + FLAG_GENERIC(CLONE_NEWTIME), +#endif #if defined(CLONE_IO) FLAG_GENERIC(CLONE_IO), #endif @@ -3467,6 +3473,18 @@ print_unlinkat(void *cpu_env, const struct syscallname *name, } #endif +#ifdef TARGET_NR_unshare +static void +print_unshare(void *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + print_syscall_prologue(name); + print_flags(clone_flags, arg0, 1); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_utime static void print_utime(void *cpu_env, const struct syscallname *name, diff --git a/linux-user/strace.list b/linux-user/strace.list index 084048ab96..3b7c15578c 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1573,7 +1573,7 @@ { TARGET_NR_unlinkat, "unlinkat" , NULL, print_unlinkat, NULL }, #endif #ifdef TARGET_NR_unshare -{ TARGET_NR_unshare, "unshare" , NULL, NULL, NULL }, +{ TARGET_NR_unshare, "unshare" , NULL, print_unshare, NULL }, #endif #ifdef TARGET_NR_userfaultfd { TARGET_NR_userfaultfd, "userfaultfd" , NULL, NULL, NULL }, From c1438d6c02eae03cc387dbdf2f30c11f45894954 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Apr 2021 09:54:10 -0700 Subject: [PATCH 0585/3028] linux-user/arm: Split out emulate_arm_fpa11 Pull out the fpa11 emulation to a helper function. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20210423165413.338259-2-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/arm/cpu_loop.c | 153 +++++++++++++++++++++++--------------- 1 file changed, 94 insertions(+), 59 deletions(-) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 989d03cd89..106909c7d8 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -224,6 +224,92 @@ static bool insn_is_linux_bkpt(uint32_t opcode, bool is_thumb) } } +static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) +{ + TaskState *ts = env_cpu(env)->opaque; + int rc = EmulateAll(opcode, &ts->fpa, env); + + if (rc == 0) { + /* Illegal instruction */ + return false; + } + if (rc > 0) { + /* Everything ok. */ + env->regs[15] += 4; + return true; + } + + /* FP exception */ + int arm_fpe = 0; + + /* Translate softfloat flags to FPSR flags */ + if (-rc & float_flag_invalid) { + arm_fpe |= BIT_IOC; + } + if (-rc & float_flag_divbyzero) { + arm_fpe |= BIT_DZC; + } + if (-rc & float_flag_overflow) { + arm_fpe |= BIT_OFC; + } + if (-rc & float_flag_underflow) { + arm_fpe |= BIT_UFC; + } + if (-rc & float_flag_inexact) { + arm_fpe |= BIT_IXC; + } + + /* Exception enabled? */ + FPSR fpsr = ts->fpa.fpsr; + if (fpsr & (arm_fpe << 16)) { + target_siginfo_t info; + + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + + /* ordered by priority, least first */ + if (arm_fpe & BIT_IXC) { + info.si_code = TARGET_FPE_FLTRES; + } + if (arm_fpe & BIT_UFC) { + info.si_code = TARGET_FPE_FLTUND; + } + if (arm_fpe & BIT_OFC) { + info.si_code = TARGET_FPE_FLTOVF; + } + if (arm_fpe & BIT_DZC) { + info.si_code = TARGET_FPE_FLTDIV; + } + if (arm_fpe & BIT_IOC) { + info.si_code = TARGET_FPE_FLTINV; + } + + info._sifields._sigfault._addr = env->regs[15]; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + } else { + env->regs[15] += 4; + } + + /* Accumulate unenabled exceptions */ + if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) { + fpsr |= BIT_IXC; + } + if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) { + fpsr |= BIT_UFC; + } + if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) { + fpsr |= BIT_OFC; + } + if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) { + fpsr |= BIT_DZC; + } + if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) { + fpsr |= BIT_IOC; + } + ts->fpa.fpsr = fpsr; + return true; +} + void cpu_loop(CPUARMState *env) { CPUState *cs = env_cpu(env); @@ -244,9 +330,7 @@ void cpu_loop(CPUARMState *env) case EXCP_NOCP: case EXCP_INVSTATE: { - TaskState *ts = cs->opaque; uint32_t opcode; - int rc; /* we handle the FPU emulation here, as Linux */ /* we get the opcode */ @@ -263,64 +347,15 @@ void cpu_loop(CPUARMState *env) goto excp_debug; } - rc = EmulateAll(opcode, &ts->fpa, env); - if (rc == 0) { /* illegal instruction */ - info.si_signo = TARGET_SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPN; - info._sifields._sigfault._addr = env->regs[15]; - queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); - } else if (rc < 0) { /* FP exception */ - int arm_fpe=0; - - /* translate softfloat flags to FPSR flags */ - if (-rc & float_flag_invalid) - arm_fpe |= BIT_IOC; - if (-rc & float_flag_divbyzero) - arm_fpe |= BIT_DZC; - if (-rc & float_flag_overflow) - arm_fpe |= BIT_OFC; - if (-rc & float_flag_underflow) - arm_fpe |= BIT_UFC; - if (-rc & float_flag_inexact) - arm_fpe |= BIT_IXC; - - FPSR fpsr = ts->fpa.fpsr; - //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe); - - if (fpsr & (arm_fpe << 16)) { /* exception enabled? */ - info.si_signo = TARGET_SIGFPE; - info.si_errno = 0; - - /* ordered by priority, least first */ - if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES; - if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND; - if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF; - if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV; - if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV; - - info._sifields._sigfault._addr = env->regs[15]; - queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); - } else { - env->regs[15] += 4; - } - - /* accumulate unenabled exceptions */ - if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) - fpsr |= BIT_IXC; - if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) - fpsr |= BIT_UFC; - if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) - fpsr |= BIT_OFC; - if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) - fpsr |= BIT_DZC; - if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) - fpsr |= BIT_IOC; - ts->fpa.fpsr=fpsr; - } else { /* everything OK */ - /* increment PC */ - env->regs[15] += 4; + if (emulate_arm_fpa11(env, opcode)) { + break; } + + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->regs[15]; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_SWI: From d827f6d5fdb0826e17c80f63547c5c2dee3f0fac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Apr 2021 09:54:11 -0700 Subject: [PATCH 0586/3028] linux-user/arm: Do not emulate fpa11 in thumb mode These antiquated instructions are arm-mode only. Buglink: https://bugs.launchpad.net/bugs/1925512 Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20210423165413.338259-3-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/arm/cpu_loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 106909c7d8..e2a1496b9f 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -347,7 +347,7 @@ void cpu_loop(CPUARMState *env) goto excp_debug; } - if (emulate_arm_fpa11(env, opcode)) { + if (!env->thumb && emulate_arm_fpa11(env, opcode)) { break; } From 0a50285ee8bf471936325f5ccd870752d2a038cb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Apr 2021 09:54:12 -0700 Subject: [PATCH 0587/3028] linux-user/arm: Do not fill in si_code for fpa11 exceptions There is no such decoding in linux/arch/arm/nwfpe/fpmodule.c. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20210423165413.338259-4-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/arm/cpu_loop.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index e2a1496b9f..5f61d25717 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -262,29 +262,15 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) /* Exception enabled? */ FPSR fpsr = ts->fpa.fpsr; if (fpsr & (arm_fpe << 16)) { - target_siginfo_t info; + target_siginfo_t info = { }; + /* + * The kernel's nwfpe emulator does not pass a real si_code. + * It merely uses send_sig(SIGFPE, current, 1). + */ info.si_signo = TARGET_SIGFPE; - info.si_errno = 0; + info.si_code = TARGET_SI_KERNEL; - /* ordered by priority, least first */ - if (arm_fpe & BIT_IXC) { - info.si_code = TARGET_FPE_FLTRES; - } - if (arm_fpe & BIT_UFC) { - info.si_code = TARGET_FPE_FLTUND; - } - if (arm_fpe & BIT_OFC) { - info.si_code = TARGET_FPE_FLTOVF; - } - if (arm_fpe & BIT_DZC) { - info.si_code = TARGET_FPE_FLTDIV; - } - if (arm_fpe & BIT_IOC) { - info.si_code = TARGET_FPE_FLTINV; - } - - info._sifields._sigfault._addr = env->regs[15]; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } else { env->regs[15] += 4; From 74081ae0ff4aea6ad0db0427ed31ac5250a58b3f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Apr 2021 09:54:13 -0700 Subject: [PATCH 0588/3028] linux-user/arm: Simplify accumulating and raising fpa11 exceptions Use bit masking instead of an if tree. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20210423165413.338259-5-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/arm/cpu_loop.c | 50 ++++++++++++++------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 5f61d25717..69632d15be 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -228,6 +228,7 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) { TaskState *ts = env_cpu(env)->opaque; int rc = EmulateAll(opcode, &ts->fpa, env); + int raise, enabled; if (rc == 0) { /* Illegal instruction */ @@ -240,28 +241,31 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) } /* FP exception */ - int arm_fpe = 0; + rc = -rc; + raise = 0; /* Translate softfloat flags to FPSR flags */ - if (-rc & float_flag_invalid) { - arm_fpe |= BIT_IOC; + if (rc & float_flag_invalid) { + raise |= BIT_IOC; } - if (-rc & float_flag_divbyzero) { - arm_fpe |= BIT_DZC; + if (rc & float_flag_divbyzero) { + raise |= BIT_DZC; } - if (-rc & float_flag_overflow) { - arm_fpe |= BIT_OFC; + if (rc & float_flag_overflow) { + raise |= BIT_OFC; } - if (-rc & float_flag_underflow) { - arm_fpe |= BIT_UFC; + if (rc & float_flag_underflow) { + raise |= BIT_UFC; } - if (-rc & float_flag_inexact) { - arm_fpe |= BIT_IXC; + if (rc & float_flag_inexact) { + raise |= BIT_IXC; } - /* Exception enabled? */ - FPSR fpsr = ts->fpa.fpsr; - if (fpsr & (arm_fpe << 16)) { + /* Accumulate unenabled exceptions */ + enabled = ts->fpa.fpsr >> 16; + ts->fpa.fpsr |= raise & ~enabled; + + if (raise & enabled) { target_siginfo_t info = { }; /* @@ -275,24 +279,6 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) } else { env->regs[15] += 4; } - - /* Accumulate unenabled exceptions */ - if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) { - fpsr |= BIT_IXC; - } - if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) { - fpsr |= BIT_UFC; - } - if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) { - fpsr |= BIT_OFC; - } - if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) { - fpsr |= BIT_DZC; - } - if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) { - fpsr |= BIT_IOC; - } - ts->fpa.fpsr = fpsr; return true; } From 9f771ad8399d5832a99564919379ab29c1bbbdce Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Wed, 12 May 2021 18:13:58 +0800 Subject: [PATCH 0589/3028] linux-user: Add strace support for printing arguments of llseek Some target are using llseek instead of _llseek like riscv, nios2, hexagon, and openrisc. Signed-off-by: Kito Cheng Reviewed-by: Laurent Vivier Message-Id: <20210512101358.122781-1-kito.cheng@sifive.com> Signed-off-by: Laurent Vivier --- linux-user/strace.c | 3 ++- linux-user/strace.list | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 1cadb6d50f..cce0a5d1e3 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -2341,7 +2341,7 @@ print_linkat(void *cpu_env, const struct syscallname *name, } #endif -#ifdef TARGET_NR__llseek +#if defined(TARGET_NR__llseek) || defined(TARGET_NR_llseek) static void print__llseek(void *cpu_env, const struct syscallname *name, abi_long arg0, abi_long arg1, abi_long arg2, @@ -2361,6 +2361,7 @@ print__llseek(void *cpu_env, const struct syscallname *name, qemu_log("%s", whence); print_syscall_epilogue(name); } +#define print_llseek print__llseek #endif #ifdef TARGET_NR_lseek diff --git a/linux-user/strace.list b/linux-user/strace.list index 3b7c15578c..18f7217275 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -511,6 +511,9 @@ #ifdef TARGET_NR__llseek { TARGET_NR__llseek, "_llseek" , NULL, print__llseek, NULL }, #endif +#ifdef TARGET_NR_llseek +{ TARGET_NR_llseek, "llseek" , NULL, print_llseek, NULL }, +#endif #ifdef TARGET_NR_lock { TARGET_NR_lock, "lock" , NULL, NULL, NULL }, #endif From 92bad948367c4b8a58f6bb81b45750f1d583f274 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:10 -0700 Subject: [PATCH 0590/3028] linux-user: Split out target_restore_altstack Create a function to match target_save_altstack. Fix some style and unlock issues in do_sigaltstack. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-2-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/signal-common.h | 1 + linux-user/signal.c | 115 +++++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 50 deletions(-) diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h index 1df1068552..34b963af9a 100644 --- a/linux-user/signal-common.h +++ b/linux-user/signal-common.h @@ -24,6 +24,7 @@ int on_sig_stack(unsigned long sp); int sas_ss_flags(unsigned long sp); abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka); void target_save_altstack(target_stack_t *uss, CPUArchState *env); +abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp); static inline void target_sigemptyset(target_sigset_t *set) { diff --git a/linux-user/signal.c b/linux-user/signal.c index 7eecec46c4..9daa89eac5 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -297,6 +297,50 @@ void target_save_altstack(target_stack_t *uss, CPUArchState *env) __put_user(ts->sigaltstack_used.ss_size, &uss->ss_size); } +abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp) +{ + TaskState *ts = (TaskState *)thread_cpu->opaque; + size_t minstacksize = TARGET_MINSIGSTKSZ; + target_stack_t ss; + +#if defined(TARGET_PPC64) + /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */ + struct image_info *image = ts->info; + if (get_ppc64_abi(image) > 1) { + minstacksize = 4096; + } +#endif + + __get_user(ss.ss_sp, &uss->ss_sp); + __get_user(ss.ss_size, &uss->ss_size); + __get_user(ss.ss_flags, &uss->ss_flags); + + if (on_sig_stack(sp)) { + return -TARGET_EPERM; + } + + switch (ss.ss_flags) { + default: + return -TARGET_EINVAL; + + case TARGET_SS_DISABLE: + ss.ss_size = 0; + ss.ss_sp = 0; + break; + + case TARGET_SS_ONSTACK: + case 0: + if (ss.ss_size < minstacksize) { + return -TARGET_ENOMEM; + } + break; + } + + ts->sigaltstack_used.ss_sp = ss.ss_sp; + ts->sigaltstack_used.ss_size = ss.ss_size; + return 0; +} + /* siginfo conversion */ static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, @@ -758,73 +802,44 @@ static void host_signal_handler(int host_signum, siginfo_t *info, /* compare linux/kernel/signal.c:do_sigaltstack() */ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) { - int ret; - struct target_sigaltstack oss; - TaskState *ts = (TaskState *)thread_cpu->opaque; + target_stack_t oss, *uoss = NULL; + abi_long ret = -TARGET_EFAULT; - /* XXX: test errors */ - if(uoss_addr) - { + if (uoss_addr) { + TaskState *ts = (TaskState *)thread_cpu->opaque; + + /* Verify writability now, but do not alter user memory yet. */ + if (!lock_user_struct(VERIFY_WRITE, uoss, uoss_addr, 0)) { + goto out; + } __put_user(ts->sigaltstack_used.ss_sp, &oss.ss_sp); __put_user(ts->sigaltstack_used.ss_size, &oss.ss_size); __put_user(sas_ss_flags(sp), &oss.ss_flags); } - if(uss_addr) - { - struct target_sigaltstack *uss; - struct target_sigaltstack ss; - size_t minstacksize = TARGET_MINSIGSTKSZ; + if (uss_addr) { + target_stack_t *uss; -#if defined(TARGET_PPC64) - /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */ - struct image_info *image = ((TaskState *)thread_cpu->opaque)->info; - if (get_ppc64_abi(image) > 1) { - minstacksize = 4096; - } -#endif - - ret = -TARGET_EFAULT; if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) { goto out; } - __get_user(ss.ss_sp, &uss->ss_sp); - __get_user(ss.ss_size, &uss->ss_size); - __get_user(ss.ss_flags, &uss->ss_flags); - unlock_user_struct(uss, uss_addr, 0); - - ret = -TARGET_EPERM; - if (on_sig_stack(sp)) + ret = target_restore_altstack(uss, sp); + if (ret) { goto out; - - ret = -TARGET_EINVAL; - if (ss.ss_flags != TARGET_SS_DISABLE - && ss.ss_flags != TARGET_SS_ONSTACK - && ss.ss_flags != 0) - goto out; - - if (ss.ss_flags == TARGET_SS_DISABLE) { - ss.ss_size = 0; - ss.ss_sp = 0; - } else { - ret = -TARGET_ENOMEM; - if (ss.ss_size < minstacksize) { - goto out; - } } - - ts->sigaltstack_used.ss_sp = ss.ss_sp; - ts->sigaltstack_used.ss_size = ss.ss_size; } if (uoss_addr) { - ret = -TARGET_EFAULT; - if (copy_to_user(uoss_addr, &oss, sizeof(oss))) - goto out; + memcpy(uoss, &oss, sizeof(oss)); + unlock_user_struct(uoss, uoss_addr, 1); + uoss = NULL; } - ret = 0; -out: + + out: + if (uoss) { + unlock_user_struct(uoss, uoss_addr, 0); + } return ret; } From 56384cf3adaeb15bab479be328605e301ae253f2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:11 -0700 Subject: [PATCH 0591/3028] linux-user: Use target_restore_altstack in all sigreturn Note that target_restore_altstack uses the host memory pointer that we have already verified, so TARGET_EFAULT is not a possible return value. Note that using -EFAULT was a bug. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-3-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/aarch64/signal.c | 6 +----- linux-user/alpha/signal.c | 6 +----- linux-user/arm/signal.c | 9 ++------- linux-user/hexagon/signal.c | 6 +----- linux-user/hppa/signal.c | 8 +------- linux-user/i386/signal.c | 5 +---- linux-user/m68k/signal.c | 5 +---- linux-user/microblaze/signal.c | 6 +----- linux-user/mips/signal.c | 6 +----- linux-user/nios2/signal.c | 8 +------- linux-user/openrisc/signal.c | 5 +---- linux-user/ppc/signal.c | 4 +--- linux-user/riscv/signal.c | 6 +----- linux-user/s390x/signal.c | 6 ++---- linux-user/sh4/signal.c | 7 +------ linux-user/xtensa/signal.c | 6 +----- 16 files changed, 18 insertions(+), 81 deletions(-) diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index b591790c22..2a1b7dbcdc 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -561,11 +561,7 @@ long do_rt_sigreturn(CPUARMState *env) goto badframe; } - if (do_sigaltstack(frame_addr + - offsetof(struct target_rt_sigframe, uc.tuc_stack), - 0, get_sp_from_cpustate(env)) == -EFAULT) { - goto badframe; - } + target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c index c5c27ce084..0af0227118 100644 --- a/linux-user/alpha/signal.c +++ b/linux-user/alpha/signal.c @@ -257,11 +257,7 @@ long do_rt_sigreturn(CPUAlphaState *env) set_sigmask(&set); restore_sigcontext(env, &frame->uc.tuc_mcontext); - if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, - uc.tuc_stack), - 0, env->ir[IR_SP]) == -EFAULT) { - goto badframe; - } + target_restore_altstack(&frame->uc.tuc_stack, env->ir[IR_SP]); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index f21d1535e4..b7a772302f 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -685,11 +685,7 @@ static int do_sigframe_return_v2(CPUARMState *env, } } - if (do_sigaltstack(context_addr - + offsetof(struct target_ucontext_v2, tuc_stack), - 0, get_sp_from_cpustate(env)) == -EFAULT) { - return 1; - } + target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env)); #if 0 /* Send SIGTRAP if we're single-stepping */ @@ -773,8 +769,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env) goto badframe; } - if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) - goto badframe; + target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); #if 0 /* Send SIGTRAP if we're single-stepping */ diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c index fde8dc93b7..3854eb4709 100644 --- a/linux-user/hexagon/signal.c +++ b/linux-user/hexagon/signal.c @@ -260,11 +260,7 @@ long do_rt_sigreturn(CPUHexagonState *env) } restore_ucontext(env, &frame->uc); - - if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, - uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) { - goto badframe; - } + target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env)); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c index d1a58feeb3..578874cf27 100644 --- a/linux-user/hppa/signal.c +++ b/linux-user/hppa/signal.c @@ -187,13 +187,7 @@ long do_rt_sigreturn(CPUArchState *env) set_sigmask(&set); restore_sigcontext(env, &frame->uc.tuc_mcontext); - unlock_user_struct(frame, frame_addr, 0); - - if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, - uc.tuc_stack), - 0, env->gr[30]) == -EFAULT) { - goto badframe; - } + target_restore_altstack(&frame->uc.tuc_stack, env->gr[30]); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 9320e1d472..3a0a1546a6 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -581,10 +581,7 @@ long do_rt_sigreturn(CPUX86State *env) goto badframe; } - if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0, - get_sp_from_cpustate(env)) == -EFAULT) { - goto badframe; - } + target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c index 49ff87c77b..004b59fb61 100644 --- a/linux-user/m68k/signal.c +++ b/linux-user/m68k/signal.c @@ -400,10 +400,7 @@ long do_rt_sigreturn(CPUM68KState *env) if (target_rt_restore_ucontext(env, &frame->uc)) goto badframe; - if (do_sigaltstack(frame_addr + - offsetof(struct target_rt_sigframe, uc.tuc_stack), - 0, get_sp_from_cpustate(env)) == -EFAULT) - goto badframe; + target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c index cf0707b556..f59a1faf47 100644 --- a/linux-user/microblaze/signal.c +++ b/linux-user/microblaze/signal.c @@ -209,11 +209,7 @@ long do_rt_sigreturn(CPUMBState *env) restore_sigcontext(&frame->uc.tuc_mcontext, env); - if (do_sigaltstack(frame_addr + - offsetof(struct target_rt_sigframe, uc.tuc_stack), - 0, get_sp_from_cpustate(env)) == -EFAULT) { - goto badframe; - } + target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c index 455a8a229a..456fa64f41 100644 --- a/linux-user/mips/signal.c +++ b/linux-user/mips/signal.c @@ -368,11 +368,7 @@ long do_rt_sigreturn(CPUMIPSState *env) set_sigmask(&blocked); restore_sigcontext(env, &frame->rs_uc.tuc_mcontext); - - if (do_sigaltstack(frame_addr + - offsetof(struct target_rt_sigframe, rs_uc.tuc_stack), - 0, get_sp_from_cpustate(env)) == -EFAULT) - goto badframe; + target_restore_altstack(&frame->rs_uc.tuc_stack, get_sp_from_cpustate(env)); env->active_tc.PC = env->CP0_EPC; mips_set_hflags_isa_mode_from_pc(env); diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c index 7d535065ed..751ea88811 100644 --- a/linux-user/nios2/signal.c +++ b/linux-user/nios2/signal.c @@ -82,9 +82,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc, int *pr2) { int temp; - abi_ulong off, frame_addr = env->regs[R_SP]; unsigned long *gregs = uc->tuc_mcontext.gregs; - int err; /* Always make any pending restarted system calls return -EINTR */ /* current->restart_block.fn = do_no_restart_syscall; */ @@ -130,11 +128,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc, __get_user(env->regs[R_RA], &gregs[23]); __get_user(env->regs[R_SP], &gregs[28]); - off = offsetof(struct target_rt_sigframe, uc.tuc_stack); - err = do_sigaltstack(frame_addr + off, 0, get_sp_from_cpustate(env)); - if (err == -EFAULT) { - return 1; - } + target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env)); *pr2 = env->regs[2]; return 0; diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c index 232ad82b98..86f94d7f76 100644 --- a/linux-user/openrisc/signal.c +++ b/linux-user/openrisc/signal.c @@ -158,10 +158,7 @@ long do_rt_sigreturn(CPUOpenRISCState *env) set_sigmask(&set); restore_sigcontext(env, &frame->uc.tuc_mcontext); - if (do_sigaltstack(frame_addr + offsetof(target_rt_sigframe, uc.tuc_stack), - 0, frame_addr) == -EFAULT) { - goto badframe; - } + target_restore_altstack(&frame->uc.tuc_stack, frame_addr); unlock_user_struct(frame, frame_addr, 0); return cpu_get_gpr(env, 11); diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index bad38f8ed9..b44d5ce73c 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -655,9 +655,7 @@ long do_rt_sigreturn(CPUPPCState *env) if (do_setcontext(&rt_sf->uc, env, 1)) goto sigsegv; - do_sigaltstack(rt_sf_addr - + offsetof(struct target_rt_sigframe, uc.tuc_stack), - 0, env->gpr[1]); + target_restore_altstack(&rt_sf->uc.tuc_stack, env->gpr[1]); unlock_user_struct(rt_sf, rt_sf_addr, 1); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c index 67a95dbc7b..81d1129da3 100644 --- a/linux-user/riscv/signal.c +++ b/linux-user/riscv/signal.c @@ -192,11 +192,7 @@ long do_rt_sigreturn(CPURISCVState *env) } restore_ucontext(env, &frame->uc); - - if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, - uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) { - goto badframe; - } + target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env)); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 7107c5fb53..73806f5472 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -307,10 +307,8 @@ long do_rt_sigreturn(CPUS390XState *env) goto badframe; } - if (do_sigaltstack(frame_addr + offsetof(rt_sigframe, uc.tuc_stack), 0, - get_sp_from_cpustate(env)) == -EFAULT) { - goto badframe; - } + target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); + unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index 29c1ee30e6..684f18da58 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -323,12 +323,7 @@ long do_rt_sigreturn(CPUSH4State *regs) set_sigmask(&blocked); restore_sigcontext(regs, &frame->uc.tuc_mcontext); - - if (do_sigaltstack(frame_addr + - offsetof(struct target_rt_sigframe, uc.tuc_stack), - 0, get_sp_from_cpustate(regs)) == -EFAULT) { - goto badframe; - } + target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(regs)); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c index 590f0313ff..22ec6cdeb9 100644 --- a/linux-user/xtensa/signal.c +++ b/linux-user/xtensa/signal.c @@ -253,12 +253,8 @@ long do_rt_sigreturn(CPUXtensaState *env) set_sigmask(&set); restore_sigcontext(env, frame); + target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); - if (do_sigaltstack(frame_addr + - offsetof(struct target_rt_sigframe, uc.tuc_stack), - 0, get_sp_from_cpustate(env)) == -TARGET_EFAULT) { - goto badframe; - } unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; From 6b2087550345e87320f777c4db8254323d0d4123 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:12 -0700 Subject: [PATCH 0592/3028] linux-user: Pass CPUArchState to do_sigaltstack Now that we have exactly one call, it's easy to pass in env instead of passing in the sp value. Use target_save_altstack, which required env. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-4-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/qemu.h | 3 ++- linux-user/signal.c | 11 ++++------- linux-user/syscall.c | 3 +-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 74e06e7121..3b0b6b75fe 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -432,7 +432,8 @@ int target_to_host_signal(int sig); int host_to_target_signal(int sig); long do_sigreturn(CPUArchState *env); long do_rt_sigreturn(CPUArchState *env); -abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp); +abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, + CPUArchState *env); int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset); abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx, abi_ulong unew_ctx, abi_long ctx_size); diff --git a/linux-user/signal.c b/linux-user/signal.c index 9daa89eac5..2e1095055b 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -800,21 +800,18 @@ static void host_signal_handler(int host_signum, siginfo_t *info, /* do_sigaltstack() returns target values and errnos. */ /* compare linux/kernel/signal.c:do_sigaltstack() */ -abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) +abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, + CPUArchState *env) { target_stack_t oss, *uoss = NULL; abi_long ret = -TARGET_EFAULT; if (uoss_addr) { - TaskState *ts = (TaskState *)thread_cpu->opaque; - /* Verify writability now, but do not alter user memory yet. */ if (!lock_user_struct(VERIFY_WRITE, uoss, uoss_addr, 0)) { goto out; } - __put_user(ts->sigaltstack_used.ss_sp, &oss.ss_sp); - __put_user(ts->sigaltstack_used.ss_size, &oss.ss_size); - __put_user(sas_ss_flags(sp), &oss.ss_flags); + target_save_altstack(&oss, env); } if (uss_addr) { @@ -823,7 +820,7 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) { goto out; } - ret = target_restore_altstack(uss, sp); + ret = target_restore_altstack(uss, get_sp_from_cpustate(env)); if (ret) { goto out; } diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 95d79ddc43..4d52b2cfe3 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11195,8 +11195,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, return ret; } case TARGET_NR_sigaltstack: - return do_sigaltstack(arg1, arg2, - get_sp_from_cpustate((CPUArchState *)cpu_env)); + return do_sigaltstack(arg1, arg2, cpu_env); #ifdef CONFIG_SENDFILE #ifdef TARGET_NR_sendfile From ddc3e74d9c5ac76562ce8abe9e5908c4ff7cb8f0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:13 -0700 Subject: [PATCH 0593/3028] linux-user: Pass CPUArchState to target_restore_altstack In most cases we were already passing get_sp_from_cpustate directly to the function. In other cases, we were passing a local variable which already contained the same value. In the rest of the cases, we were passing the stack pointer out of env directly. Reviewed by: Warner Losh Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-5-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/aarch64/signal.c | 2 +- linux-user/alpha/signal.c | 2 +- linux-user/arm/signal.c | 4 ++-- linux-user/hexagon/signal.c | 2 +- linux-user/hppa/signal.c | 2 +- linux-user/i386/signal.c | 2 +- linux-user/m68k/signal.c | 2 +- linux-user/microblaze/signal.c | 2 +- linux-user/mips/signal.c | 2 +- linux-user/nios2/signal.c | 2 +- linux-user/openrisc/signal.c | 2 +- linux-user/ppc/signal.c | 2 +- linux-user/riscv/signal.c | 2 +- linux-user/s390x/signal.c | 2 +- linux-user/sh4/signal.c | 2 +- linux-user/signal-common.h | 2 +- linux-user/signal.c | 6 +++--- linux-user/xtensa/signal.c | 2 +- 18 files changed, 21 insertions(+), 21 deletions(-) diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c index 2a1b7dbcdc..662bcd1c4e 100644 --- a/linux-user/aarch64/signal.c +++ b/linux-user/aarch64/signal.c @@ -561,7 +561,7 @@ long do_rt_sigreturn(CPUARMState *env) goto badframe; } - target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/alpha/signal.c b/linux-user/alpha/signal.c index 0af0227118..d4e4666874 100644 --- a/linux-user/alpha/signal.c +++ b/linux-user/alpha/signal.c @@ -257,7 +257,7 @@ long do_rt_sigreturn(CPUAlphaState *env) set_sigmask(&set); restore_sigcontext(env, &frame->uc.tuc_mcontext); - target_restore_altstack(&frame->uc.tuc_stack, env->ir[IR_SP]); + target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/arm/signal.c b/linux-user/arm/signal.c index b7a772302f..32b68ee302 100644 --- a/linux-user/arm/signal.c +++ b/linux-user/arm/signal.c @@ -685,7 +685,7 @@ static int do_sigframe_return_v2(CPUARMState *env, } } - target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&uc->tuc_stack, env); #if 0 /* Send SIGTRAP if we're single-stepping */ @@ -769,7 +769,7 @@ static long do_rt_sigreturn_v1(CPUARMState *env) goto badframe; } - target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&frame->uc.tuc_stack, env); #if 0 /* Send SIGTRAP if we're single-stepping */ diff --git a/linux-user/hexagon/signal.c b/linux-user/hexagon/signal.c index 3854eb4709..85eab5e943 100644 --- a/linux-user/hexagon/signal.c +++ b/linux-user/hexagon/signal.c @@ -260,7 +260,7 @@ long do_rt_sigreturn(CPUHexagonState *env) } restore_ucontext(env, &frame->uc); - target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&frame->uc.uc_stack, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/hppa/signal.c b/linux-user/hppa/signal.c index 578874cf27..0e266f472d 100644 --- a/linux-user/hppa/signal.c +++ b/linux-user/hppa/signal.c @@ -187,7 +187,7 @@ long do_rt_sigreturn(CPUArchState *env) set_sigmask(&set); restore_sigcontext(env, &frame->uc.tuc_mcontext); - target_restore_altstack(&frame->uc.tuc_stack, env->gr[30]); + target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 3a0a1546a6..8701774e37 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -581,7 +581,7 @@ long do_rt_sigreturn(CPUX86State *env) goto badframe; } - target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/m68k/signal.c b/linux-user/m68k/signal.c index 004b59fb61..d06230655e 100644 --- a/linux-user/m68k/signal.c +++ b/linux-user/m68k/signal.c @@ -400,7 +400,7 @@ long do_rt_sigreturn(CPUM68KState *env) if (target_rt_restore_ucontext(env, &frame->uc)) goto badframe; - target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/microblaze/signal.c b/linux-user/microblaze/signal.c index f59a1faf47..4c483bd8c6 100644 --- a/linux-user/microblaze/signal.c +++ b/linux-user/microblaze/signal.c @@ -209,7 +209,7 @@ long do_rt_sigreturn(CPUMBState *env) restore_sigcontext(&frame->uc.tuc_mcontext, env); - target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c index 456fa64f41..e6be807a81 100644 --- a/linux-user/mips/signal.c +++ b/linux-user/mips/signal.c @@ -368,7 +368,7 @@ long do_rt_sigreturn(CPUMIPSState *env) set_sigmask(&blocked); restore_sigcontext(env, &frame->rs_uc.tuc_mcontext); - target_restore_altstack(&frame->rs_uc.tuc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&frame->rs_uc.tuc_stack, env); env->active_tc.PC = env->CP0_EPC; mips_set_hflags_isa_mode_from_pc(env); diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c index 751ea88811..cc3872f11d 100644 --- a/linux-user/nios2/signal.c +++ b/linux-user/nios2/signal.c @@ -128,7 +128,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc, __get_user(env->regs[R_RA], &gregs[23]); __get_user(env->regs[R_SP], &gregs[28]); - target_restore_altstack(&uc->tuc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&uc->tuc_stack, env); *pr2 = env->regs[2]; return 0; diff --git a/linux-user/openrisc/signal.c b/linux-user/openrisc/signal.c index 86f94d7f76..5c5640a284 100644 --- a/linux-user/openrisc/signal.c +++ b/linux-user/openrisc/signal.c @@ -158,7 +158,7 @@ long do_rt_sigreturn(CPUOpenRISCState *env) set_sigmask(&set); restore_sigcontext(env, &frame->uc.tuc_mcontext); - target_restore_altstack(&frame->uc.tuc_stack, frame_addr); + target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); return cpu_get_gpr(env, 11); diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index b44d5ce73c..edfad28a37 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -655,7 +655,7 @@ long do_rt_sigreturn(CPUPPCState *env) if (do_setcontext(&rt_sf->uc, env, 1)) goto sigsegv; - target_restore_altstack(&rt_sf->uc.tuc_stack, env->gpr[1]); + target_restore_altstack(&rt_sf->uc.tuc_stack, env); unlock_user_struct(rt_sf, rt_sf_addr, 1); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/riscv/signal.c b/linux-user/riscv/signal.c index 81d1129da3..9405c7fd9a 100644 --- a/linux-user/riscv/signal.c +++ b/linux-user/riscv/signal.c @@ -192,7 +192,7 @@ long do_rt_sigreturn(CPURISCVState *env) } restore_ucontext(env, &frame->uc); - target_restore_altstack(&frame->uc.uc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&frame->uc.uc_stack, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 73806f5472..b68b44ae7e 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -307,7 +307,7 @@ long do_rt_sigreturn(CPUS390XState *env) goto badframe; } - target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index 684f18da58..0451e65806 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -323,7 +323,7 @@ long do_rt_sigreturn(CPUSH4State *regs) set_sigmask(&blocked); restore_sigcontext(regs, &frame->uc.tuc_mcontext); - target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(regs)); + target_restore_altstack(&frame->uc.tuc_stack, regs); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h index 34b963af9a..ea86328b28 100644 --- a/linux-user/signal-common.h +++ b/linux-user/signal-common.h @@ -24,7 +24,7 @@ int on_sig_stack(unsigned long sp); int sas_ss_flags(unsigned long sp); abi_ulong target_sigsp(abi_ulong sp, struct target_sigaction *ka); void target_save_altstack(target_stack_t *uss, CPUArchState *env); -abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp); +abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env); static inline void target_sigemptyset(target_sigset_t *set) { diff --git a/linux-user/signal.c b/linux-user/signal.c index 2e1095055b..cbd80b28cf 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -297,7 +297,7 @@ void target_save_altstack(target_stack_t *uss, CPUArchState *env) __put_user(ts->sigaltstack_used.ss_size, &uss->ss_size); } -abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp) +abi_long target_restore_altstack(target_stack_t *uss, CPUArchState *env) { TaskState *ts = (TaskState *)thread_cpu->opaque; size_t minstacksize = TARGET_MINSIGSTKSZ; @@ -315,7 +315,7 @@ abi_long target_restore_altstack(target_stack_t *uss, abi_ulong sp) __get_user(ss.ss_size, &uss->ss_size); __get_user(ss.ss_flags, &uss->ss_flags); - if (on_sig_stack(sp)) { + if (on_sig_stack(get_sp_from_cpustate(env))) { return -TARGET_EPERM; } @@ -820,7 +820,7 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) { goto out; } - ret = target_restore_altstack(uss, get_sp_from_cpustate(env)); + ret = target_restore_altstack(uss, env); if (ret) { goto out; } diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c index 22ec6cdeb9..72771e1294 100644 --- a/linux-user/xtensa/signal.c +++ b/linux-user/xtensa/signal.c @@ -253,7 +253,7 @@ long do_rt_sigreturn(CPUXtensaState *env) set_sigmask(&set); restore_sigcontext(env, frame); - target_restore_altstack(&frame->uc.tuc_stack, get_sp_from_cpustate(env)); + target_restore_altstack(&frame->uc.tuc_stack, env); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; From eb215f40c2b4cbb12e97197db5fb06bd73b8324e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:14 -0700 Subject: [PATCH 0594/3028] linux-user/sparc: Include TARGET_STACK_BIAS in get_sp_from_cpustate Move TARGET_STACK_BIAS from signal.c. Generic code cares about the logical stack pointer, not the physical one that has a bias applied for sparc64. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-6-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 2 -- linux-user/sparc/target_cpu.h | 9 ++++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index d27b7a3af7..76579093a8 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -394,8 +394,6 @@ struct target_reg_window { abi_ulong ins[8]; }; -#define TARGET_STACK_BIAS 2047 - /* {set, get}context() needed for 64-bit SparcLinux userland. */ void sparc64_set_context(CPUSPARCState *env) { diff --git a/linux-user/sparc/target_cpu.h b/linux-user/sparc/target_cpu.h index 1fa1011775..1f4bed50f4 100644 --- a/linux-user/sparc/target_cpu.h +++ b/linux-user/sparc/target_cpu.h @@ -20,6 +20,12 @@ #ifndef SPARC_TARGET_CPU_H #define SPARC_TARGET_CPU_H +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) +# define TARGET_STACK_BIAS 2047 +#else +# define TARGET_STACK_BIAS 0 +#endif + static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp, unsigned flags) { @@ -40,6 +46,7 @@ static inline void cpu_clone_regs_child(CPUSPARCState *env, target_ulong newsp, #endif /* ??? The kernel appears to copy one stack frame to the new stack. */ /* ??? The kernel force aligns the new stack. */ + /* Userspace provides a biased stack pointer value. */ env->regwptr[WREG_SP] = newsp; } @@ -77,7 +84,7 @@ static inline void cpu_set_tls(CPUSPARCState *env, target_ulong newtls) static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state) { - return state->regwptr[WREG_SP]; + return state->regwptr[WREG_SP] + TARGET_STACK_BIAS; } #endif From 089a2256eec34f56db88977bf5bf8d566c4f24ad Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:15 -0700 Subject: [PATCH 0595/3028] linux-user/sparc: Clean up init_thread Share code between sparc32 and sparc64, removing a bit of pointless difference wrt psr/tstate. Use sizeof(abi_ulong) for allocating initial register window. Use TARGET_STACK_BIAS. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-7-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index fc9c4f12be..ffc03d72f9 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -676,48 +676,25 @@ static uint32_t get_elf_hwcap2(void) #define ELF_CLASS ELFCLASS64 #define ELF_ARCH EM_SPARCV9 - -#define STACK_BIAS 2047 - -static inline void init_thread(struct target_pt_regs *regs, - struct image_info *infop) -{ -#ifndef TARGET_ABI32 - regs->tstate = 0; -#endif - regs->pc = infop->entry; - regs->npc = regs->pc + 4; - regs->y = 0; -#ifdef TARGET_ABI32 - regs->u_regs[14] = infop->start_stack - 16 * 4; -#else - if (personality(infop->personality) == PER_LINUX32) - regs->u_regs[14] = infop->start_stack - 16 * 4; - else - regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS; -#endif -} - #else #define ELF_START_MMAP 0x80000000 #define ELF_HWCAP (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | HWCAP_SPARC_SWAP \ | HWCAP_SPARC_MULDIV) - #define ELF_CLASS ELFCLASS32 #define ELF_ARCH EM_SPARC +#endif /* TARGET_SPARC64 */ static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { - regs->psr = 0; + /* Note that target_cpu_copy_regs does not read psr/tstate. */ regs->pc = infop->entry; regs->npc = regs->pc + 4; regs->y = 0; - regs->u_regs[14] = infop->start_stack - 16 * 4; + regs->u_regs[14] = (infop->start_stack - 16 * sizeof(abi_ulong) + - TARGET_STACK_BIAS); } - -#endif -#endif +#endif /* TARGET_SPARC */ #ifdef TARGET_PPC From 2f23eec6bd9e25d6d66a819a2bd7432f84dc101c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:16 -0700 Subject: [PATCH 0596/3028] linux-user/sparc: Merge sparc64 target_syscall.h There are only a few differences in sparc32 vs sparc64. This fixes target_shmlba for sparc32plus, which is v9. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-8-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/target_syscall.h | 42 +++++++++++++++++++++-------- linux-user/sparc64/target_syscall.h | 36 +------------------------ 2 files changed, 32 insertions(+), 46 deletions(-) diff --git a/linux-user/sparc/target_syscall.h b/linux-user/sparc/target_syscall.h index d8ea04ea83..15d531f389 100644 --- a/linux-user/sparc/target_syscall.h +++ b/linux-user/sparc/target_syscall.h @@ -3,18 +3,34 @@ #include "target_errno.h" +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) struct target_pt_regs { - abi_ulong psr; - abi_ulong pc; - abi_ulong npc; - abi_ulong y; - abi_ulong u_regs[16]; + abi_ulong u_regs[16]; + abi_ulong tstate; + abi_ulong pc; + abi_ulong npc; + uint32_t y; + uint32_t magic; }; +#else +struct target_pt_regs { + abi_ulong psr; + abi_ulong pc; + abi_ulong npc; + abi_ulong y; + abi_ulong u_regs[16]; +}; +#endif -#define UNAME_MACHINE "sparc" +#ifdef TARGET_SPARC64 +# define UNAME_MACHINE "sparc64" +#else +# define UNAME_MACHINE "sparc" +#endif #define UNAME_MINIMUM_RELEASE "2.6.32" -/* SPARC kernels don't define this in their Kconfig, but they have the +/* + * SPARC kernels don't define this in their Kconfig, but they have the * same ABI as if they did, implemented by sparc-specific code which fishes * directly in the u_regs() struct for half the parameters in sparc_do_fork() * and copy_thread(). @@ -25,20 +41,24 @@ struct target_pt_regs { #define TARGET_MCL_FUTURE 0x4000 #define TARGET_MCL_ONFAULT 0x8000 -/* For SPARC SHMLBA is determined at runtime in the kernel, and - * libc has to runtime-detect it using the hwcaps (see glibc - * sysdeps/unix/sysv/linux/sparc/getshmlba; we follow the same - * logic here, though we know we're not the sparc v9 64-bit case). +/* + * For SPARC SHMLBA is determined at runtime in the kernel, and + * libc has to runtime-detect it using the hwcaps. + * See glibc sysdeps/unix/sysv/linux/sparc/getshmlba. */ #define TARGET_FORCE_SHMLBA static inline abi_ulong target_shmlba(CPUSPARCState *env) { +#ifdef TARGET_SPARC64 + return MAX(TARGET_PAGE_SIZE, 16 * 1024); +#else if (!(env->def.features & CPU_FEATURE_FLUSH)) { return 64 * 1024; } else { return 256 * 1024; } +#endif } #endif /* SPARC_TARGET_SYSCALL_H */ diff --git a/linux-user/sparc64/target_syscall.h b/linux-user/sparc64/target_syscall.h index 696a68b1ed..164a5fc632 100644 --- a/linux-user/sparc64/target_syscall.h +++ b/linux-user/sparc64/target_syscall.h @@ -1,35 +1 @@ -#ifndef SPARC64_TARGET_SYSCALL_H -#define SPARC64_TARGET_SYSCALL_H - -#include "../sparc/target_errno.h" - -struct target_pt_regs { - abi_ulong u_regs[16]; - abi_ulong tstate; - abi_ulong pc; - abi_ulong npc; - abi_ulong y; - abi_ulong fprs; -}; - -#define UNAME_MACHINE "sparc64" -#define UNAME_MINIMUM_RELEASE "2.6.32" - -/* SPARC kernels don't define this in their Kconfig, but they have the - * same ABI as if they did, implemented by sparc-specific code which fishes - * directly in the u_regs() struct for half the parameters in sparc_do_fork() - * and copy_thread(). - */ -#define TARGET_CLONE_BACKWARDS -#define TARGET_MINSIGSTKSZ 4096 -#define TARGET_MCL_CURRENT 0x2000 -#define TARGET_MCL_FUTURE 0x4000 -#define TARGET_MCL_ONFAULT 0x8000 - -#define TARGET_FORCE_SHMLBA - -static inline abi_ulong target_shmlba(CPUSPARCState *env) -{ - return MAX(TARGET_PAGE_SIZE, 16 * 1024); -} -#endif /* SPARC64_TARGET_SYSCALL_H */ +#include "../sparc/target_syscall.h" From b136c211dadc8957b7e3cbb6de4031e3a69a2cfd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:17 -0700 Subject: [PATCH 0597/3028] linux-user/sparc: Merge sparc64 target_elf.h Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-9-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc64/target_elf.h | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/linux-user/sparc64/target_elf.h b/linux-user/sparc64/target_elf.h index d6e388f1cf..023b49b743 100644 --- a/linux-user/sparc64/target_elf.h +++ b/linux-user/sparc64/target_elf.h @@ -1,14 +1 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation, or (at your option) any - * later version. See the COPYING file in the top-level directory. - */ - -#ifndef SPARC64_TARGET_ELF_H -#define SPARC64_TARGET_ELF_H -static inline const char *cpu_get_model(uint32_t eflags) -{ - return "TI UltraSparc II"; -} -#endif +#include "../sparc/target_elf.h" From 6175783bfa2189f774f1ae8ccd0e6d19e5407e79 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:18 -0700 Subject: [PATCH 0598/3028] linux-user/sparc: Merge sparc64 target_structs.h Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-10-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/target_structs.h | 36 +++++++----------- linux-user/sparc64/target_structs.h | 59 +---------------------------- 2 files changed, 15 insertions(+), 80 deletions(-) diff --git a/linux-user/sparc/target_structs.h b/linux-user/sparc/target_structs.h index 9953540759..beeace8fb2 100644 --- a/linux-user/sparc/target_structs.h +++ b/linux-user/sparc/target_structs.h @@ -26,13 +26,10 @@ struct target_ipc_perm { abi_uint cuid; /* Creator's user ID. */ abi_uint cgid; /* Creator's group ID. */ #if TARGET_ABI_BITS == 32 - abi_ushort __pad1; - abi_ushort mode; /* Read/write permission. */ - abi_ushort __pad2; -#else - abi_ushort mode; - abi_ushort __pad1; + abi_ushort __pad0; #endif + abi_ushort mode; /* Read/write permission. */ + abi_ushort __pad1; abi_ushort __seq; /* Sequence number. */ uint64_t __unused1; uint64_t __unused2; @@ -40,22 +37,17 @@ struct target_ipc_perm { struct target_shmid_ds { struct target_ipc_perm shm_perm; /* operation permission struct */ -#if TARGET_ABI_BITS == 32 - abi_uint __pad1; -#endif - abi_ulong shm_atime; /* time of last shmat() */ -#if TARGET_ABI_BITS == 32 - abi_uint __pad2; -#endif - abi_ulong shm_dtime; /* time of last shmdt() */ -#if TARGET_ABI_BITS == 32 - abi_uint __pad3; -#endif - abi_ulong shm_ctime; /* time of last change by shmctl() */ - abi_long shm_segsz; /* size of segment in bytes */ - abi_ulong shm_cpid; /* pid of creator */ - abi_ulong shm_lpid; /* pid of last shmop */ - abi_long shm_nattch; /* number of current attaches */ + /* + * Note that sparc32 splits these into hi/lo parts. + * For simplicity in qemu, always use a 64-bit type. + */ + int64_t shm_atime; /* last attach time */ + int64_t shm_dtime; /* last detach time */ + int64_t shm_ctime; /* last change time */ + abi_ulong shm_segsz; /* size of segment in bytes */ + abi_int shm_cpid; /* pid of creator */ + abi_int shm_lpid; /* pid of last shmop */ + abi_ulong shm_nattch; /* number of current attaches */ abi_ulong __unused1; abi_ulong __unused2; }; diff --git a/linux-user/sparc64/target_structs.h b/linux-user/sparc64/target_structs.h index 4a8ed48df7..cbcbc4602a 100644 --- a/linux-user/sparc64/target_structs.h +++ b/linux-user/sparc64/target_structs.h @@ -1,58 +1 @@ -/* - * SPARC64 specific structures for linux-user - * - * Copyright (c) 2013 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ -#ifndef SPARC64_TARGET_STRUCTS_H -#define SPARC64_TARGET_STRUCTS_H - -struct target_ipc_perm { - abi_int __key; /* Key. */ - abi_uint uid; /* Owner's user ID. */ - abi_uint gid; /* Owner's group ID. */ - abi_uint cuid; /* Creator's user ID. */ - abi_uint cgid; /* Creator's group ID. */ - abi_ushort mode; /* Read/write permission. */ - abi_ushort __pad1; - abi_ushort __seq; /* Sequence number. */ - abi_ushort __pad2; - abi_ulong __unused1; - abi_ulong __unused2; -}; - -struct target_shmid_ds { - struct target_ipc_perm shm_perm; /* operation permission struct */ - abi_long shm_segsz; /* size of segment in bytes */ - abi_ulong shm_atime; /* time of last shmat() */ -#if TARGET_ABI_BITS == 32 - abi_ulong __unused1; -#endif - abi_ulong shm_dtime; /* time of last shmdt() */ -#if TARGET_ABI_BITS == 32 - abi_ulong __unused2; -#endif - abi_ulong shm_ctime; /* time of last change by shmctl() */ -#if TARGET_ABI_BITS == 32 - abi_ulong __unused3; -#endif - abi_int shm_cpid; /* pid of creator */ - abi_int shm_lpid; /* pid of last shmop */ - abi_ulong shm_nattch; /* number of current attaches */ - abi_ulong __unused4; - abi_ulong __unused5; -}; - -#endif +#include "../sparc/target_structs.h" From 0de9081b2369e372a6bdee5192102badad552bfb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:19 -0700 Subject: [PATCH 0599/3028] linux-user/sparc: Merge sparc64 termbits.h Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-11-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc64/termbits.h | 292 +--------------------------------- 1 file changed, 1 insertion(+), 291 deletions(-) diff --git a/linux-user/sparc64/termbits.h b/linux-user/sparc64/termbits.h index 1ab1e80db5..54ddfee3ba 100644 --- a/linux-user/sparc64/termbits.h +++ b/linux-user/sparc64/termbits.h @@ -1,291 +1 @@ -/* from asm/termbits.h */ - -#ifndef LINUX_USER_SPARC64_TERMBITS_H -#define LINUX_USER_SPARC64_TERMBITS_H - -#define TARGET_NCCS 19 - -typedef unsigned char target_cc_t; /* cc_t */ -typedef unsigned int target_speed_t; /* speed_t */ -typedef unsigned int target_tcflag_t; /* tcflag_t */ - -struct target_termios { - target_tcflag_t c_iflag; /* input mode flags */ - target_tcflag_t c_oflag; /* output mode flags */ - target_tcflag_t c_cflag; /* control mode flags */ - target_tcflag_t c_lflag; /* local mode flags */ - target_cc_t c_line; /* line discipline */ - target_cc_t c_cc[TARGET_NCCS]; /* control characters */ -}; - - -/* c_cc characters */ -#define TARGET_VINTR 0 -#define TARGET_VQUIT 1 -#define TARGET_VERASE 2 -#define TARGET_VKILL 3 -#define TARGET_VEOF 4 -#define TARGET_VEOL 5 -#define TARGET_VEOL2 6 -#define TARGET_VSWTC 7 -#define TARGET_VSTART 8 -#define TARGET_VSTOP 9 - -#define TARGET_VSUSP 10 -#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */ -#define TARGET_VREPRINT 12 -#define TARGET_VDISCARD 13 -#define TARGET_VWERASE 14 -#define TARGET_VLNEXT 15 - -/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is - * shared with eof/eol - */ -#define TARGET_VMIN TARGET_VEOF -#define TARGET_VTIME TARGET_VEOL - -/* c_iflag bits */ -#define TARGET_IGNBRK 0x00000001 -#define TARGET_BRKINT 0x00000002 -#define TARGET_IGNPAR 0x00000004 -#define TARGET_PARMRK 0x00000008 -#define TARGET_INPCK 0x00000010 -#define TARGET_ISTRIP 0x00000020 -#define TARGET_INLCR 0x00000040 -#define TARGET_IGNCR 0x00000080 -#define TARGET_ICRNL 0x00000100 -#define TARGET_IUCLC 0x00000200 -#define TARGET_IXON 0x00000400 -#define TARGET_IXANY 0x00000800 -#define TARGET_IXOFF 0x00001000 -#define TARGET_IMAXBEL 0x00002000 -#define TARGET_IUTF8 0x00004000 - -/* c_oflag bits */ -#define TARGET_OPOST 0x00000001 -#define TARGET_OLCUC 0x00000002 -#define TARGET_ONLCR 0x00000004 -#define TARGET_OCRNL 0x00000008 -#define TARGET_ONOCR 0x00000010 -#define TARGET_ONLRET 0x00000020 -#define TARGET_OFILL 0x00000040 -#define TARGET_OFDEL 0x00000080 -#define TARGET_NLDLY 0x00000100 -#define TARGET_NL0 0x00000000 -#define TARGET_NL1 0x00000100 -#define TARGET_CRDLY 0x00000600 -#define TARGET_CR0 0x00000000 -#define TARGET_CR1 0x00000200 -#define TARGET_CR2 0x00000400 -#define TARGET_CR3 0x00000600 -#define TARGET_TABDLY 0x00001800 -#define TARGET_TAB0 0x00000000 -#define TARGET_TAB1 0x00000800 -#define TARGET_TAB2 0x00001000 -#define TARGET_TAB3 0x00001800 -#define TARGET_XTABS 0x00001800 -#define TARGET_BSDLY 0x00002000 -#define TARGET_BS0 0x00000000 -#define TARGET_BS1 0x00002000 -#define TARGET_VTDLY 0x00004000 -#define TARGET_VT0 0x00000000 -#define TARGET_VT1 0x00004000 -#define TARGET_FFDLY 0x00008000 -#define TARGET_FF0 0x00000000 -#define TARGET_FF1 0x00008000 -#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */ -#define TARGET_WRAP 0x00020000 /* SUNOS specific */ - -/* c_cflag bit meaning */ -#define TARGET_CBAUD 0x0000100f -#define TARGET_B0 0x00000000 /* hang up */ -#define TARGET_B50 0x00000001 -#define TARGET_B75 0x00000002 -#define TARGET_B110 0x00000003 -#define TARGET_B134 0x00000004 -#define TARGET_B150 0x00000005 -#define TARGET_B200 0x00000006 -#define TARGET_B300 0x00000007 -#define TARGET_B600 0x00000008 -#define TARGET_B1200 0x00000009 -#define TARGET_B1800 0x0000000a -#define TARGET_B2400 0x0000000b -#define TARGET_B4800 0x0000000c -#define TARGET_B9600 0x0000000d -#define TARGET_B19200 0x0000000e -#define TARGET_B38400 0x0000000f -#define TARGET_EXTA B19200 -#define TARGET_EXTB B38400 -#define TARGET_CSIZE 0x00000030 -#define TARGET_CS5 0x00000000 -#define TARGET_CS6 0x00000010 -#define TARGET_CS7 0x00000020 -#define TARGET_CS8 0x00000030 -#define TARGET_CSTOPB 0x00000040 -#define TARGET_CREAD 0x00000080 -#define TARGET_PARENB 0x00000100 -#define TARGET_PARODD 0x00000200 -#define TARGET_HUPCL 0x00000400 -#define TARGET_CLOCAL 0x00000800 -#define TARGET_CBAUDEX 0x00001000 -/* We'll never see these speeds with the Zilogs, but for completeness... */ -#define TARGET_B57600 0x00001001 -#define TARGET_B115200 0x00001002 -#define TARGET_B230400 0x00001003 -#define TARGET_B460800 0x00001004 -/* This is what we can do with the Zilogs. */ -#define TARGET_B76800 0x00001005 -/* This is what we can do with the SAB82532. */ -#define TARGET_B153600 0x00001006 -#define TARGET_B307200 0x00001007 -#define TARGET_B614400 0x00001008 -#define TARGET_B921600 0x00001009 -/* And these are the rest... */ -#define TARGET_B500000 0x0000100a -#define TARGET_B576000 0x0000100b -#define TARGET_B1000000 0x0000100c -#define TARGET_B1152000 0x0000100d -#define TARGET_B1500000 0x0000100e -#define TARGET_B2000000 0x0000100f -/* These have totally bogus values and nobody uses them - so far. Later on we'd have to use say 0x10000x and - adjust CBAUD constant and drivers accordingly. -#define B2500000 0x00001010 -#define B3000000 0x00001011 -#define B3500000 0x00001012 -#define B4000000 0x00001013 */ -#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */ -#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */ -#define TARGET_CRTSCTS 0x80000000 /* flow control */ - -/* c_lflag bits */ -#define TARGET_ISIG 0x00000001 -#define TARGET_ICANON 0x00000002 -#define TARGET_XCASE 0x00000004 -#define TARGET_ECHO 0x00000008 -#define TARGET_ECHOE 0x00000010 -#define TARGET_ECHOK 0x00000020 -#define TARGET_ECHONL 0x00000040 -#define TARGET_NOFLSH 0x00000080 -#define TARGET_TOSTOP 0x00000100 -#define TARGET_ECHOCTL 0x00000200 -#define TARGET_ECHOPRT 0x00000400 -#define TARGET_ECHOKE 0x00000800 -#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */ -#define TARGET_FLUSHO 0x00002000 -#define TARGET_PENDIN 0x00004000 -#define TARGET_IEXTEN 0x00008000 -#define TARGET_EXTPROC 0x00010000 - -/* ioctls */ - -/* Big T */ -#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio) -#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio) -#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio) -#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio) -#define TARGET_TCSBRK TARGET_IO('T', 5) -#define TARGET_TCXONC TARGET_IO('T', 6) -#define TARGET_TCFLSH TARGET_IO('T', 7) -#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios) -#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios) -#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios) -#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios) - -/* Note that all the ioctls that are not available in Linux have a - * double underscore on the front to: a) avoid some programs to - * thing we support some ioctls under Linux (autoconfiguration stuff) - */ -/* Little t */ -#define TARGET_TIOCGETD TARGET_IOR('t', 0, int) -#define TARGET_TIOCSETD TARGET_IOW('t', 1, int) -//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */ -//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */ -//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */ -//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */ -//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */ -//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */ -#define TARGET_TIOCEXCL TARGET_IO('t', 13) -#define TARGET_TIOCNXCL TARGET_IO('t', 14) -//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */ -//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */ -//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */ -//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */ -//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */ -//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */ -//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */ -#define TARGET_TIOCCONS TARGET_IO('t', 36) -//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */ -//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */ -#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int) -#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int) -//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */ -#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) -#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) -//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */ -#define TARGET_TIOCMGET TARGET_IOR('t', 106, int) -#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int) -#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int) -#define TARGET_TIOCMSET TARGET_IOW('t', 109, int) -#define TARGET_TIOCSTART TARGET_IO('t', 110) -#define TARGET_TIOCSTOP TARGET_IO('t', 111) -#define TARGET_TIOCPKT TARGET_IOW('t', 112, int) -#define TARGET_TIOCNOTTY TARGET_IO('t', 113) -#define TARGET_TIOCSTI TARGET_IOW('t', 114, char) -#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) -//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */ -//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */ -/* 118 is the non-posix setpgrp tty ioctl */ -/* 119 is the non-posix getpgrp tty ioctl */ -//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */ -//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */ -#define TARGET_TIOCCBRK TARGET_IO('t', 122) -#define TARGET_TIOCSBRK TARGET_IO('t', 123) -//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */ -//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */ -//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */ -//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */ -//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */ -//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */ -#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int) -#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int) -#define TARGET_TIOCSCTTY TARGET_IO('t', 132) -#define TARGET_TIOCGSID TARGET_IOR('t', 133, int) -/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */ -#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */ -#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */ -#define TARGET_TIOCGPTPEER TARGET_IO('t', 137) /* Safely open the slave */ - -/* Little f */ -#define TARGET_FIOCLEX TARGET_IO('f', 1) -#define TARGET_FIONCLEX TARGET_IO('f', 2) -#define TARGET_FIOASYNC TARGET_IOW('f', 125, int) -#define TARGET_FIONBIO TARGET_IOW('f', 126, int) -#define TARGET_FIONREAD TARGET_IOR('f', 127, int) -#define TARGET_TIOCINQ TARGET_FIONREAD - -/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it - * someday. This is completely bogus, I know... - */ -//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */ -//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */ - -/* Linux specific, no SunOS equivalent. */ -#define TARGET_TIOCLINUX 0x541C -#define TARGET_TIOCGSERIAL 0x541E -#define TARGET_TIOCSSERIAL 0x541F -#define TARGET_TCSBRKP 0x5425 -#define TARGET_TIOCTTYGSTRUCT 0x5426 -#define TARGET_TIOCSERCONFIG 0x5453 -#define TARGET_TIOCSERGWILD 0x5454 -#define TARGET_TIOCSERSWILD 0x5455 -#define TARGET_TIOCGLCKTRMIOS 0x5456 -#define TARGET_TIOCSLCKTRMIOS 0x5457 -#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ -#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ -#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ -#define TARGET_TIOCMIWAIT 0x545C /* Wait input */ -#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */ - -#endif +#include "../sparc/termbits.h" From 921c16268dc599180390d73bd6432a03ccc5918f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:20 -0700 Subject: [PATCH 0600/3028] linux-user/sparc: Merge sparc64/ into sparc/ All of the source and header files already defer to sparc via #include. The syscall.tbl and syscallhdr.sh files could not do the same, but are identical. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-12-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- .../targets/sparc64-linux-user.mak | 1 + linux-user/meson.build | 1 - linux-user/sparc64/cpu_loop.c | 20 - linux-user/sparc64/meson.build | 5 - linux-user/sparc64/signal.c | 19 - linux-user/sparc64/sockbits.h | 1 - linux-user/sparc64/syscall.tbl | 487 ------------------ linux-user/sparc64/syscallhdr.sh | 32 -- linux-user/sparc64/target_cpu.h | 1 - linux-user/sparc64/target_elf.h | 1 - linux-user/sparc64/target_fcntl.h | 1 - linux-user/sparc64/target_signal.h | 1 - linux-user/sparc64/target_structs.h | 1 - linux-user/sparc64/target_syscall.h | 1 - linux-user/sparc64/termbits.h | 1 - 15 files changed, 1 insertion(+), 572 deletions(-) delete mode 100644 linux-user/sparc64/cpu_loop.c delete mode 100644 linux-user/sparc64/meson.build delete mode 100644 linux-user/sparc64/signal.c delete mode 100644 linux-user/sparc64/sockbits.h delete mode 100644 linux-user/sparc64/syscall.tbl delete mode 100644 linux-user/sparc64/syscallhdr.sh delete mode 100644 linux-user/sparc64/target_cpu.h delete mode 100644 linux-user/sparc64/target_elf.h delete mode 100644 linux-user/sparc64/target_fcntl.h delete mode 100644 linux-user/sparc64/target_signal.h delete mode 100644 linux-user/sparc64/target_structs.h delete mode 100644 linux-user/sparc64/target_syscall.h delete mode 100644 linux-user/sparc64/termbits.h diff --git a/default-configs/targets/sparc64-linux-user.mak b/default-configs/targets/sparc64-linux-user.mak index 846924201a..9d23ab4a26 100644 --- a/default-configs/targets/sparc64-linux-user.mak +++ b/default-configs/targets/sparc64-linux-user.mak @@ -1,5 +1,6 @@ TARGET_ARCH=sparc64 TARGET_BASE_ARCH=sparc +TARGET_ABI_DIR=sparc TARGET_SYSTBL_ABI=common,64 TARGET_SYSTBL=syscall.tbl TARGET_ALIGNED_ONLY=y diff --git a/linux-user/meson.build b/linux-user/meson.build index 7fe28d659e..9549f81682 100644 --- a/linux-user/meson.build +++ b/linux-user/meson.build @@ -32,7 +32,6 @@ subdir('mips') subdir('ppc') subdir('s390x') subdir('sh4') -subdir('sparc64') subdir('sparc') subdir('x86_64') subdir('xtensa') diff --git a/linux-user/sparc64/cpu_loop.c b/linux-user/sparc64/cpu_loop.c deleted file mode 100644 index 4fd44e1b1e..0000000000 --- a/linux-user/sparc64/cpu_loop.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * qemu user cpu loop - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include "../sparc/cpu_loop.c" diff --git a/linux-user/sparc64/meson.build b/linux-user/sparc64/meson.build deleted file mode 100644 index 9527a40ed4..0000000000 --- a/linux-user/sparc64/meson.build +++ /dev/null @@ -1,5 +0,0 @@ -syscall_nr_generators += { - 'sparc64': generator(sh, - arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ], - output: '@BASENAME@_nr.h') -} diff --git a/linux-user/sparc64/signal.c b/linux-user/sparc64/signal.c deleted file mode 100644 index 170ebac232..0000000000 --- a/linux-user/sparc64/signal.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Emulation of Linux signals - * - * Copyright (c) 2003 Fabrice Bellard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ -#include "../sparc/signal.c" diff --git a/linux-user/sparc64/sockbits.h b/linux-user/sparc64/sockbits.h deleted file mode 100644 index 658899e4d3..0000000000 --- a/linux-user/sparc64/sockbits.h +++ /dev/null @@ -1 +0,0 @@ -#include "../sparc/sockbits.h" diff --git a/linux-user/sparc64/syscall.tbl b/linux-user/sparc64/syscall.tbl deleted file mode 100644 index 4af114e84f..0000000000 --- a/linux-user/sparc64/syscall.tbl +++ /dev/null @@ -1,487 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note -# -# system call numbers and entry vectors for sparc -# -# The format is: -# -# -# The can be common, 64, or 32 for this file. -# -0 common restart_syscall sys_restart_syscall -1 32 exit sys_exit sparc_exit -1 64 exit sparc_exit -2 common fork sys_fork -3 common read sys_read -4 common write sys_write -5 common open sys_open compat_sys_open -6 common close sys_close -7 common wait4 sys_wait4 compat_sys_wait4 -8 common creat sys_creat -9 common link sys_link -10 common unlink sys_unlink -11 32 execv sunos_execv -11 64 execv sys_nis_syscall -12 common chdir sys_chdir -13 32 chown sys_chown16 -13 64 chown sys_chown -14 common mknod sys_mknod -15 common chmod sys_chmod -16 32 lchown sys_lchown16 -16 64 lchown sys_lchown -17 common brk sys_brk -18 common perfctr sys_nis_syscall -19 common lseek sys_lseek compat_sys_lseek -20 common getpid sys_getpid -21 common capget sys_capget -22 common capset sys_capset -23 32 setuid sys_setuid16 -23 64 setuid sys_setuid -24 32 getuid sys_getuid16 -24 64 getuid sys_getuid -25 common vmsplice sys_vmsplice compat_sys_vmsplice -26 common ptrace sys_ptrace compat_sys_ptrace -27 common alarm sys_alarm -28 common sigaltstack sys_sigaltstack compat_sys_sigaltstack -29 32 pause sys_pause -29 64 pause sys_nis_syscall -30 32 utime sys_utime32 -30 64 utime sys_utime -31 32 lchown32 sys_lchown -32 32 fchown32 sys_fchown -33 common access sys_access -34 common nice sys_nice -35 32 chown32 sys_chown -36 common sync sys_sync -37 common kill sys_kill -38 common stat sys_newstat compat_sys_newstat -39 32 sendfile sys_sendfile compat_sys_sendfile -39 64 sendfile sys_sendfile64 -40 common lstat sys_newlstat compat_sys_newlstat -41 common dup sys_dup -42 common pipe sys_sparc_pipe -43 common times sys_times compat_sys_times -44 32 getuid32 sys_getuid -45 common umount2 sys_umount -46 32 setgid sys_setgid16 -46 64 setgid sys_setgid -47 32 getgid sys_getgid16 -47 64 getgid sys_getgid -48 common signal sys_signal -49 32 geteuid sys_geteuid16 -49 64 geteuid sys_geteuid -50 32 getegid sys_getegid16 -50 64 getegid sys_getegid -51 common acct sys_acct -52 64 memory_ordering sys_memory_ordering -53 32 getgid32 sys_getgid -54 common ioctl sys_ioctl compat_sys_ioctl -55 common reboot sys_reboot -56 32 mmap2 sys_mmap2 sys32_mmap2 -57 common symlink sys_symlink -58 common readlink sys_readlink -59 32 execve sys_execve sys32_execve -59 64 execve sys64_execve -60 common umask sys_umask -61 common chroot sys_chroot -62 common fstat sys_newfstat compat_sys_newfstat -63 common fstat64 sys_fstat64 compat_sys_fstat64 -64 common getpagesize sys_getpagesize -65 common msync sys_msync -66 common vfork sys_vfork -67 common pread64 sys_pread64 compat_sys_pread64 -68 common pwrite64 sys_pwrite64 compat_sys_pwrite64 -69 32 geteuid32 sys_geteuid -70 32 getegid32 sys_getegid -71 common mmap sys_mmap -72 32 setreuid32 sys_setreuid -73 32 munmap sys_munmap -73 64 munmap sys_64_munmap -74 common mprotect sys_mprotect -75 common madvise sys_madvise -76 common vhangup sys_vhangup -77 32 truncate64 sys_truncate64 compat_sys_truncate64 -78 common mincore sys_mincore -79 32 getgroups sys_getgroups16 -79 64 getgroups sys_getgroups -80 32 setgroups sys_setgroups16 -80 64 setgroups sys_setgroups -81 common getpgrp sys_getpgrp -82 32 setgroups32 sys_setgroups -83 common setitimer sys_setitimer compat_sys_setitimer -84 32 ftruncate64 sys_ftruncate64 compat_sys_ftruncate64 -85 common swapon sys_swapon -86 common getitimer sys_getitimer compat_sys_getitimer -87 32 setuid32 sys_setuid -88 common sethostname sys_sethostname -89 32 setgid32 sys_setgid -90 common dup2 sys_dup2 -91 32 setfsuid32 sys_setfsuid -92 common fcntl sys_fcntl compat_sys_fcntl -93 common select sys_select -94 32 setfsgid32 sys_setfsgid -95 common fsync sys_fsync -96 common setpriority sys_setpriority -97 common socket sys_socket -98 common connect sys_connect -99 common accept sys_accept -100 common getpriority sys_getpriority -101 common rt_sigreturn sys_rt_sigreturn sys32_rt_sigreturn -102 common rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction -103 common rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask -104 common rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending -105 32 rt_sigtimedwait sys_rt_sigtimedwait_time32 compat_sys_rt_sigtimedwait_time32 -105 64 rt_sigtimedwait sys_rt_sigtimedwait -106 common rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo -107 common rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend -108 32 setresuid32 sys_setresuid -108 64 setresuid sys_setresuid -109 32 getresuid32 sys_getresuid -109 64 getresuid sys_getresuid -110 32 setresgid32 sys_setresgid -110 64 setresgid sys_setresgid -111 32 getresgid32 sys_getresgid -111 64 getresgid sys_getresgid -112 32 setregid32 sys_setregid -113 common recvmsg sys_recvmsg compat_sys_recvmsg -114 common sendmsg sys_sendmsg compat_sys_sendmsg -115 32 getgroups32 sys_getgroups -116 common gettimeofday sys_gettimeofday compat_sys_gettimeofday -117 common getrusage sys_getrusage compat_sys_getrusage -118 common getsockopt sys_getsockopt sys_getsockopt -119 common getcwd sys_getcwd -120 common readv sys_readv compat_sys_readv -121 common writev sys_writev compat_sys_writev -122 common settimeofday sys_settimeofday compat_sys_settimeofday -123 32 fchown sys_fchown16 -123 64 fchown sys_fchown -124 common fchmod sys_fchmod -125 common recvfrom sys_recvfrom -126 32 setreuid sys_setreuid16 -126 64 setreuid sys_setreuid -127 32 setregid sys_setregid16 -127 64 setregid sys_setregid -128 common rename sys_rename -129 common truncate sys_truncate compat_sys_truncate -130 common ftruncate sys_ftruncate compat_sys_ftruncate -131 common flock sys_flock -132 common lstat64 sys_lstat64 compat_sys_lstat64 -133 common sendto sys_sendto -134 common shutdown sys_shutdown -135 common socketpair sys_socketpair -136 common mkdir sys_mkdir -137 common rmdir sys_rmdir -138 32 utimes sys_utimes_time32 -138 64 utimes sys_utimes -139 common stat64 sys_stat64 compat_sys_stat64 -140 common sendfile64 sys_sendfile64 -141 common getpeername sys_getpeername -142 32 futex sys_futex_time32 -142 64 futex sys_futex -143 common gettid sys_gettid -144 common getrlimit sys_getrlimit compat_sys_getrlimit -145 common setrlimit sys_setrlimit compat_sys_setrlimit -146 common pivot_root sys_pivot_root -147 common prctl sys_prctl -148 common pciconfig_read sys_pciconfig_read -149 common pciconfig_write sys_pciconfig_write -150 common getsockname sys_getsockname -151 common inotify_init sys_inotify_init -152 common inotify_add_watch sys_inotify_add_watch -153 common poll sys_poll -154 common getdents64 sys_getdents64 -155 32 fcntl64 sys_fcntl64 compat_sys_fcntl64 -156 common inotify_rm_watch sys_inotify_rm_watch -157 common statfs sys_statfs compat_sys_statfs -158 common fstatfs sys_fstatfs compat_sys_fstatfs -159 common umount sys_oldumount -160 common sched_set_affinity sys_sched_setaffinity compat_sys_sched_setaffinity -161 common sched_get_affinity sys_sched_getaffinity compat_sys_sched_getaffinity -162 common getdomainname sys_getdomainname -163 common setdomainname sys_setdomainname -164 64 utrap_install sys_utrap_install -165 common quotactl sys_quotactl -166 common set_tid_address sys_set_tid_address -167 common mount sys_mount compat_sys_mount -168 common ustat sys_ustat compat_sys_ustat -169 common setxattr sys_setxattr -170 common lsetxattr sys_lsetxattr -171 common fsetxattr sys_fsetxattr -172 common getxattr sys_getxattr -173 common lgetxattr sys_lgetxattr -174 common getdents sys_getdents compat_sys_getdents -175 common setsid sys_setsid -176 common fchdir sys_fchdir -177 common fgetxattr sys_fgetxattr -178 common listxattr sys_listxattr -179 common llistxattr sys_llistxattr -180 common flistxattr sys_flistxattr -181 common removexattr sys_removexattr -182 common lremovexattr sys_lremovexattr -183 32 sigpending sys_sigpending compat_sys_sigpending -183 64 sigpending sys_nis_syscall -184 common query_module sys_ni_syscall -185 common setpgid sys_setpgid -186 common fremovexattr sys_fremovexattr -187 common tkill sys_tkill -188 32 exit_group sys_exit_group sparc_exit_group -188 64 exit_group sparc_exit_group -189 common uname sys_newuname -190 common init_module sys_init_module -191 32 personality sys_personality sys_sparc64_personality -191 64 personality sys_sparc64_personality -192 32 remap_file_pages sys_sparc_remap_file_pages sys_remap_file_pages -192 64 remap_file_pages sys_remap_file_pages -193 common epoll_create sys_epoll_create -194 common epoll_ctl sys_epoll_ctl -195 common epoll_wait sys_epoll_wait -196 common ioprio_set sys_ioprio_set -197 common getppid sys_getppid -198 32 sigaction sys_sparc_sigaction compat_sys_sparc_sigaction -198 64 sigaction sys_nis_syscall -199 common sgetmask sys_sgetmask -200 common ssetmask sys_ssetmask -201 32 sigsuspend sys_sigsuspend -201 64 sigsuspend sys_nis_syscall -202 common oldlstat sys_newlstat compat_sys_newlstat -203 common uselib sys_uselib -204 32 readdir sys_old_readdir compat_sys_old_readdir -204 64 readdir sys_nis_syscall -205 common readahead sys_readahead compat_sys_readahead -206 common socketcall sys_socketcall sys32_socketcall -207 common syslog sys_syslog -208 common lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie -209 common fadvise64 sys_fadvise64 compat_sys_fadvise64 -210 common fadvise64_64 sys_fadvise64_64 compat_sys_fadvise64_64 -211 common tgkill sys_tgkill -212 common waitpid sys_waitpid -213 common swapoff sys_swapoff -214 common sysinfo sys_sysinfo compat_sys_sysinfo -215 32 ipc sys_ipc compat_sys_ipc -215 64 ipc sys_sparc_ipc -216 32 sigreturn sys_sigreturn sys32_sigreturn -216 64 sigreturn sys_nis_syscall -217 common clone sys_clone -218 common ioprio_get sys_ioprio_get -219 32 adjtimex sys_adjtimex_time32 -219 64 adjtimex sys_sparc_adjtimex -220 32 sigprocmask sys_sigprocmask compat_sys_sigprocmask -220 64 sigprocmask sys_nis_syscall -221 common create_module sys_ni_syscall -222 common delete_module sys_delete_module -223 common get_kernel_syms sys_ni_syscall -224 common getpgid sys_getpgid -225 common bdflush sys_bdflush -226 common sysfs sys_sysfs -227 common afs_syscall sys_nis_syscall -228 common setfsuid sys_setfsuid16 -229 common setfsgid sys_setfsgid16 -230 common _newselect sys_select compat_sys_select -231 32 time sys_time32 -232 common splice sys_splice -233 32 stime sys_stime32 -233 64 stime sys_stime -234 common statfs64 sys_statfs64 compat_sys_statfs64 -235 common fstatfs64 sys_fstatfs64 compat_sys_fstatfs64 -236 common _llseek sys_llseek -237 common mlock sys_mlock -238 common munlock sys_munlock -239 common mlockall sys_mlockall -240 common munlockall sys_munlockall -241 common sched_setparam sys_sched_setparam -242 common sched_getparam sys_sched_getparam -243 common sched_setscheduler sys_sched_setscheduler -244 common sched_getscheduler sys_sched_getscheduler -245 common sched_yield sys_sched_yield -246 common sched_get_priority_max sys_sched_get_priority_max -247 common sched_get_priority_min sys_sched_get_priority_min -248 32 sched_rr_get_interval sys_sched_rr_get_interval_time32 -248 64 sched_rr_get_interval sys_sched_rr_get_interval -249 32 nanosleep sys_nanosleep_time32 -249 64 nanosleep sys_nanosleep -250 32 mremap sys_mremap -250 64 mremap sys_64_mremap -251 common _sysctl sys_ni_syscall -252 common getsid sys_getsid -253 common fdatasync sys_fdatasync -254 32 nfsservctl sys_ni_syscall sys_nis_syscall -254 64 nfsservctl sys_nis_syscall -255 common sync_file_range sys_sync_file_range compat_sys_sync_file_range -256 32 clock_settime sys_clock_settime32 -256 64 clock_settime sys_clock_settime -257 32 clock_gettime sys_clock_gettime32 -257 64 clock_gettime sys_clock_gettime -258 32 clock_getres sys_clock_getres_time32 -258 64 clock_getres sys_clock_getres -259 32 clock_nanosleep sys_clock_nanosleep_time32 -259 64 clock_nanosleep sys_clock_nanosleep -260 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity -261 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity -262 32 timer_settime sys_timer_settime32 -262 64 timer_settime sys_timer_settime -263 32 timer_gettime sys_timer_gettime32 -263 64 timer_gettime sys_timer_gettime -264 common timer_getoverrun sys_timer_getoverrun -265 common timer_delete sys_timer_delete -266 common timer_create sys_timer_create compat_sys_timer_create -# 267 was vserver -267 common vserver sys_nis_syscall -268 common io_setup sys_io_setup compat_sys_io_setup -269 common io_destroy sys_io_destroy -270 common io_submit sys_io_submit compat_sys_io_submit -271 common io_cancel sys_io_cancel -272 32 io_getevents sys_io_getevents_time32 -272 64 io_getevents sys_io_getevents -273 common mq_open sys_mq_open compat_sys_mq_open -274 common mq_unlink sys_mq_unlink -275 32 mq_timedsend sys_mq_timedsend_time32 -275 64 mq_timedsend sys_mq_timedsend -276 32 mq_timedreceive sys_mq_timedreceive_time32 -276 64 mq_timedreceive sys_mq_timedreceive -277 common mq_notify sys_mq_notify compat_sys_mq_notify -278 common mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr -279 common waitid sys_waitid compat_sys_waitid -280 common tee sys_tee -281 common add_key sys_add_key -282 common request_key sys_request_key -283 common keyctl sys_keyctl compat_sys_keyctl -284 common openat sys_openat compat_sys_openat -285 common mkdirat sys_mkdirat -286 common mknodat sys_mknodat -287 common fchownat sys_fchownat -288 32 futimesat sys_futimesat_time32 -288 64 futimesat sys_futimesat -289 common fstatat64 sys_fstatat64 compat_sys_fstatat64 -290 common unlinkat sys_unlinkat -291 common renameat sys_renameat -292 common linkat sys_linkat -293 common symlinkat sys_symlinkat -294 common readlinkat sys_readlinkat -295 common fchmodat sys_fchmodat -296 common faccessat sys_faccessat -297 32 pselect6 sys_pselect6_time32 compat_sys_pselect6_time32 -297 64 pselect6 sys_pselect6 -298 32 ppoll sys_ppoll_time32 compat_sys_ppoll_time32 -298 64 ppoll sys_ppoll -299 common unshare sys_unshare -300 common set_robust_list sys_set_robust_list compat_sys_set_robust_list -301 common get_robust_list sys_get_robust_list compat_sys_get_robust_list -302 common migrate_pages sys_migrate_pages compat_sys_migrate_pages -303 common mbind sys_mbind compat_sys_mbind -304 common get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy -305 common set_mempolicy sys_set_mempolicy compat_sys_set_mempolicy -306 common kexec_load sys_kexec_load compat_sys_kexec_load -307 common move_pages sys_move_pages compat_sys_move_pages -308 common getcpu sys_getcpu -309 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait -310 32 utimensat sys_utimensat_time32 -310 64 utimensat sys_utimensat -311 common signalfd sys_signalfd compat_sys_signalfd -312 common timerfd_create sys_timerfd_create -313 common eventfd sys_eventfd -314 common fallocate sys_fallocate compat_sys_fallocate -315 32 timerfd_settime sys_timerfd_settime32 -315 64 timerfd_settime sys_timerfd_settime -316 32 timerfd_gettime sys_timerfd_gettime32 -316 64 timerfd_gettime sys_timerfd_gettime -317 common signalfd4 sys_signalfd4 compat_sys_signalfd4 -318 common eventfd2 sys_eventfd2 -319 common epoll_create1 sys_epoll_create1 -320 common dup3 sys_dup3 -321 common pipe2 sys_pipe2 -322 common inotify_init1 sys_inotify_init1 -323 common accept4 sys_accept4 -324 common preadv sys_preadv compat_sys_preadv -325 common pwritev sys_pwritev compat_sys_pwritev -326 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo -327 common perf_event_open sys_perf_event_open -328 32 recvmmsg sys_recvmmsg_time32 compat_sys_recvmmsg_time32 -328 64 recvmmsg sys_recvmmsg -329 common fanotify_init sys_fanotify_init -330 common fanotify_mark sys_fanotify_mark compat_sys_fanotify_mark -331 common prlimit64 sys_prlimit64 -332 common name_to_handle_at sys_name_to_handle_at -333 common open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at -334 32 clock_adjtime sys_clock_adjtime32 -334 64 clock_adjtime sys_sparc_clock_adjtime -335 common syncfs sys_syncfs -336 common sendmmsg sys_sendmmsg compat_sys_sendmmsg -337 common setns sys_setns -338 common process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv -339 common process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev -340 32 kern_features sys_ni_syscall sys_kern_features -340 64 kern_features sys_kern_features -341 common kcmp sys_kcmp -342 common finit_module sys_finit_module -343 common sched_setattr sys_sched_setattr -344 common sched_getattr sys_sched_getattr -345 common renameat2 sys_renameat2 -346 common seccomp sys_seccomp -347 common getrandom sys_getrandom -348 common memfd_create sys_memfd_create -349 common bpf sys_bpf -350 32 execveat sys_execveat sys32_execveat -350 64 execveat sys64_execveat -351 common membarrier sys_membarrier -352 common userfaultfd sys_userfaultfd -353 common bind sys_bind -354 common listen sys_listen -355 common setsockopt sys_setsockopt sys_setsockopt -356 common mlock2 sys_mlock2 -357 common copy_file_range sys_copy_file_range -358 common preadv2 sys_preadv2 compat_sys_preadv2 -359 common pwritev2 sys_pwritev2 compat_sys_pwritev2 -360 common statx sys_statx -361 32 io_pgetevents sys_io_pgetevents_time32 compat_sys_io_pgetevents -361 64 io_pgetevents sys_io_pgetevents -362 common pkey_mprotect sys_pkey_mprotect -363 common pkey_alloc sys_pkey_alloc -364 common pkey_free sys_pkey_free -365 common rseq sys_rseq -# room for arch specific syscalls -392 64 semtimedop sys_semtimedop -393 common semget sys_semget -394 common semctl sys_semctl compat_sys_semctl -395 common shmget sys_shmget -396 common shmctl sys_shmctl compat_sys_shmctl -397 common shmat sys_shmat compat_sys_shmat -398 common shmdt sys_shmdt -399 common msgget sys_msgget -400 common msgsnd sys_msgsnd compat_sys_msgsnd -401 common msgrcv sys_msgrcv compat_sys_msgrcv -402 common msgctl sys_msgctl compat_sys_msgctl -403 32 clock_gettime64 sys_clock_gettime sys_clock_gettime -404 32 clock_settime64 sys_clock_settime sys_clock_settime -405 32 clock_adjtime64 sys_clock_adjtime sys_clock_adjtime -406 32 clock_getres_time64 sys_clock_getres sys_clock_getres -407 32 clock_nanosleep_time64 sys_clock_nanosleep sys_clock_nanosleep -408 32 timer_gettime64 sys_timer_gettime sys_timer_gettime -409 32 timer_settime64 sys_timer_settime sys_timer_settime -410 32 timerfd_gettime64 sys_timerfd_gettime sys_timerfd_gettime -411 32 timerfd_settime64 sys_timerfd_settime sys_timerfd_settime -412 32 utimensat_time64 sys_utimensat sys_utimensat -413 32 pselect6_time64 sys_pselect6 compat_sys_pselect6_time64 -414 32 ppoll_time64 sys_ppoll compat_sys_ppoll_time64 -416 32 io_pgetevents_time64 sys_io_pgetevents sys_io_pgetevents -417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64 -418 32 mq_timedsend_time64 sys_mq_timedsend sys_mq_timedsend -419 32 mq_timedreceive_time64 sys_mq_timedreceive sys_mq_timedreceive -420 32 semtimedop_time64 sys_semtimedop sys_semtimedop -421 32 rt_sigtimedwait_time64 sys_rt_sigtimedwait compat_sys_rt_sigtimedwait_time64 -422 32 futex_time64 sys_futex sys_futex -423 32 sched_rr_get_interval_time64 sys_sched_rr_get_interval sys_sched_rr_get_interval -424 common pidfd_send_signal sys_pidfd_send_signal -425 common io_uring_setup sys_io_uring_setup -426 common io_uring_enter sys_io_uring_enter -427 common io_uring_register sys_io_uring_register -428 common open_tree sys_open_tree -429 common move_mount sys_move_mount -430 common fsopen sys_fsopen -431 common fsconfig sys_fsconfig -432 common fsmount sys_fsmount -433 common fspick sys_fspick -434 common pidfd_open sys_pidfd_open -# 435 reserved for clone3 -436 common close_range sys_close_range -437 common openat2 sys_openat2 -438 common pidfd_getfd sys_pidfd_getfd -439 common faccessat2 sys_faccessat2 diff --git a/linux-user/sparc64/syscallhdr.sh b/linux-user/sparc64/syscallhdr.sh deleted file mode 100644 index 08c7e39bb3..0000000000 --- a/linux-user/sparc64/syscallhdr.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 - -in="$1" -out="$2" -my_abis=`echo "($3)" | tr ',' '|'` -prefix="$4" -offset="$5" - -fileguard=LINUX_USER_SPARC64_`basename "$out" | sed \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ - -e 's/[^A-Z0-9_]/_/g' -e 's/__/_/g'` -grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | ( - printf "#ifndef %s\n" "${fileguard}" - printf "#define %s\n" "${fileguard}" - printf "\n" - - nxt=0 - while read nr abi name entry compat ; do - if [ -z "$offset" ]; then - printf "#define TARGET_NR_%s%s\t%s\n" \ - "${prefix}" "${name}" "${nr}" - else - printf "#define TARGET_NR_%s%s\t(%s + %s)\n" \ - "${prefix}" "${name}" "${offset}" "${nr}" - fi - nxt=$((nr+1)) - done - - printf "\n" - printf "#endif /* %s */" "${fileguard}" -) > "$out" diff --git a/linux-user/sparc64/target_cpu.h b/linux-user/sparc64/target_cpu.h deleted file mode 100644 index b22263d2db..0000000000 --- a/linux-user/sparc64/target_cpu.h +++ /dev/null @@ -1 +0,0 @@ -#include "../sparc/target_cpu.h" diff --git a/linux-user/sparc64/target_elf.h b/linux-user/sparc64/target_elf.h deleted file mode 100644 index 023b49b743..0000000000 --- a/linux-user/sparc64/target_elf.h +++ /dev/null @@ -1 +0,0 @@ -#include "../sparc/target_elf.h" diff --git a/linux-user/sparc64/target_fcntl.h b/linux-user/sparc64/target_fcntl.h deleted file mode 100644 index 053c774257..0000000000 --- a/linux-user/sparc64/target_fcntl.h +++ /dev/null @@ -1 +0,0 @@ -#include "../sparc/target_fcntl.h" diff --git a/linux-user/sparc64/target_signal.h b/linux-user/sparc64/target_signal.h deleted file mode 100644 index 6a7d57d024..0000000000 --- a/linux-user/sparc64/target_signal.h +++ /dev/null @@ -1 +0,0 @@ -#include "../sparc/target_signal.h" diff --git a/linux-user/sparc64/target_structs.h b/linux-user/sparc64/target_structs.h deleted file mode 100644 index cbcbc4602a..0000000000 --- a/linux-user/sparc64/target_structs.h +++ /dev/null @@ -1 +0,0 @@ -#include "../sparc/target_structs.h" diff --git a/linux-user/sparc64/target_syscall.h b/linux-user/sparc64/target_syscall.h deleted file mode 100644 index 164a5fc632..0000000000 --- a/linux-user/sparc64/target_syscall.h +++ /dev/null @@ -1 +0,0 @@ -#include "../sparc/target_syscall.h" diff --git a/linux-user/sparc64/termbits.h b/linux-user/sparc64/termbits.h deleted file mode 100644 index 54ddfee3ba..0000000000 --- a/linux-user/sparc64/termbits.h +++ /dev/null @@ -1 +0,0 @@ -#include "../sparc/termbits.h" From 743f99e1176b175ff2698d0dc36b834c6cef7f24 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:21 -0700 Subject: [PATCH 0601/3028] linux-user/sparc: Remove target_sigcontext as unused Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-13-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 76579093a8..3d068e0955 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -21,34 +21,6 @@ #include "signal-common.h" #include "linux-user/trace.h" -#define __SUNOS_MAXWIN 31 - -/* This is what SunOS does, so shall I. */ -struct target_sigcontext { - abi_ulong sigc_onstack; /* state to restore */ - - abi_ulong sigc_mask; /* sigmask to restore */ - abi_ulong sigc_sp; /* stack pointer */ - abi_ulong sigc_pc; /* program counter */ - abi_ulong sigc_npc; /* next program counter */ - abi_ulong sigc_psr; /* for condition codes etc */ - abi_ulong sigc_g1; /* User uses these two registers */ - abi_ulong sigc_o0; /* within the trampoline code. */ - - /* Now comes information regarding the users window set - * at the time of the signal. - */ - abi_ulong sigc_oswins; /* outstanding windows */ - - /* stack ptrs for each regwin buf */ - char *sigc_spbuf[__SUNOS_MAXWIN]; - - /* Windows to restore after signal */ - struct { - abi_ulong locals[8]; - abi_ulong ins[8]; - } sigc_wbuf[__SUNOS_MAXWIN]; -}; /* A Sparc stack frame */ struct sparc_stackf { abi_ulong locals[8]; From 4f4fdec308d1b840d34056a0f100e14b317e1c44 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:22 -0700 Subject: [PATCH 0602/3028] linux-user/sparc: Remove target_rt_signal_frame as unused It's wrong anyway. Remove it for now. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-14-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 3d068e0955..29c5e3b0c0 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -64,17 +64,6 @@ struct target_signal_frame { abi_ulong extra_size; /* Should be 0 */ qemu_siginfo_fpu_t fpu_state; }; -struct target_rt_signal_frame { - struct sparc_stackf ss; - siginfo_t info; - abi_ulong regs[20]; - sigset_t mask; - abi_ulong fpu_save; - uint32_t insns[2]; - stack_t stack; - unsigned int extra_size; /* Should be 0 */ - qemu_siginfo_fpu_t fpu_state; -}; static inline abi_ulong get_sigframe(struct target_sigaction *sa, CPUSPARCState *env, From f8ea624e7456b10bee8e82b788885a438af8084d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:23 -0700 Subject: [PATCH 0603/3028] linux-user/sparc: Fix the stackframe structure Move target_reg_window up and use it. Fold structptr and xxargs into xargs -- the use of a host pointer was incorrect anyway. Rename the structure to target_stackf for consistency. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-15-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 29c5e3b0c0..3474098641 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -21,16 +21,26 @@ #include "signal-common.h" #include "linux-user/trace.h" -/* A Sparc stack frame */ -struct sparc_stackf { +/* A Sparc register window */ +struct target_reg_window { abi_ulong locals[8]; abi_ulong ins[8]; - /* It's simpler to treat fp and callers_pc as elements of ins[] - * since we never need to access them ourselves. - */ - char *structptr; - abi_ulong xargs[6]; - abi_ulong xxargs[1]; +}; + +/* A Sparc stack frame. */ +struct target_stackf { + /* + * Since qemu does not reference fp or callers_pc directly, + * it's simpler to treat fp and callers_pc as elements of ins[], + * and then bundle locals[] and ins[] into reg_window. + */ + struct target_reg_window win; + /* + * Similarly, bundle structptr and xxargs into xargs[]. + * This portion of the struct is part of the function call abi, + * and belongs to the callee for spilling argument registers. + */ + abi_ulong xargs[8]; }; typedef struct { @@ -56,7 +66,7 @@ typedef struct { struct target_signal_frame { - struct sparc_stackf ss; + struct target_stackf ss; __siginfo_t info; abi_ulong fpu_save; uint32_t insns[2] QEMU_ALIGNED(8); @@ -150,10 +160,10 @@ void setup_frame(int sig, struct target_sigaction *ka, } for (i = 0; i < 8; i++) { - __put_user(env->regwptr[i + WREG_L0], &sf->ss.locals[i]); + __put_user(env->regwptr[i + WREG_L0], &sf->ss.win.locals[i]); } for (i = 0; i < 8; i++) { - __put_user(env->regwptr[i + WREG_I0], &sf->ss.ins[i]); + __put_user(env->regwptr[i + WREG_I0], &sf->ss.win.ins[i]); } if (err) goto sigsegv; @@ -349,12 +359,6 @@ struct target_ucontext { target_mcontext_t tuc_mcontext; }; -/* A V9 register window */ -struct target_reg_window { - abi_ulong locals[8]; - abi_ulong ins[8]; -}; - /* {set, get}context() needed for 64-bit SparcLinux userland. */ void sparc64_set_context(CPUSPARCState *env) { From a1181d53a97dbed24b68fd04d700679cf9d6af65 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:24 -0700 Subject: [PATCH 0604/3028] linux-user/sparc: Use target_pt_regs Replace __siginfo_t with target_pt_regs, and move si_mask into target_signal_frame directly. Extract save/restore functions for target_pt_regs. Adjust for sparc64 tstate. Use proper get/put functions for psr. Turns out we were already writing to si_mask twice, so no need to handle that in the new functions. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-16-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 121 ++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 57 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 3474098641..0d9305818f 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -43,17 +43,6 @@ struct target_stackf { abi_ulong xargs[8]; }; -typedef struct { - struct { - abi_ulong psr; - abi_ulong pc; - abi_ulong npc; - abi_ulong y; - abi_ulong u_regs[16]; /* globals and ins */ - } si_regs; - int si_mask; -} __siginfo_t; - typedef struct { abi_ulong si_float_regs[32]; unsigned long si_fsr; @@ -67,7 +56,8 @@ typedef struct { struct target_signal_frame { struct target_stackf ss; - __siginfo_t info; + struct target_pt_regs regs; + uint32_t si_mask; abi_ulong fpu_save; uint32_t insns[2] QEMU_ALIGNED(8); abi_ulong extramask[TARGET_NSIG_WORDS - 1]; @@ -103,23 +93,61 @@ static inline abi_ulong get_sigframe(struct target_sigaction *sa, return sp; } -static int -setup___siginfo(__siginfo_t *si, CPUSPARCState *env, abi_ulong mask) +static void save_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env) { - int err = 0, i; + int i; - __put_user(env->psr, &si->si_regs.psr); - __put_user(env->pc, &si->si_regs.pc); - __put_user(env->npc, &si->si_regs.npc); - __put_user(env->y, &si->si_regs.y); - for (i=0; i < 8; i++) { - __put_user(env->gregs[i], &si->si_regs.u_regs[i]); +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) + __put_user(sparc64_tstate(env), ®s->tstate); + /* TODO: magic should contain PT_REG_MAGIC + %tt. */ + __put_user(0, ®s->magic); +#else + __put_user(cpu_get_psr(env), ®s->psr); +#endif + + __put_user(env->pc, ®s->pc); + __put_user(env->npc, ®s->npc); + __put_user(env->y, ®s->y); + + for (i = 0; i < 8; i++) { + __put_user(env->gregs[i], ®s->u_regs[i]); } - for (i=0; i < 8; i++) { - __put_user(env->regwptr[WREG_O0 + i], &si->si_regs.u_regs[i + 8]); + for (i = 0; i < 8; i++) { + __put_user(env->regwptr[WREG_O0 + i], ®s->u_regs[i + 8]); + } +} + +static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env) +{ + int i; + +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) + /* User can only change condition codes and %asi in %tstate. */ + uint64_t tstate; + __get_user(tstate, ®s->tstate); + cpu_put_ccr(env, tstate >> 32); + env->asi = extract64(tstate, 24, 8); +#else + /* + * User can only change condition codes and FPU enabling in %psr. + * But don't bother with FPU enabling, since a real kernel would + * just re-enable the FPU upon the next fpu trap. + */ + uint32_t psr; + __get_user(psr, ®s->psr); + env->psr = (psr & PSR_ICC) | (env->psr & ~PSR_ICC); +#endif + + /* Note that pc and npc are handled in the caller. */ + + __get_user(env->y, ®s->y); + + for (i = 0; i < 8; i++) { + __get_user(env->gregs[i], ®s->u_regs[i]); + } + for (i = 0; i < 8; i++) { + __get_user(env->regwptr[WREG_O0 + i], ®s->u_regs[i + 8]); } - __put_user(mask, &si->si_mask); - return err; } #define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) @@ -129,7 +157,7 @@ void setup_frame(int sig, struct target_sigaction *ka, { abi_ulong sf_addr; struct target_signal_frame *sf; - int sigframe_size, err, i; + int sigframe_size, i; /* 1. Make sure everything is clean */ //synchronize_user_stack(); @@ -143,18 +171,14 @@ void setup_frame(int sig, struct target_sigaction *ka, if (!sf) { goto sigsegv; } -#if 0 - if (invalid_frame_pointer(sf, sigframe_size)) - goto sigill_and_return; -#endif /* 2. Save the current process state */ - err = setup___siginfo(&sf->info, env, set->sig[0]); + save_pt_regs(&sf->regs, env); __put_user(0, &sf->extra_size); //save_fpu_state(regs, &sf->fpu_state); //__put_user(&sf->fpu_state, &sf->fpu_save); - __put_user(set->sig[0], &sf->info.si_mask); + __put_user(set->sig[0], &sf->si_mask); for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { __put_user(set->sig[i + 1], &sf->extramask[i]); } @@ -165,16 +189,14 @@ void setup_frame(int sig, struct target_sigaction *ka, for (i = 0; i < 8; i++) { __put_user(env->regwptr[i + WREG_I0], &sf->ss.win.ins[i]); } - if (err) - goto sigsegv; /* 3. signal handler back-trampoline and parameters */ env->regwptr[WREG_SP] = sf_addr; env->regwptr[WREG_O0] = sig; env->regwptr[WREG_O1] = sf_addr + - offsetof(struct target_signal_frame, info); + offsetof(struct target_signal_frame, regs); env->regwptr[WREG_O2] = sf_addr + - offsetof(struct target_signal_frame, info); + offsetof(struct target_signal_frame, regs); /* 4. signal handler */ env->pc = ka->_sa_handler; @@ -218,7 +240,7 @@ long do_sigreturn(CPUSPARCState *env) { abi_ulong sf_addr; struct target_signal_frame *sf; - abi_ulong up_psr, pc, npc; + abi_ulong pc, npc; target_sigset_t set; sigset_t host_set; int i; @@ -234,29 +256,17 @@ long do_sigreturn(CPUSPARCState *env) if (sf_addr & 3) goto segv_and_exit; - __get_user(pc, &sf->info.si_regs.pc); - __get_user(npc, &sf->info.si_regs.npc); + __get_user(pc, &sf->regs.pc); + __get_user(npc, &sf->regs.npc); if ((pc | npc) & 3) { goto segv_and_exit; } /* 2. Restore the state */ - __get_user(up_psr, &sf->info.si_regs.psr); - - /* User can only change condition codes and FPU enabling in %psr. */ - env->psr = (up_psr & (PSR_ICC /* | PSR_EF */)) - | (env->psr & ~(PSR_ICC /* | PSR_EF */)); - + restore_pt_regs(&sf->regs, env); env->pc = pc; env->npc = npc; - __get_user(env->y, &sf->info.si_regs.y); - for (i=0; i < 8; i++) { - __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]); - } - for (i=0; i < 8; i++) { - __get_user(env->regwptr[i + WREG_O0], &sf->info.si_regs.u_regs[i + 8]); - } /* FIXME: implement FPU save/restore: * __get_user(fpu_save, &sf->fpu_save); @@ -267,11 +277,8 @@ long do_sigreturn(CPUSPARCState *env) * } */ - /* This is pretty much atomic, no amount locking would prevent - * the races which exist anyways. - */ - __get_user(set.sig[0], &sf->info.si_mask); - for(i = 1; i < TARGET_NSIG_WORDS; i++) { + __get_user(set.sig[0], &sf->si_mask); + for (i = 1; i < TARGET_NSIG_WORDS; i++) { __get_user(set.sig[i], &sf->extramask[i - 1]); } From 44a5f861718caeb6f7b1ac7a6c279d32fc84041a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:25 -0700 Subject: [PATCH 0605/3028] linux-user/sparc: Split out save_reg_win Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-17-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 0d9305818f..69fee5a76a 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -150,6 +150,18 @@ static void restore_pt_regs(struct target_pt_regs *regs, CPUSPARCState *env) } } +static void save_reg_win(struct target_reg_window *win, CPUSPARCState *env) +{ + int i; + + for (i = 0; i < 8; i++) { + __put_user(env->regwptr[i + WREG_L0], &win->locals[i]); + } + for (i = 0; i < 8; i++) { + __put_user(env->regwptr[i + WREG_I0], &win->ins[i]); + } +} + #define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) void setup_frame(int sig, struct target_sigaction *ka, @@ -183,12 +195,7 @@ void setup_frame(int sig, struct target_sigaction *ka, __put_user(set->sig[i + 1], &sf->extramask[i]); } - for (i = 0; i < 8; i++) { - __put_user(env->regwptr[i + WREG_L0], &sf->ss.win.locals[i]); - } - for (i = 0; i < 8; i++) { - __put_user(env->regwptr[i + WREG_I0], &sf->ss.win.ins[i]); - } + save_reg_win(&sf->ss.win, env); /* 3. signal handler back-trampoline and parameters */ env->regwptr[WREG_SP] = sf_addr; From a0774ec4d4934b375a118a65104f658ef3b5b834 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:26 -0700 Subject: [PATCH 0606/3028] linux-user/sparc: Clean up get_sigframe Remove inline; fix spacing and comment format. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-18-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 69fee5a76a..57dbc72c99 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -65,24 +65,25 @@ struct target_signal_frame { qemu_siginfo_fpu_t fpu_state; }; -static inline abi_ulong get_sigframe(struct target_sigaction *sa, - CPUSPARCState *env, - unsigned long framesize) +static abi_ulong get_sigframe(struct target_sigaction *sa, + CPUSPARCState *env, + size_t framesize) { abi_ulong sp = get_sp_from_cpustate(env); /* * If we are on the alternate signal stack and would overflow it, don't. * Return an always-bogus address instead so we will die with SIGSEGV. - */ + */ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) { - return -1; + return -1; } /* This is the X/Open sanctioned signal stack switching. */ sp = target_sigsp(sp, sa) - framesize; - /* Always align the stack frame. This handles two cases. First, + /* + * Always align the stack frame. This handles two cases. First, * sigaltstack need not be mindful of platform specific stack * alignment. Second, if we took this signal because the stack * is not aligned properly, we'd like to take the signal cleanly From 71cda6e9128d3f47634ebc8cda7125d5039e43ac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:27 -0700 Subject: [PATCH 0607/3028] linux-user/sparc: Save and restore fpu in signal frame Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-19-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 84 ++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 57dbc72c99..59bb449512 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -43,26 +43,25 @@ struct target_stackf { abi_ulong xargs[8]; }; -typedef struct { - abi_ulong si_float_regs[32]; - unsigned long si_fsr; - unsigned long si_fpqdepth; +struct target_siginfo_fpu { + /* It is more convenient for qemu to move doubles, not singles. */ + uint64_t si_double_regs[16]; + uint32_t si_fsr; + uint32_t si_fpqdepth; struct { - unsigned long *insn_addr; - unsigned long insn; + uint32_t insn_addr; + uint32_t insn; } si_fpqueue [16]; -} qemu_siginfo_fpu_t; - +}; struct target_signal_frame { struct target_stackf ss; struct target_pt_regs regs; - uint32_t si_mask; - abi_ulong fpu_save; - uint32_t insns[2] QEMU_ALIGNED(8); - abi_ulong extramask[TARGET_NSIG_WORDS - 1]; - abi_ulong extra_size; /* Should be 0 */ - qemu_siginfo_fpu_t fpu_state; + uint32_t si_mask; + abi_ulong fpu_save; + uint32_t insns[2] QEMU_ALIGNED(8); + abi_ulong extramask[TARGET_NSIG_WORDS - 1]; + abi_ulong extra_size; /* Should be 0 */ }; static abi_ulong get_sigframe(struct target_sigaction *sa, @@ -163,33 +162,51 @@ static void save_reg_win(struct target_reg_window *win, CPUSPARCState *env) } } -#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7))) +static void save_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env) +{ + int i; + + for (i = 0; i < 16; ++i) { + __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]); + } + __put_user(env->fsr, &fpu->si_fsr); + __put_user(0, &fpu->si_fpqdepth); +} + +static void restore_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env) +{ + int i; + + for (i = 0; i < 16; ++i) { + __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]); + } + __get_user(env->fsr, &fpu->si_fsr); +} void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUSPARCState *env) { abi_ulong sf_addr; struct target_signal_frame *sf; - int sigframe_size, i; + size_t sf_size = sizeof(*sf) + sizeof(struct target_siginfo_fpu); + int i; /* 1. Make sure everything is clean */ - //synchronize_user_stack(); - sigframe_size = NF_ALIGNEDSZ; - sf_addr = get_sigframe(ka, env, sigframe_size); + sf_addr = get_sigframe(ka, env, sf_size); trace_user_setup_frame(env, sf_addr); - sf = lock_user(VERIFY_WRITE, sf_addr, - sizeof(struct target_signal_frame), 0); + sf = lock_user(VERIFY_WRITE, sf_addr, sf_size, 0); if (!sf) { goto sigsegv; } + /* 2. Save the current process state */ save_pt_regs(&sf->regs, env); __put_user(0, &sf->extra_size); - //save_fpu_state(regs, &sf->fpu_state); - //__put_user(&sf->fpu_state, &sf->fpu_save); + save_fpu((struct target_siginfo_fpu *)(sf + 1), env); + __put_user(sf_addr + sizeof(*sf), &sf->fpu_save); __put_user(set->sig[0], &sf->si_mask); for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { @@ -226,7 +243,7 @@ void setup_frame(int sig, struct target_sigaction *ka, val32 = 0x91d02010; __put_user(val32, &sf->insns[1]); } - unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); + unlock_user(sf, sf_addr, sf_size); return; #if 0 sigill_and_return: @@ -248,7 +265,7 @@ long do_sigreturn(CPUSPARCState *env) { abi_ulong sf_addr; struct target_signal_frame *sf; - abi_ulong pc, npc; + abi_ulong pc, npc, ptr; target_sigset_t set; sigset_t host_set; int i; @@ -276,14 +293,15 @@ long do_sigreturn(CPUSPARCState *env) env->pc = pc; env->npc = npc; - /* FIXME: implement FPU save/restore: - * __get_user(fpu_save, &sf->fpu_save); - * if (fpu_save) { - * if (restore_fpu_state(env, fpu_save)) { - * goto segv_and_exit; - * } - * } - */ + __get_user(ptr, &sf->fpu_save); + if (ptr) { + struct target_siginfo_fpu *fpu; + if ((ptr & 3) || !lock_user_struct(VERIFY_READ, fpu, ptr, 1)) { + goto segv_and_exit; + } + restore_fpu(fpu, env); + unlock_user_struct(fpu, ptr, 0); + } __get_user(set.sig[0], &sf->si_mask); for (i = 1; i < TARGET_NSIG_WORDS; i++) { From 819f6df1ef83385e59e182dc6223d1ad533d393c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:28 -0700 Subject: [PATCH 0608/3028] linux-user/sparc: Add rwin_save to signal frame Stub it out to zero, but at least include it. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-20-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 59bb449512..4a0578ebf3 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -62,6 +62,7 @@ struct target_signal_frame { uint32_t insns[2] QEMU_ALIGNED(8); abi_ulong extramask[TARGET_NSIG_WORDS - 1]; abi_ulong extra_size; /* Should be 0 */ + abi_ulong rwin_save; }; static abi_ulong get_sigframe(struct target_sigaction *sa, @@ -208,6 +209,8 @@ void setup_frame(int sig, struct target_sigaction *ka, save_fpu((struct target_siginfo_fpu *)(sf + 1), env); __put_user(sf_addr + sizeof(*sf), &sf->fpu_save); + __put_user(0, &sf->rwin_save); /* TODO: save_rwin_state */ + __put_user(set->sig[0], &sf->si_mask); for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) { __put_user(set->sig[i + 1], &sf->extramask[i]); @@ -303,6 +306,11 @@ long do_sigreturn(CPUSPARCState *env) unlock_user_struct(fpu, ptr, 0); } + __get_user(ptr, &sf->rwin_save); + if (ptr) { + goto segv_and_exit; /* TODO: restore_rwin */ + } + __get_user(set.sig[0], &sf->si_mask); for (i = 1; i < TARGET_NSIG_WORDS; i++) { __get_user(set.sig[i], &sf->extramask[i - 1]); From 757d260143488d1d0b4016020969ab28259b854b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:29 -0700 Subject: [PATCH 0609/3028] linux-user/sparc: Clean up setup_frame Clean up a goto label with a single use. Remove #if 0. Remove useless parentheses. Fold constants into __put_user. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-21-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 4a0578ebf3..f0f614a3af 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -192,14 +192,13 @@ void setup_frame(int sig, struct target_sigaction *ka, size_t sf_size = sizeof(*sf) + sizeof(struct target_siginfo_fpu); int i; - /* 1. Make sure everything is clean */ - sf_addr = get_sigframe(ka, env, sf_size); trace_user_setup_frame(env, sf_addr); sf = lock_user(VERIFY_WRITE, sf_addr, sf_size, 0); if (!sf) { - goto sigsegv; + force_sigsegv(sig); + return; } /* 2. Save the current process state */ @@ -228,33 +227,21 @@ void setup_frame(int sig, struct target_sigaction *ka, /* 4. signal handler */ env->pc = ka->_sa_handler; - env->npc = (env->pc + 4); + env->npc = env->pc + 4; + /* 5. return to kernel instructions */ if (ka->ka_restorer) { env->regwptr[WREG_O7] = ka->ka_restorer; } else { - uint32_t val32; - env->regwptr[WREG_O7] = sf_addr + offsetof(struct target_signal_frame, insns) - 2 * 4; /* mov __NR_sigreturn, %g1 */ - val32 = 0x821020d8; - __put_user(val32, &sf->insns[0]); - + __put_user(0x821020d8u, &sf->insns[0]); /* t 0x10 */ - val32 = 0x91d02010; - __put_user(val32, &sf->insns[1]); + __put_user(0x91d02010u, &sf->insns[1]); } unlock_user(sf, sf_addr, sf_size); - return; -#if 0 -sigill_and_return: - force_sig(TARGET_SIGILL); -#endif -sigsegv: - unlock_user(sf, sf_addr, sizeof(struct target_signal_frame)); - force_sigsegv(sig); } void setup_rt_frame(int sig, struct target_sigaction *ka, From 1176e57a8b34c845a89b2b0f86e424a825d40faa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:30 -0700 Subject: [PATCH 0610/3028] linux-user/sparc: Minor corrections to do_sigreturn Check that the input sp is 16 byte aligned, not 4. Do that before the lock_user_struct check. Validate the saved sp is 8 byte aligned. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-22-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index f0f614a3af..0ff57af43d 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -254,7 +254,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, long do_sigreturn(CPUSPARCState *env) { abi_ulong sf_addr; - struct target_signal_frame *sf; + struct target_signal_frame *sf = NULL; abi_ulong pc, npc, ptr; target_sigset_t set; sigset_t host_set; @@ -262,18 +262,21 @@ long do_sigreturn(CPUSPARCState *env) sf_addr = env->regwptr[WREG_SP]; trace_user_do_sigreturn(env, sf_addr); - if (!lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) { + + /* 1. Make sure we are not getting garbage from the user */ + if ((sf_addr & 15) || !lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) { goto segv_and_exit; } - /* 1. Make sure we are not getting garbage from the user */ - - if (sf_addr & 3) + /* Make sure stack pointer is aligned. */ + __get_user(ptr, &sf->regs.u_regs[14]); + if (ptr & 7) { goto segv_and_exit; + } - __get_user(pc, &sf->regs.pc); + /* Make sure instruction pointers are aligned. */ + __get_user(pc, &sf->regs.pc); __get_user(npc, &sf->regs.npc); - if ((pc | npc) & 3) { goto segv_and_exit; } @@ -309,7 +312,7 @@ long do_sigreturn(CPUSPARCState *env) unlock_user_struct(sf, sf_addr, 0); return -TARGET_QEMU_ESIGRETURN; -segv_and_exit: + segv_and_exit: unlock_user_struct(sf, sf_addr, 0); force_sig(TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; From 11670e849227890e7ab3f1413bae28bf6a0f6707 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:31 -0700 Subject: [PATCH 0611/3028] linux-user/sparc: Add 64-bit support to fpu save/restore The shape of the kernel's __siginfo_fpu_t is dependent on the cpu type, not the abi. Which is weird, but there ya go. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-23-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 0ff57af43d..41a8b33bac 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -44,6 +44,12 @@ struct target_stackf { }; struct target_siginfo_fpu { +#ifdef TARGET_SPARC64 + uint64_t si_double_regs[32]; + uint64_t si_fsr; + uint64_t si_gsr; + uint64_t si_fprs; +#else /* It is more convenient for qemu to move doubles, not singles. */ uint64_t si_double_regs[16]; uint32_t si_fsr; @@ -52,6 +58,7 @@ struct target_siginfo_fpu { uint32_t insn_addr; uint32_t insn; } si_fpqueue [16]; +#endif }; struct target_signal_frame { @@ -167,21 +174,50 @@ static void save_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env) { int i; +#ifdef TARGET_SPARC64 + for (i = 0; i < 32; ++i) { + __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]); + } + __put_user(env->fsr, &fpu->si_fsr); + __put_user(env->gsr, &fpu->si_gsr); + __put_user(env->fprs, &fpu->si_fprs); +#else for (i = 0; i < 16; ++i) { __put_user(env->fpr[i].ll, &fpu->si_double_regs[i]); } __put_user(env->fsr, &fpu->si_fsr); __put_user(0, &fpu->si_fpqdepth); +#endif } static void restore_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env) { int i; +#ifdef TARGET_SPARC64 + uint64_t fprs; + __get_user(fprs, &fpu->si_fprs); + + /* In case the user mucks about with FPRS, restore as directed. */ + if (fprs & FPRS_DL) { + for (i = 0; i < 16; ++i) { + __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]); + } + } + if (fprs & FPRS_DU) { + for (i = 16; i < 32; ++i) { + __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]); + } + } + __get_user(env->fsr, &fpu->si_fsr); + __get_user(env->gsr, &fpu->si_gsr); + env->fprs |= fprs; +#else for (i = 0; i < 16; ++i) { __get_user(env->fpr[i].ll, &fpu->si_double_regs[i]); } __get_user(env->fsr, &fpu->si_fsr); +#endif } void setup_frame(int sig, struct target_sigaction *ka, From e76f2f847d6e09e948ccb74657567535c5dfa398 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:32 -0700 Subject: [PATCH 0612/3028] linux-user/sparc: Implement sparc32 rt signals Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-24-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 126 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 4 deletions(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 41a8b33bac..362993da02 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -72,6 +72,18 @@ struct target_signal_frame { abi_ulong rwin_save; }; +struct target_rt_signal_frame { + struct target_stackf ss; + target_siginfo_t info; + struct target_pt_regs regs; + target_sigset_t mask; + abi_ulong fpu_save; + uint32_t insns[2]; + target_stack_t stack; + abi_ulong extra_size; /* Should be 0 */ + abi_ulong rwin_save; +}; + static abi_ulong get_sigframe(struct target_sigaction *sa, CPUSPARCState *env, size_t framesize) @@ -284,7 +296,59 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUSPARCState *env) { - qemu_log_mask(LOG_UNIMP, "setup_rt_frame: not implemented\n"); + abi_ulong sf_addr; + struct target_rt_signal_frame *sf; + size_t sf_size = sizeof(*sf) + sizeof(struct target_siginfo_fpu); + + sf_addr = get_sigframe(ka, env, sf_size); + trace_user_setup_rt_frame(env, sf_addr); + + sf = lock_user(VERIFY_WRITE, sf_addr, sf_size, 0); + if (!sf) { + force_sigsegv(sig); + return; + } + + /* 2. Save the current process state */ + save_reg_win(&sf->ss.win, env); + save_pt_regs(&sf->regs, env); + + save_fpu((struct target_siginfo_fpu *)(sf + 1), env); + __put_user(sf_addr + sizeof(*sf), &sf->fpu_save); + + __put_user(0, &sf->rwin_save); /* TODO: save_rwin_state */ + + tswap_siginfo(&sf->info, info); + tswap_sigset(&sf->mask, set); + target_save_altstack(&sf->stack, env); + + __put_user(0, &sf->extra_size); + + /* 3. signal handler back-trampoline and parameters */ + env->regwptr[WREG_SP] = sf_addr; + env->regwptr[WREG_O0] = sig; + env->regwptr[WREG_O1] = + sf_addr + offsetof(struct target_rt_signal_frame, info); + env->regwptr[WREG_O2] = + sf_addr + offsetof(struct target_rt_signal_frame, regs); + + /* 4. signal handler */ + env->pc = ka->_sa_handler; + env->npc = env->pc + 4; + + /* 5. return to kernel instructions */ + if (ka->ka_restorer) { + env->regwptr[WREG_O7] = ka->ka_restorer; + } else { + env->regwptr[WREG_O7] = + sf_addr + offsetof(struct target_rt_signal_frame, insns) - 2 * 4; + + /* mov __NR_rt_sigreturn, %g1 */ + __put_user(0x82102065u, &sf->insns[0]); + /* t 0x10 */ + __put_user(0x91d02010u, &sf->insns[1]); + } + unlock_user(sf, sf_addr, sf_size); } long do_sigreturn(CPUSPARCState *env) @@ -356,9 +420,63 @@ long do_sigreturn(CPUSPARCState *env) long do_rt_sigreturn(CPUSPARCState *env) { - trace_user_do_rt_sigreturn(env, 0); - qemu_log_mask(LOG_UNIMP, "do_rt_sigreturn: not implemented\n"); - return -TARGET_ENOSYS; + abi_ulong sf_addr, tpc, tnpc, ptr; + struct target_rt_signal_frame *sf = NULL; + sigset_t set; + + sf_addr = get_sp_from_cpustate(env); + trace_user_do_rt_sigreturn(env, sf_addr); + + /* 1. Make sure we are not getting garbage from the user */ + if ((sf_addr & 15) || !lock_user_struct(VERIFY_READ, sf, sf_addr, 1)) { + goto segv_and_exit; + } + + /* Validate SP alignment. */ + __get_user(ptr, &sf->regs.u_regs[8 + WREG_SP]); + if ((ptr + TARGET_STACK_BIAS) & 7) { + goto segv_and_exit; + } + + /* Validate PC and NPC alignment. */ + __get_user(tpc, &sf->regs.pc); + __get_user(tnpc, &sf->regs.npc); + if ((tpc | tnpc) & 3) { + goto segv_and_exit; + } + + /* 2. Restore the state */ + restore_pt_regs(&sf->regs, env); + + __get_user(ptr, &sf->fpu_save); + if (ptr) { + struct target_siginfo_fpu *fpu; + if ((ptr & 7) || !lock_user_struct(VERIFY_READ, fpu, ptr, 1)) { + goto segv_and_exit; + } + restore_fpu(fpu, env); + unlock_user_struct(fpu, ptr, 0); + } + + __get_user(ptr, &sf->rwin_save); + if (ptr) { + goto segv_and_exit; /* TODO: restore_rwin_state */ + } + + target_restore_altstack(&sf->stack, env); + target_to_host_sigset(&set, &sf->mask); + set_sigmask(&set); + + env->pc = tpc; + env->npc = tnpc; + + unlock_user_struct(sf, sf_addr, 0); + return -TARGET_QEMU_ESIGRETURN; + + segv_and_exit: + unlock_user_struct(sf, sf_addr, 0); + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) From bb3347f80f98df3935d7018a74a6dd777f2849fa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:33 -0700 Subject: [PATCH 0613/3028] linux-user/sparc: Implement sparc64 rt signals Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-25-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/sparc/signal.c | 27 ++++++++++++++++++++++++++- linux-user/sparc/target_signal.h | 2 ++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index 362993da02..0cc3db5570 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -61,6 +61,7 @@ struct target_siginfo_fpu { #endif }; +#ifdef TARGET_ARCH_HAS_SETUP_FRAME struct target_signal_frame { struct target_stackf ss; struct target_pt_regs regs; @@ -71,16 +72,23 @@ struct target_signal_frame { abi_ulong extra_size; /* Should be 0 */ abi_ulong rwin_save; }; +#endif struct target_rt_signal_frame { struct target_stackf ss; target_siginfo_t info; struct target_pt_regs regs; +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) + abi_ulong fpu_save; + target_stack_t stack; + target_sigset_t mask; +#else target_sigset_t mask; abi_ulong fpu_save; uint32_t insns[2]; target_stack_t stack; abi_ulong extra_size; /* Should be 0 */ +#endif abi_ulong rwin_save; }; @@ -232,6 +240,7 @@ static void restore_fpu(struct target_siginfo_fpu *fpu, CPUSPARCState *env) #endif } +#ifdef TARGET_ARCH_HAS_SETUP_FRAME void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUSPARCState *env) { @@ -291,6 +300,7 @@ void setup_frame(int sig, struct target_sigaction *ka, } unlock_user(sf, sf_addr, sf_size); } +#endif /* TARGET_ARCH_HAS_SETUP_FRAME */ void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, @@ -322,21 +332,28 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, tswap_sigset(&sf->mask, set); target_save_altstack(&sf->stack, env); +#ifdef TARGET_ABI32 __put_user(0, &sf->extra_size); +#endif /* 3. signal handler back-trampoline and parameters */ - env->regwptr[WREG_SP] = sf_addr; + env->regwptr[WREG_SP] = sf_addr - TARGET_STACK_BIAS; env->regwptr[WREG_O0] = sig; env->regwptr[WREG_O1] = sf_addr + offsetof(struct target_rt_signal_frame, info); +#ifdef TARGET_ABI32 env->regwptr[WREG_O2] = sf_addr + offsetof(struct target_rt_signal_frame, regs); +#else + env->regwptr[WREG_O2] = env->regwptr[WREG_O1]; +#endif /* 4. signal handler */ env->pc = ka->_sa_handler; env->npc = env->pc + 4; /* 5. return to kernel instructions */ +#ifdef TARGET_ABI32 if (ka->ka_restorer) { env->regwptr[WREG_O7] = ka->ka_restorer; } else { @@ -348,11 +365,16 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, /* t 0x10 */ __put_user(0x91d02010u, &sf->insns[1]); } +#else + env->regwptr[WREG_O7] = ka->ka_restorer; +#endif + unlock_user(sf, sf_addr, sf_size); } long do_sigreturn(CPUSPARCState *env) { +#ifdef TARGET_ARCH_HAS_SETUP_FRAME abi_ulong sf_addr; struct target_signal_frame *sf = NULL; abi_ulong pc, npc, ptr; @@ -416,6 +438,9 @@ long do_sigreturn(CPUSPARCState *env) unlock_user_struct(sf, sf_addr, 0); force_sig(TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; +#else + return -TARGET_ENOSYS; +#endif } long do_rt_sigreturn(CPUSPARCState *env) diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h index 911a3f5af5..34f9a12519 100644 --- a/linux-user/sparc/target_signal.h +++ b/linux-user/sparc/target_signal.h @@ -67,7 +67,9 @@ typedef struct target_sigaltstack { #define TARGET_MINSIGSTKSZ 4096 #define TARGET_SIGSTKSZ 16384 +#ifdef TARGET_ABI32 #define TARGET_ARCH_HAS_SETUP_FRAME +#endif /* bit-flags */ #define TARGET_SS_AUTODISARM (1U << 31) /* disable sas during sighandling */ From 4cce45df712650e494784415167a9e6a3f3d5136 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 Apr 2021 19:53:34 -0700 Subject: [PATCH 0614/3028] tests/tcg/sparc64: Re-enable linux-test It passes now that we support signals properly. Signed-off-by: Richard Henderson Message-Id: <20210426025334.1168495-26-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- tests/tcg/sparc64/Makefile.target | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/tcg/sparc64/Makefile.target b/tests/tcg/sparc64/Makefile.target index 5bd7f90583..408dace783 100644 --- a/tests/tcg/sparc64/Makefile.target +++ b/tests/tcg/sparc64/Makefile.target @@ -1,11 +1,6 @@ # -*- Mode: makefile -*- # -# sparc specific tweaks and masking out broken tests - -# different from the other hangs: -# tests/tcg/multiarch/linux-test.c:264: Value too large for defined data type (ret=-1, errno=92/Value too large for defined data type) -run-linux-test: linux-test - $(call skip-test, $<, "BROKEN") +# sparc specific tweaks # On Sparc64 Linux support 8k pages EXTRA_RUNS+=run-test-mmap-8192 From 5d79bd111ff4f9ed0b19c20f6708a770651a9048 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:33:54 -0700 Subject: [PATCH 0615/3028] linux-user/s390x: Fix sigframe types Noticed via gitlab clang-user job: TEST signals on s390x ../linux-user/s390x/signal.c:258:9: runtime error: \ 1.84467e+19 is outside the range of representable values of \ type 'unsigned long' Which points to the fact that we were performing a double-to-uint64_t conversion while storing the fp registers, instead of just copying the data across. Turns out there are several errors: target_ulong is the size of the target register, whereas abi_ulong is the target 'unsigned long' type. Not a big deal here, since we only support 64-bit s390x, but not correct either. In target_sigcontext and target ucontext, we used a host pointer instead of a target pointer, aka abi_ulong. Fixing this allows the removal of a cast to __put_user. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-2-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index b68b44ae7e..707fb603d7 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -37,13 +37,14 @@ typedef struct { target_psw_t psw; - target_ulong gprs[__NUM_GPRS]; - unsigned int acrs[__NUM_ACRS]; + abi_ulong gprs[__NUM_GPRS]; + abi_uint acrs[__NUM_ACRS]; } target_s390_regs_common; typedef struct { - unsigned int fpc; - double fprs[__NUM_FPRS]; + uint32_t fpc; + uint32_t pad; + uint64_t fprs[__NUM_FPRS]; } target_s390_fp_regs; typedef struct { @@ -51,22 +52,22 @@ typedef struct { target_s390_fp_regs fpregs; } target_sigregs; -struct target_sigcontext { - target_ulong oldmask[_SIGCONTEXT_NSIG_WORDS]; - target_sigregs *sregs; -}; +typedef struct { + abi_ulong oldmask[_SIGCONTEXT_NSIG_WORDS]; + abi_ulong sregs; +} target_sigcontext; typedef struct { uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; - struct target_sigcontext sc; + target_sigcontext sc; target_sigregs sregs; int signo; uint8_t retcode[S390_SYSCALL_SIZE]; } sigframe; struct target_ucontext { - target_ulong tuc_flags; - struct target_ucontext *tuc_link; + abi_ulong tuc_flags; + abi_ulong tuc_link; target_stack_t tuc_stack; target_sigregs tuc_mcontext; target_sigset_t tuc_sigmask; /* mask last for extensibility */ @@ -143,8 +144,7 @@ void setup_frame(int sig, struct target_sigaction *ka, save_sigregs(env, &frame->sregs); - __put_user((abi_ulong)(unsigned long)&frame->sregs, - (abi_ulong *)&frame->sc.sregs); + __put_user((abi_ulong)(unsigned long)&frame->sregs, &frame->sc.sregs); /* Set up to return from userspace. If provided, use a stub already in userspace. */ From cb1f198296dd9d7787328eab5beb2e31f550ba63 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:33:55 -0700 Subject: [PATCH 0616/3028] linux-user/s390x: Use uint16_t for signal retcode Using the right type simplifies the frame setup. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-3-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 707fb603d7..fece8ab97b 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -25,7 +25,6 @@ #define __NUM_FPRS 16 #define __NUM_ACRS 16 -#define S390_SYSCALL_SIZE 2 #define __SIGNAL_FRAMESIZE 160 /* FIXME: 31-bit mode -> 96 */ #define _SIGCONTEXT_NSIG 64 @@ -62,7 +61,7 @@ typedef struct { target_sigcontext sc; target_sigregs sregs; int signo; - uint8_t retcode[S390_SYSCALL_SIZE]; + uint16_t retcode; } sigframe; struct target_ucontext { @@ -75,7 +74,7 @@ struct target_ucontext { typedef struct { uint8_t callee_used_stack[__SIGNAL_FRAMESIZE]; - uint8_t retcode[S390_SYSCALL_SIZE]; + uint16_t retcode; struct target_siginfo info; struct target_ucontext uc; } rt_sigframe; @@ -155,7 +154,7 @@ void setup_frame(int sig, struct target_sigaction *ka, env->regs[14] = (frame_addr + offsetof(sigframe, retcode)) | PSW_ADDR_AMODE; __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, - (uint16_t *)(frame->retcode)); + &frame->retcode); } /* Set up backchain. */ @@ -216,7 +215,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, env->regs[14] = (frame_addr + offsetof(typeof(*frame), retcode)) | PSW_ADDR_AMODE; __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn, - (uint16_t *)(frame->retcode)); + &frame->retcode); } /* Set up backchain. */ From 915c69dc029e0fe509f8e4870993977068b66eaf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:33:56 -0700 Subject: [PATCH 0617/3028] linux-user/s390x: Remove PSW_ADDR_AMODE This is an unnecessary complication since we only support 64-bit mode. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-4-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index fece8ab97b..1dfca71fa9 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -31,7 +31,6 @@ #define _SIGCONTEXT_NSIG_BPW 64 /* FIXME: 31-bit mode -> 32 */ #define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW) #define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS) -#define PSW_ADDR_AMODE 0x0000000000000000UL /* 0x80000000UL for 31-bit */ #define S390_SYSCALL_OPCODE ((uint16_t)0x0a00) typedef struct { @@ -148,11 +147,9 @@ void setup_frame(int sig, struct target_sigaction *ka, /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa_flags & TARGET_SA_RESTORER) { - env->regs[14] = (unsigned long) - ka->sa_restorer | PSW_ADDR_AMODE; + env->regs[14] = ka->sa_restorer; } else { - env->regs[14] = (frame_addr + offsetof(sigframe, retcode)) - | PSW_ADDR_AMODE; + env->regs[14] = frame_addr + offsetof(sigframe, retcode); __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, &frame->retcode); } @@ -162,7 +159,7 @@ void setup_frame(int sig, struct target_sigaction *ka, /* Set up registers for signal handler */ env->regs[15] = frame_addr; - env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE; + env->psw.addr = ka->_sa_handler; env->regs[2] = sig; //map_signal(sig); env->regs[3] = frame_addr += offsetof(typeof(*frame), sc); @@ -210,10 +207,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa_flags & TARGET_SA_RESTORER) { - env->regs[14] = ka->sa_restorer | PSW_ADDR_AMODE; + env->regs[14] = ka->sa_restorer; } else { - env->regs[14] = (frame_addr + offsetof(typeof(*frame), retcode)) - | PSW_ADDR_AMODE; + env->regs[14] = frame_addr + offsetof(typeof(*frame), retcode); __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn, &frame->retcode); } @@ -223,7 +219,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, /* Set up registers for signal handler */ env->regs[15] = frame_addr; - env->psw.addr = (target_ulong) ka->_sa_handler | PSW_ADDR_AMODE; + env->psw.addr = ka->_sa_handler; env->regs[2] = sig; //map_signal(sig); env->regs[3] = frame_addr + offsetof(typeof(*frame), info); @@ -248,7 +244,6 @@ restore_sigregs(CPUS390XState *env, target_sigregs *sc) trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr, (unsigned long long)env->psw.addr); __get_user(env->psw.addr, &sc->regs.psw.addr); - /* FIXME: 31-bit -> | PSW_ADDR_AMODE */ for (i = 0; i < 16; i++) { __get_user(env->aregs[i], &sc->regs.acrs[i]); From e6f960fcbe0d2ecd72d7f7d10a2ed510701db35e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:33:57 -0700 Subject: [PATCH 0618/3028] linux-user/s390x: Remove restore_sigregs return value The function cannot fail. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-5-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 1dfca71fa9..e455a9818d 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -230,10 +230,8 @@ give_sigsegv: force_sigsegv(sig); } -static int -restore_sigregs(CPUS390XState *env, target_sigregs *sc) +static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) { - int err = 0; int i; for (i = 0; i < 16; i++) { @@ -251,8 +249,6 @@ restore_sigregs(CPUS390XState *env, target_sigregs *sc) for (i = 0; i < 16; i++) { __get_user(*get_freg(env, i), &sc->fpregs.fprs[i]); } - - return err; } long do_sigreturn(CPUS390XState *env) @@ -271,9 +267,7 @@ long do_sigreturn(CPUS390XState *env) target_to_host_sigset_internal(&set, &target_set); set_sigmask(&set); /* ~_BLOCKABLE? */ - if (restore_sigregs(env, &frame->sregs)) { - goto badframe; - } + restore_sigregs(env, &frame->sregs); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; @@ -297,9 +291,7 @@ long do_rt_sigreturn(CPUS390XState *env) set_sigmask(&set); /* ~_BLOCKABLE? */ - if (restore_sigregs(env, &frame->uc.tuc_mcontext)) { - goto badframe; - } + restore_sigregs(env, &frame->uc.tuc_mcontext); target_restore_altstack(&frame->uc.tuc_stack, env); From bd45be9f5ffcaae68d2d0de2962cdc9fa20cb832 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:33:58 -0700 Subject: [PATCH 0619/3028] linux-user/s390x: Fix trace in restore_regs Directly reading sc->regs.psw.addr misses the bswap that may be performed by __get_user. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-6-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index e455a9818d..dcc6f7bc02 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -232,16 +232,17 @@ give_sigsegv: static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) { + target_ulong prev_addr; int i; for (i = 0; i < 16; i++) { __get_user(env->regs[i], &sc->regs.gprs[i]); } + prev_addr = env->psw.addr; __get_user(env->psw.mask, &sc->regs.psw.mask); - trace_user_s390x_restore_sigregs(env, (unsigned long long)sc->regs.psw.addr, - (unsigned long long)env->psw.addr); __get_user(env->psw.addr, &sc->regs.psw.addr); + trace_user_s390x_restore_sigregs(env, env->psw.addr, prev_addr); for (i = 0; i < 16; i++) { __get_user(env->aregs[i], &sc->regs.acrs[i]); From 4e4a08200b6ed60055c45a0f05f4515365785a92 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:33:59 -0700 Subject: [PATCH 0620/3028] linux-user/s390x: Fix sigcontext sregs value Using the host address of &frame->sregs is incorrect. We need the guest address. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-7-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index dcc6f7bc02..f8515dd332 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -142,7 +142,7 @@ void setup_frame(int sig, struct target_sigaction *ka, save_sigregs(env, &frame->sregs); - __put_user((abi_ulong)(unsigned long)&frame->sregs, &frame->sc.sregs); + __put_user(frame_addr + offsetof(sigframe, sregs), &frame->sc.sregs); /* Set up to return from userspace. If provided, use a stub already in userspace. */ From bb17fc5b47af674ee429d4fca95485f9211aef4d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:34:00 -0700 Subject: [PATCH 0621/3028] linux-user/s390x: Use tswap_sigset in setup_rt_frame Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-8-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index f8515dd332..4dde55d4d5 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -182,7 +182,6 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, target_siginfo_t *info, target_sigset_t *set, CPUS390XState *env) { - int i; rt_sigframe *frame; abi_ulong frame_addr; @@ -199,10 +198,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link); target_save_altstack(&frame->uc.tuc_stack, env); save_sigregs(env, &frame->uc.tuc_mcontext); - for (i = 0; i < TARGET_NSIG_WORDS; i++) { - __put_user((abi_ulong)set->sig[i], - (abi_ulong *)&frame->uc.tuc_sigmask.sig[i]); - } + tswap_sigset(&frame->uc.tuc_sigmask, set); /* Set up to return from userspace. If provided, use a stub already in userspace. */ From 82839490e458a7e5022d6a0137c2a6a3eee0e9fc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:34:01 -0700 Subject: [PATCH 0622/3028] linux-user/s390x: Tidy save_sigregs The "save" routines copied from the kernel, which are currently commented out, are unnecessary in qemu. We can copy from env where the kernel needs special instructions. Fix comment style. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-9-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 4dde55d4d5..eabfe4293f 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -104,23 +104,25 @@ get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size) static void save_sigregs(CPUS390XState *env, target_sigregs *sregs) { int i; - //save_access_regs(current->thread.acrs); FIXME - /* Copy a 'clean' PSW mask to the user to avoid leaking - information about whether PER is currently on. */ + /* + * Copy a 'clean' PSW mask to the user to avoid leaking + * information about whether PER is currently on. + */ __put_user(env->psw.mask, &sregs->regs.psw.mask); __put_user(env->psw.addr, &sregs->regs.psw.addr); + for (i = 0; i < 16; i++) { __put_user(env->regs[i], &sregs->regs.gprs[i]); } for (i = 0; i < 16; i++) { __put_user(env->aregs[i], &sregs->regs.acrs[i]); } + /* * We have to store the fp registers to current->thread.fp_regs * to merge them with the emulated registers. */ - //save_fp_regs(¤t->thread.fp_regs); FIXME for (i = 0; i < 16; i++) { __put_user(*get_freg(env, i), &sregs->fpregs.fprs[i]); } From 20807348806e12141347d87badd34e358971e7d5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:34:02 -0700 Subject: [PATCH 0623/3028] linux-user/s390x: Clean up single-use gotos in signal.c Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-10-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index eabfe4293f..64a9eab097 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -137,7 +137,8 @@ void setup_frame(int sig, struct target_sigaction *ka, frame_addr = get_sigframe(ka, env, sizeof(*frame)); trace_user_setup_frame(env, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { - goto give_sigsegv; + force_sigsegv(sig); + return; } __put_user(set->sig[0], &frame->sc.oldmask[0]); @@ -174,10 +175,6 @@ void setup_frame(int sig, struct target_sigaction *ka, /* Place signal number on stack to allow backtrace from handler. */ __put_user(env->regs[2], &frame->signo); unlock_user_struct(frame, frame_addr, 1); - return; - -give_sigsegv: - force_sigsegv(sig); } void setup_rt_frame(int sig, struct target_sigaction *ka, @@ -190,7 +187,8 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, frame_addr = get_sigframe(ka, env, sizeof *frame); trace_user_setup_rt_frame(env, frame_addr); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { - goto give_sigsegv; + force_sigsegv(sig); + return; } tswap_siginfo(&frame->info, info); @@ -222,10 +220,6 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, env->regs[2] = sig; //map_signal(sig); env->regs[3] = frame_addr + offsetof(typeof(*frame), info); env->regs[4] = frame_addr + offsetof(typeof(*frame), uc); - return; - -give_sigsegv: - force_sigsegv(sig); } static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) @@ -259,7 +253,8 @@ long do_sigreturn(CPUS390XState *env) trace_user_do_sigreturn(env, frame_addr); if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { - goto badframe; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } __get_user(target_set.sig[0], &frame->sc.oldmask[0]); @@ -270,10 +265,6 @@ long do_sigreturn(CPUS390XState *env) unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; - -badframe: - force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUS390XState *env) @@ -284,7 +275,8 @@ long do_rt_sigreturn(CPUS390XState *env) trace_user_do_rt_sigreturn(env, frame_addr); if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { - goto badframe; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } target_to_host_sigset(&set, &frame->uc.tuc_sigmask); @@ -296,9 +288,4 @@ long do_rt_sigreturn(CPUS390XState *env) unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; - -badframe: - unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV); - return -TARGET_QEMU_ESIGRETURN; } From 7e5355578eef26ece8a783f336b2c06a1f5a083a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:34:03 -0700 Subject: [PATCH 0624/3028] linux-user/s390x: Set psw.mask properly for the signal handler Note that PSW_ADDR_{64,32} are called PSW_MASK_{EA,BA} in the kernel source. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-11-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 64a9eab097..17f617c655 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -162,6 +162,9 @@ void setup_frame(int sig, struct target_sigaction *ka, /* Set up registers for signal handler */ env->regs[15] = frame_addr; + /* Force default amode and default user address space control. */ + env->psw.mask = PSW_MASK_64 | PSW_MASK_32 | PSW_ASC_PRIMARY + | (env->psw.mask & ~PSW_MASK_ASC); env->psw.addr = ka->_sa_handler; env->regs[2] = sig; //map_signal(sig); @@ -215,6 +218,9 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, /* Set up registers for signal handler */ env->regs[15] = frame_addr; + /* Force default amode and default user address space control. */ + env->psw.mask = PSW_MASK_64 | PSW_MASK_32 | PSW_ASC_PRIMARY + | (env->psw.mask & ~PSW_MASK_ASC); env->psw.addr = ka->_sa_handler; env->regs[2] = sig; //map_signal(sig); From 6c18757dc55f0a47d926cec1aaab8c349a65a0c6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:34:04 -0700 Subject: [PATCH 0625/3028] linux-user/s390x: Add stub sigframe argument for last_break In order to properly present these arguments, we need to add code to target/s390x to record LowCore parameters for user-only. But in the meantime, at least zero the missing last_break argument, and fixup the comment style in the vicinity. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-12-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 17f617c655..bc41b01c5d 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -167,13 +167,16 @@ void setup_frame(int sig, struct target_sigaction *ka, | (env->psw.mask & ~PSW_MASK_ASC); env->psw.addr = ka->_sa_handler; - env->regs[2] = sig; //map_signal(sig); + env->regs[2] = sig; env->regs[3] = frame_addr += offsetof(typeof(*frame), sc); - /* We forgot to include these in the sigcontext. - To avoid breaking binary compatibility, they are passed as args. */ - env->regs[4] = 0; // FIXME: no clue... current->thread.trap_no; - env->regs[5] = 0; // FIXME: no clue... current->thread.prot_addr; + /* + * We forgot to include these in the sigcontext. + * To avoid breaking binary compatibility, they are passed as args. + */ + env->regs[4] = 0; /* FIXME: regs->int_code & 127 */ + env->regs[5] = 0; /* FIXME: regs->int_parm_long */ + env->regs[6] = 0; /* FIXME: current->thread.last_break */ /* Place signal number on stack to allow backtrace from handler. */ __put_user(env->regs[2], &frame->signo); @@ -223,9 +226,10 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, | (env->psw.mask & ~PSW_MASK_ASC); env->psw.addr = ka->_sa_handler; - env->regs[2] = sig; //map_signal(sig); + env->regs[2] = sig; env->regs[3] = frame_addr + offsetof(typeof(*frame), info); env->regs[4] = frame_addr + offsetof(typeof(*frame), uc); + env->regs[5] = 0; /* FIXME: current->thread.last_break */ } static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) From ac1a92ec8f1328141707965bb1df4252fdb76b68 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:34:05 -0700 Subject: [PATCH 0626/3028] linux-user/s390x: Fix frame_addr corruption in setup_frame The original value of frame_addr is still required for its use in the call to unlock_user_struct below. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-13-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index bc41b01c5d..81ba59b46a 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -168,7 +168,7 @@ void setup_frame(int sig, struct target_sigaction *ka, env->psw.addr = ka->_sa_handler; env->regs[2] = sig; - env->regs[3] = frame_addr += offsetof(typeof(*frame), sc); + env->regs[3] = frame_addr + offsetof(typeof(*frame), sc); /* * We forgot to include these in the sigcontext. From 9e0fb648b259981350777020717bba8365957b0f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:34:06 -0700 Subject: [PATCH 0627/3028] linux-user/s390x: Add build asserts for sigset sizes At point of usage, it's not immediately obvious that we don't need a loop to copy these arrays. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-14-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 81ba59b46a..839a7ae4b3 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -141,6 +141,8 @@ void setup_frame(int sig, struct target_sigaction *ka, return; } + /* Make sure that we're initializing all of oldmask. */ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(frame->sc.oldmask) != 1); __put_user(set->sig[0], &frame->sc.oldmask[0]); save_sigregs(env, &frame->sregs); @@ -266,6 +268,9 @@ long do_sigreturn(CPUS390XState *env) force_sig(TARGET_SIGSEGV); return -TARGET_QEMU_ESIGRETURN; } + + /* Make sure that we're initializing all of target_set. */ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(target_set.sig) != 1); __get_user(target_set.sig[0], &frame->sc.oldmask[0]); target_to_host_sigset_internal(&set, &target_set); From 79d6f2baa4b738bb223a0ad382661fe501b0c867 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:34:07 -0700 Subject: [PATCH 0628/3028] linux-user/s390x: Clean up signal.c Reorder the function bodies to correspond to the kernel source. Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-15-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 67 ++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 839a7ae4b3..9d470e4ca0 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -133,6 +133,7 @@ void setup_frame(int sig, struct target_sigaction *ka, { sigframe *frame; abi_ulong frame_addr; + abi_ulong restorer; frame_addr = get_sigframe(ka, env, sizeof(*frame)); trace_user_setup_frame(env, frame_addr); @@ -141,28 +142,39 @@ void setup_frame(int sig, struct target_sigaction *ka, return; } + /* Set up backchain. */ + __put_user(env->regs[15], (abi_ulong *) frame); + + /* Create struct sigcontext on the signal stack. */ /* Make sure that we're initializing all of oldmask. */ QEMU_BUILD_BUG_ON(ARRAY_SIZE(frame->sc.oldmask) != 1); __put_user(set->sig[0], &frame->sc.oldmask[0]); - - save_sigregs(env, &frame->sregs); - __put_user(frame_addr + offsetof(sigframe, sregs), &frame->sc.sregs); - /* Set up to return from userspace. If provided, use a stub - already in userspace. */ + /* Create _sigregs on the signal stack */ + save_sigregs(env, &frame->sregs); + + /* + * ??? The kernel uses regs->gprs[2] here, which is not yet the signo. + * Moreover the comment talks about allowing backtrace, which is really + * done by the r15 copy above. + */ + __put_user(sig, &frame->signo); + + /* + * Set up to return from userspace. + * If provided, use a stub already in userspace. + */ if (ka->sa_flags & TARGET_SA_RESTORER) { - env->regs[14] = ka->sa_restorer; + restorer = ka->sa_restorer; } else { - env->regs[14] = frame_addr + offsetof(sigframe, retcode); + restorer = frame_addr + offsetof(sigframe, retcode); __put_user(S390_SYSCALL_OPCODE | TARGET_NR_sigreturn, &frame->retcode); } - /* Set up backchain. */ - __put_user(env->regs[15], (abi_ulong *) frame); - /* Set up registers for signal handler */ + env->regs[14] = restorer; env->regs[15] = frame_addr; /* Force default amode and default user address space control. */ env->psw.mask = PSW_MASK_64 | PSW_MASK_32 | PSW_ASC_PRIMARY @@ -180,8 +192,6 @@ void setup_frame(int sig, struct target_sigaction *ka, env->regs[5] = 0; /* FIXME: regs->int_parm_long */ env->regs[6] = 0; /* FIXME: current->thread.last_break */ - /* Place signal number on stack to allow backtrace from handler. */ - __put_user(env->regs[2], &frame->signo); unlock_user_struct(frame, frame_addr, 1); } @@ -191,6 +201,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, { rt_sigframe *frame; abi_ulong frame_addr; + abi_ulong restorer; frame_addr = get_sigframe(ka, env, sizeof *frame); trace_user_setup_rt_frame(env, frame_addr); @@ -199,29 +210,33 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, return; } - tswap_siginfo(&frame->info, info); + /* Set up backchain. */ + __put_user(env->regs[15], (abi_ulong *) frame); - /* Create the ucontext. */ - __put_user(0, &frame->uc.tuc_flags); - __put_user((abi_ulong)0, (abi_ulong *)&frame->uc.tuc_link); - target_save_altstack(&frame->uc.tuc_stack, env); - save_sigregs(env, &frame->uc.tuc_mcontext); - tswap_sigset(&frame->uc.tuc_sigmask, set); - - /* Set up to return from userspace. If provided, use a stub - already in userspace. */ + /* + * Set up to return from userspace. + * If provided, use a stub already in userspace. + */ if (ka->sa_flags & TARGET_SA_RESTORER) { - env->regs[14] = ka->sa_restorer; + restorer = ka->sa_restorer; } else { - env->regs[14] = frame_addr + offsetof(typeof(*frame), retcode); + restorer = frame_addr + offsetof(typeof(*frame), retcode); __put_user(S390_SYSCALL_OPCODE | TARGET_NR_rt_sigreturn, &frame->retcode); } - /* Set up backchain. */ - __put_user(env->regs[15], (abi_ulong *) frame); + /* Create siginfo on the signal stack. */ + tswap_siginfo(&frame->info, info); + + /* Create ucontext on the signal stack. */ + __put_user(0, &frame->uc.tuc_flags); + __put_user(0, &frame->uc.tuc_link); + target_save_altstack(&frame->uc.tuc_stack, env); + save_sigregs(env, &frame->uc.tuc_mcontext); + tswap_sigset(&frame->uc.tuc_sigmask, set); /* Set up registers for signal handler */ + env->regs[14] = restorer; env->regs[15] = frame_addr; /* Force default amode and default user address space control. */ env->psw.mask = PSW_MASK_64 | PSW_MASK_32 | PSW_ASC_PRIMARY From 5140d6be5e71cd5d75697d47ba510d117773e970 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 Nov 2020 10:59:36 -0800 Subject: [PATCH 0629/3028] qemu/host-utils: Use __builtin_bitreverseN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clang has added some builtins for these operations; use them if available. Reviewed-by: Alex Bennée Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- include/qemu/host-utils.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index cdca2991d8..f1e52851e0 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -272,6 +272,9 @@ static inline int ctpop64(uint64_t val) */ static inline uint8_t revbit8(uint8_t x) { +#if __has_builtin(__builtin_bitreverse8) + return __builtin_bitreverse8(x); +#else /* Assign the correct nibble position. */ x = ((x & 0xf0) >> 4) | ((x & 0x0f) << 4); @@ -281,6 +284,7 @@ static inline uint8_t revbit8(uint8_t x) | ((x & 0x22) << 1) | ((x & 0x11) << 3); return x; +#endif } /** @@ -289,6 +293,9 @@ static inline uint8_t revbit8(uint8_t x) */ static inline uint16_t revbit16(uint16_t x) { +#if __has_builtin(__builtin_bitreverse16) + return __builtin_bitreverse16(x); +#else /* Assign the correct byte position. */ x = bswap16(x); /* Assign the correct nibble position. */ @@ -300,6 +307,7 @@ static inline uint16_t revbit16(uint16_t x) | ((x & 0x2222) << 1) | ((x & 0x1111) << 3); return x; +#endif } /** @@ -308,6 +316,9 @@ static inline uint16_t revbit16(uint16_t x) */ static inline uint32_t revbit32(uint32_t x) { +#if __has_builtin(__builtin_bitreverse32) + return __builtin_bitreverse32(x); +#else /* Assign the correct byte position. */ x = bswap32(x); /* Assign the correct nibble position. */ @@ -319,6 +330,7 @@ static inline uint32_t revbit32(uint32_t x) | ((x & 0x22222222u) << 1) | ((x & 0x11111111u) << 3); return x; +#endif } /** @@ -327,6 +339,9 @@ static inline uint32_t revbit32(uint32_t x) */ static inline uint64_t revbit64(uint64_t x) { +#if __has_builtin(__builtin_bitreverse64) + return __builtin_bitreverse64(x); +#else /* Assign the correct byte position. */ x = bswap64(x); /* Assign the correct nibble position. */ @@ -338,6 +353,7 @@ static inline uint64_t revbit64(uint64_t x) | ((x & 0x2222222222222222ull) << 1) | ((x & 0x1111111111111111ull) << 3); return x; +#endif } /* Host type specific sizes of these routines. */ From cec07c0b6129757337282287870da2d4c3958f48 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 Nov 2020 17:42:36 -0800 Subject: [PATCH 0630/3028] qemu/host-utils: Add wrappers for overflow builtins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These builtins came in with gcc 5 and clang 3.8, which are slightly newer than our supported minimum compiler versions. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- include/qemu/host-utils.h | 225 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index f1e52851e0..cb95626c7d 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -356,6 +356,231 @@ static inline uint64_t revbit64(uint64_t x) #endif } +/** + * sadd32_overflow - addition with overflow indication + * @x, @y: addends + * @ret: Output for sum + * + * Computes *@ret = @x + @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool sadd32_overflow(int32_t x, int32_t y, int32_t *ret) +{ +#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5 + return __builtin_add_overflow(x, y, ret); +#else + *ret = x + y; + return ((*ret ^ x) & ~(x ^ y)) < 0; +#endif +} + +/** + * sadd64_overflow - addition with overflow indication + * @x, @y: addends + * @ret: Output for sum + * + * Computes *@ret = @x + @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool sadd64_overflow(int64_t x, int64_t y, int64_t *ret) +{ +#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5 + return __builtin_add_overflow(x, y, ret); +#else + *ret = x + y; + return ((*ret ^ x) & ~(x ^ y)) < 0; +#endif +} + +/** + * uadd32_overflow - addition with overflow indication + * @x, @y: addends + * @ret: Output for sum + * + * Computes *@ret = @x + @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool uadd32_overflow(uint32_t x, uint32_t y, uint32_t *ret) +{ +#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5 + return __builtin_add_overflow(x, y, ret); +#else + *ret = x + y; + return *ret < x; +#endif +} + +/** + * uadd64_overflow - addition with overflow indication + * @x, @y: addends + * @ret: Output for sum + * + * Computes *@ret = @x + @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool uadd64_overflow(uint64_t x, uint64_t y, uint64_t *ret) +{ +#if __has_builtin(__builtin_add_overflow) || __GNUC__ >= 5 + return __builtin_add_overflow(x, y, ret); +#else + *ret = x + y; + return *ret < x; +#endif +} + +/** + * ssub32_overflow - subtraction with overflow indication + * @x: Minuend + * @y: Subtrahend + * @ret: Output for difference + * + * Computes *@ret = @x - @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool ssub32_overflow(int32_t x, int32_t y, int32_t *ret) +{ +#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5 + return __builtin_sub_overflow(x, y, ret); +#else + *ret = x - y; + return ((*ret ^ x) & (x ^ y)) < 0; +#endif +} + +/** + * ssub64_overflow - subtraction with overflow indication + * @x: Minuend + * @y: Subtrahend + * @ret: Output for sum + * + * Computes *@ret = @x - @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool ssub64_overflow(int64_t x, int64_t y, int64_t *ret) +{ +#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5 + return __builtin_sub_overflow(x, y, ret); +#else + *ret = x - y; + return ((*ret ^ x) & (x ^ y)) < 0; +#endif +} + +/** + * usub32_overflow - subtraction with overflow indication + * @x: Minuend + * @y: Subtrahend + * @ret: Output for sum + * + * Computes *@ret = @x - @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool usub32_overflow(uint32_t x, uint32_t y, uint32_t *ret) +{ +#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5 + return __builtin_sub_overflow(x, y, ret); +#else + *ret = x - y; + return x < y; +#endif +} + +/** + * usub64_overflow - subtraction with overflow indication + * @x: Minuend + * @y: Subtrahend + * @ret: Output for sum + * + * Computes *@ret = @x - @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool usub64_overflow(uint64_t x, uint64_t y, uint64_t *ret) +{ +#if __has_builtin(__builtin_sub_overflow) || __GNUC__ >= 5 + return __builtin_sub_overflow(x, y, ret); +#else + *ret = x - y; + return x < y; +#endif +} + +/** + * smul32_overflow - multiplication with overflow indication + * @x, @y: Input multipliers + * @ret: Output for product + * + * Computes *@ret = @x * @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool smul32_overflow(int32_t x, int32_t y, int32_t *ret) +{ +#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5 + return __builtin_mul_overflow(x, y, ret); +#else + int64_t z = (int64_t)x * y; + *ret = z; + return *ret != z; +#endif +} + +/** + * smul64_overflow - multiplication with overflow indication + * @x, @y: Input multipliers + * @ret: Output for product + * + * Computes *@ret = @x * @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool smul64_overflow(int64_t x, int64_t y, int64_t *ret) +{ +#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5 + return __builtin_mul_overflow(x, y, ret); +#else + uint64_t hi, lo; + muls64(&lo, &hi, x, y); + *ret = lo; + return hi != ((int64_t)lo >> 63); +#endif +} + +/** + * umul32_overflow - multiplication with overflow indication + * @x, @y: Input multipliers + * @ret: Output for product + * + * Computes *@ret = @x * @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool umul32_overflow(uint32_t x, uint32_t y, uint32_t *ret) +{ +#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5 + return __builtin_mul_overflow(x, y, ret); +#else + uint64_t z = (uint64_t)x * y; + *ret = z; + return z > UINT32_MAX; +#endif +} + +/** + * umul64_overflow - multiplication with overflow indication + * @x, @y: Input multipliers + * @ret: Output for product + * + * Computes *@ret = @x * @y, and returns true if and only if that + * value has been truncated. + */ +static inline bool umul64_overflow(uint64_t x, uint64_t y, uint64_t *ret) +{ +#if __has_builtin(__builtin_mul_overflow) || __GNUC__ >= 5 + return __builtin_mul_overflow(x, y, ret); +#else + uint64_t hi; + mulu64(ret, &hi, x, y); + return hi != 0; +#endif +} + /* Host type specific sizes of these routines. */ #if ULONG_MAX == UINT32_MAX From 1ec8070e58a30bd175a1c7186bff797488e8a17b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 13 Nov 2020 03:22:23 +0000 Subject: [PATCH 0631/3028] qemu/host-utils: Add wrappers for carry builtins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These builtins came in clang 3.8, but are not present in gcc through version 11. Even in clang the optimization is only ideal on x86_64, but never worse than the hand-coding that we currently do. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- include/qemu/host-utils.h | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h index cb95626c7d..711b221704 100644 --- a/include/qemu/host-utils.h +++ b/include/qemu/host-utils.h @@ -26,6 +26,7 @@ #ifndef HOST_UTILS_H #define HOST_UTILS_H +#include "qemu/compiler.h" #include "qemu/bswap.h" #ifdef CONFIG_INT128 @@ -581,6 +582,55 @@ static inline bool umul64_overflow(uint64_t x, uint64_t y, uint64_t *ret) #endif } +/** + * uadd64_carry - addition with carry-in and carry-out + * @x, @y: addends + * @pcarry: in-out carry value + * + * Computes @x + @y + *@pcarry, placing the carry-out back + * into *@pcarry and returning the 64-bit sum. + */ +static inline uint64_t uadd64_carry(uint64_t x, uint64_t y, bool *pcarry) +{ +#if __has_builtin(__builtin_addcll) + unsigned long long c = *pcarry; + x = __builtin_addcll(x, y, c, &c); + *pcarry = c & 1; + return x; +#else + bool c = *pcarry; + /* This is clang's internal expansion of __builtin_addc. */ + c = uadd64_overflow(x, c, &x); + c |= uadd64_overflow(x, y, &x); + *pcarry = c; + return x; +#endif +} + +/** + * usub64_borrow - subtraction with borrow-in and borrow-out + * @x, @y: addends + * @pborrow: in-out borrow value + * + * Computes @x - @y - *@pborrow, placing the borrow-out back + * into *@pborrow and returning the 64-bit sum. + */ +static inline uint64_t usub64_borrow(uint64_t x, uint64_t y, bool *pborrow) +{ +#if __has_builtin(__builtin_subcll) + unsigned long long b = *pborrow; + x = __builtin_subcll(x, y, b, &b); + *pborrow = b & 1; + return x; +#else + bool b = *pborrow; + b = usub64_overflow(x, b, &x); + b |= usub64_overflow(x, y, &x); + *pborrow = b; + return x; +#endif +} + /* Host type specific sizes of these routines. */ #if ULONG_MAX == UINT32_MAX From 7702a855195b81c6551d60991237c04316201dff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 6 Nov 2020 18:51:27 -0800 Subject: [PATCH 0632/3028] accel/tcg: Use add/sub overflow routines in tcg-runtime-gvec.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Obvious uses of the new functions. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- accel/tcg/tcg-runtime-gvec.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/accel/tcg/tcg-runtime-gvec.c b/accel/tcg/tcg-runtime-gvec.c index 521da4a813..ac7d28c251 100644 --- a/accel/tcg/tcg-runtime-gvec.c +++ b/accel/tcg/tcg-runtime-gvec.c @@ -1073,9 +1073,8 @@ void HELPER(gvec_ssadd32)(void *d, void *a, void *b, uint32_t desc) for (i = 0; i < oprsz; i += sizeof(int32_t)) { int32_t ai = *(int32_t *)(a + i); int32_t bi = *(int32_t *)(b + i); - int32_t di = ai + bi; - if (((di ^ ai) &~ (ai ^ bi)) < 0) { - /* Signed overflow. */ + int32_t di; + if (sadd32_overflow(ai, bi, &di)) { di = (di < 0 ? INT32_MAX : INT32_MIN); } *(int32_t *)(d + i) = di; @@ -1091,9 +1090,8 @@ void HELPER(gvec_ssadd64)(void *d, void *a, void *b, uint32_t desc) for (i = 0; i < oprsz; i += sizeof(int64_t)) { int64_t ai = *(int64_t *)(a + i); int64_t bi = *(int64_t *)(b + i); - int64_t di = ai + bi; - if (((di ^ ai) &~ (ai ^ bi)) < 0) { - /* Signed overflow. */ + int64_t di; + if (sadd64_overflow(ai, bi, &di)) { di = (di < 0 ? INT64_MAX : INT64_MIN); } *(int64_t *)(d + i) = di; @@ -1143,9 +1141,8 @@ void HELPER(gvec_sssub32)(void *d, void *a, void *b, uint32_t desc) for (i = 0; i < oprsz; i += sizeof(int32_t)) { int32_t ai = *(int32_t *)(a + i); int32_t bi = *(int32_t *)(b + i); - int32_t di = ai - bi; - if (((di ^ ai) & (ai ^ bi)) < 0) { - /* Signed overflow. */ + int32_t di; + if (ssub32_overflow(ai, bi, &di)) { di = (di < 0 ? INT32_MAX : INT32_MIN); } *(int32_t *)(d + i) = di; @@ -1161,9 +1158,8 @@ void HELPER(gvec_sssub64)(void *d, void *a, void *b, uint32_t desc) for (i = 0; i < oprsz; i += sizeof(int64_t)) { int64_t ai = *(int64_t *)(a + i); int64_t bi = *(int64_t *)(b + i); - int64_t di = ai - bi; - if (((di ^ ai) & (ai ^ bi)) < 0) { - /* Signed overflow. */ + int64_t di; + if (ssub64_overflow(ai, bi, &di)) { di = (di < 0 ? INT64_MAX : INT64_MIN); } *(int64_t *)(d + i) = di; @@ -1209,8 +1205,8 @@ void HELPER(gvec_usadd32)(void *d, void *a, void *b, uint32_t desc) for (i = 0; i < oprsz; i += sizeof(uint32_t)) { uint32_t ai = *(uint32_t *)(a + i); uint32_t bi = *(uint32_t *)(b + i); - uint32_t di = ai + bi; - if (di < ai) { + uint32_t di; + if (uadd32_overflow(ai, bi, &di)) { di = UINT32_MAX; } *(uint32_t *)(d + i) = di; @@ -1226,8 +1222,8 @@ void HELPER(gvec_usadd64)(void *d, void *a, void *b, uint32_t desc) for (i = 0; i < oprsz; i += sizeof(uint64_t)) { uint64_t ai = *(uint64_t *)(a + i); uint64_t bi = *(uint64_t *)(b + i); - uint64_t di = ai + bi; - if (di < ai) { + uint64_t di; + if (uadd64_overflow(ai, bi, &di)) { di = UINT64_MAX; } *(uint64_t *)(d + i) = di; @@ -1273,8 +1269,8 @@ void HELPER(gvec_ussub32)(void *d, void *a, void *b, uint32_t desc) for (i = 0; i < oprsz; i += sizeof(uint32_t)) { uint32_t ai = *(uint32_t *)(a + i); uint32_t bi = *(uint32_t *)(b + i); - uint32_t di = ai - bi; - if (ai < bi) { + uint32_t di; + if (usub32_overflow(ai, bi, &di)) { di = 0; } *(uint32_t *)(d + i) = di; @@ -1290,8 +1286,8 @@ void HELPER(gvec_ussub64)(void *d, void *a, void *b, uint32_t desc) for (i = 0; i < oprsz; i += sizeof(uint64_t)) { uint64_t ai = *(uint64_t *)(a + i); uint64_t bi = *(uint64_t *)(b + i); - uint64_t di = ai - bi; - if (ai < bi) { + uint64_t di; + if (usub64_overflow(ai, bi, &di)) { di = 0; } *(uint64_t *)(d + i) = di; From f2b84b9edb0788eb25902c4ca268476b42fceb20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 20 Oct 2020 17:37:37 +0100 Subject: [PATCH 0633/3028] tests/fp: add quad support to the benchmark utility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently this only support softfloat calculations because working out if the hardware supports 128 bit floats needs configure magic. The 3 op muladd operation is currently unimplemented so commented out for now. Reviewed-by: David Hildenbrand Signed-off-by: Alex Bennée Message-Id: <20201020163738.27700-8-alex.bennee@linaro.org> Signed-off-by: Richard Henderson --- tests/fp/fp-bench.c | 88 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 5 deletions(-) diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c index 4ba5e1d2d4..d319993280 100644 --- a/tests/fp/fp-bench.c +++ b/tests/fp/fp-bench.c @@ -14,6 +14,7 @@ #include #include #include "qemu/timer.h" +#include "qemu/int128.h" #include "fpu/softfloat.h" /* amortize the computation of random inputs */ @@ -50,8 +51,10 @@ static const char * const op_names[] = { enum precision { PREC_SINGLE, PREC_DOUBLE, + PREC_QUAD, PREC_FLOAT32, PREC_FLOAT64, + PREC_FLOAT128, PREC_MAX_NR, }; @@ -89,6 +92,7 @@ union fp { double d; float32 f32; float64 f64; + float128 f128; uint64_t u64; }; @@ -113,6 +117,10 @@ struct op_desc { static uint64_t random_ops[MAX_OPERANDS] = { SEED_A, SEED_B, SEED_C, }; + +static float128 random_quad_ops[MAX_OPERANDS] = { + {SEED_A, SEED_B}, {SEED_B, SEED_C}, {SEED_C, SEED_A}, +}; static float_status soft_status; static enum precision precision; static enum op operation; @@ -141,25 +149,45 @@ static void update_random_ops(int n_ops, enum precision prec) int i; for (i = 0; i < n_ops; i++) { - uint64_t r = random_ops[i]; switch (prec) { case PREC_SINGLE: case PREC_FLOAT32: + { + uint64_t r = random_ops[i]; do { r = xorshift64star(r); } while (!float32_is_normal(r)); + random_ops[i] = r; break; + } case PREC_DOUBLE: case PREC_FLOAT64: + { + uint64_t r = random_ops[i]; do { r = xorshift64star(r); } while (!float64_is_normal(r)); + random_ops[i] = r; break; + } + case PREC_QUAD: + case PREC_FLOAT128: + { + float128 r = random_quad_ops[i]; + uint64_t hi = r.high; + uint64_t lo = r.low; + do { + hi = xorshift64star(hi); + lo = xorshift64star(lo); + r = make_float128(hi, lo); + } while (!float128_is_normal(r)); + random_quad_ops[i] = r; + break; + } default: g_assert_not_reached(); } - random_ops[i] = r; } } @@ -184,6 +212,13 @@ static void fill_random(union fp *ops, int n_ops, enum precision prec, ops[i].f64 = float64_chs(ops[i].f64); } break; + case PREC_QUAD: + case PREC_FLOAT128: + ops[i].f128 = random_quad_ops[i]; + if (no_neg && float128_is_neg(ops[i].f128)) { + ops[i].f128 = float128_chs(ops[i].f128); + } + break; default: g_assert_not_reached(); } @@ -345,6 +380,41 @@ static void bench(enum precision prec, enum op op, int n_ops, bool no_neg) } } break; + case PREC_FLOAT128: + fill_random(ops, n_ops, prec, no_neg); + t0 = get_clock(); + for (i = 0; i < OPS_PER_ITER; i++) { + float128 a = ops[0].f128; + float128 b = ops[1].f128; + /* float128 c = ops[2].f128; */ + + switch (op) { + case OP_ADD: + res.f128 = float128_add(a, b, &soft_status); + break; + case OP_SUB: + res.f128 = float128_sub(a, b, &soft_status); + break; + case OP_MUL: + res.f128 = float128_mul(a, b, &soft_status); + break; + case OP_DIV: + res.f128 = float128_div(a, b, &soft_status); + break; + /* case OP_FMA: */ + /* res.f128 = float128_muladd(a, b, c, 0, &soft_status); */ + /* break; */ + case OP_SQRT: + res.f128 = float128_sqrt(a, &soft_status); + break; + case OP_CMP: + res.u64 = float128_compare_quiet(a, b, &soft_status); + break; + default: + g_assert_not_reached(); + } + } + break; default: g_assert_not_reached(); } @@ -369,7 +439,8 @@ static void bench(enum precision prec, enum op op, int n_ops, bool no_neg) GEN_BENCH(bench_ ## opname ## _float, float, PREC_SINGLE, op, n_ops) \ GEN_BENCH(bench_ ## opname ## _double, double, PREC_DOUBLE, op, n_ops) \ GEN_BENCH(bench_ ## opname ## _float32, float32, PREC_FLOAT32, op, n_ops) \ - GEN_BENCH(bench_ ## opname ## _float64, float64, PREC_FLOAT64, op, n_ops) + GEN_BENCH(bench_ ## opname ## _float64, float64, PREC_FLOAT64, op, n_ops) \ + GEN_BENCH(bench_ ## opname ## _float128, float128, PREC_FLOAT128, op, n_ops) GEN_BENCH_ALL_TYPES(add, OP_ADD, 2) GEN_BENCH_ALL_TYPES(sub, OP_SUB, 2) @@ -383,7 +454,8 @@ GEN_BENCH_ALL_TYPES(cmp, OP_CMP, 2) GEN_BENCH_NO_NEG(bench_ ## name ## _float, float, PREC_SINGLE, op, n) \ GEN_BENCH_NO_NEG(bench_ ## name ## _double, double, PREC_DOUBLE, op, n) \ GEN_BENCH_NO_NEG(bench_ ## name ## _float32, float32, PREC_FLOAT32, op, n) \ - GEN_BENCH_NO_NEG(bench_ ## name ## _float64, float64, PREC_FLOAT64, op, n) + GEN_BENCH_NO_NEG(bench_ ## name ## _float64, float64, PREC_FLOAT64, op, n) \ + GEN_BENCH_NO_NEG(bench_ ## name ## _float128, float128, PREC_FLOAT128, op, n) GEN_BENCH_ALL_TYPES_NO_NEG(sqrt, OP_SQRT, 1) #undef GEN_BENCH_ALL_TYPES_NO_NEG @@ -397,6 +469,7 @@ GEN_BENCH_ALL_TYPES_NO_NEG(sqrt, OP_SQRT, 1) [PREC_DOUBLE] = bench_ ## opname ## _double, \ [PREC_FLOAT32] = bench_ ## opname ## _float32, \ [PREC_FLOAT64] = bench_ ## opname ## _float64, \ + [PREC_FLOAT128] = bench_ ## opname ## _float128, \ } static const bench_func_t bench_funcs[OP_MAX_NR][PREC_MAX_NR] = { @@ -445,7 +518,7 @@ static void usage_complete(int argc, char *argv[]) fprintf(stderr, " -h = show this help message.\n"); fprintf(stderr, " -o = floating point operation (%s). Default: %s\n", op_list, op_names[0]); - fprintf(stderr, " -p = floating point precision (single, double). " + fprintf(stderr, " -p = floating point precision (single, double, quad[soft only]). " "Default: single\n"); fprintf(stderr, " -r = rounding mode (even, zero, down, up, tieaway). " "Default: even\n"); @@ -565,6 +638,8 @@ static void parse_args(int argc, char *argv[]) precision = PREC_SINGLE; } else if (!strcmp(optarg, "double")) { precision = PREC_DOUBLE; + } else if (!strcmp(optarg, "quad")) { + precision = PREC_QUAD; } else { fprintf(stderr, "Unsupported precision '%s'\n", optarg); exit(EXIT_FAILURE); @@ -608,6 +683,9 @@ static void parse_args(int argc, char *argv[]) case PREC_DOUBLE: precision = PREC_FLOAT64; break; + case PREC_QUAD: + precision = PREC_FLOAT128; + break; default: g_assert_not_reached(); } From e99c43735a413e2566b4ad36eeda6dd061a9b939 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 7 Nov 2020 11:19:32 -0800 Subject: [PATCH 0634/3028] softfloat: Move the binary point to the msb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than point the binary point at msb-1, put it at the msb. Use uadd64_overflow to detect when addition overflows instead of DECOMPOSED_OVERFLOW_BIT. This reduces the number of special cases within the code, such as shifting an int64_t either left or right during conversion. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 169 +++++++++++++++++++----------------------------- 1 file changed, 66 insertions(+), 103 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 67cfa0fd82..cd777743f1 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -503,9 +503,8 @@ typedef struct { bool sign; } FloatParts; -#define DECOMPOSED_BINARY_POINT (64 - 2) +#define DECOMPOSED_BINARY_POINT 63 #define DECOMPOSED_IMPLICIT_BIT (1ull << DECOMPOSED_BINARY_POINT) -#define DECOMPOSED_OVERFLOW_BIT (DECOMPOSED_IMPLICIT_BIT << 1) /* Structure holding all of the relevant parameters for a format. * exp_size: the size of the exponent field @@ -657,7 +656,7 @@ static FloatParts sf_canonicalize(FloatParts part, const FloatFmt *parm, part.cls = float_class_zero; part.frac = 0; } else { - int shift = clz64(part.frac) - 1; + int shift = clz64(part.frac); part.cls = float_class_normal; part.exp = parm->frac_shift - parm->exp_bias - shift + 1; part.frac <<= shift; @@ -727,9 +726,8 @@ static FloatParts round_canonical(FloatParts p, float_status *s, if (likely(exp > 0)) { if (frac & round_mask) { flags |= float_flag_inexact; - frac += inc; - if (frac & DECOMPOSED_OVERFLOW_BIT) { - frac >>= 1; + if (uadd64_overflow(frac, inc, &frac)) { + frac = (frac >> 1) | DECOMPOSED_IMPLICIT_BIT; exp++; } } @@ -758,9 +756,12 @@ static FloatParts round_canonical(FloatParts p, float_status *s, p.cls = float_class_zero; goto do_zero; } else { - bool is_tiny = s->tininess_before_rounding - || (exp < 0) - || !((frac + inc) & DECOMPOSED_OVERFLOW_BIT); + bool is_tiny = s->tininess_before_rounding || (exp < 0); + + if (!is_tiny) { + uint64_t discard; + is_tiny = !uadd64_overflow(frac, inc, &discard); + } shift64RightJamming(frac, 1 - exp, &frac); if (frac & round_mask) { @@ -985,7 +986,7 @@ static FloatParts addsub_floats(FloatParts a, FloatParts b, bool subtract, a.cls = float_class_zero; a.sign = s->float_rounding_mode == float_round_down; } else { - int shift = clz64(a.frac) - 1; + int shift = clz64(a.frac); a.frac = a.frac << shift; a.exp = a.exp - shift; a.sign = a_sign; @@ -1022,9 +1023,10 @@ static FloatParts addsub_floats(FloatParts a, FloatParts b, bool subtract, shift64RightJamming(a.frac, b.exp - a.exp, &a.frac); a.exp = b.exp; } - a.frac += b.frac; - if (a.frac & DECOMPOSED_OVERFLOW_BIT) { + + if (uadd64_overflow(a.frac, b.frac, &a.frac)) { shift64RightJamming(a.frac, 1, &a.frac); + a.frac |= DECOMPOSED_IMPLICIT_BIT; a.exp += 1; } return a; @@ -1219,16 +1221,17 @@ static FloatParts mul_floats(FloatParts a, FloatParts b, float_status *s) int exp = a.exp + b.exp; mul64To128(a.frac, b.frac, &hi, &lo); - shift128RightJamming(hi, lo, DECOMPOSED_BINARY_POINT, &hi, &lo); - if (lo & DECOMPOSED_OVERFLOW_BIT) { - shift64RightJamming(lo, 1, &lo); + if (hi & DECOMPOSED_IMPLICIT_BIT) { exp += 1; + } else { + hi <<= 1; } + hi |= (lo != 0); /* Re-use a */ a.exp = exp; a.sign = sign; - a.frac = lo; + a.frac = hi; return a; } /* handle all the NaN cases */ @@ -1411,56 +1414,41 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c, p_exp = a.exp + b.exp; - /* Multiply of 2 62-bit numbers produces a (2*62) == 124-bit - * result. - */ mul64To128(a.frac, b.frac, &hi, &lo); - /* binary point now at bit 124 */ - /* check for overflow */ - if (hi & (1ULL << (DECOMPOSED_BINARY_POINT * 2 + 1 - 64))) { - shift128RightJamming(hi, lo, 1, &hi, &lo); + /* Renormalize to the msb. */ + if (hi & DECOMPOSED_IMPLICIT_BIT) { p_exp += 1; + } else { + shortShift128Left(hi, lo, 1, &hi, &lo); } /* + add/sub */ - if (c.cls == float_class_zero) { - /* move binary point back to 62 */ - shift128RightJamming(hi, lo, DECOMPOSED_BINARY_POINT, &hi, &lo); - } else { + if (c.cls != float_class_zero) { int exp_diff = p_exp - c.exp; if (p_sign == c.sign) { /* Addition */ if (exp_diff <= 0) { - shift128RightJamming(hi, lo, - DECOMPOSED_BINARY_POINT - exp_diff, - &hi, &lo); - lo += c.frac; + shift64RightJamming(hi, -exp_diff, &hi); p_exp = c.exp; + if (uadd64_overflow(hi, c.frac, &hi)) { + shift64RightJamming(hi, 1, &hi); + hi |= DECOMPOSED_IMPLICIT_BIT; + p_exp += 1; + } } else { - uint64_t c_hi, c_lo; - /* shift c to the same binary point as the product (124) */ - c_hi = c.frac >> 2; - c_lo = 0; - shift128RightJamming(c_hi, c_lo, - exp_diff, - &c_hi, &c_lo); - add128(hi, lo, c_hi, c_lo, &hi, &lo); - /* move binary point back to 62 */ - shift128RightJamming(hi, lo, DECOMPOSED_BINARY_POINT, &hi, &lo); + uint64_t c_hi, c_lo, over; + shift128RightJamming(c.frac, 0, exp_diff, &c_hi, &c_lo); + add192(0, hi, lo, 0, c_hi, c_lo, &over, &hi, &lo); + if (over) { + shift64RightJamming(hi, 1, &hi); + hi |= DECOMPOSED_IMPLICIT_BIT; + p_exp += 1; + } } - - if (lo & DECOMPOSED_OVERFLOW_BIT) { - shift64RightJamming(lo, 1, &lo); - p_exp += 1; - } - } else { /* Subtraction */ - uint64_t c_hi, c_lo; - /* make C binary point match product at bit 124 */ - c_hi = c.frac >> 2; - c_lo = 0; + uint64_t c_hi = c.frac, c_lo = 0; if (exp_diff <= 0) { shift128RightJamming(hi, lo, -exp_diff, &hi, &lo); @@ -1495,20 +1483,15 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c, /* Normalizing to a binary point of 124 is the correct adjust for the exponent. However since we're shifting, we might as well put the binary point back - at 62 where we really want it. Therefore shift as + at 63 where we really want it. Therefore shift as if we're leaving 1 bit at the top of the word, but adjust the exponent as if we're leaving 3 bits. */ - shift -= 1; - if (shift >= 64) { - lo = lo << (shift - 64); - } else { - hi = (hi << shift) | (lo >> (64 - shift)); - lo = hi | ((lo << shift) != 0); - } - p_exp -= shift - 2; + shift128Left(hi, lo, shift, &hi, &lo); + p_exp -= shift; } } } + hi |= (lo != 0); if (flags & float_muladd_halve_result) { p_exp -= 1; @@ -1518,7 +1501,7 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c, a.cls = float_class_normal; a.sign = p_sign ^ sign_flip; a.exp = p_exp; - a.frac = lo; + a.frac = hi; return a; } @@ -1742,25 +1725,17 @@ static FloatParts div_floats(FloatParts a, FloatParts b, float_status *s) * exponent to match. * * The udiv_qrnnd algorithm that we're using requires normalization, - * i.e. the msb of the denominator must be set. Since we know that - * DECOMPOSED_BINARY_POINT is msb-1, the inputs must be shifted left - * by one (more), and the remainder must be shifted right by one. + * i.e. the msb of the denominator must be set, which is already true. */ if (a.frac < b.frac) { exp -= 1; - shift128Left(0, a.frac, DECOMPOSED_BINARY_POINT + 2, &n1, &n0); - } else { shift128Left(0, a.frac, DECOMPOSED_BINARY_POINT + 1, &n1, &n0); + } else { + shift128Left(0, a.frac, DECOMPOSED_BINARY_POINT, &n1, &n0); } - q = udiv_qrnnd(&r, n1, n0, b.frac << 1); + q = udiv_qrnnd(&r, n1, n0, b.frac); - /* - * Set lsb if there is a remainder, to set inexact. - * As mentioned above, to find the actual value of the remainder we - * would need to shift right, but (1) we are only concerned about - * non-zero-ness, and (2) the remainder will always be even because - * both inputs to the division primitive are even. - */ + /* Set lsb if there is a remainder, to set inexact. */ a.frac = q | (r != 0); a.sign = sign; a.exp = exp; @@ -2135,12 +2110,12 @@ static FloatParts round_to_int(FloatParts a, FloatRoundMode rmode, if (a.frac & rnd_mask) { s->float_exception_flags |= float_flag_inexact; - a.frac += inc; - a.frac &= ~rnd_mask; - if (a.frac & DECOMPOSED_OVERFLOW_BIT) { + if (uadd64_overflow(a.frac, inc, &a.frac)) { a.frac >>= 1; + a.frac |= DECOMPOSED_IMPLICIT_BIT; a.exp++; } + a.frac &= ~rnd_mask; } } break; @@ -2213,10 +2188,8 @@ static int64_t round_to_int_and_pack(FloatParts in, FloatRoundMode rmode, case float_class_zero: return 0; case float_class_normal: - if (p.exp < DECOMPOSED_BINARY_POINT) { + if (p.exp <= DECOMPOSED_BINARY_POINT) { r = p.frac >> (DECOMPOSED_BINARY_POINT - p.exp); - } else if (p.exp - DECOMPOSED_BINARY_POINT < 2) { - r = p.frac << (p.exp - DECOMPOSED_BINARY_POINT); } else { r = UINT64_MAX; } @@ -2498,10 +2471,8 @@ static uint64_t round_to_uint_and_pack(FloatParts in, FloatRoundMode rmode, return 0; } - if (p.exp < DECOMPOSED_BINARY_POINT) { + if (p.exp <= DECOMPOSED_BINARY_POINT) { r = p.frac >> (DECOMPOSED_BINARY_POINT - p.exp); - } else if (p.exp - DECOMPOSED_BINARY_POINT < 2) { - r = p.frac << (p.exp - DECOMPOSED_BINARY_POINT); } else { s->float_exception_flags = orig_flags | float_flag_invalid; return max; @@ -2765,11 +2736,11 @@ static FloatParts int_to_float(int64_t a, int scale, float_status *status) f = -f; r.sign = true; } - shift = clz64(f) - 1; + shift = clz64(f); scale = MIN(MAX(scale, -0x10000), 0x10000); r.exp = DECOMPOSED_BINARY_POINT - shift + scale; - r.frac = (shift < 0 ? DECOMPOSED_IMPLICIT_BIT : f << shift); + r.frac = f << shift; } return r; @@ -2920,21 +2891,16 @@ bfloat16 int16_to_bfloat16(int16_t a, float_status *status) static FloatParts uint_to_float(uint64_t a, int scale, float_status *status) { FloatParts r = { .sign = false }; + int shift; if (a == 0) { r.cls = float_class_zero; } else { scale = MIN(MAX(scale, -0x10000), 0x10000); + shift = clz64(a); r.cls = float_class_normal; - if ((int64_t)a < 0) { - r.exp = DECOMPOSED_BINARY_POINT + 1 + scale; - shift64RightJamming(a, 1, &a); - r.frac = a; - } else { - int shift = clz64(a) - 1; - r.exp = DECOMPOSED_BINARY_POINT - shift + scale; - r.frac = a << shift; - } + r.exp = DECOMPOSED_BINARY_POINT - shift + scale; + r.frac = a << shift; } return r; @@ -3475,12 +3441,9 @@ static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p) /* We need two overflow bits at the top. Adding room for that is a * right shift. If the exponent is odd, we can discard the low bit * by multiplying the fraction by 2; that's a left shift. Combine - * those and we shift right if the exponent is even. + * those and we shift right by 1 if the exponent is odd, otherwise 2. */ - a_frac = a.frac; - if (!(a.exp & 1)) { - a_frac >>= 1; - } + a_frac = a.frac >> (2 - (a.exp & 1)); a.exp >>= 1; /* Bit-by-bit computation of sqrt. */ @@ -3488,10 +3451,10 @@ static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p) s_frac = 0; /* Iterate from implicit bit down to the 3 extra bits to compute a - * properly rounded result. Remember we've inserted one more bit - * at the top, so these positions are one less. + * properly rounded result. Remember we've inserted two more bits + * at the top, so these positions are two less. */ - bit = DECOMPOSED_BINARY_POINT - 1; + bit = DECOMPOSED_BINARY_POINT - 2; last_bit = MAX(p->frac_shift - 4, 0); do { uint64_t q = 1ULL << bit; @@ -3507,7 +3470,7 @@ static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p) /* Undo the right shift done above. If there is any remaining * fraction, the result is inexact. Set the sticky bit. */ - a.frac = (r_frac << 1) + (a_frac != 0); + a.frac = (r_frac << 2) + (a_frac != 0); return a; } From 622090ae1992d242553a20c9fd08f1ad2afdab41 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 20 Oct 2020 20:05:57 -0700 Subject: [PATCH 0635/3028] softfloat: Inline float_raise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat-specialize.c.inc | 12 ------------ include/fpu/softfloat.h | 5 ++++- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index e19809c04b..96ed8c1a26 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -227,18 +227,6 @@ floatx80 floatx80_default_nan(float_status *status) const floatx80 floatx80_infinity = make_floatx80_init(floatx80_infinity_high, floatx80_infinity_low); -/*---------------------------------------------------------------------------- -| Raises the exceptions specified by `flags'. Floating-point traps can be -| defined here if desired. It is currently not possible for such a trap -| to substitute a result value. If traps are not implemented, this routine -| should be simply `float_exception_flags |= flags;'. -*----------------------------------------------------------------------------*/ - -void float_raise(uint8_t flags, float_status *status) -{ - status->float_exception_flags |= flags; -} - /*---------------------------------------------------------------------------- | Internal canonical NaN format. *----------------------------------------------------------------------------*/ diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 78ad5ca738..019c2ec66d 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -100,7 +100,10 @@ typedef enum { | Routine to raise any or all of the software IEC/IEEE floating-point | exception flags. *----------------------------------------------------------------------------*/ -void float_raise(uint8_t flags, float_status *status); +static inline void float_raise(uint8_t flags, float_status *status) +{ + status->float_exception_flags |= flags; +} /*---------------------------------------------------------------------------- | If `a' is denormal and we are in flush-to-zero mode then set the From d82f3b2dc7d0efe0fcb0cec884c2d0803b9fd4de Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 22 Oct 2020 10:45:04 -0700 Subject: [PATCH 0636/3028] softfloat: Use float_raise in more places MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have been somewhat inconsistent about when to use float_raise and when to or in the bit by hand. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat.c | 87 +++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index cd777743f1..93fe785809 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -132,7 +132,7 @@ this code that are retained. if (unlikely(soft_t ## _is_denormal(*a))) { \ *a = soft_t ## _set_sign(soft_t ## _zero, \ soft_t ## _is_neg(*a)); \ - s->float_exception_flags |= float_flag_input_denormal; \ + float_raise(float_flag_input_denormal, s); \ } \ } @@ -360,7 +360,7 @@ float32_gen2(float32 xa, float32 xb, float_status *s, ur.h = hard(ua.h, ub.h); if (unlikely(f32_is_inf(ur))) { - s->float_exception_flags |= float_flag_overflow; + float_raise(float_flag_overflow, s); } else if (unlikely(fabsf(ur.h) <= FLT_MIN) && post(ua, ub)) { goto soft; } @@ -391,7 +391,7 @@ float64_gen2(float64 xa, float64 xb, float_status *s, ur.h = hard(ua.h, ub.h); if (unlikely(f64_is_inf(ur))) { - s->float_exception_flags |= float_flag_overflow; + float_raise(float_flag_overflow, s); } else if (unlikely(fabs(ur.h) <= DBL_MIN) && post(ua, ub)) { goto soft; } @@ -880,7 +880,7 @@ static FloatParts return_nan(FloatParts a, float_status *s) { switch (a.cls) { case float_class_snan: - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); a = parts_silence_nan(a, s); /* fall through */ case float_class_qnan: @@ -898,7 +898,7 @@ static FloatParts return_nan(FloatParts a, float_status *s) static FloatParts pick_nan(FloatParts a, FloatParts b, float_status *s) { if (is_snan(a.cls) || is_snan(b.cls)) { - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); } if (s->default_nan_mode) { @@ -922,7 +922,7 @@ static FloatParts pick_nan_muladd(FloatParts a, FloatParts b, FloatParts c, int which; if (is_snan(a.cls) || is_snan(b.cls) || is_snan(c.cls)) { - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); } which = pickNaNMulAdd(a.cls, b.cls, c.cls, inf_zero, s); @@ -1241,7 +1241,7 @@ static FloatParts mul_floats(FloatParts a, FloatParts b, float_status *s) /* Inf * Zero == NaN */ if ((a.cls == float_class_inf && b.cls == float_class_zero) || (a.cls == float_class_zero && b.cls == float_class_inf)) { - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); return parts_default_nan(s); } /* Multiply by 0 or Inf */ @@ -1356,6 +1356,7 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c, } if (inf_zero) { + float_raise(float_flag_invalid, s); s->float_exception_flags |= float_flag_invalid; return parts_default_nan(s); } @@ -1380,7 +1381,7 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c, if (c.cls == float_class_inf) { if (p_class == float_class_inf && p_sign != c.sign) { - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); return parts_default_nan(s); } else { a.cls = float_class_inf; @@ -1598,7 +1599,7 @@ float32_muladd(float32 xa, float32 xb, float32 xc, int flags, float_status *s) ur.h = fmaf(ua.h, ub.h, uc.h); if (unlikely(f32_is_inf(ur))) { - s->float_exception_flags |= float_flag_overflow; + float_raise(float_flag_overflow, s); } else if (unlikely(fabsf(ur.h) <= FLT_MIN)) { ua = ua_orig; uc = uc_orig; @@ -1669,7 +1670,7 @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s) ur.h = fma(ua.h, ub.h, uc.h); if (unlikely(f64_is_inf(ur))) { - s->float_exception_flags |= float_flag_overflow; + float_raise(float_flag_overflow, s); } else if (unlikely(fabs(ur.h) <= FLT_MIN)) { ua = ua_orig; uc = uc_orig; @@ -1749,7 +1750,7 @@ static FloatParts div_floats(FloatParts a, FloatParts b, float_status *s) if (a.cls == b.cls && (a.cls == float_class_inf || a.cls == float_class_zero)) { - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); return parts_default_nan(s); } /* Inf / x or 0 / x */ @@ -1759,7 +1760,7 @@ static FloatParts div_floats(FloatParts a, FloatParts b, float_status *s) } /* Div 0 => Inf */ if (b.cls == float_class_zero) { - s->float_exception_flags |= float_flag_divbyzero; + float_raise(float_flag_divbyzero, s); a.cls = float_class_inf; a.sign = sign; return a; @@ -1895,7 +1896,7 @@ static FloatParts float_to_float(FloatParts a, const FloatFmt *dstf, /* There is no NaN in the destination format. Raise Invalid * and return a zero with the sign of the input NaN. */ - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); a.cls = float_class_zero; a.frac = 0; a.exp = 0; @@ -1905,7 +1906,7 @@ static FloatParts float_to_float(FloatParts a, const FloatFmt *dstf, /* There is no Inf in the destination format. Raise Invalid * and return the maximum normal with the correct sign. */ - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); a.cls = float_class_normal; a.exp = dstf->exp_max; a.frac = ((1ull << dstf->frac_size) - 1) << dstf->frac_shift; @@ -1916,7 +1917,7 @@ static FloatParts float_to_float(FloatParts a, const FloatFmt *dstf, } } else if (is_nan(a.cls)) { if (is_snan(a.cls)) { - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); a = parts_silence_nan(a, s); } if (s->default_nan_mode) { @@ -2048,7 +2049,7 @@ static FloatParts round_to_int(FloatParts a, FloatRoundMode rmode, if (a.exp < 0) { bool one; /* all fractional */ - s->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, s); switch (rmode) { case float_round_nearest_even: one = a.exp == -1 && a.frac > DECOMPOSED_IMPLICIT_BIT; @@ -2109,7 +2110,7 @@ static FloatParts round_to_int(FloatParts a, FloatRoundMode rmode, } if (a.frac & rnd_mask) { - s->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, s); if (uadd64_overflow(a.frac, inc, &a.frac)) { a.frac >>= 1; a.frac |= DECOMPOSED_IMPLICIT_BIT; @@ -3188,7 +3189,7 @@ static FloatRelation compare_floats(FloatParts a, FloatParts b, bool is_quiet, if (!is_quiet || a.cls == float_class_snan || b.cls == float_class_snan) { - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); } return float_relation_unordered; } @@ -3429,7 +3430,7 @@ static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p) return a; /* sqrt(+-0) = +-0 */ } if (a.sign) { - s->float_exception_flags |= float_flag_invalid; + float_raise(float_flag_invalid, s); return parts_default_nan(s); } if (a.cls == float_class_inf) { @@ -3760,7 +3761,7 @@ static int32_t roundAndPackInt32(bool zSign, uint64_t absZ, return zSign ? INT32_MIN : INT32_MAX; } if (roundBits) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return z; @@ -3822,7 +3823,7 @@ static int64_t roundAndPackInt64(bool zSign, uint64_t absZ0, uint64_t absZ1, return zSign ? INT64_MIN : INT64_MAX; } if (absZ1) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return z; @@ -3883,7 +3884,7 @@ static int64_t roundAndPackUint64(bool zSign, uint64_t absZ0, } if (absZ1) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return absZ0; } @@ -3994,7 +3995,7 @@ static float32 roundAndPackFloat32(bool zSign, int zExp, uint32_t zSig, } } if (roundBits) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } zSig = ( zSig + roundIncrement )>>7; if (!(roundBits ^ 0x40) && roundNearestEven) { @@ -4150,7 +4151,7 @@ static float64 roundAndPackFloat64(bool zSign, int zExp, uint64_t zSig, } } if (roundBits) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } zSig = ( zSig + roundIncrement )>>10; if (!(roundBits ^ 0x200) && roundNearestEven) { @@ -4284,7 +4285,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign, float_raise(float_flag_underflow, status); } if (roundBits) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } zSig0 += roundIncrement; if ( (int64_t) zSig0 < 0 ) zExp = 1; @@ -4297,7 +4298,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign, } } if (roundBits) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } zSig0 += roundIncrement; if ( zSig0 < roundIncrement ) { @@ -4360,7 +4361,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign, float_raise(float_flag_underflow, status); } if (zSig1) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } switch (roundingMode) { case float_round_nearest_even: @@ -4390,7 +4391,7 @@ floatx80 roundAndPackFloatx80(int8_t roundingPrecision, bool zSign, } } if (zSig1) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } if ( increment ) { ++zSig0; @@ -4667,7 +4668,7 @@ static float128 roundAndPackFloat128(bool zSign, int32_t zExp, } } if (zSig2) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } if ( increment ) { add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 ); @@ -5405,7 +5406,7 @@ int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *status) } else if ( aExp < 0x3FFF ) { if (aExp || aSig) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return 0; } @@ -5420,7 +5421,7 @@ int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *status) return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF; } if ( ( aSig<float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return z; @@ -5504,13 +5505,13 @@ int64_t floatx80_to_int64_round_to_zero(floatx80 a, float_status *status) } else if ( aExp < 0x3FFF ) { if (aExp | aSig) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return 0; } z = aSig>>( - shiftCount ); if ( (uint64_t) ( aSig<<( shiftCount & 63 ) ) ) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } if ( aSign ) z = - z; return z; @@ -5661,7 +5662,7 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status) && ( (uint64_t) ( extractFloatx80Frac( a ) ) == 0 ) ) { return a; } - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); aSign = extractFloatx80Sign( a ); switch (status->float_rounding_mode) { case float_round_nearest_even: @@ -5728,7 +5729,7 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status) z.low = UINT64_C(0x8000000000000000); } if (z.low != a.low) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return z; @@ -6364,7 +6365,7 @@ int32_t float128_to_int32_round_to_zero(float128 a, float_status *status) } else if ( aExp < 0x3FFF ) { if (aExp || aSig0) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return 0; } @@ -6380,7 +6381,7 @@ int32_t float128_to_int32_round_to_zero(float128 a, float_status *status) return aSign ? INT32_MIN : INT32_MAX; } if ( ( aSig0<float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return z; @@ -6458,7 +6459,7 @@ int64_t float128_to_int64_round_to_zero(float128 a, float_status *status) if ( ( a.high == UINT64_C(0xC03E000000000000) ) && ( aSig1 < UINT64_C(0x0002000000000000) ) ) { if (aSig1) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } } else { @@ -6471,20 +6472,20 @@ int64_t float128_to_int64_round_to_zero(float128 a, float_status *status) } z = ( aSig0<>( ( - shiftCount ) & 63 ) ); if ( (uint64_t) ( aSig1<float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } } else { if ( aExp < 0x3FFF ) { if ( aExp | aSig0 | aSig1 ) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return 0; } z = aSig0>>( - shiftCount ); if ( aSig1 || ( shiftCount && (uint64_t) ( aSig0<<( shiftCount & 63 ) ) ) ) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } } if ( aSign ) z = - z; @@ -6793,7 +6794,7 @@ float128 float128_round_to_int(float128 a, float_status *status) else { if ( aExp < 0x3FFF ) { if ( ( ( (uint64_t) ( a.high<<1 ) ) | a.low ) == 0 ) return a; - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); aSign = extractFloat128Sign( a ); switch (status->float_rounding_mode) { case float_round_nearest_even: @@ -6867,7 +6868,7 @@ float128 float128_round_to_int(float128 a, float_status *status) z.high &= ~ roundBitsMask; } if ( ( z.low != a.low ) || ( z.high != a.high ) ) { - status->float_exception_flags |= float_flag_inexact; + float_raise(float_flag_inexact, status); } return z; From 9793c1e224a30252dfa7ca3c1f7a5c4827ca4cfc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Sep 2020 14:58:59 -0700 Subject: [PATCH 0637/3028] softfloat: Tidy a * b + inf return MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No reason to set values in 'a', when we already have float_class_inf in 'c', and can flip that sign. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alex Bennée Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 93fe785809..ee4b5073b6 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1384,9 +1384,8 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c, float_raise(float_flag_invalid, s); return parts_default_nan(s); } else { - a.cls = float_class_inf; - a.sign = c.sign ^ sign_flip; - return a; + c.sign ^= sign_flip; + return c; } } From 134eda00e9ec4f4a2798d64b3105331f8281aba6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Sep 2020 15:00:13 -0700 Subject: [PATCH 0638/3028] softfloat: Add float_cmask and constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing more than one class at a time is better done with masks. This reduces the static branch count. Reviewed-by: Alex Bennée Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index ee4b5073b6..64edb23793 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -469,6 +469,20 @@ typedef enum __attribute__ ((__packed__)) { float_class_snan, } FloatClass; +#define float_cmask(bit) (1u << (bit)) + +enum { + float_cmask_zero = float_cmask(float_class_zero), + float_cmask_normal = float_cmask(float_class_normal), + float_cmask_inf = float_cmask(float_class_inf), + float_cmask_qnan = float_cmask(float_class_qnan), + float_cmask_snan = float_cmask(float_class_snan), + + float_cmask_infzero = float_cmask_zero | float_cmask_inf, + float_cmask_anynan = float_cmask_qnan | float_cmask_snan, +}; + + /* Simple helpers for checking if, or what kind of, NaN we have */ static inline __attribute__((unused)) bool is_nan(FloatClass c) { @@ -1338,26 +1352,28 @@ bfloat16 QEMU_FLATTEN bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c, int flags, float_status *s) { - bool inf_zero = ((1 << a.cls) | (1 << b.cls)) == - ((1 << float_class_inf) | (1 << float_class_zero)); - bool p_sign; + bool inf_zero, p_sign; bool sign_flip = flags & float_muladd_negate_result; FloatClass p_class; uint64_t hi, lo; int p_exp; + int ab_mask, abc_mask; + + ab_mask = float_cmask(a.cls) | float_cmask(b.cls); + abc_mask = float_cmask(c.cls) | ab_mask; + inf_zero = ab_mask == float_cmask_infzero; /* It is implementation-defined whether the cases of (0,inf,qnan) * and (inf,0,qnan) raise InvalidOperation or not (and what QNaN * they return if they do), so we have to hand this information * off to the target-specific pick-a-NaN routine. */ - if (is_nan(a.cls) || is_nan(b.cls) || is_nan(c.cls)) { + if (unlikely(abc_mask & float_cmask_anynan)) { return pick_nan_muladd(a, b, c, inf_zero, s); } if (inf_zero) { float_raise(float_flag_invalid, s); - s->float_exception_flags |= float_flag_invalid; return parts_default_nan(s); } @@ -1371,9 +1387,9 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c, p_sign ^= 1; } - if (a.cls == float_class_inf || b.cls == float_class_inf) { + if (ab_mask & float_cmask_inf) { p_class = float_class_inf; - } else if (a.cls == float_class_zero || b.cls == float_class_zero) { + } else if (ab_mask & float_cmask_zero) { p_class = float_class_zero; } else { p_class = float_class_normal; From 0d40cd939ac852270da545de235744abe34b61e5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 22 Oct 2020 10:48:48 -0700 Subject: [PATCH 0639/3028] softfloat: Use return_nan in float_to_float MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 64edb23793..b694e38522 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1931,13 +1931,7 @@ static FloatParts float_to_float(FloatParts a, const FloatFmt *dstf, break; } } else if (is_nan(a.cls)) { - if (is_snan(a.cls)) { - float_raise(float_flag_invalid, s); - a = parts_silence_nan(a, s); - } - if (s->default_nan_mode) { - return parts_default_nan(s); - } + return return_nan(a, s); } return a; } From 57547c6023344f4b4562d7cadb1799a31c8a4549 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 19 Nov 2020 17:34:28 -0800 Subject: [PATCH 0640/3028] softfloat: fix return_nan vs default_nan_mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not call parts_silence_nan when default_nan_mode is in effect. This will avoid an assert in a later patch. Reviewed-by: Alex Bennée Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index b694e38522..6589f00b23 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -892,21 +892,16 @@ static float64 float64_round_pack_canonical(FloatParts p, float_status *s) static FloatParts return_nan(FloatParts a, float_status *s) { - switch (a.cls) { - case float_class_snan: + g_assert(is_nan(a.cls)); + if (is_snan(a.cls)) { float_raise(float_flag_invalid, s); - a = parts_silence_nan(a, s); - /* fall through */ - case float_class_qnan: - if (s->default_nan_mode) { - return parts_default_nan(s); + if (!s->default_nan_mode) { + return parts_silence_nan(a, s); } - break; - - default: - g_assert_not_reached(); + } else if (!s->default_nan_mode) { + return a; } - return a; + return parts_default_nan(s); } static FloatParts pick_nan(FloatParts a, FloatParts b, float_status *s) From e9e5534ff30a0441d2efa59004e3f815177e7c10 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 22 Oct 2020 09:17:46 -0700 Subject: [PATCH 0641/3028] target/mips: Set set_default_nan_mode with set_snan_bit_is_one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This behavior is currently hard-coded in parts_silence_nan, but setting this bit properly will allow this to be cleaned up. Reviewed-by: Alex Bennée Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- target/mips/fpu_helper.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/target/mips/fpu_helper.h b/target/mips/fpu_helper.h index 1c2d6d35a7..ad1116e8c1 100644 --- a/target/mips/fpu_helper.h +++ b/target/mips/fpu_helper.h @@ -27,8 +27,14 @@ static inline void restore_flush_mode(CPUMIPSState *env) static inline void restore_snan_bit_mode(CPUMIPSState *env) { - set_snan_bit_is_one((env->active_fpu.fcr31 & (1 << FCR31_NAN2008)) == 0, - &env->active_fpu.fp_status); + bool nan2008 = env->active_fpu.fcr31 & (1 << FCR31_NAN2008); + + /* + * With nan2008, SNaNs are silenced in the usual way. + * Before that, SNaNs are not silenced; default nans are produced. + */ + set_snan_bit_is_one(!nan2008, &env->active_fpu.fp_status); + set_default_nan_mode(!nan2008, &env->active_fpu.fp_status); } static inline void restore_fp_status(CPUMIPSState *env) From a777d6033447a916620846d3a65bc64a0617b574 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 22 Oct 2020 09:23:46 -0700 Subject: [PATCH 0642/3028] softfloat: Do not produce a default_nan from parts_silence_nan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Require default_nan_mode to be set instead. Reviewed-by: Alex Bennée Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat-specialize.c.inc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 96ed8c1a26..05cb2ee940 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -179,16 +179,15 @@ static FloatParts parts_default_nan(float_status *status) static FloatParts parts_silence_nan(FloatParts a, float_status *status) { g_assert(!no_signaling_nans(status)); -#if defined(TARGET_HPPA) - a.frac &= ~(1ULL << (DECOMPOSED_BINARY_POINT - 1)); - a.frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 2); -#else + g_assert(!status->default_nan_mode); + + /* The only snan_bit_is_one target without default_nan_mode is HPPA. */ if (snan_bit_is_one(status)) { - return parts_default_nan(status); + a.frac &= ~(1ULL << (DECOMPOSED_BINARY_POINT - 1)); + a.frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 2); } else { a.frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 1); } -#endif a.cls = float_class_qnan; return a; } From f8155c1d5236515359ef60a03f942b5b1fcb1c7c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 22 Oct 2020 09:50:03 -0700 Subject: [PATCH 0643/3028] softfloat: Rename FloatParts to FloatParts64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat-specialize.c.inc | 6 +- fpu/softfloat.c | 362 ++++++++++++++++----------------- 2 files changed, 184 insertions(+), 184 deletions(-) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 05cb2ee940..bb928b0b9f 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -129,7 +129,7 @@ static bool parts_is_snan_frac(uint64_t frac, float_status *status) | The pattern for a default generated deconstructed floating-point NaN. *----------------------------------------------------------------------------*/ -static FloatParts parts_default_nan(float_status *status) +static FloatParts64 parts_default_nan(float_status *status) { bool sign = 0; uint64_t frac; @@ -163,7 +163,7 @@ static FloatParts parts_default_nan(float_status *status) } #endif - return (FloatParts) { + return (FloatParts64) { .cls = float_class_qnan, .sign = sign, .exp = INT_MAX, @@ -176,7 +176,7 @@ static FloatParts parts_default_nan(float_status *status) | floating-point parts. *----------------------------------------------------------------------------*/ -static FloatParts parts_silence_nan(FloatParts a, float_status *status) +static FloatParts64 parts_silence_nan(FloatParts64 a, float_status *status) { g_assert(!no_signaling_nans(status)); g_assert(!status->default_nan_mode); diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 6589f00b23..27b51659c9 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -515,7 +515,7 @@ typedef struct { int32_t exp; FloatClass cls; bool sign; -} FloatParts; +} FloatParts64; #define DECOMPOSED_BINARY_POINT 63 #define DECOMPOSED_IMPLICIT_BIT (1ull << DECOMPOSED_BINARY_POINT) @@ -580,11 +580,11 @@ static const FloatFmt float64_params = { }; /* Unpack a float to parts, but do not canonicalize. */ -static inline FloatParts unpack_raw(FloatFmt fmt, uint64_t raw) +static inline FloatParts64 unpack_raw(FloatFmt fmt, uint64_t raw) { const int sign_pos = fmt.frac_size + fmt.exp_size; - return (FloatParts) { + return (FloatParts64) { .cls = float_class_unclassified, .sign = extract64(raw, sign_pos, 1), .exp = extract64(raw, fmt.frac_size, fmt.exp_size), @@ -592,50 +592,50 @@ static inline FloatParts unpack_raw(FloatFmt fmt, uint64_t raw) }; } -static inline FloatParts float16_unpack_raw(float16 f) +static inline FloatParts64 float16_unpack_raw(float16 f) { return unpack_raw(float16_params, f); } -static inline FloatParts bfloat16_unpack_raw(bfloat16 f) +static inline FloatParts64 bfloat16_unpack_raw(bfloat16 f) { return unpack_raw(bfloat16_params, f); } -static inline FloatParts float32_unpack_raw(float32 f) +static inline FloatParts64 float32_unpack_raw(float32 f) { return unpack_raw(float32_params, f); } -static inline FloatParts float64_unpack_raw(float64 f) +static inline FloatParts64 float64_unpack_raw(float64 f) { return unpack_raw(float64_params, f); } /* Pack a float from parts, but do not canonicalize. */ -static inline uint64_t pack_raw(FloatFmt fmt, FloatParts p) +static inline uint64_t pack_raw(FloatFmt fmt, FloatParts64 p) { const int sign_pos = fmt.frac_size + fmt.exp_size; uint64_t ret = deposit64(p.frac, fmt.frac_size, fmt.exp_size, p.exp); return deposit64(ret, sign_pos, 1, p.sign); } -static inline float16 float16_pack_raw(FloatParts p) +static inline float16 float16_pack_raw(FloatParts64 p) { return make_float16(pack_raw(float16_params, p)); } -static inline bfloat16 bfloat16_pack_raw(FloatParts p) +static inline bfloat16 bfloat16_pack_raw(FloatParts64 p) { return pack_raw(bfloat16_params, p); } -static inline float32 float32_pack_raw(FloatParts p) +static inline float32 float32_pack_raw(FloatParts64 p) { return make_float32(pack_raw(float32_params, p)); } -static inline float64 float64_pack_raw(FloatParts p) +static inline float64 float64_pack_raw(FloatParts64 p) { return make_float64(pack_raw(float64_params, p)); } @@ -651,7 +651,7 @@ static inline float64 float64_pack_raw(FloatParts p) #include "softfloat-specialize.c.inc" /* Canonicalize EXP and FRAC, setting CLS. */ -static FloatParts sf_canonicalize(FloatParts part, const FloatFmt *parm, +static FloatParts64 sf_canonicalize(FloatParts64 part, const FloatFmt *parm, float_status *status) { if (part.exp == parm->exp_max && !parm->arm_althp) { @@ -689,7 +689,7 @@ static FloatParts sf_canonicalize(FloatParts part, const FloatFmt *parm, * by EXP_BIAS and must be bounded by [EXP_MAX-1, 0]. */ -static FloatParts round_canonical(FloatParts p, float_status *s, +static FloatParts64 round_canonical(FloatParts64 p, float_status *s, const FloatFmt *parm) { const uint64_t frac_lsb = parm->frac_lsb; @@ -838,59 +838,59 @@ static FloatParts round_canonical(FloatParts p, float_status *s, } /* Explicit FloatFmt version */ -static FloatParts float16a_unpack_canonical(float16 f, float_status *s, +static FloatParts64 float16a_unpack_canonical(float16 f, float_status *s, const FloatFmt *params) { return sf_canonicalize(float16_unpack_raw(f), params, s); } -static FloatParts float16_unpack_canonical(float16 f, float_status *s) +static FloatParts64 float16_unpack_canonical(float16 f, float_status *s) { return float16a_unpack_canonical(f, s, &float16_params); } -static FloatParts bfloat16_unpack_canonical(bfloat16 f, float_status *s) +static FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s) { return sf_canonicalize(bfloat16_unpack_raw(f), &bfloat16_params, s); } -static float16 float16a_round_pack_canonical(FloatParts p, float_status *s, +static float16 float16a_round_pack_canonical(FloatParts64 p, float_status *s, const FloatFmt *params) { return float16_pack_raw(round_canonical(p, s, params)); } -static float16 float16_round_pack_canonical(FloatParts p, float_status *s) +static float16 float16_round_pack_canonical(FloatParts64 p, float_status *s) { return float16a_round_pack_canonical(p, s, &float16_params); } -static bfloat16 bfloat16_round_pack_canonical(FloatParts p, float_status *s) +static bfloat16 bfloat16_round_pack_canonical(FloatParts64 p, float_status *s) { return bfloat16_pack_raw(round_canonical(p, s, &bfloat16_params)); } -static FloatParts float32_unpack_canonical(float32 f, float_status *s) +static FloatParts64 float32_unpack_canonical(float32 f, float_status *s) { return sf_canonicalize(float32_unpack_raw(f), &float32_params, s); } -static float32 float32_round_pack_canonical(FloatParts p, float_status *s) +static float32 float32_round_pack_canonical(FloatParts64 p, float_status *s) { return float32_pack_raw(round_canonical(p, s, &float32_params)); } -static FloatParts float64_unpack_canonical(float64 f, float_status *s) +static FloatParts64 float64_unpack_canonical(float64 f, float_status *s) { return sf_canonicalize(float64_unpack_raw(f), &float64_params, s); } -static float64 float64_round_pack_canonical(FloatParts p, float_status *s) +static float64 float64_round_pack_canonical(FloatParts64 p, float_status *s) { return float64_pack_raw(round_canonical(p, s, &float64_params)); } -static FloatParts return_nan(FloatParts a, float_status *s) +static FloatParts64 return_nan(FloatParts64 a, float_status *s) { g_assert(is_nan(a.cls)); if (is_snan(a.cls)) { @@ -904,7 +904,7 @@ static FloatParts return_nan(FloatParts a, float_status *s) return parts_default_nan(s); } -static FloatParts pick_nan(FloatParts a, FloatParts b, float_status *s) +static FloatParts64 pick_nan(FloatParts64 a, FloatParts64 b, float_status *s) { if (is_snan(a.cls) || is_snan(b.cls)) { float_raise(float_flag_invalid, s); @@ -925,7 +925,7 @@ static FloatParts pick_nan(FloatParts a, FloatParts b, float_status *s) return a; } -static FloatParts pick_nan_muladd(FloatParts a, FloatParts b, FloatParts c, +static FloatParts64 pick_nan_muladd(FloatParts64 a, FloatParts64 b, FloatParts64 c, bool inf_zero, float_status *s) { int which; @@ -971,7 +971,7 @@ static FloatParts pick_nan_muladd(FloatParts a, FloatParts b, FloatParts c, * Arithmetic. */ -static FloatParts addsub_floats(FloatParts a, FloatParts b, bool subtract, +static FloatParts64 addsub_floats(FloatParts64 a, FloatParts64 b, bool subtract, float_status *s) { bool a_sign = a.sign; @@ -1062,18 +1062,18 @@ static FloatParts addsub_floats(FloatParts a, FloatParts b, bool subtract, float16 QEMU_FLATTEN float16_add(float16 a, float16 b, float_status *status) { - FloatParts pa = float16_unpack_canonical(a, status); - FloatParts pb = float16_unpack_canonical(b, status); - FloatParts pr = addsub_floats(pa, pb, false, status); + FloatParts64 pa = float16_unpack_canonical(a, status); + FloatParts64 pb = float16_unpack_canonical(b, status); + FloatParts64 pr = addsub_floats(pa, pb, false, status); return float16_round_pack_canonical(pr, status); } float16 QEMU_FLATTEN float16_sub(float16 a, float16 b, float_status *status) { - FloatParts pa = float16_unpack_canonical(a, status); - FloatParts pb = float16_unpack_canonical(b, status); - FloatParts pr = addsub_floats(pa, pb, true, status); + FloatParts64 pa = float16_unpack_canonical(a, status); + FloatParts64 pb = float16_unpack_canonical(b, status); + FloatParts64 pr = addsub_floats(pa, pb, true, status); return float16_round_pack_canonical(pr, status); } @@ -1081,9 +1081,9 @@ float16 QEMU_FLATTEN float16_sub(float16 a, float16 b, float_status *status) static float32 QEMU_SOFTFLOAT_ATTR soft_f32_addsub(float32 a, float32 b, bool subtract, float_status *status) { - FloatParts pa = float32_unpack_canonical(a, status); - FloatParts pb = float32_unpack_canonical(b, status); - FloatParts pr = addsub_floats(pa, pb, subtract, status); + FloatParts64 pa = float32_unpack_canonical(a, status); + FloatParts64 pb = float32_unpack_canonical(b, status); + FloatParts64 pr = addsub_floats(pa, pb, subtract, status); return float32_round_pack_canonical(pr, status); } @@ -1101,9 +1101,9 @@ static inline float32 soft_f32_sub(float32 a, float32 b, float_status *status) static float64 QEMU_SOFTFLOAT_ATTR soft_f64_addsub(float64 a, float64 b, bool subtract, float_status *status) { - FloatParts pa = float64_unpack_canonical(a, status); - FloatParts pb = float64_unpack_canonical(b, status); - FloatParts pr = addsub_floats(pa, pb, subtract, status); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 pr = addsub_floats(pa, pb, subtract, status); return float64_round_pack_canonical(pr, status); } @@ -1199,18 +1199,18 @@ float64_sub(float64 a, float64 b, float_status *s) */ bfloat16 QEMU_FLATTEN bfloat16_add(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts pa = bfloat16_unpack_canonical(a, status); - FloatParts pb = bfloat16_unpack_canonical(b, status); - FloatParts pr = addsub_floats(pa, pb, false, status); + FloatParts64 pa = bfloat16_unpack_canonical(a, status); + FloatParts64 pb = bfloat16_unpack_canonical(b, status); + FloatParts64 pr = addsub_floats(pa, pb, false, status); return bfloat16_round_pack_canonical(pr, status); } bfloat16 QEMU_FLATTEN bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts pa = bfloat16_unpack_canonical(a, status); - FloatParts pb = bfloat16_unpack_canonical(b, status); - FloatParts pr = addsub_floats(pa, pb, true, status); + FloatParts64 pa = bfloat16_unpack_canonical(a, status); + FloatParts64 pb = bfloat16_unpack_canonical(b, status); + FloatParts64 pr = addsub_floats(pa, pb, true, status); return bfloat16_round_pack_canonical(pr, status); } @@ -1221,7 +1221,7 @@ bfloat16 QEMU_FLATTEN bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status) * for Binary Floating-Point Arithmetic. */ -static FloatParts mul_floats(FloatParts a, FloatParts b, float_status *s) +static FloatParts64 mul_floats(FloatParts64 a, FloatParts64 b, float_status *s) { bool sign = a.sign ^ b.sign; @@ -1267,9 +1267,9 @@ static FloatParts mul_floats(FloatParts a, FloatParts b, float_status *s) float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status) { - FloatParts pa = float16_unpack_canonical(a, status); - FloatParts pb = float16_unpack_canonical(b, status); - FloatParts pr = mul_floats(pa, pb, status); + FloatParts64 pa = float16_unpack_canonical(a, status); + FloatParts64 pb = float16_unpack_canonical(b, status); + FloatParts64 pr = mul_floats(pa, pb, status); return float16_round_pack_canonical(pr, status); } @@ -1277,9 +1277,9 @@ float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status) static float32 QEMU_SOFTFLOAT_ATTR soft_f32_mul(float32 a, float32 b, float_status *status) { - FloatParts pa = float32_unpack_canonical(a, status); - FloatParts pb = float32_unpack_canonical(b, status); - FloatParts pr = mul_floats(pa, pb, status); + FloatParts64 pa = float32_unpack_canonical(a, status); + FloatParts64 pb = float32_unpack_canonical(b, status); + FloatParts64 pr = mul_floats(pa, pb, status); return float32_round_pack_canonical(pr, status); } @@ -1287,9 +1287,9 @@ soft_f32_mul(float32 a, float32 b, float_status *status) static float64 QEMU_SOFTFLOAT_ATTR soft_f64_mul(float64 a, float64 b, float_status *status) { - FloatParts pa = float64_unpack_canonical(a, status); - FloatParts pb = float64_unpack_canonical(b, status); - FloatParts pr = mul_floats(pa, pb, status); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 pr = mul_floats(pa, pb, status); return float64_round_pack_canonical(pr, status); } @@ -1325,9 +1325,9 @@ float64_mul(float64 a, float64 b, float_status *s) bfloat16 QEMU_FLATTEN bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts pa = bfloat16_unpack_canonical(a, status); - FloatParts pb = bfloat16_unpack_canonical(b, status); - FloatParts pr = mul_floats(pa, pb, status); + FloatParts64 pa = bfloat16_unpack_canonical(a, status); + FloatParts64 pb = bfloat16_unpack_canonical(b, status); + FloatParts64 pr = mul_floats(pa, pb, status); return bfloat16_round_pack_canonical(pr, status); } @@ -1344,7 +1344,7 @@ bfloat16 QEMU_FLATTEN bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) * NaNs.) */ -static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c, +static FloatParts64 muladd_floats(FloatParts64 a, FloatParts64 b, FloatParts64 c, int flags, float_status *s) { bool inf_zero, p_sign; @@ -1520,10 +1520,10 @@ static FloatParts muladd_floats(FloatParts a, FloatParts b, FloatParts c, float16 QEMU_FLATTEN float16_muladd(float16 a, float16 b, float16 c, int flags, float_status *status) { - FloatParts pa = float16_unpack_canonical(a, status); - FloatParts pb = float16_unpack_canonical(b, status); - FloatParts pc = float16_unpack_canonical(c, status); - FloatParts pr = muladd_floats(pa, pb, pc, flags, status); + FloatParts64 pa = float16_unpack_canonical(a, status); + FloatParts64 pb = float16_unpack_canonical(b, status); + FloatParts64 pc = float16_unpack_canonical(c, status); + FloatParts64 pr = muladd_floats(pa, pb, pc, flags, status); return float16_round_pack_canonical(pr, status); } @@ -1532,10 +1532,10 @@ static float32 QEMU_SOFTFLOAT_ATTR soft_f32_muladd(float32 a, float32 b, float32 c, int flags, float_status *status) { - FloatParts pa = float32_unpack_canonical(a, status); - FloatParts pb = float32_unpack_canonical(b, status); - FloatParts pc = float32_unpack_canonical(c, status); - FloatParts pr = muladd_floats(pa, pb, pc, flags, status); + FloatParts64 pa = float32_unpack_canonical(a, status); + FloatParts64 pb = float32_unpack_canonical(b, status); + FloatParts64 pc = float32_unpack_canonical(c, status); + FloatParts64 pr = muladd_floats(pa, pb, pc, flags, status); return float32_round_pack_canonical(pr, status); } @@ -1544,10 +1544,10 @@ static float64 QEMU_SOFTFLOAT_ATTR soft_f64_muladd(float64 a, float64 b, float64 c, int flags, float_status *status) { - FloatParts pa = float64_unpack_canonical(a, status); - FloatParts pb = float64_unpack_canonical(b, status); - FloatParts pc = float64_unpack_canonical(c, status); - FloatParts pr = muladd_floats(pa, pb, pc, flags, status); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 pc = float64_unpack_canonical(c, status); + FloatParts64 pr = muladd_floats(pa, pb, pc, flags, status); return float64_round_pack_canonical(pr, status); } @@ -1705,10 +1705,10 @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s) bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, int flags, float_status *status) { - FloatParts pa = bfloat16_unpack_canonical(a, status); - FloatParts pb = bfloat16_unpack_canonical(b, status); - FloatParts pc = bfloat16_unpack_canonical(c, status); - FloatParts pr = muladd_floats(pa, pb, pc, flags, status); + FloatParts64 pa = bfloat16_unpack_canonical(a, status); + FloatParts64 pb = bfloat16_unpack_canonical(b, status); + FloatParts64 pc = bfloat16_unpack_canonical(c, status); + FloatParts64 pr = muladd_floats(pa, pb, pc, flags, status); return bfloat16_round_pack_canonical(pr, status); } @@ -1719,7 +1719,7 @@ bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, * the IEC/IEEE Standard for Binary Floating-Point Arithmetic. */ -static FloatParts div_floats(FloatParts a, FloatParts b, float_status *s) +static FloatParts64 div_floats(FloatParts64 a, FloatParts64 b, float_status *s) { bool sign = a.sign ^ b.sign; @@ -1786,9 +1786,9 @@ static FloatParts div_floats(FloatParts a, FloatParts b, float_status *s) float16 float16_div(float16 a, float16 b, float_status *status) { - FloatParts pa = float16_unpack_canonical(a, status); - FloatParts pb = float16_unpack_canonical(b, status); - FloatParts pr = div_floats(pa, pb, status); + FloatParts64 pa = float16_unpack_canonical(a, status); + FloatParts64 pb = float16_unpack_canonical(b, status); + FloatParts64 pr = div_floats(pa, pb, status); return float16_round_pack_canonical(pr, status); } @@ -1796,9 +1796,9 @@ float16 float16_div(float16 a, float16 b, float_status *status) static float32 QEMU_SOFTFLOAT_ATTR soft_f32_div(float32 a, float32 b, float_status *status) { - FloatParts pa = float32_unpack_canonical(a, status); - FloatParts pb = float32_unpack_canonical(b, status); - FloatParts pr = div_floats(pa, pb, status); + FloatParts64 pa = float32_unpack_canonical(a, status); + FloatParts64 pb = float32_unpack_canonical(b, status); + FloatParts64 pr = div_floats(pa, pb, status); return float32_round_pack_canonical(pr, status); } @@ -1806,9 +1806,9 @@ soft_f32_div(float32 a, float32 b, float_status *status) static float64 QEMU_SOFTFLOAT_ATTR soft_f64_div(float64 a, float64 b, float_status *status) { - FloatParts pa = float64_unpack_canonical(a, status); - FloatParts pb = float64_unpack_canonical(b, status); - FloatParts pr = div_floats(pa, pb, status); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pb = float64_unpack_canonical(b, status); + FloatParts64 pr = div_floats(pa, pb, status); return float64_round_pack_canonical(pr, status); } @@ -1878,9 +1878,9 @@ float64_div(float64 a, float64 b, float_status *s) bfloat16 bfloat16_div(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts pa = bfloat16_unpack_canonical(a, status); - FloatParts pb = bfloat16_unpack_canonical(b, status); - FloatParts pr = div_floats(pa, pb, status); + FloatParts64 pa = bfloat16_unpack_canonical(a, status); + FloatParts64 pb = bfloat16_unpack_canonical(b, status); + FloatParts64 pr = div_floats(pa, pb, status); return bfloat16_round_pack_canonical(pr, status); } @@ -1896,7 +1896,7 @@ bfloat16 bfloat16_div(bfloat16 a, bfloat16 b, float_status *status) * invalid exceptions and handling the conversion on NaNs. */ -static FloatParts float_to_float(FloatParts a, const FloatFmt *dstf, +static FloatParts64 float_to_float(FloatParts64 a, const FloatFmt *dstf, float_status *s) { if (dstf->arm_althp) { @@ -1934,32 +1934,32 @@ static FloatParts float_to_float(FloatParts a, const FloatFmt *dstf, float32 float16_to_float32(float16 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts p = float16a_unpack_canonical(a, s, fmt16); - FloatParts pr = float_to_float(p, &float32_params, s); + FloatParts64 p = float16a_unpack_canonical(a, s, fmt16); + FloatParts64 pr = float_to_float(p, &float32_params, s); return float32_round_pack_canonical(pr, s); } float64 float16_to_float64(float16 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts p = float16a_unpack_canonical(a, s, fmt16); - FloatParts pr = float_to_float(p, &float64_params, s); + FloatParts64 p = float16a_unpack_canonical(a, s, fmt16); + FloatParts64 pr = float_to_float(p, &float64_params, s); return float64_round_pack_canonical(pr, s); } float16 float32_to_float16(float32 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts p = float32_unpack_canonical(a, s); - FloatParts pr = float_to_float(p, fmt16, s); + FloatParts64 p = float32_unpack_canonical(a, s); + FloatParts64 pr = float_to_float(p, fmt16, s); return float16a_round_pack_canonical(pr, s, fmt16); } static float64 QEMU_SOFTFLOAT_ATTR soft_float32_to_float64(float32 a, float_status *s) { - FloatParts p = float32_unpack_canonical(a, s); - FloatParts pr = float_to_float(p, &float64_params, s); + FloatParts64 p = float32_unpack_canonical(a, s); + FloatParts64 pr = float_to_float(p, &float64_params, s); return float64_round_pack_canonical(pr, s); } @@ -1982,43 +1982,43 @@ float64 float32_to_float64(float32 a, float_status *s) float16 float64_to_float16(float64 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts p = float64_unpack_canonical(a, s); - FloatParts pr = float_to_float(p, fmt16, s); + FloatParts64 p = float64_unpack_canonical(a, s); + FloatParts64 pr = float_to_float(p, fmt16, s); return float16a_round_pack_canonical(pr, s, fmt16); } float32 float64_to_float32(float64 a, float_status *s) { - FloatParts p = float64_unpack_canonical(a, s); - FloatParts pr = float_to_float(p, &float32_params, s); + FloatParts64 p = float64_unpack_canonical(a, s); + FloatParts64 pr = float_to_float(p, &float32_params, s); return float32_round_pack_canonical(pr, s); } float32 bfloat16_to_float32(bfloat16 a, float_status *s) { - FloatParts p = bfloat16_unpack_canonical(a, s); - FloatParts pr = float_to_float(p, &float32_params, s); + FloatParts64 p = bfloat16_unpack_canonical(a, s); + FloatParts64 pr = float_to_float(p, &float32_params, s); return float32_round_pack_canonical(pr, s); } float64 bfloat16_to_float64(bfloat16 a, float_status *s) { - FloatParts p = bfloat16_unpack_canonical(a, s); - FloatParts pr = float_to_float(p, &float64_params, s); + FloatParts64 p = bfloat16_unpack_canonical(a, s); + FloatParts64 pr = float_to_float(p, &float64_params, s); return float64_round_pack_canonical(pr, s); } bfloat16 float32_to_bfloat16(float32 a, float_status *s) { - FloatParts p = float32_unpack_canonical(a, s); - FloatParts pr = float_to_float(p, &bfloat16_params, s); + FloatParts64 p = float32_unpack_canonical(a, s); + FloatParts64 pr = float_to_float(p, &bfloat16_params, s); return bfloat16_round_pack_canonical(pr, s); } bfloat16 float64_to_bfloat16(float64 a, float_status *s) { - FloatParts p = float64_unpack_canonical(a, s); - FloatParts pr = float_to_float(p, &bfloat16_params, s); + FloatParts64 p = float64_unpack_canonical(a, s); + FloatParts64 pr = float_to_float(p, &bfloat16_params, s); return bfloat16_round_pack_canonical(pr, s); } @@ -2029,7 +2029,7 @@ bfloat16 float64_to_bfloat16(float64 a, float_status *s) * Arithmetic. */ -static FloatParts round_to_int(FloatParts a, FloatRoundMode rmode, +static FloatParts64 round_to_int(FloatParts64 a, FloatRoundMode rmode, int scale, float_status *s) { switch (a.cls) { @@ -2132,22 +2132,22 @@ static FloatParts round_to_int(FloatParts a, FloatRoundMode rmode, float16 float16_round_to_int(float16 a, float_status *s) { - FloatParts pa = float16_unpack_canonical(a, s); - FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s); + FloatParts64 pa = float16_unpack_canonical(a, s); + FloatParts64 pr = round_to_int(pa, s->float_rounding_mode, 0, s); return float16_round_pack_canonical(pr, s); } float32 float32_round_to_int(float32 a, float_status *s) { - FloatParts pa = float32_unpack_canonical(a, s); - FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s); + FloatParts64 pa = float32_unpack_canonical(a, s); + FloatParts64 pr = round_to_int(pa, s->float_rounding_mode, 0, s); return float32_round_pack_canonical(pr, s); } float64 float64_round_to_int(float64 a, float_status *s) { - FloatParts pa = float64_unpack_canonical(a, s); - FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s); + FloatParts64 pa = float64_unpack_canonical(a, s); + FloatParts64 pr = round_to_int(pa, s->float_rounding_mode, 0, s); return float64_round_pack_canonical(pr, s); } @@ -2158,8 +2158,8 @@ float64 float64_round_to_int(float64 a, float_status *s) bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s) { - FloatParts pa = bfloat16_unpack_canonical(a, s); - FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s); + FloatParts64 pa = bfloat16_unpack_canonical(a, s); + FloatParts64 pr = round_to_int(pa, s->float_rounding_mode, 0, s); return bfloat16_round_pack_canonical(pr, s); } @@ -2174,13 +2174,13 @@ bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s) * is returned. */ -static int64_t round_to_int_and_pack(FloatParts in, FloatRoundMode rmode, +static int64_t round_to_int_and_pack(FloatParts64 in, FloatRoundMode rmode, int scale, int64_t min, int64_t max, float_status *s) { uint64_t r; int orig_flags = get_float_exception_flags(s); - FloatParts p = round_to_int(in, rmode, scale, s); + FloatParts64 p = round_to_int(in, rmode, scale, s); switch (p.cls) { case float_class_snan: @@ -2452,12 +2452,12 @@ int64_t bfloat16_to_int64_round_to_zero(bfloat16 a, float_status *s) * flag. */ -static uint64_t round_to_uint_and_pack(FloatParts in, FloatRoundMode rmode, +static uint64_t round_to_uint_and_pack(FloatParts64 in, FloatRoundMode rmode, int scale, uint64_t max, float_status *s) { int orig_flags = get_float_exception_flags(s); - FloatParts p = round_to_int(in, rmode, scale, s); + FloatParts64 p = round_to_int(in, rmode, scale, s); uint64_t r; switch (p.cls) { @@ -2726,9 +2726,9 @@ uint64_t bfloat16_to_uint64_round_to_zero(bfloat16 a, float_status *s) * to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. */ -static FloatParts int_to_float(int64_t a, int scale, float_status *status) +static FloatParts64 int_to_float(int64_t a, int scale, float_status *status) { - FloatParts r = { .sign = false }; + FloatParts64 r = { .sign = false }; if (a == 0) { r.cls = float_class_zero; @@ -2753,7 +2753,7 @@ static FloatParts int_to_float(int64_t a, int scale, float_status *status) float16 int64_to_float16_scalbn(int64_t a, int scale, float_status *status) { - FloatParts pa = int_to_float(a, scale, status); + FloatParts64 pa = int_to_float(a, scale, status); return float16_round_pack_canonical(pa, status); } @@ -2789,7 +2789,7 @@ float16 int8_to_float16(int8_t a, float_status *status) float32 int64_to_float32_scalbn(int64_t a, int scale, float_status *status) { - FloatParts pa = int_to_float(a, scale, status); + FloatParts64 pa = int_to_float(a, scale, status); return float32_round_pack_canonical(pa, status); } @@ -2820,7 +2820,7 @@ float32 int16_to_float32(int16_t a, float_status *status) float64 int64_to_float64_scalbn(int64_t a, int scale, float_status *status) { - FloatParts pa = int_to_float(a, scale, status); + FloatParts64 pa = int_to_float(a, scale, status); return float64_round_pack_canonical(pa, status); } @@ -2856,7 +2856,7 @@ float64 int16_to_float64(int16_t a, float_status *status) bfloat16 int64_to_bfloat16_scalbn(int64_t a, int scale, float_status *status) { - FloatParts pa = int_to_float(a, scale, status); + FloatParts64 pa = int_to_float(a, scale, status); return bfloat16_round_pack_canonical(pa, status); } @@ -2893,9 +2893,9 @@ bfloat16 int16_to_bfloat16(int16_t a, float_status *status) * IEC/IEEE Standard for Binary Floating-Point Arithmetic. */ -static FloatParts uint_to_float(uint64_t a, int scale, float_status *status) +static FloatParts64 uint_to_float(uint64_t a, int scale, float_status *status) { - FloatParts r = { .sign = false }; + FloatParts64 r = { .sign = false }; int shift; if (a == 0) { @@ -2913,7 +2913,7 @@ static FloatParts uint_to_float(uint64_t a, int scale, float_status *status) float16 uint64_to_float16_scalbn(uint64_t a, int scale, float_status *status) { - FloatParts pa = uint_to_float(a, scale, status); + FloatParts64 pa = uint_to_float(a, scale, status); return float16_round_pack_canonical(pa, status); } @@ -2949,7 +2949,7 @@ float16 uint8_to_float16(uint8_t a, float_status *status) float32 uint64_to_float32_scalbn(uint64_t a, int scale, float_status *status) { - FloatParts pa = uint_to_float(a, scale, status); + FloatParts64 pa = uint_to_float(a, scale, status); return float32_round_pack_canonical(pa, status); } @@ -2980,7 +2980,7 @@ float32 uint16_to_float32(uint16_t a, float_status *status) float64 uint64_to_float64_scalbn(uint64_t a, int scale, float_status *status) { - FloatParts pa = uint_to_float(a, scale, status); + FloatParts64 pa = uint_to_float(a, scale, status); return float64_round_pack_canonical(pa, status); } @@ -3016,7 +3016,7 @@ float64 uint16_to_float64(uint16_t a, float_status *status) bfloat16 uint64_to_bfloat16_scalbn(uint64_t a, int scale, float_status *status) { - FloatParts pa = uint_to_float(a, scale, status); + FloatParts64 pa = uint_to_float(a, scale, status); return bfloat16_round_pack_canonical(pa, status); } @@ -3061,7 +3061,7 @@ bfloat16 uint16_to_bfloat16(uint16_t a, float_status *status) * minnummag() and maxnummag() functions correspond to minNumMag() * and minNumMag() from the IEEE-754 2008. */ -static FloatParts minmax_floats(FloatParts a, FloatParts b, bool ismin, +static FloatParts64 minmax_floats(FloatParts64 a, FloatParts64 b, bool ismin, bool ieee, bool ismag, float_status *s) { if (unlikely(is_nan(a.cls) || is_nan(b.cls))) { @@ -3136,9 +3136,9 @@ static FloatParts minmax_floats(FloatParts a, FloatParts b, bool ismin, float ## sz float ## sz ## _ ## name(float ## sz a, float ## sz b, \ float_status *s) \ { \ - FloatParts pa = float ## sz ## _unpack_canonical(a, s); \ - FloatParts pb = float ## sz ## _unpack_canonical(b, s); \ - FloatParts pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ + FloatParts64 pa = float ## sz ## _unpack_canonical(a, s); \ + FloatParts64 pb = float ## sz ## _unpack_canonical(b, s); \ + FloatParts64 pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ \ return float ## sz ## _round_pack_canonical(pr, s); \ } @@ -3169,9 +3169,9 @@ MINMAX(64, maxnummag, false, true, true) #define BF16_MINMAX(name, ismin, isiee, ismag) \ bfloat16 bfloat16_ ## name(bfloat16 a, bfloat16 b, float_status *s) \ { \ - FloatParts pa = bfloat16_unpack_canonical(a, s); \ - FloatParts pb = bfloat16_unpack_canonical(b, s); \ - FloatParts pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ + FloatParts64 pa = bfloat16_unpack_canonical(a, s); \ + FloatParts64 pb = bfloat16_unpack_canonical(b, s); \ + FloatParts64 pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ \ return bfloat16_round_pack_canonical(pr, s); \ } @@ -3186,7 +3186,7 @@ BF16_MINMAX(maxnummag, false, true, true) #undef BF16_MINMAX /* Floating point compare */ -static FloatRelation compare_floats(FloatParts a, FloatParts b, bool is_quiet, +static FloatRelation compare_floats(FloatParts64 a, FloatParts64 b, bool is_quiet, float_status *s) { if (is_nan(a.cls) || is_nan(b.cls)) { @@ -3247,8 +3247,8 @@ static FloatRelation compare_floats(FloatParts a, FloatParts b, bool is_quiet, static int attr \ name(float ## sz a, float ## sz b, bool is_quiet, float_status *s) \ { \ - FloatParts pa = float ## sz ## _unpack_canonical(a, s); \ - FloatParts pb = float ## sz ## _unpack_canonical(b, s); \ + FloatParts64 pa = float ## sz ## _unpack_canonical(a, s); \ + FloatParts64 pb = float ## sz ## _unpack_canonical(b, s); \ return compare_floats(pa, pb, is_quiet, s); \ } @@ -3349,8 +3349,8 @@ FloatRelation float64_compare_quiet(float64 a, float64 b, float_status *s) static FloatRelation QEMU_FLATTEN soft_bf16_compare(bfloat16 a, bfloat16 b, bool is_quiet, float_status *s) { - FloatParts pa = bfloat16_unpack_canonical(a, s); - FloatParts pb = bfloat16_unpack_canonical(b, s); + FloatParts64 pa = bfloat16_unpack_canonical(a, s); + FloatParts64 pb = bfloat16_unpack_canonical(b, s); return compare_floats(pa, pb, is_quiet, s); } @@ -3365,16 +3365,16 @@ FloatRelation bfloat16_compare_quiet(bfloat16 a, bfloat16 b, float_status *s) } /* Multiply A by 2 raised to the power N. */ -static FloatParts scalbn_decomposed(FloatParts a, int n, float_status *s) +static FloatParts64 scalbn_decomposed(FloatParts64 a, int n, float_status *s) { if (unlikely(is_nan(a.cls))) { return return_nan(a, s); } if (a.cls == float_class_normal) { - /* The largest float type (even though not supported by FloatParts) + /* The largest float type (even though not supported by FloatParts64) * is float128, which has a 15 bit exponent. Bounding N to 16 bits * still allows rounding to infinity, without allowing overflow - * within the int32_t that backs FloatParts.exp. + * within the int32_t that backs FloatParts64.exp. */ n = MIN(MAX(n, -0x10000), 0x10000); a.exp += n; @@ -3384,29 +3384,29 @@ static FloatParts scalbn_decomposed(FloatParts a, int n, float_status *s) float16 float16_scalbn(float16 a, int n, float_status *status) { - FloatParts pa = float16_unpack_canonical(a, status); - FloatParts pr = scalbn_decomposed(pa, n, status); + FloatParts64 pa = float16_unpack_canonical(a, status); + FloatParts64 pr = scalbn_decomposed(pa, n, status); return float16_round_pack_canonical(pr, status); } float32 float32_scalbn(float32 a, int n, float_status *status) { - FloatParts pa = float32_unpack_canonical(a, status); - FloatParts pr = scalbn_decomposed(pa, n, status); + FloatParts64 pa = float32_unpack_canonical(a, status); + FloatParts64 pr = scalbn_decomposed(pa, n, status); return float32_round_pack_canonical(pr, status); } float64 float64_scalbn(float64 a, int n, float_status *status) { - FloatParts pa = float64_unpack_canonical(a, status); - FloatParts pr = scalbn_decomposed(pa, n, status); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pr = scalbn_decomposed(pa, n, status); return float64_round_pack_canonical(pr, status); } bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status) { - FloatParts pa = bfloat16_unpack_canonical(a, status); - FloatParts pr = scalbn_decomposed(pa, n, status); + FloatParts64 pa = bfloat16_unpack_canonical(a, status); + FloatParts64 pr = scalbn_decomposed(pa, n, status); return bfloat16_round_pack_canonical(pr, status); } @@ -3422,7 +3422,7 @@ bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status) * especially for 64 bit floats. */ -static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p) +static FloatParts64 sqrt_float(FloatParts64 a, float_status *s, const FloatFmt *p) { uint64_t a_frac, r_frac, s_frac; int bit, last_bit; @@ -3482,24 +3482,24 @@ static FloatParts sqrt_float(FloatParts a, float_status *s, const FloatFmt *p) float16 QEMU_FLATTEN float16_sqrt(float16 a, float_status *status) { - FloatParts pa = float16_unpack_canonical(a, status); - FloatParts pr = sqrt_float(pa, status, &float16_params); + FloatParts64 pa = float16_unpack_canonical(a, status); + FloatParts64 pr = sqrt_float(pa, status, &float16_params); return float16_round_pack_canonical(pr, status); } static float32 QEMU_SOFTFLOAT_ATTR soft_f32_sqrt(float32 a, float_status *status) { - FloatParts pa = float32_unpack_canonical(a, status); - FloatParts pr = sqrt_float(pa, status, &float32_params); + FloatParts64 pa = float32_unpack_canonical(a, status); + FloatParts64 pr = sqrt_float(pa, status, &float32_params); return float32_round_pack_canonical(pr, status); } static float64 QEMU_SOFTFLOAT_ATTR soft_f64_sqrt(float64 a, float_status *status) { - FloatParts pa = float64_unpack_canonical(a, status); - FloatParts pr = sqrt_float(pa, status, &float64_params); + FloatParts64 pa = float64_unpack_canonical(a, status); + FloatParts64 pr = sqrt_float(pa, status, &float64_params); return float64_round_pack_canonical(pr, status); } @@ -3559,8 +3559,8 @@ float64 QEMU_FLATTEN float64_sqrt(float64 xa, float_status *s) bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status) { - FloatParts pa = bfloat16_unpack_canonical(a, status); - FloatParts pr = sqrt_float(pa, status, &bfloat16_params); + FloatParts64 pa = bfloat16_unpack_canonical(a, status); + FloatParts64 pr = sqrt_float(pa, status, &bfloat16_params); return bfloat16_round_pack_canonical(pr, status); } @@ -3570,28 +3570,28 @@ bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status) float16 float16_default_nan(float_status *status) { - FloatParts p = parts_default_nan(status); + FloatParts64 p = parts_default_nan(status); p.frac >>= float16_params.frac_shift; return float16_pack_raw(p); } float32 float32_default_nan(float_status *status) { - FloatParts p = parts_default_nan(status); + FloatParts64 p = parts_default_nan(status); p.frac >>= float32_params.frac_shift; return float32_pack_raw(p); } float64 float64_default_nan(float_status *status) { - FloatParts p = parts_default_nan(status); + FloatParts64 p = parts_default_nan(status); p.frac >>= float64_params.frac_shift; return float64_pack_raw(p); } float128 float128_default_nan(float_status *status) { - FloatParts p = parts_default_nan(status); + FloatParts64 p = parts_default_nan(status); float128 r; /* Extrapolate from the choices made by parts_default_nan to fill @@ -3608,7 +3608,7 @@ float128 float128_default_nan(float_status *status) bfloat16 bfloat16_default_nan(float_status *status) { - FloatParts p = parts_default_nan(status); + FloatParts64 p = parts_default_nan(status); p.frac >>= bfloat16_params.frac_shift; return bfloat16_pack_raw(p); } @@ -3619,7 +3619,7 @@ bfloat16 bfloat16_default_nan(float_status *status) float16 float16_silence_nan(float16 a, float_status *status) { - FloatParts p = float16_unpack_raw(a); + FloatParts64 p = float16_unpack_raw(a); p.frac <<= float16_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= float16_params.frac_shift; @@ -3628,7 +3628,7 @@ float16 float16_silence_nan(float16 a, float_status *status) float32 float32_silence_nan(float32 a, float_status *status) { - FloatParts p = float32_unpack_raw(a); + FloatParts64 p = float32_unpack_raw(a); p.frac <<= float32_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= float32_params.frac_shift; @@ -3637,7 +3637,7 @@ float32 float32_silence_nan(float32 a, float_status *status) float64 float64_silence_nan(float64 a, float_status *status) { - FloatParts p = float64_unpack_raw(a); + FloatParts64 p = float64_unpack_raw(a); p.frac <<= float64_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= float64_params.frac_shift; @@ -3646,7 +3646,7 @@ float64 float64_silence_nan(float64 a, float_status *status) bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) { - FloatParts p = bfloat16_unpack_raw(a); + FloatParts64 p = bfloat16_unpack_raw(a); p.frac <<= bfloat16_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= bfloat16_params.frac_shift; @@ -3658,7 +3658,7 @@ bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) | input-denormal exception and return zero. Otherwise just return the value. *----------------------------------------------------------------------------*/ -static bool parts_squash_denormal(FloatParts p, float_status *status) +static bool parts_squash_denormal(FloatParts64 p, float_status *status) { if (p.exp == 0 && p.frac != 0) { float_raise(float_flag_input_denormal, status); @@ -3671,7 +3671,7 @@ static bool parts_squash_denormal(FloatParts p, float_status *status) float16 float16_squash_input_denormal(float16 a, float_status *status) { if (status->flush_inputs_to_zero) { - FloatParts p = float16_unpack_raw(a); + FloatParts64 p = float16_unpack_raw(a); if (parts_squash_denormal(p, status)) { return float16_set_sign(float16_zero, p.sign); } @@ -3682,7 +3682,7 @@ float16 float16_squash_input_denormal(float16 a, float_status *status) float32 float32_squash_input_denormal(float32 a, float_status *status) { if (status->flush_inputs_to_zero) { - FloatParts p = float32_unpack_raw(a); + FloatParts64 p = float32_unpack_raw(a); if (parts_squash_denormal(p, status)) { return float32_set_sign(float32_zero, p.sign); } @@ -3693,7 +3693,7 @@ float32 float32_squash_input_denormal(float32 a, float_status *status) float64 float64_squash_input_denormal(float64 a, float_status *status) { if (status->flush_inputs_to_zero) { - FloatParts p = float64_unpack_raw(a); + FloatParts64 p = float64_unpack_raw(a); if (parts_squash_denormal(p, status)) { return float64_set_sign(float64_zero, p.sign); } @@ -3704,7 +3704,7 @@ float64 float64_squash_input_denormal(float64 a, float_status *status) bfloat16 bfloat16_squash_input_denormal(bfloat16 a, float_status *status) { if (status->flush_inputs_to_zero) { - FloatParts p = bfloat16_unpack_raw(a); + FloatParts64 p = bfloat16_unpack_raw(a); if (parts_squash_denormal(p, status)) { return bfloat16_set_sign(bfloat16_zero, p.sign); } From aaffb7bf1c5509c2d29372f23e57f5f508d02021 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 13:34:19 -0700 Subject: [PATCH 0644/3028] softfloat: Move type-specific pack/unpack routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation from moving sf_canonicalize. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat.c | 109 +++++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 27b51659c9..398a068b58 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -837,59 +837,6 @@ static FloatParts64 round_canonical(FloatParts64 p, float_status *s, return p; } -/* Explicit FloatFmt version */ -static FloatParts64 float16a_unpack_canonical(float16 f, float_status *s, - const FloatFmt *params) -{ - return sf_canonicalize(float16_unpack_raw(f), params, s); -} - -static FloatParts64 float16_unpack_canonical(float16 f, float_status *s) -{ - return float16a_unpack_canonical(f, s, &float16_params); -} - -static FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s) -{ - return sf_canonicalize(bfloat16_unpack_raw(f), &bfloat16_params, s); -} - -static float16 float16a_round_pack_canonical(FloatParts64 p, float_status *s, - const FloatFmt *params) -{ - return float16_pack_raw(round_canonical(p, s, params)); -} - -static float16 float16_round_pack_canonical(FloatParts64 p, float_status *s) -{ - return float16a_round_pack_canonical(p, s, &float16_params); -} - -static bfloat16 bfloat16_round_pack_canonical(FloatParts64 p, float_status *s) -{ - return bfloat16_pack_raw(round_canonical(p, s, &bfloat16_params)); -} - -static FloatParts64 float32_unpack_canonical(float32 f, float_status *s) -{ - return sf_canonicalize(float32_unpack_raw(f), &float32_params, s); -} - -static float32 float32_round_pack_canonical(FloatParts64 p, float_status *s) -{ - return float32_pack_raw(round_canonical(p, s, &float32_params)); -} - -static FloatParts64 float64_unpack_canonical(float64 f, float_status *s) -{ - return sf_canonicalize(float64_unpack_raw(f), &float64_params, s); -} - -static float64 float64_round_pack_canonical(FloatParts64 p, float_status *s) -{ - return float64_pack_raw(round_canonical(p, s, &float64_params)); -} - static FloatParts64 return_nan(FloatParts64 a, float_status *s) { g_assert(is_nan(a.cls)); @@ -964,6 +911,62 @@ static FloatParts64 pick_nan_muladd(FloatParts64 a, FloatParts64 b, FloatParts64 return a; } +/* + * Pack/unpack routines with a specific FloatFmt. + */ + +static FloatParts64 float16a_unpack_canonical(float16 f, float_status *s, + const FloatFmt *params) +{ + return sf_canonicalize(float16_unpack_raw(f), params, s); +} + +static FloatParts64 float16_unpack_canonical(float16 f, float_status *s) +{ + return float16a_unpack_canonical(f, s, &float16_params); +} + +static FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s) +{ + return sf_canonicalize(bfloat16_unpack_raw(f), &bfloat16_params, s); +} + +static float16 float16a_round_pack_canonical(FloatParts64 p, float_status *s, + const FloatFmt *params) +{ + return float16_pack_raw(round_canonical(p, s, params)); +} + +static float16 float16_round_pack_canonical(FloatParts64 p, float_status *s) +{ + return float16a_round_pack_canonical(p, s, &float16_params); +} + +static bfloat16 bfloat16_round_pack_canonical(FloatParts64 p, float_status *s) +{ + return bfloat16_pack_raw(round_canonical(p, s, &bfloat16_params)); +} + +static FloatParts64 float32_unpack_canonical(float32 f, float_status *s) +{ + return sf_canonicalize(float32_unpack_raw(f), &float32_params, s); +} + +static float32 float32_round_pack_canonical(FloatParts64 p, float_status *s) +{ + return float32_pack_raw(round_canonical(p, s, &float32_params)); +} + +static FloatParts64 float64_unpack_canonical(float64 f, float_status *s) +{ + return sf_canonicalize(float64_unpack_raw(f), &float64_params, s); +} + +static float64 float64_round_pack_canonical(FloatParts64 p, float_status *s) +{ + return float64_pack_raw(round_canonical(p, s, &float64_params)); +} + /* * Returns the result of adding or subtracting the values of the * floating-point values `a' and `b'. The operation is performed From 0fc07cade25088b7449c7af5a002ea731bee154d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 14:00:33 -0700 Subject: [PATCH 0645/3028] softfloat: Use pointers with parts_default_nan At the same time, rename to parts64_default_nan and add a macro for parts_default_nan. This will be flushed out once 128-bit support is added. Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat-specialize.c.inc | 4 +-- fpu/softfloat.c | 47 +++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index bb928b0b9f..47c3652d63 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -129,7 +129,7 @@ static bool parts_is_snan_frac(uint64_t frac, float_status *status) | The pattern for a default generated deconstructed floating-point NaN. *----------------------------------------------------------------------------*/ -static FloatParts64 parts_default_nan(float_status *status) +static void parts64_default_nan(FloatParts64 *p, float_status *status) { bool sign = 0; uint64_t frac; @@ -163,7 +163,7 @@ static FloatParts64 parts_default_nan(float_status *status) } #endif - return (FloatParts64) { + *p = (FloatParts64) { .cls = float_class_qnan, .sign = sign, .exp = INT_MAX, diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 398a068b58..c7f95961cf 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -650,6 +650,8 @@ static inline float64 float64_pack_raw(FloatParts64 p) *----------------------------------------------------------------------------*/ #include "softfloat-specialize.c.inc" +#define parts_default_nan parts64_default_nan + /* Canonicalize EXP and FRAC, setting CLS. */ static FloatParts64 sf_canonicalize(FloatParts64 part, const FloatFmt *parm, float_status *status) @@ -848,7 +850,8 @@ static FloatParts64 return_nan(FloatParts64 a, float_status *s) } else if (!s->default_nan_mode) { return a; } - return parts_default_nan(s); + parts_default_nan(&a, s); + return a; } static FloatParts64 pick_nan(FloatParts64 a, FloatParts64 b, float_status *s) @@ -858,7 +861,7 @@ static FloatParts64 pick_nan(FloatParts64 a, FloatParts64 b, float_status *s) } if (s->default_nan_mode) { - return parts_default_nan(s); + parts_default_nan(&a, s); } else { if (pickNaN(a.cls, b.cls, a.frac > b.frac || @@ -900,7 +903,8 @@ static FloatParts64 pick_nan_muladd(FloatParts64 a, FloatParts64 b, FloatParts64 a = c; break; case 3: - return parts_default_nan(s); + parts_default_nan(&a, s); + break; default: g_assert_not_reached(); } @@ -1011,7 +1015,7 @@ static FloatParts64 addsub_floats(FloatParts64 a, FloatParts64 b, bool subtract, if (a.cls == float_class_inf) { if (b.cls == float_class_inf) { float_raise(float_flag_invalid, s); - return parts_default_nan(s); + parts_default_nan(&a, s); } return a; } @@ -1254,7 +1258,8 @@ static FloatParts64 mul_floats(FloatParts64 a, FloatParts64 b, float_status *s) if ((a.cls == float_class_inf && b.cls == float_class_zero) || (a.cls == float_class_zero && b.cls == float_class_inf)) { float_raise(float_flag_invalid, s); - return parts_default_nan(s); + parts_default_nan(&a, s); + return a; } /* Multiply by 0 or Inf */ if (a.cls == float_class_inf || a.cls == float_class_zero) { @@ -1372,7 +1377,8 @@ static FloatParts64 muladd_floats(FloatParts64 a, FloatParts64 b, FloatParts64 c if (inf_zero) { float_raise(float_flag_invalid, s); - return parts_default_nan(s); + parts_default_nan(&a, s); + return a; } if (flags & float_muladd_negate_c) { @@ -1396,11 +1402,11 @@ static FloatParts64 muladd_floats(FloatParts64 a, FloatParts64 b, FloatParts64 c if (c.cls == float_class_inf) { if (p_class == float_class_inf && p_sign != c.sign) { float_raise(float_flag_invalid, s); - return parts_default_nan(s); + parts_default_nan(&c, s); } else { c.sign ^= sign_flip; - return c; } + return c; } if (p_class == float_class_inf) { @@ -1764,7 +1770,8 @@ static FloatParts64 div_floats(FloatParts64 a, FloatParts64 b, float_status *s) && (a.cls == float_class_inf || a.cls == float_class_zero)) { float_raise(float_flag_invalid, s); - return parts_default_nan(s); + parts_default_nan(&a, s); + return a; } /* Inf / x or 0 / x */ if (a.cls == float_class_inf || a.cls == float_class_zero) { @@ -3438,7 +3445,8 @@ static FloatParts64 sqrt_float(FloatParts64 a, float_status *s, const FloatFmt * } if (a.sign) { float_raise(float_flag_invalid, s); - return parts_default_nan(s); + parts_default_nan(&a, s); + return a; } if (a.cls == float_class_inf) { return a; /* sqrt(+inf) = +inf */ @@ -3573,30 +3581,37 @@ bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status) float16 float16_default_nan(float_status *status) { - FloatParts64 p = parts_default_nan(status); + FloatParts64 p; + + parts_default_nan(&p, status); p.frac >>= float16_params.frac_shift; return float16_pack_raw(p); } float32 float32_default_nan(float_status *status) { - FloatParts64 p = parts_default_nan(status); + FloatParts64 p; + + parts_default_nan(&p, status); p.frac >>= float32_params.frac_shift; return float32_pack_raw(p); } float64 float64_default_nan(float_status *status) { - FloatParts64 p = parts_default_nan(status); + FloatParts64 p; + + parts_default_nan(&p, status); p.frac >>= float64_params.frac_shift; return float64_pack_raw(p); } float128 float128_default_nan(float_status *status) { - FloatParts64 p = parts_default_nan(status); + FloatParts64 p; float128 r; + parts_default_nan(&p, status); /* Extrapolate from the choices made by parts_default_nan to fill * in the quad-floating format. If the low bit is set, assume we * want to set all non-snan bits. @@ -3611,7 +3626,9 @@ float128 float128_default_nan(float_status *status) bfloat16 bfloat16_default_nan(float_status *status) { - FloatParts64 p = parts_default_nan(status); + FloatParts64 p; + + parts_default_nan(&p, status); p.frac >>= bfloat16_params.frac_shift; return bfloat16_pack_raw(p); } From d8fdd17280a7dfe7f2bc95a5a76ea241e844020d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 14:17:19 -0700 Subject: [PATCH 0646/3028] softfloat: Use pointers with unpack_raw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time, rename to unpack_raw64. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- fpu/softfloat.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index c7f95961cf..5ff9368012 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -580,36 +580,45 @@ static const FloatFmt float64_params = { }; /* Unpack a float to parts, but do not canonicalize. */ -static inline FloatParts64 unpack_raw(FloatFmt fmt, uint64_t raw) +static void unpack_raw64(FloatParts64 *r, const FloatFmt *fmt, uint64_t raw) { - const int sign_pos = fmt.frac_size + fmt.exp_size; + const int f_size = fmt->frac_size; + const int e_size = fmt->exp_size; - return (FloatParts64) { + *r = (FloatParts64) { .cls = float_class_unclassified, - .sign = extract64(raw, sign_pos, 1), - .exp = extract64(raw, fmt.frac_size, fmt.exp_size), - .frac = extract64(raw, 0, fmt.frac_size), + .sign = extract64(raw, f_size + e_size, 1), + .exp = extract64(raw, f_size, e_size), + .frac = extract64(raw, 0, f_size) }; } static inline FloatParts64 float16_unpack_raw(float16 f) { - return unpack_raw(float16_params, f); + FloatParts64 p; + unpack_raw64(&p, &float16_params, f); + return p; } static inline FloatParts64 bfloat16_unpack_raw(bfloat16 f) { - return unpack_raw(bfloat16_params, f); + FloatParts64 p; + unpack_raw64(&p, &bfloat16_params, f); + return p; } static inline FloatParts64 float32_unpack_raw(float32 f) { - return unpack_raw(float32_params, f); + FloatParts64 p; + unpack_raw64(&p, &float32_params, f); + return p; } static inline FloatParts64 float64_unpack_raw(float64 f) { - return unpack_raw(float64_params, f); + FloatParts64 p; + unpack_raw64(&p, &float64_params, f); + return p; } /* Pack a float from parts, but do not canonicalize. */ From 3dddb203bc570b5284d604d689c84c6b207a5317 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 15:16:14 -0700 Subject: [PATCH 0647/3028] softfloat: Use pointers with ftype_unpack_raw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 76 +++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 5ff9368012..5a736a46cf 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -593,32 +593,24 @@ static void unpack_raw64(FloatParts64 *r, const FloatFmt *fmt, uint64_t raw) }; } -static inline FloatParts64 float16_unpack_raw(float16 f) +static inline void float16_unpack_raw(FloatParts64 *p, float16 f) { - FloatParts64 p; - unpack_raw64(&p, &float16_params, f); - return p; + unpack_raw64(p, &float16_params, f); } -static inline FloatParts64 bfloat16_unpack_raw(bfloat16 f) +static inline void bfloat16_unpack_raw(FloatParts64 *p, bfloat16 f) { - FloatParts64 p; - unpack_raw64(&p, &bfloat16_params, f); - return p; + unpack_raw64(p, &bfloat16_params, f); } -static inline FloatParts64 float32_unpack_raw(float32 f) +static inline void float32_unpack_raw(FloatParts64 *p, float32 f) { - FloatParts64 p; - unpack_raw64(&p, &float32_params, f); - return p; + unpack_raw64(p, &float32_params, f); } -static inline FloatParts64 float64_unpack_raw(float64 f) +static inline void float64_unpack_raw(FloatParts64 *p, float64 f) { - FloatParts64 p; - unpack_raw64(&p, &float64_params, f); - return p; + unpack_raw64(p, &float64_params, f); } /* Pack a float from parts, but do not canonicalize. */ @@ -931,7 +923,10 @@ static FloatParts64 pick_nan_muladd(FloatParts64 a, FloatParts64 b, FloatParts64 static FloatParts64 float16a_unpack_canonical(float16 f, float_status *s, const FloatFmt *params) { - return sf_canonicalize(float16_unpack_raw(f), params, s); + FloatParts64 p; + + float16_unpack_raw(&p, f); + return sf_canonicalize(p, params, s); } static FloatParts64 float16_unpack_canonical(float16 f, float_status *s) @@ -941,7 +936,10 @@ static FloatParts64 float16_unpack_canonical(float16 f, float_status *s) static FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s) { - return sf_canonicalize(bfloat16_unpack_raw(f), &bfloat16_params, s); + FloatParts64 p; + + bfloat16_unpack_raw(&p, f); + return sf_canonicalize(p, &bfloat16_params, s); } static float16 float16a_round_pack_canonical(FloatParts64 p, float_status *s, @@ -962,7 +960,10 @@ static bfloat16 bfloat16_round_pack_canonical(FloatParts64 p, float_status *s) static FloatParts64 float32_unpack_canonical(float32 f, float_status *s) { - return sf_canonicalize(float32_unpack_raw(f), &float32_params, s); + FloatParts64 p; + + float32_unpack_raw(&p, f); + return sf_canonicalize(p, &float32_params, s); } static float32 float32_round_pack_canonical(FloatParts64 p, float_status *s) @@ -972,7 +973,10 @@ static float32 float32_round_pack_canonical(FloatParts64 p, float_status *s) static FloatParts64 float64_unpack_canonical(float64 f, float_status *s) { - return sf_canonicalize(float64_unpack_raw(f), &float64_params, s); + FloatParts64 p; + + float64_unpack_raw(&p, f); + return sf_canonicalize(p, &float64_params, s); } static float64 float64_round_pack_canonical(FloatParts64 p, float_status *s) @@ -3648,7 +3652,9 @@ bfloat16 bfloat16_default_nan(float_status *status) float16 float16_silence_nan(float16 a, float_status *status) { - FloatParts64 p = float16_unpack_raw(a); + FloatParts64 p; + + float16_unpack_raw(&p, a); p.frac <<= float16_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= float16_params.frac_shift; @@ -3657,7 +3663,9 @@ float16 float16_silence_nan(float16 a, float_status *status) float32 float32_silence_nan(float32 a, float_status *status) { - FloatParts64 p = float32_unpack_raw(a); + FloatParts64 p; + + float32_unpack_raw(&p, a); p.frac <<= float32_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= float32_params.frac_shift; @@ -3666,7 +3674,9 @@ float32 float32_silence_nan(float32 a, float_status *status) float64 float64_silence_nan(float64 a, float_status *status) { - FloatParts64 p = float64_unpack_raw(a); + FloatParts64 p; + + float64_unpack_raw(&p, a); p.frac <<= float64_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= float64_params.frac_shift; @@ -3675,7 +3685,9 @@ float64 float64_silence_nan(float64 a, float_status *status) bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) { - FloatParts64 p = bfloat16_unpack_raw(a); + FloatParts64 p; + + bfloat16_unpack_raw(&p, a); p.frac <<= bfloat16_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= bfloat16_params.frac_shift; @@ -3700,7 +3712,9 @@ static bool parts_squash_denormal(FloatParts64 p, float_status *status) float16 float16_squash_input_denormal(float16 a, float_status *status) { if (status->flush_inputs_to_zero) { - FloatParts64 p = float16_unpack_raw(a); + FloatParts64 p; + + float16_unpack_raw(&p, a); if (parts_squash_denormal(p, status)) { return float16_set_sign(float16_zero, p.sign); } @@ -3711,7 +3725,9 @@ float16 float16_squash_input_denormal(float16 a, float_status *status) float32 float32_squash_input_denormal(float32 a, float_status *status) { if (status->flush_inputs_to_zero) { - FloatParts64 p = float32_unpack_raw(a); + FloatParts64 p; + + float32_unpack_raw(&p, a); if (parts_squash_denormal(p, status)) { return float32_set_sign(float32_zero, p.sign); } @@ -3722,7 +3738,9 @@ float32 float32_squash_input_denormal(float32 a, float_status *status) float64 float64_squash_input_denormal(float64 a, float_status *status) { if (status->flush_inputs_to_zero) { - FloatParts64 p = float64_unpack_raw(a); + FloatParts64 p; + + float64_unpack_raw(&p, a); if (parts_squash_denormal(p, status)) { return float64_set_sign(float64_zero, p.sign); } @@ -3733,7 +3751,9 @@ float64 float64_squash_input_denormal(float64 a, float_status *status) bfloat16 bfloat16_squash_input_denormal(bfloat16 a, float_status *status) { if (status->flush_inputs_to_zero) { - FloatParts64 p = bfloat16_unpack_raw(a); + FloatParts64 p; + + bfloat16_unpack_raw(&p, a); if (parts_squash_denormal(p, status)) { return bfloat16_set_sign(bfloat16_zero, p.sign); } From 9e4af58c244e48352f57c0c02dfbd3bcbaa5e3bd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 15:22:08 -0700 Subject: [PATCH 0648/3028] softfloat: Use pointers with pack_raw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time, rename to pack_raw64. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 5a736a46cf..b59b777bca 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -614,31 +614,36 @@ static inline void float64_unpack_raw(FloatParts64 *p, float64 f) } /* Pack a float from parts, but do not canonicalize. */ -static inline uint64_t pack_raw(FloatFmt fmt, FloatParts64 p) +static uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) { - const int sign_pos = fmt.frac_size + fmt.exp_size; - uint64_t ret = deposit64(p.frac, fmt.frac_size, fmt.exp_size, p.exp); - return deposit64(ret, sign_pos, 1, p.sign); + const int f_size = fmt->frac_size; + const int e_size = fmt->exp_size; + uint64_t ret; + + ret = (uint64_t)p->sign << (f_size + e_size); + ret = deposit64(ret, f_size, e_size, p->exp); + ret = deposit64(ret, 0, f_size, p->frac); + return ret; } static inline float16 float16_pack_raw(FloatParts64 p) { - return make_float16(pack_raw(float16_params, p)); + return make_float16(pack_raw64(&p, &float16_params)); } static inline bfloat16 bfloat16_pack_raw(FloatParts64 p) { - return pack_raw(bfloat16_params, p); + return pack_raw64(&p, &bfloat16_params); } static inline float32 float32_pack_raw(FloatParts64 p) { - return make_float32(pack_raw(float32_params, p)); + return make_float32(pack_raw64(&p, &float32_params)); } static inline float64 float64_pack_raw(FloatParts64 p) { - return make_float64(pack_raw(float64_params, p)); + return make_float64(pack_raw64(&p, &float64_params)); } /*---------------------------------------------------------------------------- From 71fd178eaef94a5ad9db6bf093566f3ca4a1c7b4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 15:25:33 -0700 Subject: [PATCH 0649/3028] softfloat: Use pointers with ftype_pack_raw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index b59b777bca..e02cbafaf9 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -626,24 +626,24 @@ static uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) return ret; } -static inline float16 float16_pack_raw(FloatParts64 p) +static inline float16 float16_pack_raw(const FloatParts64 *p) { - return make_float16(pack_raw64(&p, &float16_params)); + return make_float16(pack_raw64(p, &float16_params)); } -static inline bfloat16 bfloat16_pack_raw(FloatParts64 p) +static inline bfloat16 bfloat16_pack_raw(const FloatParts64 *p) { - return pack_raw64(&p, &bfloat16_params); + return pack_raw64(p, &bfloat16_params); } -static inline float32 float32_pack_raw(FloatParts64 p) +static inline float32 float32_pack_raw(const FloatParts64 *p) { - return make_float32(pack_raw64(&p, &float32_params)); + return make_float32(pack_raw64(p, &float32_params)); } -static inline float64 float64_pack_raw(FloatParts64 p) +static inline float64 float64_pack_raw(const FloatParts64 *p) { - return make_float64(pack_raw64(&p, &float64_params)); + return make_float64(pack_raw64(p, &float64_params)); } /*---------------------------------------------------------------------------- @@ -950,7 +950,8 @@ static FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s) static float16 float16a_round_pack_canonical(FloatParts64 p, float_status *s, const FloatFmt *params) { - return float16_pack_raw(round_canonical(p, s, params)); + p = round_canonical(p, s, params); + return float16_pack_raw(&p); } static float16 float16_round_pack_canonical(FloatParts64 p, float_status *s) @@ -960,7 +961,8 @@ static float16 float16_round_pack_canonical(FloatParts64 p, float_status *s) static bfloat16 bfloat16_round_pack_canonical(FloatParts64 p, float_status *s) { - return bfloat16_pack_raw(round_canonical(p, s, &bfloat16_params)); + p = round_canonical(p, s, &bfloat16_params); + return bfloat16_pack_raw(&p); } static FloatParts64 float32_unpack_canonical(float32 f, float_status *s) @@ -973,7 +975,8 @@ static FloatParts64 float32_unpack_canonical(float32 f, float_status *s) static float32 float32_round_pack_canonical(FloatParts64 p, float_status *s) { - return float32_pack_raw(round_canonical(p, s, &float32_params)); + p = round_canonical(p, s, &float32_params); + return float32_pack_raw(&p); } static FloatParts64 float64_unpack_canonical(float64 f, float_status *s) @@ -986,7 +989,8 @@ static FloatParts64 float64_unpack_canonical(float64 f, float_status *s) static float64 float64_round_pack_canonical(FloatParts64 p, float_status *s) { - return float64_pack_raw(round_canonical(p, s, &float64_params)); + p = round_canonical(p, s, &float64_params); + return float64_pack_raw(&p); } /* @@ -3603,7 +3607,7 @@ float16 float16_default_nan(float_status *status) parts_default_nan(&p, status); p.frac >>= float16_params.frac_shift; - return float16_pack_raw(p); + return float16_pack_raw(&p); } float32 float32_default_nan(float_status *status) @@ -3612,7 +3616,7 @@ float32 float32_default_nan(float_status *status) parts_default_nan(&p, status); p.frac >>= float32_params.frac_shift; - return float32_pack_raw(p); + return float32_pack_raw(&p); } float64 float64_default_nan(float_status *status) @@ -3621,7 +3625,7 @@ float64 float64_default_nan(float_status *status) parts_default_nan(&p, status); p.frac >>= float64_params.frac_shift; - return float64_pack_raw(p); + return float64_pack_raw(&p); } float128 float128_default_nan(float_status *status) @@ -3648,7 +3652,7 @@ bfloat16 bfloat16_default_nan(float_status *status) parts_default_nan(&p, status); p.frac >>= bfloat16_params.frac_shift; - return bfloat16_pack_raw(p); + return bfloat16_pack_raw(&p); } /*---------------------------------------------------------------------------- @@ -3663,7 +3667,7 @@ float16 float16_silence_nan(float16 a, float_status *status) p.frac <<= float16_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= float16_params.frac_shift; - return float16_pack_raw(p); + return float16_pack_raw(&p); } float32 float32_silence_nan(float32 a, float_status *status) @@ -3674,7 +3678,7 @@ float32 float32_silence_nan(float32 a, float_status *status) p.frac <<= float32_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= float32_params.frac_shift; - return float32_pack_raw(p); + return float32_pack_raw(&p); } float64 float64_silence_nan(float64 a, float_status *status) @@ -3685,7 +3689,7 @@ float64 float64_silence_nan(float64 a, float_status *status) p.frac <<= float64_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= float64_params.frac_shift; - return float64_pack_raw(p); + return float64_pack_raw(&p); } bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) @@ -3696,7 +3700,7 @@ bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) p.frac <<= bfloat16_params.frac_shift; p = parts_silence_nan(p, status); p.frac >>= bfloat16_params.frac_shift; - return bfloat16_pack_raw(p); + return bfloat16_pack_raw(&p); } /*---------------------------------------------------------------------------- From 98e256fc702f1a65baeb5d3b768e6a264c2d5748 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 15:32:34 -0700 Subject: [PATCH 0650/3028] softfloat: Use pointers with ftype_unpack_canonical MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 509 ++++++++++++++++++++++++++++++------------------ 1 file changed, 320 insertions(+), 189 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index e02cbafaf9..e53d4a138f 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -925,26 +925,24 @@ static FloatParts64 pick_nan_muladd(FloatParts64 a, FloatParts64 b, FloatParts64 * Pack/unpack routines with a specific FloatFmt. */ -static FloatParts64 float16a_unpack_canonical(float16 f, float_status *s, - const FloatFmt *params) +static void float16a_unpack_canonical(FloatParts64 *p, float16 f, + float_status *s, const FloatFmt *params) { - FloatParts64 p; - - float16_unpack_raw(&p, f); - return sf_canonicalize(p, params, s); + float16_unpack_raw(p, f); + *p = sf_canonicalize(*p, params, s); } -static FloatParts64 float16_unpack_canonical(float16 f, float_status *s) +static void float16_unpack_canonical(FloatParts64 *p, float16 f, + float_status *s) { - return float16a_unpack_canonical(f, s, &float16_params); + float16a_unpack_canonical(p, f, s, &float16_params); } -static FloatParts64 bfloat16_unpack_canonical(bfloat16 f, float_status *s) +static void bfloat16_unpack_canonical(FloatParts64 *p, bfloat16 f, + float_status *s) { - FloatParts64 p; - - bfloat16_unpack_raw(&p, f); - return sf_canonicalize(p, &bfloat16_params, s); + bfloat16_unpack_raw(p, f); + *p = sf_canonicalize(*p, &bfloat16_params, s); } static float16 float16a_round_pack_canonical(FloatParts64 p, float_status *s, @@ -965,12 +963,11 @@ static bfloat16 bfloat16_round_pack_canonical(FloatParts64 p, float_status *s) return bfloat16_pack_raw(&p); } -static FloatParts64 float32_unpack_canonical(float32 f, float_status *s) +static void float32_unpack_canonical(FloatParts64 *p, float32 f, + float_status *s) { - FloatParts64 p; - - float32_unpack_raw(&p, f); - return sf_canonicalize(p, &float32_params, s); + float32_unpack_raw(p, f); + *p = sf_canonicalize(*p, &float32_params, s); } static float32 float32_round_pack_canonical(FloatParts64 p, float_status *s) @@ -979,12 +976,11 @@ static float32 float32_round_pack_canonical(FloatParts64 p, float_status *s) return float32_pack_raw(&p); } -static FloatParts64 float64_unpack_canonical(float64 f, float_status *s) +static void float64_unpack_canonical(FloatParts64 *p, float64 f, + float_status *s) { - FloatParts64 p; - - float64_unpack_raw(&p, f); - return sf_canonicalize(p, &float64_params, s); + float64_unpack_raw(p, f); + *p = sf_canonicalize(*p, &float64_params, s); } static float64 float64_round_pack_canonical(FloatParts64 p, float_status *s) @@ -1091,18 +1087,22 @@ static FloatParts64 addsub_floats(FloatParts64 a, FloatParts64 b, bool subtract, float16 QEMU_FLATTEN float16_add(float16 a, float16 b, float_status *status) { - FloatParts64 pa = float16_unpack_canonical(a, status); - FloatParts64 pb = float16_unpack_canonical(b, status); - FloatParts64 pr = addsub_floats(pa, pb, false, status); + FloatParts64 pa, pb, pr; + + float16_unpack_canonical(&pa, a, status); + float16_unpack_canonical(&pb, b, status); + pr = addsub_floats(pa, pb, false, status); return float16_round_pack_canonical(pr, status); } float16 QEMU_FLATTEN float16_sub(float16 a, float16 b, float_status *status) { - FloatParts64 pa = float16_unpack_canonical(a, status); - FloatParts64 pb = float16_unpack_canonical(b, status); - FloatParts64 pr = addsub_floats(pa, pb, true, status); + FloatParts64 pa, pb, pr; + + float16_unpack_canonical(&pa, a, status); + float16_unpack_canonical(&pb, b, status); + pr = addsub_floats(pa, pb, true, status); return float16_round_pack_canonical(pr, status); } @@ -1110,9 +1110,11 @@ float16 QEMU_FLATTEN float16_sub(float16 a, float16 b, float_status *status) static float32 QEMU_SOFTFLOAT_ATTR soft_f32_addsub(float32 a, float32 b, bool subtract, float_status *status) { - FloatParts64 pa = float32_unpack_canonical(a, status); - FloatParts64 pb = float32_unpack_canonical(b, status); - FloatParts64 pr = addsub_floats(pa, pb, subtract, status); + FloatParts64 pa, pb, pr; + + float32_unpack_canonical(&pa, a, status); + float32_unpack_canonical(&pb, b, status); + pr = addsub_floats(pa, pb, subtract, status); return float32_round_pack_canonical(pr, status); } @@ -1130,9 +1132,11 @@ static inline float32 soft_f32_sub(float32 a, float32 b, float_status *status) static float64 QEMU_SOFTFLOAT_ATTR soft_f64_addsub(float64 a, float64 b, bool subtract, float_status *status) { - FloatParts64 pa = float64_unpack_canonical(a, status); - FloatParts64 pb = float64_unpack_canonical(b, status); - FloatParts64 pr = addsub_floats(pa, pb, subtract, status); + FloatParts64 pa, pb, pr; + + float64_unpack_canonical(&pa, a, status); + float64_unpack_canonical(&pb, b, status); + pr = addsub_floats(pa, pb, subtract, status); return float64_round_pack_canonical(pr, status); } @@ -1228,18 +1232,22 @@ float64_sub(float64 a, float64 b, float_status *s) */ bfloat16 QEMU_FLATTEN bfloat16_add(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts64 pa = bfloat16_unpack_canonical(a, status); - FloatParts64 pb = bfloat16_unpack_canonical(b, status); - FloatParts64 pr = addsub_floats(pa, pb, false, status); + FloatParts64 pa, pb, pr; + + bfloat16_unpack_canonical(&pa, a, status); + bfloat16_unpack_canonical(&pb, b, status); + pr = addsub_floats(pa, pb, false, status); return bfloat16_round_pack_canonical(pr, status); } bfloat16 QEMU_FLATTEN bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts64 pa = bfloat16_unpack_canonical(a, status); - FloatParts64 pb = bfloat16_unpack_canonical(b, status); - FloatParts64 pr = addsub_floats(pa, pb, true, status); + FloatParts64 pa, pb, pr; + + bfloat16_unpack_canonical(&pa, a, status); + bfloat16_unpack_canonical(&pb, b, status); + pr = addsub_floats(pa, pb, true, status); return bfloat16_round_pack_canonical(pr, status); } @@ -1297,9 +1305,11 @@ static FloatParts64 mul_floats(FloatParts64 a, FloatParts64 b, float_status *s) float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status) { - FloatParts64 pa = float16_unpack_canonical(a, status); - FloatParts64 pb = float16_unpack_canonical(b, status); - FloatParts64 pr = mul_floats(pa, pb, status); + FloatParts64 pa, pb, pr; + + float16_unpack_canonical(&pa, a, status); + float16_unpack_canonical(&pb, b, status); + pr = mul_floats(pa, pb, status); return float16_round_pack_canonical(pr, status); } @@ -1307,9 +1317,11 @@ float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status) static float32 QEMU_SOFTFLOAT_ATTR soft_f32_mul(float32 a, float32 b, float_status *status) { - FloatParts64 pa = float32_unpack_canonical(a, status); - FloatParts64 pb = float32_unpack_canonical(b, status); - FloatParts64 pr = mul_floats(pa, pb, status); + FloatParts64 pa, pb, pr; + + float32_unpack_canonical(&pa, a, status); + float32_unpack_canonical(&pb, b, status); + pr = mul_floats(pa, pb, status); return float32_round_pack_canonical(pr, status); } @@ -1317,9 +1329,11 @@ soft_f32_mul(float32 a, float32 b, float_status *status) static float64 QEMU_SOFTFLOAT_ATTR soft_f64_mul(float64 a, float64 b, float_status *status) { - FloatParts64 pa = float64_unpack_canonical(a, status); - FloatParts64 pb = float64_unpack_canonical(b, status); - FloatParts64 pr = mul_floats(pa, pb, status); + FloatParts64 pa, pb, pr; + + float64_unpack_canonical(&pa, a, status); + float64_unpack_canonical(&pb, b, status); + pr = mul_floats(pa, pb, status); return float64_round_pack_canonical(pr, status); } @@ -1355,9 +1369,11 @@ float64_mul(float64 a, float64 b, float_status *s) bfloat16 QEMU_FLATTEN bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts64 pa = bfloat16_unpack_canonical(a, status); - FloatParts64 pb = bfloat16_unpack_canonical(b, status); - FloatParts64 pr = mul_floats(pa, pb, status); + FloatParts64 pa, pb, pr; + + bfloat16_unpack_canonical(&pa, a, status); + bfloat16_unpack_canonical(&pb, b, status); + pr = mul_floats(pa, pb, status); return bfloat16_round_pack_canonical(pr, status); } @@ -1551,10 +1567,12 @@ static FloatParts64 muladd_floats(FloatParts64 a, FloatParts64 b, FloatParts64 c float16 QEMU_FLATTEN float16_muladd(float16 a, float16 b, float16 c, int flags, float_status *status) { - FloatParts64 pa = float16_unpack_canonical(a, status); - FloatParts64 pb = float16_unpack_canonical(b, status); - FloatParts64 pc = float16_unpack_canonical(c, status); - FloatParts64 pr = muladd_floats(pa, pb, pc, flags, status); + FloatParts64 pa, pb, pc, pr; + + float16_unpack_canonical(&pa, a, status); + float16_unpack_canonical(&pb, b, status); + float16_unpack_canonical(&pc, c, status); + pr = muladd_floats(pa, pb, pc, flags, status); return float16_round_pack_canonical(pr, status); } @@ -1563,10 +1581,12 @@ static float32 QEMU_SOFTFLOAT_ATTR soft_f32_muladd(float32 a, float32 b, float32 c, int flags, float_status *status) { - FloatParts64 pa = float32_unpack_canonical(a, status); - FloatParts64 pb = float32_unpack_canonical(b, status); - FloatParts64 pc = float32_unpack_canonical(c, status); - FloatParts64 pr = muladd_floats(pa, pb, pc, flags, status); + FloatParts64 pa, pb, pc, pr; + + float32_unpack_canonical(&pa, a, status); + float32_unpack_canonical(&pb, b, status); + float32_unpack_canonical(&pc, c, status); + pr = muladd_floats(pa, pb, pc, flags, status); return float32_round_pack_canonical(pr, status); } @@ -1575,10 +1595,12 @@ static float64 QEMU_SOFTFLOAT_ATTR soft_f64_muladd(float64 a, float64 b, float64 c, int flags, float_status *status) { - FloatParts64 pa = float64_unpack_canonical(a, status); - FloatParts64 pb = float64_unpack_canonical(b, status); - FloatParts64 pc = float64_unpack_canonical(c, status); - FloatParts64 pr = muladd_floats(pa, pb, pc, flags, status); + FloatParts64 pa, pb, pc, pr; + + float64_unpack_canonical(&pa, a, status); + float64_unpack_canonical(&pb, b, status); + float64_unpack_canonical(&pc, c, status); + pr = muladd_floats(pa, pb, pc, flags, status); return float64_round_pack_canonical(pr, status); } @@ -1736,10 +1758,12 @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s) bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, int flags, float_status *status) { - FloatParts64 pa = bfloat16_unpack_canonical(a, status); - FloatParts64 pb = bfloat16_unpack_canonical(b, status); - FloatParts64 pc = bfloat16_unpack_canonical(c, status); - FloatParts64 pr = muladd_floats(pa, pb, pc, flags, status); + FloatParts64 pa, pb, pc, pr; + + bfloat16_unpack_canonical(&pa, a, status); + bfloat16_unpack_canonical(&pb, b, status); + bfloat16_unpack_canonical(&pc, c, status); + pr = muladd_floats(pa, pb, pc, flags, status); return bfloat16_round_pack_canonical(pr, status); } @@ -1818,9 +1842,11 @@ static FloatParts64 div_floats(FloatParts64 a, FloatParts64 b, float_status *s) float16 float16_div(float16 a, float16 b, float_status *status) { - FloatParts64 pa = float16_unpack_canonical(a, status); - FloatParts64 pb = float16_unpack_canonical(b, status); - FloatParts64 pr = div_floats(pa, pb, status); + FloatParts64 pa, pb, pr; + + float16_unpack_canonical(&pa, a, status); + float16_unpack_canonical(&pb, b, status); + pr = div_floats(pa, pb, status); return float16_round_pack_canonical(pr, status); } @@ -1828,9 +1854,11 @@ float16 float16_div(float16 a, float16 b, float_status *status) static float32 QEMU_SOFTFLOAT_ATTR soft_f32_div(float32 a, float32 b, float_status *status) { - FloatParts64 pa = float32_unpack_canonical(a, status); - FloatParts64 pb = float32_unpack_canonical(b, status); - FloatParts64 pr = div_floats(pa, pb, status); + FloatParts64 pa, pb, pr; + + float32_unpack_canonical(&pa, a, status); + float32_unpack_canonical(&pb, b, status); + pr = div_floats(pa, pb, status); return float32_round_pack_canonical(pr, status); } @@ -1838,9 +1866,11 @@ soft_f32_div(float32 a, float32 b, float_status *status) static float64 QEMU_SOFTFLOAT_ATTR soft_f64_div(float64 a, float64 b, float_status *status) { - FloatParts64 pa = float64_unpack_canonical(a, status); - FloatParts64 pb = float64_unpack_canonical(b, status); - FloatParts64 pr = div_floats(pa, pb, status); + FloatParts64 pa, pb, pr; + + float64_unpack_canonical(&pa, a, status); + float64_unpack_canonical(&pb, b, status); + pr = div_floats(pa, pb, status); return float64_round_pack_canonical(pr, status); } @@ -1910,9 +1940,11 @@ float64_div(float64 a, float64 b, float_status *s) bfloat16 bfloat16_div(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts64 pa = bfloat16_unpack_canonical(a, status); - FloatParts64 pb = bfloat16_unpack_canonical(b, status); - FloatParts64 pr = div_floats(pa, pb, status); + FloatParts64 pa, pb, pr; + + bfloat16_unpack_canonical(&pa, a, status); + bfloat16_unpack_canonical(&pb, b, status); + pr = div_floats(pa, pb, status); return bfloat16_round_pack_canonical(pr, status); } @@ -1966,32 +1998,40 @@ static FloatParts64 float_to_float(FloatParts64 a, const FloatFmt *dstf, float32 float16_to_float32(float16 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts64 p = float16a_unpack_canonical(a, s, fmt16); - FloatParts64 pr = float_to_float(p, &float32_params, s); + FloatParts64 pa, pr; + + float16a_unpack_canonical(&pa, a, s, fmt16); + pr = float_to_float(pa, &float32_params, s); return float32_round_pack_canonical(pr, s); } float64 float16_to_float64(float16 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts64 p = float16a_unpack_canonical(a, s, fmt16); - FloatParts64 pr = float_to_float(p, &float64_params, s); + FloatParts64 pa, pr; + + float16a_unpack_canonical(&pa, a, s, fmt16); + pr = float_to_float(pa, &float64_params, s); return float64_round_pack_canonical(pr, s); } float16 float32_to_float16(float32 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts64 p = float32_unpack_canonical(a, s); - FloatParts64 pr = float_to_float(p, fmt16, s); + FloatParts64 pa, pr; + + float32_unpack_canonical(&pa, a, s); + pr = float_to_float(pa, fmt16, s); return float16a_round_pack_canonical(pr, s, fmt16); } static float64 QEMU_SOFTFLOAT_ATTR soft_float32_to_float64(float32 a, float_status *s) { - FloatParts64 p = float32_unpack_canonical(a, s); - FloatParts64 pr = float_to_float(p, &float64_params, s); + FloatParts64 pa, pr; + + float32_unpack_canonical(&pa, a, s); + pr = float_to_float(pa, &float64_params, s); return float64_round_pack_canonical(pr, s); } @@ -2014,43 +2054,55 @@ float64 float32_to_float64(float32 a, float_status *s) float16 float64_to_float16(float64 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts64 p = float64_unpack_canonical(a, s); - FloatParts64 pr = float_to_float(p, fmt16, s); + FloatParts64 pa, pr; + + float64_unpack_canonical(&pa, a, s); + pr = float_to_float(pa, fmt16, s); return float16a_round_pack_canonical(pr, s, fmt16); } float32 float64_to_float32(float64 a, float_status *s) { - FloatParts64 p = float64_unpack_canonical(a, s); - FloatParts64 pr = float_to_float(p, &float32_params, s); + FloatParts64 pa, pr; + + float64_unpack_canonical(&pa, a, s); + pr = float_to_float(pa, &float32_params, s); return float32_round_pack_canonical(pr, s); } float32 bfloat16_to_float32(bfloat16 a, float_status *s) { - FloatParts64 p = bfloat16_unpack_canonical(a, s); - FloatParts64 pr = float_to_float(p, &float32_params, s); + FloatParts64 pa, pr; + + bfloat16_unpack_canonical(&pa, a, s); + pr = float_to_float(pa, &float32_params, s); return float32_round_pack_canonical(pr, s); } float64 bfloat16_to_float64(bfloat16 a, float_status *s) { - FloatParts64 p = bfloat16_unpack_canonical(a, s); - FloatParts64 pr = float_to_float(p, &float64_params, s); + FloatParts64 pa, pr; + + bfloat16_unpack_canonical(&pa, a, s); + pr = float_to_float(pa, &float64_params, s); return float64_round_pack_canonical(pr, s); } bfloat16 float32_to_bfloat16(float32 a, float_status *s) { - FloatParts64 p = float32_unpack_canonical(a, s); - FloatParts64 pr = float_to_float(p, &bfloat16_params, s); + FloatParts64 pa, pr; + + float32_unpack_canonical(&pa, a, s); + pr = float_to_float(pa, &bfloat16_params, s); return bfloat16_round_pack_canonical(pr, s); } bfloat16 float64_to_bfloat16(float64 a, float_status *s) { - FloatParts64 p = float64_unpack_canonical(a, s); - FloatParts64 pr = float_to_float(p, &bfloat16_params, s); + FloatParts64 pa, pr; + + float64_unpack_canonical(&pa, a, s); + pr = float_to_float(pa, &bfloat16_params, s); return bfloat16_round_pack_canonical(pr, s); } @@ -2164,22 +2216,28 @@ static FloatParts64 round_to_int(FloatParts64 a, FloatRoundMode rmode, float16 float16_round_to_int(float16 a, float_status *s) { - FloatParts64 pa = float16_unpack_canonical(a, s); - FloatParts64 pr = round_to_int(pa, s->float_rounding_mode, 0, s); + FloatParts64 pa, pr; + + float16_unpack_canonical(&pa, a, s); + pr = round_to_int(pa, s->float_rounding_mode, 0, s); return float16_round_pack_canonical(pr, s); } float32 float32_round_to_int(float32 a, float_status *s) { - FloatParts64 pa = float32_unpack_canonical(a, s); - FloatParts64 pr = round_to_int(pa, s->float_rounding_mode, 0, s); + FloatParts64 pa, pr; + + float32_unpack_canonical(&pa, a, s); + pr = round_to_int(pa, s->float_rounding_mode, 0, s); return float32_round_pack_canonical(pr, s); } float64 float64_round_to_int(float64 a, float_status *s) { - FloatParts64 pa = float64_unpack_canonical(a, s); - FloatParts64 pr = round_to_int(pa, s->float_rounding_mode, 0, s); + FloatParts64 pa, pr; + + float64_unpack_canonical(&pa, a, s); + pr = round_to_int(pa, s->float_rounding_mode, 0, s); return float64_round_pack_canonical(pr, s); } @@ -2190,8 +2248,10 @@ float64 float64_round_to_int(float64 a, float_status *s) bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s) { - FloatParts64 pa = bfloat16_unpack_canonical(a, s); - FloatParts64 pr = round_to_int(pa, s->float_rounding_mode, 0, s); + FloatParts64 pa, pr; + + bfloat16_unpack_canonical(&pa, a, s); + pr = round_to_int(pa, s->float_rounding_mode, 0, s); return bfloat16_round_pack_canonical(pr, s); } @@ -2253,71 +2313,91 @@ static int64_t round_to_int_and_pack(FloatParts64 in, FloatRoundMode rmode, int8_t float16_to_int8_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(float16_unpack_canonical(a, s), - rmode, scale, INT8_MIN, INT8_MAX, s); + FloatParts64 p; + + float16_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT8_MIN, INT8_MAX, s); } int16_t float16_to_int16_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(float16_unpack_canonical(a, s), - rmode, scale, INT16_MIN, INT16_MAX, s); + FloatParts64 p; + + float16_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float16_to_int32_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(float16_unpack_canonical(a, s), - rmode, scale, INT32_MIN, INT32_MAX, s); + FloatParts64 p; + + float16_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float16_to_int64_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(float16_unpack_canonical(a, s), - rmode, scale, INT64_MIN, INT64_MAX, s); + FloatParts64 p; + + float16_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT64_MIN, INT64_MAX, s); } int16_t float32_to_int16_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(float32_unpack_canonical(a, s), - rmode, scale, INT16_MIN, INT16_MAX, s); + FloatParts64 p; + + float32_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float32_to_int32_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(float32_unpack_canonical(a, s), - rmode, scale, INT32_MIN, INT32_MAX, s); + FloatParts64 p; + + float32_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float32_to_int64_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(float32_unpack_canonical(a, s), - rmode, scale, INT64_MIN, INT64_MAX, s); + FloatParts64 p; + + float32_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT64_MIN, INT64_MAX, s); } int16_t float64_to_int16_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(float64_unpack_canonical(a, s), - rmode, scale, INT16_MIN, INT16_MAX, s); + FloatParts64 p; + + float64_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float64_to_int32_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(float64_unpack_canonical(a, s), - rmode, scale, INT32_MIN, INT32_MAX, s); + FloatParts64 p; + + float64_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float64_to_int64_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(float64_unpack_canonical(a, s), - rmode, scale, INT64_MIN, INT64_MAX, s); + FloatParts64 p; + + float64_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT64_MIN, INT64_MAX, s); } int8_t float16_to_int8(float16 a, float_status *s) @@ -2423,22 +2503,28 @@ int64_t float64_to_int64_round_to_zero(float64 a, float_status *s) int16_t bfloat16_to_int16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(bfloat16_unpack_canonical(a, s), - rmode, scale, INT16_MIN, INT16_MAX, s); + FloatParts64 p; + + bfloat16_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t bfloat16_to_int32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(bfloat16_unpack_canonical(a, s), - rmode, scale, INT32_MIN, INT32_MAX, s); + FloatParts64 p; + + bfloat16_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t bfloat16_to_int64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_int_and_pack(bfloat16_unpack_canonical(a, s), - rmode, scale, INT64_MIN, INT64_MAX, s); + FloatParts64 p; + + bfloat16_unpack_canonical(&p, a, s); + return round_to_int_and_pack(p, rmode, scale, INT64_MIN, INT64_MAX, s); } int16_t bfloat16_to_int16(bfloat16 a, float_status *s) @@ -2532,71 +2618,91 @@ static uint64_t round_to_uint_and_pack(FloatParts64 in, FloatRoundMode rmode, uint8_t float16_to_uint8_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(float16_unpack_canonical(a, s), - rmode, scale, UINT8_MAX, s); + FloatParts64 p; + + float16_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT8_MAX, s); } uint16_t float16_to_uint16_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(float16_unpack_canonical(a, s), - rmode, scale, UINT16_MAX, s); + FloatParts64 p; + + float16_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT16_MAX, s); } uint32_t float16_to_uint32_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(float16_unpack_canonical(a, s), - rmode, scale, UINT32_MAX, s); + FloatParts64 p; + + float16_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT32_MAX, s); } uint64_t float16_to_uint64_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(float16_unpack_canonical(a, s), - rmode, scale, UINT64_MAX, s); + FloatParts64 p; + + float16_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT64_MAX, s); } uint16_t float32_to_uint16_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(float32_unpack_canonical(a, s), - rmode, scale, UINT16_MAX, s); + FloatParts64 p; + + float32_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT16_MAX, s); } uint32_t float32_to_uint32_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(float32_unpack_canonical(a, s), - rmode, scale, UINT32_MAX, s); + FloatParts64 p; + + float32_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT32_MAX, s); } uint64_t float32_to_uint64_scalbn(float32 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(float32_unpack_canonical(a, s), - rmode, scale, UINT64_MAX, s); + FloatParts64 p; + + float32_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT64_MAX, s); } uint16_t float64_to_uint16_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(float64_unpack_canonical(a, s), - rmode, scale, UINT16_MAX, s); + FloatParts64 p; + + float64_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT16_MAX, s); } uint32_t float64_to_uint32_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(float64_unpack_canonical(a, s), - rmode, scale, UINT32_MAX, s); + FloatParts64 p; + + float64_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT32_MAX, s); } uint64_t float64_to_uint64_scalbn(float64 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(float64_unpack_canonical(a, s), - rmode, scale, UINT64_MAX, s); + FloatParts64 p; + + float64_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT64_MAX, s); } uint8_t float16_to_uint8(float16 a, float_status *s) @@ -2702,22 +2808,28 @@ uint64_t float64_to_uint64_round_to_zero(float64 a, float_status *s) uint16_t bfloat16_to_uint16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(bfloat16_unpack_canonical(a, s), - rmode, scale, UINT16_MAX, s); + FloatParts64 p; + + bfloat16_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT16_MAX, s); } uint32_t bfloat16_to_uint32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(bfloat16_unpack_canonical(a, s), - rmode, scale, UINT32_MAX, s); + FloatParts64 p; + + bfloat16_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT32_MAX, s); } uint64_t bfloat16_to_uint64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, float_status *s) { - return round_to_uint_and_pack(bfloat16_unpack_canonical(a, s), - rmode, scale, UINT64_MAX, s); + FloatParts64 p; + + bfloat16_unpack_canonical(&p, a, s); + return round_to_uint_and_pack(p, rmode, scale, UINT64_MAX, s); } uint16_t bfloat16_to_uint16(bfloat16 a, float_status *s) @@ -3168,10 +3280,10 @@ static FloatParts64 minmax_floats(FloatParts64 a, FloatParts64 b, bool ismin, float ## sz float ## sz ## _ ## name(float ## sz a, float ## sz b, \ float_status *s) \ { \ - FloatParts64 pa = float ## sz ## _unpack_canonical(a, s); \ - FloatParts64 pb = float ## sz ## _unpack_canonical(b, s); \ - FloatParts64 pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ - \ + FloatParts64 pa, pb, pr; \ + float ## sz ## _unpack_canonical(&pa, a, s); \ + float ## sz ## _unpack_canonical(&pb, b, s); \ + pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ return float ## sz ## _round_pack_canonical(pr, s); \ } @@ -3201,10 +3313,10 @@ MINMAX(64, maxnummag, false, true, true) #define BF16_MINMAX(name, ismin, isiee, ismag) \ bfloat16 bfloat16_ ## name(bfloat16 a, bfloat16 b, float_status *s) \ { \ - FloatParts64 pa = bfloat16_unpack_canonical(a, s); \ - FloatParts64 pb = bfloat16_unpack_canonical(b, s); \ - FloatParts64 pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ - \ + FloatParts64 pa, pb, pr; \ + bfloat16_unpack_canonical(&pa, a, s); \ + bfloat16_unpack_canonical(&pb, b, s); \ + pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ return bfloat16_round_pack_canonical(pr, s); \ } @@ -3279,8 +3391,9 @@ static FloatRelation compare_floats(FloatParts64 a, FloatParts64 b, bool is_quie static int attr \ name(float ## sz a, float ## sz b, bool is_quiet, float_status *s) \ { \ - FloatParts64 pa = float ## sz ## _unpack_canonical(a, s); \ - FloatParts64 pb = float ## sz ## _unpack_canonical(b, s); \ + FloatParts64 pa, pb; \ + float ## sz ## _unpack_canonical(&pa, a, s); \ + float ## sz ## _unpack_canonical(&pb, b, s); \ return compare_floats(pa, pb, is_quiet, s); \ } @@ -3381,8 +3494,10 @@ FloatRelation float64_compare_quiet(float64 a, float64 b, float_status *s) static FloatRelation QEMU_FLATTEN soft_bf16_compare(bfloat16 a, bfloat16 b, bool is_quiet, float_status *s) { - FloatParts64 pa = bfloat16_unpack_canonical(a, s); - FloatParts64 pb = bfloat16_unpack_canonical(b, s); + FloatParts64 pa, pb; + + bfloat16_unpack_canonical(&pa, a, s); + bfloat16_unpack_canonical(&pb, b, s); return compare_floats(pa, pb, is_quiet, s); } @@ -3416,29 +3531,37 @@ static FloatParts64 scalbn_decomposed(FloatParts64 a, int n, float_status *s) float16 float16_scalbn(float16 a, int n, float_status *status) { - FloatParts64 pa = float16_unpack_canonical(a, status); - FloatParts64 pr = scalbn_decomposed(pa, n, status); + FloatParts64 pa, pr; + + float16_unpack_canonical(&pa, a, status); + pr = scalbn_decomposed(pa, n, status); return float16_round_pack_canonical(pr, status); } float32 float32_scalbn(float32 a, int n, float_status *status) { - FloatParts64 pa = float32_unpack_canonical(a, status); - FloatParts64 pr = scalbn_decomposed(pa, n, status); + FloatParts64 pa, pr; + + float32_unpack_canonical(&pa, a, status); + pr = scalbn_decomposed(pa, n, status); return float32_round_pack_canonical(pr, status); } float64 float64_scalbn(float64 a, int n, float_status *status) { - FloatParts64 pa = float64_unpack_canonical(a, status); - FloatParts64 pr = scalbn_decomposed(pa, n, status); + FloatParts64 pa, pr; + + float64_unpack_canonical(&pa, a, status); + pr = scalbn_decomposed(pa, n, status); return float64_round_pack_canonical(pr, status); } bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status) { - FloatParts64 pa = bfloat16_unpack_canonical(a, status); - FloatParts64 pr = scalbn_decomposed(pa, n, status); + FloatParts64 pa, pr; + + bfloat16_unpack_canonical(&pa, a, status); + pr = scalbn_decomposed(pa, n, status); return bfloat16_round_pack_canonical(pr, status); } @@ -3515,24 +3638,30 @@ static FloatParts64 sqrt_float(FloatParts64 a, float_status *s, const FloatFmt * float16 QEMU_FLATTEN float16_sqrt(float16 a, float_status *status) { - FloatParts64 pa = float16_unpack_canonical(a, status); - FloatParts64 pr = sqrt_float(pa, status, &float16_params); + FloatParts64 pa, pr; + + float16_unpack_canonical(&pa, a, status); + pr = sqrt_float(pa, status, &float16_params); return float16_round_pack_canonical(pr, status); } static float32 QEMU_SOFTFLOAT_ATTR soft_f32_sqrt(float32 a, float_status *status) { - FloatParts64 pa = float32_unpack_canonical(a, status); - FloatParts64 pr = sqrt_float(pa, status, &float32_params); + FloatParts64 pa, pr; + + float32_unpack_canonical(&pa, a, status); + pr = sqrt_float(pa, status, &float32_params); return float32_round_pack_canonical(pr, status); } static float64 QEMU_SOFTFLOAT_ATTR soft_f64_sqrt(float64 a, float_status *status) { - FloatParts64 pa = float64_unpack_canonical(a, status); - FloatParts64 pr = sqrt_float(pa, status, &float64_params); + FloatParts64 pa, pr; + + float64_unpack_canonical(&pa, a, status); + pr = sqrt_float(pa, status, &float64_params); return float64_round_pack_canonical(pr, status); } @@ -3592,8 +3721,10 @@ float64 QEMU_FLATTEN float64_sqrt(float64 xa, float_status *s) bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status) { - FloatParts64 pa = bfloat16_unpack_canonical(a, status); - FloatParts64 pr = sqrt_float(pa, status, &bfloat16_params); + FloatParts64 pa, pr; + + bfloat16_unpack_canonical(&pa, a, status); + pr = sqrt_float(pa, status, &bfloat16_params); return bfloat16_round_pack_canonical(pr, status); } From e293e927a80e0ba5a3590052917aeb8e5a2fab90 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 15:38:52 -0700 Subject: [PATCH 0651/3028] softfloat: Use pointers with ftype_round_pack_canonical MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 131 +++++++++++++++++++++++++----------------------- 1 file changed, 68 insertions(+), 63 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index e53d4a138f..b0cbd5941c 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -945,22 +945,25 @@ static void bfloat16_unpack_canonical(FloatParts64 *p, bfloat16 f, *p = sf_canonicalize(*p, &bfloat16_params, s); } -static float16 float16a_round_pack_canonical(FloatParts64 p, float_status *s, +static float16 float16a_round_pack_canonical(FloatParts64 *p, + float_status *s, const FloatFmt *params) { - p = round_canonical(p, s, params); - return float16_pack_raw(&p); + *p = round_canonical(*p, s, params); + return float16_pack_raw(p); } -static float16 float16_round_pack_canonical(FloatParts64 p, float_status *s) +static float16 float16_round_pack_canonical(FloatParts64 *p, + float_status *s) { return float16a_round_pack_canonical(p, s, &float16_params); } -static bfloat16 bfloat16_round_pack_canonical(FloatParts64 p, float_status *s) +static bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p, + float_status *s) { - p = round_canonical(p, s, &bfloat16_params); - return bfloat16_pack_raw(&p); + *p = round_canonical(*p, s, &bfloat16_params); + return bfloat16_pack_raw(p); } static void float32_unpack_canonical(FloatParts64 *p, float32 f, @@ -970,10 +973,11 @@ static void float32_unpack_canonical(FloatParts64 *p, float32 f, *p = sf_canonicalize(*p, &float32_params, s); } -static float32 float32_round_pack_canonical(FloatParts64 p, float_status *s) +static float32 float32_round_pack_canonical(FloatParts64 *p, + float_status *s) { - p = round_canonical(p, s, &float32_params); - return float32_pack_raw(&p); + *p = round_canonical(*p, s, &float32_params); + return float32_pack_raw(p); } static void float64_unpack_canonical(FloatParts64 *p, float64 f, @@ -983,10 +987,11 @@ static void float64_unpack_canonical(FloatParts64 *p, float64 f, *p = sf_canonicalize(*p, &float64_params, s); } -static float64 float64_round_pack_canonical(FloatParts64 p, float_status *s) +static float64 float64_round_pack_canonical(FloatParts64 *p, + float_status *s) { - p = round_canonical(p, s, &float64_params); - return float64_pack_raw(&p); + *p = round_canonical(*p, s, &float64_params); + return float64_pack_raw(p); } /* @@ -1093,7 +1098,7 @@ float16 QEMU_FLATTEN float16_add(float16 a, float16 b, float_status *status) float16_unpack_canonical(&pb, b, status); pr = addsub_floats(pa, pb, false, status); - return float16_round_pack_canonical(pr, status); + return float16_round_pack_canonical(&pr, status); } float16 QEMU_FLATTEN float16_sub(float16 a, float16 b, float_status *status) @@ -1104,7 +1109,7 @@ float16 QEMU_FLATTEN float16_sub(float16 a, float16 b, float_status *status) float16_unpack_canonical(&pb, b, status); pr = addsub_floats(pa, pb, true, status); - return float16_round_pack_canonical(pr, status); + return float16_round_pack_canonical(&pr, status); } static float32 QEMU_SOFTFLOAT_ATTR @@ -1116,7 +1121,7 @@ soft_f32_addsub(float32 a, float32 b, bool subtract, float_status *status) float32_unpack_canonical(&pb, b, status); pr = addsub_floats(pa, pb, subtract, status); - return float32_round_pack_canonical(pr, status); + return float32_round_pack_canonical(&pr, status); } static inline float32 soft_f32_add(float32 a, float32 b, float_status *status) @@ -1138,7 +1143,7 @@ soft_f64_addsub(float64 a, float64 b, bool subtract, float_status *status) float64_unpack_canonical(&pb, b, status); pr = addsub_floats(pa, pb, subtract, status); - return float64_round_pack_canonical(pr, status); + return float64_round_pack_canonical(&pr, status); } static inline float64 soft_f64_add(float64 a, float64 b, float_status *status) @@ -1238,7 +1243,7 @@ bfloat16 QEMU_FLATTEN bfloat16_add(bfloat16 a, bfloat16 b, float_status *status) bfloat16_unpack_canonical(&pb, b, status); pr = addsub_floats(pa, pb, false, status); - return bfloat16_round_pack_canonical(pr, status); + return bfloat16_round_pack_canonical(&pr, status); } bfloat16 QEMU_FLATTEN bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status) @@ -1249,7 +1254,7 @@ bfloat16 QEMU_FLATTEN bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status) bfloat16_unpack_canonical(&pb, b, status); pr = addsub_floats(pa, pb, true, status); - return bfloat16_round_pack_canonical(pr, status); + return bfloat16_round_pack_canonical(&pr, status); } /* @@ -1311,7 +1316,7 @@ float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status) float16_unpack_canonical(&pb, b, status); pr = mul_floats(pa, pb, status); - return float16_round_pack_canonical(pr, status); + return float16_round_pack_canonical(&pr, status); } static float32 QEMU_SOFTFLOAT_ATTR @@ -1323,7 +1328,7 @@ soft_f32_mul(float32 a, float32 b, float_status *status) float32_unpack_canonical(&pb, b, status); pr = mul_floats(pa, pb, status); - return float32_round_pack_canonical(pr, status); + return float32_round_pack_canonical(&pr, status); } static float64 QEMU_SOFTFLOAT_ATTR @@ -1335,7 +1340,7 @@ soft_f64_mul(float64 a, float64 b, float_status *status) float64_unpack_canonical(&pb, b, status); pr = mul_floats(pa, pb, status); - return float64_round_pack_canonical(pr, status); + return float64_round_pack_canonical(&pr, status); } static float hard_f32_mul(float a, float b) @@ -1375,7 +1380,7 @@ bfloat16 QEMU_FLATTEN bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) bfloat16_unpack_canonical(&pb, b, status); pr = mul_floats(pa, pb, status); - return bfloat16_round_pack_canonical(pr, status); + return bfloat16_round_pack_canonical(&pr, status); } /* @@ -1574,7 +1579,7 @@ float16 QEMU_FLATTEN float16_muladd(float16 a, float16 b, float16 c, float16_unpack_canonical(&pc, c, status); pr = muladd_floats(pa, pb, pc, flags, status); - return float16_round_pack_canonical(pr, status); + return float16_round_pack_canonical(&pr, status); } static float32 QEMU_SOFTFLOAT_ATTR @@ -1588,7 +1593,7 @@ soft_f32_muladd(float32 a, float32 b, float32 c, int flags, float32_unpack_canonical(&pc, c, status); pr = muladd_floats(pa, pb, pc, flags, status); - return float32_round_pack_canonical(pr, status); + return float32_round_pack_canonical(&pr, status); } static float64 QEMU_SOFTFLOAT_ATTR @@ -1602,7 +1607,7 @@ soft_f64_muladd(float64 a, float64 b, float64 c, int flags, float64_unpack_canonical(&pc, c, status); pr = muladd_floats(pa, pb, pc, flags, status); - return float64_round_pack_canonical(pr, status); + return float64_round_pack_canonical(&pr, status); } static bool force_soft_fma; @@ -1765,7 +1770,7 @@ bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, bfloat16_unpack_canonical(&pc, c, status); pr = muladd_floats(pa, pb, pc, flags, status); - return bfloat16_round_pack_canonical(pr, status); + return bfloat16_round_pack_canonical(&pr, status); } /* @@ -1848,7 +1853,7 @@ float16 float16_div(float16 a, float16 b, float_status *status) float16_unpack_canonical(&pb, b, status); pr = div_floats(pa, pb, status); - return float16_round_pack_canonical(pr, status); + return float16_round_pack_canonical(&pr, status); } static float32 QEMU_SOFTFLOAT_ATTR @@ -1860,7 +1865,7 @@ soft_f32_div(float32 a, float32 b, float_status *status) float32_unpack_canonical(&pb, b, status); pr = div_floats(pa, pb, status); - return float32_round_pack_canonical(pr, status); + return float32_round_pack_canonical(&pr, status); } static float64 QEMU_SOFTFLOAT_ATTR @@ -1872,7 +1877,7 @@ soft_f64_div(float64 a, float64 b, float_status *status) float64_unpack_canonical(&pb, b, status); pr = div_floats(pa, pb, status); - return float64_round_pack_canonical(pr, status); + return float64_round_pack_canonical(&pr, status); } static float hard_f32_div(float a, float b) @@ -1946,7 +1951,7 @@ bfloat16 bfloat16_div(bfloat16 a, bfloat16 b, float_status *status) bfloat16_unpack_canonical(&pb, b, status); pr = div_floats(pa, pb, status); - return bfloat16_round_pack_canonical(pr, status); + return bfloat16_round_pack_canonical(&pr, status); } /* @@ -2002,7 +2007,7 @@ float32 float16_to_float32(float16 a, bool ieee, float_status *s) float16a_unpack_canonical(&pa, a, s, fmt16); pr = float_to_float(pa, &float32_params, s); - return float32_round_pack_canonical(pr, s); + return float32_round_pack_canonical(&pr, s); } float64 float16_to_float64(float16 a, bool ieee, float_status *s) @@ -2012,7 +2017,7 @@ float64 float16_to_float64(float16 a, bool ieee, float_status *s) float16a_unpack_canonical(&pa, a, s, fmt16); pr = float_to_float(pa, &float64_params, s); - return float64_round_pack_canonical(pr, s); + return float64_round_pack_canonical(&pr, s); } float16 float32_to_float16(float32 a, bool ieee, float_status *s) @@ -2022,7 +2027,7 @@ float16 float32_to_float16(float32 a, bool ieee, float_status *s) float32_unpack_canonical(&pa, a, s); pr = float_to_float(pa, fmt16, s); - return float16a_round_pack_canonical(pr, s, fmt16); + return float16a_round_pack_canonical(&pr, s, fmt16); } static float64 QEMU_SOFTFLOAT_ATTR @@ -2032,7 +2037,7 @@ soft_float32_to_float64(float32 a, float_status *s) float32_unpack_canonical(&pa, a, s); pr = float_to_float(pa, &float64_params, s); - return float64_round_pack_canonical(pr, s); + return float64_round_pack_canonical(&pr, s); } float64 float32_to_float64(float32 a, float_status *s) @@ -2058,7 +2063,7 @@ float16 float64_to_float16(float64 a, bool ieee, float_status *s) float64_unpack_canonical(&pa, a, s); pr = float_to_float(pa, fmt16, s); - return float16a_round_pack_canonical(pr, s, fmt16); + return float16a_round_pack_canonical(&pr, s, fmt16); } float32 float64_to_float32(float64 a, float_status *s) @@ -2067,7 +2072,7 @@ float32 float64_to_float32(float64 a, float_status *s) float64_unpack_canonical(&pa, a, s); pr = float_to_float(pa, &float32_params, s); - return float32_round_pack_canonical(pr, s); + return float32_round_pack_canonical(&pr, s); } float32 bfloat16_to_float32(bfloat16 a, float_status *s) @@ -2076,7 +2081,7 @@ float32 bfloat16_to_float32(bfloat16 a, float_status *s) bfloat16_unpack_canonical(&pa, a, s); pr = float_to_float(pa, &float32_params, s); - return float32_round_pack_canonical(pr, s); + return float32_round_pack_canonical(&pr, s); } float64 bfloat16_to_float64(bfloat16 a, float_status *s) @@ -2085,7 +2090,7 @@ float64 bfloat16_to_float64(bfloat16 a, float_status *s) bfloat16_unpack_canonical(&pa, a, s); pr = float_to_float(pa, &float64_params, s); - return float64_round_pack_canonical(pr, s); + return float64_round_pack_canonical(&pr, s); } bfloat16 float32_to_bfloat16(float32 a, float_status *s) @@ -2094,7 +2099,7 @@ bfloat16 float32_to_bfloat16(float32 a, float_status *s) float32_unpack_canonical(&pa, a, s); pr = float_to_float(pa, &bfloat16_params, s); - return bfloat16_round_pack_canonical(pr, s); + return bfloat16_round_pack_canonical(&pr, s); } bfloat16 float64_to_bfloat16(float64 a, float_status *s) @@ -2103,7 +2108,7 @@ bfloat16 float64_to_bfloat16(float64 a, float_status *s) float64_unpack_canonical(&pa, a, s); pr = float_to_float(pa, &bfloat16_params, s); - return bfloat16_round_pack_canonical(pr, s); + return bfloat16_round_pack_canonical(&pr, s); } /* @@ -2220,7 +2225,7 @@ float16 float16_round_to_int(float16 a, float_status *s) float16_unpack_canonical(&pa, a, s); pr = round_to_int(pa, s->float_rounding_mode, 0, s); - return float16_round_pack_canonical(pr, s); + return float16_round_pack_canonical(&pr, s); } float32 float32_round_to_int(float32 a, float_status *s) @@ -2229,7 +2234,7 @@ float32 float32_round_to_int(float32 a, float_status *s) float32_unpack_canonical(&pa, a, s); pr = round_to_int(pa, s->float_rounding_mode, 0, s); - return float32_round_pack_canonical(pr, s); + return float32_round_pack_canonical(&pr, s); } float64 float64_round_to_int(float64 a, float_status *s) @@ -2238,7 +2243,7 @@ float64 float64_round_to_int(float64 a, float_status *s) float64_unpack_canonical(&pa, a, s); pr = round_to_int(pa, s->float_rounding_mode, 0, s); - return float64_round_pack_canonical(pr, s); + return float64_round_pack_canonical(&pr, s); } /* @@ -2252,7 +2257,7 @@ bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s) bfloat16_unpack_canonical(&pa, a, s); pr = round_to_int(pa, s->float_rounding_mode, 0, s); - return bfloat16_round_pack_canonical(pr, s); + return bfloat16_round_pack_canonical(&pr, s); } /* @@ -2898,7 +2903,7 @@ static FloatParts64 int_to_float(int64_t a, int scale, float_status *status) float16 int64_to_float16_scalbn(int64_t a, int scale, float_status *status) { FloatParts64 pa = int_to_float(a, scale, status); - return float16_round_pack_canonical(pa, status); + return float16_round_pack_canonical(&pa, status); } float16 int32_to_float16_scalbn(int32_t a, int scale, float_status *status) @@ -2934,7 +2939,7 @@ float16 int8_to_float16(int8_t a, float_status *status) float32 int64_to_float32_scalbn(int64_t a, int scale, float_status *status) { FloatParts64 pa = int_to_float(a, scale, status); - return float32_round_pack_canonical(pa, status); + return float32_round_pack_canonical(&pa, status); } float32 int32_to_float32_scalbn(int32_t a, int scale, float_status *status) @@ -2965,7 +2970,7 @@ float32 int16_to_float32(int16_t a, float_status *status) float64 int64_to_float64_scalbn(int64_t a, int scale, float_status *status) { FloatParts64 pa = int_to_float(a, scale, status); - return float64_round_pack_canonical(pa, status); + return float64_round_pack_canonical(&pa, status); } float64 int32_to_float64_scalbn(int32_t a, int scale, float_status *status) @@ -3001,7 +3006,7 @@ float64 int16_to_float64(int16_t a, float_status *status) bfloat16 int64_to_bfloat16_scalbn(int64_t a, int scale, float_status *status) { FloatParts64 pa = int_to_float(a, scale, status); - return bfloat16_round_pack_canonical(pa, status); + return bfloat16_round_pack_canonical(&pa, status); } bfloat16 int32_to_bfloat16_scalbn(int32_t a, int scale, float_status *status) @@ -3058,7 +3063,7 @@ static FloatParts64 uint_to_float(uint64_t a, int scale, float_status *status) float16 uint64_to_float16_scalbn(uint64_t a, int scale, float_status *status) { FloatParts64 pa = uint_to_float(a, scale, status); - return float16_round_pack_canonical(pa, status); + return float16_round_pack_canonical(&pa, status); } float16 uint32_to_float16_scalbn(uint32_t a, int scale, float_status *status) @@ -3094,7 +3099,7 @@ float16 uint8_to_float16(uint8_t a, float_status *status) float32 uint64_to_float32_scalbn(uint64_t a, int scale, float_status *status) { FloatParts64 pa = uint_to_float(a, scale, status); - return float32_round_pack_canonical(pa, status); + return float32_round_pack_canonical(&pa, status); } float32 uint32_to_float32_scalbn(uint32_t a, int scale, float_status *status) @@ -3125,7 +3130,7 @@ float32 uint16_to_float32(uint16_t a, float_status *status) float64 uint64_to_float64_scalbn(uint64_t a, int scale, float_status *status) { FloatParts64 pa = uint_to_float(a, scale, status); - return float64_round_pack_canonical(pa, status); + return float64_round_pack_canonical(&pa, status); } float64 uint32_to_float64_scalbn(uint32_t a, int scale, float_status *status) @@ -3161,7 +3166,7 @@ float64 uint16_to_float64(uint16_t a, float_status *status) bfloat16 uint64_to_bfloat16_scalbn(uint64_t a, int scale, float_status *status) { FloatParts64 pa = uint_to_float(a, scale, status); - return bfloat16_round_pack_canonical(pa, status); + return bfloat16_round_pack_canonical(&pa, status); } bfloat16 uint32_to_bfloat16_scalbn(uint32_t a, int scale, float_status *status) @@ -3284,7 +3289,7 @@ float ## sz float ## sz ## _ ## name(float ## sz a, float ## sz b, \ float ## sz ## _unpack_canonical(&pa, a, s); \ float ## sz ## _unpack_canonical(&pb, b, s); \ pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ - return float ## sz ## _round_pack_canonical(pr, s); \ + return float ## sz ## _round_pack_canonical(&pr, s); \ } MINMAX(16, min, true, false, false) @@ -3317,7 +3322,7 @@ bfloat16 bfloat16_ ## name(bfloat16 a, bfloat16 b, float_status *s) \ bfloat16_unpack_canonical(&pa, a, s); \ bfloat16_unpack_canonical(&pb, b, s); \ pr = minmax_floats(pa, pb, ismin, isiee, ismag, s); \ - return bfloat16_round_pack_canonical(pr, s); \ + return bfloat16_round_pack_canonical(&pr, s); \ } BF16_MINMAX(min, true, false, false) @@ -3535,7 +3540,7 @@ float16 float16_scalbn(float16 a, int n, float_status *status) float16_unpack_canonical(&pa, a, status); pr = scalbn_decomposed(pa, n, status); - return float16_round_pack_canonical(pr, status); + return float16_round_pack_canonical(&pr, status); } float32 float32_scalbn(float32 a, int n, float_status *status) @@ -3544,7 +3549,7 @@ float32 float32_scalbn(float32 a, int n, float_status *status) float32_unpack_canonical(&pa, a, status); pr = scalbn_decomposed(pa, n, status); - return float32_round_pack_canonical(pr, status); + return float32_round_pack_canonical(&pr, status); } float64 float64_scalbn(float64 a, int n, float_status *status) @@ -3553,7 +3558,7 @@ float64 float64_scalbn(float64 a, int n, float_status *status) float64_unpack_canonical(&pa, a, status); pr = scalbn_decomposed(pa, n, status); - return float64_round_pack_canonical(pr, status); + return float64_round_pack_canonical(&pr, status); } bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status) @@ -3562,7 +3567,7 @@ bfloat16 bfloat16_scalbn(bfloat16 a, int n, float_status *status) bfloat16_unpack_canonical(&pa, a, status); pr = scalbn_decomposed(pa, n, status); - return bfloat16_round_pack_canonical(pr, status); + return bfloat16_round_pack_canonical(&pr, status); } /* @@ -3642,7 +3647,7 @@ float16 QEMU_FLATTEN float16_sqrt(float16 a, float_status *status) float16_unpack_canonical(&pa, a, status); pr = sqrt_float(pa, status, &float16_params); - return float16_round_pack_canonical(pr, status); + return float16_round_pack_canonical(&pr, status); } static float32 QEMU_SOFTFLOAT_ATTR @@ -3652,7 +3657,7 @@ soft_f32_sqrt(float32 a, float_status *status) float32_unpack_canonical(&pa, a, status); pr = sqrt_float(pa, status, &float32_params); - return float32_round_pack_canonical(pr, status); + return float32_round_pack_canonical(&pr, status); } static float64 QEMU_SOFTFLOAT_ATTR @@ -3662,7 +3667,7 @@ soft_f64_sqrt(float64 a, float_status *status) float64_unpack_canonical(&pa, a, status); pr = sqrt_float(pa, status, &float64_params); - return float64_round_pack_canonical(pr, status); + return float64_round_pack_canonical(&pr, status); } float32 QEMU_FLATTEN float32_sqrt(float32 xa, float_status *s) @@ -3725,7 +3730,7 @@ bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status) bfloat16_unpack_canonical(&pa, a, status); pr = sqrt_float(pa, status, &bfloat16_params); - return bfloat16_round_pack_canonical(pr, status); + return bfloat16_round_pack_canonical(&pr, status); } /*---------------------------------------------------------------------------- From 92ff426d7bc60821080f9d15cca896cfad7052b7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 16:23:06 -0700 Subject: [PATCH 0652/3028] softfloat: Use pointers with parts_silence_nan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time, rename to parts64_silence_nan, split out parts_silence_nan_frac, and define a macro for parts_silence_nan. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-specialize.c.inc | 17 +++++++++++------ fpu/softfloat.c | 16 +++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 47c3652d63..4038955379 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -176,20 +176,25 @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) | floating-point parts. *----------------------------------------------------------------------------*/ -static FloatParts64 parts_silence_nan(FloatParts64 a, float_status *status) +static uint64_t parts_silence_nan_frac(uint64_t frac, float_status *status) { g_assert(!no_signaling_nans(status)); g_assert(!status->default_nan_mode); /* The only snan_bit_is_one target without default_nan_mode is HPPA. */ if (snan_bit_is_one(status)) { - a.frac &= ~(1ULL << (DECOMPOSED_BINARY_POINT - 1)); - a.frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 2); + frac &= ~(1ULL << (DECOMPOSED_BINARY_POINT - 1)); + frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 2); } else { - a.frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 1); + frac |= 1ULL << (DECOMPOSED_BINARY_POINT - 1); } - a.cls = float_class_qnan; - return a; + return frac; +} + +static void parts64_silence_nan(FloatParts64 *p, float_status *status) +{ + p->frac = parts_silence_nan_frac(p->frac, status); + p->cls = float_class_qnan; } /*---------------------------------------------------------------------------- diff --git a/fpu/softfloat.c b/fpu/softfloat.c index b0cbd5941c..2123453d40 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -657,6 +657,7 @@ static inline float64 float64_pack_raw(const FloatParts64 *p) #include "softfloat-specialize.c.inc" #define parts_default_nan parts64_default_nan +#define parts_silence_nan parts64_silence_nan /* Canonicalize EXP and FRAC, setting CLS. */ static FloatParts64 sf_canonicalize(FloatParts64 part, const FloatFmt *parm, @@ -851,7 +852,8 @@ static FloatParts64 return_nan(FloatParts64 a, float_status *s) if (is_snan(a.cls)) { float_raise(float_flag_invalid, s); if (!s->default_nan_mode) { - return parts_silence_nan(a, s); + parts_silence_nan(&a, s); + return a; } } else if (!s->default_nan_mode) { return a; @@ -875,7 +877,7 @@ static FloatParts64 pick_nan(FloatParts64 a, FloatParts64 b, float_status *s) a = b; } if (is_snan(a.cls)) { - return parts_silence_nan(a, s); + parts_silence_nan(&a, s); } } return a; @@ -916,7 +918,7 @@ static FloatParts64 pick_nan_muladd(FloatParts64 a, FloatParts64 b, FloatParts64 } if (is_snan(a.cls)) { - return parts_silence_nan(a, s); + parts_silence_nan(&a, s); } return a; } @@ -3801,7 +3803,7 @@ float16 float16_silence_nan(float16 a, float_status *status) float16_unpack_raw(&p, a); p.frac <<= float16_params.frac_shift; - p = parts_silence_nan(p, status); + parts_silence_nan(&p, status); p.frac >>= float16_params.frac_shift; return float16_pack_raw(&p); } @@ -3812,7 +3814,7 @@ float32 float32_silence_nan(float32 a, float_status *status) float32_unpack_raw(&p, a); p.frac <<= float32_params.frac_shift; - p = parts_silence_nan(p, status); + parts_silence_nan(&p, status); p.frac >>= float32_params.frac_shift; return float32_pack_raw(&p); } @@ -3823,7 +3825,7 @@ float64 float64_silence_nan(float64 a, float_status *status) float64_unpack_raw(&p, a); p.frac <<= float64_params.frac_shift; - p = parts_silence_nan(p, status); + parts_silence_nan(&p, status); p.frac >>= float64_params.frac_shift; return float64_pack_raw(&p); } @@ -3834,7 +3836,7 @@ bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) bfloat16_unpack_raw(&p, a); p.frac <<= bfloat16_params.frac_shift; - p = parts_silence_nan(p, status); + parts_silence_nan(&p, status); p.frac >>= bfloat16_params.frac_shift; return bfloat16_pack_raw(&p); } From 4109b9ea8ada91894dd561594dc5f2db83ebacf3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 11 Nov 2020 17:36:39 -0800 Subject: [PATCH 0653/3028] softfloat: Rearrange FloatParts64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shuffle the fraction to the end, otherwise sort by size. Add frac_hi and frac_lo members to alias frac. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 2123453d40..ee609540aa 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -511,10 +511,20 @@ static inline __attribute__((unused)) bool is_qnan(FloatClass c) */ typedef struct { - uint64_t frac; - int32_t exp; FloatClass cls; bool sign; + int32_t exp; + union { + /* Routines that know the structure may reference the singular name. */ + uint64_t frac; + /* + * Routines expanded with multiple structures reference "hi" and "lo" + * depending on the operation. In FloatParts64, "hi" and "lo" are + * both the same word and aliased here. + */ + uint64_t frac_hi; + uint64_t frac_lo; + }; } FloatParts64; #define DECOMPOSED_BINARY_POINT 63 From 0018b1f41bf37f8c3dff7663395a231c8a77771d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 16:36:19 -0700 Subject: [PATCH 0654/3028] softfloat: Convert float128_silence_nan to parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the minimal change that also introduces float128_params, float128_unpack_raw, and float128_pack_raw without running into unused symbol Werrors. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-specialize.c.inc | 25 +++------ fpu/softfloat.c | 96 +++++++++++++++++++++++++++++----- 2 files changed, 89 insertions(+), 32 deletions(-) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 4038955379..5b85b843c2 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -197,6 +197,12 @@ static void parts64_silence_nan(FloatParts64 *p, float_status *status) p->cls = float_class_qnan; } +static void parts128_silence_nan(FloatParts128 *p, float_status *status) +{ + p->frac_hi = parts_silence_nan_frac(p->frac_hi, status); + p->cls = float_class_qnan; +} + /*---------------------------------------------------------------------------- | The pattern for a default generated extended double-precision NaN. *----------------------------------------------------------------------------*/ @@ -1062,25 +1068,6 @@ bool float128_is_signaling_nan(float128 a, float_status *status) } } -/*---------------------------------------------------------------------------- -| Returns a quiet NaN from a signalling NaN for the quadruple-precision -| floating point value `a'. -*----------------------------------------------------------------------------*/ - -float128 float128_silence_nan(float128 a, float_status *status) -{ - if (no_signaling_nans(status)) { - g_assert_not_reached(); - } else { - if (snan_bit_is_one(status)) { - return float128_default_nan(status); - } else { - a.high |= UINT64_C(0x0000800000000000); - return a; - } - } -} - /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point NaN | `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid diff --git a/fpu/softfloat.c b/fpu/softfloat.c index ee609540aa..f8f4ef51e8 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -500,14 +500,12 @@ static inline __attribute__((unused)) bool is_qnan(FloatClass c) } /* - * Structure holding all of the decomposed parts of a float. The - * exponent is unbiased and the fraction is normalized. All - * calculations are done with a 64 bit fraction and then rounded as - * appropriate for the final format. + * Structure holding all of the decomposed parts of a float. + * The exponent is unbiased and the fraction is normalized. * - * Thanks to the packed FloatClass a decent compiler should be able to - * fit the whole structure into registers and avoid using the stack - * for parameter passing. + * The fraction words are stored in big-endian word ordering, + * so that truncation from a larger format to a smaller format + * can be done simply by ignoring subsequent elements. */ typedef struct { @@ -527,6 +525,15 @@ typedef struct { }; } FloatParts64; +typedef struct { + FloatClass cls; + bool sign; + int32_t exp; + uint64_t frac_hi; + uint64_t frac_lo; +} FloatParts128; + +/* These apply to the most significant word of each FloatPartsN. */ #define DECOMPOSED_BINARY_POINT 63 #define DECOMPOSED_IMPLICIT_BIT (1ull << DECOMPOSED_BINARY_POINT) @@ -562,11 +569,11 @@ typedef struct { .exp_bias = ((1 << E) - 1) >> 1, \ .exp_max = (1 << E) - 1, \ .frac_size = F, \ - .frac_shift = DECOMPOSED_BINARY_POINT - F, \ - .frac_lsb = 1ull << (DECOMPOSED_BINARY_POINT - F), \ - .frac_lsbm1 = 1ull << ((DECOMPOSED_BINARY_POINT - F) - 1), \ - .round_mask = (1ull << (DECOMPOSED_BINARY_POINT - F)) - 1, \ - .roundeven_mask = (2ull << (DECOMPOSED_BINARY_POINT - F)) - 1 + .frac_shift = (-F - 1) & 63, \ + .frac_lsb = 1ull << ((-F - 1) & 63), \ + .frac_lsbm1 = 1ull << ((-F - 2) & 63), \ + .round_mask = (1ull << ((-F - 1) & 63)) - 1, \ + .roundeven_mask = (2ull << ((-F - 1) & 63)) - 1 static const FloatFmt float16_params = { FLOAT_PARAMS(5, 10) @@ -589,6 +596,10 @@ static const FloatFmt float64_params = { FLOAT_PARAMS(11, 52) }; +static const FloatFmt float128_params = { + FLOAT_PARAMS(15, 112) +}; + /* Unpack a float to parts, but do not canonicalize. */ static void unpack_raw64(FloatParts64 *r, const FloatFmt *fmt, uint64_t raw) { @@ -623,6 +634,20 @@ static inline void float64_unpack_raw(FloatParts64 *p, float64 f) unpack_raw64(p, &float64_params, f); } +static void float128_unpack_raw(FloatParts128 *p, float128 f) +{ + const int f_size = float128_params.frac_size - 64; + const int e_size = float128_params.exp_size; + + *p = (FloatParts128) { + .cls = float_class_unclassified, + .sign = extract64(f.high, f_size + e_size, 1), + .exp = extract64(f.high, f_size, e_size), + .frac_hi = extract64(f.high, 0, f_size), + .frac_lo = f.low, + }; +} + /* Pack a float from parts, but do not canonicalize. */ static uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt) { @@ -656,6 +681,18 @@ static inline float64 float64_pack_raw(const FloatParts64 *p) return make_float64(pack_raw64(p, &float64_params)); } +static float128 float128_pack_raw(const FloatParts128 *p) +{ + const int f_size = float128_params.frac_size - 64; + const int e_size = float128_params.exp_size; + uint64_t hi; + + hi = (uint64_t)p->sign << (f_size + e_size); + hi = deposit64(hi, f_size, e_size, p->exp); + hi = deposit64(hi, 0, f_size, p->frac_hi); + return make_float128(hi, p->frac_lo); +} + /*---------------------------------------------------------------------------- | Functions and definitions to determine: (1) whether tininess for underflow | is detected before or after rounding by default, (2) what (if anything) @@ -666,8 +703,30 @@ static inline float64 float64_pack_raw(const FloatParts64 *p) *----------------------------------------------------------------------------*/ #include "softfloat-specialize.c.inc" +#define PARTS_GENERIC_64_128(NAME, P) \ + QEMU_GENERIC(P, (FloatParts128 *, parts128_##NAME), parts64_##NAME) + #define parts_default_nan parts64_default_nan -#define parts_silence_nan parts64_silence_nan +#define parts_silence_nan(P, S) PARTS_GENERIC_64_128(silence_nan, P)(P, S) + + +/* + * Helper functions for softfloat-parts.c.inc, per-size operations. + */ + +static void frac128_shl(FloatParts128 *a, int c) +{ + shift128Left(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo); +} + +#define frac_shl(A, C) frac128_shl(A, C) + +static void frac128_shr(FloatParts128 *a, int c) +{ + shift128Right(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo); +} + +#define frac_shr(A, C) frac128_shr(A, C) /* Canonicalize EXP and FRAC, setting CLS. */ static FloatParts64 sf_canonicalize(FloatParts64 part, const FloatFmt *parm, @@ -3851,6 +3910,17 @@ bfloat16 bfloat16_silence_nan(bfloat16 a, float_status *status) return bfloat16_pack_raw(&p); } +float128 float128_silence_nan(float128 a, float_status *status) +{ + FloatParts128 p; + + float128_unpack_raw(&p, a); + frac_shl(&p, float128_params.frac_shift); + parts_silence_nan(&p, status); + frac_shr(&p, float128_params.frac_shift); + return float128_pack_raw(&p); +} + /*---------------------------------------------------------------------------- | If `a' is denormal and we are in flush-to-zero mode then set the | input-denormal exception and return zero. Otherwise just return the value. From e9034ea87e33d2e981a79d6f34567bd8e31c91a3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 16:37:01 -0700 Subject: [PATCH 0655/3028] softfloat: Convert float128_default_nan to parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-specialize.c.inc | 19 +++++++++++++++++++ fpu/softfloat.c | 17 ++++------------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index 5b85b843c2..c895733e79 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -171,6 +171,25 @@ static void parts64_default_nan(FloatParts64 *p, float_status *status) }; } +static void parts128_default_nan(FloatParts128 *p, float_status *status) +{ + /* + * Extrapolate from the choices made by parts64_default_nan to fill + * in the quad-floating format. If the low bit is set, assume we + * want to set all non-snan bits. + */ + FloatParts64 p64; + parts64_default_nan(&p64, status); + + *p = (FloatParts128) { + .cls = float_class_qnan, + .sign = p64.sign, + .exp = INT_MAX, + .frac_hi = p64.frac, + .frac_lo = -(p64.frac & 1) + }; +} + /*---------------------------------------------------------------------------- | Returns a quiet NaN from a signalling NaN for the deconstructed | floating-point parts. diff --git a/fpu/softfloat.c b/fpu/softfloat.c index f8f4ef51e8..08fd812ea0 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -706,7 +706,7 @@ static float128 float128_pack_raw(const FloatParts128 *p) #define PARTS_GENERIC_64_128(NAME, P) \ QEMU_GENERIC(P, (FloatParts128 *, parts128_##NAME), parts64_##NAME) -#define parts_default_nan parts64_default_nan +#define parts_default_nan(P, S) PARTS_GENERIC_64_128(default_nan, P)(P, S) #define parts_silence_nan(P, S) PARTS_GENERIC_64_128(silence_nan, P)(P, S) @@ -3837,20 +3837,11 @@ float64 float64_default_nan(float_status *status) float128 float128_default_nan(float_status *status) { - FloatParts64 p; - float128 r; + FloatParts128 p; parts_default_nan(&p, status); - /* Extrapolate from the choices made by parts_default_nan to fill - * in the quad-floating format. If the low bit is set, assume we - * want to set all non-snan bits. - */ - r.low = -(p.frac & 1); - r.high = p.frac >> (DECOMPOSED_BINARY_POINT - 48); - r.high |= UINT64_C(0x7FFF000000000000); - r.high |= (uint64_t)p.sign << 63; - - return r; + frac_shr(&p, float128_params.frac_shift); + return float128_pack_raw(&p); } bfloat16 bfloat16_default_nan(float_status *status) From 7c45bad866b098b8f91ffe727769d3d9f7e99cac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 16:47:04 -0700 Subject: [PATCH 0656/3028] softfloat: Move return_nan to softfloat-parts.c.inc At the same time, convert to pointers, rename to return_nan$N and define a macro for return_nan using QEMU_GENERIC. Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 37 ++++++++++++++++++++++++++++++++ fpu/softfloat.c | 45 ++++++++++++++++++++++----------------- 2 files changed, 62 insertions(+), 20 deletions(-) create mode 100644 fpu/softfloat-parts.c.inc diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc new file mode 100644 index 0000000000..2a3075d6fe --- /dev/null +++ b/fpu/softfloat-parts.c.inc @@ -0,0 +1,37 @@ +/* + * QEMU float support + * + * The code in this source file is derived from release 2a of the SoftFloat + * IEC/IEEE Floating-point Arithmetic Package. Those parts of the code (and + * some later contributions) are provided under that license, as detailed below. + * It has subsequently been modified by contributors to the QEMU Project, + * so some portions are provided under: + * the SoftFloat-2a license + * the BSD license + * GPL-v2-or-later + * + * Any future contributions to this file after December 1st 2014 will be + * taken to be licensed under the Softfloat-2a license unless specifically + * indicated otherwise. + */ + +static void partsN(return_nan)(FloatPartsN *a, float_status *s) +{ + switch (a->cls) { + case float_class_snan: + float_raise(float_flag_invalid, s); + if (s->default_nan_mode) { + parts_default_nan(a, s); + } else { + parts_silence_nan(a, s); + } + break; + case float_class_qnan: + if (s->default_nan_mode) { + parts_default_nan(a, s); + } + break; + default: + g_assert_not_reached(); + } +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 08fd812ea0..bdc3125e5c 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -709,6 +709,10 @@ static float128 float128_pack_raw(const FloatParts128 *p) #define parts_default_nan(P, S) PARTS_GENERIC_64_128(default_nan, P)(P, S) #define parts_silence_nan(P, S) PARTS_GENERIC_64_128(silence_nan, P)(P, S) +static void parts64_return_nan(FloatParts64 *a, float_status *s); +static void parts128_return_nan(FloatParts128 *a, float_status *s); + +#define parts_return_nan(P, S) PARTS_GENERIC_64_128(return_nan, P)(P, S) /* * Helper functions for softfloat-parts.c.inc, per-size operations. @@ -915,22 +919,6 @@ static FloatParts64 round_canonical(FloatParts64 p, float_status *s, return p; } -static FloatParts64 return_nan(FloatParts64 a, float_status *s) -{ - g_assert(is_nan(a.cls)); - if (is_snan(a.cls)) { - float_raise(float_flag_invalid, s); - if (!s->default_nan_mode) { - parts_silence_nan(&a, s); - return a; - } - } else if (!s->default_nan_mode) { - return a; - } - parts_default_nan(&a, s); - return a; -} - static FloatParts64 pick_nan(FloatParts64 a, FloatParts64 b, float_status *s) { if (is_snan(a.cls) || is_snan(b.cls)) { @@ -992,6 +980,21 @@ static FloatParts64 pick_nan_muladd(FloatParts64 a, FloatParts64 b, FloatParts64 return a; } +#define partsN(NAME) parts64_##NAME +#define FloatPartsN FloatParts64 + +#include "softfloat-parts.c.inc" + +#undef partsN +#undef FloatPartsN +#define partsN(NAME) parts128_##NAME +#define FloatPartsN FloatParts128 + +#include "softfloat-parts.c.inc" + +#undef partsN +#undef FloatPartsN + /* * Pack/unpack routines with a specific FloatFmt. */ @@ -2066,7 +2069,7 @@ static FloatParts64 float_to_float(FloatParts64 a, const FloatFmt *dstf, break; } } else if (is_nan(a.cls)) { - return return_nan(a, s); + parts_return_nan(&a, s); } return a; } @@ -2195,7 +2198,8 @@ static FloatParts64 round_to_int(FloatParts64 a, FloatRoundMode rmode, switch (a.cls) { case float_class_qnan: case float_class_snan: - return return_nan(a, s); + parts_return_nan(&a, s); + break; case float_class_zero: case float_class_inf: @@ -3591,7 +3595,7 @@ FloatRelation bfloat16_compare_quiet(bfloat16 a, bfloat16 b, float_status *s) static FloatParts64 scalbn_decomposed(FloatParts64 a, int n, float_status *s) { if (unlikely(is_nan(a.cls))) { - return return_nan(a, s); + parts_return_nan(&a, s); } if (a.cls == float_class_normal) { /* The largest float type (even though not supported by FloatParts64) @@ -3659,7 +3663,8 @@ static FloatParts64 sqrt_float(FloatParts64 a, float_status *s, const FloatFmt * int bit, last_bit; if (is_nan(a.cls)) { - return return_nan(a, s); + parts_return_nan(&a, s); + return a; } if (a.cls == float_class_zero) { return a; /* sqrt(+-0) = +-0 */ From 22c355f41785f258689cbba0af1c1e78365c4180 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 17:03:11 -0700 Subject: [PATCH 0657/3028] softfloat: Move pick_nan to softfloat-parts.c.inc At the same time, convert to pointers, rename to parts$N_pick_nan and define a macro for parts_pick_nan using QEMU_GENERIC. Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 25 ++++++++++++++++ fpu/softfloat.c | 62 ++++++++++++++++++++++----------------- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index 2a3075d6fe..11a71650f7 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -35,3 +35,28 @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s) g_assert_not_reached(); } } + +static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, + float_status *s) +{ + if (is_snan(a->cls) || is_snan(b->cls)) { + float_raise(float_flag_invalid, s); + } + + if (s->default_nan_mode) { + parts_default_nan(a, s); + } else { + int cmp = frac_cmp(a, b); + if (cmp == 0) { + cmp = a->sign < b->sign; + } + + if (pickNaN(a->cls, b->cls, cmp > 0, s)) { + a = b; + } + if (is_snan(a->cls)) { + parts_silence_nan(a, s); + } + } + return a; +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index bdc3125e5c..019b34d378 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -714,10 +714,39 @@ static void parts128_return_nan(FloatParts128 *a, float_status *s); #define parts_return_nan(P, S) PARTS_GENERIC_64_128(return_nan, P)(P, S) +static FloatParts64 *parts64_pick_nan(FloatParts64 *a, FloatParts64 *b, + float_status *s); +static FloatParts128 *parts128_pick_nan(FloatParts128 *a, FloatParts128 *b, + float_status *s); + +#define parts_pick_nan(A, B, S) PARTS_GENERIC_64_128(pick_nan, A)(A, B, S) + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ +#define FRAC_GENERIC_64_128(NAME, P) \ + QEMU_GENERIC(P, (FloatParts128 *, frac128_##NAME), frac64_##NAME) + +static int frac64_cmp(FloatParts64 *a, FloatParts64 *b) +{ + return a->frac == b->frac ? 0 : a->frac < b->frac ? -1 : 1; +} + +static int frac128_cmp(FloatParts128 *a, FloatParts128 *b) +{ + uint64_t ta = a->frac_hi, tb = b->frac_hi; + if (ta == tb) { + ta = a->frac_lo, tb = b->frac_lo; + if (ta == tb) { + return 0; + } + } + return ta < tb ? -1 : 1; +} + +#define frac_cmp(A, B) FRAC_GENERIC_64_128(cmp, A)(A, B) + static void frac128_shl(FloatParts128 *a, int c) { shift128Left(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo); @@ -919,27 +948,6 @@ static FloatParts64 round_canonical(FloatParts64 p, float_status *s, return p; } -static FloatParts64 pick_nan(FloatParts64 a, FloatParts64 b, float_status *s) -{ - if (is_snan(a.cls) || is_snan(b.cls)) { - float_raise(float_flag_invalid, s); - } - - if (s->default_nan_mode) { - parts_default_nan(&a, s); - } else { - if (pickNaN(a.cls, b.cls, - a.frac > b.frac || - (a.frac == b.frac && a.sign < b.sign), s)) { - a = b; - } - if (is_snan(a.cls)) { - parts_silence_nan(&a, s); - } - } - return a; -} - static FloatParts64 pick_nan_muladd(FloatParts64 a, FloatParts64 b, FloatParts64 c, bool inf_zero, float_status *s) { @@ -1107,7 +1115,7 @@ static FloatParts64 addsub_floats(FloatParts64 a, FloatParts64 b, bool subtract, return a; } if (is_nan(a.cls) || is_nan(b.cls)) { - return pick_nan(a, b, s); + return *parts_pick_nan(&a, &b, s); } if (a.cls == float_class_inf) { if (b.cls == float_class_inf) { @@ -1145,7 +1153,7 @@ static FloatParts64 addsub_floats(FloatParts64 a, FloatParts64 b, bool subtract, return a; } if (is_nan(a.cls) || is_nan(b.cls)) { - return pick_nan(a, b, s); + return *parts_pick_nan(&a, &b, s); } if (a.cls == float_class_inf || b.cls == float_class_zero) { return a; @@ -1361,7 +1369,7 @@ static FloatParts64 mul_floats(FloatParts64 a, FloatParts64 b, float_status *s) } /* handle all the NaN cases */ if (is_nan(a.cls) || is_nan(b.cls)) { - return pick_nan(a, b, s); + return *parts_pick_nan(&a, &b, s); } /* Inf * Zero == NaN */ if ((a.cls == float_class_inf && b.cls == float_class_zero) || @@ -1888,7 +1896,7 @@ static FloatParts64 div_floats(FloatParts64 a, FloatParts64 b, float_status *s) } /* handle all the NaN cases */ if (is_nan(a.cls) || is_nan(b.cls)) { - return pick_nan(a, b, s); + return *parts_pick_nan(&a, &b, s); } /* 0/0 or Inf/Inf */ if (a.cls == b.cls @@ -3296,14 +3304,14 @@ static FloatParts64 minmax_floats(FloatParts64 a, FloatParts64 b, bool ismin, * the invalid exception is raised. */ if (is_snan(a.cls) || is_snan(b.cls)) { - return pick_nan(a, b, s); + return *parts_pick_nan(&a, &b, s); } else if (is_nan(a.cls) && !is_nan(b.cls)) { return b; } else if (is_nan(b.cls) && !is_nan(a.cls)) { return a; } } - return pick_nan(a, b, s); + return *parts_pick_nan(&a, &b, s); } else { int a_exp, b_exp; From 979582d07115ff3c5c0c1f2bed90a2db91191281 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 17:12:12 -0700 Subject: [PATCH 0658/3028] softfloat: Move pick_nan_muladd to softfloat-parts.c.inc At the same time, convert to pointers, rename to pick_nan_muladd$N and define a macro for pick_nan_muladd using QEMU_GENERIC. Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 40 +++++++++++++++++++++++++++++ fpu/softfloat.c | 53 ++++++++++----------------------------- 2 files changed, 53 insertions(+), 40 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index 11a71650f7..a78d61ea07 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -60,3 +60,43 @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b, } return a; } + +static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, + FloatPartsN *c, float_status *s, + int ab_mask, int abc_mask) +{ + int which; + + if (unlikely(abc_mask & float_cmask_snan)) { + float_raise(float_flag_invalid, s); + } + + which = pickNaNMulAdd(a->cls, b->cls, c->cls, + ab_mask == float_cmask_infzero, s); + + if (s->default_nan_mode || which == 3) { + /* + * Note that this check is after pickNaNMulAdd so that function + * has an opportunity to set the Invalid flag for infzero. + */ + parts_default_nan(a, s); + return a; + } + + switch (which) { + case 0: + break; + case 1: + a = b; + break; + case 2: + a = c; + break; + default: + g_assert_not_reached(); + } + if (is_snan(a->cls)) { + parts_silence_nan(a, s); + } + return a; +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 019b34d378..df004dbe2f 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -721,6 +721,18 @@ static FloatParts128 *parts128_pick_nan(FloatParts128 *a, FloatParts128 *b, #define parts_pick_nan(A, B, S) PARTS_GENERIC_64_128(pick_nan, A)(A, B, S) +static FloatParts64 *parts64_pick_nan_muladd(FloatParts64 *a, FloatParts64 *b, + FloatParts64 *c, float_status *s, + int ab_mask, int abc_mask); +static FloatParts128 *parts128_pick_nan_muladd(FloatParts128 *a, + FloatParts128 *b, + FloatParts128 *c, + float_status *s, + int ab_mask, int abc_mask); + +#define parts_pick_nan_muladd(A, B, C, S, ABM, ABCM) \ + PARTS_GENERIC_64_128(pick_nan_muladd, A)(A, B, C, S, ABM, ABCM) + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ @@ -948,45 +960,6 @@ static FloatParts64 round_canonical(FloatParts64 p, float_status *s, return p; } -static FloatParts64 pick_nan_muladd(FloatParts64 a, FloatParts64 b, FloatParts64 c, - bool inf_zero, float_status *s) -{ - int which; - - if (is_snan(a.cls) || is_snan(b.cls) || is_snan(c.cls)) { - float_raise(float_flag_invalid, s); - } - - which = pickNaNMulAdd(a.cls, b.cls, c.cls, inf_zero, s); - - if (s->default_nan_mode) { - /* Note that this check is after pickNaNMulAdd so that function - * has an opportunity to set the Invalid flag. - */ - which = 3; - } - - switch (which) { - case 0: - break; - case 1: - a = b; - break; - case 2: - a = c; - break; - case 3: - parts_default_nan(&a, s); - break; - default: - g_assert_not_reached(); - } - - if (is_snan(a.cls)) { - parts_silence_nan(&a, s); - } - return a; -} #define partsN(NAME) parts64_##NAME #define FloatPartsN FloatParts64 @@ -1497,7 +1470,7 @@ static FloatParts64 muladd_floats(FloatParts64 a, FloatParts64 b, FloatParts64 c * off to the target-specific pick-a-NaN routine. */ if (unlikely(abc_mask & float_cmask_anynan)) { - return pick_nan_muladd(a, b, c, inf_zero, s); + return *parts_pick_nan_muladd(&a, &b, &c, s, ab_mask, abc_mask); } if (inf_zero) { From d46975bce10e163b9f10a7f569d3e046114d8580 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 8 Nov 2020 13:01:55 -0800 Subject: [PATCH 0659/3028] softfloat: Move sf_canonicalize to softfloat-parts.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time, convert to pointers, rename to parts$N_canonicalize and define a macro for parts_canonicalize using QEMU_GENERIC. Rearrange the cases to recognize float_class_normal as early as possible. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 33 +++++++++++ fpu/softfloat.c | 117 +++++++++++++++++++++++++------------- 2 files changed, 112 insertions(+), 38 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index a78d61ea07..25bf99bd0f 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -100,3 +100,36 @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b, } return a; } + +/* + * Canonicalize the FloatParts structure. Determine the class, + * unbias the exponent, and normalize the fraction. + */ +static void partsN(canonicalize)(FloatPartsN *p, float_status *status, + const FloatFmt *fmt) +{ + if (unlikely(p->exp == 0)) { + if (likely(frac_eqz(p))) { + p->cls = float_class_zero; + } else if (status->flush_inputs_to_zero) { + float_raise(float_flag_input_denormal, status); + p->cls = float_class_zero; + frac_clear(p); + } else { + int shift = frac_normalize(p); + p->cls = float_class_normal; + p->exp = fmt->frac_shift - fmt->exp_bias - shift + 1; + } + } else if (likely(p->exp < fmt->exp_max) || fmt->arm_althp) { + p->cls = float_class_normal; + p->exp -= fmt->exp_bias; + frac_shl(p, fmt->frac_shift); + p->frac_hi |= DECOMPOSED_IMPLICIT_BIT; + } else if (likely(frac_eqz(p))) { + p->cls = float_class_inf; + } else { + frac_shl(p, fmt->frac_shift); + p->cls = (parts_is_snan_frac(p->frac_hi, status) + ? float_class_snan : float_class_qnan); + } +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index df004dbe2f..535261db44 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -733,6 +733,14 @@ static FloatParts128 *parts128_pick_nan_muladd(FloatParts128 *a, #define parts_pick_nan_muladd(A, B, C, S, ABM, ABCM) \ PARTS_GENERIC_64_128(pick_nan_muladd, A)(A, B, C, S, ABM, ABCM) +static void parts64_canonicalize(FloatParts64 *p, float_status *status, + const FloatFmt *fmt); +static void parts128_canonicalize(FloatParts128 *p, float_status *status, + const FloatFmt *fmt); + +#define parts_canonicalize(A, S, F) \ + PARTS_GENERIC_64_128(canonicalize, A)(A, S, F) + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ @@ -759,52 +767,85 @@ static int frac128_cmp(FloatParts128 *a, FloatParts128 *b) #define frac_cmp(A, B) FRAC_GENERIC_64_128(cmp, A)(A, B) +static void frac64_clear(FloatParts64 *a) +{ + a->frac = 0; +} + +static void frac128_clear(FloatParts128 *a) +{ + a->frac_hi = a->frac_lo = 0; +} + +#define frac_clear(A) FRAC_GENERIC_64_128(clear, A)(A) + +static bool frac64_eqz(FloatParts64 *a) +{ + return a->frac == 0; +} + +static bool frac128_eqz(FloatParts128 *a) +{ + return (a->frac_hi | a->frac_lo) == 0; +} + +#define frac_eqz(A) FRAC_GENERIC_64_128(eqz, A)(A) + +static int frac64_normalize(FloatParts64 *a) +{ + if (a->frac) { + int shift = clz64(a->frac); + a->frac <<= shift; + return shift; + } + return 64; +} + +static int frac128_normalize(FloatParts128 *a) +{ + if (a->frac_hi) { + int shl = clz64(a->frac_hi); + if (shl) { + int shr = 64 - shl; + a->frac_hi = (a->frac_hi << shl) | (a->frac_lo >> shr); + a->frac_lo = (a->frac_lo << shl); + } + return shl; + } else if (a->frac_lo) { + int shl = clz64(a->frac_lo); + a->frac_hi = (a->frac_lo << shl); + a->frac_lo = 0; + return shl + 64; + } + return 128; +} + +#define frac_normalize(A) FRAC_GENERIC_64_128(normalize, A)(A) + +static void frac64_shl(FloatParts64 *a, int c) +{ + a->frac <<= c; +} + static void frac128_shl(FloatParts128 *a, int c) { shift128Left(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo); } -#define frac_shl(A, C) frac128_shl(A, C) +#define frac_shl(A, C) FRAC_GENERIC_64_128(shl, A)(A, C) + +static void frac64_shr(FloatParts64 *a, int c) +{ + a->frac >>= c; +} static void frac128_shr(FloatParts128 *a, int c) { shift128Right(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo); } -#define frac_shr(A, C) frac128_shr(A, C) +#define frac_shr(A, C) FRAC_GENERIC_64_128(shr, A)(A, C) -/* Canonicalize EXP and FRAC, setting CLS. */ -static FloatParts64 sf_canonicalize(FloatParts64 part, const FloatFmt *parm, - float_status *status) -{ - if (part.exp == parm->exp_max && !parm->arm_althp) { - if (part.frac == 0) { - part.cls = float_class_inf; - } else { - part.frac <<= parm->frac_shift; - part.cls = (parts_is_snan_frac(part.frac, status) - ? float_class_snan : float_class_qnan); - } - } else if (part.exp == 0) { - if (likely(part.frac == 0)) { - part.cls = float_class_zero; - } else if (status->flush_inputs_to_zero) { - float_raise(float_flag_input_denormal, status); - part.cls = float_class_zero; - part.frac = 0; - } else { - int shift = clz64(part.frac); - part.cls = float_class_normal; - part.exp = parm->frac_shift - parm->exp_bias - shift + 1; - part.frac <<= shift; - } - } else { - part.cls = float_class_normal; - part.exp -= parm->exp_bias; - part.frac = DECOMPOSED_IMPLICIT_BIT + (part.frac << parm->frac_shift); - } - return part; -} /* Round and uncanonicalize a floating-point number by parts. There * are FRAC_SHIFT bits that may require rounding at the bottom of the @@ -984,7 +1025,7 @@ static void float16a_unpack_canonical(FloatParts64 *p, float16 f, float_status *s, const FloatFmt *params) { float16_unpack_raw(p, f); - *p = sf_canonicalize(*p, params, s); + parts_canonicalize(p, s, params); } static void float16_unpack_canonical(FloatParts64 *p, float16 f, @@ -997,7 +1038,7 @@ static void bfloat16_unpack_canonical(FloatParts64 *p, bfloat16 f, float_status *s) { bfloat16_unpack_raw(p, f); - *p = sf_canonicalize(*p, &bfloat16_params, s); + parts_canonicalize(p, s, &bfloat16_params); } static float16 float16a_round_pack_canonical(FloatParts64 *p, @@ -1025,7 +1066,7 @@ static void float32_unpack_canonical(FloatParts64 *p, float32 f, float_status *s) { float32_unpack_raw(p, f); - *p = sf_canonicalize(*p, &float32_params, s); + parts_canonicalize(p, s, &float32_params); } static float32 float32_round_pack_canonical(FloatParts64 *p, @@ -1039,7 +1080,7 @@ static void float64_unpack_canonical(FloatParts64 *p, float64 f, float_status *s) { float64_unpack_raw(p, f); - *p = sf_canonicalize(*p, &float64_params, s); + parts_canonicalize(p, s, &float64_params); } static float64 float64_round_pack_canonical(FloatParts64 *p, From ee6959f277f7667034be3584897f8e390fe6a61e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 17:53:55 -0700 Subject: [PATCH 0660/3028] softfloat: Move round_canonical to softfloat-parts.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time, convert to pointers, renaming to parts$N_uncanon, and define a macro for parts_uncanon using QEMU_GENERIC. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 148 ++++++++++++++++++++++++++++ fpu/softfloat.c | 201 +++++++++----------------------------- 2 files changed, 193 insertions(+), 156 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index 25bf99bd0f..efdc724770 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -133,3 +133,151 @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status, ? float_class_snan : float_class_qnan); } } + +/* + * Round and uncanonicalize a floating-point number by parts. There + * are FRAC_SHIFT bits that may require rounding at the bottom of the + * fraction; these bits will be removed. The exponent will be biased + * by EXP_BIAS and must be bounded by [EXP_MAX-1, 0]. + */ +static void partsN(uncanon)(FloatPartsN *p, float_status *s, + const FloatFmt *fmt) +{ + const int exp_max = fmt->exp_max; + const int frac_shift = fmt->frac_shift; + const uint64_t frac_lsb = fmt->frac_lsb; + const uint64_t frac_lsbm1 = fmt->frac_lsbm1; + const uint64_t round_mask = fmt->round_mask; + const uint64_t roundeven_mask = fmt->roundeven_mask; + uint64_t inc; + bool overflow_norm; + int exp, flags = 0; + + if (unlikely(p->cls != float_class_normal)) { + switch (p->cls) { + case float_class_zero: + p->exp = 0; + frac_clear(p); + return; + case float_class_inf: + g_assert(!fmt->arm_althp); + p->exp = fmt->exp_max; + frac_clear(p); + return; + case float_class_qnan: + case float_class_snan: + g_assert(!fmt->arm_althp); + p->exp = fmt->exp_max; + frac_shr(p, fmt->frac_shift); + return; + default: + break; + } + g_assert_not_reached(); + } + + switch (s->float_rounding_mode) { + case float_round_nearest_even: + overflow_norm = false; + inc = ((p->frac_lo & roundeven_mask) != frac_lsbm1 ? frac_lsbm1 : 0); + break; + case float_round_ties_away: + overflow_norm = false; + inc = frac_lsbm1; + break; + case float_round_to_zero: + overflow_norm = true; + inc = 0; + break; + case float_round_up: + inc = p->sign ? 0 : round_mask; + overflow_norm = p->sign; + break; + case float_round_down: + inc = p->sign ? round_mask : 0; + overflow_norm = !p->sign; + break; + case float_round_to_odd: + overflow_norm = true; + inc = p->frac_lo & frac_lsb ? 0 : round_mask; + break; + default: + g_assert_not_reached(); + } + + exp = p->exp + fmt->exp_bias; + if (likely(exp > 0)) { + if (p->frac_lo & round_mask) { + flags |= float_flag_inexact; + if (frac_addi(p, p, inc)) { + frac_shr(p, 1); + p->frac_hi |= DECOMPOSED_IMPLICIT_BIT; + exp++; + } + } + frac_shr(p, frac_shift); + + if (fmt->arm_althp) { + /* ARM Alt HP eschews Inf and NaN for a wider exponent. */ + if (unlikely(exp > exp_max)) { + /* Overflow. Return the maximum normal. */ + flags = float_flag_invalid; + exp = exp_max; + frac_allones(p); + } + } else if (unlikely(exp >= exp_max)) { + flags |= float_flag_overflow | float_flag_inexact; + if (overflow_norm) { + exp = exp_max - 1; + frac_allones(p); + } else { + p->cls = float_class_inf; + exp = exp_max; + frac_clear(p); + } + } + } else if (s->flush_to_zero) { + flags |= float_flag_output_denormal; + p->cls = float_class_zero; + exp = 0; + frac_clear(p); + } else { + bool is_tiny = s->tininess_before_rounding || exp < 0; + + if (!is_tiny) { + FloatPartsN discard; + is_tiny = !frac_addi(&discard, p, inc); + } + + frac_shrjam(p, 1 - exp); + + if (p->frac_lo & round_mask) { + /* Need to recompute round-to-even/round-to-odd. */ + switch (s->float_rounding_mode) { + case float_round_nearest_even: + inc = ((p->frac_lo & roundeven_mask) != frac_lsbm1 + ? frac_lsbm1 : 0); + break; + case float_round_to_odd: + inc = p->frac_lo & frac_lsb ? 0 : round_mask; + break; + default: + break; + } + flags |= float_flag_inexact; + frac_addi(p, p, inc); + } + + exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) != 0; + frac_shr(p, frac_shift); + + if (is_tiny && (flags & float_flag_inexact)) { + flags |= float_flag_underflow; + } + if (exp == 0 && frac_eqz(p)) { + p->cls = float_class_zero; + } + } + p->exp = exp; + float_raise(flags, s); +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 535261db44..817a91de85 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -741,6 +741,14 @@ static void parts128_canonicalize(FloatParts128 *p, float_status *status, #define parts_canonicalize(A, S, F) \ PARTS_GENERIC_64_128(canonicalize, A)(A, S, F) +static void parts64_uncanon(FloatParts64 *p, float_status *status, + const FloatFmt *fmt); +static void parts128_uncanon(FloatParts128 *p, float_status *status, + const FloatFmt *fmt); + +#define parts_uncanon(A, S, F) \ + PARTS_GENERIC_64_128(uncanon, A)(A, S, F) + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ @@ -748,6 +756,31 @@ static void parts128_canonicalize(FloatParts128 *p, float_status *status, #define FRAC_GENERIC_64_128(NAME, P) \ QEMU_GENERIC(P, (FloatParts128 *, frac128_##NAME), frac64_##NAME) +static bool frac64_addi(FloatParts64 *r, FloatParts64 *a, uint64_t c) +{ + return uadd64_overflow(a->frac, c, &r->frac); +} + +static bool frac128_addi(FloatParts128 *r, FloatParts128 *a, uint64_t c) +{ + c = uadd64_overflow(a->frac_lo, c, &r->frac_lo); + return uadd64_overflow(a->frac_hi, c, &r->frac_hi); +} + +#define frac_addi(R, A, C) FRAC_GENERIC_64_128(addi, R)(R, A, C) + +static void frac64_allones(FloatParts64 *a) +{ + a->frac = -1; +} + +static void frac128_allones(FloatParts128 *a) +{ + a->frac_hi = a->frac_lo = -1; +} + +#define frac_allones(A) FRAC_GENERIC_64_128(allones, A)(A) + static int frac64_cmp(FloatParts64 *a, FloatParts64 *b) { return a->frac == b->frac ? 0 : a->frac < b->frac ? -1 : 1; @@ -846,161 +879,17 @@ static void frac128_shr(FloatParts128 *a, int c) #define frac_shr(A, C) FRAC_GENERIC_64_128(shr, A)(A, C) - -/* Round and uncanonicalize a floating-point number by parts. There - * are FRAC_SHIFT bits that may require rounding at the bottom of the - * fraction; these bits will be removed. The exponent will be biased - * by EXP_BIAS and must be bounded by [EXP_MAX-1, 0]. - */ - -static FloatParts64 round_canonical(FloatParts64 p, float_status *s, - const FloatFmt *parm) +static void frac64_shrjam(FloatParts64 *a, int c) { - const uint64_t frac_lsb = parm->frac_lsb; - const uint64_t frac_lsbm1 = parm->frac_lsbm1; - const uint64_t round_mask = parm->round_mask; - const uint64_t roundeven_mask = parm->roundeven_mask; - const int exp_max = parm->exp_max; - const int frac_shift = parm->frac_shift; - uint64_t frac, inc; - int exp, flags = 0; - bool overflow_norm; - - frac = p.frac; - exp = p.exp; - - switch (p.cls) { - case float_class_normal: - switch (s->float_rounding_mode) { - case float_round_nearest_even: - overflow_norm = false; - inc = ((frac & roundeven_mask) != frac_lsbm1 ? frac_lsbm1 : 0); - break; - case float_round_ties_away: - overflow_norm = false; - inc = frac_lsbm1; - break; - case float_round_to_zero: - overflow_norm = true; - inc = 0; - break; - case float_round_up: - inc = p.sign ? 0 : round_mask; - overflow_norm = p.sign; - break; - case float_round_down: - inc = p.sign ? round_mask : 0; - overflow_norm = !p.sign; - break; - case float_round_to_odd: - overflow_norm = true; - inc = frac & frac_lsb ? 0 : round_mask; - break; - default: - g_assert_not_reached(); - } - - exp += parm->exp_bias; - if (likely(exp > 0)) { - if (frac & round_mask) { - flags |= float_flag_inexact; - if (uadd64_overflow(frac, inc, &frac)) { - frac = (frac >> 1) | DECOMPOSED_IMPLICIT_BIT; - exp++; - } - } - frac >>= frac_shift; - - if (parm->arm_althp) { - /* ARM Alt HP eschews Inf and NaN for a wider exponent. */ - if (unlikely(exp > exp_max)) { - /* Overflow. Return the maximum normal. */ - flags = float_flag_invalid; - exp = exp_max; - frac = -1; - } - } else if (unlikely(exp >= exp_max)) { - flags |= float_flag_overflow | float_flag_inexact; - if (overflow_norm) { - exp = exp_max - 1; - frac = -1; - } else { - p.cls = float_class_inf; - goto do_inf; - } - } - } else if (s->flush_to_zero) { - flags |= float_flag_output_denormal; - p.cls = float_class_zero; - goto do_zero; - } else { - bool is_tiny = s->tininess_before_rounding || (exp < 0); - - if (!is_tiny) { - uint64_t discard; - is_tiny = !uadd64_overflow(frac, inc, &discard); - } - - shift64RightJamming(frac, 1 - exp, &frac); - if (frac & round_mask) { - /* Need to recompute round-to-even. */ - switch (s->float_rounding_mode) { - case float_round_nearest_even: - inc = ((frac & roundeven_mask) != frac_lsbm1 - ? frac_lsbm1 : 0); - break; - case float_round_to_odd: - inc = frac & frac_lsb ? 0 : round_mask; - break; - default: - break; - } - flags |= float_flag_inexact; - frac += inc; - } - - exp = (frac & DECOMPOSED_IMPLICIT_BIT ? 1 : 0); - frac >>= frac_shift; - - if (is_tiny && (flags & float_flag_inexact)) { - flags |= float_flag_underflow; - } - if (exp == 0 && frac == 0) { - p.cls = float_class_zero; - } - } - break; - - case float_class_zero: - do_zero: - exp = 0; - frac = 0; - break; - - case float_class_inf: - do_inf: - assert(!parm->arm_althp); - exp = exp_max; - frac = 0; - break; - - case float_class_qnan: - case float_class_snan: - assert(!parm->arm_althp); - exp = exp_max; - frac >>= parm->frac_shift; - break; - - default: - g_assert_not_reached(); - } - - float_raise(flags, s); - p.exp = exp; - p.frac = frac; - return p; + shift64RightJamming(a->frac, c, &a->frac); } +static void frac128_shrjam(FloatParts128 *a, int c) +{ + shift128RightJamming(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo); +} + +#define frac_shrjam(A, C) FRAC_GENERIC_64_128(shrjam, A)(A, C) #define partsN(NAME) parts64_##NAME #define FloatPartsN FloatParts64 @@ -1045,7 +934,7 @@ static float16 float16a_round_pack_canonical(FloatParts64 *p, float_status *s, const FloatFmt *params) { - *p = round_canonical(*p, s, params); + parts_uncanon(p, s, params); return float16_pack_raw(p); } @@ -1058,7 +947,7 @@ static float16 float16_round_pack_canonical(FloatParts64 *p, static bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p, float_status *s) { - *p = round_canonical(*p, s, &bfloat16_params); + parts_uncanon(p, s, &bfloat16_params); return bfloat16_pack_raw(p); } @@ -1072,7 +961,7 @@ static void float32_unpack_canonical(FloatParts64 *p, float32 f, static float32 float32_round_pack_canonical(FloatParts64 *p, float_status *s) { - *p = round_canonical(*p, s, &float32_params); + parts_uncanon(p, s, &float32_params); return float32_pack_raw(p); } @@ -1086,7 +975,7 @@ static void float64_unpack_canonical(FloatParts64 *p, float64 f, static float64 float64_round_pack_canonical(FloatParts64 *p, float_status *s) { - *p = round_canonical(*p, s, &float64_params); + parts_uncanon(p, s, &float64_params); return float64_pack_raw(p); } From cb3ad0365fb17f679c69057f384f1f4928c19647 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 13 Nov 2020 04:19:08 +0000 Subject: [PATCH 0661/3028] softfloat: Use uadd64_carry, usub64_borrow in softfloat-macros.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use compiler support for carry arithmetic. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- include/fpu/softfloat-macros.h | 95 +++++++++------------------------- 1 file changed, 25 insertions(+), 70 deletions(-) diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h index a35ec2893a..2e3760a9c1 100644 --- a/include/fpu/softfloat-macros.h +++ b/include/fpu/softfloat-macros.h @@ -83,6 +83,7 @@ this code that are retained. #define FPU_SOFTFLOAT_MACROS_H #include "fpu/softfloat-types.h" +#include "qemu/host-utils.h" /*---------------------------------------------------------------------------- | Shifts `a' right by the number of bits given in `count'. If any nonzero @@ -403,16 +404,12 @@ static inline void | are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. *----------------------------------------------------------------------------*/ -static inline void - add128( - uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr ) +static inline void add128(uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, + uint64_t *z0Ptr, uint64_t *z1Ptr) { - uint64_t z1; - - z1 = a1 + b1; - *z1Ptr = z1; - *z0Ptr = a0 + b0 + ( z1 < a1 ); - + bool c = 0; + *z1Ptr = uadd64_carry(a1, b1, &c); + *z0Ptr = uadd64_carry(a0, b0, &c); } /*---------------------------------------------------------------------------- @@ -423,34 +420,14 @@ static inline void | `z1Ptr', and `z2Ptr'. *----------------------------------------------------------------------------*/ -static inline void - add192( - uint64_t a0, - uint64_t a1, - uint64_t a2, - uint64_t b0, - uint64_t b1, - uint64_t b2, - uint64_t *z0Ptr, - uint64_t *z1Ptr, - uint64_t *z2Ptr - ) +static inline void add192(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t b0, uint64_t b1, uint64_t b2, + uint64_t *z0Ptr, uint64_t *z1Ptr, uint64_t *z2Ptr) { - uint64_t z0, z1, z2; - int8_t carry0, carry1; - - z2 = a2 + b2; - carry1 = ( z2 < a2 ); - z1 = a1 + b1; - carry0 = ( z1 < a1 ); - z0 = a0 + b0; - z1 += carry1; - z0 += ( z1 < carry1 ); - z0 += carry0; - *z2Ptr = z2; - *z1Ptr = z1; - *z0Ptr = z0; - + bool c = 0; + *z2Ptr = uadd64_carry(a2, b2, &c); + *z1Ptr = uadd64_carry(a1, b1, &c); + *z0Ptr = uadd64_carry(a0, b0, &c); } /*---------------------------------------------------------------------------- @@ -461,14 +438,12 @@ static inline void | `z1Ptr'. *----------------------------------------------------------------------------*/ -static inline void - sub128( - uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, uint64_t *z0Ptr, uint64_t *z1Ptr ) +static inline void sub128(uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1, + uint64_t *z0Ptr, uint64_t *z1Ptr) { - - *z1Ptr = a1 - b1; - *z0Ptr = a0 - b0 - ( a1 < b1 ); - + bool c = 0; + *z1Ptr = usub64_borrow(a1, b1, &c); + *z0Ptr = usub64_borrow(a0, b0, &c); } /*---------------------------------------------------------------------------- @@ -479,34 +454,14 @@ static inline void | pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. *----------------------------------------------------------------------------*/ -static inline void - sub192( - uint64_t a0, - uint64_t a1, - uint64_t a2, - uint64_t b0, - uint64_t b1, - uint64_t b2, - uint64_t *z0Ptr, - uint64_t *z1Ptr, - uint64_t *z2Ptr - ) +static inline void sub192(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t b0, uint64_t b1, uint64_t b2, + uint64_t *z0Ptr, uint64_t *z1Ptr, uint64_t *z2Ptr) { - uint64_t z0, z1, z2; - int8_t borrow0, borrow1; - - z2 = a2 - b2; - borrow1 = ( a2 < b2 ); - z1 = a1 - b1; - borrow0 = ( a1 < b1 ); - z0 = a0 - b0; - z0 -= ( z1 < borrow1 ); - z1 -= borrow1; - z0 -= borrow0; - *z2Ptr = z2; - *z1Ptr = z1; - *z0Ptr = z0; - + bool c = 0; + *z2Ptr = usub64_borrow(a2, b2, &c); + *z1Ptr = usub64_borrow(a1, b1, &c); + *z0Ptr = usub64_borrow(a0, b0, &c); } /*---------------------------------------------------------------------------- From da10a9074a630c1b1cfa9df5f510bbfdd3f7d327 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 22 Oct 2020 15:22:55 -0700 Subject: [PATCH 0662/3028] softfloat: Move addsub_floats to softfloat-parts.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for implementing multiple sizes. Rename to parts_addsub, split out parts_add/sub_normal for future reuse with muladd. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-parts-addsub.c.inc | 62 ++++++++ fpu/softfloat-parts.c.inc | 81 ++++++++++ fpu/softfloat.c | 253 ++++++++++++++----------------- 3 files changed, 255 insertions(+), 141 deletions(-) create mode 100644 fpu/softfloat-parts-addsub.c.inc diff --git a/fpu/softfloat-parts-addsub.c.inc b/fpu/softfloat-parts-addsub.c.inc new file mode 100644 index 0000000000..ae5c1017c5 --- /dev/null +++ b/fpu/softfloat-parts-addsub.c.inc @@ -0,0 +1,62 @@ +/* + * Floating point arithmetic implementation + * + * The code in this source file is derived from release 2a of the SoftFloat + * IEC/IEEE Floating-point Arithmetic Package. Those parts of the code (and + * some later contributions) are provided under that license, as detailed below. + * It has subsequently been modified by contributors to the QEMU Project, + * so some portions are provided under: + * the SoftFloat-2a license + * the BSD license + * GPL-v2-or-later + * + * Any future contributions to this file after December 1st 2014 will be + * taken to be licensed under the Softfloat-2a license unless specifically + * indicated otherwise. + */ + +static void partsN(add_normal)(FloatPartsN *a, FloatPartsN *b) +{ + int exp_diff = a->exp - b->exp; + + if (exp_diff > 0) { + frac_shrjam(b, exp_diff); + } else if (exp_diff < 0) { + frac_shrjam(a, -exp_diff); + a->exp = b->exp; + } + + if (frac_add(a, a, b)) { + frac_shrjam(a, 1); + a->frac_hi |= DECOMPOSED_IMPLICIT_BIT; + a->exp += 1; + } +} + +static bool partsN(sub_normal)(FloatPartsN *a, FloatPartsN *b) +{ + int exp_diff = a->exp - b->exp; + int shift; + + if (exp_diff > 0) { + frac_shrjam(b, exp_diff); + frac_sub(a, a, b); + } else if (exp_diff < 0) { + a->exp = b->exp; + a->sign ^= 1; + frac_shrjam(a, -exp_diff); + frac_sub(a, b, a); + } else if (frac_sub(a, a, b)) { + /* Overflow means that A was less than B. */ + frac_neg(a); + a->sign ^= 1; + } + + shift = frac_normalize(a); + if (likely(shift < N)) { + a->exp -= shift; + return true; + } + a->cls = float_class_zero; + return false; +} diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index efdc724770..cfce9f6421 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -281,3 +281,84 @@ static void partsN(uncanon)(FloatPartsN *p, float_status *s, p->exp = exp; float_raise(flags, s); } + +/* + * Returns the result of adding or subtracting the values of the + * floating-point values `a' and `b'. The operation is performed + * according to the IEC/IEEE Standard for Binary Floating-Point + * Arithmetic. + */ +static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, + float_status *s, bool subtract) +{ + bool b_sign = b->sign ^ subtract; + int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); + + if (a->sign != b_sign) { + /* Subtraction */ + if (likely(ab_mask == float_cmask_normal)) { + if (parts_sub_normal(a, b)) { + return a; + } + /* Subtract was exact, fall through to set sign. */ + ab_mask = float_cmask_zero; + } + + if (ab_mask == float_cmask_zero) { + a->sign = s->float_rounding_mode == float_round_down; + return a; + } + + if (unlikely(ab_mask & float_cmask_anynan)) { + goto p_nan; + } + + if (ab_mask & float_cmask_inf) { + if (a->cls != float_class_inf) { + /* N - Inf */ + goto return_b; + } + if (b->cls != float_class_inf) { + /* Inf - N */ + return a; + } + /* Inf - Inf */ + float_raise(float_flag_invalid, s); + parts_default_nan(a, s); + return a; + } + } else { + /* Addition */ + if (likely(ab_mask == float_cmask_normal)) { + parts_add_normal(a, b); + return a; + } + + if (ab_mask == float_cmask_zero) { + return a; + } + + if (unlikely(ab_mask & float_cmask_anynan)) { + goto p_nan; + } + + if (ab_mask & float_cmask_inf) { + a->cls = float_class_inf; + return a; + } + } + + if (b->cls == float_class_zero) { + g_assert(a->cls == float_class_normal); + return a; + } + + g_assert(a->cls == float_class_zero); + g_assert(b->cls == float_class_normal); + return_b: + b->sign = b_sign; + return b; + + p_nan: + return parts_pick_nan(a, b, s); +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 817a91de85..afeef00097 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -749,6 +749,26 @@ static void parts128_uncanon(FloatParts128 *p, float_status *status, #define parts_uncanon(A, S, F) \ PARTS_GENERIC_64_128(uncanon, A)(A, S, F) +static void parts64_add_normal(FloatParts64 *a, FloatParts64 *b); +static void parts128_add_normal(FloatParts128 *a, FloatParts128 *b); + +#define parts_add_normal(A, B) \ + PARTS_GENERIC_64_128(add_normal, A)(A, B) + +static bool parts64_sub_normal(FloatParts64 *a, FloatParts64 *b); +static bool parts128_sub_normal(FloatParts128 *a, FloatParts128 *b); + +#define parts_sub_normal(A, B) \ + PARTS_GENERIC_64_128(sub_normal, A)(A, B) + +static FloatParts64 *parts64_addsub(FloatParts64 *a, FloatParts64 *b, + float_status *s, bool subtract); +static FloatParts128 *parts128_addsub(FloatParts128 *a, FloatParts128 *b, + float_status *s, bool subtract); + +#define parts_addsub(A, B, S, Z) \ + PARTS_GENERIC_64_128(addsub, A)(A, B, S, Z) + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ @@ -756,6 +776,21 @@ static void parts128_uncanon(FloatParts128 *p, float_status *status, #define FRAC_GENERIC_64_128(NAME, P) \ QEMU_GENERIC(P, (FloatParts128 *, frac128_##NAME), frac64_##NAME) +static bool frac64_add(FloatParts64 *r, FloatParts64 *a, FloatParts64 *b) +{ + return uadd64_overflow(a->frac, b->frac, &r->frac); +} + +static bool frac128_add(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b) +{ + bool c = 0; + r->frac_lo = uadd64_carry(a->frac_lo, b->frac_lo, &c); + r->frac_hi = uadd64_carry(a->frac_hi, b->frac_hi, &c); + return c; +} + +#define frac_add(R, A, B) FRAC_GENERIC_64_128(add, R)(R, A, B) + static bool frac64_addi(FloatParts64 *r, FloatParts64 *a, uint64_t c) { return uadd64_overflow(a->frac, c, &r->frac); @@ -824,6 +859,20 @@ static bool frac128_eqz(FloatParts128 *a) #define frac_eqz(A) FRAC_GENERIC_64_128(eqz, A)(A) +static void frac64_neg(FloatParts64 *a) +{ + a->frac = -a->frac; +} + +static void frac128_neg(FloatParts128 *a) +{ + bool c = 0; + a->frac_lo = usub64_borrow(0, a->frac_lo, &c); + a->frac_hi = usub64_borrow(0, a->frac_hi, &c); +} + +#define frac_neg(A) FRAC_GENERIC_64_128(neg, A)(A) + static int frac64_normalize(FloatParts64 *a) { if (a->frac) { @@ -891,18 +940,36 @@ static void frac128_shrjam(FloatParts128 *a, int c) #define frac_shrjam(A, C) FRAC_GENERIC_64_128(shrjam, A)(A, C) -#define partsN(NAME) parts64_##NAME -#define FloatPartsN FloatParts64 +static bool frac64_sub(FloatParts64 *r, FloatParts64 *a, FloatParts64 *b) +{ + return usub64_overflow(a->frac, b->frac, &r->frac); +} +static bool frac128_sub(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b) +{ + bool c = 0; + r->frac_lo = usub64_borrow(a->frac_lo, b->frac_lo, &c); + r->frac_hi = usub64_borrow(a->frac_hi, b->frac_hi, &c); + return c; +} + +#define frac_sub(R, A, B) FRAC_GENERIC_64_128(sub, R)(R, A, B) + +#define partsN(NAME) glue(glue(glue(parts,N),_),NAME) +#define FloatPartsN glue(FloatParts,N) + +#define N 64 + +#include "softfloat-parts-addsub.c.inc" #include "softfloat-parts.c.inc" -#undef partsN -#undef FloatPartsN -#define partsN(NAME) parts128_##NAME -#define FloatPartsN FloatParts128 +#undef N +#define N 128 +#include "softfloat-parts-addsub.c.inc" #include "softfloat-parts.c.inc" +#undef N #undef partsN #undef FloatPartsN @@ -980,165 +1047,73 @@ static float64 float64_round_pack_canonical(FloatParts64 *p, } /* - * Returns the result of adding or subtracting the values of the - * floating-point values `a' and `b'. The operation is performed - * according to the IEC/IEEE Standard for Binary Floating-Point - * Arithmetic. + * Addition and subtraction */ -static FloatParts64 addsub_floats(FloatParts64 a, FloatParts64 b, bool subtract, - float_status *s) +static float16 QEMU_FLATTEN +float16_addsub(float16 a, float16 b, float_status *status, bool subtract) { - bool a_sign = a.sign; - bool b_sign = b.sign ^ subtract; - - if (a_sign != b_sign) { - /* Subtraction */ - - if (a.cls == float_class_normal && b.cls == float_class_normal) { - if (a.exp > b.exp || (a.exp == b.exp && a.frac >= b.frac)) { - shift64RightJamming(b.frac, a.exp - b.exp, &b.frac); - a.frac = a.frac - b.frac; - } else { - shift64RightJamming(a.frac, b.exp - a.exp, &a.frac); - a.frac = b.frac - a.frac; - a.exp = b.exp; - a_sign ^= 1; - } - - if (a.frac == 0) { - a.cls = float_class_zero; - a.sign = s->float_rounding_mode == float_round_down; - } else { - int shift = clz64(a.frac); - a.frac = a.frac << shift; - a.exp = a.exp - shift; - a.sign = a_sign; - } - return a; - } - if (is_nan(a.cls) || is_nan(b.cls)) { - return *parts_pick_nan(&a, &b, s); - } - if (a.cls == float_class_inf) { - if (b.cls == float_class_inf) { - float_raise(float_flag_invalid, s); - parts_default_nan(&a, s); - } - return a; - } - if (a.cls == float_class_zero && b.cls == float_class_zero) { - a.sign = s->float_rounding_mode == float_round_down; - return a; - } - if (a.cls == float_class_zero || b.cls == float_class_inf) { - b.sign = a_sign ^ 1; - return b; - } - if (b.cls == float_class_zero) { - return a; - } - } else { - /* Addition */ - if (a.cls == float_class_normal && b.cls == float_class_normal) { - if (a.exp > b.exp) { - shift64RightJamming(b.frac, a.exp - b.exp, &b.frac); - } else if (a.exp < b.exp) { - shift64RightJamming(a.frac, b.exp - a.exp, &a.frac); - a.exp = b.exp; - } - - if (uadd64_overflow(a.frac, b.frac, &a.frac)) { - shift64RightJamming(a.frac, 1, &a.frac); - a.frac |= DECOMPOSED_IMPLICIT_BIT; - a.exp += 1; - } - return a; - } - if (is_nan(a.cls) || is_nan(b.cls)) { - return *parts_pick_nan(&a, &b, s); - } - if (a.cls == float_class_inf || b.cls == float_class_zero) { - return a; - } - if (b.cls == float_class_inf || a.cls == float_class_zero) { - b.sign = b_sign; - return b; - } - } - g_assert_not_reached(); -} - -/* - * Returns the result of adding or subtracting the floating-point - * values `a' and `b'. The operation is performed according to the - * IEC/IEEE Standard for Binary Floating-Point Arithmetic. - */ - -float16 QEMU_FLATTEN float16_add(float16 a, float16 b, float_status *status) -{ - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; float16_unpack_canonical(&pa, a, status); float16_unpack_canonical(&pb, b, status); - pr = addsub_floats(pa, pb, false, status); + pr = parts_addsub(&pa, &pb, status, subtract); - return float16_round_pack_canonical(&pr, status); + return float16_round_pack_canonical(pr, status); } -float16 QEMU_FLATTEN float16_sub(float16 a, float16 b, float_status *status) +float16 float16_add(float16 a, float16 b, float_status *status) { - FloatParts64 pa, pb, pr; + return float16_addsub(a, b, status, false); +} - float16_unpack_canonical(&pa, a, status); - float16_unpack_canonical(&pb, b, status); - pr = addsub_floats(pa, pb, true, status); - - return float16_round_pack_canonical(&pr, status); +float16 float16_sub(float16 a, float16 b, float_status *status) +{ + return float16_addsub(a, b, status, true); } static float32 QEMU_SOFTFLOAT_ATTR -soft_f32_addsub(float32 a, float32 b, bool subtract, float_status *status) +soft_f32_addsub(float32 a, float32 b, float_status *status, bool subtract) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; float32_unpack_canonical(&pa, a, status); float32_unpack_canonical(&pb, b, status); - pr = addsub_floats(pa, pb, subtract, status); + pr = parts_addsub(&pa, &pb, status, subtract); - return float32_round_pack_canonical(&pr, status); + return float32_round_pack_canonical(pr, status); } -static inline float32 soft_f32_add(float32 a, float32 b, float_status *status) +static float32 soft_f32_add(float32 a, float32 b, float_status *status) { - return soft_f32_addsub(a, b, false, status); + return soft_f32_addsub(a, b, status, false); } -static inline float32 soft_f32_sub(float32 a, float32 b, float_status *status) +static float32 soft_f32_sub(float32 a, float32 b, float_status *status) { - return soft_f32_addsub(a, b, true, status); + return soft_f32_addsub(a, b, status, true); } static float64 QEMU_SOFTFLOAT_ATTR -soft_f64_addsub(float64 a, float64 b, bool subtract, float_status *status) +soft_f64_addsub(float64 a, float64 b, float_status *status, bool subtract) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); - pr = addsub_floats(pa, pb, subtract, status); + pr = parts_addsub(&pa, &pb, status, subtract); - return float64_round_pack_canonical(&pr, status); + return float64_round_pack_canonical(pr, status); } -static inline float64 soft_f64_add(float64 a, float64 b, float_status *status) +static float64 soft_f64_add(float64 a, float64 b, float_status *status) { - return soft_f64_addsub(a, b, false, status); + return soft_f64_addsub(a, b, status, false); } -static inline float64 soft_f64_sub(float64 a, float64 b, float_status *status) +static float64 soft_f64_sub(float64 a, float64 b, float_status *status) { - return soft_f64_addsub(a, b, true, status); + return soft_f64_addsub(a, b, status, true); } static float hard_f32_add(float a, float b) @@ -1216,30 +1191,26 @@ float64_sub(float64 a, float64 b, float_status *s) return float64_addsub(a, b, s, hard_f64_sub, soft_f64_sub); } -/* - * Returns the result of adding or subtracting the bfloat16 - * values `a' and `b'. - */ -bfloat16 QEMU_FLATTEN bfloat16_add(bfloat16 a, bfloat16 b, float_status *status) +static bfloat16 QEMU_FLATTEN +bfloat16_addsub(bfloat16 a, bfloat16 b, float_status *status, bool subtract) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; bfloat16_unpack_canonical(&pa, a, status); bfloat16_unpack_canonical(&pb, b, status); - pr = addsub_floats(pa, pb, false, status); + pr = parts_addsub(&pa, &pb, status, subtract); - return bfloat16_round_pack_canonical(&pr, status); + return bfloat16_round_pack_canonical(pr, status); } -bfloat16 QEMU_FLATTEN bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status) +bfloat16 bfloat16_add(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts64 pa, pb, pr; + return bfloat16_addsub(a, b, status, false); +} - bfloat16_unpack_canonical(&pa, a, status); - bfloat16_unpack_canonical(&pb, b, status); - pr = addsub_floats(pa, pb, true, status); - - return bfloat16_round_pack_canonical(&pr, status); +bfloat16 bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status) +{ + return bfloat16_addsub(a, b, status, true); } /* From 3ff49e56a7294e1b0d29ee62250a877838f4a1eb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Oct 2020 19:22:50 -0700 Subject: [PATCH 0663/3028] softfloat: Implement float128_add/sub via parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the existing Berkeley implementation with the FloatParts implementation. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 257 +++++++----------------------------------------- 1 file changed, 36 insertions(+), 221 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index afeef00097..8f734f6020 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1046,6 +1046,20 @@ static float64 float64_round_pack_canonical(FloatParts64 *p, return float64_pack_raw(p); } +static void float128_unpack_canonical(FloatParts128 *p, float128 f, + float_status *s) +{ + float128_unpack_raw(p, f); + parts_canonicalize(p, s, &float128_params); +} + +static float128 float128_round_pack_canonical(FloatParts128 *p, + float_status *s) +{ + parts_uncanon(p, s, &float128_params); + return float128_pack_raw(p); +} + /* * Addition and subtraction */ @@ -1213,6 +1227,28 @@ bfloat16 bfloat16_sub(bfloat16 a, bfloat16 b, float_status *status) return bfloat16_addsub(a, b, status, true); } +static float128 QEMU_FLATTEN +float128_addsub(float128 a, float128 b, float_status *status, bool subtract) +{ + FloatParts128 pa, pb, *pr; + + float128_unpack_canonical(&pa, a, status); + float128_unpack_canonical(&pb, b, status); + pr = parts_addsub(&pa, &pb, status, subtract); + + return float128_round_pack_canonical(pr, status); +} + +float128 float128_add(float128 a, float128 b, float_status *status) +{ + return float128_addsub(a, b, status, false); +} + +float128 float128_sub(float128 a, float128 b, float_status *status) +{ + return float128_addsub(a, b, status, true); +} + /* * Returns the result of multiplying the floating-point values `a' and * `b'. The operation is performed according to the IEC/IEEE Standard @@ -7032,227 +7068,6 @@ float128 float128_round_to_int(float128 a, float_status *status) } -/*---------------------------------------------------------------------------- -| Returns the result of adding the absolute values of the quadruple-precision -| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated -| before being returned. `zSign' is ignored if the result is a NaN. -| The addition is performed according to the IEC/IEEE Standard for Binary -| Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -static float128 addFloat128Sigs(float128 a, float128 b, bool zSign, - float_status *status) -{ - int32_t aExp, bExp, zExp; - uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; - int32_t expDiff; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - expDiff = aExp - bExp; - if ( 0 < expDiff ) { - if ( aExp == 0x7FFF ) { - if (aSig0 | aSig1) { - return propagateFloat128NaN(a, b, status); - } - return a; - } - if ( bExp == 0 ) { - --expDiff; - } - else { - bSig0 |= UINT64_C(0x0001000000000000); - } - shift128ExtraRightJamming( - bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); - zExp = aExp; - } - else if ( expDiff < 0 ) { - if ( bExp == 0x7FFF ) { - if (bSig0 | bSig1) { - return propagateFloat128NaN(a, b, status); - } - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - ++expDiff; - } - else { - aSig0 |= UINT64_C(0x0001000000000000); - } - shift128ExtraRightJamming( - aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); - zExp = bExp; - } - else { - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 | bSig0 | bSig1 ) { - return propagateFloat128NaN(a, b, status); - } - return a; - } - add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - if ( aExp == 0 ) { - if (status->flush_to_zero) { - if (zSig0 | zSig1) { - float_raise(float_flag_output_denormal, status); - } - return packFloat128(zSign, 0, 0, 0); - } - return packFloat128( zSign, 0, zSig0, zSig1 ); - } - zSig2 = 0; - zSig0 |= UINT64_C(0x0002000000000000); - zExp = aExp; - goto shiftRight1; - } - aSig0 |= UINT64_C(0x0001000000000000); - add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - --zExp; - if ( zSig0 < UINT64_C(0x0002000000000000) ) goto roundAndPack; - ++zExp; - shiftRight1: - shift128ExtraRightJamming( - zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); - roundAndPack: - return roundAndPackFloat128(zSign, zExp, zSig0, zSig1, zSig2, status); - -} - -/*---------------------------------------------------------------------------- -| Returns the result of subtracting the absolute values of the quadruple- -| precision floating-point values `a' and `b'. If `zSign' is 1, the -| difference is negated before being returned. `zSign' is ignored if the -| result is a NaN. The subtraction is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -static float128 subFloat128Sigs(float128 a, float128 b, bool zSign, - float_status *status) -{ - int32_t aExp, bExp, zExp; - uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; - int32_t expDiff; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - expDiff = aExp - bExp; - shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); - shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 ); - if ( 0 < expDiff ) goto aExpBigger; - if ( expDiff < 0 ) goto bExpBigger; - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 | bSig0 | bSig1 ) { - return propagateFloat128NaN(a, b, status); - } - float_raise(float_flag_invalid, status); - return float128_default_nan(status); - } - if ( aExp == 0 ) { - aExp = 1; - bExp = 1; - } - if ( bSig0 < aSig0 ) goto aBigger; - if ( aSig0 < bSig0 ) goto bBigger; - if ( bSig1 < aSig1 ) goto aBigger; - if ( aSig1 < bSig1 ) goto bBigger; - return packFloat128(status->float_rounding_mode == float_round_down, - 0, 0, 0); - bExpBigger: - if ( bExp == 0x7FFF ) { - if (bSig0 | bSig1) { - return propagateFloat128NaN(a, b, status); - } - return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - ++expDiff; - } - else { - aSig0 |= UINT64_C(0x4000000000000000); - } - shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); - bSig0 |= UINT64_C(0x4000000000000000); - bBigger: - sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); - zExp = bExp; - zSign ^= 1; - goto normalizeRoundAndPack; - aExpBigger: - if ( aExp == 0x7FFF ) { - if (aSig0 | aSig1) { - return propagateFloat128NaN(a, b, status); - } - return a; - } - if ( bExp == 0 ) { - --expDiff; - } - else { - bSig0 |= UINT64_C(0x4000000000000000); - } - shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); - aSig0 |= UINT64_C(0x4000000000000000); - aBigger: - sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - zExp = aExp; - normalizeRoundAndPack: - --zExp; - return normalizeRoundAndPackFloat128(zSign, zExp - 14, zSig0, zSig1, - status); - -} - -/*---------------------------------------------------------------------------- -| Returns the result of adding the quadruple-precision floating-point values -| `a' and `b'. The operation is performed according to the IEC/IEEE Standard -| for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -float128 float128_add(float128 a, float128 b, float_status *status) -{ - bool aSign, bSign; - - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign == bSign ) { - return addFloat128Sigs(a, b, aSign, status); - } - else { - return subFloat128Sigs(a, b, aSign, status); - } - -} - -/*---------------------------------------------------------------------------- -| Returns the result of subtracting the quadruple-precision floating-point -| values `a' and `b'. The operation is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -float128 float128_sub(float128 a, float128 b, float_status *status) -{ - bool aSign, bSign; - - aSign = extractFloat128Sign( a ); - bSign = extractFloat128Sign( b ); - if ( aSign == bSign ) { - return subFloat128Sigs(a, b, aSign, status); - } - else { - return addFloat128Sigs(a, b, aSign, status); - } - -} - /*---------------------------------------------------------------------------- | Returns the result of multiplying the quadruple-precision floating-point | values `a' and `b'. The operation is performed according to the IEC/IEEE From aca845275a62e79daee8ed5bf95ccb8ace4aeac9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 11 Nov 2020 20:44:57 -0800 Subject: [PATCH 0664/3028] softfloat: Move mul_floats to softfloat-parts.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename to parts$N_mul. Reimplement float128_mul with FloatParts128. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 51 ++++++++++ fpu/softfloat.c | 206 ++++++++++++++------------------------ 2 files changed, 128 insertions(+), 129 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index cfce9f6421..9a67ab2bea 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -362,3 +362,54 @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b, p_nan: return parts_pick_nan(a, b, s); } + +/* + * Returns the result of multiplying the floating-point values `a' and + * `b'. The operation is performed according to the IEC/IEEE Standard + * for Binary Floating-Point Arithmetic. + */ +static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, + float_status *s) +{ + int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); + bool sign = a->sign ^ b->sign; + + if (likely(ab_mask == float_cmask_normal)) { + FloatPartsW tmp; + + frac_mulw(&tmp, a, b); + frac_truncjam(a, &tmp); + + a->exp += b->exp + 1; + if (!(a->frac_hi & DECOMPOSED_IMPLICIT_BIT)) { + frac_add(a, a, a); + a->exp -= 1; + } + + a->sign = sign; + return a; + } + + /* Inf * Zero == NaN */ + if (unlikely(ab_mask == float_cmask_infzero)) { + float_raise(float_flag_invalid, s); + parts_default_nan(a, s); + return a; + } + + if (unlikely(ab_mask & float_cmask_anynan)) { + return parts_pick_nan(a, b, s); + } + + /* Multiply by 0 or Inf */ + if (ab_mask & float_cmask_inf) { + a->cls = float_class_inf; + a->sign = sign; + return a; + } + + g_assert(ab_mask & float_cmask_zero); + a->cls = float_class_zero; + a->sign = sign; + return a; +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 8f734f6020..ac7959557c 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -533,6 +533,16 @@ typedef struct { uint64_t frac_lo; } FloatParts128; +typedef struct { + FloatClass cls; + bool sign; + int32_t exp; + uint64_t frac_hi; + uint64_t frac_hm; /* high-middle */ + uint64_t frac_lm; /* low-middle */ + uint64_t frac_lo; +} FloatParts256; + /* These apply to the most significant word of each FloatPartsN. */ #define DECOMPOSED_BINARY_POINT 63 #define DECOMPOSED_IMPLICIT_BIT (1ull << DECOMPOSED_BINARY_POINT) @@ -769,6 +779,14 @@ static FloatParts128 *parts128_addsub(FloatParts128 *a, FloatParts128 *b, #define parts_addsub(A, B, S, Z) \ PARTS_GENERIC_64_128(addsub, A)(A, B, S, Z) +static FloatParts64 *parts64_mul(FloatParts64 *a, FloatParts64 *b, + float_status *s); +static FloatParts128 *parts128_mul(FloatParts128 *a, FloatParts128 *b, + float_status *s); + +#define parts_mul(A, B, S) \ + PARTS_GENERIC_64_128(mul, A)(A, B, S) + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ @@ -859,6 +877,19 @@ static bool frac128_eqz(FloatParts128 *a) #define frac_eqz(A) FRAC_GENERIC_64_128(eqz, A)(A) +static void frac64_mulw(FloatParts128 *r, FloatParts64 *a, FloatParts64 *b) +{ + mulu64(&r->frac_lo, &r->frac_hi, a->frac, b->frac); +} + +static void frac128_mulw(FloatParts256 *r, FloatParts128 *a, FloatParts128 *b) +{ + mul128To256(a->frac_hi, a->frac_lo, b->frac_hi, b->frac_lo, + &r->frac_hi, &r->frac_hm, &r->frac_lm, &r->frac_lo); +} + +#define frac_mulw(R, A, B) FRAC_GENERIC_64_128(mulw, A)(R, A, B) + static void frac64_neg(FloatParts64 *a) { a->frac = -a->frac; @@ -955,23 +986,42 @@ static bool frac128_sub(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b) #define frac_sub(R, A, B) FRAC_GENERIC_64_128(sub, R)(R, A, B) +static void frac64_truncjam(FloatParts64 *r, FloatParts128 *a) +{ + r->frac = a->frac_hi | (a->frac_lo != 0); +} + +static void frac128_truncjam(FloatParts128 *r, FloatParts256 *a) +{ + r->frac_hi = a->frac_hi; + r->frac_lo = a->frac_hm | ((a->frac_lm | a->frac_lo) != 0); +} + +#define frac_truncjam(R, A) FRAC_GENERIC_64_128(truncjam, R)(R, A) + #define partsN(NAME) glue(glue(glue(parts,N),_),NAME) #define FloatPartsN glue(FloatParts,N) +#define FloatPartsW glue(FloatParts,W) #define N 64 +#define W 128 #include "softfloat-parts-addsub.c.inc" #include "softfloat-parts.c.inc" #undef N +#undef W #define N 128 +#define W 256 #include "softfloat-parts-addsub.c.inc" #include "softfloat-parts.c.inc" #undef N +#undef W #undef partsN #undef FloatPartsN +#undef FloatPartsW /* * Pack/unpack routines with a specific FloatFmt. @@ -1250,89 +1300,42 @@ float128 float128_sub(float128 a, float128 b, float_status *status) } /* - * Returns the result of multiplying the floating-point values `a' and - * `b'. The operation is performed according to the IEC/IEEE Standard - * for Binary Floating-Point Arithmetic. + * Multiplication */ -static FloatParts64 mul_floats(FloatParts64 a, FloatParts64 b, float_status *s) -{ - bool sign = a.sign ^ b.sign; - - if (a.cls == float_class_normal && b.cls == float_class_normal) { - uint64_t hi, lo; - int exp = a.exp + b.exp; - - mul64To128(a.frac, b.frac, &hi, &lo); - if (hi & DECOMPOSED_IMPLICIT_BIT) { - exp += 1; - } else { - hi <<= 1; - } - hi |= (lo != 0); - - /* Re-use a */ - a.exp = exp; - a.sign = sign; - a.frac = hi; - return a; - } - /* handle all the NaN cases */ - if (is_nan(a.cls) || is_nan(b.cls)) { - return *parts_pick_nan(&a, &b, s); - } - /* Inf * Zero == NaN */ - if ((a.cls == float_class_inf && b.cls == float_class_zero) || - (a.cls == float_class_zero && b.cls == float_class_inf)) { - float_raise(float_flag_invalid, s); - parts_default_nan(&a, s); - return a; - } - /* Multiply by 0 or Inf */ - if (a.cls == float_class_inf || a.cls == float_class_zero) { - a.sign = sign; - return a; - } - if (b.cls == float_class_inf || b.cls == float_class_zero) { - b.sign = sign; - return b; - } - g_assert_not_reached(); -} - float16 QEMU_FLATTEN float16_mul(float16 a, float16 b, float_status *status) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; float16_unpack_canonical(&pa, a, status); float16_unpack_canonical(&pb, b, status); - pr = mul_floats(pa, pb, status); + pr = parts_mul(&pa, &pb, status); - return float16_round_pack_canonical(&pr, status); + return float16_round_pack_canonical(pr, status); } static float32 QEMU_SOFTFLOAT_ATTR soft_f32_mul(float32 a, float32 b, float_status *status) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; float32_unpack_canonical(&pa, a, status); float32_unpack_canonical(&pb, b, status); - pr = mul_floats(pa, pb, status); + pr = parts_mul(&pa, &pb, status); - return float32_round_pack_canonical(&pr, status); + return float32_round_pack_canonical(pr, status); } static float64 QEMU_SOFTFLOAT_ATTR soft_f64_mul(float64 a, float64 b, float_status *status) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); - pr = mul_floats(pa, pb, status); + pr = parts_mul(&pa, &pb, status); - return float64_round_pack_canonical(&pr, status); + return float64_round_pack_canonical(pr, status); } static float hard_f32_mul(float a, float b) @@ -1359,20 +1362,28 @@ float64_mul(float64 a, float64 b, float_status *s) f64_is_zon2, f64_addsubmul_post); } -/* - * Returns the result of multiplying the bfloat16 - * values `a' and `b'. - */ - -bfloat16 QEMU_FLATTEN bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) +bfloat16 QEMU_FLATTEN +bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; bfloat16_unpack_canonical(&pa, a, status); bfloat16_unpack_canonical(&pb, b, status); - pr = mul_floats(pa, pb, status); + pr = parts_mul(&pa, &pb, status); - return bfloat16_round_pack_canonical(&pr, status); + return bfloat16_round_pack_canonical(pr, status); +} + +float128 QEMU_FLATTEN +float128_mul(float128 a, float128 b, float_status *status) +{ + FloatParts128 pa, pb, *pr; + + float128_unpack_canonical(&pa, a, status); + float128_unpack_canonical(&pb, b, status); + pr = parts_mul(&pa, &pb, status); + + return float128_round_pack_canonical(pr, status); } /* @@ -7068,69 +7079,6 @@ float128 float128_round_to_int(float128 a, float_status *status) } -/*---------------------------------------------------------------------------- -| Returns the result of multiplying the quadruple-precision floating-point -| values `a' and `b'. The operation is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -float128 float128_mul(float128 a, float128 b, float_status *status) -{ - bool aSign, bSign, zSign; - int32_t aExp, bExp, zExp; - uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - bSign = extractFloat128Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0x7FFF ) { - if ( ( aSig0 | aSig1 ) - || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) { - return propagateFloat128NaN(a, b, status); - } - if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid; - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( bExp == 0x7FFF ) { - if (bSig0 | bSig1) { - return propagateFloat128NaN(a, b, status); - } - if ( ( aExp | aSig0 | aSig1 ) == 0 ) { - invalid: - float_raise(float_flag_invalid, status); - return float128_default_nan(status); - } - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); - normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); - } - if ( bExp == 0 ) { - if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); - normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); - } - zExp = aExp + bExp - 0x4000; - aSig0 |= UINT64_C(0x0001000000000000); - shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 ); - mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 ); - add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 ); - zSig2 |= ( zSig3 != 0 ); - if (UINT64_C( 0x0002000000000000) <= zSig0 ) { - shift128ExtraRightJamming( - zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); - ++zExp; - } - return roundAndPackFloat128(zSign, zExp, zSig0, zSig1, zSig2, status); - -} - /*---------------------------------------------------------------------------- | Returns the result of dividing the quadruple-precision floating-point value | `a' by the corresponding value `b'. The operation is performed according to From dedd123c56214f897d7045f2133b0261502690c6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 24 Oct 2020 06:04:19 -0700 Subject: [PATCH 0665/3028] softfloat: Move muladd_floats to softfloat-parts.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename to parts$N_muladd. Implement float128_muladd with FloatParts128. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 126 ++++++++++++ fpu/softfloat.c | 406 ++++++++++++++++++-------------------- include/fpu/softfloat.h | 2 + tests/fp/fp-bench.c | 8 +- tests/fp/fp-test.c | 2 +- tests/fp/wrap.c.inc | 12 ++ 6 files changed, 342 insertions(+), 214 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index 9a67ab2bea..a203811299 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -413,3 +413,129 @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b, a->sign = sign; return a; } + +/* + * Returns the result of multiplying the floating-point values `a' and + * `b' then adding 'c', with no intermediate rounding step after the + * multiplication. The operation is performed according to the + * IEC/IEEE Standard for Binary Floating-Point Arithmetic 754-2008. + * The flags argument allows the caller to select negation of the + * addend, the intermediate product, or the final result. (The + * difference between this and having the caller do a separate + * negation is that negating externally will flip the sign bit on NaNs.) + * + * Requires A and C extracted into a double-sized structure to provide the + * extra space for the widening multiply. + */ +static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, + FloatPartsN *c, int flags, float_status *s) +{ + int ab_mask, abc_mask; + FloatPartsW p_widen, c_widen; + + ab_mask = float_cmask(a->cls) | float_cmask(b->cls); + abc_mask = float_cmask(c->cls) | ab_mask; + + /* + * It is implementation-defined whether the cases of (0,inf,qnan) + * and (inf,0,qnan) raise InvalidOperation or not (and what QNaN + * they return if they do), so we have to hand this information + * off to the target-specific pick-a-NaN routine. + */ + if (unlikely(abc_mask & float_cmask_anynan)) { + return parts_pick_nan_muladd(a, b, c, s, ab_mask, abc_mask); + } + + if (flags & float_muladd_negate_c) { + c->sign ^= 1; + } + + /* Compute the sign of the product into A. */ + a->sign ^= b->sign; + if (flags & float_muladd_negate_product) { + a->sign ^= 1; + } + + if (unlikely(ab_mask != float_cmask_normal)) { + if (unlikely(ab_mask == float_cmask_infzero)) { + goto d_nan; + } + + if (ab_mask & float_cmask_inf) { + if (c->cls == float_class_inf && a->sign != c->sign) { + goto d_nan; + } + goto return_inf; + } + + g_assert(ab_mask & float_cmask_zero); + if (c->cls == float_class_normal) { + *a = *c; + goto return_normal; + } + if (c->cls == float_class_zero) { + if (a->sign != c->sign) { + goto return_sub_zero; + } + goto return_zero; + } + g_assert(c->cls == float_class_inf); + } + + if (unlikely(c->cls == float_class_inf)) { + a->sign = c->sign; + goto return_inf; + } + + /* Perform the multiplication step. */ + p_widen.sign = a->sign; + p_widen.exp = a->exp + b->exp + 1; + frac_mulw(&p_widen, a, b); + if (!(p_widen.frac_hi & DECOMPOSED_IMPLICIT_BIT)) { + frac_add(&p_widen, &p_widen, &p_widen); + p_widen.exp -= 1; + } + + /* Perform the addition step. */ + if (c->cls != float_class_zero) { + /* Zero-extend C to less significant bits. */ + frac_widen(&c_widen, c); + c_widen.exp = c->exp; + + if (a->sign == c->sign) { + parts_add_normal(&p_widen, &c_widen); + } else if (!parts_sub_normal(&p_widen, &c_widen)) { + goto return_sub_zero; + } + } + + /* Narrow with sticky bit, for proper rounding later. */ + frac_truncjam(a, &p_widen); + a->sign = p_widen.sign; + a->exp = p_widen.exp; + + return_normal: + if (flags & float_muladd_halve_result) { + a->exp -= 1; + } + finish_sign: + if (flags & float_muladd_negate_result) { + a->sign ^= 1; + } + return a; + + return_sub_zero: + a->sign = s->float_rounding_mode == float_round_down; + return_zero: + a->cls = float_class_zero; + goto finish_sign; + + return_inf: + a->cls = float_class_inf; + goto finish_sign; + + d_nan: + float_raise(float_flag_invalid, s); + parts_default_nan(a, s); + return a; +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index ac7959557c..571309e74f 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -716,6 +716,10 @@ static float128 float128_pack_raw(const FloatParts128 *p) #define PARTS_GENERIC_64_128(NAME, P) \ QEMU_GENERIC(P, (FloatParts128 *, parts128_##NAME), parts64_##NAME) +#define PARTS_GENERIC_64_128_256(NAME, P) \ + QEMU_GENERIC(P, (FloatParts256 *, parts256_##NAME), \ + (FloatParts128 *, parts128_##NAME), parts64_##NAME) + #define parts_default_nan(P, S) PARTS_GENERIC_64_128(default_nan, P)(P, S) #define parts_silence_nan(P, S) PARTS_GENERIC_64_128(silence_nan, P)(P, S) @@ -761,15 +765,17 @@ static void parts128_uncanon(FloatParts128 *p, float_status *status, static void parts64_add_normal(FloatParts64 *a, FloatParts64 *b); static void parts128_add_normal(FloatParts128 *a, FloatParts128 *b); +static void parts256_add_normal(FloatParts256 *a, FloatParts256 *b); #define parts_add_normal(A, B) \ - PARTS_GENERIC_64_128(add_normal, A)(A, B) + PARTS_GENERIC_64_128_256(add_normal, A)(A, B) static bool parts64_sub_normal(FloatParts64 *a, FloatParts64 *b); static bool parts128_sub_normal(FloatParts128 *a, FloatParts128 *b); +static bool parts256_sub_normal(FloatParts256 *a, FloatParts256 *b); #define parts_sub_normal(A, B) \ - PARTS_GENERIC_64_128(sub_normal, A)(A, B) + PARTS_GENERIC_64_128_256(sub_normal, A)(A, B) static FloatParts64 *parts64_addsub(FloatParts64 *a, FloatParts64 *b, float_status *s, bool subtract); @@ -787,6 +793,16 @@ static FloatParts128 *parts128_mul(FloatParts128 *a, FloatParts128 *b, #define parts_mul(A, B, S) \ PARTS_GENERIC_64_128(mul, A)(A, B, S) +static FloatParts64 *parts64_muladd(FloatParts64 *a, FloatParts64 *b, + FloatParts64 *c, int flags, + float_status *s); +static FloatParts128 *parts128_muladd(FloatParts128 *a, FloatParts128 *b, + FloatParts128 *c, int flags, + float_status *s); + +#define parts_muladd(A, B, C, Z, S) \ + PARTS_GENERIC_64_128(muladd, A)(A, B, C, Z, S) + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ @@ -794,6 +810,10 @@ static FloatParts128 *parts128_mul(FloatParts128 *a, FloatParts128 *b, #define FRAC_GENERIC_64_128(NAME, P) \ QEMU_GENERIC(P, (FloatParts128 *, frac128_##NAME), frac64_##NAME) +#define FRAC_GENERIC_64_128_256(NAME, P) \ + QEMU_GENERIC(P, (FloatParts256 *, frac256_##NAME), \ + (FloatParts128 *, frac128_##NAME), frac64_##NAME) + static bool frac64_add(FloatParts64 *r, FloatParts64 *a, FloatParts64 *b) { return uadd64_overflow(a->frac, b->frac, &r->frac); @@ -807,7 +827,17 @@ static bool frac128_add(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b) return c; } -#define frac_add(R, A, B) FRAC_GENERIC_64_128(add, R)(R, A, B) +static bool frac256_add(FloatParts256 *r, FloatParts256 *a, FloatParts256 *b) +{ + bool c = 0; + r->frac_lo = uadd64_carry(a->frac_lo, b->frac_lo, &c); + r->frac_lm = uadd64_carry(a->frac_lm, b->frac_lm, &c); + r->frac_hm = uadd64_carry(a->frac_hm, b->frac_hm, &c); + r->frac_hi = uadd64_carry(a->frac_hi, b->frac_hi, &c); + return c; +} + +#define frac_add(R, A, B) FRAC_GENERIC_64_128_256(add, R)(R, A, B) static bool frac64_addi(FloatParts64 *r, FloatParts64 *a, uint64_t c) { @@ -902,7 +932,16 @@ static void frac128_neg(FloatParts128 *a) a->frac_hi = usub64_borrow(0, a->frac_hi, &c); } -#define frac_neg(A) FRAC_GENERIC_64_128(neg, A)(A) +static void frac256_neg(FloatParts256 *a) +{ + bool c = 0; + a->frac_lo = usub64_borrow(0, a->frac_lo, &c); + a->frac_lm = usub64_borrow(0, a->frac_lm, &c); + a->frac_hm = usub64_borrow(0, a->frac_hm, &c); + a->frac_hi = usub64_borrow(0, a->frac_hi, &c); +} + +#define frac_neg(A) FRAC_GENERIC_64_128_256(neg, A)(A) static int frac64_normalize(FloatParts64 *a) { @@ -933,7 +972,55 @@ static int frac128_normalize(FloatParts128 *a) return 128; } -#define frac_normalize(A) FRAC_GENERIC_64_128(normalize, A)(A) +static int frac256_normalize(FloatParts256 *a) +{ + uint64_t a0 = a->frac_hi, a1 = a->frac_hm; + uint64_t a2 = a->frac_lm, a3 = a->frac_lo; + int ret, shl, shr; + + if (likely(a0)) { + shl = clz64(a0); + if (shl == 0) { + return 0; + } + ret = shl; + } else { + if (a1) { + ret = 64; + a0 = a1, a1 = a2, a2 = a3, a3 = 0; + } else if (a2) { + ret = 128; + a0 = a2, a1 = a3, a2 = 0, a3 = 0; + } else if (a3) { + ret = 192; + a0 = a3, a1 = 0, a2 = 0, a3 = 0; + } else { + ret = 256; + a0 = 0, a1 = 0, a2 = 0, a3 = 0; + goto done; + } + shl = clz64(a0); + if (shl == 0) { + goto done; + } + ret += shl; + } + + shr = -shl & 63; + a0 = (a0 << shl) | (a1 >> shr); + a1 = (a1 << shl) | (a2 >> shr); + a2 = (a2 << shl) | (a3 >> shr); + a3 = (a3 << shl); + + done: + a->frac_hi = a0; + a->frac_hm = a1; + a->frac_lm = a2; + a->frac_lo = a3; + return ret; +} + +#define frac_normalize(A) FRAC_GENERIC_64_128_256(normalize, A)(A) static void frac64_shl(FloatParts64 *a, int c) { @@ -969,7 +1056,51 @@ static void frac128_shrjam(FloatParts128 *a, int c) shift128RightJamming(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo); } -#define frac_shrjam(A, C) FRAC_GENERIC_64_128(shrjam, A)(A, C) +static void frac256_shrjam(FloatParts256 *a, int c) +{ + uint64_t a0 = a->frac_hi, a1 = a->frac_hm; + uint64_t a2 = a->frac_lm, a3 = a->frac_lo; + uint64_t sticky = 0; + int invc; + + if (unlikely(c == 0)) { + return; + } else if (likely(c < 64)) { + /* nothing */ + } else if (likely(c < 256)) { + if (unlikely(c & 128)) { + sticky |= a2 | a3; + a3 = a1, a2 = a0, a1 = 0, a0 = 0; + } + if (unlikely(c & 64)) { + sticky |= a3; + a3 = a2, a2 = a1, a1 = a0, a0 = 0; + } + c &= 63; + if (c == 0) { + goto done; + } + } else { + sticky = a0 | a1 | a2 | a3; + a0 = a1 = a2 = a3 = 0; + goto done; + } + + invc = -c & 63; + sticky |= a3 << invc; + a3 = (a3 >> c) | (a2 << invc); + a2 = (a2 >> c) | (a1 << invc); + a1 = (a1 >> c) | (a0 << invc); + a0 = (a0 >> c); + + done: + a->frac_lo = a3 | (sticky != 0); + a->frac_lm = a2; + a->frac_hm = a1; + a->frac_hi = a0; +} + +#define frac_shrjam(A, C) FRAC_GENERIC_64_128_256(shrjam, A)(A, C) static bool frac64_sub(FloatParts64 *r, FloatParts64 *a, FloatParts64 *b) { @@ -984,7 +1115,17 @@ static bool frac128_sub(FloatParts128 *r, FloatParts128 *a, FloatParts128 *b) return c; } -#define frac_sub(R, A, B) FRAC_GENERIC_64_128(sub, R)(R, A, B) +static bool frac256_sub(FloatParts256 *r, FloatParts256 *a, FloatParts256 *b) +{ + bool c = 0; + r->frac_lo = usub64_borrow(a->frac_lo, b->frac_lo, &c); + r->frac_lm = usub64_borrow(a->frac_lm, b->frac_lm, &c); + r->frac_hm = usub64_borrow(a->frac_hm, b->frac_hm, &c); + r->frac_hi = usub64_borrow(a->frac_hi, b->frac_hi, &c); + return c; +} + +#define frac_sub(R, A, B) FRAC_GENERIC_64_128_256(sub, R)(R, A, B) static void frac64_truncjam(FloatParts64 *r, FloatParts128 *a) { @@ -999,6 +1140,22 @@ static void frac128_truncjam(FloatParts128 *r, FloatParts256 *a) #define frac_truncjam(R, A) FRAC_GENERIC_64_128(truncjam, R)(R, A) +static void frac64_widen(FloatParts128 *r, FloatParts64 *a) +{ + r->frac_hi = a->frac; + r->frac_lo = 0; +} + +static void frac128_widen(FloatParts256 *r, FloatParts128 *a) +{ + r->frac_hi = a->frac_hi; + r->frac_hm = a->frac_lo; + r->frac_lm = 0; + r->frac_lo = 0; +} + +#define frac_widen(A, B) FRAC_GENERIC_64_128(widen, B)(A, B) + #define partsN(NAME) glue(glue(glue(parts,N),_),NAME) #define FloatPartsN glue(FloatParts,N) #define FloatPartsW glue(FloatParts,W) @@ -1017,6 +1174,12 @@ static void frac128_truncjam(FloatParts128 *r, FloatParts256 *a) #include "softfloat-parts-addsub.c.inc" #include "softfloat-parts.c.inc" +#undef N +#undef W +#define N 256 + +#include "softfloat-parts-addsub.c.inc" + #undef N #undef W #undef partsN @@ -1387,230 +1550,48 @@ float128_mul(float128 a, float128 b, float_status *status) } /* - * Returns the result of multiplying the floating-point values `a' and - * `b' then adding 'c', with no intermediate rounding step after the - * multiplication. The operation is performed according to the - * IEC/IEEE Standard for Binary Floating-Point Arithmetic 754-2008. - * The flags argument allows the caller to select negation of the - * addend, the intermediate product, or the final result. (The - * difference between this and having the caller do a separate - * negation is that negating externally will flip the sign bit on - * NaNs.) + * Fused multiply-add */ -static FloatParts64 muladd_floats(FloatParts64 a, FloatParts64 b, FloatParts64 c, - int flags, float_status *s) -{ - bool inf_zero, p_sign; - bool sign_flip = flags & float_muladd_negate_result; - FloatClass p_class; - uint64_t hi, lo; - int p_exp; - int ab_mask, abc_mask; - - ab_mask = float_cmask(a.cls) | float_cmask(b.cls); - abc_mask = float_cmask(c.cls) | ab_mask; - inf_zero = ab_mask == float_cmask_infzero; - - /* It is implementation-defined whether the cases of (0,inf,qnan) - * and (inf,0,qnan) raise InvalidOperation or not (and what QNaN - * they return if they do), so we have to hand this information - * off to the target-specific pick-a-NaN routine. - */ - if (unlikely(abc_mask & float_cmask_anynan)) { - return *parts_pick_nan_muladd(&a, &b, &c, s, ab_mask, abc_mask); - } - - if (inf_zero) { - float_raise(float_flag_invalid, s); - parts_default_nan(&a, s); - return a; - } - - if (flags & float_muladd_negate_c) { - c.sign ^= 1; - } - - p_sign = a.sign ^ b.sign; - - if (flags & float_muladd_negate_product) { - p_sign ^= 1; - } - - if (ab_mask & float_cmask_inf) { - p_class = float_class_inf; - } else if (ab_mask & float_cmask_zero) { - p_class = float_class_zero; - } else { - p_class = float_class_normal; - } - - if (c.cls == float_class_inf) { - if (p_class == float_class_inf && p_sign != c.sign) { - float_raise(float_flag_invalid, s); - parts_default_nan(&c, s); - } else { - c.sign ^= sign_flip; - } - return c; - } - - if (p_class == float_class_inf) { - a.cls = float_class_inf; - a.sign = p_sign ^ sign_flip; - return a; - } - - if (p_class == float_class_zero) { - if (c.cls == float_class_zero) { - if (p_sign != c.sign) { - p_sign = s->float_rounding_mode == float_round_down; - } - c.sign = p_sign; - } else if (flags & float_muladd_halve_result) { - c.exp -= 1; - } - c.sign ^= sign_flip; - return c; - } - - /* a & b should be normals now... */ - assert(a.cls == float_class_normal && - b.cls == float_class_normal); - - p_exp = a.exp + b.exp; - - mul64To128(a.frac, b.frac, &hi, &lo); - - /* Renormalize to the msb. */ - if (hi & DECOMPOSED_IMPLICIT_BIT) { - p_exp += 1; - } else { - shortShift128Left(hi, lo, 1, &hi, &lo); - } - - /* + add/sub */ - if (c.cls != float_class_zero) { - int exp_diff = p_exp - c.exp; - if (p_sign == c.sign) { - /* Addition */ - if (exp_diff <= 0) { - shift64RightJamming(hi, -exp_diff, &hi); - p_exp = c.exp; - if (uadd64_overflow(hi, c.frac, &hi)) { - shift64RightJamming(hi, 1, &hi); - hi |= DECOMPOSED_IMPLICIT_BIT; - p_exp += 1; - } - } else { - uint64_t c_hi, c_lo, over; - shift128RightJamming(c.frac, 0, exp_diff, &c_hi, &c_lo); - add192(0, hi, lo, 0, c_hi, c_lo, &over, &hi, &lo); - if (over) { - shift64RightJamming(hi, 1, &hi); - hi |= DECOMPOSED_IMPLICIT_BIT; - p_exp += 1; - } - } - } else { - /* Subtraction */ - uint64_t c_hi = c.frac, c_lo = 0; - - if (exp_diff <= 0) { - shift128RightJamming(hi, lo, -exp_diff, &hi, &lo); - if (exp_diff == 0 - && - (hi > c_hi || (hi == c_hi && lo >= c_lo))) { - sub128(hi, lo, c_hi, c_lo, &hi, &lo); - } else { - sub128(c_hi, c_lo, hi, lo, &hi, &lo); - p_sign ^= 1; - p_exp = c.exp; - } - } else { - shift128RightJamming(c_hi, c_lo, - exp_diff, - &c_hi, &c_lo); - sub128(hi, lo, c_hi, c_lo, &hi, &lo); - } - - if (hi == 0 && lo == 0) { - a.cls = float_class_zero; - a.sign = s->float_rounding_mode == float_round_down; - a.sign ^= sign_flip; - return a; - } else { - int shift; - if (hi != 0) { - shift = clz64(hi); - } else { - shift = clz64(lo) + 64; - } - /* Normalizing to a binary point of 124 is the - correct adjust for the exponent. However since we're - shifting, we might as well put the binary point back - at 63 where we really want it. Therefore shift as - if we're leaving 1 bit at the top of the word, but - adjust the exponent as if we're leaving 3 bits. */ - shift128Left(hi, lo, shift, &hi, &lo); - p_exp -= shift; - } - } - } - hi |= (lo != 0); - - if (flags & float_muladd_halve_result) { - p_exp -= 1; - } - - /* finally prepare our result */ - a.cls = float_class_normal; - a.sign = p_sign ^ sign_flip; - a.exp = p_exp; - a.frac = hi; - - return a; -} - float16 QEMU_FLATTEN float16_muladd(float16 a, float16 b, float16 c, - int flags, float_status *status) + int flags, float_status *status) { - FloatParts64 pa, pb, pc, pr; + FloatParts64 pa, pb, pc, *pr; float16_unpack_canonical(&pa, a, status); float16_unpack_canonical(&pb, b, status); float16_unpack_canonical(&pc, c, status); - pr = muladd_floats(pa, pb, pc, flags, status); + pr = parts_muladd(&pa, &pb, &pc, flags, status); - return float16_round_pack_canonical(&pr, status); + return float16_round_pack_canonical(pr, status); } static float32 QEMU_SOFTFLOAT_ATTR soft_f32_muladd(float32 a, float32 b, float32 c, int flags, float_status *status) { - FloatParts64 pa, pb, pc, pr; + FloatParts64 pa, pb, pc, *pr; float32_unpack_canonical(&pa, a, status); float32_unpack_canonical(&pb, b, status); float32_unpack_canonical(&pc, c, status); - pr = muladd_floats(pa, pb, pc, flags, status); + pr = parts_muladd(&pa, &pb, &pc, flags, status); - return float32_round_pack_canonical(&pr, status); + return float32_round_pack_canonical(pr, status); } static float64 QEMU_SOFTFLOAT_ATTR soft_f64_muladd(float64 a, float64 b, float64 c, int flags, float_status *status) { - FloatParts64 pa, pb, pc, pr; + FloatParts64 pa, pb, pc, *pr; float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); float64_unpack_canonical(&pc, c, status); - pr = muladd_floats(pa, pb, pc, flags, status); + pr = parts_muladd(&pa, &pb, &pc, flags, status); - return float64_round_pack_canonical(&pr, status); + return float64_round_pack_canonical(pr, status); } static bool force_soft_fma; @@ -1757,23 +1738,30 @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s) return soft_f64_muladd(ua.s, ub.s, uc.s, flags, s); } -/* - * Returns the result of multiplying the bfloat16 values `a' - * and `b' then adding 'c', with no intermediate rounding step after the - * multiplication. - */ - bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c, int flags, float_status *status) { - FloatParts64 pa, pb, pc, pr; + FloatParts64 pa, pb, pc, *pr; bfloat16_unpack_canonical(&pa, a, status); bfloat16_unpack_canonical(&pb, b, status); bfloat16_unpack_canonical(&pc, c, status); - pr = muladd_floats(pa, pb, pc, flags, status); + pr = parts_muladd(&pa, &pb, &pc, flags, status); - return bfloat16_round_pack_canonical(&pr, status); + return bfloat16_round_pack_canonical(pr, status); +} + +float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, + int flags, float_status *status) +{ + FloatParts128 pa, pb, pc, *pr; + + float128_unpack_canonical(&pa, a, status); + float128_unpack_canonical(&pb, b, status); + float128_unpack_canonical(&pc, c, status); + pr = parts_muladd(&pa, &pb, &pc, flags, status); + + return float128_round_pack_canonical(pr, status); } /* diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 019c2ec66d..53f2c2ea3c 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -1197,6 +1197,8 @@ float128 float128_round_to_int(float128, float_status *status); float128 float128_add(float128, float128, float_status *status); float128 float128_sub(float128, float128, float_status *status); float128 float128_mul(float128, float128, float_status *status); +float128 float128_muladd(float128, float128, float128, int, + float_status *status); float128 float128_div(float128, float128, float_status *status); float128 float128_rem(float128, float128, float_status *status); float128 float128_sqrt(float128, float_status *status); diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c index d319993280..c24baf8535 100644 --- a/tests/fp/fp-bench.c +++ b/tests/fp/fp-bench.c @@ -386,7 +386,7 @@ static void bench(enum precision prec, enum op op, int n_ops, bool no_neg) for (i = 0; i < OPS_PER_ITER; i++) { float128 a = ops[0].f128; float128 b = ops[1].f128; - /* float128 c = ops[2].f128; */ + float128 c = ops[2].f128; switch (op) { case OP_ADD: @@ -401,9 +401,9 @@ static void bench(enum precision prec, enum op op, int n_ops, bool no_neg) case OP_DIV: res.f128 = float128_div(a, b, &soft_status); break; - /* case OP_FMA: */ - /* res.f128 = float128_muladd(a, b, c, 0, &soft_status); */ - /* break; */ + case OP_FMA: + res.f128 = float128_muladd(a, b, c, 0, &soft_status); + break; case OP_SQRT: res.f128 = float128_sqrt(a, &soft_status); break; diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c index 5a4cad8c8b..ff131afbde 100644 --- a/tests/fp/fp-test.c +++ b/tests/fp/fp-test.c @@ -717,7 +717,7 @@ static void do_testfloat(int op, int rmode, bool exact) test_abz_f128(true_abz_f128M, subj_abz_f128M); break; case F128_MULADD: - not_implemented(); + test_abcz_f128(slow_f128M_mulAdd, qemu_f128M_mulAdd); break; case F128_SQRT: test_az_f128(slow_f128M_sqrt, qemu_f128M_sqrt); diff --git a/tests/fp/wrap.c.inc b/tests/fp/wrap.c.inc index 0cbd20013e..cb1bb77e4c 100644 --- a/tests/fp/wrap.c.inc +++ b/tests/fp/wrap.c.inc @@ -574,6 +574,18 @@ WRAP_MULADD(qemu_f32_mulAdd, float32_muladd, float32) WRAP_MULADD(qemu_f64_mulAdd, float64_muladd, float64) #undef WRAP_MULADD +static void qemu_f128M_mulAdd(const float128_t *ap, const float128_t *bp, + const float128_t *cp, float128_t *res) +{ + float128 a, b, c, ret; + + a = soft_to_qemu128(*ap); + b = soft_to_qemu128(*bp); + c = soft_to_qemu128(*cp); + ret = float128_muladd(a, b, c, 0, &qsf); + *res = qemu_to_soft128(ret); +} + #define WRAP_CMP16(name, func, retcond) \ static bool name(float16_t a, float16_t b) \ { \ From b4d09b1794b08cbed5b33ea4bd146f523a2c3c1f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Sep 2020 08:57:01 -0700 Subject: [PATCH 0666/3028] softfloat: Use mulu64 for mul64To128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Via host-utils.h, we use a host widening multiply for 64-bit hosts, and a common subroutine for 32-bit hosts. Reviewed-by: Alex Bennée Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson --- include/fpu/softfloat-macros.h | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h index 2e3760a9c1..f6dfbe108d 100644 --- a/include/fpu/softfloat-macros.h +++ b/include/fpu/softfloat-macros.h @@ -470,27 +470,10 @@ static inline void sub192(uint64_t a0, uint64_t a1, uint64_t a2, | `z0Ptr' and `z1Ptr'. *----------------------------------------------------------------------------*/ -static inline void mul64To128( uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr ) +static inline void +mul64To128(uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr) { - uint32_t aHigh, aLow, bHigh, bLow; - uint64_t z0, zMiddleA, zMiddleB, z1; - - aLow = a; - aHigh = a>>32; - bLow = b; - bHigh = b>>32; - z1 = ( (uint64_t) aLow ) * bLow; - zMiddleA = ( (uint64_t) aLow ) * bHigh; - zMiddleB = ( (uint64_t) aHigh ) * bLow; - z0 = ( (uint64_t) aHigh ) * bHigh; - zMiddleA += zMiddleB; - z0 += ( ( (uint64_t) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); - zMiddleA <<= 32; - z1 += zMiddleA; - z0 += ( z1 < zMiddleA ); - *z1Ptr = z1; - *z0Ptr = z0; - + mulu64(z1Ptr, z0Ptr, a, b); } /*---------------------------------------------------------------------------- From cd55a56e5c6fa0265e9c688e602279b66782362a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 26 Oct 2020 14:33:53 -0700 Subject: [PATCH 0667/3028] softfloat: Use add192 in mul128To256 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can perform the operation in 6 total adds instead of 8. Reviewed-by: Alex Bennée Tested-by: Alex Bennée Signed-off-by: Richard Henderson --- include/fpu/softfloat-macros.h | 37 +++++++++++----------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h index f6dfbe108d..76327d844d 100644 --- a/include/fpu/softfloat-macros.h +++ b/include/fpu/softfloat-macros.h @@ -511,34 +511,21 @@ static inline void | the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. *----------------------------------------------------------------------------*/ -static inline void - mul128To256( - uint64_t a0, - uint64_t a1, - uint64_t b0, - uint64_t b1, - uint64_t *z0Ptr, - uint64_t *z1Ptr, - uint64_t *z2Ptr, - uint64_t *z3Ptr - ) +static inline void mul128To256(uint64_t a0, uint64_t a1, + uint64_t b0, uint64_t b1, + uint64_t *z0Ptr, uint64_t *z1Ptr, + uint64_t *z2Ptr, uint64_t *z3Ptr) { - uint64_t z0, z1, z2, z3; - uint64_t more1, more2; + uint64_t z0, z1, z2; + uint64_t m0, m1, m2, n1, n2; - mul64To128( a1, b1, &z2, &z3 ); - mul64To128( a1, b0, &z1, &more2 ); - add128( z1, more2, 0, z2, &z1, &z2 ); - mul64To128( a0, b0, &z0, &more1 ); - add128( z0, more1, 0, z1, &z0, &z1 ); - mul64To128( a0, b1, &more1, &more2 ); - add128( more1, more2, 0, z2, &more1, &z2 ); - add128( z0, z1, 0, more1, &z0, &z1 ); - *z3Ptr = z3; - *z2Ptr = z2; - *z1Ptr = z1; - *z0Ptr = z0; + mul64To128(a1, b0, &m1, &m2); + mul64To128(a0, b1, &n1, &n2); + mul64To128(a1, b1, &z2, z3Ptr); + mul64To128(a0, b0, &z0, &z1); + add192( 0, m1, m2, 0, n1, n2, &m0, &m1, &m2); + add192(m0, m1, m2, z0, z1, z2, z0Ptr, z1Ptr, z2Ptr); } /*---------------------------------------------------------------------------- From 5ffb6bd9c44763a0ee11981c632b9be96ec68d8c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 12 Nov 2020 11:40:12 -0800 Subject: [PATCH 0668/3028] softfloat: Tidy mul128By64To192 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clean up the formatting and variables; no functional change. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- include/fpu/softfloat-macros.h | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h index 76327d844d..672c1db555 100644 --- a/include/fpu/softfloat-macros.h +++ b/include/fpu/softfloat-macros.h @@ -484,24 +484,14 @@ mul64To128(uint64_t a, uint64_t b, uint64_t *z0Ptr, uint64_t *z1Ptr) *----------------------------------------------------------------------------*/ static inline void - mul128By64To192( - uint64_t a0, - uint64_t a1, - uint64_t b, - uint64_t *z0Ptr, - uint64_t *z1Ptr, - uint64_t *z2Ptr - ) +mul128By64To192(uint64_t a0, uint64_t a1, uint64_t b, + uint64_t *z0Ptr, uint64_t *z1Ptr, uint64_t *z2Ptr) { - uint64_t z0, z1, z2, more1; - - mul64To128( a1, b, &z1, &z2 ); - mul64To128( a0, b, &z0, &more1 ); - add128( z0, more1, 0, z1, &z0, &z1 ); - *z2Ptr = z2; - *z1Ptr = z1; - *z0Ptr = z0; + uint64_t z0, z1, m1; + mul64To128(a1, b, &m1, z2Ptr); + mul64To128(a0, b, &z0, &z1); + add128(z0, z1, 0, m1, z0Ptr, z1Ptr); } /*---------------------------------------------------------------------------- From 463e45dcb4aa1a878b5ae5c6bbaf4ae70e24bf50 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 9 Nov 2020 19:08:30 -0800 Subject: [PATCH 0669/3028] softfloat: Introduce sh[lr]_double primitives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Have x86_64 assembly for them, with a fallback. This avoids shuffling values through %cl in the x86 case. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 102 +++++++++++++++++++++++++-------- include/fpu/softfloat-macros.h | 36 ++++++++++++ 2 files changed, 115 insertions(+), 23 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 571309e74f..34689959a9 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -957,15 +957,12 @@ static int frac128_normalize(FloatParts128 *a) { if (a->frac_hi) { int shl = clz64(a->frac_hi); - if (shl) { - int shr = 64 - shl; - a->frac_hi = (a->frac_hi << shl) | (a->frac_lo >> shr); - a->frac_lo = (a->frac_lo << shl); - } + a->frac_hi = shl_double(a->frac_hi, a->frac_lo, shl); + a->frac_lo <<= shl; return shl; } else if (a->frac_lo) { int shl = clz64(a->frac_lo); - a->frac_hi = (a->frac_lo << shl); + a->frac_hi = a->frac_lo << shl; a->frac_lo = 0; return shl + 64; } @@ -976,7 +973,7 @@ static int frac256_normalize(FloatParts256 *a) { uint64_t a0 = a->frac_hi, a1 = a->frac_hm; uint64_t a2 = a->frac_lm, a3 = a->frac_lo; - int ret, shl, shr; + int ret, shl; if (likely(a0)) { shl = clz64(a0); @@ -1006,11 +1003,10 @@ static int frac256_normalize(FloatParts256 *a) ret += shl; } - shr = -shl & 63; - a0 = (a0 << shl) | (a1 >> shr); - a1 = (a1 << shl) | (a2 >> shr); - a2 = (a2 << shl) | (a3 >> shr); - a3 = (a3 << shl); + a0 = shl_double(a0, a1, shl); + a1 = shl_double(a1, a2, shl); + a2 = shl_double(a2, a3, shl); + a3 <<= shl; done: a->frac_hi = a0; @@ -1029,7 +1025,20 @@ static void frac64_shl(FloatParts64 *a, int c) static void frac128_shl(FloatParts128 *a, int c) { - shift128Left(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo); + uint64_t a0 = a->frac_hi, a1 = a->frac_lo; + + if (c & 64) { + a0 = a1, a1 = 0; + } + + c &= 63; + if (c) { + a0 = shl_double(a0, a1, c); + a1 = a1 << c; + } + + a->frac_hi = a0; + a->frac_lo = a1; } #define frac_shl(A, C) FRAC_GENERIC_64_128(shl, A)(A, C) @@ -1041,19 +1050,68 @@ static void frac64_shr(FloatParts64 *a, int c) static void frac128_shr(FloatParts128 *a, int c) { - shift128Right(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo); + uint64_t a0 = a->frac_hi, a1 = a->frac_lo; + + if (c & 64) { + a1 = a0, a0 = 0; + } + + c &= 63; + if (c) { + a1 = shr_double(a0, a1, c); + a0 = a0 >> c; + } + + a->frac_hi = a0; + a->frac_lo = a1; } #define frac_shr(A, C) FRAC_GENERIC_64_128(shr, A)(A, C) static void frac64_shrjam(FloatParts64 *a, int c) { - shift64RightJamming(a->frac, c, &a->frac); + uint64_t a0 = a->frac; + + if (likely(c != 0)) { + if (likely(c < 64)) { + a0 = (a0 >> c) | (shr_double(a0, 0, c) != 0); + } else { + a0 = a0 != 0; + } + a->frac = a0; + } } static void frac128_shrjam(FloatParts128 *a, int c) { - shift128RightJamming(a->frac_hi, a->frac_lo, c, &a->frac_hi, &a->frac_lo); + uint64_t a0 = a->frac_hi, a1 = a->frac_lo; + uint64_t sticky = 0; + + if (unlikely(c == 0)) { + return; + } else if (likely(c < 64)) { + /* nothing */ + } else if (likely(c < 128)) { + sticky = a1; + a1 = a0; + a0 = 0; + c &= 63; + if (c == 0) { + goto done; + } + } else { + sticky = a0 | a1; + a0 = a1 = 0; + goto done; + } + + sticky |= shr_double(a1, 0, c); + a1 = shr_double(a0, a1, c); + a0 = a0 >> c; + + done: + a->frac_lo = a1 | (sticky != 0); + a->frac_hi = a0; } static void frac256_shrjam(FloatParts256 *a, int c) @@ -1061,7 +1119,6 @@ static void frac256_shrjam(FloatParts256 *a, int c) uint64_t a0 = a->frac_hi, a1 = a->frac_hm; uint64_t a2 = a->frac_lm, a3 = a->frac_lo; uint64_t sticky = 0; - int invc; if (unlikely(c == 0)) { return; @@ -1086,12 +1143,11 @@ static void frac256_shrjam(FloatParts256 *a, int c) goto done; } - invc = -c & 63; - sticky |= a3 << invc; - a3 = (a3 >> c) | (a2 << invc); - a2 = (a2 >> c) | (a1 << invc); - a1 = (a1 >> c) | (a0 << invc); - a0 = (a0 >> c); + sticky |= shr_double(a3, 0, c); + a3 = shr_double(a2, a3, c); + a2 = shr_double(a1, a2, c); + a1 = shr_double(a0, a1, c); + a0 = a0 >> c; done: a->frac_lo = a3 | (sticky != 0); diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h index 672c1db555..ec4e27a595 100644 --- a/include/fpu/softfloat-macros.h +++ b/include/fpu/softfloat-macros.h @@ -85,6 +85,42 @@ this code that are retained. #include "fpu/softfloat-types.h" #include "qemu/host-utils.h" +/** + * shl_double: double-word merging left shift + * @l: left or most-significant word + * @r: right or least-significant word + * @c: shift count + * + * Shift @l left by @c bits, shifting in bits from @r. + */ +static inline uint64_t shl_double(uint64_t l, uint64_t r, int c) +{ +#if defined(__x86_64__) + asm("shld %b2, %1, %0" : "+r"(l) : "r"(r), "ci"(c)); + return l; +#else + return c ? (l << c) | (r >> (64 - c)) : l; +#endif +} + +/** + * shr_double: double-word merging right shift + * @l: left or most-significant word + * @r: right or least-significant word + * @c: shift count + * + * Shift @r right by @c bits, shifting in bits from @l. + */ +static inline uint64_t shr_double(uint64_t l, uint64_t r, int c) +{ +#if defined(__x86_64__) + asm("shrd %b2, %1, %0" : "+r"(r) : "r"(l), "ci"(c)); + return r; +#else + return c ? (r >> c) | (l << (64 - c)) : r; +#endif +} + /*---------------------------------------------------------------------------- | Shifts `a' right by the number of bits given in `count'. If any nonzero | bits are shifted off, they are ``jammed'' into the least significant bit of From ec961b81b40a70ff9352f3a1ecc43db610afd2aa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 11 Nov 2020 12:50:44 -0800 Subject: [PATCH 0670/3028] softfloat: Move div_floats to softfloat-parts.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename to parts$N_div. Implement float128_div with FloatParts128. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 55 ++++++++ fpu/softfloat.c | 290 +++++++++++++++----------------------- 2 files changed, 171 insertions(+), 174 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index a203811299..f8165d92f9 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -539,3 +539,58 @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b, parts_default_nan(a, s); return a; } + +/* + * Returns the result of dividing the floating-point value `a' by the + * corresponding value `b'. The operation is performed according to + * the IEC/IEEE Standard for Binary Floating-Point Arithmetic. + */ +static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b, + float_status *s) +{ + int ab_mask = float_cmask(a->cls) | float_cmask(b->cls); + bool sign = a->sign ^ b->sign; + + if (likely(ab_mask == float_cmask_normal)) { + a->sign = sign; + a->exp -= b->exp + frac_div(a, b); + return a; + } + + /* 0/0 or Inf/Inf => NaN */ + if (unlikely(ab_mask == float_cmask_zero) || + unlikely(ab_mask == float_cmask_inf)) { + float_raise(float_flag_invalid, s); + parts_default_nan(a, s); + return a; + } + + /* All the NaN cases */ + if (unlikely(ab_mask & float_cmask_anynan)) { + return parts_pick_nan(a, b, s); + } + + a->sign = sign; + + /* Inf / X */ + if (a->cls == float_class_inf) { + return a; + } + + /* 0 / X */ + if (a->cls == float_class_zero) { + return a; + } + + /* X / Inf */ + if (b->cls == float_class_inf) { + a->cls = float_class_zero; + return a; + } + + /* X / 0 => Inf */ + g_assert(b->cls == float_class_zero); + float_raise(float_flag_divbyzero, s); + a->cls = float_class_inf; + return a; +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 34689959a9..a6dbb1dabf 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -803,6 +803,14 @@ static FloatParts128 *parts128_muladd(FloatParts128 *a, FloatParts128 *b, #define parts_muladd(A, B, C, Z, S) \ PARTS_GENERIC_64_128(muladd, A)(A, B, C, Z, S) +static FloatParts64 *parts64_div(FloatParts64 *a, FloatParts64 *b, + float_status *s); +static FloatParts128 *parts128_div(FloatParts128 *a, FloatParts128 *b, + float_status *s); + +#define parts_div(A, B, S) \ + PARTS_GENERIC_64_128(div, A)(A, B, S) + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ @@ -895,6 +903,87 @@ static void frac128_clear(FloatParts128 *a) #define frac_clear(A) FRAC_GENERIC_64_128(clear, A)(A) +static bool frac64_div(FloatParts64 *a, FloatParts64 *b) +{ + uint64_t n1, n0, r, q; + bool ret; + + /* + * We want a 2*N / N-bit division to produce exactly an N-bit + * result, so that we do not lose any precision and so that we + * do not have to renormalize afterward. If A.frac < B.frac, + * then division would produce an (N-1)-bit result; shift A left + * by one to produce the an N-bit result, and return true to + * decrement the exponent to match. + * + * The udiv_qrnnd algorithm that we're using requires normalization, + * i.e. the msb of the denominator must be set, which is already true. + */ + ret = a->frac < b->frac; + if (ret) { + n0 = a->frac; + n1 = 0; + } else { + n0 = a->frac >> 1; + n1 = a->frac << 63; + } + q = udiv_qrnnd(&r, n0, n1, b->frac); + + /* Set lsb if there is a remainder, to set inexact. */ + a->frac = q | (r != 0); + + return ret; +} + +static bool frac128_div(FloatParts128 *a, FloatParts128 *b) +{ + uint64_t q0, q1, a0, a1, b0, b1; + uint64_t r0, r1, r2, r3, t0, t1, t2, t3; + bool ret = false; + + a0 = a->frac_hi, a1 = a->frac_lo; + b0 = b->frac_hi, b1 = b->frac_lo; + + ret = lt128(a0, a1, b0, b1); + if (!ret) { + a1 = shr_double(a0, a1, 1); + a0 = a0 >> 1; + } + + /* Use 128/64 -> 64 division as estimate for 192/128 -> 128 division. */ + q0 = estimateDiv128To64(a0, a1, b0); + + /* + * Estimate is high because B1 was not included (unless B1 == 0). + * Reduce quotient and increase remainder until remainder is non-negative. + * This loop will execute 0 to 2 times. + */ + mul128By64To192(b0, b1, q0, &t0, &t1, &t2); + sub192(a0, a1, 0, t0, t1, t2, &r0, &r1, &r2); + while (r0 != 0) { + q0--; + add192(r0, r1, r2, 0, b0, b1, &r0, &r1, &r2); + } + + /* Repeat using the remainder, producing a second word of quotient. */ + q1 = estimateDiv128To64(r1, r2, b0); + mul128By64To192(b0, b1, q1, &t1, &t2, &t3); + sub192(r1, r2, 0, t1, t2, t3, &r1, &r2, &r3); + while (r1 != 0) { + q1--; + add192(r1, r2, r3, 0, b0, b1, &r1, &r2, &r3); + } + + /* Any remainder indicates inexact; set sticky bit. */ + q1 |= (r2 | r3) != 0; + + a->frac_hi = q0; + a->frac_lo = q1; + return ret; +} + +#define frac_div(A, B) FRAC_GENERIC_64_128(div, A)(A, B) + static bool frac64_eqz(FloatParts64 *a) { return a->frac == 0; @@ -1821,110 +1910,42 @@ float128 QEMU_FLATTEN float128_muladd(float128 a, float128 b, float128 c, } /* - * Returns the result of dividing the floating-point value `a' by the - * corresponding value `b'. The operation is performed according to - * the IEC/IEEE Standard for Binary Floating-Point Arithmetic. + * Division */ -static FloatParts64 div_floats(FloatParts64 a, FloatParts64 b, float_status *s) -{ - bool sign = a.sign ^ b.sign; - - if (a.cls == float_class_normal && b.cls == float_class_normal) { - uint64_t n0, n1, q, r; - int exp = a.exp - b.exp; - - /* - * We want a 2*N / N-bit division to produce exactly an N-bit - * result, so that we do not lose any precision and so that we - * do not have to renormalize afterward. If A.frac < B.frac, - * then division would produce an (N-1)-bit result; shift A left - * by one to produce the an N-bit result, and decrement the - * exponent to match. - * - * The udiv_qrnnd algorithm that we're using requires normalization, - * i.e. the msb of the denominator must be set, which is already true. - */ - if (a.frac < b.frac) { - exp -= 1; - shift128Left(0, a.frac, DECOMPOSED_BINARY_POINT + 1, &n1, &n0); - } else { - shift128Left(0, a.frac, DECOMPOSED_BINARY_POINT, &n1, &n0); - } - q = udiv_qrnnd(&r, n1, n0, b.frac); - - /* Set lsb if there is a remainder, to set inexact. */ - a.frac = q | (r != 0); - a.sign = sign; - a.exp = exp; - return a; - } - /* handle all the NaN cases */ - if (is_nan(a.cls) || is_nan(b.cls)) { - return *parts_pick_nan(&a, &b, s); - } - /* 0/0 or Inf/Inf */ - if (a.cls == b.cls - && - (a.cls == float_class_inf || a.cls == float_class_zero)) { - float_raise(float_flag_invalid, s); - parts_default_nan(&a, s); - return a; - } - /* Inf / x or 0 / x */ - if (a.cls == float_class_inf || a.cls == float_class_zero) { - a.sign = sign; - return a; - } - /* Div 0 => Inf */ - if (b.cls == float_class_zero) { - float_raise(float_flag_divbyzero, s); - a.cls = float_class_inf; - a.sign = sign; - return a; - } - /* Div by Inf */ - if (b.cls == float_class_inf) { - a.cls = float_class_zero; - a.sign = sign; - return a; - } - g_assert_not_reached(); -} - float16 float16_div(float16 a, float16 b, float_status *status) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; float16_unpack_canonical(&pa, a, status); float16_unpack_canonical(&pb, b, status); - pr = div_floats(pa, pb, status); + pr = parts_div(&pa, &pb, status); - return float16_round_pack_canonical(&pr, status); + return float16_round_pack_canonical(pr, status); } static float32 QEMU_SOFTFLOAT_ATTR soft_f32_div(float32 a, float32 b, float_status *status) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; float32_unpack_canonical(&pa, a, status); float32_unpack_canonical(&pb, b, status); - pr = div_floats(pa, pb, status); + pr = parts_div(&pa, &pb, status); - return float32_round_pack_canonical(&pr, status); + return float32_round_pack_canonical(pr, status); } static float64 QEMU_SOFTFLOAT_ATTR soft_f64_div(float64 a, float64 b, float_status *status) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; float64_unpack_canonical(&pa, a, status); float64_unpack_canonical(&pb, b, status); - pr = div_floats(pa, pb, status); + pr = parts_div(&pa, &pb, status); - return float64_round_pack_canonical(&pr, status); + return float64_round_pack_canonical(pr, status); } static float hard_f32_div(float a, float b) @@ -1985,20 +2006,28 @@ float64_div(float64 a, float64 b, float_status *s) f64_div_pre, f64_div_post); } -/* - * Returns the result of dividing the bfloat16 - * value `a' by the corresponding value `b'. - */ - -bfloat16 bfloat16_div(bfloat16 a, bfloat16 b, float_status *status) +bfloat16 QEMU_FLATTEN +bfloat16_div(bfloat16 a, bfloat16 b, float_status *status) { - FloatParts64 pa, pb, pr; + FloatParts64 pa, pb, *pr; bfloat16_unpack_canonical(&pa, a, status); bfloat16_unpack_canonical(&pb, b, status); - pr = div_floats(pa, pb, status); + pr = parts_div(&pa, &pb, status); - return bfloat16_round_pack_canonical(&pr, status); + return bfloat16_round_pack_canonical(pr, status); +} + +float128 QEMU_FLATTEN +float128_div(float128 a, float128 b, float_status *status) +{ + FloatParts128 pa, pb, *pr; + + float128_unpack_canonical(&pa, a, status); + float128_unpack_canonical(&pb, b, status); + pr = parts_div(&pa, &pb, status); + + return float128_round_pack_canonical(pr, status); } /* @@ -7123,93 +7152,6 @@ float128 float128_round_to_int(float128 a, float_status *status) } -/*---------------------------------------------------------------------------- -| Returns the result of dividing the quadruple-precision floating-point value -| `a' by the corresponding value `b'. The operation is performed according to -| the IEC/IEEE Standard for Binary Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -float128 float128_div(float128 a, float128 b, float_status *status) -{ - bool aSign, bSign, zSign; - int32_t aExp, bExp, zExp; - uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; - uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - bSig1 = extractFloat128Frac1( b ); - bSig0 = extractFloat128Frac0( b ); - bExp = extractFloat128Exp( b ); - bSign = extractFloat128Sign( b ); - zSign = aSign ^ bSign; - if ( aExp == 0x7FFF ) { - if (aSig0 | aSig1) { - return propagateFloat128NaN(a, b, status); - } - if ( bExp == 0x7FFF ) { - if (bSig0 | bSig1) { - return propagateFloat128NaN(a, b, status); - } - goto invalid; - } - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( bExp == 0x7FFF ) { - if (bSig0 | bSig1) { - return propagateFloat128NaN(a, b, status); - } - return packFloat128( zSign, 0, 0, 0 ); - } - if ( bExp == 0 ) { - if ( ( bSig0 | bSig1 ) == 0 ) { - if ( ( aExp | aSig0 | aSig1 ) == 0 ) { - invalid: - float_raise(float_flag_invalid, status); - return float128_default_nan(status); - } - float_raise(float_flag_divbyzero, status); - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 ); - } - if ( aExp == 0 ) { - if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 ); - normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 ); - } - zExp = aExp - bExp + 0x3FFD; - shortShift128Left( - aSig0 | UINT64_C(0x0001000000000000), aSig1, 15, &aSig0, &aSig1 ); - shortShift128Left( - bSig0 | UINT64_C(0x0001000000000000), bSig1, 15, &bSig0, &bSig1 ); - if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) { - shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 ); - ++zExp; - } - zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); - mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); - sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); - while ( (int64_t) rem0 < 0 ) { - --zSig0; - add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); - } - zSig1 = estimateDiv128To64( rem1, rem2, bSig0 ); - if ( ( zSig1 & 0x3FFF ) <= 4 ) { - mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); - sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); - while ( (int64_t) rem1 < 0 ) { - --zSig1; - add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); - } - zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); - } - shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 ); - return roundAndPackFloat128(zSign, zExp, zSig0, zSig1, zSig2, status); - -} - /*---------------------------------------------------------------------------- | Returns the remainder of the quadruple-precision floating-point value `a' | with respect to the corresponding value `b'. The operation is performed From c3f1875ea3004fa6ffa7788804635919d3f0f828 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 13 Nov 2020 17:43:41 -0800 Subject: [PATCH 0671/3028] softfloat: Split float_to_float MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split out parts_float_to_ahp and parts_float_to_float. Convert to pointers. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 174 ++++++++++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 73 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index a6dbb1dabf..80025539ef 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2037,83 +2037,105 @@ float128_div(float128 a, float128 b, float_status *status) * conversion is performed according to the IEC/IEEE Standard for * Binary Floating-Point Arithmetic. * - * The float_to_float helper only needs to take care of raising - * invalid exceptions and handling the conversion on NaNs. + * Usually this only needs to take care of raising invalid exceptions + * and handling the conversion on NaNs. */ -static FloatParts64 float_to_float(FloatParts64 a, const FloatFmt *dstf, - float_status *s) +static void parts_float_to_ahp(FloatParts64 *a, float_status *s) { - if (dstf->arm_althp) { - switch (a.cls) { - case float_class_qnan: - case float_class_snan: - /* There is no NaN in the destination format. Raise Invalid - * and return a zero with the sign of the input NaN. - */ - float_raise(float_flag_invalid, s); - a.cls = float_class_zero; - a.frac = 0; - a.exp = 0; - break; + switch (a->cls) { + case float_class_qnan: + case float_class_snan: + /* + * There is no NaN in the destination format. Raise Invalid + * and return a zero with the sign of the input NaN. + */ + float_raise(float_flag_invalid, s); + a->cls = float_class_zero; + break; - case float_class_inf: - /* There is no Inf in the destination format. Raise Invalid - * and return the maximum normal with the correct sign. - */ - float_raise(float_flag_invalid, s); - a.cls = float_class_normal; - a.exp = dstf->exp_max; - a.frac = ((1ull << dstf->frac_size) - 1) << dstf->frac_shift; - break; + case float_class_inf: + /* + * There is no Inf in the destination format. Raise Invalid + * and return the maximum normal with the correct sign. + */ + float_raise(float_flag_invalid, s); + a->cls = float_class_normal; + a->exp = float16_params_ahp.exp_max; + a->frac = MAKE_64BIT_MASK(float16_params_ahp.frac_shift, + float16_params_ahp.frac_size + 1); + break; - default: - break; - } - } else if (is_nan(a.cls)) { - parts_return_nan(&a, s); + case float_class_normal: + case float_class_zero: + break; + + default: + g_assert_not_reached(); } - return a; } +static void parts64_float_to_float(FloatParts64 *a, float_status *s) +{ + if (is_nan(a->cls)) { + parts_return_nan(a, s); + } +} + +static void parts128_float_to_float(FloatParts128 *a, float_status *s) +{ + if (is_nan(a->cls)) { + parts_return_nan(a, s); + } +} + +#define parts_float_to_float(P, S) \ + PARTS_GENERIC_64_128(float_to_float, P)(P, S) + float32 float16_to_float32(float16 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts64 pa, pr; + FloatParts64 p; - float16a_unpack_canonical(&pa, a, s, fmt16); - pr = float_to_float(pa, &float32_params, s); - return float32_round_pack_canonical(&pr, s); + float16a_unpack_canonical(&p, a, s, fmt16); + parts_float_to_float(&p, s); + return float32_round_pack_canonical(&p, s); } float64 float16_to_float64(float16 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts64 pa, pr; + FloatParts64 p; - float16a_unpack_canonical(&pa, a, s, fmt16); - pr = float_to_float(pa, &float64_params, s); - return float64_round_pack_canonical(&pr, s); + float16a_unpack_canonical(&p, a, s, fmt16); + parts_float_to_float(&p, s); + return float64_round_pack_canonical(&p, s); } float16 float32_to_float16(float32 a, bool ieee, float_status *s) { - const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts64 pa, pr; + FloatParts64 p; + const FloatFmt *fmt; - float32_unpack_canonical(&pa, a, s); - pr = float_to_float(pa, fmt16, s); - return float16a_round_pack_canonical(&pr, s, fmt16); + float32_unpack_canonical(&p, a, s); + if (ieee) { + parts_float_to_float(&p, s); + fmt = &float16_params; + } else { + parts_float_to_ahp(&p, s); + fmt = &float16_params_ahp; + } + return float16a_round_pack_canonical(&p, s, fmt); } static float64 QEMU_SOFTFLOAT_ATTR soft_float32_to_float64(float32 a, float_status *s) { - FloatParts64 pa, pr; + FloatParts64 p; - float32_unpack_canonical(&pa, a, s); - pr = float_to_float(pa, &float64_params, s); - return float64_round_pack_canonical(&pr, s); + float32_unpack_canonical(&p, a, s); + parts_float_to_float(&p, s); + return float64_round_pack_canonical(&p, s); } float64 float32_to_float64(float32 a, float_status *s) @@ -2134,57 +2156,63 @@ float64 float32_to_float64(float32 a, float_status *s) float16 float64_to_float16(float64 a, bool ieee, float_status *s) { - const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; - FloatParts64 pa, pr; + FloatParts64 p; + const FloatFmt *fmt; - float64_unpack_canonical(&pa, a, s); - pr = float_to_float(pa, fmt16, s); - return float16a_round_pack_canonical(&pr, s, fmt16); + float64_unpack_canonical(&p, a, s); + if (ieee) { + parts_float_to_float(&p, s); + fmt = &float16_params; + } else { + parts_float_to_ahp(&p, s); + fmt = &float16_params_ahp; + } + return float16a_round_pack_canonical(&p, s, fmt); } float32 float64_to_float32(float64 a, float_status *s) { - FloatParts64 pa, pr; + FloatParts64 p; - float64_unpack_canonical(&pa, a, s); - pr = float_to_float(pa, &float32_params, s); - return float32_round_pack_canonical(&pr, s); + float64_unpack_canonical(&p, a, s); + parts_float_to_float(&p, s); + return float32_round_pack_canonical(&p, s); } float32 bfloat16_to_float32(bfloat16 a, float_status *s) { - FloatParts64 pa, pr; + FloatParts64 p; - bfloat16_unpack_canonical(&pa, a, s); - pr = float_to_float(pa, &float32_params, s); - return float32_round_pack_canonical(&pr, s); + bfloat16_unpack_canonical(&p, a, s); + parts_float_to_float(&p, s); + return float32_round_pack_canonical(&p, s); } float64 bfloat16_to_float64(bfloat16 a, float_status *s) { - FloatParts64 pa, pr; + FloatParts64 p; - bfloat16_unpack_canonical(&pa, a, s); - pr = float_to_float(pa, &float64_params, s); - return float64_round_pack_canonical(&pr, s); + bfloat16_unpack_canonical(&p, a, s); + parts_float_to_float(&p, s); + return float64_round_pack_canonical(&p, s); } bfloat16 float32_to_bfloat16(float32 a, float_status *s) { - FloatParts64 pa, pr; + FloatParts64 p; - float32_unpack_canonical(&pa, a, s); - pr = float_to_float(pa, &bfloat16_params, s); - return bfloat16_round_pack_canonical(&pr, s); + float32_unpack_canonical(&p, a, s); + parts_float_to_float(&p, s); + return bfloat16_round_pack_canonical(&p, s); } bfloat16 float64_to_bfloat16(float64 a, float_status *s) { - FloatParts64 pa, pr; + FloatParts64 p; - float64_unpack_canonical(&pa, a, s); - pr = float_to_float(pa, &bfloat16_params, s); - return bfloat16_round_pack_canonical(&pr, s); + float64_unpack_canonical(&p, a, s); + parts_float_to_float(&p, s); + return bfloat16_round_pack_canonical(&p, s); } /* From 9882ccaff93b5f4c8fdc775074dd92f1a9a17b61 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 13 Nov 2020 18:17:39 -0800 Subject: [PATCH 0672/3028] softfloat: Convert float-to-float conversions with float128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce parts_float_to_float_widen and parts_float_to_float_narrow. Use them for float128_to_float{32,64} and float{32,64}_to_float128. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat.c | 203 ++++++++++++++++-------------------------------- 1 file changed, 69 insertions(+), 134 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 80025539ef..d056b5730b 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -2092,6 +2092,35 @@ static void parts128_float_to_float(FloatParts128 *a, float_status *s) #define parts_float_to_float(P, S) \ PARTS_GENERIC_64_128(float_to_float, P)(P, S) +static void parts_float_to_float_narrow(FloatParts64 *a, FloatParts128 *b, + float_status *s) +{ + a->cls = b->cls; + a->sign = b->sign; + a->exp = b->exp; + + if (a->cls == float_class_normal) { + frac_truncjam(a, b); + } else if (is_nan(a->cls)) { + /* Discard the low bits of the NaN. */ + a->frac = b->frac_hi; + parts_return_nan(a, s); + } +} + +static void parts_float_to_float_widen(FloatParts128 *a, FloatParts64 *b, + float_status *s) +{ + a->cls = b->cls; + a->sign = b->sign; + a->exp = b->exp; + frac_widen(a, b); + + if (is_nan(a->cls)) { + parts_return_nan(a, s); + } +} + float32 float16_to_float32(float16 a, bool ieee, float_status *s) { const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp; @@ -2215,6 +2244,46 @@ bfloat16 float64_to_bfloat16(float64 a, float_status *s) return bfloat16_round_pack_canonical(&p, s); } +float32 float128_to_float32(float128 a, float_status *s) +{ + FloatParts64 p64; + FloatParts128 p128; + + float128_unpack_canonical(&p128, a, s); + parts_float_to_float_narrow(&p64, &p128, s); + return float32_round_pack_canonical(&p64, s); +} + +float64 float128_to_float64(float128 a, float_status *s) +{ + FloatParts64 p64; + FloatParts128 p128; + + float128_unpack_canonical(&p128, a, s); + parts_float_to_float_narrow(&p64, &p128, s); + return float64_round_pack_canonical(&p64, s); +} + +float128 float32_to_float128(float32 a, float_status *s) +{ + FloatParts64 p64; + FloatParts128 p128; + + float32_unpack_canonical(&p64, a, s); + parts_float_to_float_widen(&p128, &p64, s); + return float128_round_pack_canonical(&p128, s); +} + +float128 float64_to_float128(float64 a, float_status *s) +{ + FloatParts64 p64; + FloatParts128 p128; + + float64_unpack_canonical(&p64, a, s); + parts_float_to_float_widen(&p128, &p64, s); + return float128_round_pack_canonical(&p128, s); +} + /* * Rounds the floating-point value `a' to an integer, and returns the * result as a floating-point value. The operation is performed @@ -5175,38 +5244,6 @@ floatx80 float32_to_floatx80(float32 a, float_status *status) } -/*---------------------------------------------------------------------------- -| Returns the result of converting the single-precision floating-point value -| `a' to the double-precision floating-point format. The conversion is -| performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. -*----------------------------------------------------------------------------*/ - -float128 float32_to_float128(float32 a, float_status *status) -{ - bool aSign; - int aExp; - uint32_t aSig; - - a = float32_squash_input_denormal(a, status); - aSig = extractFloat32Frac( a ); - aExp = extractFloat32Exp( a ); - aSign = extractFloat32Sign( a ); - if ( aExp == 0xFF ) { - if (aSig) { - return commonNaNToFloat128(float32ToCommonNaN(a, status), status); - } - return packFloat128( aSign, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); - normalizeFloat32Subnormal( aSig, &aExp, &aSig ); - --aExp; - } - return packFloat128( aSign, aExp + 0x3F80, ( (uint64_t) aSig )<<25, 0 ); - -} - /*---------------------------------------------------------------------------- | Returns the remainder of the single-precision floating-point value `a' | with respect to the corresponding value `b'. The operation is performed @@ -5480,40 +5517,6 @@ floatx80 float64_to_floatx80(float64 a, float_status *status) } -/*---------------------------------------------------------------------------- -| Returns the result of converting the double-precision floating-point value -| `a' to the quadruple-precision floating-point format. The conversion is -| performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. -*----------------------------------------------------------------------------*/ - -float128 float64_to_float128(float64 a, float_status *status) -{ - bool aSign; - int aExp; - uint64_t aSig, zSig0, zSig1; - - a = float64_squash_input_denormal(a, status); - aSig = extractFloat64Frac( a ); - aExp = extractFloat64Exp( a ); - aSign = extractFloat64Sign( a ); - if ( aExp == 0x7FF ) { - if (aSig) { - return commonNaNToFloat128(float64ToCommonNaN(a, status), status); - } - return packFloat128( aSign, 0x7FFF, 0, 0 ); - } - if ( aExp == 0 ) { - if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 ); - normalizeFloat64Subnormal( aSig, &aExp, &aSig ); - --aExp; - } - shift128Right( aSig, 0, 4, &zSig0, &zSig1 ); - return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 ); - -} - - /*---------------------------------------------------------------------------- | Returns the remainder of the double-precision floating-point value `a' | with respect to the corresponding value `b'. The operation is performed @@ -6915,74 +6918,6 @@ uint32_t float128_to_uint32(float128 a, float_status *status) return res; } -/*---------------------------------------------------------------------------- -| Returns the result of converting the quadruple-precision floating-point -| value `a' to the single-precision floating-point format. The conversion -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. -*----------------------------------------------------------------------------*/ - -float32 float128_to_float32(float128 a, float_status *status) -{ - bool aSign; - int32_t aExp; - uint64_t aSig0, aSig1; - uint32_t zSig; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) { - return commonNaNToFloat32(float128ToCommonNaN(a, status), status); - } - return packFloat32( aSign, 0xFF, 0 ); - } - aSig0 |= ( aSig1 != 0 ); - shift64RightJamming( aSig0, 18, &aSig0 ); - zSig = aSig0; - if ( aExp || zSig ) { - zSig |= 0x40000000; - aExp -= 0x3F81; - } - return roundAndPackFloat32(aSign, aExp, zSig, status); - -} - -/*---------------------------------------------------------------------------- -| Returns the result of converting the quadruple-precision floating-point -| value `a' to the double-precision floating-point format. The conversion -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. -*----------------------------------------------------------------------------*/ - -float64 float128_to_float64(float128 a, float_status *status) -{ - bool aSign; - int32_t aExp; - uint64_t aSig0, aSig1; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) { - return commonNaNToFloat64(float128ToCommonNaN(a, status), status); - } - return packFloat64( aSign, 0x7FF, 0 ); - } - shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); - aSig0 |= ( aSig1 != 0 ); - if ( aExp || aSig0 ) { - aSig0 |= UINT64_C(0x4000000000000000); - aExp -= 0x3C01; - } - return roundAndPackFloat64(aSign, aExp, aSig0, status); - -} - /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the extended double-precision floating-point format. The From afc34931ebb919e41dcafcfea14e0ac8aff6e9ce Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 14 Nov 2020 12:53:12 -0800 Subject: [PATCH 0673/3028] softfloat: Move round_to_int to softfloat-parts.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time, convert to pointers, split out parts$N_round_to_int_normal, define a macro for parts_round_to_int using QEMU_GENERIC. This necessarily meant some rearrangement to the rount_to_{,u}int_and_pack routines, so go ahead and convert to parts_round_to_int_normal, which in turn allows cleaning up of the raised exception handling. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 157 ++++++++++++++ fpu/softfloat.c | 434 ++++++++++---------------------------- 2 files changed, 263 insertions(+), 328 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index f8165d92f9..b2c4624d8c 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -594,3 +594,160 @@ static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b, a->cls = float_class_inf; return a; } + +/* + * Rounds the floating-point value `a' to an integer, and returns the + * result as a floating-point value. The operation is performed + * according to the IEC/IEEE Standard for Binary Floating-Point + * Arithmetic. + * + * parts_round_to_int_normal is an internal helper function for + * normal numbers only, returning true for inexact but not directly + * raising float_flag_inexact. + */ +static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, + int scale, int frac_size) +{ + uint64_t frac_lsb, frac_lsbm1, rnd_even_mask, rnd_mask, inc; + int shift_adj; + + scale = MIN(MAX(scale, -0x10000), 0x10000); + a->exp += scale; + + if (a->exp < 0) { + bool one; + + /* All fractional */ + switch (rmode) { + case float_round_nearest_even: + one = false; + if (a->exp == -1) { + FloatPartsN tmp; + /* Shift left one, discarding DECOMPOSED_IMPLICIT_BIT */ + frac_add(&tmp, a, a); + /* Anything remaining means frac > 0.5. */ + one = !frac_eqz(&tmp); + } + break; + case float_round_ties_away: + one = a->exp == -1; + break; + case float_round_to_zero: + one = false; + break; + case float_round_up: + one = !a->sign; + break; + case float_round_down: + one = a->sign; + break; + case float_round_to_odd: + one = true; + break; + default: + g_assert_not_reached(); + } + + frac_clear(a); + a->exp = 0; + if (one) { + a->frac_hi = DECOMPOSED_IMPLICIT_BIT; + } else { + a->cls = float_class_zero; + } + return true; + } + + if (a->exp >= frac_size) { + /* All integral */ + return false; + } + + if (N > 64 && a->exp < N - 64) { + /* + * Rounding is not in the low word -- shift lsb to bit 2, + * which leaves room for sticky and rounding bit. + */ + shift_adj = (N - 1) - (a->exp + 2); + frac_shrjam(a, shift_adj); + frac_lsb = 1 << 2; + } else { + shift_adj = 0; + frac_lsb = DECOMPOSED_IMPLICIT_BIT >> (a->exp & 63); + } + + frac_lsbm1 = frac_lsb >> 1; + rnd_mask = frac_lsb - 1; + rnd_even_mask = rnd_mask | frac_lsb; + + if (!(a->frac_lo & rnd_mask)) { + /* Fractional bits already clear, undo the shift above. */ + frac_shl(a, shift_adj); + return false; + } + + switch (rmode) { + case float_round_nearest_even: + inc = ((a->frac_lo & rnd_even_mask) != frac_lsbm1 ? frac_lsbm1 : 0); + break; + case float_round_ties_away: + inc = frac_lsbm1; + break; + case float_round_to_zero: + inc = 0; + break; + case float_round_up: + inc = a->sign ? 0 : rnd_mask; + break; + case float_round_down: + inc = a->sign ? rnd_mask : 0; + break; + case float_round_to_odd: + inc = a->frac_lo & frac_lsb ? 0 : rnd_mask; + break; + default: + g_assert_not_reached(); + } + + if (shift_adj == 0) { + if (frac_addi(a, a, inc)) { + frac_shr(a, 1); + a->frac_hi |= DECOMPOSED_IMPLICIT_BIT; + a->exp++; + } + a->frac_lo &= ~rnd_mask; + } else { + frac_addi(a, a, inc); + a->frac_lo &= ~rnd_mask; + /* Be careful shifting back, not to overflow */ + frac_shl(a, shift_adj - 1); + if (a->frac_hi & DECOMPOSED_IMPLICIT_BIT) { + a->exp++; + } else { + frac_add(a, a, a); + } + } + return true; +} + +static void partsN(round_to_int)(FloatPartsN *a, FloatRoundMode rmode, + int scale, float_status *s, + const FloatFmt *fmt) +{ + switch (a->cls) { + case float_class_qnan: + case float_class_snan: + parts_return_nan(a, s); + break; + case float_class_zero: + case float_class_inf: + break; + case float_class_normal: + if (parts_round_to_int_normal(a, rmode, scale, fmt->frac_size)) { + float_raise(float_flag_inexact, s); + } + break; + default: + g_assert_not_reached(); + } +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index d056b5730b..5647a05d5d 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -811,6 +811,24 @@ static FloatParts128 *parts128_div(FloatParts128 *a, FloatParts128 *b, #define parts_div(A, B, S) \ PARTS_GENERIC_64_128(div, A)(A, B, S) +static bool parts64_round_to_int_normal(FloatParts64 *a, FloatRoundMode rm, + int scale, int frac_size); +static bool parts128_round_to_int_normal(FloatParts128 *a, FloatRoundMode r, + int scale, int frac_size); + +#define parts_round_to_int_normal(A, R, C, F) \ + PARTS_GENERIC_64_128(round_to_int_normal, A)(A, R, C, F) + +static void parts64_round_to_int(FloatParts64 *a, FloatRoundMode rm, + int scale, float_status *s, + const FloatFmt *fmt); +static void parts128_round_to_int(FloatParts128 *a, FloatRoundMode r, + int scale, float_status *s, + const FloatFmt *fmt); + +#define parts_round_to_int(A, R, C, S, F) \ + PARTS_GENERIC_64_128(round_to_int, A)(A, R, C, S, F) + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ @@ -2285,153 +2303,52 @@ float128 float64_to_float128(float64 a, float_status *s) } /* - * Rounds the floating-point value `a' to an integer, and returns the - * result as a floating-point value. The operation is performed - * according to the IEC/IEEE Standard for Binary Floating-Point - * Arithmetic. + * Round to integral value */ -static FloatParts64 round_to_int(FloatParts64 a, FloatRoundMode rmode, - int scale, float_status *s) -{ - switch (a.cls) { - case float_class_qnan: - case float_class_snan: - parts_return_nan(&a, s); - break; - - case float_class_zero: - case float_class_inf: - /* already "integral" */ - break; - - case float_class_normal: - scale = MIN(MAX(scale, -0x10000), 0x10000); - a.exp += scale; - - if (a.exp >= DECOMPOSED_BINARY_POINT) { - /* already integral */ - break; - } - if (a.exp < 0) { - bool one; - /* all fractional */ - float_raise(float_flag_inexact, s); - switch (rmode) { - case float_round_nearest_even: - one = a.exp == -1 && a.frac > DECOMPOSED_IMPLICIT_BIT; - break; - case float_round_ties_away: - one = a.exp == -1 && a.frac >= DECOMPOSED_IMPLICIT_BIT; - break; - case float_round_to_zero: - one = false; - break; - case float_round_up: - one = !a.sign; - break; - case float_round_down: - one = a.sign; - break; - case float_round_to_odd: - one = true; - break; - default: - g_assert_not_reached(); - } - - if (one) { - a.frac = DECOMPOSED_IMPLICIT_BIT; - a.exp = 0; - } else { - a.cls = float_class_zero; - } - } else { - uint64_t frac_lsb = DECOMPOSED_IMPLICIT_BIT >> a.exp; - uint64_t frac_lsbm1 = frac_lsb >> 1; - uint64_t rnd_even_mask = (frac_lsb - 1) | frac_lsb; - uint64_t rnd_mask = rnd_even_mask >> 1; - uint64_t inc; - - switch (rmode) { - case float_round_nearest_even: - inc = ((a.frac & rnd_even_mask) != frac_lsbm1 ? frac_lsbm1 : 0); - break; - case float_round_ties_away: - inc = frac_lsbm1; - break; - case float_round_to_zero: - inc = 0; - break; - case float_round_up: - inc = a.sign ? 0 : rnd_mask; - break; - case float_round_down: - inc = a.sign ? rnd_mask : 0; - break; - case float_round_to_odd: - inc = a.frac & frac_lsb ? 0 : rnd_mask; - break; - default: - g_assert_not_reached(); - } - - if (a.frac & rnd_mask) { - float_raise(float_flag_inexact, s); - if (uadd64_overflow(a.frac, inc, &a.frac)) { - a.frac >>= 1; - a.frac |= DECOMPOSED_IMPLICIT_BIT; - a.exp++; - } - a.frac &= ~rnd_mask; - } - } - break; - default: - g_assert_not_reached(); - } - return a; -} - float16 float16_round_to_int(float16 a, float_status *s) { - FloatParts64 pa, pr; + FloatParts64 p; - float16_unpack_canonical(&pa, a, s); - pr = round_to_int(pa, s->float_rounding_mode, 0, s); - return float16_round_pack_canonical(&pr, s); + float16_unpack_canonical(&p, a, s); + parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float16_params); + return float16_round_pack_canonical(&p, s); } float32 float32_round_to_int(float32 a, float_status *s) { - FloatParts64 pa, pr; + FloatParts64 p; - float32_unpack_canonical(&pa, a, s); - pr = round_to_int(pa, s->float_rounding_mode, 0, s); - return float32_round_pack_canonical(&pr, s); + float32_unpack_canonical(&p, a, s); + parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float32_params); + return float32_round_pack_canonical(&p, s); } float64 float64_round_to_int(float64 a, float_status *s) { - FloatParts64 pa, pr; + FloatParts64 p; - float64_unpack_canonical(&pa, a, s); - pr = round_to_int(pa, s->float_rounding_mode, 0, s); - return float64_round_pack_canonical(&pr, s); + float64_unpack_canonical(&p, a, s); + parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float64_params); + return float64_round_pack_canonical(&p, s); } -/* - * Rounds the bfloat16 value `a' to an integer, and returns the - * result as a bfloat16 value. - */ - bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s) { - FloatParts64 pa, pr; + FloatParts64 p; - bfloat16_unpack_canonical(&pa, a, s); - pr = round_to_int(pa, s->float_rounding_mode, 0, s); - return bfloat16_round_pack_canonical(&pr, s); + bfloat16_unpack_canonical(&p, a, s); + parts_round_to_int(&p, s->float_rounding_mode, 0, s, &bfloat16_params); + return bfloat16_round_pack_canonical(&p, s); +} + +float128 float128_round_to_int(float128 a, float_status *s) +{ + FloatParts128 p; + + float128_unpack_canonical(&p, a, s); + parts_round_to_int(&p, s->float_rounding_mode, 0, s, &float128_params); + return float128_round_pack_canonical(&p, s); } /* @@ -2445,48 +2362,58 @@ bfloat16 bfloat16_round_to_int(bfloat16 a, float_status *s) * is returned. */ -static int64_t round_to_int_and_pack(FloatParts64 in, FloatRoundMode rmode, +static int64_t round_to_int_and_pack(FloatParts64 p, FloatRoundMode rmode, int scale, int64_t min, int64_t max, float_status *s) { + int flags = 0; uint64_t r; - int orig_flags = get_float_exception_flags(s); - FloatParts64 p = round_to_int(in, rmode, scale, s); switch (p.cls) { case float_class_snan: case float_class_qnan: - s->float_exception_flags = orig_flags | float_flag_invalid; - return max; + flags = float_flag_invalid; + r = max; + break; + case float_class_inf: - s->float_exception_flags = orig_flags | float_flag_invalid; - return p.sign ? min : max; + flags = float_flag_invalid; + r = p.sign ? min : max; + break; + case float_class_zero: return 0; + case float_class_normal: + /* TODO: 62 = N - 2, frac_size for rounding */ + if (parts_round_to_int_normal(&p, rmode, scale, 62)) { + flags = float_flag_inexact; + } + if (p.exp <= DECOMPOSED_BINARY_POINT) { r = p.frac >> (DECOMPOSED_BINARY_POINT - p.exp); } else { r = UINT64_MAX; } if (p.sign) { - if (r <= -(uint64_t) min) { - return -r; + if (r <= -(uint64_t)min) { + r = -r; } else { - s->float_exception_flags = orig_flags | float_flag_invalid; - return min; - } - } else { - if (r <= max) { - return r; - } else { - s->float_exception_flags = orig_flags | float_flag_invalid; - return max; + flags = float_flag_invalid; + r = min; } + } else if (r > max) { + flags = float_flag_invalid; + r = max; } + break; + default: g_assert_not_reached(); } + + float_raise(flags, s); + return r; } int8_t float16_to_int8_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -2749,49 +2676,59 @@ int64_t bfloat16_to_int64_round_to_zero(bfloat16 a, float_status *s) * flag. */ -static uint64_t round_to_uint_and_pack(FloatParts64 in, FloatRoundMode rmode, +static uint64_t round_to_uint_and_pack(FloatParts64 p, FloatRoundMode rmode, int scale, uint64_t max, float_status *s) { - int orig_flags = get_float_exception_flags(s); - FloatParts64 p = round_to_int(in, rmode, scale, s); + int flags = 0; uint64_t r; switch (p.cls) { case float_class_snan: case float_class_qnan: - s->float_exception_flags = orig_flags | float_flag_invalid; - return max; + flags = float_flag_invalid; + r = max; + break; + case float_class_inf: - s->float_exception_flags = orig_flags | float_flag_invalid; - return p.sign ? 0 : max; + flags = float_flag_invalid; + r = p.sign ? 0 : max; + break; + case float_class_zero: return 0; + case float_class_normal: + /* TODO: 62 = N - 2, frac_size for rounding */ + if (parts_round_to_int_normal(&p, rmode, scale, 62)) { + flags = float_flag_inexact; + if (p.cls == float_class_zero) { + r = 0; + break; + } + } + if (p.sign) { - s->float_exception_flags = orig_flags | float_flag_invalid; - return 0; - } - - if (p.exp <= DECOMPOSED_BINARY_POINT) { - r = p.frac >> (DECOMPOSED_BINARY_POINT - p.exp); + flags = float_flag_invalid; + r = 0; + } else if (p.exp > DECOMPOSED_BINARY_POINT) { + flags = float_flag_invalid; + r = max; } else { - s->float_exception_flags = orig_flags | float_flag_invalid; - return max; + r = p.frac >> (DECOMPOSED_BINARY_POINT - p.exp); + if (r > max) { + flags = float_flag_invalid; + r = max; + } } + break; - /* For uint64 this will never trip, but if p.exp is too large - * to shift a decomposed fraction we shall have exited via the - * 3rd leg above. - */ - if (r > max) { - s->float_exception_flags = orig_flags | float_flag_invalid; - return max; - } - return r; default: g_assert_not_reached(); } + + float_raise(flags, s); + return r; } uint8_t float16_to_uint8_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -6956,165 +6893,6 @@ floatx80 float128_to_floatx80(float128 a, float_status *status) } -/*---------------------------------------------------------------------------- -| Rounds the quadruple-precision floating-point value `a' to an integer, and -| returns the result as a quadruple-precision floating-point value. The -| operation is performed according to the IEC/IEEE Standard for Binary -| Floating-Point Arithmetic. -*----------------------------------------------------------------------------*/ - -float128 float128_round_to_int(float128 a, float_status *status) -{ - bool aSign; - int32_t aExp; - uint64_t lastBitMask, roundBitsMask; - float128 z; - - aExp = extractFloat128Exp( a ); - if ( 0x402F <= aExp ) { - if ( 0x406F <= aExp ) { - if ( ( aExp == 0x7FFF ) - && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) - ) { - return propagateFloat128NaN(a, a, status); - } - return a; - } - lastBitMask = 1; - lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1; - roundBitsMask = lastBitMask - 1; - z = a; - switch (status->float_rounding_mode) { - case float_round_nearest_even: - if ( lastBitMask ) { - add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low ); - if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; - } - else { - if ( (int64_t) z.low < 0 ) { - ++z.high; - if ( (uint64_t) ( z.low<<1 ) == 0 ) z.high &= ~1; - } - } - break; - case float_round_ties_away: - if (lastBitMask) { - add128(z.high, z.low, 0, lastBitMask >> 1, &z.high, &z.low); - } else { - if ((int64_t) z.low < 0) { - ++z.high; - } - } - break; - case float_round_to_zero: - break; - case float_round_up: - if (!extractFloat128Sign(z)) { - add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low); - } - break; - case float_round_down: - if (extractFloat128Sign(z)) { - add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low); - } - break; - case float_round_to_odd: - /* - * Note that if lastBitMask == 0, the last bit is the lsb - * of high, and roundBitsMask == -1. - */ - if ((lastBitMask ? z.low & lastBitMask : z.high & 1) == 0) { - add128(z.high, z.low, 0, roundBitsMask, &z.high, &z.low); - } - break; - default: - abort(); - } - z.low &= ~ roundBitsMask; - } - else { - if ( aExp < 0x3FFF ) { - if ( ( ( (uint64_t) ( a.high<<1 ) ) | a.low ) == 0 ) return a; - float_raise(float_flag_inexact, status); - aSign = extractFloat128Sign( a ); - switch (status->float_rounding_mode) { - case float_round_nearest_even: - if ( ( aExp == 0x3FFE ) - && ( extractFloat128Frac0( a ) - | extractFloat128Frac1( a ) ) - ) { - return packFloat128( aSign, 0x3FFF, 0, 0 ); - } - break; - case float_round_ties_away: - if (aExp == 0x3FFE) { - return packFloat128(aSign, 0x3FFF, 0, 0); - } - break; - case float_round_down: - return - aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) - : packFloat128( 0, 0, 0, 0 ); - case float_round_up: - return - aSign ? packFloat128( 1, 0, 0, 0 ) - : packFloat128( 0, 0x3FFF, 0, 0 ); - - case float_round_to_odd: - return packFloat128(aSign, 0x3FFF, 0, 0); - - case float_round_to_zero: - break; - } - return packFloat128( aSign, 0, 0, 0 ); - } - lastBitMask = 1; - lastBitMask <<= 0x402F - aExp; - roundBitsMask = lastBitMask - 1; - z.low = 0; - z.high = a.high; - switch (status->float_rounding_mode) { - case float_round_nearest_even: - z.high += lastBitMask>>1; - if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) { - z.high &= ~ lastBitMask; - } - break; - case float_round_ties_away: - z.high += lastBitMask>>1; - break; - case float_round_to_zero: - break; - case float_round_up: - if (!extractFloat128Sign(z)) { - z.high |= ( a.low != 0 ); - z.high += roundBitsMask; - } - break; - case float_round_down: - if (extractFloat128Sign(z)) { - z.high |= (a.low != 0); - z.high += roundBitsMask; - } - break; - case float_round_to_odd: - if ((z.high & lastBitMask) == 0) { - z.high |= (a.low != 0); - z.high += roundBitsMask; - } - break; - default: - abort(); - } - z.high &= ~ roundBitsMask; - } - if ( ( z.low != a.low ) || ( z.high != a.high ) ) { - float_raise(float_flag_inexact, status); - } - return z; - -} - /*---------------------------------------------------------------------------- | Returns the remainder of the quadruple-precision floating-point value `a' | with respect to the corresponding value `b'. The operation is performed From 463b3f0d7fa11054daeb5ca22346f77d566795bf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 14 Nov 2020 13:21:43 -0800 Subject: [PATCH 0674/3028] softfloat: Move round_to_int_and_pack to softfloat-parts.c.inc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename to parts$N_float_to_sint. Reimplement float128_to_int{32,64}{_round_to_zero} with FloatParts128. Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- fpu/softfloat-parts.c.inc | 64 +++++++ fpu/softfloat.c | 365 +++++++++----------------------------- 2 files changed, 145 insertions(+), 284 deletions(-) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index b2c4624d8c..a897a5a743 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -751,3 +751,67 @@ static void partsN(round_to_int)(FloatPartsN *a, FloatRoundMode rmode, g_assert_not_reached(); } } + +/* + * Returns the result of converting the floating-point value `a' to + * the two's complement integer format. The conversion is performed + * according to the IEC/IEEE Standard for Binary Floating-Point + * Arithmetic---which means in particular that the conversion is + * rounded according to the current rounding mode. If `a' is a NaN, + * the largest positive integer is returned. Otherwise, if the + * conversion overflows, the largest integer with the same sign as `a' + * is returned. +*/ +static int64_t partsN(float_to_sint)(FloatPartsN *p, FloatRoundMode rmode, + int scale, int64_t min, int64_t max, + float_status *s) +{ + int flags = 0; + uint64_t r; + + switch (p->cls) { + case float_class_snan: + case float_class_qnan: + flags = float_flag_invalid; + r = max; + break; + + case float_class_inf: + flags = float_flag_invalid; + r = p->sign ? min : max; + break; + + case float_class_zero: + return 0; + + case float_class_normal: + /* TODO: N - 2 is frac_size for rounding; could use input fmt. */ + if (parts_round_to_int_normal(p, rmode, scale, N - 2)) { + flags = float_flag_inexact; + } + + if (p->exp <= DECOMPOSED_BINARY_POINT) { + r = p->frac_hi >> (DECOMPOSED_BINARY_POINT - p->exp); + } else { + r = UINT64_MAX; + } + if (p->sign) { + if (r <= -(uint64_t)min) { + r = -r; + } else { + flags = float_flag_invalid; + r = min; + } + } else if (r > max) { + flags = float_flag_invalid; + r = max; + } + break; + + default: + g_assert_not_reached(); + } + + float_raise(flags, s); + return r; +} diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 5647a05d5d..0dc2203477 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -829,6 +829,16 @@ static void parts128_round_to_int(FloatParts128 *a, FloatRoundMode r, #define parts_round_to_int(A, R, C, S, F) \ PARTS_GENERIC_64_128(round_to_int, A)(A, R, C, S, F) +static int64_t parts64_float_to_sint(FloatParts64 *p, FloatRoundMode rmode, + int scale, int64_t min, int64_t max, + float_status *s); +static int64_t parts128_float_to_sint(FloatParts128 *p, FloatRoundMode rmode, + int scale, int64_t min, int64_t max, + float_status *s); + +#define parts_float_to_sint(P, R, Z, MN, MX, S) \ + PARTS_GENERIC_64_128(float_to_sint, P)(P, R, Z, MN, MX, S) + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ @@ -2352,69 +2362,8 @@ float128 float128_round_to_int(float128 a, float_status *s) } /* - * Returns the result of converting the floating-point value `a' to - * the two's complement integer format. The conversion is performed - * according to the IEC/IEEE Standard for Binary Floating-Point - * Arithmetic---which means in particular that the conversion is - * rounded according to the current rounding mode. If `a' is a NaN, - * the largest positive integer is returned. Otherwise, if the - * conversion overflows, the largest integer with the same sign as `a' - * is returned. -*/ - -static int64_t round_to_int_and_pack(FloatParts64 p, FloatRoundMode rmode, - int scale, int64_t min, int64_t max, - float_status *s) -{ - int flags = 0; - uint64_t r; - - switch (p.cls) { - case float_class_snan: - case float_class_qnan: - flags = float_flag_invalid; - r = max; - break; - - case float_class_inf: - flags = float_flag_invalid; - r = p.sign ? min : max; - break; - - case float_class_zero: - return 0; - - case float_class_normal: - /* TODO: 62 = N - 2, frac_size for rounding */ - if (parts_round_to_int_normal(&p, rmode, scale, 62)) { - flags = float_flag_inexact; - } - - if (p.exp <= DECOMPOSED_BINARY_POINT) { - r = p.frac >> (DECOMPOSED_BINARY_POINT - p.exp); - } else { - r = UINT64_MAX; - } - if (p.sign) { - if (r <= -(uint64_t)min) { - r = -r; - } else { - flags = float_flag_invalid; - r = min; - } - } else if (r > max) { - flags = float_flag_invalid; - r = max; - } - break; - - default: - g_assert_not_reached(); - } - - float_raise(flags, s); - return r; -} + * Floating-point to signed integer conversions + */ int8_t float16_to_int8_scalbn(float16 a, FloatRoundMode rmode, int scale, float_status *s) @@ -2422,7 +2371,7 @@ int8_t float16_to_int8_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT8_MIN, INT8_MAX, s); + return parts_float_to_sint(&p, rmode, scale, INT8_MIN, INT8_MAX, s); } int16_t float16_to_int16_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -2431,7 +2380,7 @@ int16_t float16_to_int16_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT16_MIN, INT16_MAX, s); + return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float16_to_int32_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -2440,7 +2389,7 @@ int32_t float16_to_int32_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT32_MIN, INT32_MAX, s); + return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float16_to_int64_scalbn(float16 a, FloatRoundMode rmode, int scale, @@ -2449,7 +2398,7 @@ int64_t float16_to_int64_scalbn(float16 a, FloatRoundMode rmode, int scale, FloatParts64 p; float16_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT64_MIN, INT64_MAX, s); + return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } int16_t float32_to_int16_scalbn(float32 a, FloatRoundMode rmode, int scale, @@ -2458,7 +2407,7 @@ int16_t float32_to_int16_scalbn(float32 a, FloatRoundMode rmode, int scale, FloatParts64 p; float32_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT16_MIN, INT16_MAX, s); + return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float32_to_int32_scalbn(float32 a, FloatRoundMode rmode, int scale, @@ -2467,7 +2416,7 @@ int32_t float32_to_int32_scalbn(float32 a, FloatRoundMode rmode, int scale, FloatParts64 p; float32_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT32_MIN, INT32_MAX, s); + return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float32_to_int64_scalbn(float32 a, FloatRoundMode rmode, int scale, @@ -2476,7 +2425,7 @@ int64_t float32_to_int64_scalbn(float32 a, FloatRoundMode rmode, int scale, FloatParts64 p; float32_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT64_MIN, INT64_MAX, s); + return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } int16_t float64_to_int16_scalbn(float64 a, FloatRoundMode rmode, int scale, @@ -2485,7 +2434,7 @@ int16_t float64_to_int16_scalbn(float64 a, FloatRoundMode rmode, int scale, FloatParts64 p; float64_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT16_MIN, INT16_MAX, s); + return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); } int32_t float64_to_int32_scalbn(float64 a, FloatRoundMode rmode, int scale, @@ -2494,7 +2443,7 @@ int32_t float64_to_int32_scalbn(float64 a, FloatRoundMode rmode, int scale, FloatParts64 p; float64_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT32_MIN, INT32_MAX, s); + return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); } int64_t float64_to_int64_scalbn(float64 a, FloatRoundMode rmode, int scale, @@ -2503,7 +2452,52 @@ int64_t float64_to_int64_scalbn(float64 a, FloatRoundMode rmode, int scale, FloatParts64 p; float64_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT64_MIN, INT64_MAX, s); + return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); +} + +int16_t bfloat16_to_int16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, + float_status *s) +{ + FloatParts64 p; + + bfloat16_unpack_canonical(&p, a, s); + return parts_float_to_sint(&p, rmode, scale, INT16_MIN, INT16_MAX, s); +} + +int32_t bfloat16_to_int32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, + float_status *s) +{ + FloatParts64 p; + + bfloat16_unpack_canonical(&p, a, s); + return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); +} + +int64_t bfloat16_to_int64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, + float_status *s) +{ + FloatParts64 p; + + bfloat16_unpack_canonical(&p, a, s); + return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); +} + +static int32_t float128_to_int32_scalbn(float128 a, FloatRoundMode rmode, + int scale, float_status *s) +{ + FloatParts128 p; + + float128_unpack_canonical(&p, a, s); + return parts_float_to_sint(&p, rmode, scale, INT32_MIN, INT32_MAX, s); +} + +static int64_t float128_to_int64_scalbn(float128 a, FloatRoundMode rmode, + int scale, float_status *s) +{ + FloatParts128 p; + + float128_unpack_canonical(&p, a, s); + return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } int8_t float16_to_int8(float16 a, float_status *s) @@ -2556,6 +2550,16 @@ int64_t float64_to_int64(float64 a, float_status *s) return float64_to_int64_scalbn(a, s->float_rounding_mode, 0, s); } +int32_t float128_to_int32(float128 a, float_status *s) +{ + return float128_to_int32_scalbn(a, s->float_rounding_mode, 0, s); +} + +int64_t float128_to_int64(float128 a, float_status *s) +{ + return float128_to_int64_scalbn(a, s->float_rounding_mode, 0, s); +} + int16_t float16_to_int16_round_to_zero(float16 a, float_status *s) { return float16_to_int16_scalbn(a, float_round_to_zero, 0, s); @@ -2601,36 +2605,14 @@ int64_t float64_to_int64_round_to_zero(float64 a, float_status *s) return float64_to_int64_scalbn(a, float_round_to_zero, 0, s); } -/* - * Returns the result of converting the floating-point value `a' to - * the two's complement integer format. - */ - -int16_t bfloat16_to_int16_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, - float_status *s) +int32_t float128_to_int32_round_to_zero(float128 a, float_status *s) { - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT16_MIN, INT16_MAX, s); + return float128_to_int32_scalbn(a, float_round_to_zero, 0, s); } -int32_t bfloat16_to_int32_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, - float_status *s) +int64_t float128_to_int64_round_to_zero(float128 a, float_status *s) { - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT32_MIN, INT32_MAX, s); -} - -int64_t bfloat16_to_int64_scalbn(bfloat16 a, FloatRoundMode rmode, int scale, - float_status *s) -{ - FloatParts64 p; - - bfloat16_unpack_canonical(&p, a, s); - return round_to_int_and_pack(p, rmode, scale, INT64_MIN, INT64_MAX, s); + return float128_to_int64_scalbn(a, float_round_to_zero, 0, s); } int16_t bfloat16_to_int16(bfloat16 a, float_status *s) @@ -6554,191 +6536,6 @@ floatx80 floatx80_sqrt(floatx80 a, float_status *status) 0, zExp, zSig0, zSig1, status); } -/*---------------------------------------------------------------------------- -| Returns the result of converting the quadruple-precision floating-point -| value `a' to the 32-bit two's complement integer format. The conversion -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic---which means in particular that the conversion is rounded -| according to the current rounding mode. If `a' is a NaN, the largest -| positive integer is returned. Otherwise, if the conversion overflows, the -| largest integer with the same sign as `a' is returned. -*----------------------------------------------------------------------------*/ - -int32_t float128_to_int32(float128 a, float_status *status) -{ - bool aSign; - int32_t aExp, shiftCount; - uint64_t aSig0, aSig1; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0; - if ( aExp ) aSig0 |= UINT64_C(0x0001000000000000); - aSig0 |= ( aSig1 != 0 ); - shiftCount = 0x4028 - aExp; - if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 ); - return roundAndPackInt32(aSign, aSig0, status); - -} - -/*---------------------------------------------------------------------------- -| Returns the result of converting the quadruple-precision floating-point -| value `a' to the 32-bit two's complement integer format. The conversion -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic, except that the conversion is always rounded toward zero. If -| `a' is a NaN, the largest positive integer is returned. Otherwise, if the -| conversion overflows, the largest integer with the same sign as `a' is -| returned. -*----------------------------------------------------------------------------*/ - -int32_t float128_to_int32_round_to_zero(float128 a, float_status *status) -{ - bool aSign; - int32_t aExp, shiftCount; - uint64_t aSig0, aSig1, savedASig; - int32_t z; - - aSig1 = extractFloat128Frac1( a ); - aSig0 = extractFloat128Frac0( a ); - aExp = extractFloat128Exp( a ); - aSign = extractFloat128Sign( a ); - aSig0 |= ( aSig1 != 0 ); - if ( 0x401E < aExp ) { - if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0; - goto invalid; - } - else if ( aExp < 0x3FFF ) { - if (aExp || aSig0) { - float_raise(float_flag_inexact, status); - } - return 0; - } - aSig0 |= UINT64_C(0x0001000000000000); - shiftCount = 0x402F - aExp; - savedASig = aSig0; - aSig0 >>= shiftCount; - z = aSig0; - if ( aSign ) z = - z; - if ( ( z < 0 ) ^ aSign ) { - invalid: - float_raise(float_flag_invalid, status); - return aSign ? INT32_MIN : INT32_MAX; - } - if ( ( aSig0<>( ( - shiftCount ) & 63 ) ); - if ( (uint64_t) ( aSig1<>( - shiftCount ); - if ( aSig1 - || ( shiftCount && (uint64_t) ( aSig0<<( shiftCount & 63 ) ) ) ) { - float_raise(float_flag_inexact, status); - } - } - if ( aSign ) z = - z; - return z; - -} - /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point value | `a' to the 64-bit unsigned integer format. The conversion is From 6c6a4a76eea900112c343ba4f9c5737e298feddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 15 May 2021 12:42:02 +0200 Subject: [PATCH 0675/3028] accel/tcg: Align data dumped at end of TB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To better visualize the data dumped at the end of a TB, left-align it (padding it with 0). Print ".long" instead of ".quad" on 32-bit hosts. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20210515104202.241504-1-f4bug@amsat.org> [rth: Split the qemu_log and print .long for 32-bit hosts.] Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index ae7e873713..fbf8fc630b 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -2042,8 +2042,15 @@ TranslationBlock *tb_gen_code(CPUState *cpu, int i; qemu_log(" data: [size=%d]\n", data_size); for (i = 0; i < data_size / sizeof(tcg_target_ulong); i++) { - qemu_log("0x%08" PRIxPTR ": .quad 0x%" TCG_PRIlx "\n", - (uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]); + if (sizeof(tcg_target_ulong) == 8) { + qemu_log("0x%08" PRIxPTR ": .quad 0x%016" TCG_PRIlx "\n", + (uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]); + } else if (sizeof(tcg_target_ulong) == 4) { + qemu_log("0x%08" PRIxPTR ": .long 0x%08" TCG_PRIlx "\n", + (uintptr_t)&rx_data_gen_ptr[i], rx_data_gen_ptr[i]); + } else { + qemu_build_not_reached(); + } } } qemu_log("\n"); From bc8afa62b4ce389b9847080a65e7c58696a30c06 Mon Sep 17 00:00:00 2001 From: Gollu Appalanaidu Date: Wed, 14 Apr 2021 12:34:35 +0530 Subject: [PATCH 0676/3028] hw/block/nvme: remove redundant invalid_lba_range trace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently pci_nvme_err_invalid_lba_range trace is called individually at each nvme_check_bounds() call site. Move the trace event to nvme_check_bounds() and remove the redundant events. Signed-off-by: Gollu Appalanaidu Reviewed-by: Philippe Mathieu-Daudé [k.jensen: commit message fixup] Signed-off-by: Klaus Jensen --- hw/block/nvme.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 5fe082ec34..cd594280a7 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1426,6 +1426,7 @@ static inline uint16_t nvme_check_bounds(NvmeNamespace *ns, uint64_t slba, uint64_t nsze = le64_to_cpu(ns->id_ns.nsze); if (unlikely(UINT64_MAX - slba < nlb || slba + nlb > nsze)) { + trace_pci_nvme_err_invalid_lba_range(slba, nlb, nsze); return NVME_LBA_RANGE | NVME_DNR; } @@ -2268,7 +2269,6 @@ static void nvme_copy_in_complete(NvmeRequest *req) status = nvme_check_bounds(ns, sdlba, ctx->nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(sdlba, ctx->nlb, ns->id_ns.nsze); goto invalid; } @@ -2530,8 +2530,6 @@ static uint16_t nvme_dsm(NvmeCtrl *n, NvmeRequest *req) uint32_t nlb = le32_to_cpu(range[i].nlb); if (nvme_check_bounds(ns, slba, nlb)) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, - ns->id_ns.nsze); continue; } @@ -2604,7 +2602,6 @@ static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest *req) status = nvme_check_bounds(ns, slba, nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); return status; } @@ -2689,7 +2686,6 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) status = nvme_check_bounds(ns, slba, _nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, _nlb, ns->id_ns.nsze); goto out; } @@ -2818,7 +2814,6 @@ static uint16_t nvme_compare(NvmeCtrl *n, NvmeRequest *req) status = nvme_check_bounds(ns, slba, nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); return status; } @@ -2938,7 +2933,6 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) status = nvme_check_bounds(ns, slba, nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); goto invalid; } @@ -3018,7 +3012,6 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, status = nvme_check_bounds(ns, slba, nlb); if (status) { - trace_pci_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); goto invalid; } From 9a31c61583cd7577a1716e1ed6bdd463f591e810 Mon Sep 17 00:00:00 2001 From: Gollu Appalanaidu Date: Wed, 17 Mar 2021 15:00:06 +0530 Subject: [PATCH 0677/3028] hw/block/nvme: rename reserved fields declarations Align the 'rsvd1' reserved field declaration in NvmeBar with existing style. Signed-off-by: Gollu Appalanaidu [k.jensen: minor commit message fixup] Signed-off-by: Klaus Jensen --- include/block/nvme.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/block/nvme.h b/include/block/nvme.h index 4ac926fbc6..e7fc119adb 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -7,7 +7,7 @@ typedef struct QEMU_PACKED NvmeBar { uint32_t intms; uint32_t intmc; uint32_t cc; - uint32_t rsvd1; + uint8_t rsvd24[4]; uint32_t csts; uint32_t nssrc; uint32_t aqa; From b4a983239343efd0a2d8a6cdf0690d0d707ec4ea Mon Sep 17 00:00:00 2001 From: Gollu Appalanaidu Date: Fri, 16 Apr 2021 12:52:33 +0530 Subject: [PATCH 0678/3028] hw/block/nvme: consider metadata read aio return value in compare Currently in compare command metadata aio read blk_aio_preadv return value ignored. Consider it and complete the block accounting. Signed-off-by: Gollu Appalanaidu Fixes: 0a384f923f51 ("hw/block/nvme: add compare command") Signed-off-by: Klaus Jensen --- hw/block/nvme.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index cd594280a7..67abc9eb2c 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -2369,10 +2369,19 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) uint32_t reftag = le32_to_cpu(rw->reftag); struct nvme_compare_ctx *ctx = req->opaque; g_autofree uint8_t *buf = NULL; + BlockBackend *blk = ns->blkconf.blk; + BlockAcctCookie *acct = &req->acct; + BlockAcctStats *stats = blk_get_stats(blk); uint16_t status = NVME_SUCCESS; trace_pci_nvme_compare_mdata_cb(nvme_cid(req)); + if (ret) { + block_acct_failed(stats, acct); + nvme_aio_err(req, ret); + goto out; + } + buf = g_malloc(ctx->mdata.iov.size); status = nvme_bounce_mdata(n, buf, ctx->mdata.iov.size, @@ -2421,6 +2430,8 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) goto out; } + block_acct_done(stats, acct); + out: qemu_iovec_destroy(&ctx->data.iov); g_free(ctx->data.bounce); From e5360eabd2a58f740ca92549461f6a23b3c3d8dc Mon Sep 17 00:00:00 2001 From: Gollu Appalanaidu Date: Mon, 19 Apr 2021 16:18:32 +0530 Subject: [PATCH 0679/3028] hw/block/nvme: fix io-command set profile feature Currently IO Command Set Profile feature is supported, but the feature support flag not set. Further, this feature is changable. Fix that. Additionally, remove filling default value of the CQE result with zero, since it will fall back to the default case anyway. Signed-off-by: Gollu Appalanaidu [k.jensen: fix up commit message] Signed-off-by: Klaus Jensen --- hw/block/nvme.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 67abc9eb2c..14c24f9b08 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -185,6 +185,7 @@ static const bool nvme_feature_support[NVME_FID_MAX] = { [NVME_WRITE_ATOMICITY] = true, [NVME_ASYNCHRONOUS_EVENT_CONF] = true, [NVME_TIMESTAMP] = true, + [NVME_COMMAND_SET_PROFILE] = true, }; static const uint32_t nvme_feature_cap[NVME_FID_MAX] = { @@ -194,6 +195,7 @@ static const uint32_t nvme_feature_cap[NVME_FID_MAX] = { [NVME_NUMBER_OF_QUEUES] = NVME_FEAT_CAP_CHANGE, [NVME_ASYNCHRONOUS_EVENT_CONF] = NVME_FEAT_CAP_CHANGE, [NVME_TIMESTAMP] = NVME_FEAT_CAP_CHANGE, + [NVME_COMMAND_SET_PROFILE] = NVME_FEAT_CAP_CHANGE, }; static const uint32_t nvme_cse_acs[256] = { @@ -4711,9 +4713,6 @@ defaults: result |= NVME_INTVC_NOCOALESCING; } break; - case NVME_COMMAND_SET_PROFILE: - result = 0; - break; default: result = nvme_feature_default[fid]; break; From 8e8555a38d6bb68242e2653bf3243d49501200a9 Mon Sep 17 00:00:00 2001 From: Gollu Appalanaidu Date: Wed, 21 Apr 2021 00:52:59 +0530 Subject: [PATCH 0680/3028] hw/block/nvme: function formatting fix nvme_map_addr_pmr function arguments not aligned, fix that. Signed-off-by: Gollu Appalanaidu Signed-off-by: Klaus Jensen --- hw/block/nvme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 14c24f9b08..79a087a41c 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -576,7 +576,7 @@ static uint16_t nvme_map_addr_cmb(NvmeCtrl *n, QEMUIOVector *iov, hwaddr addr, } static uint16_t nvme_map_addr_pmr(NvmeCtrl *n, QEMUIOVector *iov, hwaddr addr, - size_t len) + size_t len) { if (!len) { return NVME_SUCCESS; From 312c3531bba416e589f106db8c8241fc6e7e6332 Mon Sep 17 00:00:00 2001 From: Gollu Appalanaidu Date: Fri, 16 Apr 2021 09:22:28 +0530 Subject: [PATCH 0681/3028] hw/block/nvme: align with existing style While QEMU coding style prefers lowercase hexadecimals in constants, the NVMe subsystem uses the format from the NVMe specifications in comments, i.e. 'h' suffix instead of '0x' prefix. Fix this up across the code base. Signed-off-by: Gollu Appalanaidu [k.jensen: updated message; added conversion in a couple of missing comments] Signed-off-by: Klaus Jensen --- hw/block/nvme-ns.c | 2 +- hw/block/nvme.c | 67 +++++++++++++++++++++++++------------------- include/block/nvme.h | 10 +++---- 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 7bb618f182..a0895614d9 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -303,7 +303,7 @@ static void nvme_ns_init_zoned(NvmeNamespace *ns) id_ns_z = g_malloc0(sizeof(NvmeIdNsZoned)); - /* MAR/MOR are zeroes-based, 0xffffffff means no limit */ + /* MAR/MOR are zeroes-based, FFFFFFFFFh means no limit */ id_ns_z->mar = cpu_to_le32(ns->params.max_active_zones - 1); id_ns_z->mor = cpu_to_le32(ns->params.max_open_zones - 1); id_ns_z->zoc = 0; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 79a087a41c..baba949660 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -12,10 +12,19 @@ * Reference Specs: http://www.nvmexpress.org, 1.4, 1.3, 1.2, 1.1, 1.0e * * https://nvmexpress.org/developers/nvme-specification/ - */ - -/** - * Usage: add options: + * + * + * Notes on coding style + * --------------------- + * While QEMU coding style prefers lowercase hexadecimals in constants, the + * NVMe subsystem use thes format from the NVMe specifications in the comments + * (i.e. 'h' suffix instead of '0x' prefix). + * + * Usage + * ----- + * See docs/system/nvme.rst for extensive documentation. + * + * Add options: * -drive file=,if=none,id= * -device nvme-subsys,id=,nqn= * -device nvme,serial=,id=, \ @@ -3613,18 +3622,18 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) /* * In the base NVM command set, Flush may apply to all namespaces - * (indicated by NSID being set to 0xFFFFFFFF). But if that feature is used + * (indicated by NSID being set to FFFFFFFFh). But if that feature is used * along with TP 4056 (Namespace Types), it may be pretty screwed up. * - * If NSID is indeed set to 0xFFFFFFFF, we simply cannot associate the + * If NSID is indeed set to FFFFFFFFh, we simply cannot associate the * opcode with a specific command since we cannot determine a unique I/O - * command set. Opcode 0x0 could have any other meaning than something + * command set. Opcode 0h could have any other meaning than something * equivalent to flushing and say it DOES have completely different - * semantics in some other command set - does an NSID of 0xFFFFFFFF then + * semantics in some other command set - does an NSID of FFFFFFFFh then * mean "for all namespaces, apply whatever command set specific command - * that uses the 0x0 opcode?" Or does it mean "for all namespaces, apply - * whatever command that uses the 0x0 opcode if, and only if, it allows - * NSID to be 0xFFFFFFFF"? + * that uses the 0h opcode?" Or does it mean "for all namespaces, apply + * whatever command that uses the 0h opcode if, and only if, it allows NSID + * to be FFFFFFFFh"? * * Anyway (and luckily), for now, we do not care about this since the * device only supports namespace types that includes the NVM Flush command @@ -3940,7 +3949,7 @@ static uint16_t nvme_changed_nslist(NvmeCtrl *n, uint8_t rae, uint32_t buf_len, NVME_CHANGED_NSID_SIZE) { /* * If more than 1024 namespaces, the first entry in the log page should - * be set to 0xffffffff and the others to 0 as spec. + * be set to FFFFFFFFh and the others to 0 as spec. */ if (i == ARRAY_SIZE(nslist)) { memset(nslist, 0x0, sizeof(nslist)); @@ -4338,7 +4347,7 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req, trace_pci_nvme_identify_nslist(min_nsid); /* - * Both 0xffffffff (NVME_NSID_BROADCAST) and 0xfffffffe are invalid values + * Both FFFFFFFFh (NVME_NSID_BROADCAST) and FFFFFFFFEh are invalid values * since the Active Namespace ID List should return namespaces with ids * *higher* than the NSID specified in the command. This is also specified * in the spec (NVM Express v1.3d, Section 5.15.4). @@ -4385,7 +4394,7 @@ static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeRequest *req, trace_pci_nvme_identify_nslist_csi(min_nsid, c->csi); /* - * Same as in nvme_identify_nslist(), 0xffffffff/0xfffffffe are invalid. + * Same as in nvme_identify_nslist(), FFFFFFFFh/FFFFFFFFEh are invalid. */ if (min_nsid >= NVME_NSID_BROADCAST - 1) { return NVME_INVALID_NSID | NVME_DNR; @@ -4452,7 +4461,7 @@ static uint16_t nvme_identify_ns_descr_list(NvmeCtrl *n, NvmeRequest *req) /* * Because the NGUID and EUI64 fields are 0 in the Identify Namespace data - * structure, a Namespace UUID (nidt = 0x3) must be reported in the + * structure, a Namespace UUID (nidt = 3h) must be reported in the * Namespace Identification Descriptor. Add the namespace UUID here. */ ns_descrs->uuid.hdr.nidt = NVME_NIDT_UUID; @@ -4601,7 +4610,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req) /* * The Reservation Notification Mask and Reservation Persistence * features require a status code of Invalid Field in Command when - * NSID is 0xFFFFFFFF. Since the device does not support those + * NSID is FFFFFFFFh. Since the device does not support those * features we can always return Invalid Namespace or Format as we * should do for all other features. */ @@ -4850,15 +4859,15 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) } /* - * NVMe v1.3, Section 5.21.1.7: 0xffff is not an allowed value for NCQR + * NVMe v1.3, Section 5.21.1.7: FFFFh is not an allowed value for NCQR * and NSQR. */ if ((dw11 & 0xffff) == 0xffff || ((dw11 >> 16) & 0xffff) == 0xffff) { return NVME_INVALID_FIELD | NVME_DNR; } - trace_pci_nvme_setfeat_numq((dw11 & 0xFFFF) + 1, - ((dw11 >> 16) & 0xFFFF) + 1, + trace_pci_nvme_setfeat_numq((dw11 & 0xffff) + 1, + ((dw11 >> 16) & 0xffff) + 1, n->params.max_ioqpairs, n->params.max_ioqpairs); req->cqe.result = cpu_to_le32((n->params.max_ioqpairs - 1) | @@ -5496,7 +5505,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, n->bar.cc = data; } break; - case 0x1C: /* CSTS */ + case 0x1c: /* CSTS */ if (data & (1 << 4)) { NVME_GUEST_ERR(pci_nvme_ub_mmiowr_ssreset_w1c_unsupported, "attempted to W1C CSTS.NSSRO" @@ -5508,7 +5517,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, } break; case 0x20: /* NSSR */ - if (data == 0x4E564D65) { + if (data == 0x4e564d65) { trace_pci_nvme_ub_mmiowr_ssreset_unsupported(); } else { /* The spec says that writes of other values have no effect */ @@ -5578,11 +5587,11 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, n->bar.cmbmsc = (n->bar.cmbmsc & 0xffffffff) | (data << 32); return; - case 0xE00: /* PMRCAP */ + case 0xe00: /* PMRCAP */ NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrcap_readonly, "invalid write to PMRCAP register, ignored"); return; - case 0xE04: /* PMRCTL */ + case 0xe04: /* PMRCTL */ n->bar.pmrctl = data; if (NVME_PMRCTL_EN(data)) { memory_region_set_enabled(&n->pmr.dev->mr, true); @@ -5593,19 +5602,19 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, n->pmr.cmse = false; } return; - case 0xE08: /* PMRSTS */ + case 0xe08: /* PMRSTS */ NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrsts_readonly, "invalid write to PMRSTS register, ignored"); return; - case 0xE0C: /* PMREBS */ + case 0xe0C: /* PMREBS */ NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrebs_readonly, "invalid write to PMREBS register, ignored"); return; - case 0xE10: /* PMRSWTP */ + case 0xe10: /* PMRSWTP */ NVME_GUEST_ERR(pci_nvme_ub_mmiowr_pmrswtp_readonly, "invalid write to PMRSWTP register, ignored"); return; - case 0xE14: /* PMRMSCL */ + case 0xe14: /* PMRMSCL */ if (!NVME_CAP_PMRS(n->bar.cap)) { return; } @@ -5625,7 +5634,7 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, } return; - case 0xE18: /* PMRMSCU */ + case 0xe18: /* PMRMSCU */ if (!NVME_CAP_PMRS(n->bar.cap)) { return; } @@ -5667,7 +5676,7 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) * from PMRSTS should ensure prior writes * made it to persistent media */ - if (addr == 0xE08 && + if (addr == 0xe08 && (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) { memory_region_msync(&n->pmr.dev->mr, 0, n->pmr.dev->size); } diff --git a/include/block/nvme.h b/include/block/nvme.h index e7fc119adb..0ff9ce17a9 100644 --- a/include/block/nvme.h +++ b/include/block/nvme.h @@ -848,8 +848,8 @@ enum NvmeStatusCodes { NVME_FW_REQ_SUSYSTEM_RESET = 0x0110, NVME_NS_ALREADY_ATTACHED = 0x0118, NVME_NS_PRIVATE = 0x0119, - NVME_NS_NOT_ATTACHED = 0x011A, - NVME_NS_CTRL_LIST_INVALID = 0x011C, + NVME_NS_NOT_ATTACHED = 0x011a, + NVME_NS_CTRL_LIST_INVALID = 0x011c, NVME_CONFLICTING_ATTRS = 0x0180, NVME_INVALID_PROT_INFO = 0x0181, NVME_WRITE_TO_RO = 0x0182, @@ -1409,9 +1409,9 @@ typedef enum NvmeZoneState { NVME_ZONE_STATE_IMPLICITLY_OPEN = 0x02, NVME_ZONE_STATE_EXPLICITLY_OPEN = 0x03, NVME_ZONE_STATE_CLOSED = 0x04, - NVME_ZONE_STATE_READ_ONLY = 0x0D, - NVME_ZONE_STATE_FULL = 0x0E, - NVME_ZONE_STATE_OFFLINE = 0x0F, + NVME_ZONE_STATE_READ_ONLY = 0x0d, + NVME_ZONE_STATE_FULL = 0x0e, + NVME_ZONE_STATE_OFFLINE = 0x0f, } NvmeZoneState; static inline void _nvme_check_size(void) From c6dfa9d6b4b460a7dcf033478606fb17f8c5b0fa Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Thu, 15 Apr 2021 08:37:36 +0200 Subject: [PATCH 0682/3028] hw/block/nvme: rename __nvme_zrm_open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of the (reserved) double underscore use. Rename the "generic" zone open function to nvme_zrm_open_flags() and add a generic `int flags` argument instead which allows more flags to be easily added in the future. There is at least one TP under standardization that would add an additional flag. Cc: Philippe Mathieu-Daudé Cc: Thomas Huth Signed-off-by: Klaus Jensen Reviewed-by: Thomas Huth Reviewed-by: Keith Busch --- hw/block/nvme.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index baba949660..9e5ab4cacb 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1694,8 +1694,12 @@ static void nvme_zrm_auto_transition_zone(NvmeNamespace *ns) } } -static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone, - bool implicit) +enum { + NVME_ZRM_AUTO = 1 << 0, +}; + +static uint16_t nvme_zrm_open_flags(NvmeNamespace *ns, NvmeZone *zone, + int flags) { int act = 0; uint16_t status; @@ -1719,7 +1723,7 @@ static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone, nvme_aor_inc_open(ns); - if (implicit) { + if (flags & NVME_ZRM_AUTO) { nvme_assign_zone_state(ns, zone, NVME_ZONE_STATE_IMPLICITLY_OPEN); return NVME_SUCCESS; } @@ -1727,7 +1731,7 @@ static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone, /* fallthrough */ case NVME_ZONE_STATE_IMPLICITLY_OPEN: - if (implicit) { + if (flags & NVME_ZRM_AUTO) { return NVME_SUCCESS; } @@ -1745,12 +1749,12 @@ static uint16_t __nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone, static inline uint16_t nvme_zrm_auto(NvmeNamespace *ns, NvmeZone *zone) { - return __nvme_zrm_open(ns, zone, true); + return nvme_zrm_open_flags(ns, zone, NVME_ZRM_AUTO); } static inline uint16_t nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone) { - return __nvme_zrm_open(ns, zone, false); + return nvme_zrm_open_flags(ns, zone, 0); } static void __nvme_advance_zone_wp(NvmeNamespace *ns, NvmeZone *zone, From 7dbe53778ecba4c59de082e69f06c64d47d6eecb Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Thu, 15 Apr 2021 08:38:28 +0200 Subject: [PATCH 0683/3028] hw/block/nvme: rename __nvme_advance_zone_wp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of the (reserved) double underscore use. Cc: Philippe Mathieu-Daudé Cc: Thomas Huth Signed-off-by: Klaus Jensen Reviewed-by: Thomas Huth Reviewed-by: Keith Busch --- hw/block/nvme.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 9e5ab4cacb..acbfa3f890 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1757,8 +1757,8 @@ static inline uint16_t nvme_zrm_open(NvmeNamespace *ns, NvmeZone *zone) return nvme_zrm_open_flags(ns, zone, 0); } -static void __nvme_advance_zone_wp(NvmeNamespace *ns, NvmeZone *zone, - uint32_t nlb) +static void nvme_advance_zone_wp(NvmeNamespace *ns, NvmeZone *zone, + uint32_t nlb) { zone->d.wp += nlb; @@ -1778,7 +1778,7 @@ static void nvme_finalize_zoned_write(NvmeNamespace *ns, NvmeRequest *req) nlb = le16_to_cpu(rw->nlb) + 1; zone = nvme_get_zone_by_slba(ns, slba); - __nvme_advance_zone_wp(ns, zone, nlb); + nvme_advance_zone_wp(ns, zone, nlb); } static inline bool nvme_is_write(NvmeRequest *req) @@ -2167,7 +2167,7 @@ out: uint64_t sdlba = le64_to_cpu(copy->sdlba); NvmeZone *zone = nvme_get_zone_by_slba(ns, sdlba); - __nvme_advance_zone_wp(ns, zone, ctx->nlb); + nvme_advance_zone_wp(ns, zone, ctx->nlb); } g_free(ctx->bounce); From 42821d28648ff9fc456786192f944ce233aea0d3 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Thu, 15 Apr 2021 08:39:08 +0200 Subject: [PATCH 0684/3028] hw/block/nvme: rename __nvme_select_ns_iocs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of the (reserved) double underscore use. Cc: Philippe Mathieu-Daudé Cc: Thomas Huth Signed-off-by: Klaus Jensen Reviewed-by: Thomas Huth Reviewed-by: Keith Busch --- hw/block/nvme.c | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index acbfa3f890..f0cfca8698 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -4928,7 +4928,25 @@ static void nvme_update_dmrsl(NvmeCtrl *n) } } -static void __nvme_select_ns_iocs(NvmeCtrl *n, NvmeNamespace *ns); +static void nvme_select_iocs_ns(NvmeCtrl *n, NvmeNamespace *ns) +{ + ns->iocs = nvme_cse_iocs_none; + switch (ns->csi) { + case NVME_CSI_NVM: + if (NVME_CC_CSS(n->bar.cc) != NVME_CC_CSS_ADMIN_ONLY) { + ns->iocs = nvme_cse_iocs_nvm; + } + break; + case NVME_CSI_ZONED: + if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_CSI) { + ns->iocs = nvme_cse_iocs_zoned; + } else if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_NVM) { + ns->iocs = nvme_cse_iocs_nvm; + } + break; + } +} + static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req) { NvmeNamespace *ns; @@ -4979,7 +4997,7 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req) } nvme_attach_ns(ctrl, ns); - __nvme_select_ns_iocs(ctrl, ns); + nvme_select_iocs_ns(ctrl, ns); } else { if (!nvme_ns(ctrl, nsid)) { return NVME_NS_NOT_ATTACHED | NVME_DNR; @@ -5280,26 +5298,7 @@ static void nvme_ctrl_shutdown(NvmeCtrl *n) } } -static void __nvme_select_ns_iocs(NvmeCtrl *n, NvmeNamespace *ns) -{ - ns->iocs = nvme_cse_iocs_none; - switch (ns->csi) { - case NVME_CSI_NVM: - if (NVME_CC_CSS(n->bar.cc) != NVME_CC_CSS_ADMIN_ONLY) { - ns->iocs = nvme_cse_iocs_nvm; - } - break; - case NVME_CSI_ZONED: - if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_CSI) { - ns->iocs = nvme_cse_iocs_zoned; - } else if (NVME_CC_CSS(n->bar.cc) == NVME_CC_CSS_NVM) { - ns->iocs = nvme_cse_iocs_nvm; - } - break; - } -} - -static void nvme_select_ns_iocs(NvmeCtrl *n) +static void nvme_select_iocs(NvmeCtrl *n) { NvmeNamespace *ns; int i; @@ -5310,7 +5309,7 @@ static void nvme_select_ns_iocs(NvmeCtrl *n) continue; } - __nvme_select_ns_iocs(n, ns); + nvme_select_iocs_ns(n, ns); } } @@ -5412,7 +5411,7 @@ static int nvme_start_ctrl(NvmeCtrl *n) QTAILQ_INIT(&n->aer_queue); - nvme_select_ns_iocs(n); + nvme_select_iocs(n); return 0; } From d88e784f349591786ea673e55fc0c87383f2430c Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 14 Apr 2021 19:10:01 +0200 Subject: [PATCH 0685/3028] hw/block/nvme: consolidate header files In preparation for moving the nvme device into its own subtree, merge the header files into one. Also add missing copyright notice and add list of authors with substantial contributions. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-dif.c | 1 - hw/block/nvme-dif.h | 63 ------- hw/block/nvme-ns.c | 1 - hw/block/nvme-ns.h | 229 ------------------------ hw/block/nvme-subsys.c | 1 - hw/block/nvme-subsys.h | 59 ------- hw/block/nvme.c | 2 - hw/block/nvme.h | 383 +++++++++++++++++++++++++++++++++++++---- 8 files changed, 348 insertions(+), 391 deletions(-) delete mode 100644 hw/block/nvme-dif.h delete mode 100644 hw/block/nvme-ns.h delete mode 100644 hw/block/nvme-subsys.h diff --git a/hw/block/nvme-dif.c b/hw/block/nvme-dif.c index 81b0a4cb13..25e5a90854 100644 --- a/hw/block/nvme-dif.c +++ b/hw/block/nvme-dif.c @@ -15,7 +15,6 @@ #include "qapi/error.h" #include "trace.h" #include "nvme.h" -#include "nvme-dif.h" uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba, uint32_t reftag) diff --git a/hw/block/nvme-dif.h b/hw/block/nvme-dif.h deleted file mode 100644 index 524faffbd7..0000000000 --- a/hw/block/nvme-dif.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * QEMU NVM Express End-to-End Data Protection support - * - * Copyright (c) 2021 Samsung Electronics Co., Ltd. - * - * Authors: - * Klaus Jensen - * Gollu Appalanaidu - */ - -#ifndef HW_NVME_DIF_H -#define HW_NVME_DIF_H - -/* from Linux kernel (crypto/crct10dif_common.c) */ -static const uint16_t t10_dif_crc_table[256] = { - 0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B, - 0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6, - 0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6, - 0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B, - 0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1, - 0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C, - 0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C, - 0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781, - 0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8, - 0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255, - 0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925, - 0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698, - 0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472, - 0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF, - 0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF, - 0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02, - 0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA, - 0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067, - 0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17, - 0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA, - 0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640, - 0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD, - 0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D, - 0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30, - 0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759, - 0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4, - 0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394, - 0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29, - 0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3, - 0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E, - 0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E, - 0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3 -}; - -uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba, - uint32_t reftag); -uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen, - uint64_t slba); -void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len, - uint8_t *mbuf, size_t mlen, uint16_t apptag, - uint32_t reftag); -uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, - uint8_t *mbuf, size_t mlen, uint16_t ctrl, - uint64_t slba, uint16_t apptag, - uint16_t appmask, uint32_t reftag); -uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req); - -#endif /* HW_NVME_DIF_H */ diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index a0895614d9..4d7103e78f 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -28,7 +28,6 @@ #include "trace.h" #include "nvme.h" -#include "nvme-ns.h" #define MIN_DISCARD_GRANULARITY (4 * KiB) diff --git a/hw/block/nvme-ns.h b/hw/block/nvme-ns.h deleted file mode 100644 index fb0a41f912..0000000000 --- a/hw/block/nvme-ns.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * QEMU NVM Express Virtual Namespace - * - * Copyright (c) 2019 CNEX Labs - * Copyright (c) 2020 Samsung Electronics - * - * Authors: - * Klaus Jensen - * - * This work is licensed under the terms of the GNU GPL, version 2. See the - * COPYING file in the top-level directory. - * - */ - -#ifndef NVME_NS_H -#define NVME_NS_H - -#include "qemu/uuid.h" - -#define TYPE_NVME_NS "nvme-ns" -#define NVME_NS(obj) \ - OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS) - -typedef struct NvmeZone { - NvmeZoneDescr d; - uint64_t w_ptr; - QTAILQ_ENTRY(NvmeZone) entry; -} NvmeZone; - -typedef struct NvmeNamespaceParams { - bool detached; - bool shared; - uint32_t nsid; - QemuUUID uuid; - - uint16_t ms; - uint8_t mset; - uint8_t pi; - uint8_t pil; - - uint16_t mssrl; - uint32_t mcl; - uint8_t msrc; - - bool zoned; - bool cross_zone_read; - uint64_t zone_size_bs; - uint64_t zone_cap_bs; - uint32_t max_active_zones; - uint32_t max_open_zones; - uint32_t zd_extension_size; -} NvmeNamespaceParams; - -typedef struct NvmeNamespace { - DeviceState parent_obj; - BlockConf blkconf; - int32_t bootindex; - int64_t size; - int64_t mdata_offset; - NvmeIdNs id_ns; - const uint32_t *iocs; - uint8_t csi; - uint16_t status; - int attached; - - QTAILQ_ENTRY(NvmeNamespace) entry; - - NvmeIdNsZoned *id_ns_zoned; - NvmeZone *zone_array; - QTAILQ_HEAD(, NvmeZone) exp_open_zones; - QTAILQ_HEAD(, NvmeZone) imp_open_zones; - QTAILQ_HEAD(, NvmeZone) closed_zones; - QTAILQ_HEAD(, NvmeZone) full_zones; - uint32_t num_zones; - uint64_t zone_size; - uint64_t zone_capacity; - uint32_t zone_size_log2; - uint8_t *zd_extensions; - int32_t nr_open_zones; - int32_t nr_active_zones; - - NvmeNamespaceParams params; - - struct { - uint32_t err_rec; - } features; -} NvmeNamespace; - -static inline uint16_t nvme_ns_status(NvmeNamespace *ns) -{ - return ns->status; -} - -static inline uint32_t nvme_nsid(NvmeNamespace *ns) -{ - if (ns) { - return ns->params.nsid; - } - - return 0; -} - -static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns) -{ - NvmeIdNs *id_ns = &ns->id_ns; - return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; -} - -static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns) -{ - return nvme_ns_lbaf(ns)->ds; -} - -/* convert an LBA to the equivalent in bytes */ -static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba) -{ - return lba << nvme_ns_lbads(ns); -} - -static inline size_t nvme_lsize(NvmeNamespace *ns) -{ - return 1 << nvme_ns_lbads(ns); -} - -static inline uint16_t nvme_msize(NvmeNamespace *ns) -{ - return nvme_ns_lbaf(ns)->ms; -} - -static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba) -{ - return nvme_msize(ns) * lba; -} - -static inline bool nvme_ns_ext(NvmeNamespace *ns) -{ - return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas); -} - -/* calculate the number of LBAs that the namespace can accomodate */ -static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns) -{ - if (nvme_msize(ns)) { - return ns->size / (nvme_lsize(ns) + nvme_msize(ns)); - } - return ns->size >> nvme_ns_lbads(ns); -} - -typedef struct NvmeCtrl NvmeCtrl; - -static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone) -{ - return zone->d.zs >> 4; -} - -static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state) -{ - zone->d.zs = state << 4; -} - -static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone) -{ - return zone->d.zslba + ns->zone_size; -} - -static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone) -{ - return zone->d.zslba + zone->d.zcap; -} - -static inline bool nvme_wp_is_valid(NvmeZone *zone) -{ - uint8_t st = nvme_get_zone_state(zone); - - return st != NVME_ZONE_STATE_FULL && - st != NVME_ZONE_STATE_READ_ONLY && - st != NVME_ZONE_STATE_OFFLINE; -} - -static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns, - uint32_t zone_idx) -{ - return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size]; -} - -static inline void nvme_aor_inc_open(NvmeNamespace *ns) -{ - assert(ns->nr_open_zones >= 0); - if (ns->params.max_open_zones) { - ns->nr_open_zones++; - assert(ns->nr_open_zones <= ns->params.max_open_zones); - } -} - -static inline void nvme_aor_dec_open(NvmeNamespace *ns) -{ - if (ns->params.max_open_zones) { - assert(ns->nr_open_zones > 0); - ns->nr_open_zones--; - } - assert(ns->nr_open_zones >= 0); -} - -static inline void nvme_aor_inc_active(NvmeNamespace *ns) -{ - assert(ns->nr_active_zones >= 0); - if (ns->params.max_active_zones) { - ns->nr_active_zones++; - assert(ns->nr_active_zones <= ns->params.max_active_zones); - } -} - -static inline void nvme_aor_dec_active(NvmeNamespace *ns) -{ - if (ns->params.max_active_zones) { - assert(ns->nr_active_zones > 0); - ns->nr_active_zones--; - assert(ns->nr_active_zones >= ns->nr_open_zones); - } - assert(ns->nr_active_zones >= 0); -} - -void nvme_ns_init_format(NvmeNamespace *ns); -int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp); -void nvme_ns_drain(NvmeNamespace *ns); -void nvme_ns_shutdown(NvmeNamespace *ns); -void nvme_ns_cleanup(NvmeNamespace *ns); - -#endif /* NVME_NS_H */ diff --git a/hw/block/nvme-subsys.c b/hw/block/nvme-subsys.c index 9604c19117..3c404e3fcb 100644 --- a/hw/block/nvme-subsys.c +++ b/hw/block/nvme-subsys.c @@ -19,7 +19,6 @@ #include "block/accounting.h" #include "hw/pci/pci.h" #include "nvme.h" -#include "nvme-subsys.h" int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp) { diff --git a/hw/block/nvme-subsys.h b/hw/block/nvme-subsys.h deleted file mode 100644 index 7d7ef5f7f1..0000000000 --- a/hw/block/nvme-subsys.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * QEMU NVM Express Subsystem: nvme-subsys - * - * Copyright (c) 2021 Minwoo Im - * - * This code is licensed under the GNU GPL v2. Refer COPYING. - */ - -#ifndef NVME_SUBSYS_H -#define NVME_SUBSYS_H - -#define TYPE_NVME_SUBSYS "nvme-subsys" -#define NVME_SUBSYS(obj) \ - OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS) - -#define NVME_SUBSYS_MAX_CTRLS 32 -#define NVME_MAX_NAMESPACES 256 - -typedef struct NvmeCtrl NvmeCtrl; -typedef struct NvmeNamespace NvmeNamespace; -typedef struct NvmeSubsystem { - DeviceState parent_obj; - uint8_t subnqn[256]; - - NvmeCtrl *ctrls[NVME_SUBSYS_MAX_CTRLS]; - /* Allocated namespaces for this subsystem */ - NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1]; - - struct { - char *nqn; - } params; -} NvmeSubsystem; - -int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp); - -static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys, - uint32_t cntlid) -{ - if (!subsys || cntlid >= NVME_SUBSYS_MAX_CTRLS) { - return NULL; - } - - return subsys->ctrls[cntlid]; -} - -/* - * Return allocated namespace of the specified nsid in the subsystem. - */ -static inline NvmeNamespace *nvme_subsys_ns(NvmeSubsystem *subsys, - uint32_t nsid) -{ - if (!subsys || !nsid || nsid > NVME_MAX_NAMESPACES) { - return NULL; - } - - return subsys->namespaces[nsid]; -} - -#endif /* NVME_SUBSYS_H */ diff --git a/hw/block/nvme.c b/hw/block/nvme.c index f0cfca8698..29f80d5439 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -162,8 +162,6 @@ #include "qemu/cutils.h" #include "trace.h" #include "nvme.h" -#include "nvme-ns.h" -#include "nvme-dif.h" #define NVME_MAX_IOQPAIRS 0xffff #define NVME_DB_SIZE 4 diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 5d05ec368f..d9374d3e33 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -1,28 +1,281 @@ +/* + * QEMU NVM Express + * + * Copyright (c) 2012 Intel Corporation + * Copyright (c) 2021 Minwoo Im + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Authors: + * Keith Busch + * Klaus Jensen + * Gollu Appalanaidu + * Dmitry Fomichev + * Minwoo Im + * + * This code is licensed under the GNU GPL v2 or later. + */ + #ifndef HW_NVME_H #define HW_NVME_H -#include "block/nvme.h" +#include "qemu/uuid.h" #include "hw/pci/pci.h" -#include "nvme-subsys.h" -#include "nvme-ns.h" +#include "hw/block/block.h" + +#include "block/nvme.h" #define NVME_DEFAULT_ZONE_SIZE (128 * MiB) #define NVME_DEFAULT_MAX_ZA_SIZE (128 * KiB) +#define NVME_MAX_CONTROLLERS 32 +#define NVME_MAX_NAMESPACES 256 -typedef struct NvmeParams { - char *serial; - uint32_t num_queues; /* deprecated since 5.1 */ - uint32_t max_ioqpairs; - uint16_t msix_qsize; - uint32_t cmb_size_mb; - uint8_t aerl; - uint32_t aer_max_queued; - uint8_t mdts; - uint8_t vsl; - bool use_intel_id; - uint8_t zasl; - bool legacy_cmb; -} NvmeParams; +typedef struct NvmeCtrl NvmeCtrl; +typedef struct NvmeNamespace NvmeNamespace; + +#define TYPE_NVME_SUBSYS "nvme-subsys" +#define NVME_SUBSYS(obj) \ + OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS) + +typedef struct NvmeSubsystem { + DeviceState parent_obj; + uint8_t subnqn[256]; + + NvmeCtrl *ctrls[NVME_MAX_CONTROLLERS]; + NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1]; + + struct { + char *nqn; + } params; +} NvmeSubsystem; + +int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp); + +static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys, + uint32_t cntlid) +{ + if (!subsys || cntlid >= NVME_MAX_CONTROLLERS) { + return NULL; + } + + return subsys->ctrls[cntlid]; +} + +static inline NvmeNamespace *nvme_subsys_ns(NvmeSubsystem *subsys, + uint32_t nsid) +{ + if (!subsys || !nsid || nsid > NVME_MAX_NAMESPACES) { + return NULL; + } + + return subsys->namespaces[nsid]; +} + +#define TYPE_NVME_NS "nvme-ns" +#define NVME_NS(obj) \ + OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS) + +typedef struct NvmeZone { + NvmeZoneDescr d; + uint64_t w_ptr; + QTAILQ_ENTRY(NvmeZone) entry; +} NvmeZone; + +typedef struct NvmeNamespaceParams { + bool detached; + bool shared; + uint32_t nsid; + QemuUUID uuid; + + uint16_t ms; + uint8_t mset; + uint8_t pi; + uint8_t pil; + + uint16_t mssrl; + uint32_t mcl; + uint8_t msrc; + + bool zoned; + bool cross_zone_read; + uint64_t zone_size_bs; + uint64_t zone_cap_bs; + uint32_t max_active_zones; + uint32_t max_open_zones; + uint32_t zd_extension_size; +} NvmeNamespaceParams; + +typedef struct NvmeNamespace { + DeviceState parent_obj; + BlockConf blkconf; + int32_t bootindex; + int64_t size; + int64_t mdata_offset; + NvmeIdNs id_ns; + const uint32_t *iocs; + uint8_t csi; + uint16_t status; + int attached; + + QTAILQ_ENTRY(NvmeNamespace) entry; + + NvmeIdNsZoned *id_ns_zoned; + NvmeZone *zone_array; + QTAILQ_HEAD(, NvmeZone) exp_open_zones; + QTAILQ_HEAD(, NvmeZone) imp_open_zones; + QTAILQ_HEAD(, NvmeZone) closed_zones; + QTAILQ_HEAD(, NvmeZone) full_zones; + uint32_t num_zones; + uint64_t zone_size; + uint64_t zone_capacity; + uint32_t zone_size_log2; + uint8_t *zd_extensions; + int32_t nr_open_zones; + int32_t nr_active_zones; + + NvmeNamespaceParams params; + + struct { + uint32_t err_rec; + } features; +} NvmeNamespace; + +static inline uint16_t nvme_ns_status(NvmeNamespace *ns) +{ + return ns->status; +} + +static inline uint32_t nvme_nsid(NvmeNamespace *ns) +{ + if (ns) { + return ns->params.nsid; + } + + return 0; +} + +static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns) +{ + NvmeIdNs *id_ns = &ns->id_ns; + return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; +} + +static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns) +{ + return nvme_ns_lbaf(ns)->ds; +} + +/* convert an LBA to the equivalent in bytes */ +static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba) +{ + return lba << nvme_ns_lbads(ns); +} + +static inline size_t nvme_lsize(NvmeNamespace *ns) +{ + return 1 << nvme_ns_lbads(ns); +} + +static inline uint16_t nvme_msize(NvmeNamespace *ns) +{ + return nvme_ns_lbaf(ns)->ms; +} + +static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba) +{ + return nvme_msize(ns) * lba; +} + +static inline bool nvme_ns_ext(NvmeNamespace *ns) +{ + return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas); +} + +/* calculate the number of LBAs that the namespace can accomodate */ +static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns) +{ + if (nvme_msize(ns)) { + return ns->size / (nvme_lsize(ns) + nvme_msize(ns)); + } + return ns->size >> nvme_ns_lbads(ns); +} + +static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone) +{ + return zone->d.zs >> 4; +} + +static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state) +{ + zone->d.zs = state << 4; +} + +static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone) +{ + return zone->d.zslba + ns->zone_size; +} + +static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone) +{ + return zone->d.zslba + zone->d.zcap; +} + +static inline bool nvme_wp_is_valid(NvmeZone *zone) +{ + uint8_t st = nvme_get_zone_state(zone); + + return st != NVME_ZONE_STATE_FULL && + st != NVME_ZONE_STATE_READ_ONLY && + st != NVME_ZONE_STATE_OFFLINE; +} + +static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns, + uint32_t zone_idx) +{ + return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size]; +} + +static inline void nvme_aor_inc_open(NvmeNamespace *ns) +{ + assert(ns->nr_open_zones >= 0); + if (ns->params.max_open_zones) { + ns->nr_open_zones++; + assert(ns->nr_open_zones <= ns->params.max_open_zones); + } +} + +static inline void nvme_aor_dec_open(NvmeNamespace *ns) +{ + if (ns->params.max_open_zones) { + assert(ns->nr_open_zones > 0); + ns->nr_open_zones--; + } + assert(ns->nr_open_zones >= 0); +} + +static inline void nvme_aor_inc_active(NvmeNamespace *ns) +{ + assert(ns->nr_active_zones >= 0); + if (ns->params.max_active_zones) { + ns->nr_active_zones++; + assert(ns->nr_active_zones <= ns->params.max_active_zones); + } +} + +static inline void nvme_aor_dec_active(NvmeNamespace *ns) +{ + if (ns->params.max_active_zones) { + assert(ns->nr_active_zones > 0); + ns->nr_active_zones--; + assert(ns->nr_active_zones >= ns->nr_open_zones); + } + assert(ns->nr_active_zones >= 0); +} + +void nvme_ns_init_format(NvmeNamespace *ns); +int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp); +void nvme_ns_drain(NvmeNamespace *ns); +void nvme_ns_shutdown(NvmeNamespace *ns); +void nvme_ns_cleanup(NvmeNamespace *ns); typedef struct NvmeAsyncEvent { QTAILQ_ENTRY(NvmeAsyncEvent) entry; @@ -43,6 +296,11 @@ typedef struct NvmeSg { }; } NvmeSg; +typedef enum NvmeTxDirection { + NVME_TX_DIRECTION_TO_DEVICE = 0, + NVME_TX_DIRECTION_FROM_DEVICE = 1, +} NvmeTxDirection; + typedef struct NvmeRequest { struct NvmeSQueue *sq; struct NvmeNamespace *ns; @@ -143,13 +401,20 @@ typedef struct NvmeBus { #define NVME(obj) \ OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME) -typedef struct NvmeFeatureVal { - struct { - uint16_t temp_thresh_hi; - uint16_t temp_thresh_low; - }; - uint32_t async_config; -} NvmeFeatureVal; +typedef struct NvmeParams { + char *serial; + uint32_t num_queues; /* deprecated since 5.1 */ + uint32_t max_ioqpairs; + uint16_t msix_qsize; + uint32_t cmb_size_mb; + uint8_t aerl; + uint32_t aer_max_queued; + uint8_t mdts; + uint8_t vsl; + bool use_intel_id; + uint8_t zasl; + bool legacy_cmb; +} NvmeParams; typedef struct NvmeCtrl { PCIDevice parent_obj; @@ -204,22 +469,25 @@ typedef struct NvmeCtrl { NvmeSubsystem *subsys; NvmeNamespace namespace; - /* - * Attached namespaces to this controller. If subsys is not given, all - * namespaces in this list will always be attached. - */ NvmeNamespace *namespaces[NVME_MAX_NAMESPACES]; NvmeSQueue **sq; NvmeCQueue **cq; NvmeSQueue admin_sq; NvmeCQueue admin_cq; NvmeIdCtrl id_ctrl; - NvmeFeatureVal features; + + struct { + struct { + uint16_t temp_thresh_hi; + uint16_t temp_thresh_low; + }; + uint32_t async_config; + } features; } NvmeCtrl; static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid) { - if (!nsid || nsid > n->num_namespaces) { + if (!nsid || nsid > NVME_MAX_NAMESPACES) { return NULL; } @@ -249,11 +517,6 @@ static inline uint16_t nvme_cid(NvmeRequest *req) return le16_to_cpu(req->cqe.cid); } -typedef enum NvmeTxDirection { - NVME_TX_DIRECTION_TO_DEVICE = 0, - NVME_TX_DIRECTION_FROM_DEVICE = 1, -} NvmeTxDirection; - void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns); uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len, NvmeTxDirection dir, NvmeRequest *req); @@ -263,4 +526,54 @@ void nvme_rw_complete_cb(void *opaque, int ret); uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len, NvmeCmd *cmd); +/* from Linux kernel (crypto/crct10dif_common.c) */ +static const uint16_t t10_dif_crc_table[256] = { + 0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B, + 0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6, + 0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6, + 0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B, + 0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1, + 0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C, + 0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C, + 0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781, + 0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8, + 0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255, + 0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925, + 0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698, + 0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472, + 0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF, + 0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF, + 0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02, + 0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA, + 0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067, + 0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17, + 0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA, + 0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640, + 0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD, + 0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D, + 0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30, + 0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759, + 0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4, + 0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394, + 0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29, + 0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3, + 0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E, + 0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E, + 0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3 +}; + +uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba, + uint32_t reftag); +uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen, + uint64_t slba); +void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len, + uint8_t *mbuf, size_t mlen, uint16_t apptag, + uint32_t reftag); +uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, + uint8_t *mbuf, size_t mlen, uint16_t ctrl, + uint64_t slba, uint16_t apptag, + uint16_t appmask, uint32_t reftag); +uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req); + + #endif /* HW_NVME_H */ From 7ef37c1c59d62ace4417b33d81b430f165f102a4 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 14 Apr 2021 20:41:20 +0200 Subject: [PATCH 0686/3028] hw/block/nvme: cleanup includes Clean up includes. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-dif.c | 7 +++---- hw/block/nvme-ns.c | 11 ++--------- hw/block/nvme-subsys.c | 11 +---------- hw/block/nvme.c | 22 +++++++++------------- 4 files changed, 15 insertions(+), 36 deletions(-) diff --git a/hw/block/nvme-dif.c b/hw/block/nvme-dif.c index 25e5a90854..e269d275eb 100644 --- a/hw/block/nvme-dif.c +++ b/hw/block/nvme-dif.c @@ -9,12 +9,11 @@ */ #include "qemu/osdep.h" -#include "hw/block/block.h" -#include "sysemu/dma.h" -#include "sysemu/block-backend.h" #include "qapi/error.h" -#include "trace.h" +#include "sysemu/block-backend.h" + #include "nvme.h" +#include "trace.h" uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint16_t ctrl, uint64_t slba, uint32_t reftag) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 4d7103e78f..d91bf7bbbb 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -14,20 +14,13 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "qemu/cutils.h" -#include "qemu/log.h" #include "qemu/error-report.h" -#include "hw/block/block.h" -#include "hw/pci/pci.h" +#include "qapi/error.h" #include "sysemu/sysemu.h" #include "sysemu/block-backend.h" -#include "qapi/error.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-core.h" - -#include "trace.h" #include "nvme.h" +#include "trace.h" #define MIN_DISCARD_GRANULARITY (4 * KiB) diff --git a/hw/block/nvme-subsys.c b/hw/block/nvme-subsys.c index 3c404e3fcb..192223d17c 100644 --- a/hw/block/nvme-subsys.c +++ b/hw/block/nvme-subsys.c @@ -6,18 +6,9 @@ * This code is licensed under the GNU GPL v2. Refer COPYING. */ -#include "qemu/units.h" #include "qemu/osdep.h" -#include "qemu/uuid.h" -#include "qemu/iov.h" -#include "qemu/cutils.h" #include "qapi/error.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-core.h" -#include "hw/block/block.h" -#include "block/aio.h" -#include "block/accounting.h" -#include "hw/pci/pci.h" + #include "nvme.h" int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 29f80d5439..e152c61adb 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -144,24 +144,20 @@ */ #include "qemu/osdep.h" -#include "qemu/units.h" +#include "qemu/cutils.h" #include "qemu/error-report.h" -#include "hw/block/block.h" -#include "hw/pci/msix.h" -#include "hw/pci/pci.h" -#include "hw/qdev-properties.h" -#include "migration/vmstate.h" -#include "sysemu/sysemu.h" +#include "qemu/log.h" +#include "qemu/units.h" #include "qapi/error.h" #include "qapi/visitor.h" -#include "sysemu/hostmem.h" +#include "sysemu/sysemu.h" #include "sysemu/block-backend.h" -#include "exec/memory.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "qemu/cutils.h" -#include "trace.h" +#include "sysemu/hostmem.h" +#include "hw/pci/msix.h" +#include "migration/vmstate.h" + #include "nvme.h" +#include "trace.h" #define NVME_MAX_IOQPAIRS 0xffff #define NVME_DB_SIZE 4 From de482d1fad184d142433b939cdff9681f5cfc668 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 14 Apr 2021 20:42:27 +0200 Subject: [PATCH 0687/3028] hw/block/nvme: remove non-shared defines from header file Remove non-shared defines from the shared header. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-ns.c | 1 + hw/block/nvme.c | 1 + hw/block/nvme.h | 2 -- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index d91bf7bbbb..93aaf6de02 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -23,6 +23,7 @@ #include "trace.h" #define MIN_DISCARD_GRANULARITY (4 * KiB) +#define NVME_DEFAULT_ZONE_SIZE (128 * MiB) void nvme_ns_init_format(NvmeNamespace *ns) { diff --git a/hw/block/nvme.c b/hw/block/nvme.c index e152c61adb..e7bd22b8b2 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -168,6 +168,7 @@ #define NVME_TEMPERATURE_WARNING 0x157 #define NVME_TEMPERATURE_CRITICAL 0x175 #define NVME_NUM_FW_SLOTS 1 +#define NVME_DEFAULT_MAX_ZA_SIZE (128 * KiB) #define NVME_GUEST_ERR(trace, fmt, ...) \ do { \ diff --git a/hw/block/nvme.h b/hw/block/nvme.h index d9374d3e33..2c4e7b90fa 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -24,8 +24,6 @@ #include "block/nvme.h" -#define NVME_DEFAULT_ZONE_SIZE (128 * MiB) -#define NVME_DEFAULT_MAX_ZA_SIZE (128 * KiB) #define NVME_MAX_CONTROLLERS 32 #define NVME_MAX_NAMESPACES 256 From 0c76fee2f8e3332b8d7db89da13e4edfdcc5a4f0 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 14 Apr 2021 20:43:50 +0200 Subject: [PATCH 0688/3028] hw/block/nvme: replace nvme_ns_status The inline nvme_ns_status() helper only has a single call site. Remove it from the header file and inline it for real. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme.c | 15 ++++++++------- hw/block/nvme.h | 5 ----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index e7bd22b8b2..710af6a714 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -3609,8 +3609,8 @@ static uint16_t nvme_zone_mgmt_recv(NvmeCtrl *n, NvmeRequest *req) static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) { + NvmeNamespace *ns; uint32_t nsid = le32_to_cpu(req->cmd.nsid); - uint16_t status; trace_pci_nvme_io_cmd(nvme_cid(req), nsid, nvme_sqid(req), req->cmd.opcode, nvme_io_opc_str(req->cmd.opcode)); @@ -3642,21 +3642,22 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeRequest *req) return nvme_flush(n, req); } - req->ns = nvme_ns(n, nsid); - if (unlikely(!req->ns)) { + ns = nvme_ns(n, nsid); + if (unlikely(!ns)) { return NVME_INVALID_FIELD | NVME_DNR; } - if (!(req->ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) { + if (!(ns->iocs[req->cmd.opcode] & NVME_CMD_EFF_CSUPP)) { trace_pci_nvme_err_invalid_opc(req->cmd.opcode); return NVME_INVALID_OPCODE | NVME_DNR; } - status = nvme_ns_status(req->ns); - if (unlikely(status)) { - return status; + if (ns->status) { + return ns->status; } + req->ns = ns; + switch (req->cmd.opcode) { case NVME_CMD_WRITE_ZEROES: return nvme_write_zeroes(n, req); diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 2c4e7b90fa..d9bee7e5a0 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -137,11 +137,6 @@ typedef struct NvmeNamespace { } features; } NvmeNamespace; -static inline uint16_t nvme_ns_status(NvmeNamespace *ns) -{ - return ns->status; -} - static inline uint32_t nvme_nsid(NvmeNamespace *ns) { if (ns) { From 6146f3dd35cd71b4ac594b2e4a86c4bb3af52b09 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 14 Apr 2021 21:34:44 +0200 Subject: [PATCH 0689/3028] hw/block/nvme: cache lba and ms sizes There is no need to look up the lba size and metadata size in the LBA Format structure everytime we want to use it. And we use it a lot. Cache the values in the NvmeNamespace and update them if the namespace is formatted. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-dif.c | 45 ++++++++++++++++++------------------------- hw/block/nvme-ns.c | 26 +++++++++++++------------ hw/block/nvme.c | 47 ++++++++++++++++++--------------------------- hw/block/nvme.h | 37 ++++------------------------------- 4 files changed, 56 insertions(+), 99 deletions(-) diff --git a/hw/block/nvme-dif.c b/hw/block/nvme-dif.c index e269d275eb..c72e43195a 100644 --- a/hw/block/nvme-dif.c +++ b/hw/block/nvme-dif.c @@ -44,20 +44,18 @@ void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len, uint32_t reftag) { uint8_t *end = buf + len; - size_t lsize = nvme_lsize(ns); - size_t msize = nvme_msize(ns); int16_t pil = 0; if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { - pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + pil = ns->lbaf.ms - sizeof(NvmeDifTuple); } - trace_pci_nvme_dif_pract_generate_dif(len, lsize, lsize + pil, apptag, - reftag); + trace_pci_nvme_dif_pract_generate_dif(len, ns->lbasz, ns->lbasz + pil, + apptag, reftag); - for (; buf < end; buf += lsize, mbuf += msize) { + for (; buf < end; buf += ns->lbasz, mbuf += ns->lbaf.ms) { NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil); - uint16_t crc = crc_t10dif(0x0, buf, lsize); + uint16_t crc = crc_t10dif(0x0, buf, ns->lbasz); if (pil) { crc = crc_t10dif(crc, mbuf, pil); @@ -98,7 +96,7 @@ static uint16_t nvme_dif_prchk(NvmeNamespace *ns, NvmeDifTuple *dif, } if (ctrl & NVME_RW_PRINFO_PRCHK_GUARD) { - uint16_t crc = crc_t10dif(0x0, buf, nvme_lsize(ns)); + uint16_t crc = crc_t10dif(0x0, buf, ns->lbasz); if (pil) { crc = crc_t10dif(crc, mbuf, pil); @@ -137,8 +135,6 @@ uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, uint16_t appmask, uint32_t reftag) { uint8_t *end = buf + len; - size_t lsize = nvme_lsize(ns); - size_t msize = nvme_msize(ns); int16_t pil = 0; uint16_t status; @@ -148,12 +144,12 @@ uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, } if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { - pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + pil = ns->lbaf.ms - sizeof(NvmeDifTuple); } - trace_pci_nvme_dif_check(NVME_RW_PRINFO(ctrl), lsize + pil); + trace_pci_nvme_dif_check(NVME_RW_PRINFO(ctrl), ns->lbasz + pil); - for (; buf < end; buf += lsize, mbuf += msize) { + for (; buf < end; buf += ns->lbasz, mbuf += ns->lbaf.ms) { NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil); status = nvme_dif_prchk(ns, dif, buf, mbuf, pil, ctrl, apptag, @@ -176,20 +172,18 @@ uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen, BlockBackend *blk = ns->blkconf.blk; BlockDriverState *bs = blk_bs(blk); - size_t msize = nvme_msize(ns); - size_t lsize = nvme_lsize(ns); int64_t moffset = 0, offset = nvme_l2b(ns, slba); uint8_t *mbufp, *end; bool zeroed; int16_t pil = 0; - int64_t bytes = (mlen / msize) * lsize; + int64_t bytes = (mlen / ns->lbaf.ms) << ns->lbaf.ds; int64_t pnum = 0; Error *err = NULL; if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { - pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + pil = ns->lbaf.ms - sizeof(NvmeDifTuple); } do { @@ -211,15 +205,15 @@ uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen, if (zeroed) { mbufp = mbuf + moffset; - mlen = (pnum / lsize) * msize; + mlen = (pnum >> ns->lbaf.ds) * ns->lbaf.ms; end = mbufp + mlen; - for (; mbufp < end; mbufp += msize) { + for (; mbufp < end; mbufp += ns->lbaf.ms) { memset(mbufp + pil, 0xff, sizeof(NvmeDifTuple)); } } - moffset += (pnum / lsize) * msize; + moffset += (pnum >> ns->lbaf.ds) * ns->lbaf.ms; offset += pnum; } while (pnum != bytes); @@ -289,7 +283,7 @@ static void nvme_dif_rw_check_cb(void *opaque, int ret) goto out; } - if (ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8) { + if (ctrl & NVME_RW_PRINFO_PRACT && ns->lbaf.ms == 8) { goto out; } @@ -393,8 +387,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req) if (pract) { uint8_t *mbuf, *end; - size_t msize = nvme_msize(ns); - int16_t pil = msize - sizeof(NvmeDifTuple); + int16_t pil = ns->lbaf.ms - sizeof(NvmeDifTuple); status = nvme_check_prinfo(ns, ctrl, slba, reftag); if (status) { @@ -415,7 +408,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req) pil = 0; } - for (; mbuf < end; mbuf += msize) { + for (; mbuf < end; mbuf += ns->lbaf.ms) { NvmeDifTuple *dif = (NvmeDifTuple *)(mbuf + pil); dif->apptag = cpu_to_be16(apptag); @@ -434,7 +427,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req) return NVME_NO_COMPLETE; } - if (nvme_ns_ext(ns) && !(pract && nvme_msize(ns) == 8)) { + if (nvme_ns_ext(ns) && !(pract && ns->lbaf.ms == 8)) { mapped_len += mlen; } @@ -468,7 +461,7 @@ uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req) qemu_iovec_init(&ctx->mdata.iov, 1); qemu_iovec_add(&ctx->mdata.iov, ctx->mdata.bounce, mlen); - if (!(pract && nvme_msize(ns) == 8)) { + if (!(pract && ns->lbaf.ms == 8)) { status = nvme_bounce_mdata(n, ctx->mdata.bounce, ctx->mdata.iov.size, NVME_TX_DIRECTION_TO_DEVICE, req); if (status) { diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 93aaf6de02..b9369460b9 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -31,7 +31,10 @@ void nvme_ns_init_format(NvmeNamespace *ns) BlockDriverInfo bdi; int npdg, nlbas, ret; - nlbas = nvme_ns_nlbas(ns); + ns->lbaf = id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; + ns->lbasz = 1 << ns->lbaf.ds; + + nlbas = ns->size / (ns->lbasz + ns->lbaf.ms); id_ns->nsze = cpu_to_le64(nlbas); @@ -39,13 +42,13 @@ void nvme_ns_init_format(NvmeNamespace *ns) id_ns->ncap = id_ns->nsze; id_ns->nuse = id_ns->ncap; - ns->mdata_offset = nvme_l2b(ns, nlbas); + ns->mdata_offset = (int64_t)nlbas << ns->lbaf.ds; - npdg = ns->blkconf.discard_granularity / nvme_lsize(ns); + npdg = ns->blkconf.discard_granularity / ns->lbasz; ret = bdrv_get_info(blk_bs(ns->blkconf.blk), &bdi); if (ret >= 0 && bdi.cluster_size > ns->blkconf.discard_granularity) { - npdg = bdi.cluster_size / nvme_lsize(ns); + npdg = bdi.cluster_size / ns->lbasz; } id_ns->npda = id_ns->npdg = npdg - 1; @@ -163,7 +166,6 @@ static int nvme_ns_init_blk(NvmeNamespace *ns, Error **errp) static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) { uint64_t zone_size, zone_cap; - uint32_t lbasz = nvme_lsize(ns); /* Make sure that the values of ZNS properties are sane */ if (ns->params.zone_size_bs) { @@ -181,14 +183,14 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) "zone size %"PRIu64"B", zone_cap, zone_size); return -1; } - if (zone_size < lbasz) { + if (zone_size < ns->lbasz) { error_setg(errp, "zone size %"PRIu64"B too small, " - "must be at least %"PRIu32"B", zone_size, lbasz); + "must be at least %zuB", zone_size, ns->lbasz); return -1; } - if (zone_cap < lbasz) { + if (zone_cap < ns->lbasz) { error_setg(errp, "zone capacity %"PRIu64"B too small, " - "must be at least %"PRIu32"B", zone_cap, lbasz); + "must be at least %zuB", zone_cap, ns->lbasz); return -1; } @@ -196,9 +198,9 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) * Save the main zone geometry values to avoid * calculating them later again. */ - ns->zone_size = zone_size / lbasz; - ns->zone_capacity = zone_cap / lbasz; - ns->num_zones = nvme_ns_nlbas(ns) / ns->zone_size; + ns->zone_size = zone_size / ns->lbasz; + ns->zone_capacity = zone_cap / ns->lbasz; + ns->num_zones = le64_to_cpu(ns->id_ns.nsze) / ns->zone_size; /* Do a few more sanity checks of ZNS properties */ if (!ns->num_zones) { diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 710af6a714..9153d5d913 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -517,9 +517,7 @@ static void nvme_sg_split(NvmeSg *sg, NvmeNamespace *ns, NvmeSg *data, NvmeSg *mdata) { NvmeSg *dst = data; - size_t size = nvme_lsize(ns); - size_t msize = nvme_msize(ns); - uint32_t trans_len, count = size; + uint32_t trans_len, count = ns->lbasz; uint64_t offset = 0; bool dma = sg->flags & NVME_SG_DMA; size_t sge_len; @@ -551,7 +549,7 @@ static void nvme_sg_split(NvmeSg *sg, NvmeNamespace *ns, NvmeSg *data, if (count == 0) { dst = (dst == data) ? mdata : data; - count = (dst == data) ? size : msize; + count = (dst == data) ? ns->lbasz : ns->lbaf.ms; } if (sge_len == offset) { @@ -1010,7 +1008,7 @@ static uint16_t nvme_map_data(NvmeCtrl *n, uint32_t nlb, NvmeRequest *req) uint16_t status; if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps) && - (ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8)) { + (ctrl & NVME_RW_PRINFO_PRACT && ns->lbaf.ms == 8)) { goto out; } @@ -1193,12 +1191,9 @@ uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len, uint16_t ctrl = le16_to_cpu(rw->control); if (nvme_ns_ext(ns) && - !(ctrl & NVME_RW_PRINFO_PRACT && nvme_msize(ns) == 8)) { - size_t lsize = nvme_lsize(ns); - size_t msize = nvme_msize(ns); - - return nvme_tx_interleaved(n, &req->sg, ptr, len, lsize, msize, 0, - dir); + !(ctrl & NVME_RW_PRINFO_PRACT && ns->lbaf.ms == 8)) { + return nvme_tx_interleaved(n, &req->sg, ptr, len, ns->lbasz, + ns->lbaf.ms, 0, dir); } return nvme_tx(n, &req->sg, ptr, len, dir); @@ -1211,11 +1206,8 @@ uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len, uint16_t status; if (nvme_ns_ext(ns)) { - size_t lsize = nvme_lsize(ns); - size_t msize = nvme_msize(ns); - - return nvme_tx_interleaved(n, &req->sg, ptr, len, msize, lsize, lsize, - dir); + return nvme_tx_interleaved(n, &req->sg, ptr, len, ns->lbaf.ms, + ns->lbasz, ns->lbasz, dir); } nvme_sg_unmap(&req->sg); @@ -1843,7 +1835,7 @@ static void nvme_rw_cb(void *opaque, int ret) goto out; } - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; @@ -2115,7 +2107,7 @@ static void nvme_aio_zone_reset_cb(void *opaque, int ret) goto out; } - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { int64_t offset = ns->mdata_offset + nvme_m2b(ns, zone->d.zslba); blk_aio_pwrite_zeroes(ns->blkconf.blk, offset, @@ -2184,7 +2176,7 @@ static void nvme_copy_cb(void *opaque, int ret) goto out; } - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd; uint64_t sdlba = le64_to_cpu(copy->sdlba); int64_t offset = ns->mdata_offset + nvme_m2b(ns, sdlba); @@ -2406,7 +2398,6 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) uint8_t *bufp; uint8_t *mbufp = ctx->mdata.bounce; uint8_t *end = mbufp + ctx->mdata.iov.size; - size_t msize = nvme_msize(ns); int16_t pil = 0; status = nvme_dif_check(ns, ctx->data.bounce, ctx->data.iov.size, @@ -2422,11 +2413,11 @@ static void nvme_compare_mdata_cb(void *opaque, int ret) * tuple. */ if (!(ns->id_ns.dps & NVME_ID_NS_DPS_FIRST_EIGHT)) { - pil = nvme_msize(ns) - sizeof(NvmeDifTuple); + pil = ns->lbaf.ms - sizeof(NvmeDifTuple); } - for (bufp = buf; mbufp < end; bufp += msize, mbufp += msize) { - if (memcmp(bufp + pil, mbufp + pil, msize - pil)) { + for (bufp = buf; mbufp < end; bufp += ns->lbaf.ms, mbufp += ns->lbaf.ms) { + if (memcmp(bufp + pil, mbufp + pil, ns->lbaf.ms - pil)) { req->status = NVME_CMP_FAILURE; goto out; } @@ -2489,7 +2480,7 @@ static void nvme_compare_data_cb(void *opaque, int ret) goto out; } - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = le16_to_cpu(rw->nlb) + 1; @@ -2733,7 +2724,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) } bounce = bouncep = g_malloc(nvme_l2b(ns, nlb)); - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { mbounce = mbouncep = g_malloc(nvme_m2b(ns, nlb)); } @@ -2769,7 +2760,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) bouncep += len; - if (nvme_msize(ns)) { + if (ns->lbaf.ms) { len = nvme_m2b(ns, nlb); offset = ns->mdata_offset + nvme_m2b(ns, slba); @@ -2939,7 +2930,7 @@ static uint16_t nvme_read(NvmeCtrl *n, NvmeRequest *req) if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { bool pract = ctrl & NVME_RW_PRINFO_PRACT; - if (pract && nvme_msize(ns) == 8) { + if (pract && ns->lbaf.ms == 8) { mapped_size = data_size; } } @@ -3015,7 +3006,7 @@ static uint16_t nvme_do_write(NvmeCtrl *n, NvmeRequest *req, bool append, if (NVME_ID_NS_DPS_TYPE(ns->id_ns.dps)) { bool pract = ctrl & NVME_RW_PRINFO_PRACT; - if (pract && nvme_msize(ns) == 8) { + if (pract && ns->lbaf.ms == 8) { mapped_size -= nvme_m2b(ns, nlb); } } diff --git a/hw/block/nvme.h b/hw/block/nvme.h index d9bee7e5a0..dc065e57b5 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -109,6 +109,8 @@ typedef struct NvmeNamespace { int64_t size; int64_t mdata_offset; NvmeIdNs id_ns; + NvmeLBAF lbaf; + size_t lbasz; const uint32_t *iocs; uint8_t csi; uint16_t status; @@ -146,36 +148,14 @@ static inline uint32_t nvme_nsid(NvmeNamespace *ns) return 0; } -static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns) -{ - NvmeIdNs *id_ns = &ns->id_ns; - return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)]; -} - -static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns) -{ - return nvme_ns_lbaf(ns)->ds; -} - -/* convert an LBA to the equivalent in bytes */ static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba) { - return lba << nvme_ns_lbads(ns); -} - -static inline size_t nvme_lsize(NvmeNamespace *ns) -{ - return 1 << nvme_ns_lbads(ns); -} - -static inline uint16_t nvme_msize(NvmeNamespace *ns) -{ - return nvme_ns_lbaf(ns)->ms; + return lba << ns->lbaf.ds; } static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba) { - return nvme_msize(ns) * lba; + return ns->lbaf.ms * lba; } static inline bool nvme_ns_ext(NvmeNamespace *ns) @@ -183,15 +163,6 @@ static inline bool nvme_ns_ext(NvmeNamespace *ns) return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas); } -/* calculate the number of LBAs that the namespace can accomodate */ -static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns) -{ - if (nvme_msize(ns)) { - return ns->size / (nvme_lsize(ns) + nvme_msize(ns)); - } - return ns->size >> nvme_ns_lbads(ns); -} - static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone) { return zone->d.zs >> 4; From 3ef73f9462a0c142dce80ce5b4ff8789b39f2f64 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 13 Apr 2021 21:51:30 +0200 Subject: [PATCH 0690/3028] hw/block/nvme: add metadata offset helper Add an nvme_moff() helper. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-dif.c | 4 ++-- hw/block/nvme-ns.c | 2 +- hw/block/nvme.c | 12 ++++++------ hw/block/nvme.h | 7 ++++++- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/hw/block/nvme-dif.c b/hw/block/nvme-dif.c index c72e43195a..88efcbe9bd 100644 --- a/hw/block/nvme-dif.c +++ b/hw/block/nvme-dif.c @@ -306,7 +306,7 @@ static void nvme_dif_rw_mdata_in_cb(void *opaque, int ret) uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = le16_to_cpu(rw->nlb) + 1; size_t mlen = nvme_m2b(ns, nlb); - uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + uint64_t offset = nvme_moff(ns, slba); BlockBackend *blk = ns->blkconf.blk; trace_pci_nvme_dif_rw_mdata_in_cb(nvme_cid(req), blk_name(blk)); @@ -335,7 +335,7 @@ static void nvme_dif_rw_mdata_out_cb(void *opaque, int ret) NvmeNamespace *ns = req->ns; NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; uint64_t slba = le64_to_cpu(rw->slba); - uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + uint64_t offset = nvme_moff(ns, slba); BlockBackend *blk = ns->blkconf.blk; trace_pci_nvme_dif_rw_mdata_out_cb(nvme_cid(req), blk_name(blk)); diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index b9369460b9..b25838ac4f 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -42,7 +42,7 @@ void nvme_ns_init_format(NvmeNamespace *ns) id_ns->ncap = id_ns->nsze; id_ns->nuse = id_ns->ncap; - ns->mdata_offset = (int64_t)nlbas << ns->lbaf.ds; + ns->moff = (int64_t)nlbas << ns->lbaf.ds; npdg = ns->blkconf.discard_granularity / ns->lbasz; diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 9153d5d913..1db9a603f5 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -1839,7 +1839,7 @@ static void nvme_rw_cb(void *opaque, int ret) NvmeRwCmd *rw = (NvmeRwCmd *)&req->cmd; uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = (uint32_t)le16_to_cpu(rw->nlb) + 1; - uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + uint64_t offset = nvme_moff(ns, slba); if (req->cmd.opcode == NVME_CMD_WRITE_ZEROES) { size_t mlen = nvme_m2b(ns, nlb); @@ -2005,7 +2005,7 @@ static void nvme_verify_mdata_in_cb(void *opaque, int ret) uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = le16_to_cpu(rw->nlb) + 1; size_t mlen = nvme_m2b(ns, nlb); - uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + uint64_t offset = nvme_moff(ns, slba); BlockBackend *blk = ns->blkconf.blk; trace_pci_nvme_verify_mdata_in_cb(nvme_cid(req), blk_name(blk)); @@ -2108,7 +2108,7 @@ static void nvme_aio_zone_reset_cb(void *opaque, int ret) } if (ns->lbaf.ms) { - int64_t offset = ns->mdata_offset + nvme_m2b(ns, zone->d.zslba); + int64_t offset = nvme_moff(ns, zone->d.zslba); blk_aio_pwrite_zeroes(ns->blkconf.blk, offset, nvme_m2b(ns, ns->zone_size), BDRV_REQ_MAY_UNMAP, @@ -2179,7 +2179,7 @@ static void nvme_copy_cb(void *opaque, int ret) if (ns->lbaf.ms) { NvmeCopyCmd *copy = (NvmeCopyCmd *)&req->cmd; uint64_t sdlba = le64_to_cpu(copy->sdlba); - int64_t offset = ns->mdata_offset + nvme_m2b(ns, sdlba); + int64_t offset = nvme_moff(ns, sdlba); qemu_iovec_reset(&req->sg.iov); qemu_iovec_add(&req->sg.iov, ctx->mbounce, nvme_m2b(ns, ctx->nlb)); @@ -2485,7 +2485,7 @@ static void nvme_compare_data_cb(void *opaque, int ret) uint64_t slba = le64_to_cpu(rw->slba); uint32_t nlb = le16_to_cpu(rw->nlb) + 1; size_t mlen = nvme_m2b(ns, nlb); - uint64_t offset = ns->mdata_offset + nvme_m2b(ns, slba); + uint64_t offset = nvme_moff(ns, slba); ctx->mdata.bounce = g_malloc(mlen); @@ -2762,7 +2762,7 @@ static uint16_t nvme_copy(NvmeCtrl *n, NvmeRequest *req) if (ns->lbaf.ms) { len = nvme_m2b(ns, nlb); - offset = ns->mdata_offset + nvme_m2b(ns, slba); + offset = nvme_moff(ns, slba); in_ctx = g_new(struct nvme_copy_in_ctx, 1); in_ctx->req = req; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index dc065e57b5..9349d1c33a 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -107,7 +107,7 @@ typedef struct NvmeNamespace { BlockConf blkconf; int32_t bootindex; int64_t size; - int64_t mdata_offset; + int64_t moff; NvmeIdNs id_ns; NvmeLBAF lbaf; size_t lbasz; @@ -158,6 +158,11 @@ static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba) return ns->lbaf.ms * lba; } +static inline int64_t nvme_moff(NvmeNamespace *ns, uint64_t lba) +{ + return ns->moff + nvme_m2b(ns, lba); +} + static inline bool nvme_ns_ext(NvmeNamespace *ns) { return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas); From 72ea5c2c2067086ced90c7f5e4d98c93072a0fc2 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 14 Apr 2021 21:40:40 +0200 Subject: [PATCH 0691/3028] hw/block/nvme: streamline namespace array indexing Streamline namespace array indexing such that both the subsystem and controller namespaces arrays are 1-indexed. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme.c | 4 ++-- hw/block/nvme.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 1db9a603f5..baf7b67145 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -4990,7 +4990,7 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req) return NVME_NS_NOT_ATTACHED | NVME_DNR; } - ctrl->namespaces[nsid - 1] = NULL; + ctrl->namespaces[nsid] = NULL; ns->attached--; nvme_update_dmrsl(ctrl); @@ -6163,7 +6163,7 @@ void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns) uint32_t nsid = ns->params.nsid; assert(nsid && nsid <= NVME_MAX_NAMESPACES); - n->namespaces[nsid - 1] = ns; + n->namespaces[nsid] = ns; ns->attached++; n->dmrsl = MIN_NON_ZERO(n->dmrsl, diff --git a/hw/block/nvme.h b/hw/block/nvme.h index 9349d1c33a..ac3f0a8867 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -438,7 +438,7 @@ typedef struct NvmeCtrl { NvmeSubsystem *subsys; NvmeNamespace namespace; - NvmeNamespace *namespaces[NVME_MAX_NAMESPACES]; + NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1]; NvmeSQueue **sq; NvmeCQueue **cq; NvmeSQueue admin_sq; @@ -460,7 +460,7 @@ static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid) return NULL; } - return n->namespaces[nsid - 1]; + return n->namespaces[nsid]; } static inline NvmeCQueue *nvme_cq(NvmeRequest *req) From 9d394c80f19b86c5a0a8ca30d976bf2a25c3b645 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 14 Apr 2021 21:46:00 +0200 Subject: [PATCH 0692/3028] hw/block/nvme: remove num_namespaces member The NvmeCtrl num_namespaces member is just an indirection for the NVME_MAX_NAMESPACES constant. Remove the indirection. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme.c | 30 +++++++++++++++--------------- hw/block/nvme.h | 1 - 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index baf7b67145..0bcaf7192f 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -393,7 +393,8 @@ static int nvme_addr_write(NvmeCtrl *n, hwaddr addr, void *buf, int size) static bool nvme_nsid_valid(NvmeCtrl *n, uint32_t nsid) { - return nsid && (nsid == NVME_NSID_BROADCAST || nsid <= n->num_namespaces); + return nsid && + (nsid == NVME_NSID_BROADCAST || nsid <= NVME_MAX_NAMESPACES); } static int nvme_check_sqid(NvmeCtrl *n, uint16_t sqid) @@ -2882,7 +2883,7 @@ static uint16_t nvme_flush(NvmeCtrl *n, NvmeRequest *req) /* 1-initialize; see comment in nvme_dsm */ *num_flushes = 1; - for (int i = 1; i <= n->num_namespaces; i++) { + for (int i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -3850,7 +3851,7 @@ static uint16_t nvme_smart_info(NvmeCtrl *n, uint8_t rae, uint32_t buf_len, } else { int i; - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -4347,7 +4348,7 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeRequest *req, return NVME_INVALID_NSID | NVME_DNR; } - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { if (!active) { @@ -4395,7 +4396,7 @@ static uint16_t nvme_identify_nslist_csi(NvmeCtrl *n, NvmeRequest *req, return NVME_INVALID_FIELD | NVME_DNR; } - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { if (!active) { @@ -4661,7 +4662,7 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeRequest *req) goto out; case NVME_VOLATILE_WRITE_CACHE: result = 0; - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -4808,7 +4809,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) break; case NVME_ERROR_RECOVERY: if (nsid == NVME_NSID_BROADCAST) { - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { @@ -4829,7 +4830,7 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeRequest *req) } break; case NVME_VOLATILE_WRITE_CACHE: - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -5122,7 +5123,7 @@ static uint16_t nvme_format(NvmeCtrl *n, NvmeRequest *req) req->status = status; } } else { - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -5233,7 +5234,7 @@ static void nvme_ctrl_reset(NvmeCtrl *n) NvmeNamespace *ns; int i; - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -5275,7 +5276,7 @@ static void nvme_ctrl_shutdown(NvmeCtrl *n) memory_region_msync(&n->pmr.dev->mr, 0, n->pmr.dev->size); } - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -5290,7 +5291,7 @@ static void nvme_select_iocs(NvmeCtrl *n) NvmeNamespace *ns; int i; - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; @@ -5917,7 +5918,6 @@ static void nvme_check_constraints(NvmeCtrl *n, Error **errp) static void nvme_init_state(NvmeCtrl *n) { - n->num_namespaces = NVME_MAX_NAMESPACES; /* add one to max_ioqpairs to account for the admin queue pair */ n->reg_size = pow2ceil(sizeof(NvmeBar) + 2 * (n->params.max_ioqpairs + 1) * NVME_DB_SIZE); @@ -6098,7 +6098,7 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev) id->sqes = (0x6 << 4) | 0x6; id->cqes = (0x4 << 4) | 0x4; - id->nn = cpu_to_le32(n->num_namespaces); + id->nn = cpu_to_le32(NVME_MAX_NAMESPACES); id->oncs = cpu_to_le16(NVME_ONCS_WRITE_ZEROES | NVME_ONCS_TIMESTAMP | NVME_ONCS_FEATURES | NVME_ONCS_DSM | NVME_ONCS_COMPARE | NVME_ONCS_COPY); @@ -6217,7 +6217,7 @@ static void nvme_exit(PCIDevice *pci_dev) nvme_ctrl_reset(n); - for (i = 1; i <= n->num_namespaces; i++) { + for (i = 1; i <= NVME_MAX_NAMESPACES; i++) { ns = nvme_ns(n, i); if (!ns) { continue; diff --git a/hw/block/nvme.h b/hw/block/nvme.h index ac3f0a8867..fb028d81d1 100644 --- a/hw/block/nvme.h +++ b/hw/block/nvme.h @@ -401,7 +401,6 @@ typedef struct NvmeCtrl { uint16_t cqe_size; uint16_t sqe_size; uint32_t reg_size; - uint32_t num_namespaces; uint32_t max_q_ents; uint8_t outstanding_aers; uint32_t irq_status; From 83e85b614ddab2810b75583c6b3106ff42207a57 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Mar 2021 12:17:15 +0100 Subject: [PATCH 0693/3028] hw/block/nvme: remove irrelevant zone resource checks It is not an error to report more active/open zones supported than the number of zones in the namespace. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-ns.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index b25838ac4f..008deb5e87 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -210,19 +210,6 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) return -1; } - if (ns->params.max_open_zones > ns->num_zones) { - error_setg(errp, - "max_open_zones value %u exceeds the number of zones %u", - ns->params.max_open_zones, ns->num_zones); - return -1; - } - if (ns->params.max_active_zones > ns->num_zones) { - error_setg(errp, - "max_active_zones value %u exceeds the number of zones %u", - ns->params.max_active_zones, ns->num_zones); - return -1; - } - if (ns->params.max_active_zones) { if (ns->params.max_open_zones > ns->params.max_active_zones) { error_setg(errp, "max_open_zones (%u) exceeds max_active_zones (%u)", From 49ad39c55a2086637bbde4616491dfee17a142e7 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Tue, 9 Mar 2021 12:20:41 +0100 Subject: [PATCH 0694/3028] hw/block/nvme: move zoned constraints checks Validation of the max_active and max_open zoned parameters are independent of any other state, so move them to the early nvme_ns_check_constraints parameter checks. Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- hw/block/nvme-ns.c | 52 +++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/hw/block/nvme-ns.c b/hw/block/nvme-ns.c index 008deb5e87..992e5a13f5 100644 --- a/hw/block/nvme-ns.c +++ b/hw/block/nvme-ns.c @@ -210,30 +210,6 @@ static int nvme_ns_zoned_check_calc_geometry(NvmeNamespace *ns, Error **errp) return -1; } - if (ns->params.max_active_zones) { - if (ns->params.max_open_zones > ns->params.max_active_zones) { - error_setg(errp, "max_open_zones (%u) exceeds max_active_zones (%u)", - ns->params.max_open_zones, ns->params.max_active_zones); - return -1; - } - - if (!ns->params.max_open_zones) { - ns->params.max_open_zones = ns->params.max_active_zones; - } - } - - if (ns->params.zd_extension_size) { - if (ns->params.zd_extension_size & 0x3f) { - error_setg(errp, - "zone descriptor extension size must be a multiple of 64B"); - return -1; - } - if ((ns->params.zd_extension_size >> 6) > 0xff) { - error_setg(errp, "zone descriptor extension size is too large"); - return -1; - } - } - return 0; } @@ -403,6 +379,34 @@ static int nvme_ns_check_constraints(NvmeCtrl *n, NvmeNamespace *ns, } } + if (ns->params.zoned) { + if (ns->params.max_active_zones) { + if (ns->params.max_open_zones > ns->params.max_active_zones) { + error_setg(errp, "max_open_zones (%u) exceeds " + "max_active_zones (%u)", ns->params.max_open_zones, + ns->params.max_active_zones); + return -1; + } + + if (!ns->params.max_open_zones) { + ns->params.max_open_zones = ns->params.max_active_zones; + } + } + + if (ns->params.zd_extension_size) { + if (ns->params.zd_extension_size & 0x3f) { + error_setg(errp, "zone descriptor extension size must be a " + "multiple of 64B"); + return -1; + } + if ((ns->params.zd_extension_size >> 6) > 0xff) { + error_setg(errp, + "zone descriptor extension size is too large"); + return -1; + } + } + } + return 0; } From 88eea45c536470cd3c43440cbb1cd4d3b9fa519c Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 14 Apr 2021 22:14:30 +0200 Subject: [PATCH 0695/3028] hw/nvme: move nvme emulation out of hw/block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the introduction of the nvme-subsystem device we are really cluttering up the hw/block directory. As suggested by Philippe previously, move the nvme emulation to hw/nvme. Suggested-by: Philippe Mathieu-Daudé Signed-off-by: Klaus Jensen Reviewed-by: Keith Busch --- MAINTAINERS | 2 +- hw/Kconfig | 1 + hw/block/Kconfig | 5 - hw/block/meson.build | 1 - hw/block/trace-events | 206 ---------------------- hw/meson.build | 1 + hw/nvme/Kconfig | 4 + hw/{block/nvme.c => nvme/ctrl.c} | 0 hw/{block/nvme-dif.c => nvme/dif.c} | 0 hw/nvme/meson.build | 1 + hw/{block/nvme-ns.c => nvme/ns.c} | 0 hw/{block => nvme}/nvme.h | 6 +- hw/{block/nvme-subsys.c => nvme/subsys.c} | 0 hw/nvme/trace-events | 204 +++++++++++++++++++++ hw/nvme/trace.h | 1 + meson.build | 1 + 16 files changed, 217 insertions(+), 216 deletions(-) create mode 100644 hw/nvme/Kconfig rename hw/{block/nvme.c => nvme/ctrl.c} (100%) rename hw/{block/nvme-dif.c => nvme/dif.c} (100%) create mode 100644 hw/nvme/meson.build rename hw/{block/nvme-ns.c => nvme/ns.c} (100%) rename hw/{block => nvme}/nvme.h (99%) rename hw/{block/nvme-subsys.c => nvme/subsys.c} (100%) create mode 100644 hw/nvme/trace-events create mode 100644 hw/nvme/trace.h diff --git a/MAINTAINERS b/MAINTAINERS index 78561a223f..e3c2866393 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1956,7 +1956,7 @@ M: Keith Busch M: Klaus Jensen L: qemu-block@nongnu.org S: Supported -F: hw/block/nvme* +F: hw/nvme/* F: include/block/nvme.h F: tests/qtest/nvme-test.c F: docs/system/nvme.rst diff --git a/hw/Kconfig b/hw/Kconfig index aa10357adf..805860f564 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -21,6 +21,7 @@ source mem/Kconfig source misc/Kconfig source net/Kconfig source nubus/Kconfig +source nvme/Kconfig source nvram/Kconfig source pci-bridge/Kconfig source pci-host/Kconfig diff --git a/hw/block/Kconfig b/hw/block/Kconfig index 4fcd152166..295441e64a 100644 --- a/hw/block/Kconfig +++ b/hw/block/Kconfig @@ -25,11 +25,6 @@ config ONENAND config TC58128 bool -config NVME_PCI - bool - default y if PCI_DEVICES - depends on PCI - config VIRTIO_BLK bool default y diff --git a/hw/block/meson.build b/hw/block/meson.build index 5b4a7699f9..8b0de54db1 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -13,7 +13,6 @@ softmmu_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c')) softmmu_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c')) softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c')) softmmu_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c')) -softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c', 'nvme-ns.c', 'nvme-subsys.c', 'nvme-dif.c')) specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c')) specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c')) diff --git a/hw/block/trace-events b/hw/block/trace-events index fa12e3a67a..646917d045 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -49,212 +49,6 @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6 hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d" hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d" -# nvme.c -# nvme traces for successful events -pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u" -pci_nvme_irq_pin(void) "pulsing IRQ pin" -pci_nvme_irq_masked(void) "IRQ is masked" -pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64"" -pci_nvme_map_addr(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64"" -pci_nvme_map_addr_cmb(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64"" -pci_nvme_map_prp(uint64_t trans_len, uint32_t len, uint64_t prp1, uint64_t prp2, int num_prps) "trans_len %"PRIu64" len %"PRIu32" prp1 0x%"PRIx64" prp2 0x%"PRIx64" num_prps %d" -pci_nvme_map_sgl(uint8_t typ, uint64_t len) "type 0x%"PRIx8" len %"PRIu64"" -pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'" -pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'" -pci_nvme_flush(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" -pci_nvme_format(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8"" -pci_nvme_format_ns(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8"" -pci_nvme_format_cb(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" -pci_nvme_read(uint16_t cid, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" -pci_nvme_write(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" -pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_misc_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_dif_rw(uint8_t pract, uint8_t prinfo) "pract 0x%"PRIx8" prinfo 0x%"PRIx8"" -pci_nvme_dif_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_dif_rw_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_dif_rw_mdata_out_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_dif_rw_check_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32"" -pci_nvme_dif_pract_generate_dif(size_t len, size_t lba_size, size_t chksum_len, uint16_t apptag, uint32_t reftag) "len %zu lba_size %zu chksum_len %zu apptag 0x%"PRIx16" reftag 0x%"PRIx32"" -pci_nvme_dif_check(uint8_t prinfo, uint16_t chksum_len) "prinfo 0x%"PRIx8" chksum_len %"PRIu16"" -pci_nvme_dif_prchk_disabled(uint16_t apptag, uint32_t reftag) "apptag 0x%"PRIx16" reftag 0x%"PRIx32"" -pci_nvme_dif_prchk_guard(uint16_t guard, uint16_t crc) "guard 0x%"PRIx16" crc 0x%"PRIx16"" -pci_nvme_dif_prchk_apptag(uint16_t apptag, uint16_t elbat, uint16_t elbatm) "apptag 0x%"PRIx16" elbat 0x%"PRIx16" elbatm 0x%"PRIx16"" -pci_nvme_dif_prchk_reftag(uint32_t reftag, uint32_t elbrt) "reftag 0x%"PRIx32" elbrt 0x%"PRIx32"" -pci_nvme_copy(uint16_t cid, uint32_t nsid, uint16_t nr, uint8_t format) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu16" format 0x%"PRIx8"" -pci_nvme_copy_source_range(uint64_t slba, uint32_t nlb) "slba 0x%"PRIx64" nlb %"PRIu32"" -pci_nvme_copy_in_complete(uint16_t cid) "cid %"PRIu16"" -pci_nvme_copy_cb(uint16_t cid) "cid %"PRIu16"" -pci_nvme_verify(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" -pci_nvme_verify_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_verify_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32"" -pci_nvme_rw_complete_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_block_status(int64_t offset, int64_t bytes, int64_t pnum, int ret, bool zeroed) "offset %"PRId64" bytes %"PRId64" pnum %"PRId64" ret 0x%x zeroed %d" -pci_nvme_dsm(uint16_t cid, uint32_t nsid, uint32_t nr, uint32_t attr) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu32" attr 0x%"PRIx32"" -pci_nvme_dsm_deallocate(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba %"PRIu64" nlb %"PRIu32"" -pci_nvme_dsm_single_range_limit_exceeded(uint32_t nlb, uint32_t dmrsl) "nlb %"PRIu32" dmrsl %"PRIu32"" -pci_nvme_compare(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" -pci_nvme_compare_data_cb(uint16_t cid) "cid %"PRIu16"" -pci_nvme_compare_mdata_cb(uint16_t cid) "cid %"PRIu16"" -pci_nvme_aio_discard_cb(uint16_t cid) "cid %"PRIu16"" -pci_nvme_aio_copy_in_cb(uint16_t cid) "cid %"PRIu16"" -pci_nvme_aio_zone_reset_cb(uint16_t cid, uint64_t zslba) "cid %"PRIu16" zslba 0x%"PRIx64"" -pci_nvme_aio_flush_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" -pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" -pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" -pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16"" -pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16"" -pci_nvme_identify(uint16_t cid, uint8_t cns, uint16_t ctrlid, uint8_t csi) "cid %"PRIu16" cns 0x%"PRIx8" ctrlid %"PRIu16" csi 0x%"PRIx8"" -pci_nvme_identify_ctrl(void) "identify controller" -pci_nvme_identify_ctrl_csi(uint8_t csi) "identify controller, csi=0x%"PRIx8"" -pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32"" -pci_nvme_identify_ns_attached_list(uint16_t cntid) "cntid=%"PRIu16"" -pci_nvme_identify_ns_csi(uint32_t ns, uint8_t csi) "nsid=%"PRIu32", csi=0x%"PRIx8"" -pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32"" -pci_nvme_identify_nslist_csi(uint16_t ns, uint8_t csi) "nsid=%"PRIu16", csi=0x%"PRIx8"" -pci_nvme_identify_cmd_set(void) "identify i/o command set" -pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32"" -pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64"" -pci_nvme_getfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32"" -pci_nvme_setfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32"" -pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s" -pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d" -pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d" -pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64"" -pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64"" -pci_nvme_process_aers(int queued) "queued %d" -pci_nvme_aer(uint16_t cid) "cid %"PRIu16"" -pci_nvme_aer_aerl_exceeded(void) "aerl exceeded" -pci_nvme_aer_masked(uint8_t type, uint8_t mask) "type 0x%"PRIx8" mask 0x%"PRIx8"" -pci_nvme_aer_post_cqe(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" -pci_nvme_ns_attachment(uint16_t cid, uint8_t sel) "cid %"PRIu16", sel=0x%"PRIx8"" -pci_nvme_ns_attachment_attach(uint16_t cntlid, uint32_t nsid) "cntlid=0x%"PRIx16", nsid=0x%"PRIx32"" -pci_nvme_enqueue_event(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" -pci_nvme_enqueue_event_noqueue(int queued) "queued %d" -pci_nvme_enqueue_event_masked(uint8_t typ) "type 0x%"PRIx8"" -pci_nvme_no_outstanding_aers(void) "ignoring event; no outstanding AERs" -pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16"" -pci_nvme_mmio_read(uint64_t addr, unsigned size) "addr 0x%"PRIx64" size %d" -pci_nvme_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d" -pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16"" -pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "sqid %"PRIu16" new_tail %"PRIu16"" -pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" -pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" -pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64"" -pci_nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64"" -pci_nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64"" -pci_nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64"" -pci_nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" -pci_nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" -pci_nvme_mmio_start_success(void) "setting controller enable bit succeeded" -pci_nvme_mmio_stopped(void) "cleared controller enable bit" -pci_nvme_mmio_shutdown_set(void) "shutdown bit set" -pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" -pci_nvme_open_zone(uint64_t slba, uint32_t zone_idx, int all) "open zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" -pci_nvme_close_zone(uint64_t slba, uint32_t zone_idx, int all) "close zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" -pci_nvme_finish_zone(uint64_t slba, uint32_t zone_idx, int all) "finish zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" -pci_nvme_reset_zone(uint64_t slba, uint32_t zone_idx, int all) "reset zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" -pci_nvme_offline_zone(uint64_t slba, uint32_t zone_idx, int all) "offline zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" -pci_nvme_set_descriptor_extension(uint64_t slba, uint32_t zone_idx) "set zone descriptor extension, slba=%"PRIu64", idx=%"PRIu32"" -pci_nvme_zd_extension_set(uint32_t zone_idx) "set descriptor extension for zone_idx=%"PRIu32"" -pci_nvme_clear_ns_close(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Closed state" -pci_nvme_clear_ns_reset(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Empty state" - -# nvme traces for error conditions -pci_nvme_err_mdts(size_t len) "len %zu" -pci_nvme_err_zasl(size_t len) "len %zu" -pci_nvme_err_req_status(uint16_t cid, uint32_t nsid, uint16_t status, uint8_t opc) "cid %"PRIu16" nsid %"PRIu32" status 0x%"PRIx16" opc 0x%"PRIx8"" -pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64"" -pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64"" -pci_nvme_err_cfs(void) "controller fatal status" -pci_nvme_err_aio(uint16_t cid, const char *errname, uint16_t status) "cid %"PRIu16" err '%s' status 0x%"PRIx16"" -pci_nvme_err_copy_invalid_format(uint8_t format) "format 0x%"PRIx8"" -pci_nvme_err_invalid_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" -pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" -pci_nvme_err_invalid_sgl_excess_length(uint32_t residual) "residual %"PRIu32"" -pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size" -pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is not page aligned: 0x%"PRIx64"" -pci_nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64"" -pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8"" -pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8"" -pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64"" -pci_nvme_err_invalid_log_page_offset(uint64_t ofs, uint64_t size) "must be <= %"PRIu64", got %"PRIu64"" -pci_nvme_err_cmb_invalid_cba(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64"" -pci_nvme_err_cmb_not_enabled(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64"" -pci_nvme_err_unaligned_zone_cmd(uint8_t action, uint64_t slba, uint64_t zslba) "unaligned zone op 0x%"PRIx32", got slba=%"PRIu64", zslba=%"PRIu64"" -pci_nvme_err_invalid_zone_state_transition(uint8_t action, uint64_t slba, uint8_t attrs) "action=0x%"PRIx8", slba=%"PRIu64", attrs=0x%"PRIx32"" -pci_nvme_err_write_not_at_wp(uint64_t slba, uint64_t zone, uint64_t wp) "writing at slba=%"PRIu64", zone=%"PRIu64", but wp=%"PRIu64"" -pci_nvme_err_append_not_at_start(uint64_t slba, uint64_t zone) "appending at slba=%"PRIu64", but zone=%"PRIu64"" -pci_nvme_err_zone_is_full(uint64_t zslba) "zslba 0x%"PRIx64"" -pci_nvme_err_zone_is_read_only(uint64_t zslba) "zslba 0x%"PRIx64"" -pci_nvme_err_zone_is_offline(uint64_t zslba) "zslba 0x%"PRIx64"" -pci_nvme_err_zone_boundary(uint64_t slba, uint32_t nlb, uint64_t zcap) "lba 0x%"PRIx64" nlb %"PRIu32" zcap 0x%"PRIx64"" -pci_nvme_err_zone_invalid_write(uint64_t slba, uint64_t wp) "lba 0x%"PRIx64" wp 0x%"PRIx64"" -pci_nvme_err_zone_write_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16"" -pci_nvme_err_zone_read_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16"" -pci_nvme_err_insuff_active_res(uint32_t max_active) "max_active=%"PRIu32" zone limit exceeded" -pci_nvme_err_insuff_open_res(uint32_t max_open) "max_open=%"PRIu32" zone limit exceeded" -pci_nvme_err_zd_extension_map_error(uint32_t zone_idx) "can't map descriptor extension for zone_idx=%"PRIu32"" -pci_nvme_err_invalid_iocsci(uint32_t idx) "unsupported command set combination index %"PRIu32"" -pci_nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16"" -pci_nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16"" -pci_nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16"" -pci_nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16"" -pci_nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64"" -pci_nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16"" -pci_nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16"" -pci_nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16"" -pci_nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16"" -pci_nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16"" -pci_nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64"" -pci_nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16"" -pci_nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16"" -pci_nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16"" -pci_nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32"" -pci_nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32"" -pci_nvme_err_invalid_log_page(uint16_t cid, uint16_t lid) "cid %"PRIu16" lid 0x%"PRIx16"" -pci_nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues" -pci_nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues" -pci_nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null" -pci_nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null" -pci_nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64"" -pci_nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64"" -pci_nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u" -pci_nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u" -pci_nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u" -pci_nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u" -pci_nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u" -pci_nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u" -pci_nvme_err_startfail_css(uint8_t css) "nvme_start_ctrl failed because invalid command set selected:%u" -pci_nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero" -pci_nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero" -pci_nvme_err_startfail_zasl_too_small(uint32_t zasl, uint32_t pagesz) "nvme_start_ctrl failed because zone append size limit %"PRIu32" is too small, needs to be >= %"PRIu32"" -pci_nvme_err_startfail(void) "setting controller enable bit failed" -pci_nvme_err_invalid_mgmt_action(uint8_t action) "action=0x%"PRIx8"" - -# Traces for undefined behavior -pci_nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64"" -pci_nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u" -pci_nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled" -pci_nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status" -pci_nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)" -pci_nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" -pci_nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" -pci_nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" -pci_nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored" -pci_nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored" -pci_nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored" -pci_nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored" -pci_nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" -pci_nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" -pci_nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" -pci_nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0" -pci_nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring" -pci_nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring" -pci_nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring" -pci_nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring" -pci_nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring" -pci_nvme_ub_unknown_css_value(void) "unknown value in cc.css field" - # xen-block.c xen_block_realize(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" xen_block_connect(const char *type, uint32_t disk, uint32_t partition) "%s d%up%u" diff --git a/hw/meson.build b/hw/meson.build index 6bdbae0e81..ba0601e36e 100644 --- a/hw/meson.build +++ b/hw/meson.build @@ -21,6 +21,7 @@ subdir('mem') subdir('misc') subdir('net') subdir('nubus') +subdir('nvme') subdir('nvram') subdir('pci') subdir('pci-bridge') diff --git a/hw/nvme/Kconfig b/hw/nvme/Kconfig new file mode 100644 index 0000000000..8ac90942e5 --- /dev/null +++ b/hw/nvme/Kconfig @@ -0,0 +1,4 @@ +config NVME_PCI + bool + default y if PCI_DEVICES + depends on PCI diff --git a/hw/block/nvme.c b/hw/nvme/ctrl.c similarity index 100% rename from hw/block/nvme.c rename to hw/nvme/ctrl.c diff --git a/hw/block/nvme-dif.c b/hw/nvme/dif.c similarity index 100% rename from hw/block/nvme-dif.c rename to hw/nvme/dif.c diff --git a/hw/nvme/meson.build b/hw/nvme/meson.build new file mode 100644 index 0000000000..3cf40046ee --- /dev/null +++ b/hw/nvme/meson.build @@ -0,0 +1 @@ +softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('ctrl.c', 'dif.c', 'ns.c', 'subsys.c')) diff --git a/hw/block/nvme-ns.c b/hw/nvme/ns.c similarity index 100% rename from hw/block/nvme-ns.c rename to hw/nvme/ns.c diff --git a/hw/block/nvme.h b/hw/nvme/nvme.h similarity index 99% rename from hw/block/nvme.h rename to hw/nvme/nvme.h index fb028d81d1..81a35cda14 100644 --- a/hw/block/nvme.h +++ b/hw/nvme/nvme.h @@ -15,8 +15,8 @@ * This code is licensed under the GNU GPL v2 or later. */ -#ifndef HW_NVME_H -#define HW_NVME_H +#ifndef HW_NVME_INTERNAL_H +#define HW_NVME_INTERNAL_H #include "qemu/uuid.h" #include "hw/pci/pci.h" @@ -544,4 +544,4 @@ uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len, uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req); -#endif /* HW_NVME_H */ +#endif /* HW_NVME_INTERNAL_H */ diff --git a/hw/block/nvme-subsys.c b/hw/nvme/subsys.c similarity index 100% rename from hw/block/nvme-subsys.c rename to hw/nvme/subsys.c diff --git a/hw/nvme/trace-events b/hw/nvme/trace-events new file mode 100644 index 0000000000..ea33d0ccc3 --- /dev/null +++ b/hw/nvme/trace-events @@ -0,0 +1,204 @@ +# successful events +pci_nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u" +pci_nvme_irq_pin(void) "pulsing IRQ pin" +pci_nvme_irq_masked(void) "IRQ is masked" +pci_nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64"" +pci_nvme_map_addr(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64"" +pci_nvme_map_addr_cmb(uint64_t addr, uint64_t len) "addr 0x%"PRIx64" len %"PRIu64"" +pci_nvme_map_prp(uint64_t trans_len, uint32_t len, uint64_t prp1, uint64_t prp2, int num_prps) "trans_len %"PRIu64" len %"PRIu32" prp1 0x%"PRIx64" prp2 0x%"PRIx64" num_prps %d" +pci_nvme_map_sgl(uint8_t typ, uint64_t len) "type 0x%"PRIx8" len %"PRIu64"" +pci_nvme_io_cmd(uint16_t cid, uint32_t nsid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" nsid %"PRIu32" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'" +pci_nvme_admin_cmd(uint16_t cid, uint16_t sqid, uint8_t opcode, const char *opname) "cid %"PRIu16" sqid %"PRIu16" opc 0x%"PRIx8" opname '%s'" +pci_nvme_flush(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" +pci_nvme_format(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8"" +pci_nvme_format_ns(uint16_t cid, uint32_t nsid, uint8_t lbaf, uint8_t mset, uint8_t pi, uint8_t pil) "cid %"PRIu16" nsid %"PRIu32" lbaf %"PRIu8" mset %"PRIu8" pi %"PRIu8" pil %"PRIu8"" +pci_nvme_format_cb(uint16_t cid, uint32_t nsid) "cid %"PRIu16" nsid %"PRIu32"" +pci_nvme_read(uint16_t cid, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" +pci_nvme_write(uint16_t cid, const char *verb, uint32_t nsid, uint32_t nlb, uint64_t count, uint64_t lba) "cid %"PRIu16" opname '%s' nsid %"PRIu32" nlb %"PRIu32" count %"PRIu64" lba 0x%"PRIx64"" +pci_nvme_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_misc_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw(uint8_t pract, uint8_t prinfo) "pract 0x%"PRIx8" prinfo 0x%"PRIx8"" +pci_nvme_dif_rw_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw_mdata_out_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_dif_rw_check_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_dif_pract_generate_dif(size_t len, size_t lba_size, size_t chksum_len, uint16_t apptag, uint32_t reftag) "len %zu lba_size %zu chksum_len %zu apptag 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_dif_check(uint8_t prinfo, uint16_t chksum_len) "prinfo 0x%"PRIx8" chksum_len %"PRIu16"" +pci_nvme_dif_prchk_disabled(uint16_t apptag, uint32_t reftag) "apptag 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_dif_prchk_guard(uint16_t guard, uint16_t crc) "guard 0x%"PRIx16" crc 0x%"PRIx16"" +pci_nvme_dif_prchk_apptag(uint16_t apptag, uint16_t elbat, uint16_t elbatm) "apptag 0x%"PRIx16" elbat 0x%"PRIx16" elbatm 0x%"PRIx16"" +pci_nvme_dif_prchk_reftag(uint32_t reftag, uint32_t elbrt) "reftag 0x%"PRIx32" elbrt 0x%"PRIx32"" +pci_nvme_copy(uint16_t cid, uint32_t nsid, uint16_t nr, uint8_t format) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu16" format 0x%"PRIx8"" +pci_nvme_copy_source_range(uint64_t slba, uint32_t nlb) "slba 0x%"PRIx64" nlb %"PRIu32"" +pci_nvme_copy_in_complete(uint16_t cid) "cid %"PRIu16"" +pci_nvme_copy_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_verify(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" +pci_nvme_verify_mdata_in_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_verify_cb(uint16_t cid, uint8_t prinfo, uint16_t apptag, uint16_t appmask, uint32_t reftag) "cid %"PRIu16" prinfo 0x%"PRIx8" apptag 0x%"PRIx16" appmask 0x%"PRIx16" reftag 0x%"PRIx32"" +pci_nvme_rw_complete_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_block_status(int64_t offset, int64_t bytes, int64_t pnum, int ret, bool zeroed) "offset %"PRId64" bytes %"PRId64" pnum %"PRId64" ret 0x%x zeroed %d" +pci_nvme_dsm(uint16_t cid, uint32_t nsid, uint32_t nr, uint32_t attr) "cid %"PRIu16" nsid %"PRIu32" nr %"PRIu32" attr 0x%"PRIx32"" +pci_nvme_dsm_deallocate(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba %"PRIu64" nlb %"PRIu32"" +pci_nvme_dsm_single_range_limit_exceeded(uint32_t nlb, uint32_t dmrsl) "nlb %"PRIu32" dmrsl %"PRIu32"" +pci_nvme_compare(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb) "cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32"" +pci_nvme_compare_data_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_compare_mdata_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_aio_discard_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_aio_copy_in_cb(uint16_t cid) "cid %"PRIu16"" +pci_nvme_aio_zone_reset_cb(uint16_t cid, uint64_t zslba) "cid %"PRIu16" zslba 0x%"PRIx64"" +pci_nvme_aio_flush_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk '%s'" +pci_nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" +pci_nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" +pci_nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16"" +pci_nvme_del_cq(uint16_t cqid) "deleted completion queue, cqid=%"PRIu16"" +pci_nvme_identify(uint16_t cid, uint8_t cns, uint16_t ctrlid, uint8_t csi) "cid %"PRIu16" cns 0x%"PRIx8" ctrlid %"PRIu16" csi 0x%"PRIx8"" +pci_nvme_identify_ctrl(void) "identify controller" +pci_nvme_identify_ctrl_csi(uint8_t csi) "identify controller, csi=0x%"PRIx8"" +pci_nvme_identify_ns(uint32_t ns) "nsid %"PRIu32"" +pci_nvme_identify_ns_attached_list(uint16_t cntid) "cntid=%"PRIu16"" +pci_nvme_identify_ns_csi(uint32_t ns, uint8_t csi) "nsid=%"PRIu32", csi=0x%"PRIx8"" +pci_nvme_identify_nslist(uint32_t ns) "nsid %"PRIu32"" +pci_nvme_identify_nslist_csi(uint16_t ns, uint8_t csi) "nsid=%"PRIu16", csi=0x%"PRIx8"" +pci_nvme_identify_cmd_set(void) "identify i/o command set" +pci_nvme_identify_ns_descr_list(uint32_t ns) "nsid %"PRIu32"" +pci_nvme_get_log(uint16_t cid, uint8_t lid, uint8_t lsp, uint8_t rae, uint32_t len, uint64_t off) "cid %"PRIu16" lid 0x%"PRIx8" lsp 0x%"PRIx8" rae 0x%"PRIx8" len %"PRIu32" off %"PRIu64"" +pci_nvme_getfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t sel, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" sel 0x%"PRIx8" cdw11 0x%"PRIx32"" +pci_nvme_setfeat(uint16_t cid, uint32_t nsid, uint8_t fid, uint8_t save, uint32_t cdw11) "cid %"PRIu16" nsid 0x%"PRIx32" fid 0x%"PRIx8" save 0x%"PRIx8" cdw11 0x%"PRIx32"" +pci_nvme_getfeat_vwcache(const char* result) "get feature volatile write cache, result=%s" +pci_nvme_getfeat_numq(int result) "get feature number of queues, result=%d" +pci_nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d" +pci_nvme_setfeat_timestamp(uint64_t ts) "set feature timestamp = 0x%"PRIx64"" +pci_nvme_getfeat_timestamp(uint64_t ts) "get feature timestamp = 0x%"PRIx64"" +pci_nvme_process_aers(int queued) "queued %d" +pci_nvme_aer(uint16_t cid) "cid %"PRIu16"" +pci_nvme_aer_aerl_exceeded(void) "aerl exceeded" +pci_nvme_aer_masked(uint8_t type, uint8_t mask) "type 0x%"PRIx8" mask 0x%"PRIx8"" +pci_nvme_aer_post_cqe(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" +pci_nvme_ns_attachment(uint16_t cid, uint8_t sel) "cid %"PRIu16", sel=0x%"PRIx8"" +pci_nvme_ns_attachment_attach(uint16_t cntlid, uint32_t nsid) "cntlid=0x%"PRIx16", nsid=0x%"PRIx32"" +pci_nvme_enqueue_event(uint8_t typ, uint8_t info, uint8_t log_page) "type 0x%"PRIx8" info 0x%"PRIx8" lid 0x%"PRIx8"" +pci_nvme_enqueue_event_noqueue(int queued) "queued %d" +pci_nvme_enqueue_event_masked(uint8_t typ) "type 0x%"PRIx8"" +pci_nvme_no_outstanding_aers(void) "ignoring event; no outstanding AERs" +pci_nvme_enqueue_req_completion(uint16_t cid, uint16_t cqid, uint16_t status) "cid %"PRIu16" cqid %"PRIu16" status 0x%"PRIx16"" +pci_nvme_mmio_read(uint64_t addr, unsigned size) "addr 0x%"PRIx64" size %d" +pci_nvme_mmio_write(uint64_t addr, uint64_t data, unsigned size) "addr 0x%"PRIx64" data 0x%"PRIx64" size %d" +pci_nvme_mmio_doorbell_cq(uint16_t cqid, uint16_t new_head) "cqid %"PRIu16" new_head %"PRIu16"" +pci_nvme_mmio_doorbell_sq(uint16_t sqid, uint16_t new_tail) "sqid %"PRIu16" new_tail %"PRIu16"" +pci_nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" +pci_nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" +pci_nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64"" +pci_nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64"" +pci_nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64"" +pci_nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64"" +pci_nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" +pci_nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" +pci_nvme_mmio_start_success(void) "setting controller enable bit succeeded" +pci_nvme_mmio_stopped(void) "cleared controller enable bit" +pci_nvme_mmio_shutdown_set(void) "shutdown bit set" +pci_nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" +pci_nvme_open_zone(uint64_t slba, uint32_t zone_idx, int all) "open zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" +pci_nvme_close_zone(uint64_t slba, uint32_t zone_idx, int all) "close zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" +pci_nvme_finish_zone(uint64_t slba, uint32_t zone_idx, int all) "finish zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" +pci_nvme_reset_zone(uint64_t slba, uint32_t zone_idx, int all) "reset zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" +pci_nvme_offline_zone(uint64_t slba, uint32_t zone_idx, int all) "offline zone, slba=%"PRIu64", idx=%"PRIu32", all=%"PRIi32"" +pci_nvme_set_descriptor_extension(uint64_t slba, uint32_t zone_idx) "set zone descriptor extension, slba=%"PRIu64", idx=%"PRIu32"" +pci_nvme_zd_extension_set(uint32_t zone_idx) "set descriptor extension for zone_idx=%"PRIu32"" +pci_nvme_clear_ns_close(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Closed state" +pci_nvme_clear_ns_reset(uint32_t state, uint64_t slba) "zone state=%"PRIu32", slba=%"PRIu64" transitioned to Empty state" + +# error conditions +pci_nvme_err_mdts(size_t len) "len %zu" +pci_nvme_err_zasl(size_t len) "len %zu" +pci_nvme_err_req_status(uint16_t cid, uint32_t nsid, uint16_t status, uint8_t opc) "cid %"PRIu16" nsid %"PRIu32" status 0x%"PRIx16" opc 0x%"PRIx8"" +pci_nvme_err_addr_read(uint64_t addr) "addr 0x%"PRIx64"" +pci_nvme_err_addr_write(uint64_t addr) "addr 0x%"PRIx64"" +pci_nvme_err_cfs(void) "controller fatal status" +pci_nvme_err_aio(uint16_t cid, const char *errname, uint16_t status) "cid %"PRIu16" err '%s' status 0x%"PRIx16"" +pci_nvme_err_copy_invalid_format(uint8_t format) "format 0x%"PRIx8"" +pci_nvme_err_invalid_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" +pci_nvme_err_invalid_num_sgld(uint16_t cid, uint8_t typ) "cid %"PRIu16" type 0x%"PRIx8"" +pci_nvme_err_invalid_sgl_excess_length(uint32_t residual) "residual %"PRIu32"" +pci_nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size" +pci_nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is not page aligned: 0x%"PRIx64"" +pci_nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64"" +pci_nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8"" +pci_nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8"" +pci_nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64"" +pci_nvme_err_invalid_log_page_offset(uint64_t ofs, uint64_t size) "must be <= %"PRIu64", got %"PRIu64"" +pci_nvme_err_cmb_invalid_cba(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64"" +pci_nvme_err_cmb_not_enabled(uint64_t cmbmsc) "cmbmsc 0x%"PRIx64"" +pci_nvme_err_unaligned_zone_cmd(uint8_t action, uint64_t slba, uint64_t zslba) "unaligned zone op 0x%"PRIx32", got slba=%"PRIu64", zslba=%"PRIu64"" +pci_nvme_err_invalid_zone_state_transition(uint8_t action, uint64_t slba, uint8_t attrs) "action=0x%"PRIx8", slba=%"PRIu64", attrs=0x%"PRIx32"" +pci_nvme_err_write_not_at_wp(uint64_t slba, uint64_t zone, uint64_t wp) "writing at slba=%"PRIu64", zone=%"PRIu64", but wp=%"PRIu64"" +pci_nvme_err_append_not_at_start(uint64_t slba, uint64_t zone) "appending at slba=%"PRIu64", but zone=%"PRIu64"" +pci_nvme_err_zone_is_full(uint64_t zslba) "zslba 0x%"PRIx64"" +pci_nvme_err_zone_is_read_only(uint64_t zslba) "zslba 0x%"PRIx64"" +pci_nvme_err_zone_is_offline(uint64_t zslba) "zslba 0x%"PRIx64"" +pci_nvme_err_zone_boundary(uint64_t slba, uint32_t nlb, uint64_t zcap) "lba 0x%"PRIx64" nlb %"PRIu32" zcap 0x%"PRIx64"" +pci_nvme_err_zone_invalid_write(uint64_t slba, uint64_t wp) "lba 0x%"PRIx64" wp 0x%"PRIx64"" +pci_nvme_err_zone_write_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16"" +pci_nvme_err_zone_read_not_ok(uint64_t slba, uint32_t nlb, uint16_t status) "slba=%"PRIu64", nlb=%"PRIu32", status=0x%"PRIx16"" +pci_nvme_err_insuff_active_res(uint32_t max_active) "max_active=%"PRIu32" zone limit exceeded" +pci_nvme_err_insuff_open_res(uint32_t max_open) "max_open=%"PRIu32" zone limit exceeded" +pci_nvme_err_zd_extension_map_error(uint32_t zone_idx) "can't map descriptor extension for zone_idx=%"PRIu32"" +pci_nvme_err_invalid_iocsci(uint32_t idx) "unsupported command set combination index %"PRIu32"" +pci_nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16"" +pci_nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16"" +pci_nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16"" +pci_nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16"" +pci_nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64"" +pci_nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16"" +pci_nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16"" +pci_nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16"" +pci_nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16"" +pci_nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16"" +pci_nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64"" +pci_nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16"" +pci_nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16"" +pci_nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16"" +pci_nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32"" +pci_nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32"" +pci_nvme_err_invalid_log_page(uint16_t cid, uint16_t lid) "cid %"PRIu16" lid 0x%"PRIx16"" +pci_nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues" +pci_nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues" +pci_nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null" +pci_nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null" +pci_nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64"" +pci_nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64"" +pci_nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u" +pci_nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u" +pci_nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u" +pci_nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u" +pci_nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u" +pci_nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u" +pci_nvme_err_startfail_css(uint8_t css) "nvme_start_ctrl failed because invalid command set selected:%u" +pci_nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero" +pci_nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero" +pci_nvme_err_startfail_zasl_too_small(uint32_t zasl, uint32_t pagesz) "nvme_start_ctrl failed because zone append size limit %"PRIu32" is too small, needs to be >= %"PRIu32"" +pci_nvme_err_startfail(void) "setting controller enable bit failed" +pci_nvme_err_invalid_mgmt_action(uint8_t action) "action=0x%"PRIx8"" + +# undefined behavior +pci_nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64"" +pci_nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u" +pci_nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled" +pci_nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status" +pci_nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)" +pci_nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" +pci_nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" +pci_nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" +pci_nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored" +pci_nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored" +pci_nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored" +pci_nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored" +pci_nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" +pci_nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" +pci_nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" +pci_nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0" +pci_nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring" +pci_nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring" +pci_nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring" +pci_nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring" +pci_nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring" +pci_nvme_ub_unknown_css_value(void) "unknown value in cc.css field" diff --git a/hw/nvme/trace.h b/hw/nvme/trace.h new file mode 100644 index 0000000000..b398ea107f --- /dev/null +++ b/hw/nvme/trace.h @@ -0,0 +1 @@ +#include "trace/trace-hw_nvme.h" diff --git a/meson.build b/meson.build index 8e16e05c2a..1559e8d873 100644 --- a/meson.build +++ b/meson.build @@ -1822,6 +1822,7 @@ if have_system 'hw/misc/macio', 'hw/net', 'hw/net/can', + 'hw/nvme', 'hw/nvram', 'hw/pci', 'hw/pci-host', From 0b16f04c1fa3f4f2abc538154c77b06c2aba52df Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Apr 2021 12:34:08 -0700 Subject: [PATCH 0696/3028] linux-user/s390x: Handle vector regs in signal stack Signed-off-by: Richard Henderson Reviewed-by: David Hildenbrand Message-Id: <20210428193408.233706-16-richard.henderson@linaro.org> [lv: fix indentation] Signed-off-by: Laurent Vivier --- linux-user/s390x/signal.c | 62 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/linux-user/s390x/signal.c b/linux-user/s390x/signal.c index 9d470e4ca0..ef136dae33 100644 --- a/linux-user/s390x/signal.c +++ b/linux-user/s390x/signal.c @@ -50,6 +50,12 @@ typedef struct { target_s390_fp_regs fpregs; } target_sigregs; +typedef struct { + uint64_t vxrs_low[16]; + uint64_t vxrs_high[16][2]; + uint8_t reserved[128]; +} target_sigregs_ext; + typedef struct { abi_ulong oldmask[_SIGCONTEXT_NSIG_WORDS]; abi_ulong sregs; @@ -60,15 +66,20 @@ typedef struct { target_sigcontext sc; target_sigregs sregs; int signo; + target_sigregs_ext sregs_ext; uint16_t retcode; } sigframe; +#define TARGET_UC_VXRS 2 + struct target_ucontext { abi_ulong tuc_flags; abi_ulong tuc_link; target_stack_t tuc_stack; target_sigregs tuc_mcontext; - target_sigset_t tuc_sigmask; /* mask last for extensibility */ + target_sigset_t tuc_sigmask; + uint8_t reserved[128 - sizeof(target_sigset_t)]; + target_sigregs_ext tuc_mcontext_ext; }; typedef struct { @@ -128,6 +139,24 @@ static void save_sigregs(CPUS390XState *env, target_sigregs *sregs) } } +static void save_sigregs_ext(CPUS390XState *env, target_sigregs_ext *ext) +{ + int i; + + /* + * if (MACHINE_HAS_VX) ... + * That said, we always allocate the stack storage and the + * space is always available in env. + */ + for (i = 0; i < 16; ++i) { + __put_user(env->vregs[i][1], &ext->vxrs_low[i]); + } + for (i = 0; i < 16; ++i) { + __put_user(env->vregs[i + 16][0], &ext->vxrs_high[i][0]); + __put_user(env->vregs[i + 16][1], &ext->vxrs_high[i][1]); + } +} + void setup_frame(int sig, struct target_sigaction *ka, target_sigset_t *set, CPUS390XState *env) { @@ -161,6 +190,9 @@ void setup_frame(int sig, struct target_sigaction *ka, */ __put_user(sig, &frame->signo); + /* Create sigregs_ext on the signal stack. */ + save_sigregs_ext(env, &frame->sregs_ext); + /* * Set up to return from userspace. * If provided, use a stub already in userspace. @@ -202,6 +234,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, rt_sigframe *frame; abi_ulong frame_addr; abi_ulong restorer; + abi_ulong uc_flags; frame_addr = get_sigframe(ka, env, sizeof *frame); trace_user_setup_rt_frame(env, frame_addr); @@ -229,10 +262,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, tswap_siginfo(&frame->info, info); /* Create ucontext on the signal stack. */ - __put_user(0, &frame->uc.tuc_flags); + uc_flags = 0; + if (s390_has_feat(S390_FEAT_VECTOR)) { + uc_flags |= TARGET_UC_VXRS; + } + __put_user(uc_flags, &frame->uc.tuc_flags); __put_user(0, &frame->uc.tuc_link); target_save_altstack(&frame->uc.tuc_stack, env); save_sigregs(env, &frame->uc.tuc_mcontext); + save_sigregs_ext(env, &frame->uc.tuc_mcontext_ext); tswap_sigset(&frame->uc.tuc_sigmask, set); /* Set up registers for signal handler */ @@ -271,6 +309,24 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc) } } +static void restore_sigregs_ext(CPUS390XState *env, target_sigregs_ext *ext) +{ + int i; + + /* + * if (MACHINE_HAS_VX) ... + * That said, we always allocate the stack storage and the + * space is always available in env. + */ + for (i = 0; i < 16; ++i) { + __get_user(env->vregs[i][1], &ext->vxrs_low[i]); + } + for (i = 0; i < 16; ++i) { + __get_user(env->vregs[i + 16][0], &ext->vxrs_high[i][0]); + __get_user(env->vregs[i + 16][1], &ext->vxrs_high[i][1]); + } +} + long do_sigreturn(CPUS390XState *env) { sigframe *frame; @@ -292,6 +348,7 @@ long do_sigreturn(CPUS390XState *env) set_sigmask(&set); /* ~_BLOCKABLE? */ restore_sigregs(env, &frame->sregs); + restore_sigregs_ext(env, &frame->sregs_ext); unlock_user_struct(frame, frame_addr, 0); return -TARGET_QEMU_ESIGRETURN; @@ -313,6 +370,7 @@ long do_rt_sigreturn(CPUS390XState *env) set_sigmask(&set); /* ~_BLOCKABLE? */ restore_sigregs(env, &frame->uc.tuc_mcontext); + restore_sigregs_ext(env, &frame->uc.tuc_mcontext_ext); target_restore_altstack(&frame->uc.tuc_stack, env); From db3221454d6b242c248cc4c33c60b9016e153516 Mon Sep 17 00:00:00 2001 From: Giuseppe Musacchio Date: Mon, 3 May 2021 19:41:58 +0200 Subject: [PATCH 0697/3028] linux-user: Add copy_file_range to strace.list Signed-off-by: Giuseppe Musacchio Reviewed-by: Laurent Vivier Message-Id: <20210503174159.54302-2-thatlemon@gmail.com> Signed-off-by: Laurent Vivier --- linux-user/strace.list | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-user/strace.list b/linux-user/strace.list index 18f7217275..278596acd1 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1668,3 +1668,6 @@ #ifdef TARGET_NR_statx { TARGET_NR_statx, "statx", NULL, print_statx, NULL }, #endif +#ifdef TARGET_NR_copy_file_range +{ TARGET_NR_copy_file_range, "copy_file_range", "%s(%d,%p,%d,%p,"TARGET_ABI_FMT_lu",%u)", NULL, NULL }, +#endif From 0fa259dd7986d152294f31a6483272a4cb627b6d Mon Sep 17 00:00:00 2001 From: Giuseppe Musacchio Date: Mon, 3 May 2021 19:41:59 +0200 Subject: [PATCH 0698/3028] linux-user: Fix erroneous conversion in copy_file_range The implicit cast from abi_long to size_t may introduce an intermediate unwanted sign-extension of the value for 32bit targets running on 64bit hosts. Signed-off-by: Giuseppe Musacchio Reviewed-by: Laurent Vivier Message-Id: <20210503174159.54302-3-thatlemon@gmail.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 4d52b2cfe3..e05870c338 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -13244,8 +13244,9 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, } poutoff = &outoff; } + /* Do not sign-extend the count parameter. */ ret = get_errno(safe_copy_file_range(arg1, pinoff, arg3, poutoff, - arg5, arg6)); + (abi_ulong)arg5, arg6)); if (!is_error(ret) && ret > 0) { if (arg2) { if (put_user_u64(inoff, arg2)) { From 68af19ad72630f00d1b92635334050826e4b6f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 5 May 2021 11:37:01 +0100 Subject: [PATCH 0699/3028] linux-user: use GDateTime for formatting timestamp for core file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The GDateTime APIs provided by GLib avoid portability pitfalls, such as some platforms where 'struct timeval.tv_sec' field is still 'long' instead of 'time_t'. When combined with automatic cleanup, GDateTime often results in simpler code too. Signed-off-by: Daniel P. Berrangé Reviewed-by: Laurent Vivier Message-Id: <20210505103702.521457-7-berrange@redhat.com> Signed-off-by: Laurent Vivier --- linux-user/elfload.c | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index ffc03d72f9..015eed1a27 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -3376,7 +3376,6 @@ static size_t note_size(const struct memelfnote *); static void free_note_info(struct elf_note_info *); static int fill_note_info(struct elf_note_info *, long, const CPUArchState *); static void fill_thread_info(struct elf_note_info *, const CPUArchState *); -static int core_dump_filename(const TaskState *, char *, size_t); static int dump_write(int, const void *, size_t); static int write_note(struct memelfnote *, int); @@ -3675,32 +3674,16 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts) * for the name: * qemu__-